如何将 imagecropauto() 与 IMG_CROP_TRANSPARENT 一起使用?

问题描述 投票:0回答:2

当我尝试裁剪图像的透明区域时,它会保持原始大小,并且透明区域会变成黑色。

如果我运行这段代码:

<?php
    // Create a 300x300px transparant image with a 100px wide red circle in the middle
    $i = imagecreatetruecolor(300, 300);
    imagealphablending($i, FALSE);
    imagesavealpha($i, TRUE);
    $transparant = imagecolorallocatealpha($i, 0xDD, 0xDD, 0xDD, 0x7F);
    imagefill($i, 0, 0, $transparant);
    $red = imagecolorallocate($i, 0xFF, 0x0, 0x0);
    imagefilledellipse($i, 150, 150, 100, 100, $red);
    imagepng($i, "red_300.png");

    // Crop away transparant parts and save
    $i2 = imagecropauto($i, IMG_CROP_TRANSPARENT);
    imagepng($i2, "red_crop_trans.png");
    imagedestroy($i2);

    // Crop away bg-color parts and save
    $i2 = imagecropauto($i, IMG_CROP_SIDES);
    imagepng($i2, "red_crop_sides.png");
    imagedestroy($i2);

    // clean up org image
    imagedestroy($i);

我最终得到了一个

red_crop_trans.png
图像,它是一个
300x300px
黑色图像,其中有一个
100x100px
红色圆圈。 还有一个 red_crop_sides.png,它是一个
100x100px
黑色图像,其中有
100x100px
红色圆圈。

为什么 red_crop_trans.png 没有被裁剪为

100x100px
?为什么两个图像的背景都是黑色的?如何在保持透明度的同时裁剪它们?

php gd
2个回答
3
投票

我花了一段时间才弄清楚到底发生了什么。事实证明

$i2 = imagecropauto($i, IMG_CROP_TRANSPARENT);
返回 false 而不是 true。根据文档:

imagecropauto() 在没有任何可裁剪的内容或没有内容时返回 FALSE 整个图像将被裁剪。

所以我用了

IMG_CROP_TRANSPARENT
代替了
IMG_CROP_DEFAULT

尝试使用 IMG_CROP_TRANSPARENT,如果失败,则会回退到 IMG_CROP_SIDES。

这给了我预期的结果。现在我自己没有得到任何黑色背景。但这是一个已知问题,因此很容易找到解决方案:

imagecolortransparent($i, $transparant); // Set background transparent

这让我看到了最终完成的代码:

<?php
    // Create a 300x300px transparant image with a 100px wide red circle in the middle
    $i = imagecreatetruecolor(300, 300);
    imagealphablending($i, FALSE);
    imagesavealpha($i, TRUE);
    $transparant = imagecolorallocatealpha($i, 0xDD, 0xDD, 0xDD, 0x7F);
    imagecolortransparent($i, $transparant); // Set background transparent
    imagefill($i, 0, 0, $transparant);
    $red = imagecolorallocate($i, 0xFF, 0x0, 0x0);
    imagefilledellipse($i, 150, 150, 100, 100, $red);
    imagepng($i, "red_300.png");

    // Crop away transparant parts and save
    $i2 = imagecropauto($i, IMG_CROP_DEFAULT); //Attempts to use IMG_CROP_TRANSPARENT and if it fails it falls back to IMG_CROP_SIDES.
    imagepng($i2, "red_crop_trans.png");
    imagedestroy($i2);

    // Crop away bg-color parts and save
    $i2 = imagecropauto($i, IMG_CROP_SIDES);
    imagepng($i2, "red_crop_sides.png");
    imagedestroy($i2);

    // clean up org image
    imagedestroy($i);

?>

0
投票

这里是对这个 IMG_CROP_TRANSPARENT 标志的更详细解释以及它为什么有效和为什么无效。它实际上与函数imagecrop相关,如果你查看php源代码,它有一行非常奇怪的代码,并且正在做类似这样的事情

gdImagePtr gdImageCrop(gdImagePtr src, const gdRectPtr crop)
{
    gdImagePtr dst;
    int alphaBlendingFlag;

    if (gdImageTrueColor(src)) {
        dst = gdImageCreateTrueColor(crop->width, crop->height);
    } else {
        dst = gdImageCreate(crop->width, crop->height);
    }
    if (!dst) return NULL;
    alphaBlendingFlag = dst->alphaBlendingFlag;
    gdImageAlphaBlending(dst, gdEffectReplace);
    gdImageCopy(dst, src, 0, 0, crop->x, crop->y, crop->width, crop->height);
    gdImageAlphaBlending(dst, alphaBlendingFlag);

    return dst;
}
找到要裁剪的边缘后,

imagecropimagecropauto 调用。正如您在调用 gdImageCopy 之前所看到的,由于某些未知的原因!!!,开发人员调用了 gdImageAlphaBlending(dst, gdEffectReplace);。它的作用是将 Alpha 颜色替换为黑色。 Alpha 颜色是您在使用 imagecolortransparent 函数时定义的颜色。

所以现在,如果你想使用标志 IMG_CROP_TRANSPARENT,你需要设置 alpha 颜色,因为最初它是“-1”,即使你从 PNG 创建图像。然后该函数将正确裁剪图像,但会用黑色替换透明背景,因为来自 C 源代码的那行代码。所以你不能设置alpha颜色,所以你不能同时使用IMG_CROP_TRANSPARENT

相反,有效的是使用标志IMG_CROP_SIDES,在C源代码中调用函数gdGuessBackgroundColorFromCorners,我猜它试图在图像边缘找到透明颜色,但会不设置 Alpha 颜色。

现在仍然是个谜,为什么开发人员决定在裁剪时复制图像之前替换 Alpha 颜色。

© www.soinside.com 2019 - 2024. All rights reserved.