简体   繁体   English

用GD PHP水印PNG图像时的局部黑色背景

[英]Partial black background when watermarking PNG image with GD PHP

I have pieced together a PHP class to perform various image related functions using GD functions of PHP. 我已经拼凑了一个PHP类,使用PHP的GD函数执行各种与图像相关的函数。

It works great for all image types. 它适用于所有图像类型。 Rotate, flip, resize, crop and to a lesser extent, watermark. 旋转,翻转,调整大小,裁剪以及较小程度的水印。

All but the latter work perfectly. 除了后者之外的所有工作都完美 For example after a few changes, rotated PNG images retained their transparency whereas before they were losing that and the background turning black. 例如,经过一些更改后,旋转的PNG图像保持其透明度,而在它们丢失之前,背景变黑。 Common problem, it appears. 看来常见的问题。 But all working now. 但现在一切正常。

Where I'm still getting stuck is watermarking a PNG image with another PNG image. 我仍然卡住的地方是用另一个PNG图像为PNG图像添加水印。 It appears to work fine with JPG and other images. 它似乎与JPG和其他图像一起使用。 This is the code (simplified): 这是代码(简化):

public function writeWatermarkSimple()
{
    $watermarkFile = 'watermark.png';
    $watermarkImage = imagecreatefrompng($watermarkFile);

    imagealphablending($watermarkImage, false);
    imagesavealpha($watermarkImage, true);

    $imageFile = 'image.png';
    $baseImage = imagecreatefrompng($imageFile);

    imagealphablending($baseImage, false);
    imagesavealpha($baseImage, true);

    $marginH = imagesx($baseImage) - imagesx($watermarkImage);
    $marginV = imagesy($baseImage) - imagesy($watermarkImage);

    $cut = imagecreatetruecolor(imagesx($watermarkImage), imagesy($watermarkImage));
    imagecopy($cut, $baseImage, 0, 0, $marginH, $marginV, imagesx($watermarkImage), imagesy($watermarkImage));
    imagecopy($cut, $watermarkImage, 0, 0, 0, 0, imagesx($watermarkImage), imagesy($watermarkImage));

    imagecopymerge($baseImage, $cut, $marginH, $marginV, 0, 0, imagesx($watermarkImage), imagesy($watermarkImage), 80);

    if (!imagepng($baseImage, 'watermarked_image.png'))
    {
        return false;
    }

    return true;
}

This has been pieced together with various guides and advice people have given based on a similar issue. 这已经与人们基于类似问题给出的各种指南和建议拼凑在一起。 Again, working perfectly with JPG images and PNG watermarks, but not PNG & PNG. 再次,完美地与JPG图像和PNG水印,但不是PNG和PNG。

Some example images: 一些示例图片:

http://i.imgur.com/hHRWinj.png - This is the watermark I'm using. http://i.imgur.com/hHRWinj.png - 这是我正在使用的水印。 http://i.imgur.com/6sy8Ncs.png - This is the image I'm applying the watermark to. http://i.imgur.com/6sy8Ncs.png - 这是我正在应用水印的图像。 http://i.imgur.com/ghovYLm.png - This is the end result. http://i.imgur.com/ghovYLm.png - 这是最终结果。

The bit I find interesting is that any part of the watermark that is overlaid on a non-transparent portion of the image is working fine. 我觉得有趣的是,覆盖在图像的非透明部分上的水印的任何部分都能正常工作。 Just the rest of it has the black background. 其余部分都是黑色背景。

This leads me to believe I'm close, and I hope that the expertise of you fine people may lead me to the solution. 这让我相信自己很亲近,我希望你这些优秀人才的专业知识可以引导我找到解决方案。

Thanks ever so for reading. 非常感谢您的阅读。

So, I'm not giving up on finding the correct answer to do this using GD. 所以,我并没有放弃使用GD来找到正确的答案。 However, I was overjoyed to find that what needed up to 30 lines of code with GD can be achieved using much less with ImageMagick: 但是,我非常高兴地发现,使用ImageMagick可以使用更少的代码来实现GD需要多达30行的代码:

    $image = new Imagick();
    $image->readimage($this->_image);

    $watermark = new Imagick();
    $watermark->readimage($this->_watermark->_getImage());
    $watermark->evaluateImage(Imagick::EVALUATE_DIVIDE, 2, Imagick::CHANNEL_ALPHA);

    $image->compositeImage($watermark, imagick::COMPOSITE_OVER, $marginH, $marginV);

So this is before (with GD): http://i.imgur.com/AlS0TcO.png 所以这是之前(使用GD): http//i.imgur.com/AlS0TcO.png

And after (with ImageMagick and the code above): http://i.imgur.com/zBxlC3R.png 之后(使用ImageMagick和上面的代码): http//i.imgur.com/zBxlC3R.png

If anyone has an answer that is purely GD then I'd be immensely grateful. 如果有人的答案纯粹是GD,那么我会非常感激。

