GD Image Library在操作后创建透明GIF

时间:2018-01-11 00:58:22

标签: php image gd

我使用PHP生成动态图像,这是一个具有透明度的PNG。

在此过程中,我在图像顶部添加了透明的PNG徽标,同时保留了其透明度。

当我使用php imagepng($destination)将最终产品作为PNG输出时,我目前正常工作。

但是,由于它是PNG,我的图像尺寸相当大,我需要将最终输出转换为gif(以保持背景图像的透明度)。

这是我的代码:

$data = [
    'name' => [
        'x' => ($noBG ? 150 : 400),
        'y' => ($noBG ? 700 : 920),
        'size' => 40,
        'angle' => 0,
        'content' => $name,
    ],
    'pin' => [
        'x' => ($noBG ? 130 : 440),
        'y' => ($noBG ? 475 : 700),
        'size' => 75,
        'angle' => 0,
        'content' => implode('  ', str_split($pin)),
    ],
    'denomination' => [
        'x' => denominationPosition($denomination, $noBG),
        'y' => ($noBG ? 150 : 375),
        'size' => 70,
        'angle' => 0,
        'content' => $denomination,
    ],
    'defaultText' => [
        'x' => ($noBG ? 150 : 400),
        'y' => ($noBG ? 780 : 980),
        'size' => 30,
        'angle' => 0,
        'content' => 'It Doesn\'t Cost - It PAY$!',
    ],
    'logo' => [
        'x' => ($noBG ? 875 : 1200),
        'y' => ($noBG ? 675 : 880),
    ],
];

// Are we using the template with or without a background?
if($noBG){
    $style = 'assets/images/templateNoBG.png';
}else{
    $style = 'assets/images/template.png';
}


// Did we pass a logo?
if ($logo) {
    $src = imagecreatefrompng($logo);
}else{
    $src= imagecreatefrompng($noLogo);
}

// Transparent sponsor logo
imagealphablending($src, false);
imagesavealpha($src, true);

// Define our source image (the background)
$destination = imagecreatefrompng($style);

// Colors
$textColor = imagecolorallocate($destination, 255, 255, 255);
$regularFont = 'assets/fonts/Bungee-Regular.otf';

// Transparent background
imagealphablending($destination, true);
imagesavealpha($destination, true);

// Name
imagettftext($destination, $data['name']['size'], $data['name']['angle'], $data['name']['x'], $data['name']['y'], $textColor, $regularFont, $data['name']['content']);
// Pin
imagettftext($destination, $data['pin']['size'], $data['pin']['angle'], $data['pin']['x'], $data['pin']['y'], $textColor, $regularFont, $data['pin']['content']);
// Denomination
imagettftext($destination, $data['denomination']['size'], $data['denomination']['angle'], $data['denomination']['x'], $data['denomination']['y'], $textColor, $regularFont, '$' . $data['denomination']['content']);
// Default Text
imagettftext($destination, $data['defaultText']['size'], $data['defaultText']['angle'], $data['defaultText']['x'], $data['defaultText']['y'], $textColor, $regularFont, $data['defaultText']['content']);

// Merge the logo and template together
imagecopy($destination, $src, $data['logo']['x'], $data['logo']['y'], 0, 0, $logoWidth, $logoHeight);


// Create our header to flush the image to browser
//header("Content-type: image/png");
header("Content-type: image/gif");
header("Cache-Control: no-store, no-cache");

/**
 * Un-comment to ask to save file
 * header('Content-Disposition: attachment; filename="DiningCard.png"');
 */

// Render image
//imagepng($destination); // Works
imagegif($destination);

// Cleanup
imagedestroy($destination);


/**
 * Depending on the number of of numbers in the denomination,
 * pass x coordinates to help keep it in position
 */
function denominationPosition($denomination, $noBG)
{
    switch (strlen($denomination)) {
        case 1:
            return ($noBG ? 1150 : 950);
            break;
        case 2:
            return ($noBG ? 1100: 1400);
            break;
        case 3:
            return ($noBG ? 1050 : 1350);
            break;
        case 4:
            return ($noBG ? 950 : 1290);
            break;
    }

}

我遇到的问题是,当我使用imagegif($destination)时,背景图像会失去透明度而且都会失真。

图像的背景应该是透明的,但你可以看到失真和缺少alpha通道。 enter image description here

通过png输出为imagepng()时,一切正常。

这是PNG版本:

enter image description here

我把它放在一个bitbucket repo上,任何人都想查看代码 - 这样的事情很难解决只是看代码。

https://bitbucket.org/sbbdev/cardgen/src

有关如何使gif版本工作的任何想法?两者之间的大小差异对于工作至关重要。

2 个答案:

答案 0 :(得分:1)

@astrangeloop的solution proposed在我的笔记本电脑上渲染大约需要2.5秒。由于OP有indicated that speed is a factor,我不认为这个解决方案有效。

我建议:

  • 手动优化服务器上​​的资产
  • 在PHP中打开时将这些资产转换为真彩色
  • 呈现为GIF

举例来说,我使用tinypng.com优化templateNoBG.png,将文件大小从1.02MiB减少到227KiB:

enter image description here

由于图像现在是8位(256色),我们需要在打开时使其成为真彩色,以便合并的图像保留其颜色:

$destination = imagecreatefrompng($style);
imagepalettetotruecolor($destination);

当使用imagegif输出图像时,它再次缩减为8位,具有更好的调色板选择,尽管由于GIF仅支持二进制透明度而出现明显的锯齿状边缘:

enter image description here

生成的图像仅为395KiB,在笔记本电脑上生成约120ms。

这可能是速度,质量和尺寸之间的最佳平衡。

答案 1 :(得分:0)

如评论中所述,gif是一种基于调色板的格式,并不支持完整的Alpha透明度。在转换为gif格式之前,您可以通过分配透明色,然后扫描图像并将alpha值为50%或更高的像素设置为此透明色来实现与您想要的接近的效果。

// Render image
//imagepng($destination); // Works
$transparent = imagecolortransparent($destination, imagecolorallocate($destination, 0, 0, 0));
$width = imagesx($destination);
$height = imagesy($destination);
for ($x = 0; $x < $width; $x++) {
    for ($y = 0; $y < $height; $y++) {
        $pixel = imagecolorsforindex($destination, imagecolorat($destination, $x, $y));
        if ($pixel['alpha'] >= 64) {
            imagesetpixel($destination, $x, $y, $transparent);
        }
    }
}
imagegif($destination);

请注意,虽然这会在图像中产生粗糙边缘,因为像素要么完全不透明,要么完全透明为gif格式。