PHP Imagick添加水印背景变灰且描边异常问题求助
问题描述
我制作了一张水印图片,使用的代码如下:
$im = new Imagick(); $draw = new ImagickDraw(); $text = 'watermark text'; $draw->setFontFamily('Arial'); $draw->setFontSize(50); $draw->setFillColor('white'); $draw->setStrokeColor('black'); $draw->setStrokeWidth(1); $draw->setStrokeAntialias(true); $draw->setTextAntialias(true); $qfm = $im->queryFontMetrics($draw, $text); $im->newImage($qfm['textWidth'], $qfm['textHeight'], new ImagickPixel('rgba(120,120,120,0)')); $im->setImageFormat('png'); $text_x = 1; $text_y = ceil($qfm['textHeight'] / 2) + ceil($qfm['ascender'] / 3) - 1; $im->annotateImage($draw, $text_x, $text_y, 0, $text); $im->writeImage('watermark.png');
随后我使用以下代码将该水印添加到图片中:
$wmark = new imagick('watermark.png'); $image = new imagick('image.jpg'); $wmark_width = $wmark->getImageWidth(); $wmark_height = $wmark->getImageHeight(); $image_width = $image->getImageWidth(); $image_height = $image->getImageHeight(); $wmark->setImageOpacity(0.3); $wmark_x = floor(($image_width - $wmark_width) / 2); $wmark_y = floor(($image_height - $wmark_height) / 2); $image->compositeImage($wmark, Imagick::COMPOSITE_OVER, $wmark_x, $wmark_y); $image->writeImage('result.jpg');
但水印未保持透明背景,反而变成了灰色,且文字带有奇怪的描边。
环境信息:ImageMagick 6.9.11-60 Q16 x86_64 2021-01-25,PHP 7.4.33
问题原因及解决方法
原因分析
- 背景变灰:你创建水印时用了
rgba(120,120,120,0)作为背景,虽然alpha通道是透明状态,但这个灰色底色会和后续设置的setImageOpacity(0.3)叠加,导致最终呈现半透灰色。另外JPG格式本身不支持透明,合成时透明区域会被ImageMagick默认填充灰色。 - 奇怪描边:你设置了黑色描边和1px宽度,给整个水印加全局透明度后,描边的黑色也会变半透明,和白色填充的文字叠加后就出现了怪异的边缘效果。
解决步骤
步骤1:修正水印创建代码
- 把水印背景改成完全透明的
rgba(0,0,0,0),避免底色干扰; - 要么移除描边设置,要么给描边色单独加透明度,不要用全局水印透明度。
修正后的水印代码:
$im = new Imagick(); $draw = new ImagickDraw(); $text = 'watermark text'; $draw->setFontFamily('Arial'); $draw->setFontSize(50); // 直接给文字填充色加透明度,替代全局水印透明度 $draw->setFillColor('rgba(255,255,255,0.3)'); // 如果需要描边,同样给描边色加透明度,不需要就删掉下面两行 // $draw->setStrokeColor('rgba(0,0,0,0.3)'); // $draw->setStrokeWidth(1); $draw->setStrokeAntialias(true); $draw->setTextAntialias(true); $qfm = $im->queryFontMetrics($draw, $text); // 使用完全透明的背景 $im->newImage($qfm['textWidth'], $qfm['textHeight'], new ImagickPixel('rgba(0,0,0,0)')); $im->setImageFormat('png'); $text_x = 1; $text_y = ceil($qfm['textHeight'] / 2) + ceil($qfm['ascender'] / 3) - 1; $im->annotateImage($draw, $text_x, $text_y, 0, $text); $im->writeImage('watermark.png');
步骤2:修正水印合成代码
- 删掉
$wmark->setImageOpacity(0.3),因为已经在文字颜色里设置了透明度; - 如果需要保留透明效果,把输出格式改成PNG(JPG不支持透明)。
修正后的合成代码:
$wmark = new imagick('watermark.png'); $image = new imagick('image.jpg'); $wmark_width = $wmark->getImageWidth(); $wmark_height = $wmark->getImageHeight(); $image_width = $image->getImageWidth(); $image_height = $image->getImageHeight(); // 移除全局透明度设置 $wmark_x = floor(($image_width - $wmark_width) / 2); $wmark_y = floor(($image_height - $wmark_height) / 2); $image->compositeImage($wmark, Imagick::COMPOSITE_OVER, $wmark_x, $wmark_y); // 若需要透明背景,启用下面一行并把输出后缀改成png // $image->setImageFormat('png'); $image->writeImage('result.jpg');
额外优化:直接在目标图上绘制水印
可以跳过生成水印文件的步骤,直接在原图上绘制,减少IO操作且避免格式问题:
$image = new Imagick('image.jpg'); $draw = new ImagickDraw(); $text = 'watermark text'; $draw->setFontFamily('Arial'); $draw->setFontSize(50); $draw->setFillColor('rgba(255,255,255,0.3)'); // 可选:设置带透明度的描边 // $draw->setStrokeColor('rgba(0,0,0,0.3)'); // $draw->setStrokeWidth(1); $draw->setStrokeAntialias(true); $draw->setTextAntialias(true); $qfm = $image->queryFontMetrics($draw, $text); $image_width = $image->getImageWidth(); $image_height = $image->getImageHeight(); $text_x = floor(($image_width - $qfm['textWidth']) / 2); $text_y = floor(($image_height + $qfm['ascender']) / 2); $image->annotateImage($draw, $text_x, $text_y, 0, $text); $image->writeImage('result.jpg');
内容的提问来源于stack exchange,提问作者reinforcers
相关产品推荐
相关产品推荐

