. */ /** * This file contains the ColorReplace filter class. * * @author Dinu Florin * @package Modules * @subpackage Images */ /** * ColorReplace filter class. * * @author Dinu Florin * @package Modules * @subpackage Images */ class ColorReplace extends AbstractImageFilter { protected $colors = array(); protected $fast = false; /** * Constructor. * * @param array $colors The colors to replace and their replacements. * @param bool $fast Skip some calculations and apply faster. */ public function __construct($colors, $fast=false) { $this->colors = $colors; $this->fast = $fast; } static public function diff($color1, $color2) { //CIE94 difference $color1 = Image::LabToLch(Image::RgbToLab($color1)); $color2 = Image::LabToLch(Image::RgbToLab($color2)); $KL= 1; $K1 = 0.045; $K2 = 0.015; $dL = pow(($color2['L']-$color1['L'])/$KL, 2); $dC = pow(($color2['c']-$color1['c'])/(1 + $K1*$color1['c']), 2); $dh = pow(($color2['h'] - $color1['h'])/(1 + $K2*$color1['c']), 2); return sqrt($dL + $dC + $dh); } /** * Apply to an image * * @param Image $image The image to apply the filter to */ public function applyTo(Image $image) { $img = $image->getResource(); $imgw = $image->width; $imgh = $image->height; $minSurface = 30/100*$imgw*$imgh; $newImg = imagecreatetruecolor($imgw, $imgh); imagealphablending($newImg, false); foreach($this->colors as $old=>$new) { $old = Image::decodeColor($old); $new = Image::decodeColor($new); $old['surface'] = 0; $old = array_merge($old, Image::rgbToHsv($old)); $new = array_merge($old, Image::rgbToHsv($new)); $o_colors[] = $old; $n_colors[] = $new; } if(!$this->fast) { $oldPc = -1; $oldIndex = -1; for($y = 0; $y < $imgh; $y++) { for($x = 0; $x < $imgw; $x++) { $pc = imagecolorat($img, $x, $y); if($pc == $oldPc) { $o_colors[$oldIndex]['surface'] += 1; continue; } else { $oldPc = $pc; } $pixelColor = imagecolorsforindex($img, $pc); //We need the RGB components to be floats between 0 and 1 $pixelColor['r'] = $pixelColor['red']; $pixelColor['g'] = $pixelColor['green']; $pixelColor['b'] = $pixelColor['blue']; $md = 5000000000; $oi = 0; foreach($o_colors as $i=>$c) { $d = self::diff($c, $pixelColor); if($d < $md) { $md = $d; $oi = $i; $oldIndex = $i; } } $o_colors[$oi]['surface'] += 1; } } } $oldPc = -1; $oldPixelColor = array(); for($y = 0; $y < $imgh; $y++) { for($x = 0; $x < $imgw; $x++) { $pc = imagecolorat($img, $x, $y); if($pc == $oldPc) { imagesetpixel($newImg, $x, $y, $oldPixelColor); continue; } else { $oldPc = $pc; } $pixelColor = imagecolorsforindex($img, $pc); //We need the RGB components to be floats between 0 and 1 $pixelColor['r'] = $pixelColor['red']; $pixelColor['g'] = $pixelColor['green']; $pixelColor['b'] = $pixelColor['blue']; $pixelAlpha = ($pc & 0x7F000000) >> 24; $pixelColor['a'] = $pixelAlpha; $md = 5000000000; $nc = null; $oc = null; foreach($o_colors as $i=>$c) { if($this->fast || $c['surface'] > $minSurface) { $d = self::diff($c, $pixelColor); if($d < $md) { $md = $d; $nc = $n_colors[$i]; $oc = $c; } } } $pixelColor = Image::rgbToHsv($pixelColor); $pixelColor['h'] = $nc['h']; $pixelColor['s'] = max(min($pixelColor['s']-$oc['s'] + $nc['s'], 1), 0); $pixelColor['v'] = max(min($pixelColor['v']-$oc['v'] + $nc['v'], 1), 0); $pixelColor = Image::HsvToRgb($pixelColor); //Go back to RGB space $pc = imagecolorallocatealpha($newImg, $pixelColor['r'], $pixelColor['g'], $pixelColor['b'], $pixelAlpha); imagesetpixel($newImg, $x, $y, $pc); $oldPixelColor = $pc; } } imagesavealpha($newImg, true); $image->setResource($newImg); imagedestroy($img); } } ?>