Php imagecopyresampled()在透明PNG中引入瑕疵

Php imagecopyresampled()在透明PNG中引入瑕疵,php,gd,Php,Gd,我正在向图像添加一个透明的PNG水印。水印是高分辨率的,所以在将其覆盖到原始图像之前,我会调整其大小。这似乎在水印中引入了一些我无法避免的瑕疵 原始图像: 调整大小的图像(查看字母之间的水平线,如“污垢”): 缩放已调整大小的图像(非透明),以澄清我所说的字母之间的“污垢”是什么意思。我已使用“选择”工具清理了“s”和“t”之间的区域并将其删除(在“新建”选项卡中打开以查看更清晰的全尺寸): 以下是我使用的代码: function resizeImage($image_filename,

我正在向图像添加一个透明的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);
}

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

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

我用蓝色代替了纯白(
#FFFFFF
)/100%透明以突出斑点

如您所见,GD将散斑添加到RGB通道和alpha通道

在没有检查GD代码的情况下,我猜测它是由舍入错误引起的,导致一些像素偏离1或2

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

否则,我不能建议一种不修复GD代码的方法来解决这个问题,但是,我可以建议一种肮脏的解决方法,它可能会起作用:


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

正如我在回复瑟伦·勒沃格的回答时所写的那样,看起来这只是[GD/
imagecopyresampled()]的一个问题][1]
无法轻易避免。也有同样的问题

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


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

这似乎不会发生在黑色背景上,因此另一种方法是在调整大小之前反转图像,然后再进行调整

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

我没有看到任何人工制品?它们不是很明显,但是100%透明的区域(在原图中)字母之间包含一些模糊的灰线/灰点。是的,没关系,用更好的显示器看图片,它们是非常可见的。我尝试在Photoshop中为web保存-没有变化。这似乎只是GD/
imagecopyresampled()
的问题(例如,我现在看到其他人也有同样的问题).
imagecopyresized()
似乎可以更好地处理透明度,但它的重采样不好,会产生一些非常锯齿状的边缘。