Как проверить, прозрачно ли изображение с помощью GD? - PullRequest
12 голосов
/ 31 марта 2011

Как проверить, есть ли у изображения прозрачные пиксели в библиотеке php GD?

Ответы [ 8 ]

14 голосов
/ 06 января 2012

Я знаю, что это старый, но я только что нашел это в комментариях к документации по PHP. ( ссылка )

Вот функция, которая определяет, содержит ли изображение PNG альфа:

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

Тип цвета изображения PNG сохраняется со смещением байта 25. Возможные значения этого 25-го байта:

  • 0 - оттенки серого
  • 2 - RGB
  • 3 - RGB с палитрой
  • 4 - оттенки серого + альфа
  • 6 - RGB + альфа

Хотя работает только для изображений PNG.

5 голосов
/ 01 апреля 2015

Это можно сделать!

Я объединил все ответы и комментарии в одну функцию, которая должна быть быстрой и надежной:

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
5 голосов
/ 31 марта 2011

Не похоже, что вы можете сразу определить прозрачность.

Комментарии на imagecolorat странице справки предполагают, что результирующее целое число при работе с изображением в истинном цвете может быть смещено в четыре раза, причем четвертый является альфа-каналом (остальные три быть красным, зеленым и синим). Поэтому, учитывая любое положение пикселя в $x и $y, вы можете обнаружить альфа, используя:

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

$alpha из 127, по-видимому, полностью прозрачен, а ноль - полностью непрозрачен.

К сожалению, вам может понадобиться обработать каждый пиксель на изображении, чтобы найти прозрачный, и тогда это работает только с изображениями в истинном цвете. В противном случае imagecolorat возвращает индекс цвета, который затем необходимо найти, используя imagecolorsforindex, который фактически возвращает массив со значением альфа.

3 голосов
/ 16 мая 2017

Я знаю, что это старая ветка, но, на мой взгляд, она нуждается в улучшении, поскольку проход через огромный png путем проверки всех пикселей только для того, чтобы выяснить, что он не прозрачен, является пустой тратой времени. Поэтому после некоторого поиска я нашел Блог Джона Фокса и улучшил его код с помощью спецификации 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);
}
2 голосов
/ 10 апреля 2013

Довольно прямолинейная функция вперед, она проверит, есть ли прозрачный пиксель на изображении, если это так, она вернет 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;
}
1 голос
/ 09 сентября 2018

Так я обнаруживаю 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;
}
0 голосов
/ 22 февраля 2019

Улучшена функция хронокли.Убрано ненужное смещение бит для каждого пикселя, уменьшено количество ложных негативов, добавлено объяснение в описании функции.

/**
 * 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
0 голосов
/ 04 января 2018
Функция

cronoklee очень хороша, но когда я ее использовал, я обнаружил ошибку. Это не работает для изображений с 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;
}
...