Чи можна зберегти прозорість зображення у форматі PNG, використовуючи зображення GDlib PHP на прикладі?


101

Наведений нижче фрагмент коду PHP використовує GD для зміни розміру завантаженого у браузер PNG до 128x128. Це чудово, за винятком того, що прозорі області в оригінальному зображенні замінюються суцільним кольоровим - чорним у моєму випадку.

Хоча imagesavealphaце встановлено, щось не зовсім правильно.

Який найкращий спосіб зберегти прозорість у повторно обрамленому зображенні?

$uploadTempFile = $myField[ 'tmp_name' ]
list( $uploadWidth, $uploadHeight, $uploadType ) 
  = getimagesize( $uploadTempFile );

$srcImage = imagecreatefrompng( $uploadTempFile );    
imagesavealpha( $targetImage, true );

$targetImage = imagecreatetruecolor( 128, 128 );
imagecopyresampled( $targetImage, $srcImage, 
                    0, 0, 
                    0, 0, 
                    128, 128, 
                    $uploadWidth, $uploadHeight );

imagepng(  $targetImage, 'out.png', 9 );

Відповіді:


199
imagealphablending( $targetImage, false );
imagesavealpha( $targetImage, true );

зробив це для мене. Дякую ceejayoz.

Зауважте, цільовому зображенню потрібні параметри альфа, а не вихідне зображення.

Редагувати: повний код заміни. Дивіться також відповіді нижче та їх коментарі. Це не гарантовано є ідеальним в будь-якому випадку, але все ж таки досяг моїх потреб.

$uploadTempFile = $myField[ 'tmp_name' ]
list( $uploadWidth, $uploadHeight, $uploadType ) 
  = getimagesize( $uploadTempFile );

$srcImage = imagecreatefrompng( $uploadTempFile ); 

$targetImage = imagecreatetruecolor( 128, 128 );   
imagealphablending( $targetImage, false );
imagesavealpha( $targetImage, true );

imagecopyresampled( $targetImage, $srcImage, 
                    0, 0, 
                    0, 0, 
                    128, 128, 
                    $uploadWidth, $uploadHeight );

imagepng(  $targetImage, 'out.png', 9 );

5
FIY, це потрібно зробити після створення цільового зображення. У цьому випадку це буде після imagecreatetruecolor.
RisingSun

Цікаво, чому тут alphablending = falseважливо? Документ констатує це ... "Ви повинні скасувати alfanding ( imagealphablending($im, false)), щоб використовувати його."
вісімдесят п'ятого

2
Ця відповідь не тільки є правильною та корисною, вона особливо корисна, оскільки перший коментар (на момент написання) до документів PHP imagecreatefrompng()пропонує запропонувати imagealphablendingїї встановити true, що явно неправильно. Велике спасибі
spikyjt

3
Це рішення, в моєму випадку, GD працює нормально ТОЛЬКО, якщо PNG має "регулярну" область прозорості, як оточуюча прозора область, якщо вона має складну область, як, наприклад, із внутрішніми частинами зображення з прозорістю, вона завжди виходить з ладу і ставить чорний фон , наприклад, це зображення виходить з ладу: seomofo.com/downloads/new-google-logo-knockoff.png . Хтось може спробувати це і підтвердити?
aesede

2
Схоже, це не працює з деякими прозорими png-файлами. Я спробував створити зображення з jpg та скопіювати прозорий png всередину. Як вказує aesede, результат - чорний квадрат.
RubbelDeCatc

21

Чому ти ускладнюєш справи? далі - те, що я використовую, і поки що це зробило роботу для мене.

$im = ImageCreateFromPNG($source);
$new_im = imagecreatetruecolor($new_size[0],$new_size[1]);
imagecolortransparent($new_im, imagecolorallocate($new_im, 0, 0, 0));
imagecopyresampled($new_im,$im,0,0,0,0,$new_size[0],$new_size[1],$size[0],$size[1]);

Не вийшло, я все одно отримую чорний фон із цим зображенням: seomofo.com/downloads/new-google-logo-knockoff.png
aesede

Випробовували обидва рішення: ваше та вищезазначене з більш ніж 150 голосами. Ваші рішення чудово підходять для GIF. Вищезгадане найкраще працює з файлами PNG, тоді як ваше рішення втрачає функцію згладжування того, що ви найкраще бачите у створенні мініатюр (виглядає блокованим, нерівним).
Джоні

11

Я вважаю, що це повинно зробити трюк:

$srcImage = imagecreatefrompng($uploadTempFile);
imagealphablending($srcImage, false);
imagesavealpha($srcImage, true);

редагувати: хтось із претензій на документи PHP imagealphablendingповинен бути правдивим, а не хибним. YMMV.


2
Використовуючи imagealphablendingабо істинну, або хибну, я завжди отримую чорний фон.
aesede

PHP7 - Робота для мене
Єгонатан

Пограли з ним (PHP 7.x): PNG: imagealphablending ($ targetImage, false); // якщо вірно на PNG-файлах: чорний фон GIF: imagealphablending ($ targetImage, true); // якщо в GIF-файлах помилково: чорний фон
Джонні

9

Доповнення, яке може допомогти деяким людям:

Під час побудови зображення можна перемикати зображення на замовлення. Я конкретний випадок, що мені це було потрібно, я хотів поєднати кілька напівпрозорих PNG на прозорому тлі.

Спочатку ви встановлюєте параметр imagealphablending на false та заповнюєте новостворене справжнє кольорове зображення прозорим кольором. Якби візуалізація зображення була справжньою, нічого не відбудеться, оскільки прозора заливка злиється з чорним фоном за замовчуванням і призведе до чорного.

Потім ви перемикаєте зображення на альфабленд на істинне і додаєте зображення PNG до полотна, залишаючи частину фону видимим (тобто не заповнюючи все зображення).

В результаті виходить зображення з прозорим фоном та декількома комбінованими зображеннями PNG.


6

Я створив функцію зміни розміру зображення на зразок JPEG / GIF / PNG за допомогою copyimageresample а зображення PNG досі зберігають прозорість:

$myfile=$_FILES["youimage"];

function ismyimage($myfile) {
    if((($myfile["type"] == "image/gif") || ($myfile["type"] == "image/jpg") || ($myfile["type"] == "image/jpeg") || ($myfile["type"] == "image/png")) && ($myfile["size"] <= 2097152 /*2mb*/) ) return true; 
    else return false;
}

function upload_file($myfile) {         
    if(ismyimage($myfile)) {
        $information=getimagesize($myfile["tmp_name"]);
        $mywidth=$information[0];
        $myheight=$information[1];

        $newwidth=$mywidth;
        $newheight=$myheight;
        while(($newwidth > 600) || ($newheight > 400 )) {
            $newwidth = $newwidth-ceil($newwidth/100);
            $newheight = $newheight-ceil($newheight/100);
        } 

        $files=$myfile["name"];

        if($myfile["type"] == "image/gif") {
            $tmp=imagecreatetruecolor($newwidth,$newheight);
            $src=imagecreatefromgif($myfile["tmp_name"]);
            imagecopyresampled($tmp, $src, 0, 0, 0, 0, $newwidth, $newheight, $mywidth, $myheight);
            $con=imagegif($tmp, $files);
            imagedestroy($tmp);
            imagedestroy($src);
            if($con){
                return true;
            } else {
                return false;
            }
        } else if(($myfile["type"] == "image/jpg") || ($myfile["type"] == "image/jpeg") ) {
            $tmp=imagecreatetruecolor($newwidth,$newheight);
            $src=imagecreatefromjpeg($myfile["tmp_name"]); 
            imagecopyresampled($tmp, $src, 0, 0, 0, 0, $newwidth, $newheight, $mywidth, $myheight);
            $con=imagejpeg($tmp, $files);
            imagedestroy($tmp);
            imagedestroy($src);
            if($con) {  
                return true;
            } else {
                return false;
            }
        } else if($myfile["type"] == "image/png") {
            $tmp=imagecreatetruecolor($newwidth,$newheight);
            $src=imagecreatefrompng($myfile["tmp_name"]);
            imagealphablending($tmp, false);
            imagesavealpha($tmp,true);
            $transparent = imagecolorallocatealpha($tmp, 255, 255, 255, 127);
            imagefilledrectangle($tmp, 0, 0, $newwidth, $newheight, $transparent); 
            imagecopyresampled($tmp, $src, 0, 0, 0, 0, $newwidth, $newheight, $mywidth, $myheight);
            $con=imagepng($tmp, $files);
            imagedestroy($tmp);
            imagedestroy($src);
            if($con) {
                return true;
            } else {
                return false;
            }
        }   
    } else
          return false;
}

