Reputation: 2391
I'm adding a transparent PNG watermark to an image. 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):
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?
Upvotes: 0
Views: 2338
Reputation: 1
I ran into similar issue recently. What worked for me was after resampleing image was to re-setting alpha to pixles that were broken. I got the idea from zuegs on https://www.php.net/manual/en/function.imagecopyresampled.php . It is not full solution to a problem, just an idea that could help.
$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);
}
}
}
}
Upvotes: 0
Reputation: 2391
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. GD Quality Issue with Transparent PNGs has the same issue.
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.
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.
Upvotes: 3
Reputation: 53
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);
Upvotes: 3
Reputation: 8751
Okay, first of all, here's your "dirty" test image with the RGB channels (above) and alpha channel (below) separated:
I've replaced pure white (#FFFFFF
)/100% transparent with blue to highlight the speckles.
As you can see, GD adds speckles to both the RGB channels and the alpha channel.
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.
I notice that you have an embedded color profile in the source PNG. Try removing that; the artefacts may be caused by GD doing color correction. (In Photoshop, you should use Save for 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:
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. This way you avoid resizing any image while it has an alpha channel, which may avoid visible artifacts.
Upvotes: 1