¿Se puede conservar la transparencia de la imagen PNG cuando se utiliza imagecopyresampled GDlib de PHP?

StackOverflow https://stackoverflow.com/questions/32243

Pregunta

El siguiente fragmento de código PHP utiliza GD para cambiar el tamaño de un PNG cargado en el navegador a 128x128.Funciona muy bien, excepto que las áreas transparentes de la imagen original se reemplazan con un color sólido: negro en mi caso.

A pesar de imagesavealpha está configurado, algo no está del todo bien.

¿Cuál es la mejor manera de preservar la transparencia en la imagen remuestreada?

$uploadTempFile = $myField[ 'tmp_name' ]
list( $uploadWidth, $uploadHeight, $uploadType ) 
  = getimagesize( $uploadTempFile );

$srcImage = imagecreatefrompng( $uploadTempFile );    
imagesavealpha( $targetImage, true );

$targetImage = imagecreatetruecolor( 128, 128 );
imagecopyresampled( $targetImage, $srcImage, 
                    0, 0, 
                    0, 0, 
                    128, 128, 
                    $uploadWidth, $uploadHeight );

imagepng(  $targetImage, 'out.png', 9 );
¿Fue útil?

Solución

imagealphablending( $targetImage, false );
imagesavealpha( $targetImage, true );

lo hizo por mí.Gracias ceejayoz.

tenga en cuenta que la imagen de destino necesita la configuración alfa, no la imagen de origen.

Editar:código de reemplazo completo.Vea también las respuestas a continuación y sus comentarios.No se garantiza que esto sea perfecto de ninguna manera, pero cumplió con mis necesidades en ese momento.

$uploadTempFile = $myField[ 'tmp_name' ]
list( $uploadWidth, $uploadHeight, $uploadType ) 
  = getimagesize( $uploadTempFile );

$srcImage = imagecreatefrompng( $uploadTempFile ); 

$targetImage = imagecreatetruecolor( 128, 128 );   
imagealphablending( $targetImage, false );
imagesavealpha( $targetImage, true );

imagecopyresampled( $targetImage, $srcImage, 
                    0, 0, 
                    0, 0, 
                    128, 128, 
                    $uploadWidth, $uploadHeight );

imagepng(  $targetImage, 'out.png', 9 );

Otros consejos

¿Por qué complicas tanto las cosas?Lo siguiente es lo que uso y hasta ahora me ha funcionado.

$im = ImageCreateFromPNG($source);
$new_im = imagecreatetruecolor($new_size[0],$new_size[1]);
imagecolortransparent($new_im, imagecolorallocate($new_im, 0, 0, 0));
imagecopyresampled($new_im,$im,0,0,0,0,$new_size[0],$new_size[1],$size[0],$size[1]);

Creo que esto debería funcionar:

$srcImage = imagecreatefrompng($uploadTempFile);
imagealphablending($srcImage, false);
imagesavealpha($srcImage, true);

editar: Alguien en los documentos PHP afirma imagealphablending debe ser verdadero, no falso.YMMV.

Una adición que podría ayudar a algunas personas:

Es posible alternar la combinación alfabética de la imagen mientras se crea la imagen.En el caso específico que necesitaba esto, quería combinar algunos PNG semitransparentes sobre un fondo transparente.

Primero configura imagealphablending en falso y rellena la imagen en color verdadero recién creada con un color transparente.Si imagealphablending fuera cierto, no pasaría nada porque el relleno transparente se fusionaría con el fondo negro predeterminado y daría como resultado negro.

Luego cambia imagealphablending a verdadero y agrega algunas imágenes PNG al lienzo, dejando parte del fondo visible (es decir,no llenar toda la imagen).

El resultado es una imagen con un fondo transparente y varias imágenes PNG combinadas.

He creado una función para cambiar el tamaño de imágenes como JPEG/GIF/PNG con copyimageresample y las imágenes PNG aún mantienen su transparencia:

$myfile=$_FILES["youimage"];

function ismyimage($myfile) {
    if((($myfile["type"] == "image/gif") || ($myfile["type"] == "image/jpg") || ($myfile["type"] == "image/jpeg") || ($myfile["type"] == "image/png")) && ($myfile["size"] <= 2097152 /*2mb*/) ) return true; 
    else return false;
}

