How do I check if a PNG image has transparent pixels using PHP's GD extension?
-
What kind of image? GIF, PNG-8 or PNG-24? – Salman A Mar 31 '11 at 08:41
-
Since all answers were for PNG, I've edited the question to be PNG-specific. The same question for GIF is here: https://stackoverflow.com/q/48493724 – miken32 Oct 14 '22 at 15:40
8 Answers
I know this is old, but I just found this on the comments of the PHP docs. (link)
Here is the function which determines whether the PNG image contains alpha or not:
<?php function is_alpha_png($fn){ return (ord(@file_get_contents($fn, NULL, NULL, 25, 1)) == 6); } ?>
The color type of PNG image is stored at byte offset 25. Possible values of that 25'th byte is:
- 0 - greyscale
- 2 - RGB
- 3 - RGB with palette
- 4 - greyscale + alpha
- 6 - RGB + alpha
Only works for PNG images though.

- 2,020
- 2
- 18
- 32
-
4This will not work. This value indicates a particular PNG *supports* transparency. If the value indicates it does, you still need to check if it actually *contains* at least a single transparent pixel. – Jongware May 08 '14 at 22:34
-
1@Jongware You're absolutely right. However, I think it's a great way to avoid the overhead of checking every pixel in every image. Depending on your requirements, you can get away with guessing if the image has transparency with this function or you could use it to determine if you need to further process it. – Javier Parra May 16 '14 at 15:21
-
1a solution could be to first check with that `is_alpha_png` function, and only make deep search for transparent pixel if it's true – Alex K Aug 15 '14 at 09:23
-
Not quite solid enough. I had a transparent PNG where the 25th byte was `3`. I will be using @Anubis answer instead as it will be checking for `PLTE` and `tRNS` as well as per http://www.libpng.org/pub/png/book/chapter08.html#png.ch08.div.5.2 – TheStoryCoder Oct 30 '18 at 15:17
-
file_get_contents() will copy the whole file into memory. Why not just only read byte 25? – EricP Sep 10 '19 at 16:11
It doesn't look like you can detect transparency at a glance.
The comments on the imagecolorat
manual page suggest that the resulting integer when working with a true-color image can actually be shifted four times total, with the fourth being the alpha channel (the other three being red, green and blue). Therefore, given any pixel location at $x
and $y
, you can detect alpha using:
$rgba = imagecolorat($im,$x,$y);
$alpha = ($rgba & 0x7F000000) >> 24;
$red = ($rgba & 0xFF0000) >> 16;
$green = ($rgba & 0x00FF00) >> 8;
$blue = ($rgba & 0x0000FF);
An $alpha
of 127 is apparently completely transparent, while zero is completely opaque.
Unfortunately you might need to process every single pixel in the image just to find one that is transparent, and then this only works with true-color images. Otherwise imagecolorat
returns a color index, which you must then look up using imagecolorsforindex
, which actually returns an array with an alpha value.

- 50,943
- 13
- 104
- 142
-
-
2Probably, but this *specific* question is all about GD. Considering your other (dupe) question, you're *already* using GD, so this isn't a problem. – Charles Apr 03 '11 at 15:02
-
What I meant is if there is an other way without GD so you don't need to check every single pixel? – Deniz Zoeteman Apr 03 '11 at 16:20
-
If you have the Imagick extension, the [`getImageAlphaChannel`](http://us2.php.net/manual/en/function.imagick-getimagealphachannel.php) method looks like it could do this. The Imagick extension is non-standard, and I'm not sure if this can be done with plain old vanilla called-through-exec Image Magick. – Charles Apr 03 '11 at 16:26
I know this is an old thread, but in my opinion it needs improvement since walking through a huge png by checking all pixels only to find out it is not transparent is a waste of time. So after some googleing I found Jon Fox's Blog and I improved his code with the help of the W3C PNG Specification further to be reliable, fast and have a minimum on memory imprint:
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);
}

- 481
- 4
- 4
-
Specific mention of PNG palettes with transparency: http://www.libpng.org/pub/png/book/chapter08.html#png.ch08.div.5.2 – TheStoryCoder Oct 30 '18 at 15:18
-
Could it happen that `PLTE` or one of the other keywords would be spanning two chunks of 1024 bytes? Then your script would fail... Otherwise this seems to be made the accepted answer. – TheStoryCoder Oct 30 '18 at 15:26
-
I'm not sure the answer to @TheStoryCoder's question but I've been using this script and it works quite well. The one downside is that this function will return true if the image has a transparency layer. Even if no transparent pixels are visible (or rather seen (seen through ?)). For example if you add alpha transparency to the background of a PNG and then cover that background with a solid black layer. - Which in turn. If you're using GD and trying to keep transparency, this will add some odd transparent pixels/sections to images that fit the prior described properties. – Eric Shoberg Mar 18 '19 at 18:09
-
Correction, I was just saving the image without correctly setting the transparencies. So... Works pretty well. (Couldn't edit my original comment.) – Eric Shoberg Mar 19 '19 at 01:35
It can be done!
I've combined all answers and comments into one function which should be fast & reliable:
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

- 6,482
- 9
- 52
- 80
-
3what if the image is 1px by 10000px.. your function will unnecessarily resize what is still a pretty small image. i suggest you divide the width by the height and check the ratio instead.. or simply check the actual filesize.. also, if there is say a single transparent pixel you might squish it out by compressing the image to 10x10.. you may want to consider making that a bit bigger, and possibly retaining the aspect ratio. other than that, well done! +1 – I wrestled a bear once. Dec 01 '15 at 21:43
Pretty strait forward function, it will check if there is any transparent pixel in the image, if it is, it will return 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;
}

- 3,380
- 5
- 31
- 42
This is how I detect 8-32 bit transparency. It only work with PNG's.
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;
}

- 47,830
- 31
- 106
- 135

- 41
- 2
cronoklee's function is very good, but when I was using it I found a bug. It does not work for images with 8 bit pallet. Here is the fixed variant:
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;
}

- 106
- 1
- 5
Improved cronoklee's function. Removed unnecessary bit shifting for each pixel, reduced false negatives count, added explanation in function description.
/**
* 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;
}
Usage:
hasTransparency( imagecreatefrompng("myfile.png") ); //returns true if img has transparency

- 673
- 10
- 11