如果您想使用混合,目标图像资源不必是调色板。
这意味着使用 ImageCreateTrueColor() 而不是 ImageCreate()。
(如果您的源是例如 jpeg,并且您使用了 ImageCreateFromJPEG(),则上述内容无关。)
(PHP 4 >= 4.0.6, PHP 5, PHP 7, PHP 8)
imagealphablending — 设置图像的混合模式
imagealphablending() 允许在真彩色图像上进行两种不同的绘制模式。在混合模式下,提供给所有绘制函数(如 imagesetpixel())的颜色中的 alpha 通道分量决定了应允许多少底层颜色透射。因此,gd 会自动将该点处的现有颜色与绘制颜色混合,并将结果存储在图像中。生成的像素是不透明的。在非混合模式下,绘制颜色将以其 alpha 通道信息完全复制,替换目标像素。在绘制调色板图像时,混合模式不可用。
示例 #1 imagealphablending() 用法示例
<?php
// 创建图像
$im = imagecreatetruecolor(100, 100);
// 将 alpha 混合设置为打开
imagealphablending($im, true);
// 绘制一个正方形
imagefilledrectangle($im, 30, 30, 70, 70, imagecolorallocate($im, 255, 0, 0));
// 输出
header('Content-Type: image/png');
imagepng($im);
imagedestroy($im);
?>
如果您想使用混合,目标图像资源不必是调色板。
这意味着使用 ImageCreateTrueColor() 而不是 ImageCreate()。
(如果您的源是例如 jpeg,并且您使用了 ImageCreateFromJPEG(),则上述内容无关。)
如果您尝试将透明图像复制到另一个图像上,您可能会认为应该将 ImageAlphaBlending 函数应用于具有透明度的图像,即源图像。实际上,您必须将 ImageAlphaBlending 函数应用于目标图像。基本上,它表示“使指定的图像尊重透明度”。
以下是一个现实世界的示例。假设您想将您的徽标放在照片的左上角。您的徽标是具有透明度的 PNG,照片是 JPEG。以下是您将执行的操作
<?php
$photoImage = ImageCreateFromJPEG('photo.jpg');
ImageAlphaBlending($photoImage, true);
$logoImage = ImageCreateFromPNG('logo.png');
$logoW = ImageSX($logoImage);
$logoH = ImageSY($logoImage);
ImageCopy($photoImage, $logoImage, 0, 0, 0, 0, $logoW, $logoH);
ImageJPEG($photoImage); // 输出到浏览器
ImageDestroy($photoImage);
ImageDestroy($logoImage);
?>
我已经寻找了一段时间,想要找到一个执行以下操作的脚本:使用指定的字体和给定的颜色生成带有文本的图像,但背景完全透明(通过 alpha 通道,而不是通过颜色透明度)。最终,我自己创建了这个脚本。这只是一个粗略的想法,说明如何做到这一点。
<?php
$tekst = "这是一条测试信息\nza???? g??l? ja??!\nZA?ӣ? GʦL? JA???";
$h = 9;
$size = imageTTFBBox($h, 0, "arial.ttf", $tekst);
$image = imageCreateTrueColor(abs($size[2]) + abs($size[0]), abs($size[7]) + abs($size[1]));
imageSaveAlpha($image, true);
ImageAlphaBlending($image, false);
$tlo = imagecolorallocatealpha($image, 220, 220, 220, 127);
imagefill($image, 0, 0, $tlo);
$napis = imagecolorallocate($image, 220, 220, 220);
imagettftext($image, $h, 0, 0, abs($size[5]), $napis, "arial.ttf", $tekst);
imagepng($image, "output.png");
imagedestroy($image);
?>
<html>
<head>
</head>
<body bgcolor="#808080">
<img src="output.png" alt="">
</body>
</html>
"如果 imagealphablending 设置为 true 并且您要合并两个图像,则最终会没有透明度。如果它设置为 false,则只尊重第二个图像的透明度,导致第一个图像的任何部分都不会显示。要解决此问题,请使用以下函数:"
dscharrer at gmail dot com 提供了这个,但没有使用示例,所以这里有一个
<?
$flag = imagecreatefrompng('a.png');
$mask = imagecreatefrompng('b.png');
imagealphablending($flag, 1);
imagealphablending($mask, 1);
$i= array($flag, $mask); // 这里是用上面指定的 $flag 和 $mask 图像的图像数组
$s = imagemergealpha($i);
header("Content-type: image/png");
imagepng($s);
// 合并多个图像并保留透明度
//$i 是要合并的图像数组
// $i[1] 将覆盖 $i[0]
// $i[2] 将覆盖在上面
// ...
// 该函数返回准备保存的结果图像
function imagemergealpha($i) {
// 创建一个新图像
$s = imagecreatetruecolor(imagesx($i[0]),imagesy($i[1]));
// 合并所有图像
imagealphablending($s,true);
$z = $i;
while($d = each($z)) {
imagecopy($s,$d[1],0,0,0,0,imagesx($d[1]),imagesy($d[1]));
}
// 恢复透明度
imagealphablending($s,false);
$w = imagesx($s);
$h = imagesy($s);
for($x=0;$x<$w;$x++) {
for($y=0;$y<$h;$y++) {
$c = imagecolorat($s,$x,$y);
$c = imagecolorsforindex($s,$c);
$z = $i;
$t = 0;
while($d = each($z)) {
$ta = imagecolorat($d[1],$x,$y);
$ta = imagecolorsforindex($d[1],$ta);
$t += 127-$ta['alpha'];
}
$t = ($t > 127) ? 127 : $t;
$t = 127-$t;
$c = imagecolorallocatealpha($s,$c['red'],$c['green'],$c['blue'],$t);
imagesetpixel($s,$x,$y,$c);
}
}
imagesavealpha($s,true);
return $s;
}
?>
我创建了一个小函数,用于在任何图片上添加水印。
水印可以是 png,具有透明度,并且可以使用诸如 'bottom-left' 或 'center' 之类的简单字符串将水印放置在图像的任何位置。
<?
function imagelogo (&$dst_image, $src_image, $dst_w, $dst_h, $src_w, $src_h, $position='bottom-left') {
imagealphablending($dst_image,true);
imagealphablending($src_image,true);
if ($position == 'random') {
$position = rand(1,8);
}
switch ($position) {
case 'top-right'
case 'right-top'
case 1
imagecopy($dst_image, $src_image, ($dst_w-$src_w), 0, 0, 0, $src_w, $src_h);
break;
case 'top-left'
case 'left-top'
case 2
imagecopy($dst_image, $src_image, 0, 0, 0, 0, $src_w, $src_h);
break;
case 'bottom-right'
case 'right-bottom'
case 3
imagecopy($dst_image, $src_image, ($dst_w-$src_w), ($dst_h-$src_h), 0, 0, $src_w, $src_h);
break;
case 'bottom-left'
case 'left-bottom'
case 4
imagecopy($dst_image, $src_image, 0 , ($dst_h-$src_h), 0, 0, $src_w, $src_h);
break;
case 'center'
case 5
imagecopy($dst_image, $src_image, (($dst_w/2)-($src_w/2)), (($dst_h/2)-($src_h/2)), 0, 0, $src_w, $src_h);
break;
case 'top'
case 6
imagecopy($dst_image, $src_image, (($dst_w/2)-($src_w/2)), 0, 0, 0, $src_w, $src_h);
break;
case 'bottom'
case 7
imagecopy($dst_image, $src_image, (($dst_w/2)-($src_w/2)), ($dst_h-$src_h), 0, 0, $src_w, $src_h);
break;
case 'left'
case 8
imagecopy($dst_image, $src_image, 0, (($dst_h/2)-($src_h/2)), 0, 0, $src_w, $src_h);
break;
case 'right'
case 9
imagecopy($dst_image, $src_image, ($dst_w-$src_w), (($dst_h/2)-($src_h/2)), 0, 0, $src_w, $src_h);
break;
}
}
// 示例
imagelogo($image, $watermark, imagesx($image), imagesy($image), imagesx($watermark), imagesy($watermark), 'random');
?>
我重写了下面的代码,以在不需要时跳过计算和像素设置(完全不透明或完全透明像素),因为我的叠加层的 内容通常大部分是透明的。将 216x145px 图像的处理时间从 ~0.17s 减少到 ~0.06s。
function alphaOverlay($destImg, $overlayImg, $imgW, $imgH)
{
for($y=0;$y<$imgH;$y++)
{
for($x=0;$x<$imgW;$x++)
{
$ovrARGB = imagecolorat($overlayImg, $x, $y);
$ovrA = ($ovrARGB >> 24) << 1;
$ovrR = $ovrARGB >> 16 & 0xFF;
$ovrG = $ovrARGB >> 8 & 0xFF;
$ovrB = $ovrARGB & 0xFF;
$change = false;
if($ovrA == 0)
{
$dstR = $ovrR;
$dstG = $ovrG;
$dstB = $ovrB;
$change = true;
}
elseif($ovrA < 254)
{
$dstARGB = imagecolorat($destImg, $x, $y);
$dstR = $dstARGB >> 16 & 0xFF;
$dstG = $dstARGB >> 8 & 0xFF;
$dstB = $dstARGB & 0xFF;
$dstR = (($ovrR * (0xFF-$ovrA)) >> 8) + (($dstR * $ovrA) >> 8);
$dstG = (($ovrG * (0xFF-$ovrA)) >> 8) + (($dstG * $ovrA) >> 8);
$dstB = (($ovrB * (0xFF-$ovrA)) >> 8) + (($dstB * $ovrA) >> 8);
$change = true;
}
if($change)
{
$dstRGB = imagecolorallocatealpha($destImg, $dstR, $dstG, $dstB, 0);
imagesetpixel($destImg, $x, $y, $dstRGB);
}
}
}
return $destImg;
}
请注意,必须启用 alpha 混合才能在真彩色模式下呈现抗锯齿文本。
对于旧版本的 PHP 和/或 GD(例如,Debian woody 附带的版本),alpha 混合默认情况下是禁用的,而对于较新版本是启用的。
Roy Conejo 说
我必须将图像“按像素 alpha 混合”到纯色背景中,如“barnabas at kendall dot NOSPAM dot net”的简洁示例所示:在 .jpg 照片上使用 alpha 混合的 .png logo。问题是……它根本没有在这里奏效(为什么?T_T)。
请注意,我只是使用源 alpha 来确定最终像素中将存在多少源颜色和目标颜色……并且我必须将 alpha 值(0 - 127)乘以 2,因为我需要它 是 8 位的,用于计算。
我认为代码相当快,没有小数,没有舍入,没有不必要的编码。如果您确实需要,可以实现边界检查或裁剪。
希望它对遇到相同情况的人有所帮助 ^.^
<?php
## alpha_blending 函数开始 -------------------------------------------
function
alpha_blending ($dest, $source, $dest_x, $dest_y) {
## 将源像素与其 alpha 值混合到目标图像中 =)
for ($y = 0; $y < imagesy($source); $y++) {
for ($x = 0; $x < imagesx($source); $x++) {
$argb_s = imagecolorat ($source ,$x ,$y);
$argb_d = imagecolorat ($dest ,$x+$dest_x ,$y+$dest_y);
$a_s = ($argb_s >> 24) << 1; ## 将 7 位 alpha 值转换为 8 位.
$r_s = $argb_s >> 16 & 0xFF;
$g_s = $argb_s >> 8 & 0xFF;
$b_s = $argb_s & 0xFF;
$r_d = $argb_d >> 16 & 0xFF;
$g_d = $argb_d >> 8 & 0xFF;
$b_d = $argb_d & 0xFF;
## 源像素完全不透明(alpha == 0)
if ($a_s == 0) {
$r_d = $r_s; $g_d = $g_s; $b_d = $b_s;
}
## 源像素完全透明(alpha == 255)
else if ($a_s > 253) {
## 使用源 alpha 值,需要混合 (100-"some")% 的源像素与 "some" % 的目标像素.
} else {
$r_d = (($r_s * (0xFF-$a_s)) >> 8) + (($r_d * $a_s) >> 8);
$g_d = (($g_s * (0xFF-$a_s)) >> 8) + (($g_d * $a_s) >> 8);
$b_d = (($b_s * (0xFF-$a_s)) >> 8) + (($b_d * $a_s) >> 8);
}
$rgb_d = imagecolorallocatealpha ($dest, $r_d, $g_d, $b_d, 0);
imagesetpixel ($dest, $x, $y, $rgb_d);
}
}
}
## alpha_blending 函数结束 -------------------------------------------
## 开始加载图像...
$source = imagecreatefrompng ('logo.png');
$dest = imagecreatefromjpg ('photo.jpg');
## 将 $source 图像混合到 $dest 图像中,起始位置为 (10, 5).
alpha_blending ($dest, $source, 10, 5);
## 这里需要保存 "$dest" 图像或将其发送到浏览器...
##
imagedestroy ($source);
imagedestroy ($dest);
?>
eof =p
我编写了一个函数,它以图像作为参数,并返回具有反射效果的相同图像(通常在 WEB 2.0 网站中看到)。我没有对大型图像文件进行性能测试,对于缩略图,它工作正常(需要 PHP 4.3.2 或更高版本,或 PHP5)。
<?php
function imagereflection($src_img) {
$src_height = imagesy($src_img);
$src_width = imagesx($src_img);
$dest_height = $src_height + ($src_height / 2);
$dest_width = $src_width;
$reflected = imagecreatetruecolor($dest_width, $dest_height);
imagealphablending($reflected, false);
imagesavealpha($reflected, true);
imagecopy($reflected, $src_img, 0, 0, 0, 0, $src_width, $src_height);
$reflection_height = $src_height / 2;
$alpha_step = 80 / $reflection_height;
for ($y = 1; $y <= $reflection_height; $y++) {
for ($x = 0; $x < $dest_width; $x++) {
// 将像素从 x / $src_height - y 复制到 x / $src_height + y
$rgba = imagecolorat($src_img, $x, $src_height - $y);
$alpha = ($rgba & 0x7F000000) >> 24;
$alpha = max($alpha, 47 + ($y * $alpha_step));
$rgba = imagecolorsforindex($src_img, $rgba);
$rgba = imagecolorallocatealpha($reflected, $rgba['red'], $rgba['green'], $rgba['blue'], $alpha);
imagesetpixel($reflected, $x, $src_height + $y - 1, $rgba);
}
}
return $reflected;
}
?>
这段代码比较硬编码。您可以将一些值作为参数提取(80 是透明度起始值,$height / 2 是反射区域...)。
祝好!
Christian
在上一条消息中,我发现它工作完美。但是,它可以更容易地完成,正如 "barnabas at kendall dot NOSPAM dot net" 的第一条消息中所描述的那样。尽管它不完全有效,但您必须使用 imageSaveAlpha,而不是使用 imageAlphaBlending。
因此,我发现更正和更小的代码将是
<?php
$im_a = @imagecreatefrompng("a.png");
$im_c = @imagecreatefrompng("c.png");
imageSaveAlpha($im_c, true);
imagecopy($im_c,$im_a,0,0,0,0,200,200);
header("Content-type: image/png");
imagepng($im_c);
?>
如果 imagealphablending 设置为 true 并且您想要合并两个图像,则最终将没有透明度。如果将其设置为 false,则仅尊重第二个图像的透明度,导致第一个图像的任何部分都无法显示。要解决此问题,请使用以下函数
<?
// 合并多个图像并保留透明度
//$i 是要合并的图像数组
// $i[1] 将覆盖 $i[0]
// $i[2] 将覆盖在上面
// ...
// 该函数返回准备保存的结果图像
function imagemergealpha($i) {
// 创建一个新图像
$s = imagecreatetruecolor(imagesx($i[0]),imagesy($i[1]));
// 合并所有图像
imagealphablending($s,true);
$z = $i;
while($d = each($z)) {
imagecopy($s,$d[1],0,0,0,0,imagesx($d[1]),imagesy($d[1]));
}
// 恢复透明度
imagealphablending($s,false);
$w = imagesx($s);
$h = imagesy($s);
for($x=0;$x<$w;$x++) {
for($y=0;$y<$h;$y++) {
$c = imagecolorat($s,$x,$y);
$c = imagecolorsforindex($s,$c);
$z = $i;
$t = 0;
while($d = each($z)) {
$ta = imagecolorat($d[1],$x,$y);
$ta = imagecolorsforindex($d[1],$ta);
$t += 127-$ta['alpha'];
}
$t = ($t > 127) ? 127 : $t;
$t = 127-$t;
$c = imagecolorallocatealpha($s,$c['red'],$c['green'],$c['blue'],$t);
imagesetpixel($s,$x,$y,$c);
}
}
imagesavealpha($s,true);
return $s;
}
?>
当我保存要用于透明叠加(如上面提到的徽标添加)的图像时,我发现 PNG-24 不成功,只有 GIF 和 PNG-8 成功。我在 PNG-8 上取得了巨大成功。
如果您将图像保存为具有透明度的 PNG,然后将其保存为 PNG-8,它将以与 GIF 相同的方式获得透明度,但这不适用于此函数。
为了使此函数正常工作,图像需要具有 alpha 通道(当然,当您认真思考时确实如此),因此请确保将其保存为 PNG-24