Colorextractor not working since Kirby 3.8?

Hello all,
It looks like the colorextractor does not work anymore.
Did anymbody else experience this problem?

What is the error that you get. There is this issue that I also got when I tested: Image must be a gd resource · Issue #13 · sylvainjule/kirby-colorextractor · GitHub

Looking further into this, the underlying problem seems to have been fixed, but the version of league/color-extractor that comes as a dependency of SimpleImage isn’t up to date.

I get the same error and the color is not distracted.
THat sounds good but how should I imoplement it then?
Should I update SimpleImage? Or does Kirby do this automatically?

Should I use the one from League? Or do you think Sylvain Jule will fix this at some point?

Thank you!

Kirby uses the latest available SimpleImage version. However, this latest available version of SimpleImage does not use the latest release (0.4.0) of thephpleague/color-extractor/. So we would need to wait until SimpleImage updates its dependencies.

This plugin was so helpful. And I now have the feeling the solution is close.

I have been trying to get it to work with Colorthief, which should be working according to the page bellow.

but no succes so far. I added colorthief in this directory:

/kirby/vendor/colorthief/colorthief/src/ColorThief

In the plugin:

<?php

namespace SylvainJule;

use ColorThief\ColorThief;

use Kirby\Cms\Files;
use Kirby\Cms\File;

class ColorExtractor {

	public static function extractColor($image, $mode, $fallbackColor) {
        $colors = [];

		if($image->isResizable()) {
            if(in_array($mode, ['dominant', 'both'])) {
                $colors[] = static::processImage($image, 300, $fallbackColor);
            }
            // Size below 10 seems to fail / timeout with ColorThief...
            if(in_array($mode, ['average', 'both'])) {
                $colors[] = static::processImage($image, 10, $fallbackColor);
            }

			$image->update(['color' => implode(',', $colors)]);
		}
	}

    public static function processImage($image, $size, $fallbackColor) {
        $thumb     = $image->width() > $image->height() ? $image->resize(null, $size) : $image->resize($size);
        $thumb     = $thumb->save();
        $root      = $thumb->root();

        // ColorThief::getColor($sourceImage[, $quality=10, $area=null, $outputFormat='array', $adapter = null])
        $dominantColor = ColorThief::getColor($root, 10, null, 'hex', null);

        return $dominantColor;
    }

    public static function getFilesIndex() {
        $published = site()->index()->images();
        $drafts    = site()->drafts()->images();
        $images    = new Files(array($published, $drafts));
        $images    = $images->filterBy('extension', 'in', ['png', 'jpg', 'jpeg', 'gif', 'webp']);

        return $images;
    }

}

When I upload an image I get this error:
‘Class “ColorThief\ColorThief” not found’

I guess the plugin can not find the colorthief files. Is there anything obvious that I am not doing right?

Thanks everyone!!

You have to require colorthief via composer, not add the files there manually, if that’s what you did?

yes thats what I did.

But now I added the files through composer. My filestructure looks like this now:

I does not load yet, having the same error in the panel… Am I running Composer in the right directory now?

In the kirby folder? I dont think I should change that folder , right?
Or like I did now, in the pluginfolder? I dont understand (yet!)

Thank you.

Ok, that looks good, additionally, you have to require the autoloader in the plugin’s index.php

<?php

if (!class_exists('SylvainJule\ColorExtractor')) {
	require_once __DIR__ . '/lib/colorextractor.php';
}

@include_once __DIR__ . '/vendor/autoload.php';

// ....

Great!
Now I get another error:
‘Array to string conversion’

The first problem seems to be solved. Any idea about this one?

index.php

<?php

if (!class_exists('SylvainJule\ColorExtractor')) {
	require_once __DIR__ . '/lib/colorextractor.php';
}

@include_once __DIR__ . '/vendor/autoload.php';

