what lossy images php image colors png transparency

lossy - Php: reemplace el color base de la imagen transparente png



what is a bmp image (5)

Ampliando la respuesta de SteAp , tuve la necesidad también de poder ajustar la transparencia de cada píxel en función de un color objetivo RGBA.

También solucioné el problema de tener bordes oscuros, que era el resultado del ajuste del color de cada píxel por el nivel alfa original, en lugar de simplemente ajustar el alfa por sí mismo.

// R,G,B = 0-255 range // A = 0.0 to 1.0 range function colorizeBasedOnAplhaChannnel($file, $targetR, $targetG, $targetB, $targetA, $targetName ) { $im_src = imagecreatefrompng($file); $width = imagesx($im_src); $height = imagesy($im_src); $im_dst = imagecreatefrompng($file); // Turn off alpha blending and set alpha flag imagealphablending($im_dst, false); imagesavealpha($im_dst, true); // Fill transparent first (otherwise would result in black background) imagefill($im_dst, 0, 0, imagecolorallocatealpha($im_dst, 0, 0, 0, 127)); for ($x=0; $x<$width; $x++) { for ($y=0; $y<$height; $y++) { $alpha = (imagecolorat( $im_src, $x, $y ) >> 24 & 0xFF); $col = imagecolorallocatealpha( $im_dst, $targetR - (int) ( 1.0 / 255.0 * (double) $targetR ), $targetG - (int) ( 1.0 / 255.0 * (double) $targetG ), $targetB - (int) ( 1.0 / 255.0 * (double) $targetB ), (($alpha - 127) * $targetA) + 127 ); if (false === $col) { die( ''sorry, out of colors...'' ); } imagesetpixel( $im_dst, $x, $y, $col ); } } imagepng( $im_dst, $targetName); imagedestroy($im_dst); }

He buscado mucho y encontré solo algunas soluciones (en google y stackoverflow, así que no marques este como duplicado a menos que realmente haya una pregunta duplicada), pero los problemas son duros. ¿Hay alguna forma adecuada de cambiar el color base de, digamos, la imagen png de forma negra con fondo transparente, pero para preservar los bordes suaves?

Esta es una imagen de ejemplo:

Quiero que se vea así:

pero las soluciones que encontré me dan esta:

Como usaré esto en mi servidor local, solo para uso personal, se agradece cualquier biblioteca php que pueda ayudar a lograr esto.

ACTUALIZAR:

Esta es la función que me da la 3ra imagen:

function LoadPNG($imgname) { $im = imagecreatefrompng ($imgname); imagetruecolortopalette($im,false, 255); $index = imagecolorclosest ( $im, 0,0,0 ); // GET BLACK COLOR imagecolorset($im,$index,0,150,255); // SET COLOR TO BLUE $name = basename($imgname); imagepng($im, getcwd()."/tmp/$name" ); // save image as png imagedestroy($im); } $dir = getcwd()."/img/"; $images = glob($dir."/*.png",GLOB_BRACE); foreach($images as $image) { LoadPNG($image); }

Originalmente, esta función era una solución para imágenes GIF (paleta de 255 colores), así que supongo que es por eso que hay bordes duros. Estoy buscando una solución (mejora de este script) para preservar la transparencia y los bordes suaves de la imagen PNG.

EDICION 2:

He encontrado un enfoque interesante usando html5 canvas y javascript aquí: http://users7.jabry.com/overlord/mug.html

Tal vez alguien pueda tener una idea de cómo traducir esto a PHP si es posible.

NUEVA SOLUCIÓN

En respuestas


Como ya dije, pasé mucho tiempo buscando y lo que encontré hasta ahora es usar html5 canvas, javascript y ajax.

Solo la biblioteca que utilicé es javascript library jQuery, pero es opcional. El código se puede reescribir fácilmente para usar javascript simple.

Cómo funciona:

1) js extrae datos de ajax.php que devuelve una matriz de todos los archivos

2) js luego realiza un bucle a través de la lista de archivos y realiza change(src,color) para cada elemento

3) el change(src,color) función js change(src,color) carga la imagen de la fuente, reemplaza su color y agrega un elemento img a #Cell y lo muestra (para depuración).

4) change() también llama a la función save(src,filename,cname) 5) js function save(src,filename,cname) envía una solicitud ajax con datos de imagen y ajax.php guarda la imagen en el servidor.

Así que aquí está el código:

ajax.php

<?php $r = $_REQUEST; $act = $r[''action'']; if($act == "get_all") { $js = ""; $dir = getcwd()."/img/"; $images = glob($dir."/*.png",GLOB_BRACE); foreach($images as $image) { $name = basename($image); $js[] = $name; } echo json_encode($js); die(); } elseif($act == "save") { $img = $r[''file'']; $name = $r[''name'']; $color = $r[''color'']; $dir = "results/$color"; if(!file_exists($dir) || !is_dir($dir)) mkdir($dir,777,true); $file = $dir."/$name"; file_put_contents($file,file_get_contents("data://".$img)); if(file_exists($file)) echo "Success"; else echo $file; die(); }

index.php (solo html)

<!doctype html> <html> <head> <script src="jquery.js" type="text/javascript"></script> <script src="demo.js" type="text/javascript"></script> </head> <body> <div id="ctrl"> <input type="text" id="color" value="#666666" placeholder="Color in HEX format (ex. #ff0000)" /> <input type="text" id="cname" value="grey" placeholder="Color name (destionation dir name)" /> <button type="button" id="doit">Change</button> </div> <div id="Cell"> </div> </body> </html>

demo.js

