简体   繁体   English

imagecopyresampled()在透明PNG中引入伪像

[英]imagecopyresampled() introduces artifacts in transparent PNG

I'm adding a transparent PNG watermark to an image. 我在图像上添加了透明的PNG水印。 The watermark is high resolution so before overlaying it in the original image I resize it. 水印是高分辨率的,因此在将其覆盖在原始图像中之前,请先调整其大小。 This seems to introduce some artifacts in the watermark that I haven't found a way to avoid. 这似乎在水印中引入了一些我没有找到避免方法的伪像。

Original image: 原始图片: 在此处输入图片说明

Resized image (look at the horizontal line-like "dirt" between letters"): 调整大小后的图片(请看字母之间的水平线状“污垢”): 在此处输入图片说明

Zoom of resized image (not transparent) to clarify what I mean by the "dirt" between the letters. 调整大小后的图像的缩放(不透明),以阐明字母之间的“污垢”是什么意思。 The area between "s" and "t" I've cleaned with the select tool and delete (open in new tab to see full size where it's more clear): 我已经使用选择工具清理并删除了“ s”和“ t”之间的区域(在新标签页中打开以查看更清晰的完整尺寸): 在此处输入图片说明

Here's the code I'm using: 这是我正在使用的代码:

function resizeImage($image_filename, $out_filename, $width, $height){
  // Get image info
  $image_info = @getimagesize($image_filename);
  if ($image_info == false) return false;
  $org_width = $image_info[0];
  $org_height = $image_info[1];
  $image_type = $image_info[2];

  // Open image
  if ($image_type == IMAGETYPE_JPEG) $org_image = @imagecreatefromjpeg($image_filename);
  else if ($image_type == IMAGETYPE_GIF) $org_image = @imagecreatefromgif($image_filename);
  else if ($image_type == IMAGETYPE_PNG) $org_image = @imagecreatefrompng($image_filename);
  else return false;

  // Open stream for resized image
  $resized_image = @imagecreatetruecolor($width, $height);
  if ($resized_image == false) return false;

  // Handle transparency in PNGs
  if ($image_type == IMAGETYPE_PNG){
    $transparent = imagecolorallocatealpha($resized_image, 255, 255, 255, 127);
    imagefilledrectangle($resized_image, 0, 0, $width, $height, $transparent);
    imagealphablending($resized_image, false);
    imagesavealpha($resized_image, true);
  }

  // Resize
  $resize_result = @imagecopyresampled($resized_image, $org_image, 0, 0, 0, 0, $width, $height, $org_width, $org_height);

  // Free original image
  @imagedestroy($org_image);

  // Save
  if ($image_type == IMAGETYPE_JPEG) $save_result = imagejpeg($resized_image, $out_filename, 90); // 90 = compression
  else if ($image_type == IMAGETYPE_GIF) $save_result = imagegif($resized_image, $out_filename);
  else if ($image_type == IMAGETYPE_PNG) $save_result =  imagepng($resized_image, $out_filename, 0);

  // Free resized image
  if ($resize_result) @imagedestroy($resized_image);

  return ($resize_result && $save_result);
}

Any idea on what is causing the artifacts? 对造成这些伪像的原因有任何想法吗?

As I wrote in my comment in response to Søren Løvborgs answer it looks like it's simply [an issue with GD/ imagecopyresampled()][1] that can not be easily avoided. 正如我在回应SørenLøvborgs的评论中所写的那样,它看起来[GD / imagecopyresampled()][1]一个问题imagecopyresampled()][1]很难避免。 GD Quality Issue with Transparent PNGs has the same issue. 具有透明PNG的GD质量问题也存在同样的问题。

It's possible to use Søren Løvborgs suggested workaround, just keep in mind that it may introduce noticable quality reduction due to resizing the original image twice. 可以使用SørenLøvborgs建议的解决方法,但要记住,由于将原始图像调整为两倍大小,可能会导致明显的质量下降。

I suggest using a photo editor to resize the watermark before overlaying instead. 我建议在覆盖之前使用照片编辑器调整水印的大小。 This isn't as flexible, but it will keep the image quality and not add any noise. 这不是那么灵活,但是可以保持图像质量并且不会增加任何噪音。

This does not seem to occur on black backgrounds, so another hack would be to invert the image before resizing and do it again after 在黑色背景上似乎不会发生这种情况,因此另一招是在调整大小之前反转图像,然后在调整大小后再次执行

imagefilter($org_image, IMG_FILTER_NEGATE);
imagecopyresampled($resized_image, $org_image, 0, 0, 0, 0, $width, $height, $org_width, $org_height);
imagefilter($resized_image, IMG_FILTER_NEGATE);

Okay, first of all, here's your "dirty" test image with the RGB channels (above) and alpha channel (below) separated: 好的,首先,这是RGB通道(上方)和alpha通道(下方)分开的“脏”测试图像:

脏图像分成通道

I've replaced pure white ( #FFFFFF )/100% transparent with blue to highlight the speckles. 我用蓝色替换了纯白色( #FFFFFF )/ 100%透明以突出斑点。

As you can see, GD adds speckles to both the RGB channels and the alpha channel. 如您所见,GD将斑点添加到RGB通道和alpha通道。

Without having examined the GD code, I'm guessing that it's caused by a rounding error, causing some pixels to be off by 1 or 2. 在没有检查GD代码的情况下,我猜测它是由舍入错误引起的,导致一些像素偏离1或2。

I notice that you have an embedded color profile in the source PNG. 我注意到您在源PNG中具有嵌入式颜色配置文件。 Try removing that; 尝试删除它; the artefacts may be caused by GD doing color correction. 伪影可能是由GD进行色彩校正引起的。 (In Photoshop, you should use Save for Web.) (在Photoshop中,您应该使用“另存为Web”。)

Otherwise, I can't suggest a way to solve this without fixing the GD code, however, I can suggest a dirty workaround, which might work: 否则,我不能建议一种无需修复GD代码即可解决此问题的方法,但是,我可以建议一种肮脏的解决方法,该方法可能会起作用:

Instead of resizing the watermark to the target image size, then overlaying it on the target image, you can resize the target image to the watermark size, overlay the watermark, drop the alpha channel and then resize to the old target image size. 无需将水印调整为目标图像大小,然后将其覆盖在目标图像上,您可以将目标图像调整为水印大小,覆盖水印,删除alpha通道,然后调整为旧的目标图像大小。 This way you avoid resizing any image while it has an alpha channel, which may avoid visible artifacts. 这样,您可以避免在具有Alpha通道的情况下调整任何图像的大小,这可以避免出现可见的伪像。

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

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