【问题标题】:GD Image Library to create transparent GIF after manipulation处理后创建透明 GIF 的 GD 图像库
【发布时间】:2018-01-18 20:39:25
【问题描述】:

我正在使用 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 通道。

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

这是PNG版本:

我把它放在一个 bitbucket 存储库中,以防有人想查看代码 - 仅查看代码就很难解决此类问题。

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

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

【问题讨论】:

  • 我没有时间尝试这个,但是尝试分配一个透明颜色作为加载背景图像后的第一件事,例如$transp = imagecolorallocatealpha($destination,255,255,255,127);
  • GIF 不是真彩色格式,也不支持 Alpha 通道透明度。当您要求 PHP 输出 GIF 时,它会将资源缩减为 8 位 (256) 调色板。由于您没有通过imagecolortransparent 专门设置透明颜色,因此没有透明度。
  • @timclutton - 想尝试一下答案吗?非常愿意为快速解决方案奖励赏金:)
  • @SBB 我几天前看过这个。您将不得不决定要妥协的地方:质量或尺寸。 PNG出来〜900KiB,而GIF〜300KiB。你的用例是什么?为什么缩小尺寸很重要?您可以运行服务器端优化器吗? (只需通过 tinypng.com 运行 templateNoBG.png 即可将其从 1.02MiB 减少到 227KiB,而没有明显的质量损失。)
  • @timclutton - 我的用例是这张图片将在每个用户自定义的电子邮件活动中发出。在进行一些测试时,当他的图像出现并加载到电子邮件中时,会有几秒钟的中继。 gif 版本几乎立即出现(当然基于我自己的速度)。在某种程度上,质量和尺寸都很重要。你知道 tinypng 对图像做了什么来减少我可以在我这边启用的图像吗?

标签: php image gd


【解决方案1】:

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

我建议:

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

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

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

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

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

生成的图像只有 395KiB,在我的笔记本电脑上生成大约需要 120 毫秒。

这可能是可以预期的速度、质量和尺寸之间的最佳平衡。

【讨论】:

  • 谢谢你!我将尝试尽快整合它,并让你知道它是如何进行的。只是出于好奇,如果我只是从优化的 PNG 背景开始,并保留其他所有内容,输出一个 png,它会增加文件大小还是保持较低的文件大小? GIF 不是输出格式的要求,但认为 PNG 是完全未压缩的,所以 gif 会是最好的结果。
  • @SBB 我在帖子中并不清楚;仅优化了背景图像就实现了 395KiB。其他资产未修改。当输出为真彩色 PNG 时,我认为图像约为 600KiB。
【解决方案2】:

正如 cmets 中所说,gif 是一种基于调色板的格式,不支持完整的 alpha 透明度。您可以通过分配透明颜色,然后扫描图像并将具有 50% 或更高 alpha 值的像素设置为该透明颜色,然后再转换为 gif 格式来实现接近您想要的效果。

// 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 格式中要么完全不透明,要么完全透明。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-08-31
    • 2011-10-19
    • 1970-01-01
    • 2011-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多