3
Досить обтяжливо прочитати весь код, щоб зрозуміти, чому в цьому коді зберігається прозорість над кодом у питанні.
eh9

Я пропустив ці два рядки, і це все одно спрацювало: $transparent = imagecolorallocatealpha($tmp, 255, 255, 255, 127); imagefilledrectangle($tmp, 0, 0, $newwidth, $newheight, $transparent);
Сантьяго Арісті

Ця відповідь схожа на stackoverflow.com/a/279310/470749 .
Райан

5

Я думаю, що це може зробити трюк:

$uploadTempFile = $myField[ 'tmp_name' ]
list( $uploadWidth, $uploadHeight, $uploadType ) 
  = getimagesize( $uploadTempFile );

$srcImage = imagecreatefrompng( $uploadTempFile );

$targetImage = imagecreatetruecolor( 128, 128 );

$transparent = imagecolorallocate($targetImage,0,255,0);
imagecolortransparent($targetImage,$transparent);
imagefilledrectangle($targetImage,0,0,127,127,$transparent);

imagecopyresampled( $targetImage, $srcImage, 
                    0, 0, 
                    0, 0, 
                    128, 128, 
                    $uploadWidth, $uploadHeight );

imagepng(  $targetImage, 'out.png', 9 );

Мінусом є те, що зображення буде позбавлене кожні 100% зелених пікселів. Так чи інакше, сподіваюся, що це допоможе :)


Якщо ви встановите надзвичайно потворний колір, який майже жодне зображення не використовуватиме, це може бути дуже корисним.
Cory

1
Прийнята відповідь не спрацювала для мене. imagecreate(...)Однак, використовуючи цю відповідь, працював. Ви створюєте зображення, яке заповнюється першим виділеним вами кольором. Потім ви встановите цей колір прозорим. Якщо для алфавіту встановлено вірно для цільового зображення, обидва зображення будуть об'єднані, а прозорість працює правильно.
Сумурай8

2

Зменшуючи прозорість збереження, тоді так, як зазначено в інших публікаціях imagesavealpha (), потрібно встановити значення true, для використання зображення альфа-альфа-зображення () потрібно встановити значення false, але це не працює.

Також у вашому коді я помітив дві незначні речі:

  1. Вам не потрібно дзвонити, getimagesize()щоб отримати ширину / висотуimagecopyresmapled()
  2. $uploadWidthІ $uploadHeightмає бути -1значення, так як cordinates починається 0і не 1, тому було б скопіювати їх в порожній піксель. Замінивши його на: imagesx($targetImage) - 1і imagesy($targetImage) - 1, відносно слід зробити :)

0

Ось мій загальний тестовий код. Це працює для мене

$imageFileType = pathinfo($_FILES["image"]["name"], PATHINFO_EXTENSION);
$filename = 'test.' . $imageFileType;
move_uploaded_file($_FILES["image"]["tmp_name"], $filename);

$source_image = imagecreatefromjpeg($filename);

$source_imagex = imagesx($source_image);
$source_imagey = imagesy($source_image);

$dest_imagex = 400;
$dest_imagey = 600;
$dest_image = imagecreatetruecolor($dest_imagex, $dest_imagey);

imagecopyresampled($dest_image, $source_image, 0, 0, 0, 0, $dest_imagex, $dest_imagey, $source_imagex, $source_imagey);

imagesavealpha($dest_image, true);
$trans_colour = imagecolorallocatealpha($dest_image, 0, 0, 0, 127);
imagefill($dest_image, 0, 0, $trans_colour);

imagepng($dest_image,"test1.png",1);

0

Зверніть увагу на вихідні зображення widthта heightзначення, які передаються у imagecopyresampledфункцію. Якщо вони перевищують фактичний розмір вихідного зображення, решта зображення буде заповнена чорним кольором.


0

Я поєднав відповіді від ceejayoz та Cheekysoft, які дали найкращий результат для мене. Без imagealphablending () та imagesavealpha () зображення не зрозуміло:

$img3 = imagecreatetruecolor(128, 128);
imagecolortransparent($img3, imagecolorallocate($img3, 0, 0, 0));
imagealphablending( $img3, false );
imagesavealpha( $img3, true );
imagecopyresampled($img3, $srcImage, 0, 0, 0, 0, 128, 128, $uploadWidth, $uploadHeight);
imagepng($img3, 'filename.png', 9);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.