2011-03-31 9 views

Respuesta

4

No parece que pueda detectar la transparencia de un vistazo.

The comments on the imagecolorat manual page sugieren que el entero resultante cuando se trabaja con una imagen de verdadero color se puede desplazar cuatro veces en total, siendo el cuarto canal alfa (los otros tres son rojo, verde y azul). Por lo tanto, dado cualquier ubicación de píxel en $x y $y, puede detectar alfa usando:

$rgba = imagecolorat($im,$x,$y); 
$alpha = ($rgba & 0x7F000000) >> 24; 
$red = ($rgba & 0xFF0000) >> 16; 
$green = ($rgba & 0x00FF00) >> 8; 
$blue = ($rgba & 0x0000FF); 

Un $alpha de 127 es al parecer completamente transparente, mientras que el cero es completamente opaca.

Lamentablemente es posible que necesite procesar cada píxel en la imagen solo para encontrar uno que sea transparente, y luego esto solo funciona con imágenes de color verdadero. De lo contrario, imagecolorat devuelve un índice de color, que luego debe buscar utilizando imagecolorsforindex, que en realidad devuelve una matriz con un valor alfa.

+0

¿hay alguna otra forma sin GD? –

+2

Probablemente, pero esta pregunta * específica * tiene que ver con GD. Teniendo en cuenta su otra pregunta (engaños), ya * usa * GD, por lo que no es un problema. – Charles

+0

Lo que quise decir es si hay otra forma sin GD, por lo que no es necesario que compruebe cada píxel por separado. –

14

Sé que esto es viejo, pero acabo de encontrar esto en los comentarios de los documentos de PHP. (link)

Aquí es la función que determina si la imagen PNG contiene alfa o no:

<?php 
    function is_alpha_png($fn){ 
     return (ord(@file_get_contents($fn, NULL, NULL, 25, 1)) == 6); 
    } 
?> 

El tipo de color de la imagen PNG de se almacena en el byte compensado 25. Los valores posibles de que 25' simo byte es:

  • 0 - escala de grises
  • 2 - RGB
  • 3 - RGB con palett e
  • 4 - en escala de grises con canales alfa
  • 6 - RGB + alfa

sólo funciona para las imágenes PNG sin embargo.

+2

Esto no funcionará. Este valor indica que un PNG * particular admite * transparencia. Si el valor indica que sí, aún debe verificar si en realidad * contiene * al menos un único píxel transparente. – usr2564301

+1

@Jongware Tienes toda la razón. Sin embargo, creo que es una gran manera de evitar la sobrecarga de verificar cada píxel en cada imagen. Dependiendo de sus requisitos, puede evitar conjeturar si la imagen tiene transparencia con esta función o podría usarla para determinar si necesita procesarla más. –

+1

una solución podría ser verificar primero con esa función 'is_alpha_png', y solo hacer una búsqueda profunda de píxeles transparentes si es verdadero –

2

Bonita función de avance hacia adelante, comprobará si hay algún píxel transparente en la imagen, si lo está, devolverá verdadero.

$im = imagecreatefrompng('./transparent.png'); 
if(check_transparent($im)) { 
    echo 'DA'; 
} 
else { 
    echo 'NU'; 
} 

function check_transparent($im) { 

    $width = imagesx($im); // Get the width of the image 
    $height = imagesy($im); // Get the height of the image 

    // We run the image pixel by pixel and as soon as we find a transparent pixel we stop and return true. 
    for($i = 0; $i < $width; $i++) { 
     for($j = 0; $j < $height; $j++) { 
      $rgba = imagecolorat($im, $i, $j); 
      if(($rgba & 0x7F000000) >> 24) { 
       return true; 
      } 
     } 
    } 

    // If we dont find any pixel the function will return false. 
    return false; 
} 
4

Se puede hacer!

He combinado todas las respuestas y comentarios en una sola función que debe ser rápido & fiable:

function hasAlpha($imgdata) { 
    $w = imagesx($imgdata); 
    $h = imagesy($imgdata); 

    if($w>50 || $h>50){ //resize the image to save processing if larger than 50px: 
     $thumb = imagecreatetruecolor(10, 10); 
     imagealphablending($thumb, FALSE); 
     imagecopyresized($thumb, $imgdata, 0, 0, 0, 0, 10, 10, $w, $h); 
     $imgdata = $thumb; 
     $w = imagesx($imgdata); 
     $h = imagesy($imgdata); 
    } 
    //run through pixels until transparent pixel is found: 
    for($i = 0; $i<$w; $i++) { 
     for($j = 0; $j < $h; $j++) { 
      $rgba = imagecolorat($imgdata, $i, $j); 
      if(($rgba & 0x7F000000) >> 24) return true; 
     } 
    } 
    return false; 
} 

//SAMPLE USE: 
hasAlpha(imagecreatefrompng("myfile.png")); //returns true if img has transparency 
+0

qué ocurre si la imagen es de 1px por 10000px ... su función cambiará innecesariamente el tamaño de una imagen bastante pequeña. sugiero que divida el ancho por la altura y verifique la proporción en su lugar ... o simplemente verifique el tamaño real del archivo. También, si hay, por ejemplo, un único píxel transparente, puede aplastarlo comprimiendo la imagen a 10x10. Es posible que desee para considerar hacerlo un poco más grande, y posiblemente reteniendo la relación de aspecto. aparte de eso, ¡bien hecho! +1 –

0

Sé que esto es un hilo viejo, pero en mi opinión, ya que las necesidades de mejoras caminando a través de un enorme png al comprobar todos los píxeles solo para descubrir que no es transparente es una pérdida de tiempo.Así que después de algún Googleing encontré Jon Fox's Blog y mejoró su código con la ayuda de la W3C PNG Specification adicionalmente que sea fiable, rápido y tener un mínimo de huella de memoria: la función

function IsTransparentPng($File){ 
    //32-bit pngs 
    //4 checks for greyscale + alpha and RGB + alpha 
    if ((ord(file_get_contents($File, false, null, 25, 1)) & 4)>0){ 
     return true; 
    } 
    //8 bit pngs 
    $fd=fopen($File, 'r'); 
    $continue=true; 
    $plte=false; 
    $trns=false; 
    $idat=false; 
    while($continue===true){ 
     $continue=false; 
     $line=fread($fd, 1024); 
     if ($plte===false){ 
      $plte=(stripos($line, 'PLTE')!==false); 
     } 
     if ($trns===false){ 
      $trns=(stripos($line, 'tRNS')!==false); 
     } 
     if ($idat===false){ 
      $idat=(stripos($line, 'IDAT')!==false); 
     } 
     if ($idat===false and !($plte===true and $trns===true)){ 
      $continue=true; 
     } 
    } 
    fclose($fd); 
    return ($plte===true and $trns===true); 
} 
0

de cronoklee es muy buena, pero cuando yo estaba usando encontré un error. No funciona para imágenes con pallet de 8 bits. Aquí está la variante fija:

public function hasAlpha($imgdata) 
{ 
    $w = imagesx($imgdata); 
    $h = imagesy($imgdata); 

    if($w>100 || $h>100){ //resize the image to save processing 
     $thumb = imagecreatetruecolor(100, 100); 
     imagealphablending($thumb, FALSE); 
     imagecopyresized($thumb, $imgdata, 0, 0, 0, 0, 100, 100, $w, $h); 
     $imgdata = $thumb; 
     $w = imagesx($imgdata); 
     $h = imagesy($imgdata); 
    } 
    //run through pixels until transparent pixel is found: 
    for($i = 0; $i<$w; $i++) { 
     for($j = 0; $j < $h; $j++) { 
      $ci = imagecolorat($imgdata, $i, $j); 
      $rgba = imagecolorsforindex($imgdata, $ci); 
      if($rgba['alpha']) { return true; } 
     } 
    } 
    return false; 
} 
Cuestiones relacionadas