<commit_before><?php

namespace MatTheCat\ColorExtractor;

class ColorExtractor
{
    public static function extract($imageResource, $maxPaletteSize = 1, $minColorRatio = 0, $minSaturation = 0)
    {
        $w = imagesx($imageResource);
        $h = imagesy($imageResource);

        $x = $y = 0;

        $colors = array();

        do {
            do {
                $rgba = imagecolorsforindex($imageResource, imagecolorat($imageResource, $x, $y));
                $rgb = array($rgba['red'], $rgba['green'], $rgba['blue']);
                $color = hexdec(sprintf('%02X%02X%02X', $rgb[0], $rgb[1], $rgb[2]));
                if(array_key_exists($color, $colors)) {
                    $colors[$color]['count']++;
                }
                else {
                    $saturation = self::getColorSaturation(self::getSRGBComponents(self::getRGBComponents($color)));
                    if($saturation >= $minSaturation) {
                        $colors[$color] = array(
                            'count' => 1,
                            'saturation' => $saturation
                        );
                    }
                }
            } while(++$y < $h);
            $y = 0;
        } while(++$x < $w);

        uasort($colors, function($firstColor, $secondColor) {
            $diff = $firstColor['saturation']*$firstColor['count'] - $secondColor['saturation']*$secondColor['count'];
            return !$diff ?
                ($firstColor['saturation'] > $secondColor['saturation'] ? 1 : -1) :
                ($diff < 0 ? 1 : -1);
        });

        $totalColorCount = count($colors);
        $maxPaletteSize = min($maxPaletteSize, $totalColorCount);
        $minDeltaE = 100/($maxPaletteSize + 1);
        $minCountAllowed = $totalColorCount*$minColorRatio;
        $paletteSize = 1;

        if($maxPaletteSize > 1) {
            $i = 0;
            while($i++ < $maxPaletteSize) {
                $j = 0;
                reset($colors);
                while(++$j < $i) {
                    next($colors);
                }
                $refColor = key($colors);

                if(current($colors)['count'] <= $minCountAllowed) {
                    break;
                }

                while($j++ < $maxPaletteSize) {
                    next($colors);
                    $cmpColor = key($colors);
                    if(current($colors)['count'] <= $minCountAllowed) {
                        break;
                    }
                    if(self::CIEDE2000DeltaE(self::getLabFromColor($refColor), self::getLabFromColor($cmpColor)) <= $minDeltaE) {
                        $j--;
                        prev($colors);
                        unset($colors[$cmpColor]);
                        if($i > 1) {
                            $i = 0;
                        }
                    }
                }
            }
            $paletteSize = max(1, $i - 1);
        }
        return array_map(
            function($color) {
                return self::toHex($color);
            },
            array_keys(array_slice($colors, 0, $paletteSize, true))
        );
    }

    protected static function toHex($color)
    {
        $hex = '#';
        foreach(self::getRGBComponents($color) as $component) {
            $hex.=sprintf('%02X', $component);
        }
        return $hex;
    }

    protected static function getLabFromColor($color)
    {
        return self::getLabFromSRGB(self::getSRGBComponents(self::getRGBComponents($color)));
    }

    protected static function getLabFromSRGB($sRGBComponents)
    {
        return self::getLabComponents(self::getXYZComponents($sRGBComponents));
    }

    protected static function getRGBComponents($color)
    {
        return array(
            ($color >> 16) & 0xFF,
            ($color >> 8) & 0xFF,
            $color & 0xFF
        );
    }

    protected static function getColorSaturation(array $sRGBComponents)
    {
        $max = max($sRGBComponents);
        $min = min($sRGBComponents);
        $diff = $max - $min;<commit_msg>rewrite toHex method<commit_after><?php

namespace MatTheCat\ColorExtractor;

class ColorExtractor
{
    public static function extract($imageResource, $maxPaletteSize = 1, $minColorRatio = 0, $minSaturation = 0)
    {
        $w = imagesx($imageResource);
        $h = imagesy($imageResource);

        $x = $y = 0;

        $colors = array();

        do {
            do {
                $rgba = imagecolorsforindex($imageResource, imagecolorat($imageResource, $x, $y));
                $rgb = array($rgba['red'], $rgba['green'], $rgba['blue']);
                $color = hexdec(sprintf('%02X%02X%02X', $rgb[0], $rgb[1], $rgb[2]));
                if(array_key_exists($color, $colors)) {
                    $colors[$color]['count']++;
                }
                else {
                    $saturation = self::getColorSaturation(self::getSRGBComponents(self::getRGBComponents($color)));
                    if($saturation >= $minSaturation) {
                        $colors[$color] = array(
                            'count' => 1,
                            'saturation' => $saturation
                        );
                    }
                }
            } while(++$y < $h);
            $y = 0;
        } while(++$x < $w);

        uasort($colors, function($firstColor, $secondColor) {
            $diff = $firstColor['saturation']*$firstColor['count'] - $secondColor['saturation']*$secondColor['count'];
            return !$diff ?
                ($firstColor['saturation'] > $secondColor['saturation'] ? 1 : -1) :
                ($diff < 0 ? 1 : -1);
        });

        $totalColorCount = count($colors);
        $maxPaletteSize = min($maxPaletteSize, $totalColorCount);
        $minDeltaE = 100/($maxPaletteSize + 1);
        $minCountAllowed = $totalColorCount*$minColorRatio;
        $paletteSize = 1;

        if($maxPaletteSize > 1) {
            $i = 0;
            while($i++ < $maxPaletteSize) {
                $j = 0;
                reset($colors);
                while(++$j < $i) {
                    next($colors);
                }
                $refColor = key($colors);

                if(current($colors)['count'] <= $minCountAllowed) {
                    break;
                }

                while($j++ < $maxPaletteSize) {
                    next($colors);
                    $cmpColor = key($colors);
                    if(current($colors)['count'] <= $minCountAllowed) {
                        break;
                    }
                    if(self::CIEDE2000DeltaE(self::getLabFromColor($refColor), self::getLabFromColor($cmpColor)) <= $minDeltaE) {
                        $j--;
                        prev($colors);
                        unset($colors[$cmpColor]);
                        if($i > 1) {
                            $i = 0;
                        }
                    }
                }
            }
            $paletteSize = max(1, $i - 1);
        }
        return array_map(
            function($color) {
                return self::toHex($color);
            },
            array_keys(array_slice($colors, 0, $paletteSize, true))
        );
    }

    protected static function toHex($color)
    {
        $rgb = self::getRGBComponents($color);
        return sprintf('#%02X%02X%02X', $rgb[0], $rgb[1], $rgb[2]);
    }

    protected static function getLabFromColor($color)
    {
        return self::getLabFromSRGB(self::getSRGBComponents(self::getRGBComponents($color)));
    }

    protected static function getLabFromSRGB($sRGBComponents)
    {
        return self::getLabComponents(self::getXYZComponents($sRGBComponents));
    }

    protected static function getRGBComponents($color)
    {
        return array(
            ($color >> 16) & 0xFF,
            ($color >> 8) & 0xFF,
            $color & 0xFF
        );
    }

    protected static function getColorSaturation(array $sRGBComponents)
    {
        $max = max($sRGBComponents);
        $min = min($sRGBComponents);
        $diff = $max - $min;
{'fraction_non_alphanumeric': 0.14214835028528902, 'fraction_numerical': 0.012031753907219053, 'mean_word_length': 1.5087118855009334, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4694209', 'n_tokens_mistral': 2366, 'n_tokens_neox': 2181, 'n_words': 372}