我使用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通道。
通过png
输出为imagepng()
时,一切正常。
这是PNG版本:
我把它放在一个bitbucket repo上,任何人都想查看代码 - 这样的事情很难解决只是看代码。
https://bitbucket.org/sbbdev/cardgen/src
有关如何使gif版本工作的任何想法?两者之间的大小差异对于工作至关重要。
答案 0 :(得分:1)
@astrangeloop的solution proposed在我的笔记本电脑上渲染大约需要2.5秒。由于OP有indicated that speed is a factor,我不认为这个解决方案有效。
我建议:
举例来说,我使用tinypng.com优化templateNoBG.png
,将文件大小从1.02MiB减少到227KiB:
由于图像现在是8位(256色),我们需要在打开时使其成为真彩色,以便合并的图像保留其颜色:
$destination = imagecreatefrompng($style);
imagepalettetotruecolor($destination);
当使用imagegif
输出图像时,它再次缩减为8位,具有更好的调色板选择,尽管由于GIF仅支持二进制透明度而出现明显的锯齿状边缘:
生成的图像仅为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格式。