Kirby::plugin('sylvainjule/colorextractor', [
	'options' => [
		'average'       => false,
		'fallbackColor' => '#ffffff',
        'mode'          => 'dominant',
        'jobs' => [
            'extractColors' => function () {
                $files      = SylvainJule\ColorExtractor::getFilesIndex();
                $files      = $files->filter(function($file) { return $file->color()->isEmpty(); });
                $filesCount = $files->count();

                foreach($files as $file) {
                    $file->extractColor();
                }

                return [
                    'status' => 200,
                    'label' => tc('colorextractor.processed', $filesCount)
                ];
            },
            'forceExtractColors' => function () {
                $files      = SylvainJule\ColorExtractor::getFilesIndex();
                $filesCount = $files->count();

                foreach($files as $file) {
                    $file->extractColor();
                }

                return [
                    'status' => 200,
                    'label' => tc('colorextractor.processed', $filesCount)
                ];
            },
        ]
	],
    'hooks'  => [
        'file.create:after'  => function ($file) {
            $file->extractColor();
        },
        'file.replace:after' => function ($newFile, $oldFile) {
            $newFile->extractColor();
        }
    ],
    'fileMethods' => [
        'extractColor' => function() : Kirby\Cms\Field {
            if($this->type() === 'image') {
                $mode          = option('sylvainjule.colorextractor.mode');
                // compatibility with previous versions
                $mode          = option('sylvainjule.colorextractor.average') == true ? 'average' : $mode;
                $fallbackColor = option('sylvainjule.colorextractor.fallBackColor');

                SylvainJule\ColorExtractor::extractColor($this, $mode, $fallbackColor);
            }
            return $this->color()->toString();
        }
    ],
    'fieldMethods' => [
        'dominantColor' => function($field, $mode = 'dominant') {
            $colors = $field->split(',');
            $count  = count($colors);

            if($count == 0) $field->value = null;
            else $field->value = $colors[0];

            return $field;
        },
        'averageColor' => function($field, $mode = 'dominant') {
            $colors = $field->split(',');
            $count  = count($colors);

            if($count == 0) $field->value = null;
            else $field->value = $count == 1 ? $colors[0] : $colors[1];

            return $field;
        }
    ],
    'translations' => array(
        'en' => [
            'colorextractor.processed'  => [
                'There are no images with missing colors.',
                '1 image processed!',
                '{{ count }} images processed!'
            ],
        ],
        'de' => [
            'colorextractor.processed'  => [
                'Keine fehlenden Farben.',
                'Bild verarbeitet!',
                '{{ count }} Bilder verarbeitet!'
            ],
        ],
        'fr' => [
            'colorextractor.processed'  => [
                'Aucune couleur manquante.',
                '1 couleur extraite !',
                '{{ count }} couleurs extraites !'
            ],
        ]
    ),
]);

colorextractor.php

<?php

namespace SylvainJule;

use ColorThief\ColorThief;

use Kirby\Cms\Files;
use Kirby\Cms\File;

class ColorExtractor {

	public static function extractColor($image, $mode, $fallbackColor) {
        $colors = [];

		if($image->isResizable()) {
            if(in_array($mode, ['dominant', 'both'])) {
                $colors[] = static::processImage($image, 300, $fallbackColor);
            }
            // Size below 10 seems to fail / timeout with ColorThief...
            if(in_array($mode, ['average', 'both'])) {
                $colors[] = static::processImage($image, 10, $fallbackColor);
            }

			$image->update(['color' => implode(',', $colors)]);
		}
	}

    public static function processImage($image, $size, $fallbackColor) {
        $thumb     = $image->width() > $image->height() ? $image->resize(null, $size) : $image->resize($size);
        $thumb     = $thumb->save();
        $root      = $thumb->root();

        // ColorThief::getColor($sourceImage[, $quality=10, $area=null, $outputFormat='array', $adapter = null])
        $dominantColor = ColorThief::getColor($root, 10, null, 'hex', null);

        return $dominantColor;
    }

    public static function getFilesIndex() {
        $published = site()->index()->images();
        $drafts    = site()->drafts()->images();
        $images    = new Files(array($published, $drafts));
        $images    = $images->filterBy('extension', 'in', ['png', 'jpg', 'jpeg', 'gif', 'webp']);

        return $images;
    }

}

But I’m wondering if the underlying issue in the plugin isn’t solved since the latest Kirby release.

No, is there no stack trace for the error? Without proper debugging, this will be hard to find.

But as I wrote above, if you use the latest version of Kirby, the plugin should actually work again without the addition, I think, because the issues mentioned above have been resolved in the meantime.

The plugin is indeed working in the last version. Then I want to batch all the existing images.
However when I install the Janitor plugin, Kirby asks for the installation of CLI.
I came to this page:

My question is where to install this? Maybe a general thing I don’t really understand about Composer. Is there a guide somewhere which can explain this?
When I ‘just’ install the CLI through Composer the files (which are many) are placed in the rootfolder of the site, and I have the feeling that is not how it is supposed to be done :slight_smile: