Как объединить несколько прозрачных png-файлов разного размера в одно изображение без обрезки, используя библиотеку PHP GD?

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

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

Вот код, который я использую в настоящее время:

$images = array();
    foreach (scandir($this->img_dir) as $key => $dirname) {
        if(!strstr($dirname, "."))
        {
            if(isset($_GET[$dirname])) 
            {
                foreach ($this->layer_order as $lkey => $order) {
                    if($lkey == $dirname)
                        $images[$order] = glob($this->img_dir . "/" . $dirname . "/" . $_GET[$dirname] . ".png");
                }
            }
        }
    }


    $destination = imagecreatetruecolor(458, 600);


    imagealphablending($destination, true);
    imagesavealpha($destination, true);

    ksort($images);
    foreach($images as $key => $value) {        
        foreach ($value as $fn) {
            // Load image
            $source = imagecreatefrompng($fn);
            //$source = $this->resize_image($source, 50, 50, 2);

            // Copy over image
            imagecopy($destination, $source, 10, 50, 0, 0, 458, 600);

            // Free memory
            imagedestroy($source);
        }
    }

    return $destination;

person emipac    schedule 14.07.2016    source источник
comment
Исходные изображения обрезаются, потому что imagecopy указывает копировать только из x0, y0 (параметры 5 и 6) в x458, y600 (параметры 7 и 8). Ваше заявление о том, что все изображения объединены с их первоначальным размером, противоречит вашему коду: imagecreatetruecolor(458, 600);. Вам нужно либо увеличить $destination (по крайней мере, до размера самого большого исходного изображения), либо изменить размер исходных изображений, чтобы они соответствовали разрешению 458x600. Что ты хочешь делать?   -  person timclutton    schedule 15.07.2016
comment
Я хотел бы сделать приложение, в котором люди могли бы нажимать на изображения частей двери, и скрипт объединял бы их в один окончательный вариант. Размер результирующего изображения всегда должен быть 458x600, и изображения разного размера должны быть объединены в пределах этого размера. Моя проблема заключалась в том, что изображение двери больше, чем изображение дверной ручки, которое является последним, и в пределах этого 458x600 части объединенных изображений были видны только в пределах размера изображения дверной ручки, а остальная часть окончательного изображения 458x600 была черной. Я хотел поместить дверную ручку на дверь, когда люди нажимают на это изображение.   -  person emipac    schedule 16.07.2016


Ответы (1)


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

Выкладываю все содержимое функции на случай, если кому-то понадобится подобное решение. Это функция внутри класса.

    $images = array();

    // Foreach loop to set images order and creating an array with image paths using params from $_GET before merging
    foreach (scandir($this->img_dir) as $key => $dirname) {
        if(!strstr($dirname, "."))
        {
            if(isset($_GET[$dirname])) 
            {
                foreach ($this->layer_order as $lkey => $order) {
                    if($lkey == $dirname) {
                        $imageArray = glob($this->img_dir . "/" . $dirname . "/" . ($dirname == "door" && isset($_GET['type']) ? $_GET['type']."/" : "") . $_GET[$dirname] . ".png");
                        foreach ($imageArray as $imgPath) {
                            $images[$order] = $imgPath;
                        }
                    }       
                }
            }
        }
    }

    // Allocate new image
    $destination = imagecreatetruecolor($this->canvas_width, $this->canvas_height);

    imagealphablending($destination, false);
    $col = imagecolorallocatealpha($destination, 255, 255, 255, 127);
    imagefilledrectangle($destination, 0, 0, $this->canvas_width, $this->canvas_height, $col);
    imagealphablending($destination, true);

    // Sort order
    ksort($images);

    // Merging images
    foreach($images as $key => $fn) {

        // Load image
        if(strstr($fn, "handle")) 
        {
            $source = $this->resizePng($fn, 0.18, 100, 205);
            imagecopy($destination, $source, 0, 0, 0, 0, $this->canvas_width, $this->canvas_height);
        }
        elseif (strstr($fn, "glass")) 
        {
            // Create a background image by filling a canvas with small image tiles. Params: $file, $shrink_ratio_percent, $column_size, $stretch
            $source = $this->multiplyMergeAndResizePngs($fn, 0.2095, 3, 3.6);
            // Applying mask on images based on black and white patterns
            if ($this->glass_mask)
                $source = $this->createMask($source, $this->glass_mask);
            imagecopy($destination, $source, 118, 28, 0, 0, $this->canvas_width, $this->canvas_height);
        }
        elseif (strstr($fn, "door")) 
        {    
            $source = imagecreatefrompng($fn);
            imagecopy($destination, $source, 32, 0, 0, 0, $this->canvas_width, $this->canvas_height);
        } else {
            $source = imagecreatefrompng($fn);
            imagecopy($destination, $source, 0, 0, 0, 0, $this->canvas_width, $this->canvas_height);
        }

        imagealphablending($destination, true);

        // Free memory
        imagedestroy($source);
    }

    return $destination;
person emipac    schedule 01.11.2016