【问题标题】:imagecopyresampled() introduces artifacts in transparent PNGimagecopyresampled() 在透明 PNG 中引入伪影
【发布时间】:2014-06-02 11:52:37
【问题描述】:

我正在向图像添加透明 PNG 水印。水印是高分辨率的,所以在将其覆盖在原始图像中之前,我调整了它的大小。这似乎在水印中引入了一些我还没有找到避免的方法。

原图:

调整大小的图像(查看字母之间的水平线状“污垢”):

缩放调整大小的图像(不透明)以阐明我所说的字母之间的“污垢”是什么意思。我用选择工具清理了“s”和“t”之间的区域并删除(在新选项卡中打开以查看更清晰的完整尺寸):

这是我正在使用的代码:

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);
}

知道是什么导致了伪影吗?

【问题讨论】:

  • 我没有看到任何文物?
  • 它们不是很明显,但字母之间的 100% 透明区域(在原图中)在调整大小的图像中包含一些模糊的灰色线条/点。
  • 是的,没关系,用更好的显示器看照片,它们很明显。

标签: php gd


【解决方案1】:

这似乎不会发生在黑色背景上,所以另一个技巧是在调整大小之前反转图像,然后再做一次

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);

【讨论】:

    【解决方案2】:

    正如我在回复 Søren Løvborgs 回答的评论中所写的,看起来这只是 [GD/imagecopyresampled()][1] 的一个问题,无法轻易避免。 GD Quality Issue with Transparent PNGs 也有同样的问题。

    可以使用 Søren Løvborgs 建议的解决方法,但请记住,由于两次调整原始图像的大小,它可能会导致明显的质量下降。

    我建议在叠加之前使用照片编辑器调整水印的大小。这不是那么灵活,但它会保持图像质量并且不会添加任何噪点。

    【讨论】:

      【解决方案3】:

      好的,首先,这是您的“脏”测试图像,RGB 通道(上)和 Alpha 通道(下)分开:

      我已将纯白色 (#FFFFFF)/100% 透明替换为蓝色以突出斑点。

      如您所见,GD 为 RGB 通道和 Alpha 通道添加了斑点。

      没有检查 GD 代码,我猜测它是由舍入误差引起的,导致某些像素偏离 1 或 2。

      我注意到您在源 PNG 中嵌入了颜色配置文件。尝试删除它;伪影可能是由 GD 进行颜色校正造成的。 (在 Photoshop 中,您应该使用 Save for Web。)

      否则,我无法在不修复 GD 代码的情况下提出解决此问题的方法,但是,我可以建议一种可能有效的变通方法:

      您可以将目标图像调整为水印大小,覆盖水印,删除 alpha 通道,然后调整为旧的目标图像大小,而不是将水印调整为目标图像大小,然后将其覆盖在目标图像上.这样可以避免在任何图像具有 Alpha 通道时调整其大小,这可能会避免可见的伪影。

      【讨论】:

      • 我尝试在 Photoshop 中为网页保存 - 没有变化。看起来这只是 GD/imagecopyresampled() 的问题(我现在看到其他人也有同样的问题,例如stackoverflow.com/questions/23200823/…)。 imagecopyresized() 似乎可以更好地处理透明度,但它的重采样很糟糕并且会产生一些非常锯齿状的边缘。
      【解决方案4】:

      我最近遇到了类似的问题。对我有用的是在重新采样图像之后将 alpha 重新设置为损坏的像素。我在https://www.php.net/manual/en/function.imagecopyresampled.php 上从zuegs 那里得到了这个想法。 这不是一个问题的完整解决方案,只是一个可以提供帮助的想法。

      $transindex = imagecolorallocatealpha($dst_img, 0, 0, 0, 127);
      imagefill($dst_img, 0, 0, $transindex);
      imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $new_w, $new_h, $origw, $origh);
      if ($transindex >= 0) {
          imagecolortransparent($dst_img, $transindex);
          for ($y = 0; $y < $new_h; ++$y) {
              for ($x = 0; $x < $new_w; ++$x) {
                  if (((imagecolorat($dst_img, $x, $y) >> 24) & 0x7F) >= 100) {
                      imagesetpixel($dst_img, $x, $y, $transindex);
                  }
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-05-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-07
        • 2018-07-10
        • 2012-12-22
        相关资源
        最近更新 更多