function upload_file($myfile) {         
    if(ismyimage($myfile)) {
        $information=getimagesize($myfile["tmp_name"]);
        $mywidth=$information[0];
        $myheight=$information[1];

        $newwidth=$mywidth;
        $newheight=$myheight;
        while(($newwidth > 600) || ($newheight > 400 )) {
            $newwidth = $newwidth-ceil($newwidth/100);
            $newheight = $newheight-ceil($newheight/100);
        } 

        $files=$myfile["name"];

        if($myfile["type"] == "image/gif") {
            $tmp=imagecreatetruecolor($newwidth,$newheight);
            $src=imagecreatefromgif($myfile["tmp_name"]);
            imagecopyresampled($tmp, $src, 0, 0, 0, 0, $newwidth, $newheight, $mywidth, $myheight);
            $con=imagegif($tmp, $files);
            imagedestroy($tmp);
            imagedestroy($src);
            if($con){
                return true;
            } else {
                return false;
            }
        } else if(($myfile["type"] == "image/jpg") || ($myfile["type"] == "image/jpeg") ) {
            $tmp=imagecreatetruecolor($newwidth,$newheight);
            $src=imagecreatefromjpeg($myfile["tmp_name"]); 
            imagecopyresampled($tmp, $src, 0, 0, 0, 0, $newwidth, $newheight, $mywidth, $myheight);
            $con=imagejpeg($tmp, $files);
            imagedestroy($tmp);
            imagedestroy($src);
            if($con) {  
                return true;
            } else {
                return false;
            }
        } else if($myfile["type"] == "image/png") {
            $tmp=imagecreatetruecolor($newwidth,$newheight);
            $src=imagecreatefrompng($myfile["tmp_name"]);
            imagealphablending($tmp, false);
            imagesavealpha($tmp,true);
            $transparent = imagecolorallocatealpha($tmp, 255, 255, 255, 127);
            imagefilledrectangle($tmp, 0, 0, $newwidth, $newheight, $transparent); 
            imagecopyresampled($tmp, $src, 0, 0, 0, 0, $newwidth, $newheight, $mywidth, $myheight);
            $con=imagepng($tmp, $files);
            imagedestroy($tmp);
            imagedestroy($src);
            if($con) {
                return true;
            } else {
                return false;
            }
        }   
    } else
          return false;
}

Supongo que esto podría funcionar:

$uploadTempFile = $myField[ 'tmp_name' ]
list( $uploadWidth, $uploadHeight, $uploadType ) 
  = getimagesize( $uploadTempFile );

$srcImage = imagecreatefrompng( $uploadTempFile );

$targetImage = imagecreatetruecolor( 128, 128 );

$transparent = imagecolorallocate($targetImage,0,255,0);
imagecolortransparent($targetImage,$transparent);
imagefilledrectangle($targetImage,0,0,127,127,$transparent);

imagecopyresampled( $targetImage, $srcImage, 
                    0, 0, 
                    0, 0, 
                    128, 128, 
                    $uploadWidth, $uploadHeight );

imagepng(  $targetImage, 'out.png', 9 );

La desventaja es que la imagen será despojada de cada 100% de píxeles verdes.De todos modos, espero que ayude :)

Al volver a calificar la preservación de la transparencia, entonces sí, como se indica en otras publicaciones, imagesavealpha() debe establecerse en verdadero, para usar la bandera alfa, imagealphablend() debe configurarse en falso, de lo contrario no funciona.

También vi dos cosas menores en tu código:

  1. No necesitas llamar getimagesize() para obtener el ancho/alto para imagecopyresmapled()
  2. El $uploadWidth y $uploadHeight debiera ser -1 el valor, ya que las coordenadas comienzan en 0 y no 1, por lo que los copiaría en un píxel vacío.Reemplazándolo con: imagesx($targetImage) - 1 y imagesy($targetImage) - 1, relativamente debería funcionar :)

Aquí está mi código de prueba total.Esto funciona para mi

$imageFileType = pathinfo($_FILES["image"]["name"], PATHINFO_EXTENSION);
$filename = 'test.' . $imageFileType;
move_uploaded_file($_FILES["image"]["tmp_name"], $filename);

$source_image = imagecreatefromjpeg($filename);

$source_imagex = imagesx($source_image);
$source_imagey = imagesy($source_image);

$dest_imagex = 400;
$dest_imagey = 600;
$dest_image = imagecreatetruecolor($dest_imagex, $dest_imagey);

imagecopyresampled($dest_image, $source_image, 0, 0, 0, 0, $dest_imagex, $dest_imagey, $source_imagex, $source_imagey);

imagesavealpha($dest_image, true);
$trans_colour = imagecolorallocatealpha($dest_image, 0, 0, 0, 127);
imagefill($dest_image, 0, 0, $trans_colour);

imagepng($dest_image,"test1.png",1);

Preste atención a la imagen de origen. width y height valores que se pasan a imagecopyresampled función.Si son más grandes que el tamaño real de la imagen de origen, el resto del área de la imagen se llenará de color negro.

Combiné las respuestas de ceejayoz y Cheekysoft, lo que me dio el mejor resultado.Sin imagealphablend() e imagesavealpha() la imagen no es clara:

$img3 = imagecreatetruecolor(128, 128);
imagecolortransparent($img3, imagecolorallocate($img3, 0, 0, 0));
imagealphablending( $img3, false );
imagesavealpha( $img3, true );
imagecopyresampled($img3, $srcImage, 0, 0, 0, 0, 128, 128, $uploadWidth, $uploadHeight);
imagepng($img3, 'filename.png', 9);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top