How to check if an image has transparency using GD?

后端 未结 8 1378
耶瑟儿~
耶瑟儿~ 2020-12-09 18:48

How do I check if an image has transparent pixels with php\'s GD library?

相关标签:
8条回答
  • 2020-12-09 19:20

    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
    
    0 讨论(0)
  • 2020-12-09 19:23

    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);
    }
    
    0 讨论(0)
提交回复
热议问题