首页 > 解决方案 > Encapsulate ImageMagick in a PHP class to find the closest colour from a predefined palette

问题描述

I am trying to make a class with a method that will accept a single colour as an argument and return the closest colour to it from a predefined palette of colours.

I am aware that there are many ways to calculate the distance between two colours, but I would like to use ImageMagick's implementation, which I have tried to figure out from the source code, but not had any luck. Unfortunately, ImageMagick for PHP is not documented very well. There is lots of documentation, but much of it is vague.

So far, I have some up with 3 different methods, but only one is working. I'm curious as to why the other two methods aren't working and I would also be keen to know if anyone else has a better way to encapsulate ImageMagick in a PHP class that will allow me to achieve my goal.

The code below runs on PHPFiddle.org. Unfortunately, it seems to be broken at the moment and won't let me save it and link to it, so you will need to copy and paste it yourself.

Thanks in advance.

<?php

class ImagickTest
{
    protected function createPalette()
    {
        // Just a limited palette to use as an example.
        $colors = [
            '#ffffff',
            '#000000',
            '#d2d3d1',
            '#efecf2',
        ];
        
        // Create a new Imagick object. 4 pixels on a single row.
        $im = new \Imagick();
        $im->newImage(1, 4, 'white');
        
        // Add the colours.
        $i = 0;
        $iterator = $im->getPixelIterator();
        
        foreach ($iterator as $pixels) {
            foreach ($pixels as $pixel) {
                $pixel->setColor($colors[$i++]);
            }
            
            $iterator->syncIterator();
        }
        
        return $im;
    }

    public function run()
    {
        $tests = [
            ['withBackgroundColor', "// Why doesn't this work?"],
            ['withPixelIterator', "// This is a really close match. Good result!"],
            ['withDirectPixelModification', "// Why hasn't the pixel colour changed?"]
        ];
        
        $palette = $this->createPalette();

        $color = '#cfcfcf';
        
        echo "<table><tbody>\n";
        
        foreach ($tests as $test) {
            echo sprintf("<tr><td>%s</td><td>%s</td><td>%s</td></tr>\n",
                     $test[0],
                     $this->{$test[0]}($color, $palette),
                     $test[1]
                );
        }
        
        echo '</tbody></table>';
    }

    protected function withBackgroundColor($newColor, $palette)
    {
        $im = new \Imagick();
        // WTH does the fourth parameter do, anyway??
        $im->newImage(1, 1, 'white' /*, $format*/);
        
        $im->setImageBackgroundColor($newColor);
        $im->remapImage($palette, 0); // Remap has no effect at all.
        
        return $this->pixelToHex($im->getImageBackgroundColor());
    }

    protected function withPixelIterator($newColor, $palette)
    {
        $im = new \Imagick();
        $im->newImage(1, 1, 'white');
        
        $iterator = $im->getPixelIterator();
        $pixel = $iterator->getCurrentIteratorRow()[0];
        $pixel->setColor($newColor);
        $iterator->syncIterator();
        $im->remapImage($palette, 0);
        
        return $this->pixelToHex($im->getImagePixelColor(1, 1));
    }

    protected function withDirectPixelModification($newColor, $palette)
    {
        $im = new \Imagick();
        $im->newImage(2, 2, 'white');
        
        $pixel = $im->getImagePixelColor(1, 1);
        $pixel->setColor($newColor); // Seems to be ignored.
        $im->remapImage($palette, 0);
        
        return $this->pixelToHex($im->getImagePixelColor(1, 1));
    }

    protected function pixelToHex($pixel)
    {
        $color = $pixel->getColor();

        return sprintf('#%s%s%s',
            str_pad(dechex($color['r']), 2, '0', STR_PAD_LEFT),
            str_pad(dechex($color['g']), 2, '0', STR_PAD_LEFT),
            str_pad(dechex($color['b']), 2, '0', STR_PAD_LEFT)
        );
    }
}

(new ImagickTest)->run();

标签: phpimagemagick

解决方案


推荐阅读