PHP GD2:如何保持 alpha 通道透明度和正确的 gamma

发布于 2024-09-10 12:47:18 字数 1631 浏览 1 评论 0原文

我对图像缩放的这个讨论很感兴趣,随后发现 PHP我用来从上传的图像创建缩略图的代码也遇到同样的问题。我决定尝试底部附近发布的 PHP 修复(将 gamma 从 2.2 转换为 1.0、调整图像大小、将 gamma 从 1.0 转换回 2.2)。这可以解决文章中提到的问题,但是对代码的这种修改会带来不幸的副作用,即破坏 PNG alpha 通道透明度。

这是我进行了伽玛校正的代码。

<?php
$image = imagecreatefrompng($source_file);
$resized_image = imagecreatetruecolor($new_width, $new_height);
imagealphablending($resized_image, false);
imagesavealpha($resized_image, true);
imagegammacorrect($image, 2.2, 1.0);
imagecopyresampled($resized_image, $image, 0, 0, 0, 0, $new_width, $new_height, $image_width, $image_height);
imagegammacorrect($resized_image, 1.0, 2.2);
imagepng($resized_image, $dest_file);
?>

任何人都知道如何使用伽马校正技巧来调整图像大小,同时保持原始图像的 alpha 通道透明度?

编辑

示例图像:

  1. 原始文件 - 具有 alpha 通道透明度的 PNG
  2. 使用两个 imagegamma Correct() 函数调用调整大小的文件注释掉
  3. 使用两个 imagegamma Correct() 函数调用调整大小的文件

您可以看到透明度很好,直到您尝试校正伽马。 (查看透明度的最简单方法是检查图像周围的段落标签,并通过 FireBug 或类似的方式添加背景:黑色;到其样式属性。)

原始图片 http://ender.hosting.emarketsouth.com/images/test-image.png 无伽玛校正 http://ender.hosting.emarketsouth .com/images/test-image-resized-no-gamma.png 伽玛校正 - 无透明度 http://ender.hosting.emarketsouth.com /images/test-image-resized.png

I was intrigued by this discussion of image scaling and subsequently found out that the PHP code I'm using to create thumbnails from uploaded images suffers from the same problem. I decided to try the PHP fix posted near the bottom (converting gamma from 2.2 to 1.0, resizing the image, converting gamma back from 1.0 to 2.2). This works to solve the issue noted in the article, however this modification to the code has the unfortunate side effect of knocking out PNG alpha channel transparency.

Here is the code I have with the gamma correction in place.

<?php
$image = imagecreatefrompng($source_file);
$resized_image = imagecreatetruecolor($new_width, $new_height);
imagealphablending($resized_image, false);
imagesavealpha($resized_image, true);
imagegammacorrect($image, 2.2, 1.0);
imagecopyresampled($resized_image, $image, 0, 0, 0, 0, $new_width, $new_height, $image_width, $image_height);
imagegammacorrect($resized_image, 1.0, 2.2);
imagepng($resized_image, $dest_file);
?>

Anyone know how to resize the image, employing the gamma correction trick, while maintaining the alpha channel transparency of the original image?

Edit

sample images:

  1. original file - PNG with alpha channel transparency
  2. resized file with both imagegammacorrect() function calls commented out
  3. resized file with both imagegammacorrect() function calls in place

You can see that the transparency is fine until you attempt to correct the gamma. (easiest way to see the transparency is working below is to inspect the paragraph tag wrapped around the images and add a background: black; to its style attribute via FireBug or similar.)

original image http://ender.hosting.emarketsouth.com/images/test-image.png
no gamma correction http://ender.hosting.emarketsouth.com/images/test-image-resized-no-gamma.png
gamma corrected - no transparency http://ender.hosting.emarketsouth.com/images/test-image-resized.png

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

小情绪 2024-09-17 12:47:18

这是一些有效的代码。基本上,它会分离出 alpha 通道,使用 gamma 校正调整图像大小,在不使用 gamma 校正的情况下调整 alpha 通道的大小,然后将 alpha 通道复制到使用 gamma 校正完成的调整大小的图像。

我的猜测是 imagegamma Correct() 函数有一个错误。也许 gamma 仅适用于 RGB,而 GD 也尝试对 alpha 通道进行相同的计算?色彩理论不是我的强项。

无论如何,这是代码。不幸的是,我找不到比逐一循环像素更好的方法来分离通道。哦,好吧...

<?php
// Load image
$image = imagecreatefrompng('test-image.png');

// Create destination
$resized_image = imagecreatetruecolor(100, 100);
imagealphablending($resized_image, false); // Overwrite alpha
imagesavealpha($resized_image, true);

// Create a separate alpha channel
$alpha_image = imagecreatetruecolor(200, 200);
imagealphablending($alpha_image, false); // Overwrite alpha
imagesavealpha($alpha_image, true);

for ($x = 0; $x < 200; $x++) {
    for ($y = 0; $y < 200; $y++) {
        $alpha = (imagecolorat($image, $x, $y) >> 24) & 0xFF;
        $color = imagecolorallocatealpha($alpha_image, 0, 0, 0, $alpha);
        imagesetpixel($alpha_image, $x, $y, $color);
    }
}

// Resize image to destination, using gamma correction
imagegammacorrect($image, 2.2, 1.0);
imagecopyresampled($resized_image, $image, 0, 0, 0, 0, 100, 100, 200, 200);
imagegammacorrect($resized_image, 1.0, 2.2);

// Resize alpha channel
$alpha_resized_image = imagecreatetruecolor(200, 200);
imagealphablending($alpha_resized_image, false);
imagesavealpha($alpha_resized_image, true);

imagecopyresampled($alpha_resized_image, $alpha_image, 0, 0, 0, 0, 100, 100, 200, 200);

// Copy alpha channel back to resized image
for ($x = 0; $x < 100; $x++) {
    for ($y = 0; $y < 100; $y++) {
        $alpha = (imagecolorat($alpha_resized_image, $x, $y) >> 24) & 0xFF;
        $rgb = imagecolorat($resized_image, $x, $y);
        $r = ($rgb >> 16 ) & 0xFF;
        $g = ($rgb >> 8 ) & 0xFF;
        $b = $rgb & 0xFF;
        $color = imagecolorallocatealpha($resized_image, $r, $g, $b, $alpha);
        imagesetpixel($resized_image, $x, $y, $color);
    }
}

imagepng($resized_image, 'test-image-scaled.png');
?>

当然用变量替换硬编码值...这是我使用您的图像和我的代码得到的结果:

调整图像大小
(来源:jejik.com

Here's some code that does work. Basically, it separates out the alpha channel, resizes the image using gamma correct, resizes the alpha channel without gamma correct, then copies over the alpha channel to the resized image that was done with gamma correct.

My guess is that the imagegammacorrect() function has a bug. Perhaps gamma only applies to RGB and GD tries to do the same calculation to the alpha channel as well? Color theory is not my forte.

Anyway, here's the code. Unfortunately I could not find a better way to separate out the channels than to loop over the pixels one-by-one. Oh well...

<?php
// Load image
$image = imagecreatefrompng('test-image.png');

// Create destination
$resized_image = imagecreatetruecolor(100, 100);
imagealphablending($resized_image, false); // Overwrite alpha
imagesavealpha($resized_image, true);

// Create a separate alpha channel
$alpha_image = imagecreatetruecolor(200, 200);
imagealphablending($alpha_image, false); // Overwrite alpha
imagesavealpha($alpha_image, true);

for ($x = 0; $x < 200; $x++) {
    for ($y = 0; $y < 200; $y++) {
        $alpha = (imagecolorat($image, $x, $y) >> 24) & 0xFF;
        $color = imagecolorallocatealpha($alpha_image, 0, 0, 0, $alpha);
        imagesetpixel($alpha_image, $x, $y, $color);
    }
}

// Resize image to destination, using gamma correction
imagegammacorrect($image, 2.2, 1.0);
imagecopyresampled($resized_image, $image, 0, 0, 0, 0, 100, 100, 200, 200);
imagegammacorrect($resized_image, 1.0, 2.2);

// Resize alpha channel
$alpha_resized_image = imagecreatetruecolor(200, 200);
imagealphablending($alpha_resized_image, false);
imagesavealpha($alpha_resized_image, true);

imagecopyresampled($alpha_resized_image, $alpha_image, 0, 0, 0, 0, 100, 100, 200, 200);

// Copy alpha channel back to resized image
for ($x = 0; $x < 100; $x++) {
    for ($y = 0; $y < 100; $y++) {
        $alpha = (imagecolorat($alpha_resized_image, $x, $y) >> 24) & 0xFF;
        $rgb = imagecolorat($resized_image, $x, $y);
        $r = ($rgb >> 16 ) & 0xFF;
        $g = ($rgb >> 8 ) & 0xFF;
        $b = $rgb & 0xFF;
        $color = imagecolorallocatealpha($resized_image, $r, $g, $b, $alpha);
        imagesetpixel($resized_image, $x, $y, $color);
    }
}

imagepng($resized_image, 'test-image-scaled.png');
?>

Replace hard-coded values with variables of course... And here's the result I get using your image and my code:

Resized image
(source: jejik.com)

究竟谁懂我的在乎 2024-09-17 12:47:18

imagecopyresampled() 和透明度存在问题。查看 php.net 上的这条评论可能的解决方案。

There is a problem with imagecopyresampled() and transparency. Take a look at this comment on php.net for a possible solution.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文