$(document).ready(function() { $(document).on("click","#doit",function() { var c = $("#color"); if(c.val() != "") { $("#Cell").html(""); $.post("ajax.php",{ action: "get_all" },function(s) { var images = $.parseJSON(s); $.each(images, function(index, element) { change(images[index], c.val()); }); }); } }); }); function change(src,color) { var myImg = new Image(); myImg.src = "img/"+src; myImg.onload = function() { var canvas = document.createElement("canvas"); var ctx = canvas.getContext("2d"); ctx.drawImage(myImg,0,0); var imgd = ctx.getImageData(0, 0, myImg.width, myImg.height); canvas.height = myImg.height; canvas.width = myImg.width; var new_color = HexToRGB(color); // console.log(imgd) for (i = 0; i <imgd.data.length; i += 4) { imgd.data[i] = new_color.R; imgd.data[i+1] = new_color.G; imgd.data[i+2] = new_color.B; } ctx.putImageData(imgd, 0, 0); var newImage=new Image() newImage.src=canvas.toDataURL("image/png"); $(newImage).css("margin","5px"); $(newImage).attr(''data-title'',src); $("#Cell").append(newImage); var c = $("#cname"); if(c.val() == "") c.val("temp"); save(newImage.src,src, c.val()); }; } function save(src,filename,cname) { $.post("ajax.php", { action: "save", file: src, name: filename, color: cname },function(s) { console.log(s); }) } function HexToRGB(Hex) { var Long = parseInt(Hex.replace(/^#/, ""), 16); return { R: (Long >>> 16) & 0xff, G: (Long >>> 8) & 0xff, B: Long & 0xff }; }

Lo he probado, para volver a colorear y guardar 420 imágenes de 24x24, tomó menos de 10 segundos (en el servidor local) (420 llamadas async ajax). Una vez que las imágenes originales se almacenan en caché, termina mucho más rápido. La calidad de la imagen permanece igual que la original.

Una vez más, esta solución es para mi uso personal, por lo que el código es bastante no administrado y estoy seguro de que se puede mejorar, pero aquí va - como es, funciona.


Este código no ejemplifica el problema, pero transforma colores como este:

Utiliza el canal ALPHA de una imagen para determinar el color. Para otros resultados, simplemente juega con imagecolorallocatealpha() :

function colorizeBasedOnAplhaChannnel( $file, $targetR, $targetG, $targetB, $targetName ) { $im_src = imagecreatefrompng( $file ); $width = imagesx($im_src); $height = imagesy($im_src); $im_dst = imagecreatefrompng( $file ); // Note this: // Let''s reduce the number of colors in the image to ONE imagefilledrectangle( $im_dst, 0, 0, $width, $height, 0xFFFFFF ); for( $x=0; $x<$width; $x++ ) { for( $y=0; $y<$height; $y++ ) { $alpha = ( imagecolorat( $im_src, $x, $y ) >> 24 & 0xFF ); $col = imagecolorallocatealpha( $im_dst, $targetR - (int) ( 1.0 / 255.0 * $alpha * (double) $targetR ), $targetG - (int) ( 1.0 / 255.0 * $alpha * (double) $targetG ), $targetB - (int) ( 1.0 / 255.0 * $alpha * (double) $targetB ), $alpha ); if ( false === $col ) { die( ''sorry, out of colors...'' ); } imagesetpixel( $im_dst, $x, $y, $col ); } } imagepng( $im_dst, $targetName); imagedestroy($im_dst); } unlink( dirname ( __FILE__ ) . ''/newleaf.png'' ); unlink( dirname ( __FILE__ ) . ''/newleaf1.png'' ); unlink( dirname ( __FILE__ ) . ''/newleaf2.png'' ); $img = dirname ( __FILE__ ) . ''/leaf.png''; colorizeBasedOnAplhaChannnel( $img, 0, 0, 0xFF, ''newleaf1.png'' ); colorizeBasedOnAplhaChannnel( $img, 0xFF, 0, 0xFF, ''newleaf2.png'' ); ?> Original <img src="leaf.png"> <br /> <img src="newleaf1.png"> <br /> <img src="newleaf2.png">


La tercera imagen no se ve bien, porque imagetruecolortopalette($im,true, 255); hace una imagen fea:

Dado que la segunda imagen no se ve bien, la tercera tampoco puede verse hermosa.

Código:

<?php unlink( dirname ( __FILE__ ) . ''/newleaf.png'' ); unlink( dirname ( __FILE__ ) . ''/newleaf1.png'' ); function LoadPNG( $imgname ) { $im = imagecreatefrompng ($imgname); imagetruecolortopalette($im,true, 255); imagepng($im, ''newleaf1.png'' ); // save image as png $index = imagecolorclosest ( $im, 0,0,0 ); // GET BLACK COLOR imagecolorset($im,$index,0,150,255); // SET COLOR TO BLUE $name = basename($imgname); imagepng($im, ''newleaf.png'' ); // save image as png imagedestroy($im); } $img = dirname ( __FILE__ ) . ''/leaf.png''; LoadPNG( $img ); ?> Original <img src="leaf.png"> <br />After make truecolortopalette($im,true, 255); <img src="newleaf1.png"> <br />Thus.. <img src="newleaf.png">


SteAp el código aceptado de SteAp como punto de partida (ya que con él no SteAp lograr transparencia, solo un fondo blanco), adapté dicho código y el resultado es el siguiente:

<?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:$x y:$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 = 0; $targetGreen = 180; $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 />

esta variación cambia TODOS los colores al color elegido (no solo negro, un IF simple puede resolver el problema - descomenta 3 líneas indicadas en función y lo lograras)

Para fines ilustrativos, en este caso, se utilizó la siguiente imagen (porque leaf.png es monocromático, con transparencia):