thephpleague / color-extractor

Extract colors from an image like a human would do.
thephpleague.com
MIT License
1.3k stars 159 forks source link

add Imagick support #38

Closed MatTheCat closed 6 years ago

MatTheCat commented 8 years ago

Fix #37

Add creation method for Imagick and call it from fromFilename if the extension is loaded because it seems faster.

Since ext-gd is no longer mandatory I moved it with ext-imagick in composer.json suggest section.

I'm thinking this PR could introduce the 1.0.0 release. What do you think @GrahamCampbell @philsturgeon @toin0u?

MatTheCat commented 8 years ago

I just discovered Imagick produces a slightly different palette, so tests are failing. Dunno why for now.

pedrogasparcs commented 7 years ago

Hi @MatTheCat, it should be because of the following line: $colorComponents = $pixel->getColor(true);

where you get the normalized values for the colorComponents. If you pick the standard (getColor(false)) the result will be the same as GD.

The problem is that if you use standard you'll end up only with binary values for the alpha component. Reading a note on http://php.net/manual/en/imagickpixel.getcolor.php it suggests to use standard for rgb components and normalized for the alpha component.

MatTheCat commented 7 years ago

Sadly I still see a difference, even when transparency isn't involved.

pedrogasparcs commented 7 years ago

You have modified the components calculation assuming them as normalized, I kept it similar to the one developed for GD, using the standard components, and the results seem to match. Nevertheless, not sure about the alpha component calc.

foreach ($image->getImageHistogram() as $pixel) { $normalizedColorComponents = $pixel->getColor(true); $standardColorComponents = $pixel->getColor(false);

        $color = ($normalizedColorComponents['a'] * 16777216) +
            ($standardColorComponents['r'] * 65536) +
            ($standardColorComponents['g'] * 256) +
            ($standardColorComponents['b']);

        if ($alpha = $color >> 24) {
            if ($backgroundColor === null) {
                continue;
            }
            $alpha /= 127;
            $color = (int) (($color >> 16 & 0xFF) * (1 - $alpha) + $backgroundColorRed * $alpha) * 65536 +
                (int) (($color >> 8 & 0xFF) * (1 - $alpha) + $backgroundColorGreen * $alpha) * 256 +
                (int) (($color & 0xFF) * (1 - $alpha) + $backgroundColorBlue * $alpha);
        }

        $palette->colors[$color] = $pixel->getColorCount();
    } 
MatTheCat commented 7 years ago

Have you tested the code you pasted? alpha component is not the transparency but the opacity so without background no color is added.

If you do see a difference please let me reproduce.

pedrogasparcs commented 7 years ago

Yes I tested.

You're suggesting to reverse the "a" component value to behave like the one returned by GD (which is meant to be alpha and not opacity)?

Since I'm always setting the $backgroundColor I didn't fall into that use case.