GD 图像库在操作后创建透明 GIF
GD Image Library to create transparent GIF after manipulation
我正在使用 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 版本工作的任何想法?两者之间的尺寸差异对于开始工作至关重要。
如评论中所述,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 格式中要么完全不透明,要么完全透明。
by @astrangeloop takes about 2.5 seconds to render on my laptop. As OP has 我认为这个解决方案行不通。
我提议:
- 手动优化服务器上的资产
- 在 PHP
中打开时将这些资源转换为真彩色
- 呈现为 GIF
例如,我使用 tinypng.com 优化了 templateNoBG.png
,将文件大小从 1.02MiB 减少到 227KiB:
由于图像现在是 8 位(256 色),我们需要在打开时将其设为真彩色,以便合并后的图像保留其颜色:
$destination = imagecreatefrompng($style);
imagepalettetotruecolor($destination);
当使用 imagegif
输出图像时,它再次减少到 8 位,具有更好的调色板选择,尽管由于 GIF 仅支持二进制透明度而具有明显的锯齿状边缘:
生成的图像只有 395KiB,在我的笔记本电脑上生成大约需要 120 毫秒。
这可能是可以预期的速度、质量和大小之间的最佳权衡。
我正在使用 PHP 生成具有透明度的 PNG 动态图像。
在此过程中,我在图像顶部添加了一个透明的 PNG 徽标,同时保留了它的透明度。
当我使用 php imagepng($destination)
.
但是,由于这张图片是 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 版本工作的任何想法?两者之间的尺寸差异对于开始工作至关重要。
如评论中所述,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 格式中要么完全不透明,要么完全透明。
我提议:
- 手动优化服务器上的资产
- 在 PHP 中打开时将这些资源转换为真彩色
- 呈现为 GIF
例如,我使用 tinypng.com 优化了 templateNoBG.png
,将文件大小从 1.02MiB 减少到 227KiB:
由于图像现在是 8 位(256 色),我们需要在打开时将其设为真彩色,以便合并后的图像保留其颜色:
$destination = imagecreatefrompng($style);
imagepalettetotruecolor($destination);
当使用 imagegif
输出图像时,它再次减少到 8 位,具有更好的调色板选择,尽管由于 GIF 仅支持二进制透明度而具有明显的锯齿状边缘:
生成的图像只有 395KiB,在我的笔记本电脑上生成大约需要 120 毫秒。
这可能是可以预期的速度、质量和大小之间的最佳权衡。