Как проверить прозрачность изображения с помощью GD?
Как проверить, имеет ли изображение прозрачные пиксели с помощью библиотеки GD php?
7 answers
Не похоже, что вы можете определить прозрачность с первого взгляда.
Комментарии на странице руководства 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
, который фактически возвращает массив с альфа-значением.
Я знаю, что это старое, но я только что нашел это в комментариях к документам 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.
Это можно сделать!
Я объединил все ответы и комментарии в одну функцию, которая должна быть быстрой и надежной:
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
Довольно прямая функция, она проверит, есть ли на изображении какой-либо прозрачный пиксель, если он есть, она вернет 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;
}
Вот как я определяю 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;
}
Я знаю, что это старая тема, но, на мой взгляд, она нуждается в улучшении, поскольку просмотр огромного png, проверяя все пиксели только для того, чтобы выяснить, что он непрозрачен, - пустая трата времени. Итак, после некоторого поиска в Google я нашел Блог Джона Фокса и улучшил его код с помощью Спецификации 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);
}
Функция 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;
}