Как заменить один цвет на другой в png 24 альфа-прозрачном изображении с помощью GD

Я пытался:

$index = imagecolorresolve ( $im, 0,0,0 ); // get black imagecolorset($im, $index, 255, 0, 255); // SET NEW COLOR 

Кажется, что это работает с png 8, но не с 24, и если я это делаю с 8, это получается странно из-за сглаживания.

Вот полный тестовый код, который я использую. (это всего лишь тестовый код, поэтому будьте осторожны).

 function LoadPNG($imgname, $color = false) { $im = @imagecreatefrompng($imgname); imagealphablending($im, false); if($color) { $index = imagecolorresolve ( $im, 0,0,0 ); // get black imagecolorset($im, $index, 255, 0, 255); // SET NEW COLOR } imageAlphaBlending($im, true); imageSaveAlpha($im, true); return $im; } header('Content-Type: image/png'); $img = LoadPNG("head.png", "red"); imagepng($img); imagedestroy($img); 

Вы можете попробовать следующее:

  • цикл всех точек
  • получить цвет этой точки
  • если он соответствует вашему цвету A, установите этот пиксель на желаемый цвет B

Код:

 for ($x=imagesx($im); $x--; ) { for ($y=imagesy($im); $y--; ) { $c = imagecolorat($im, $x, $y); if ($c[0] == 0 && $c[1] == 0 && $c[2] == 0) { // here we use the new color, but the original alpha channel $colorB = imagecolorallocatealpha($im, 255, 0, 255, $c[3]); imagesetpixel($im, $x, $y, $colorB); } } } 

Надеюсь это поможет!

Основываясь на решении inti, я создал скрипт, который работает:

 $imgname = "yourimage.png"; $im = imagecreatefrompng($imgname); imagealphablending($im, false); for ($x = imagesx($im); $x--;) { for ($y = imagesy($im); $y--;) { $rgb = imagecolorat($im, $x, $y); $c = imagecolorsforindex($im, $rgb); if ($c['red'] < 40 && $c['green'] < 40 && $c['blue'] < 40) { // dark colors // here we use the new color, but the original alpha channel $colorB = imagecolorallocatealpha($im, 255, 0, 255, $c['alpha']); imagesetpixel($im, $x, $y, $colorB); } } } imageAlphaBlending($im, true); imageSaveAlpha($im, true); header('Content-Type: image/png'); imagepng($im); imagedestroy($im); 

Я бы хотел оптимизировать его, потому что он довольно медленный

эта функция заменит один или все цвета на один новый цвет, поддерживая уровни прозрачности (в противном случае границы, вероятно, будут выглядеть ужасно, если для рисования границ использовалась прозрачность PARTIAL).

ПОЛНЫЙ ОТВЕТ НА ПОДОБНЫЕ ПОЧТЫ

 <?php function colorizeKeepAplhaChannnel( $inputFilePathIn, $targetRedIn, $targetGreenIn, $targetBlueIn, $outputFilePathIn ) { $im_src = imagecreatefrompng( $inputFilePathIn ); $im_dst = imagecreatefrompng( $inputFilePathIn ); $width = imagesx($im_src); $height = imagesy($im_src); // Note this: FILL IMAGE WITH TRANSPARENT BG imagefill($im_dst, 0, 0, IMG_COLOR_TRANSPARENT); imagesavealpha($im_dst,true); imagealphablending($im_dst, true); $flagOK = 1; for( $x=0; $x<$width; $x++ ) { for( $y=0; $y<$height; $y++ ) { $rgb = imagecolorat( $im_src, $x, $y ); $colorOldRGB = imagecolorsforindex($im_src, $rgb); $alpha = $colorOldRGB["alpha"]; $colorNew = imagecolorallocatealpha($im_src, $targetRedIn, $targetGreenIn, $targetBlueIn, $alpha); $flagFoundColor = true; // uncomment next 3 lines to substitute only 1 color (in this case, BLACK/greys) /* $colorOld = imagecolorallocatealpha($im_src, $colorOldRGB["red"], $colorOldRGB["green"], $colorOldRGB["blue"], 0); // original color WITHOUT alpha channel $color2Change = imagecolorallocatealpha($im_src, 0, 0, 0, 0); // opaque BLACK - change to desired color $flagFoundColor = ($color2Change == $colorOld); */ if ( false === $colorNew ) { //echo( "FALSE COLOR:$colorNew alpha:$alpha<br/>" ); $flagOK = 0; } else if ($flagFoundColor) { imagesetpixel( $im_dst, $x, $y, $colorNew ); //echo "x:$xy:$y col=$colorNew alpha:$alpha<br/>"; } } } $flagOK2 = imagepng($im_dst, $outputFilePathIn); if ($flagOK && $flagOK2) { echo ("<strong>Congratulations, your conversion was successful </strong><br/>new file $outputFilePathIn<br/>"); } else if ($flagOK2 && !$flagOK) { echo ("<strong>ERROR, your conversion was UNsuccessful</strong><br/>Please verify if your PNG is truecolor<br/>input file $inputFilePathIn<br/>"); } else if (!$flagOK2 && $flagOK) { $dirNameOutput = dirname($outputFilePathIn)."/"; echo ("<strong>ERROR, your conversion was successful, but could not save file</strong><br/>Please verify that you have PERMISSION to save to directory $dirName <br/>input file $inputFilePathIn<br/>"); } else { $dirNameOutput = dirname($outputFilePathIn)."/"; echo ("<strong>ERROR, your conversion was UNsuccessful AND could not save file</strong><br/>Please verify if your PNG is truecolor<br/>Please verify that you have PERMISSION to save to directory $dirName <br/>input file $inputFilePathIn<br/>"); } echo ("TargetName:$outputFilePathIn wid:$width height:$height CONVERTED:|$flagOK| SAVED:|$flagOK2|<br/>"); imagedestroy($im_dst); imagedestroy($im_src); } $targetRed = 255; $targetGreen = 255; $targetBlue = 0; //$inputFileName = 'frameSquareBlack_88x110.png'; $inputFileName = 'testMe.png'; $dirName = "../img/profilePics/"; $nameTemp = basename($inputFileName, ".png"); $outputFileName = $nameTemp."_$targetRed"."_$targetGreen"."_$targetBlue.png"; $inputFilePath = $dirName.$inputFileName; $outputFilePath = $dirName.$outputFileName; //echo "inputFileName:$inputFilePath<br>outputName:$outputFilePath<br>"; colorizeKeepAplhaChannnel( $inputFilePath, $targetRed, $targetGreen, $targetBlue, $outputFilePath); ?> <br/><br/> Original <br/> <img src="<?php echo $inputFilePath; ?>"> <br /><br />Colorized<br/> <img src="<?php echo $outputFilePath; ?>"> <br /> 

Хороший способ сделать это – использовать paintOpaqueImage (), что также позволяет использовать цветоустойчивость

 $targetColor = "#0074AD"; $fill = "#0074AA"; $tolerance = 30000; $im = new Imagick( "yourimage.png"); if ($im->paintOpaqueImage ( $targetColor , $fill , $tolerance) ){ $im->writeImage("yourimage.png"); } 

Вы можете увидеть документ tolenrance в http://www.imagemagick.org/script/command-line-options.php#fuzz

Эта функция работает как шарм:

 public function ImageToBlackAndWhite($im) { for ($x = imagesx($im); $x--;) { for ($y = imagesy($im); $y--;) { $rgb = imagecolorat($im, $x, $y); $r = ($rgb >> 16) & 0xFF; $g = ($rgb >> 8 ) & 0xFF; $b = $rgb & 0xFF; $gray = ($r + $g + $b) / 3; if ($gray < 0xFF) { imagesetpixel($im, $x, $y, 0xFFFFFF); }else imagesetpixel($im, $x, $y, 0x000000); } } imagefilter($im, IMG_FILTER_NEGATE); }