Skip to content

Commit d734c8b

Browse files
authored
Merge pull request #7888 from radarhere/convert_rgb
2 parents 6464d5c + e79d174 commit d734c8b

File tree

3 files changed

+41
-11
lines changed

3 files changed

+41
-11
lines changed

Tests/test_image_convert.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,14 @@ def test_trns_RGB(tmp_path: Path) -> None:
183183
assert im_l.info["transparency"] == im_l.getpixel((0, 0)) # undone
184184
im_l.save(f)
185185

186+
im_la = im.convert("LA")
187+
assert "transparency" not in im_la.info
188+
im_la.save(f)
189+
190+
im_la = im.convert("La")
191+
assert "transparency" not in im_la.info
192+
assert im_la.getpixel((0, 0)) == (0, 0)
193+
186194
im_p = im.convert("P")
187195
assert "transparency" in im_p.info
188196
im_p.save(f)
@@ -191,6 +199,10 @@ def test_trns_RGB(tmp_path: Path) -> None:
191199
assert "transparency" not in im_rgba.info
192200
im_rgba.save(f)
193201

202+
im_rgba = im.convert("RGBa")
203+
assert "transparency" not in im_rgba.info
204+
assert im_rgba.getpixel((0, 0)) == (0, 0, 0, 0)
205+
194206
im_p = pytest.warns(UserWarning, im.convert, "P", palette=Image.Palette.ADAPTIVE)
195207
assert "transparency" not in im_p.info
196208
im_p.save(f)

src/PIL/Image.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -978,7 +978,7 @@ def convert_transparency(m, v):
978978
# transparency handling
979979
if has_transparency:
980980
if (self.mode in ("1", "L", "I", "I;16") and mode in ("LA", "RGBA")) or (
981-
self.mode == "RGB" and mode == "RGBA"
981+
self.mode == "RGB" and mode in ("La", "LA", "RGBa", "RGBA")
982982
):
983983
# Use transparent conversion to promote from transparent
984984
# color to an alpha channel.

src/libImaging/Convert.c

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -499,26 +499,27 @@ rgba2rgb_(UINT8 *out, const UINT8 *in, int xsize) {
499499
}
500500

501501
/*
502-
* Conversion of RGB + single transparent color to RGBA,
503-
* where any pixel that matches the color will have the
504-
* alpha channel set to 0
502+
* Conversion of RGB + single transparent color either to
503+
* RGBA or LA, where any pixel matching the color will have the alpha channel set to 0, or
504+
* RGBa or La, where any pixel matching the color will have all channels set to 0
505505
*/
506506

507507
static void
508-
rgbT2rgba(UINT8 *out, int xsize, int r, int g, int b) {
508+
rgbT2a(UINT8 *out, UINT8 *in, int xsize, int r, int g, int b, int premultiplied) {
509509
#ifdef WORDS_BIGENDIAN
510510
UINT32 trns = ((r & 0xff) << 24) | ((g & 0xff) << 16) | ((b & 0xff) << 8) | 0xff;
511-
UINT32 repl = trns & 0xffffff00;
511+
UINT32 repl = premultiplied ? 0 : (trns & 0xffffff00);
512512
#else
513513
UINT32 trns = (0xffU << 24) | ((b & 0xff) << 16) | ((g & 0xff) << 8) | (r & 0xff);
514-
UINT32 repl = trns & 0x00ffffff;
514+
UINT32 repl = premultiplied ? 0 : (trns & 0x00ffffff);
515515
#endif
516516

517517
int i;
518518

519-
for (i = 0; i < xsize; i++, out += sizeof(trns)) {
519+
UINT8 *ref = in != NULL ? in : out;
520+
for (i = 0; i < xsize; i++, ref += sizeof(trns), out += sizeof(trns)) {
520521
UINT32 v;
521-
memcpy(&v, out, sizeof(v));
522+
memcpy(&v, ref, sizeof(v));
522523
if (v == trns) {
523524
memcpy(out, &repl, sizeof(repl));
524525
}
@@ -941,12 +942,14 @@ static struct {
941942
{"RGB", "1", rgb2bit},
942943
{"RGB", "L", rgb2l},
943944
{"RGB", "LA", rgb2la},
945+
{"RGB", "La", rgb2la},
944946
{"RGB", "I", rgb2i},
945947
{"RGB", "F", rgb2f},
946948
{"RGB", "BGR;15", rgb2bgr15},
947949
{"RGB", "BGR;16", rgb2bgr16},
948950
{"RGB", "BGR;24", rgb2bgr24},
949951
{"RGB", "RGBA", rgb2rgba},
952+
{"RGB", "RGBa", rgb2rgba},
950953
{"RGB", "RGBX", rgb2rgba},
951954
{"RGB", "CMYK", rgb2cmyk},
952955
{"RGB", "YCbCr", ImagingConvertRGB2YCbCr},
@@ -1681,14 +1684,27 @@ ImagingConvertTransparent(Imaging imIn, const char *mode, int r, int g, int b) {
16811684
ImagingSectionCookie cookie;
16821685
ImagingShuffler convert;
16831686
Imaging imOut = NULL;
1687+
int premultiplied = 0;
1688+
// If the transparency matches pixels in the source image, not the converted image
1689+
UINT8 *source;
1690+
int source_transparency = 0;
16841691
int y;
16851692

16861693
if (!imIn) {
16871694
return (Imaging)ImagingError_ModeError();
16881695
}
16891696

1690-
if (strcmp(imIn->mode, "RGB") == 0 && strcmp(mode, "RGBA") == 0) {
1697+
if (strcmp(imIn->mode, "RGB") == 0 && (strcmp(mode, "RGBA") == 0 || strcmp(mode, "RGBa") == 0)) {
16911698
convert = rgb2rgba;
1699+
if (strcmp(mode, "RGBa") == 0) {
1700+
premultiplied = 1;
1701+
}
1702+
} else if (strcmp(imIn->mode, "RGB") == 0 && (strcmp(mode, "LA") == 0 || strcmp(mode, "La") == 0)) {
1703+
convert = rgb2la;
1704+
source_transparency = 1;
1705+
if (strcmp(mode, "La") == 0) {
1706+
premultiplied = 1;
1707+
}
16921708
} else if ((strcmp(imIn->mode, "1") == 0 ||
16931709
strcmp(imIn->mode, "I") == 0 ||
16941710
strcmp(imIn->mode, "I;16") == 0 ||
@@ -1726,7 +1742,9 @@ ImagingConvertTransparent(Imaging imIn, const char *mode, int r, int g, int b) {
17261742
ImagingSectionEnter(&cookie);
17271743
for (y = 0; y < imIn->ysize; y++) {
17281744
(*convert)((UINT8 *)imOut->image[y], (UINT8 *)imIn->image[y], imIn->xsize);
1729-
rgbT2rgba((UINT8 *)imOut->image[y], imIn->xsize, r, g, b);
1745+
1746+
source = source_transparency ? (UINT8 *)imIn->image[y] : NULL;
1747+
rgbT2a((UINT8 *)imOut->image[y], source, imIn->xsize, r, g, b, premultiplied);
17301748
}
17311749
ImagingSectionLeave(&cookie);
17321750

0 commit comments

Comments
 (0)