Use transparency info when converting from RGB to LA

This commit is contained in:
Andrew Murray 2024-03-26 19:55:22 +11:00
parent 8b6a182815
commit ab8f465f1a
3 changed files with 19 additions and 6 deletions

View File

@ -183,6 +183,10 @@ def test_trns_RGB(tmp_path: Path) -> None:
assert im_l.info["transparency"] == im_l.getpixel((0, 0)) # undone
im_l.save(f)
im_la = im.convert("LA")
assert "transparency" not in im_la.info
im_la.save(f)
im_p = im.convert("P")
assert "transparency" in im_p.info
im_p.save(f)

View File

@ -979,7 +979,7 @@ class Image:
# transparency handling
if has_transparency:
if (self.mode in ("1", "L", "I", "I;16") and mode in ("LA", "RGBA")) or (
self.mode == "RGB" and mode in ("RGBa", "RGBA")
self.mode == "RGB" and mode in ("LA", "RGBa", "RGBA")
):
# Use transparent conversion to promote from transparent
# color to an alpha channel.

View File

@ -500,12 +500,12 @@ rgba2rgb_(UINT8 *out, const UINT8 *in, int xsize) {
/*
* Conversion of RGB + single transparent color either to
* RGBA, where any pixel matching the color will have the alpha channel set to 0, or
* RGBA or LA, where any pixel matching the color will have the alpha channel set to 0, or
* RGBa, where any pixel matching the color will have all channels set to 0
*/
static void
rgbT2rgba(UINT8 *out, int xsize, int r, int g, int b, int premultiplied) {
rgbT2a(UINT8 *out, UINT8 *in, int xsize, int r, int g, int b, int premultiplied) {
#ifdef WORDS_BIGENDIAN
UINT32 trns = ((r & 0xff) << 24) | ((g & 0xff) << 16) | ((b & 0xff) << 8) | 0xff;
UINT32 repl = premultiplied ? 0 : (trns & 0xffffff00);
@ -516,9 +516,10 @@ rgbT2rgba(UINT8 *out, int xsize, int r, int g, int b, int premultiplied) {
int i;
for (i = 0; i < xsize; i++, out += sizeof(trns)) {
UINT8 *ref = in != NULL ? in : out;
for (i = 0; i < xsize; i++, ref += sizeof(trns), out += sizeof(trns)) {
UINT32 v;
memcpy(&v, out, sizeof(v));
memcpy(&v, ref, sizeof(v));
if (v == trns) {
memcpy(out, &repl, sizeof(repl));
}
@ -1683,6 +1684,9 @@ ImagingConvertTransparent(Imaging imIn, const char *mode, int r, int g, int b) {
ImagingShuffler convert;
Imaging imOut = NULL;
int premultiplied = 0;
// If the transparency matches pixels in the source image, not the converted image
UINT8 *source;
int source_transparency = 0;
int y;
if (!imIn) {
@ -1694,6 +1698,9 @@ ImagingConvertTransparent(Imaging imIn, const char *mode, int r, int g, int b) {
if (strcmp(mode, "RGBa") == 0) {
premultiplied = 1;
}
} else if (strcmp(imIn->mode, "RGB") == 0 && strcmp(mode, "LA") == 0) {
convert = rgb2la;
source_transparency = 1;
} else if ((strcmp(imIn->mode, "1") == 0 ||
strcmp(imIn->mode, "I") == 0 ||
strcmp(imIn->mode, "I;16") == 0 ||
@ -1731,7 +1738,9 @@ ImagingConvertTransparent(Imaging imIn, const char *mode, int r, int g, int b) {
ImagingSectionEnter(&cookie);
for (y = 0; y < imIn->ysize; y++) {
(*convert)((UINT8 *)imOut->image[y], (UINT8 *)imIn->image[y], imIn->xsize);
rgbT2rgba((UINT8 *)imOut->image[y], imIn->xsize, r, g, b, premultiplied);
source = source_transparency ? (UINT8 *)imIn->image[y] : NULL;
rgbT2a((UINT8 *)imOut->image[y], source, imIn->xsize, r, g, b, premultiplied);
}
ImagingSectionLeave(&cookie);