Skip to content

Commit 819b8ac

Browse files
committed
Improved PA conversion
1 parent 2adfea9 commit 819b8ac

2 files changed

Lines changed: 120 additions & 26 deletions

File tree

Tests/test_image_convert.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ def convert(im, mode):
1212
self.assertEqual(out.mode, mode)
1313
self.assertEqual(out.size, im.size)
1414

15-
modes = "1", "L", "I", "F", "RGB", "RGBA", "RGBX", "CMYK", "YCbCr"
15+
modes = ("1", "L", "LA", "P", "PA", "I", "F",
16+
"RGB", "RGBA", "RGBX", "CMYK", "YCbCr")
1617

1718
for mode in modes:
1819
im = hopper(mode)

src/libImaging/Convert.c

Lines changed: 118 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -913,6 +913,15 @@ p2bit(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
913913
*out++ = (L(&palette[in[x]*4]) >= 128000) ? 255 : 0;
914914
}
915915

916+
static void
917+
pa2bit(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
918+
{
919+
int x;
920+
/* FIXME: precalculate greyscale palette? */
921+
for (x = 0; x < xsize; x++, in += 4)
922+
*out++ = (L(&palette[in[0]*4]) >= 128000) ? 255 : 0;
923+
}
924+
916925
static void
917926
p2l(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
918927
{
@@ -922,6 +931,28 @@ p2l(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
922931
*out++ = L(&palette[in[x]*4]) / 1000;
923932
}
924933

934+
static void
935+
pa2l(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
936+
{
937+
int x;
938+
/* FIXME: precalculate greyscale palette? */
939+
for (x = 0; x < xsize; x++, in += 4)
940+
*out++ = L(&palette[in[0]*4]) / 1000;
941+
}
942+
943+
static void
944+
p2pa(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
945+
{
946+
int x;
947+
for (x = 0; x < xsize; x++, in+=4) {
948+
const UINT8* rgba = &palette[in[0] * 4];
949+
*out++ = in[0];
950+
*out++ = in[0];
951+
*out++ = in[0];
952+
*out++ = rgba[3];
953+
}
954+
}
955+
925956
static void
926957
p2la(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
927958
{
@@ -939,9 +970,9 @@ pa2la(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
939970
{
940971
int x;
941972
/* FIXME: precalculate greyscale palette? */
942-
for (x = 0; x < xsize; x++, in += 2) {
943-
*out++ = L(&palette[in[0]*4]) / 1000;
944-
*out++ = in[1];
973+
for (x = 0; x < xsize; x++, in += 4, out += 4) {
974+
out[0] = out[1] = out[2] = L(&palette[in[0]*4]) / 1000;
975+
out[3] = in[3];
945976
}
946977
}
947978

@@ -954,6 +985,15 @@ p2i(UINT8* out_, const UINT8* in, int xsize, const UINT8* palette)
954985
*out++ = L(&palette[in[x]*4]) / 1000;
955986
}
956987

988+
static void
989+
pa2i(UINT8* out_, const UINT8* in, int xsize, const UINT8* palette)
990+
{
991+
int x;
992+
INT32* out = (INT32*) out_;
993+
for (x = 0; x < xsize; x++, in += 4)
994+
*out++ = L(&palette[in[0]*4]) / 1000;
995+
}
996+
957997
static void
958998
p2f(UINT8* out_, const UINT8* in, int xsize, const UINT8* palette)
959999
{
@@ -963,6 +1003,15 @@ p2f(UINT8* out_, const UINT8* in, int xsize, const UINT8* palette)
9631003
*out++ = (float) L(&palette[in[x]*4]) / 1000.0F;
9641004
}
9651005

1006+
static void
1007+
pa2f(UINT8* out_, const UINT8* in, int xsize, const UINT8* palette)
1008+
{
1009+
int x;
1010+
FLOAT32* out = (FLOAT32*) out_;
1011+
for (x = 0; x < xsize; x++, in += 4)
1012+
*out++ = (float) L(&palette[in[0]*4]) / 1000.0F;
1013+
}
1014+
9661015
static void
9671016
p2rgb(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
9681017
{
@@ -976,6 +1025,19 @@ p2rgb(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
9761025
}
9771026
}
9781027

1028+
static void
1029+
pa2rgb(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
1030+
{
1031+
int x;
1032+
for (x = 0; x < xsize; x++, in += 4) {
1033+
const UINT8* rgb = &palette[in[0] * 4];
1034+
*out++ = rgb[0];
1035+
*out++ = rgb[1];
1036+
*out++ = rgb[2];
1037+
*out++ = 255;
1038+
}
1039+
}
1040+
9791041
static void
9801042
p2rgba(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
9811043
{
@@ -1009,13 +1071,27 @@ p2cmyk(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
10091071
rgb2cmyk(out, out, xsize);
10101072
}
10111073

1074+
static void
1075+
pa2cmyk(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
1076+
{
1077+
pa2rgb(out, in, xsize, palette);
1078+
rgb2cmyk(out, out, xsize);
1079+
}
1080+
10121081
static void
10131082
p2ycbcr(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
10141083
{
10151084
p2rgb(out, in, xsize, palette);
10161085
ImagingConvertRGB2YCbCr(out, out, xsize);
10171086
}
10181087

1088+
static void
1089+
pa2ycbcr(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
1090+
{
1091+
pa2rgb(out, in, xsize, palette);
1092+
ImagingConvertRGB2YCbCr(out, out, xsize);
1093+
}
1094+
10191095
static Imaging
10201096
frompalette(Imaging imOut, Imaging imIn, const char *mode)
10211097
{
@@ -1032,27 +1108,27 @@ frompalette(Imaging imOut, Imaging imIn, const char *mode)
10321108
alpha = !strcmp(imIn->mode, "PA");
10331109

10341110
if (strcmp(mode, "1") == 0)
1035-
convert = p2bit;
1111+
convert = alpha ? pa2bit : p2bit;
10361112
else if (strcmp(mode, "L") == 0)
1037-
convert = p2l;
1113+
convert = alpha ? pa2l : p2l;
10381114
else if (strcmp(mode, "LA") == 0)
1039-
convert = (alpha) ? pa2la : p2la;
1115+
convert = alpha ? pa2la : p2la;
10401116
else if (strcmp(mode, "PA") == 0)
1041-
convert = l2la;
1117+
convert = p2pa;
10421118
else if (strcmp(mode, "I") == 0)
1043-
convert = p2i;
1119+
convert = alpha ? pa2i : p2i;
10441120
else if (strcmp(mode, "F") == 0)
1045-
convert = p2f;
1121+
convert = alpha ? pa2f : p2f;
10461122
else if (strcmp(mode, "RGB") == 0)
1047-
convert = p2rgb;
1123+
convert = alpha ? pa2rgb : p2rgb;
10481124
else if (strcmp(mode, "RGBA") == 0)
1049-
convert = (alpha) ? pa2rgba : p2rgba;
1125+
convert = alpha ? pa2rgba : p2rgba;
10501126
else if (strcmp(mode, "RGBX") == 0)
1051-
convert = p2rgba;
1127+
convert = alpha ? pa2rgba : p2rgba;
10521128
else if (strcmp(mode, "CMYK") == 0)
1053-
convert = p2cmyk;
1129+
convert = alpha ? pa2cmyk : p2cmyk;
10541130
else if (strcmp(mode, "YCbCr") == 0)
1055-
convert = p2ycbcr;
1131+
convert = alpha ? pa2ycbcr : p2ycbcr;
10561132
else
10571133
return (Imaging) ImagingError_ValueError("conversion not supported");
10581134

@@ -1073,16 +1149,19 @@ frompalette(Imaging imOut, Imaging imIn, const char *mode)
10731149
#pragma optimize("", off)
10741150
#endif
10751151
static Imaging
1076-
topalette(Imaging imOut, Imaging imIn, ImagingPalette inpalette, int dither)
1152+
topalette(Imaging imOut, Imaging imIn, const char *mode, ImagingPalette inpalette, int dither)
10771153
{
10781154
ImagingSectionCookie cookie;
1155+
int alpha;
10791156
int x, y;
10801157
ImagingPalette palette = inpalette;;
10811158

10821159
/* Map L or RGB/RGBX/RGBA to palette image */
10831160
if (strcmp(imIn->mode, "L") != 0 && strncmp(imIn->mode, "RGB", 3) != 0)
10841161
return (Imaging) ImagingError_ValueError("conversion not supported");
10851162

1163+
alpha = !strcmp(mode, "PA");
1164+
10861165
if (palette == NULL) {
10871166
/* FIXME: make user configurable */
10881167
if (imIn->bands == 1)
@@ -1094,7 +1173,7 @@ topalette(Imaging imOut, Imaging imIn, ImagingPalette inpalette, int dither)
10941173
if (!palette)
10951174
return (Imaging) ImagingError_ValueError("no palette");
10961175

1097-
imOut = ImagingNew2Dirty("P", imOut, imIn);
1176+
imOut = ImagingNew2Dirty(mode, imOut, imIn);
10981177
if (!imOut) {
10991178
if (palette != inpalette)
11001179
ImagingPaletteDelete(palette);
@@ -1109,8 +1188,13 @@ topalette(Imaging imOut, Imaging imIn, ImagingPalette inpalette, int dither)
11091188

11101189
/* Greyscale palette: copy data as is */
11111190
ImagingSectionEnter(&cookie);
1112-
for (y = 0; y < imIn->ysize; y++)
1113-
memcpy(imOut->image[y], imIn->image[y], imIn->linesize);
1191+
for (y = 0; y < imIn->ysize; y++) {
1192+
if (alpha) {
1193+
l2la((UINT8*) imOut->image[y], (UINT8*) imIn->image[y], imIn->xsize);
1194+
} else {
1195+
memcpy(imOut->image[y], imIn->image[y], imIn->linesize);
1196+
}
1197+
}
11141198
ImagingSectionLeave(&cookie);
11151199

11161200
} else {
@@ -1141,7 +1225,7 @@ topalette(Imaging imOut, Imaging imIn, ImagingPalette inpalette, int dither)
11411225
int g, g0, g1, g2;
11421226
int b, b0, b1, b2;
11431227
UINT8* in = (UINT8*) imIn->image[y];
1144-
UINT8* out = imOut->image8[y];
1228+
UINT8* out = alpha ? (UINT8*) imOut->image32[y] : imOut->image8[y];
11451229
int* e = errors;
11461230

11471231
r = r0 = r1 = 0;
@@ -1160,7 +1244,12 @@ topalette(Imaging imOut, Imaging imIn, ImagingPalette inpalette, int dither)
11601244
cache = &ImagingPaletteCache(palette, r, g, b);
11611245
if (cache[0] == 0x100)
11621246
ImagingPaletteCacheUpdate(palette, r, g, b);
1163-
out[x] = (UINT8) cache[0];
1247+
if (alpha) {
1248+
out[x*4] = out[x*4+1] = out[x*4+2] = (UINT8) cache[0];
1249+
out[x*4+3] = 255;
1250+
} else {
1251+
out[x] = (UINT8) cache[0];
1252+
}
11641253

11651254
r -= (int) palette->palette[cache[0]*4];
11661255
g -= (int) palette->palette[cache[0]*4+1];
@@ -1193,7 +1282,7 @@ topalette(Imaging imOut, Imaging imIn, ImagingPalette inpalette, int dither)
11931282
for (y = 0; y < imIn->ysize; y++) {
11941283
int r, g, b;
11951284
UINT8* in = (UINT8*) imIn->image[y];
1196-
UINT8* out = imOut->image8[y];
1285+
UINT8* out = alpha ? (UINT8*) imOut->image32[y] : imOut->image8[y];
11971286

11981287
for (x = 0; x < imIn->xsize; x++, in += 4) {
11991288
INT16* cache;
@@ -1204,8 +1293,12 @@ topalette(Imaging imOut, Imaging imIn, ImagingPalette inpalette, int dither)
12041293
cache = &ImagingPaletteCache(palette, r, g, b);
12051294
if (cache[0] == 0x100)
12061295
ImagingPaletteCacheUpdate(palette, r, g, b);
1207-
out[x] = (UINT8) cache[0];
1208-
1296+
if (alpha) {
1297+
out[x*4] = out[x*4+1] = out[x*4+2] = (UINT8) cache[0];
1298+
out[x*4+3] = 255;
1299+
} else {
1300+
out[x] = (UINT8) cache[0];
1301+
}
12091302
}
12101303
}
12111304
ImagingSectionLeave(&cookie);
@@ -1335,8 +1428,8 @@ convert(Imaging imOut, Imaging imIn, const char *mode,
13351428
if (strcmp(imIn->mode, "P") == 0 || strcmp(imIn->mode, "PA") == 0)
13361429
return frompalette(imOut, imIn, mode);
13371430

1338-
if (strcmp(mode, "P") == 0)
1339-
return topalette(imOut, imIn, palette, dither);
1431+
if (strcmp(mode, "P") == 0 || strcmp(mode, "PA") == 0)
1432+
return topalette(imOut, imIn, mode, palette, dither);
13401433

13411434
if (dither && strcmp(mode, "1") == 0)
13421435
return tobilevel(imOut, imIn, dither);

0 commit comments

Comments
 (0)