如何使用GD检查图像是否具有透明度?

Hap*_*per 13 php gd image-processing

如何使用php的GD库检查图像是否具有透明像素?

Jav*_*rra 14

我知道这是旧的,但我刚刚在PHP文档的评论中找到了这个.(链接)

以下是确定PNG图像是否包含alpha的函数:

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

PNG图像的颜色类型存储在字节偏移25处.该第25个字节的可能值为:

  • 0 - 灰度
  • 2 - RGB
  • 3 - 带调色板的RGB
  • 4 - 灰度+ alpha
  • 6 - RGB + alpha

仅适用于PNG图像.

  • 这不行.此值表示特定的PNG*支持*透明度.如果值指示它,您仍然需要检查它是否实际*包含*至少一个透明像素. (3认同)

Cha*_*les 5

看起来您不能一目了然地检测透明度.

imagecolorat手册页上的注释表明,使用真彩色图像时得到的整数实际上可以总共移动四次,第四个是alpha通道(其他三个是红色,绿色和蓝色).因此,在任何给定的像素位置$x$y,您可以使用检测阿尔法:

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

一个$alpha127显然是完全透明的,而零是完全不透明的.

不幸的是,您可能需要处理图像中的每个像素,只是为了找到一个透明的像素,然后这只适用于真彩色图像.否则imagecolorat返回一个颜色索引,然后你必须使用它imagecolorsforindex,它实际上返回一个带有alpha值的数组.

  • 可能,但这个*特定*问题都是关于GD的.考虑到你的其他(欺骗)问题,你已经*使用GD了,所以这不是问题. (2认同)

cro*_*lee 5

可以办到!

我将所有答案和评论合并到一个应该快速可靠的功能中:

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
Run Code Online (Sandbox Code Playgroud)

  • 如果图像是1px乘10000px怎么办...你的功能将不必要地调整仍然是一个非常小的图像.我建议你将宽度除以高度,然后检查比例..或者只是检查实际的文件大小..还有,如果说有一个透明像素,你可以通过将图像压缩到10x10来压缩它...你可能想要考虑使其更大,并可能保持纵横比.除此之外,干得好!+1 (3认同)

Anu*_*bis 5

我知道这是一个旧线程,但在我看来它需要改进,因为通过检查所有像素来浏览一个巨大的 png 只是发现它不透明是浪费时间。因此,经过一番谷歌搜索后,我找到了Jon Fox 的博客,并在W3C PNG 规范的帮助下改进了他的代码,使其更加可靠、快速且内存印记最少:

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);
}
Run Code Online (Sandbox Code Playgroud)