问题
Yes I know there are related questions available on stackoverflow but they are not perfectly work as per my need. I am trying to replace a color of an image with another color. In below code I am replacing (255,0,255) with (0,192,239). Below code works but not perfectly replacing new color over pink(255,0,255) color some minor dots or border of pink color is still remaining as you can see in output image.
How can i get its perfect solution ?
<?php
$filename = 'img/Mascots_Aviators_General-copy.png';
$im = imagecreatefrompng($filename);
$out = imagecreatetruecolor(imagesx($im), imagesy($im));
$transColor = imagecolorallocatealpha($out, 254, 254, 254, 127);
imagefill($out, 0, 0, $transColor);
for ($x = 0; $x < imagesx($im); $x++) {
for ($y = 0; $y < imagesy($im); $y++) {
$pixel = imagecolorat($im, $x, $y);
$red = ($pixel >> 16) & 0xFF;
$green = ($pixel >> 8) & 0xFF;
$blue = $pixel & 0xFF;
$alpha = ($pixel & 0x7F000000) >> 24;
if ($red == 255 && $green == 0 && $blue == 255) {
$red = 0;
$green=192;
$blue =239;
}
if ($alpha == 127) {
imagesetpixel($out, $x, $y, $transColor);
}
else {
imagesetpixel($out, $x, $y, imagecolorallocatealpha($out, $red, $green, $blue, $alpha));
}
}
}
imagecolortransparent($out, $transColor);
imagesavealpha($out, TRUE);
header('Content-type: image/png');
imagepng($out);
回答1:
EDIT 2 :
You might need to optimize something and change hueAbsoluteError
to suit your needs, but hue is the way to enlightenment and sharper picture quality (functions taken from https://gist.github.com/brandonheyer/5254516):
<?php
function RGBtoHSL( $r, $g, $b ) {
$r /= 255;
$g /= 255;
$b /= 255;
$max = max( $r, $g, $b );
$min = min( $r, $g, $b );
$l = ( $max + $min ) / 2;
$d = $max - $min;
if( $d == 0 ){
$h = $s = 0;
} else {
$s = $d / ( 1 - abs( 2 * $l - 1 ) );
switch( $max ){
case $r:
$h = 60 * fmod( ( ( $g - $b ) / $d ), 6 );
if ($b > $g) {
$h += 360;
}
break;
case $g:
$h = 60 * ( ( $b - $r ) / $d + 2 );
break;
case $b:
$h = 60 * ( ( $r - $g ) / $d + 4 );
break;
}
}
return array( round( $h, 2 ), round( $s, 2 ), round( $l, 2 ) );
}
function HSLtoRGB( $h, $s, $l ){
$c = ( 1 - abs( 2 * $l - 1 ) ) * $s;
$x = $c * ( 1 - abs( fmod( ( $h / 60 ), 2 ) - 1 ) );
$m = $l - ( $c / 2 );
if ( $h < 60 ) {
$r = $c;
$g = $x;
$b = 0;
} else if ( $h < 120 ) {
$r = $x;
$g = $c;
$b = 0;
} else if ( $h < 180 ) {
$r = 0;
$g = $c;
$b = $x;
} else if ( $h < 240 ) {
$r = 0;
$g = $x;
$b = $c;
} else if ( $h < 300 ) {
$r = $x;
$g = 0;
$b = $c;
} else {
$r = $c;
$g = 0;
$b = $x;
}
$r = ( $r + $m ) * 255;
$g = ( $g + $m ) * 255;
$b = ( $b + $m ) * 255;
return array( floor( $r ), floor( $g ), floor( $b ) );
}
/* ---------------CHANGE THESE------------------- */
$colorToReplace = RGBtoHSL(255, 0, 255);
$hueAbsoluteError = 0.4;
$replacementColor = RGBtoHSL(0, 192, 239);
/* ---------------------------------------------- */
$filename = 'img/Mascots_Aviators_General-copy.png';
$im = imagecreatefrompng($filename);
$out = imagecreatetruecolor(imagesx($im), imagesy($im));
$transColor = imagecolorallocatealpha($out, 254, 254, 254, 127);
imagefill($out, 0, 0, $transColor);
for ($x = 0; $x < imagesx($im); $x++) {
for ($y = 0; $y < imagesy($im); $y++) {
$pixel = imagecolorat($im, $x, $y);
$red = ($pixel >> 16) & 0xFF;
$green = ($pixel >> 8) & 0xFF;
$blue = $pixel & 0xFF;
$alpha = ($pixel & 0x7F000000) >> 24;
$colorHSL = RGBtoHSL($red, $green, $blue);
if ((($colorHSL[0] >= $colorToReplace[0] - $hueAbsoluteError) && ($colorToReplace[0] + $hueAbsoluteError) >= $colorHSL[0])){
$color = HSLtoRGB($replacementColor[0], $replacementColor[1], $colorHSL[2]);
$red = $color[0];
$green= $color[1];
$blue = $color[2];
}
if ($alpha == 127) {
imagesetpixel($out, $x, $y, $transColor);
}
else {
imagesetpixel($out, $x, $y, imagecolorallocatealpha($out, $red, $green, $blue, $alpha));
}
}
}
imagecolortransparent($out, $transColor);
imagesavealpha($out, TRUE);
header('Content-type: image/png');
imagepng($out);
EDIT : Better solution - determine if color needs replacement (using this method). Determine replaced color's hue (I have no idea if it's correct term, what I mean is lightness and darkness). Apply it to replacement color to give it a shade or AA feeling.
So, as I have said in my comment, you need to determine if this color is really ping (dark, light, etc.). Easiest solution is to apply absolute error method for specific color channels. There may be (there definitely is) better universal method, but I hope this will do:
$color = [255, 0, 255];
$colorAbsoluteError = [150, 0, 150];
$replacementColor = [0, 192, 239];
$filename = 'img/Mascots_Aviators_General-copy.png';
$im = imagecreatefrompng($filename);
$out = imagecreatetruecolor(imagesx($im), imagesy($im));
$transColor = imagecolorallocatealpha($out, 254, 254, 254, 127);
imagefill($out, 0, 0, $transColor);
for ($x = 0; $x < imagesx($im); $x++) {
for ($y = 0; $y < imagesy($im); $y++) {
$pixel = imagecolorat($im, $x, $y);
$red = ($pixel >> 16) & 0xFF;
$green = ($pixel >> 8) & 0xFF;
$blue = $pixel & 0xFF;
$alpha = ($pixel & 0x7F000000) >> 24;
if ((($red >= $color[0] - $colorAbsoluteError[0]) && ($color[0] + $colorAbsoluteError[0]) >= $red) &&
(($green >= $color[1] - $colorAbsoluteError[1]) && ($color[1] + $colorAbsoluteError[1]) >= $green) &&
(($blue >= $color[2] - $colorAbsoluteError[2]) && ($color[2] + $colorAbsoluteError[2]) >= $blue)){
$red = $replacementColor[0];
$green= $replacementColor[1];
$blue = $replacementColor[2];
}
if ($alpha == 127) {
imagesetpixel($out, $x, $y, $transColor);
}
else {
imagesetpixel($out, $x, $y, imagecolorallocatealpha($out, $red, $green, $blue, $alpha));
}
}
}
imagecolortransparent($out, $transColor);
imagesavealpha($out, TRUE);
header('Content-type: image/png');
imagepng($out);
来源:https://stackoverflow.com/questions/32710180/replace-a-color-with-another-color-in-an-image-with-php