如何使用php的GD库检查图像是否具有透明像素?
答案 0 :(得分:14)
我知道这是旧的,但我刚刚在PHP文档的评论中找到了这个。 (link)
以下是确定PNG图像是否包含alpha的函数:
<?php function is_alpha_png($fn){ return (ord(@file_get_contents($fn, NULL, NULL, 25, 1)) == 6); } ?>
PNG图像的颜色类型存储在字节偏移25处。该第25个字节的可能值为:
- 0 - greyscale
- 2 - RGB
- 3 - 带调色板的RGB
- 4 - greyscale + alpha
- 6 - RGB + alpha
仅适用于PNG图像。
答案 1 :(得分:5)
看起来您不能一目了然地检测透明度。
The comments on the imagecolorat
manual page建议使用真彩色图像时得到的整数实际上可以总共移动四次,第四个是alpha通道(其他三个是红色,绿色和蓝色)。因此,给定$x
和$y
处的任何像素位置,您可以使用以下方法检测alpha:
$rgba = imagecolorat($im,$x,$y);
$alpha = ($rgba & 0x7F000000) >> 24;
$red = ($rgba & 0xFF0000) >> 16;
$green = ($rgba & 0x00FF00) >> 8;
$blue = ($rgba & 0x0000FF);
127的$alpha
显然是完全透明的,而零是完全不透明的。
不幸的是,您可能需要在图像中处理每个像素,只是为了找到一个透明的像素,然后这只适用于真彩色图像。否则imagecolorat
会返回一个颜色索引,然后您必须使用imagecolorsforindex
查找颜色索引,这实际上会返回一个带有alpha值的数组。
答案 2 :(得分:5)
可以做到!
我已将所有答案和评论合并到一个功能中,该功能应该是快速的&amp;可靠:
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
答案 3 :(得分:3)
我知道这是一个旧线程,但在我看来,它需要改进,因为通过检查所有像素只是为了发现它不透明是通过一个巨大的png是浪费时间。因此,经过一些谷歌搜索后,我找到了Jon Fox's Blog,并且我在W3C PNG Specification的帮助下改进了他的代码,进一步提高了可靠性,快速性并且内存印记最少:
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);
}
答案 4 :(得分:2)
漂亮的前进功能,它会检查图像中是否有透明像素,如果是,则返回true。
$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;
}
答案 5 :(得分:1)
这就是我检测8-32位透明性的方式。它仅适用于PNG。
function detect_transparency($file){
if(!@getimagesize($file)) return false;
if(ord(file_get_contents($file, false, null, 25, 1)) & 4) return true;
$content = file_get_contents($file);
if(stripos($content,'PLTE') !== false && stripos($content, 'tRNS') !== false) return true;
return false;
}
答案 6 :(得分:0)
cronoklee的功能非常好,但是当我使用它时,我发现了一个bug。它不适用于8位托盘的图像。以下是固定变体:
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;
}
答案 7 :(得分:0)
改善了cronoklee的功能。消除了每个像素不必要的移位,减少了假阴性计数,在功能描述中增加了解释。
/**
* Estimates, if image has pixels with transparency. It shrinks image to 64 times smaller
* size, if necessary, and searches for the first pixel with non-zero alpha byte.
* If image has 1% opacity, it will be detected. If any block of 8x8 pixels has at least
* one semi-opaque pixel, the block will trigger positive result. There are still cases,
* where image with hardly noticeable transparency will be reported as non-transparent,
* but it's almost always safe to fill such image with monotonic background.
*
* Icons with size <= 64x64 (or having square <= 4096 pixels) are fully scanned with
* absolutely reliable result.
*
* @param resource $image
* @return bool
*/
function hasTransparency ($image): bool {
if (!is_resource($image)) {
throw new \InvalidArgumentException("Image resource expected. Got: " . gettype($image));
}
$shrinkFactor = 64.0;
$minSquareToShrink = 64.0 * 64.0;
$width = imagesx($image);
$height = imagesy($image);
$square = $width * $height;
if ($square <= $minSquareToShrink) {
[$thumb, $thumbWidth, $thumbHeight] = [$image, $width, $height];
} else {
$thumbSquare = $square / $shrinkFactor;
$thumbWidth = (int) round($width / sqrt($shrinkFactor));
$thumbWidth < 1 and $thumbWidth = 1;
$thumbHeight = (int) round($thumbSquare / $thumbWidth);
$thumb = imagecreatetruecolor($thumbWidth, $thumbHeight);
imagealphablending($thumb, false);
imagecopyresized($thumb, $image, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $width, $height);
}
for ($i = 0; $i < $thumbWidth; $i++) {
for ($j = 0; $j < $thumbHeight; $j++) {
if (imagecolorat($thumb, $i, $j) & 0x7F000000) {
return true;
}
}
}
return false;
}
hasTransparency( imagecreatefrompng("myfile.png") ); //returns true if img has transparency