Ran into some similar issues recently and while this may not exactly solve your problem, these were some useful discoveries that I made. 最近遇到了一些类似的问题,虽然这可能无法解决你的问题,但这些都是我做的一些有用的发现。

In my case, I have an original .jpg image and a watermark .png image. 就我而言,我有一个原始的.jpg图像和一个水印.png图像。 The watermark image has a fully transparent background. 水印图像具有完全透明的背景。 I wanted to specify the opacity in my script and have it change the watermark opacity before placing it on top of the origina image. 我想在我的脚本中指定不透明度,并在将其置于原始图像顶部之前更改水印不透明度。 Most posts out there regarding PHP watermarking assume that the original watermark .png file already has the solid watermark portion set to the correct opacity rather than changing it via the script. 关于PHP水印的大多数帖子假设原始水印.png文件已经将实心水印部分设置为正确的不透明度而不是通过脚本更改它。

  1. gd didn't like a 24 bit .png and caused some goofy issues. gd不喜欢24位.png并引起了一些愚蠢的问题。 Switching to 8 bit resolved that with gd . 切换到8位用gd解决了这个问题。 On the other hand, imagick works very well with a 24 bit .png and the final result seems to be better. 另一方面, imagick与24位.png效果非常好,最终结果似乎更好。
  2. For me, using gd worked just fine if I was opening the original watermark .png and using imagecopymerge() to set the watermark transparency. 对我来说,如果我打开原始水印.png并使用imagecopymerge()设置水印透明度,使用gd工作得很好。 If however I tried to scale the original watermark .png (which has transparent background) first, then I would get similar results as you with black or white background portion of where watermark image is. 但是,如果我首先尝试缩放原始水印.png (具有透明背景),那么我会得到与水印图像所在的黑色或白色背景部分类似的结果。 See How do I resize pngs with transparency in PHP? 请参阅如何在PHP中使用透明度调整png的大小? for a partial solution by filling the new wm image with transparent rectangle first. 通过首先用透明矩形填充新的wm图像来获得部分解决方案。 For me this still produced an opaque white background on the final result no matter what I tried. 对我来说,无论我尝试什么,这仍然会在最终结果上产生不透明的白色背景。
  3. I switched to imagick and was using setImageOpacity() to change the transparency of my watermark .png before applying it on top of my original image and I was still getting the same effect with a black background. 我切换到imagick并使用setImageOpacity()来改变我的水印.png的透明度,然后将其应用到原始图像之上,我仍然在黑色背景下获得相同的效果。 Finally read in the PHP doc for setImageOpacity() that if the original .png has any transparent pixels and you try to lower the opacity, those pixels become opaque (black) with the new transparency applied. 最后在PHP文档中读取setImageOpacity() ,如果原始.png具有任何透明像素并且您尝试降低不透明度,那么这些像素将变为不透明(黑色)并应用新的透明度。 Instead, need to use the evaluateImage() function. 相反,需要使用evaluateImage()函数。 This will instead evaluate each pixel's alpha channel only and divide by the specifid number. 这将仅改为评估每个像素的alpha通道并除以特定的数字。
  4. I assume the black / white background issue with gd is likely due to similar ways that it treats alpha channels when scaling / combining as compared to imagick and if you want to do it all in gd you just need to find some similar way to evaluate and manipulate the alpha channel per-pixel because the "easy" ways seem to take an already transparent background and make it opaque. 我认为gd的黑/白背景问题很可能是因为与imagick相比,它在缩放/组合时处理alpha通道的方式相似,如果你想在gd完成所有这些,你只需要找到一些类似的方法来评估和操纵每像素的alpha通道,因为“简单”的方式似乎采用已经透明的背景并使其不透明。

So, the solution: 所以,解决方案:

Assuming you want to apply your watermark at an opacity of 45% and you're using imagick , then instead of this: 假设您想以45%的不透明度应用水印并且您正在使用imagick ,那么请改为:

$watermark->setImageOpacity(.45);

do this 做这个

$watermark->evaluateImage(Imagick::EVALUATE_DIVIDE, (1/.45), Imagick::CHANNEL_ALPHA);

You need to divide 1 by your opacity to get the demoninator by which the function will divide the alpha channel value for each pixel. 您需要将1除以不透明度以获得幻化器,函数将为每个像素划分Alpha通道值。 In this case, 1/.45 = 2.2222 , so then the function will divide the alpha channel of each pixel by 2.2222 . 在这种情况下, 1/.45 = 2.2222 ,那么函数将每个像素的alpha通道除以2.2222 This means a solid pixel (alpha of 1 ) would result in 1/2.2222 or .45 alpha or transparency when finished. 这意味着实心像素(alpha为1 )在完成时会产生1/2.2222.45 alpha或透明度。 Any pixels that were already transparent (alpha 0 ) would stay transparent because 0 divided by anything is always what? 任何已经透明的像素(alpha 0 )都会保持透明,因为0除以任何东西总是如此? Zero! 零!

After you change the watermark transparency then you can use compositeImage() to merge the watermark onto the original image. 更改水印透明度后,您可以使用compositeImage()将水印合并到原始图像上。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM