Как изменить размер png с прозрачностью в PHP?

Я пытаюсь изменить размер png с прозрачным фоном в PHP, и образцы кода, которые я нашел в Интернете, у меня не работают. Вот код, который я использую, я буду благодарен за совет!

$this->image = imagecreatefrompng($filename);

imagesavealpha($this->image, true);
$newImage = imagecreatetruecolor($width, $height);

// Make a new transparent image and turn off alpha blending to keep the alpha channel
$background = imagecolorallocatealpha($newImage, 255, 255, 255, 127);
imagecolortransparent($newImage, $background);
imagealphablending($newImage, false);
imagesavealpha($newImage, true);

imagecopyresampled($newImage, $this->image, 0, 0, 0, 0, $width, $height,  $this->getWidth(), $this->getHeight());
$this->image = $newImage;  
imagepng($this->image,$filename);


Обновлять Под «не работает» я имел в виду, что цвет фона меняется на черный, когда я изменяю размер png.

что вы имеете в виду, говоря, что примеры вам не подходят?

Tom Haigh 11.11.2008 00:37
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
43
1
60 084
10
Перейти к ответу Данный вопрос помечен как решенный

Ответы 10

Ответ принят как подходящий

Насколько я могу судить, вам нужно установить режим наложения на false, а флаг сохранения альфа-канала - на trueдо, вы выполняете imagecolorallocatealpha ()

<?php
/**
 * https://stackoverflow.com/a/279310/470749
 * 
 * @param resource $image
 * @param int $newWidth
 * @param int $newHeight
 * @return resource
 */
public function getImageResized($image, int $newWidth, int $newHeight) {
    $newImg = imagecreatetruecolor($newWidth, $newHeight);
    imagealphablending($newImg, false);
    imagesavealpha($newImg, true);
    $transparent = imagecolorallocatealpha($newImg, 255, 255, 255, 127);
    imagefilledrectangle($newImg, 0, 0, $newWidth, $newHeight, $transparent);
    $src_w = imagesx($image);
    $src_h = imagesy($image);
    imagecopyresampled($newImg, $image, 0, 0, 0, 0, $newWidth, $newHeight, $src_w, $src_h);
    return $newImg;
}
?>

ОБНОВИТЬ: этот код работает только с прозрачным фоном с непрозрачностью = 0. Если у вашего изображения 0 <непрозрачность <100, это будет черный фон.

Ответ был совершенно не связан, но это правильный способ изменить размер с помощью прозрачности.

Ryan Doherty 30.11.2009 19:28

Это определенно ПРАВИЛЬНЫЙ способ создавать / копировать прозрачные изображения PNG.

tftd 01.12.2011 02:09

@RyanDoherty, если это не было ответ, то можете ли вы предоставить свое решение?

Steve Robbins 30.03.2012 00:22

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

Andreas Linden 24.09.2012 18:20

Миллион различных методов был испробован из миллиона различных ответов и предложений, и это единственный, который сработал. Спасибо @Dycey

Onimusha 26.01.2014 04:18

Помните, что ресурс сохраняет прозрачность. Поэтому, если вы скопируете прозрачное изображение на изображение, которое вы только что изменили, оно будет неправильным. Я не смог найти ничего о невыделении прозрачности, поэтому я использовал imagecopy для ресурса с измененным размером, чтобы очистить его. Просто говорю.

JSG 20.06.2020 03:53

Также требуется заливка нового изображения прозрачным цветом (как закодировал Дайси, но я предполагаю, что забыл упомянуть :)), а не только «стратегическая» экономия сама по себе.

IIRC, вам также необходимо убедиться, что PNG 24-битный, то есть истинный цвет, а не 8-битный, чтобы избежать ошибок.

старый поток, но на всякий случай - пример Дайси должен работать, если правильно называть вещи. Вот модифицированная версия, используемая в моем классе изменения размера изображения. Обратите внимание на проверку, чтобы убедиться, что imagecolorallocatealpha () определен, чего не будет, если вы используете GD <2.0.8.

  /**
     * usually when people use PNGs, it's because they need alpha channel 
     * support (that means transparency kids). So here we jump through some 
     * hoops to create a big transparent rectangle which the resampled image 
     * will be copied on top of. This will prevent GD from using its default 
     * background, which is black, and almost never correct. Why GD doesn't do 
     * this automatically, is a good question.
     *
     * @param $w int width of target image
     * @param $h int height of target image
     * @return void
     * @private
     */
    function _preallocate_transparency($w, $h) {
        if (!empty($this->filetype) && !empty($this->new_img) && $this->filetype == 'image/png')) {
            if (function_exists('imagecolorallocatealpha')) {
                imagealphablending($this->new_img, false);
                imagesavealpha($this->new_img, true);
                $transparent = imagecolorallocatealpha($this->new_img, 255, 255, 255, 127);
                imagefilledrectangle($this->new_img, 0, 0, $tw, $th, $transparent);
            }
        }
    }

tw - Ширина цели th - Высота цели

Beniston 18.05.2012 14:47

Я думаю, что он имел в виду: tw и th не определены. Параметры функции называются $ w и $ h, но imagefilledrectangle () вызывается с $ tw и $ th. Это ошибка.

Gerben 18.10.2018 16:20

у меня это тоже не работает :( это мое решение .. но я также получаю черный фон и изображение не прозрачное

    <?php
$img_id = 153;

$source = "images/".$img_id.".png";
$source = imagecreatefrompng($source);
$o_w = imagesx($source);
$o_h = imagesy($source);

$w = 200;
$h = 200;

$newImg = imagecreatetruecolor($w, $h);
imagealphablending($newImg, false);
imagesavealpha($newImg,true);
$transparent = imagecolorallocatealpha($newImg, 255, 255, 255, 127);
imagefilledrectangle($newImg, 0, 0, $w, $h, $transparent);
imagecopyresampled($newImg, $source, 0, 0, 0, 0, $w, $h, $o_w, $o_h);

imagepng($newImg, $img_id.".png");

?>
<img src = "<?php echo $img_id.".png" ?>" />

Полный пример. Обратите внимание, что для некоторых изображений png, найденных в Интернете, он работает некорректно, но для моих собственных, созданных с помощью Photoshop, он работает нормально.

    header('Content-Type: image/png');

$filename = "url to some image";

$newWidth = 300;
$newHeight = 300;

$imageInfo = getimagesize($filename);

$image = imagecreatefrompng($filename); //create source image resource
imagesavealpha($image, true); //saving transparency

$newImg = imagecreatetruecolor($newWidth, $newHeight); //creating conteiner for new image
imagealphablending($newImg, false);
imagesavealpha($newImg,true);
$transparent = imagecolorallocatealpha($newImg, 255, 255, 255, 127); //seting transparent background
imagefilledrectangle($newImg, 0, 0, $newWidth, $newHeight, $transparent);
imagecopyresampled($newImg, $image, 0, 0, 0, 0, $newWidth, $newHeight,  $imageInfo[0], $imageInfo[1]);

imagepng($newImg); //printout image string

Вот окончательное решение, которое мне подходит.

function resizePng($im, $dst_width, $dst_height) {
    $width = imagesx($im);
    $height = imagesy($im);

    $newImg = imagecreatetruecolor($dst_width, $dst_height);

    imagealphablending($newImg, false);
    imagesavealpha($newImg, true);
    $transparent = imagecolorallocatealpha($newImg, 255, 255, 255, 127);
    imagefilledrectangle($newImg, 0, 0, $width, $height, $transparent);
    imagecopyresampled($newImg, $im, 0, 0, 0, 0, $dst_width, $dst_height, $width, $height);

    return $newImg;
}

Вероятно, это связано с более новыми версиями PHP (я тестировал с PHP 5.6), но теперь это работает без необходимости заливки изображения прозрачным фоном:

$image_p = imagecreatetruecolor(480, 270);
imageAlphaBlending($image_p, false);
imageSaveAlpha($image_p, true);
$image = imagecreatefrompng('image_with_some_transaprency.png');
imagecopyresampled($image_p, $image, 0, 0, 0, 0, 480, 270, 1920, 1080);
imagepng($image_p, 'resized.png', 0);

Да, это работает! imageAlphaBlending и imageSaveAlpha хватит, спасибо;)

daVe 20.10.2015 19:13

Вот полный код, работающий с файлами png с сохранением прозрачности их изображений.

list($width, $height) = getimagesize($filepath);
$new_width = "300";
$new_height = "100";

if ($width>$new_width && $height>$new_height)
{
    $image_p = imagecreatetruecolor($new_width, $new_height);
    imagealphablending($image_p, false);
    imagesavealpha($image_p, true);
    $image = imagecreatefrompng($filepath);
    imagecopyresampled($image_p, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
    imagepng($image_p,$filepath,5);
}

Ни одно из приведенных выше решений не помогло мне. Вот как я выяснил, как решить проблему.

// upload directory
$upload_dir = "../uploads/";
// valid image formats
$valid_formats = array("jpg", "jpeg", "png");
// maximum image size 1 mb
$max_size = 1048576;
// crop image width, height
$nw = $nh = 800;
$nw1 = $nh1 = 400;
$nw3 = $nh3 = 200;
$nw2 = $nh2 = 100;
// checks that if upload_dir a directory/not
if (is_dir($upload_dir) && is_writeable($upload_dir)) {
    // not empty file
    if (!empty($_FILES['image'])) {
        // assign file name 
        $name = $_FILES['image']['name'];
        // $_FILES to execute all files within a loop
        if ($_FILES['image']['error'] == 4) {
            $message = "Empty FIle";
        }
        if ($_FILES['image']['error'] == 0) {
            if ($_FILES['image']['size'] > $max_size) {
                echo "E-Image is too large!<br>";
                $_SESSION['alert'] = "Image is too large!!";
            } else if (!in_array(pathinfo($name, PATHINFO_EXTENSION), $valid_formats)) {
                $_SESSION['alert'] = "This image is not a valid image format!!";
                echo "E-This image is not a valid image format<br>";
            } else if (file_exists($upload_dir . $name)) {
                $_SESSION['alert'] = "Image already exists!!";
                echo "E-Image already exists<br>";
            } else { // No error found! Move uploaded files 
                $size = getimagesize($_FILES['image']['tmp_name']);
                $x = (int) $_POST['x'];
                $y = (int) $_POST['y'];
                $w = (int) $_POST['w'] ? $_POST['w'] : $size[0];
                $h = (int) $_POST['h'] ? $_POST['h'] : $size[1];
                // path for big image
                $big_image_path = $upload_dir . "big/" . $name;
                // medium image path
                $medium_image_path = $upload_dir . "medium/" . $name;
                // small image path
                $small_image_path = $upload_dir . "small/" . $name;
                // check permission
                if (!is_dir($upload_dir . "big/") && !is_writeable($upload_dir . "big/")) {
                    mkdir($upload_dir . "big/", 0777, false);
                }
                if (!is_dir($upload_dir . "medium/") && !is_writeable($upload_dir . "medium/")) {
                    mkdir($upload_dir . "medium/", 0777, false);
                }
                if (!is_dir($upload_dir . "small/") && !is_writeable($upload_dir . "small/")) {
                    mkdir($upload_dir . "small/", 0777, false);
                }
                // image raw data from form
                $data = file_get_contents($_FILES["image"]["tmp_name"]);
                // create image
                $vImg = imagecreatefromstring($data);
                //create big image
                $dstImg = imagecreatetruecolor($nw, $nh);
                imagealphablending($dstImg, false);
                $trans_colour = imagecolorallocatealpha($dstImg, 0, 0, 0, 127);
                imagefilledrectangle($dstImg, 0, 0, $w, $h, $trans_colour);
                imagesavealpha($dstImg, true);
                imagecopyresampled($dstImg, $vImg, 0, 0, $x, $y, $nw, $nh, $w, $h);
                imagepng($dstImg, $big_image_path);
                //create medium thumb
                $dstImg1 = imagecreatetruecolor($nw1, $nh1);
                imagealphablending($dstImg1, false);
                $trans_colour1 = imagecolorallocatealpha($dstImg1, 0, 0, 0, 127);
                imagefilledrectangle($dstImg1, 0, 0, $w, $h, $trans_colour1);
                imagesavealpha($dstImg1, true);
                imagecopyresampled($dstImg1, $vImg, 0, 0, $x, $y, $nw1, $nh1, $w, $h);
                imagepng($dstImg1, $medium_image_path);
                // create smallest thumb
                $dstImg2 = imagecreatetruecolor($nw2, $nh2);
                imagealphablending($dstImg2, false);
                $trans_colour2 = imagecolorallocatealpha($dstImg2, 0, 0, 0, 127);
                imagefilledrectangle($dstImg2, 0, 0, $w, $h, $trans_colour2);
                imagesavealpha($dstImg2, true);
                imagecopyresampled($dstImg2, $vImg, 0, 0, $x, $y, $nw2, $nh2, $w, $h);
                imagepng($dstImg2, $small_image_path);
                /*
                 * Database insertion
                 */
                $sql = "INSERT INTO tbl_inksand_product_gallery ("
                        . "Product_Id,Gallery_Image_Big,Gallery_Image_Medium,Gallery_Image_Thumb,"
                        . "Gallery_Status,Created_By,Created_Datetime"
                        . ") VALUES ("
                        . "'{$Product_Id}','{$big_image_path}','{$medium_image_path}','{$small_image_path}',"
                        . "'A','$Created_By','{$time}'"
                        . ")";
                db_query($sql);
                if (db_affected_rows() == 1) {
                    if (imagedestroy($dstImg)) {
                        $_SESSION['success'] = "Image uploaded successfully.";
                        echo "S-Image uploaded successfully<br>";
                    } else {
                        $_SESSION['alert'] = "Image not uploaded!!";
                        echo "S-Image not uploaded";
                    }
                } else {
                    $_SESSION['alert'] = "Error in uploading image!!";
                    echo "E-Error in uploading image!!";
                }
            }
        }
    }
} else {
    mkdir($upload_dir, 0777);
}

использование imagescale лучше, чем imagecopyresampled. Для изображения с измененным размером не требуется пустой ресурс изображения, требуется только два аргумента по сравнению с десятью, требуемыми для imagecopyresampled. Также обеспечивает лучшее качество при меньших размерах. Если вы используете PHP 5.5.18 или более раннюю версию или PHP 5.6.2 или более раннюю версию, вы должны указать высоту, которая является третьим аргументом, поскольку расчет соотношения сторон был неправильным.

$this->image =   imagecreatefrompng($filename);
$scaled = imagescale($this->image, $width);
imagealphablending($scaled, false);
imagesavealpha($scaled, true);
imagepng($scaled, $filename);

Спасибо за это. У меня это сработало в конце 2020 года. Я использовал imagecreatetruecolor вместо imagecreatefrompng и пропустил часть imagescale.

Tayler 11.12.2020 00:17

Другие вопросы по теме