From 2643a3d97133ff4d0968461f8b373d7a13834ad7 Mon Sep 17 00:00:00 2001 From: Yay295 Date: Wed, 17 Aug 2022 22:45:24 -0500 Subject: [PATCH] change pixelsize of La/LA/LA modes from 4 to 2 --- src/PIL/PyAccess.py | 16 +- src/libImaging/Access.c | 35 ++--- src/libImaging/Bands.c | 203 +++++++++----------------- src/libImaging/Convert.c | 266 ++++++++++++++++++++++------------ src/libImaging/Geometry.c | 190 +++++------------------- src/libImaging/GetBBox.c | 133 ++++++++++------- src/libImaging/Imaging.h | 9 +- src/libImaging/Jpeg2KDecode.c | 81 ++++++++++- src/libImaging/Jpeg2KEncode.c | 6 +- src/libImaging/Pack.c | 25 +--- src/libImaging/Paste.c | 114 ++++++++++----- src/libImaging/Storage.c | 15 +- src/libImaging/Unpack.c | 29 ++-- 13 files changed, 567 insertions(+), 555 deletions(-) diff --git a/src/PIL/PyAccess.py b/src/PIL/PyAccess.py index 2a48c53f7..27f9d0541 100644 --- a/src/PIL/PyAccess.py +++ b/src/PIL/PyAccess.py @@ -26,7 +26,11 @@ import sys try: from cffi import FFI + # Pixel_XA uses "r" instead of "x" for backwards compatibility. defs = """ + struct Pixel_XA { + unsigned char r,a; + }; struct Pixel_RGBA { unsigned char r,g,b,a; }; @@ -127,11 +131,11 @@ class PyAccess: return xy -class _PyAccess32_2(PyAccess): - """PA, LA, stored in first and last bytes of a 32 bit word""" +class _PyAccess16(PyAccess): + """La, LA, and PA stored in first and last bytes of a 16 bit word""" def _post_init(self, *args, **kwargs): - self.pixels = ffi.cast("struct Pixel_RGBA **", self.image32) + self.pixels = ffi.cast("struct Pixel_XA **", self.image) def get_pixel(self, x, y): pixel = self.pixels[y][x] @@ -314,9 +318,9 @@ mode_map = { "1": _PyAccess8, "L": _PyAccess8, "P": _PyAccess8, - "LA": _PyAccess32_2, - "La": _PyAccess32_2, - "PA": _PyAccess32_2, + "LA": _PyAccess16, + "La": _PyAccess16, + "PA": _PyAccess16, "RGB": _PyAccess32_3, "LAB": _PyAccess32_3, "HSV": _PyAccess32_3, diff --git a/src/libImaging/Access.c b/src/libImaging/Access.c index 514fb2929..a4bdd9a93 100644 --- a/src/libImaging/Access.c +++ b/src/libImaging/Access.c @@ -45,6 +45,11 @@ add_item(const char *mode) { /* fetch pointer to pixel line */ +static void * +line(Imaging im, int x, int y) { + return &im->image[y][x * im->pixelsize]; +} + static void * line_8(Imaging im, int x, int y) { return &im->image8[y][x]; @@ -64,21 +69,8 @@ line_32(Imaging im, int x, int y) { static void get_pixel(Imaging im, int x, int y, void *color) { - char *out = color; - - /* generic pixel access*/ - - if (im->image8) { - out[0] = im->image8[y][x]; - } else { - UINT8 *p = (UINT8 *)&im->image32[y][x]; - if (im->type == IMAGING_TYPE_UINT8 && im->bands == 2) { - out[0] = p[0]; - out[1] = p[3]; - return; - } - memcpy(out, p, im->pixelsize); - } + int pixelsize = im->pixelsize; + memcpy(color, &im->image[y][x * pixelsize], pixelsize); } static void @@ -140,11 +132,8 @@ get_pixel_32B(Imaging im, int x, int y, void *color) { static void put_pixel(Imaging im, int x, int y, const void *color) { - if (im->image8) { - im->image8[y][x] = *((UINT8 *)color); - } else { - memcpy(&im->image32[y][x], color, sizeof(INT32)); - } + int pixelsize = im->pixelsize; + memcpy(&im->image[y][x * pixelsize], color, pixelsize); } static void @@ -198,8 +187,8 @@ ImagingAccessInit() { /* populate access table */ ADD("1", line_8, get_pixel_8, put_pixel_8); ADD("L", line_8, get_pixel_8, put_pixel_8); - ADD("LA", line_32, get_pixel, put_pixel); - ADD("La", line_32, get_pixel, put_pixel); + ADD("LA", line, get_pixel, put_pixel); + ADD("La", line, get_pixel, put_pixel); ADD("I", line_32, get_pixel_32, put_pixel_32); ADD("I;16", line_16, get_pixel_16L, put_pixel_16L); ADD("I;16L", line_16, get_pixel_16L, put_pixel_16L); @@ -208,7 +197,7 @@ ImagingAccessInit() { ADD("I;32B", line_32, get_pixel_32B, put_pixel_32B); ADD("F", line_32, get_pixel_32, put_pixel_32); ADD("P", line_8, get_pixel_8, put_pixel_8); - ADD("PA", line_32, get_pixel, put_pixel); + ADD("PA", line, get_pixel, put_pixel); ADD("RGB", line_32, get_pixel_32, put_pixel_32); ADD("RGBA", line_32, get_pixel_32, put_pixel_32); ADD("RGBa", line_32, get_pixel_32, put_pixel_32); diff --git a/src/libImaging/Bands.c b/src/libImaging/Bands.c index e1b16b34a..60856b188 100644 --- a/src/libImaging/Bands.c +++ b/src/libImaging/Bands.c @@ -31,34 +31,33 @@ ImagingGetBand(Imaging imIn, int band) { return (Imaging)ImagingError_ValueError("band index out of range"); } - /* Shortcuts */ + /* Shortcut */ if (imIn->bands == 1) { return ImagingCopy(imIn); } - /* Special case for LXXA etc */ - if (imIn->bands == 2 && band == 1) { - band = 3; - } - + /* Allocate memory for result */ imOut = ImagingNewDirty("L", imIn->xsize, imIn->ysize); if (!imOut) { return NULL; } /* Extract band from image */ + int pixelsize = imIn->pixelsize; for (y = 0; y < imIn->ysize; y++) { UINT8 *in = (UINT8 *)imIn->image[y] + band; UINT8 *out = imOut->image8[y]; x = 0; + /* Copy four values at a time */ for (; x < imIn->xsize - 3; x += 4) { - UINT32 v = MAKE_UINT32(in[0], in[4], in[8], in[12]); + UINT32 v = MAKE_UINT32(in[0], in[pixelsize], in[pixelsize * 2], in[pixelsize * 3]); memcpy(out + x, &v, sizeof(v)); - in += 16; + in += pixelsize * 4; } + /* Copy any remaining values on this line */ for (; x < imIn->xsize; x++) { out[x] = *in; - in += 4; + in += pixelsize; } } @@ -66,8 +65,8 @@ ImagingGetBand(Imaging imIn, int band) { } int -ImagingSplit(Imaging imIn, Imaging bands[4]) { - int i, j, x, y; +ImagingSplit(Imaging imIn, Imaging *bands) { + int i, j, band, x, y; /* Check arguments */ if (!imIn || imIn->type != IMAGING_TYPE_UINT8) { @@ -75,12 +74,13 @@ ImagingSplit(Imaging imIn, Imaging bands[4]) { return 0; } - /* Shortcuts */ + /* Shortcut */ if (imIn->bands == 1) { bands[0] = ImagingCopy(imIn); - return imIn->bands; + return 1; } + /* Allocate memory for "bands" */ for (i = 0; i < imIn->bands; i++) { bands[i] = ImagingNewDirty("L", imIn->xsize, imIn->ysize); if (!bands[i]) { @@ -92,73 +92,22 @@ ImagingSplit(Imaging imIn, Imaging bands[4]) { } /* Extract bands from image */ - if (imIn->bands == 2) { + int pixelsize = imIn->pixelsize; + for (band = 0; band < imIn->bands; band++) { for (y = 0; y < imIn->ysize; y++) { - UINT8 *in = (UINT8 *)imIn->image[y]; - UINT8 *out0 = bands[0]->image8[y]; - UINT8 *out1 = bands[1]->image8[y]; + UINT8 *in = (UINT8 *)imIn->image[y] + band; + UINT8 *out = bands[band]->image8[y]; x = 0; + /* Copy four values at a time */ for (; x < imIn->xsize - 3; x += 4) { - UINT32 v = MAKE_UINT32(in[0], in[4], in[8], in[12]); - memcpy(out0 + x, &v, sizeof(v)); - v = MAKE_UINT32(in[0 + 3], in[4 + 3], in[8 + 3], in[12 + 3]); - memcpy(out1 + x, &v, sizeof(v)); - in += 16; + UINT32 v = MAKE_UINT32(in[0], in[pixelsize], in[pixelsize * 2], in[pixelsize * 3]); + memcpy(out + x, &v, sizeof(v)); + in += pixelsize * 4; } + /* Copy any remaining values on this line */ for (; x < imIn->xsize; x++) { - out0[x] = in[0]; - out1[x] = in[3]; - in += 4; - } - } - } else if (imIn->bands == 3) { - for (y = 0; y < imIn->ysize; y++) { - UINT8 *in = (UINT8 *)imIn->image[y]; - UINT8 *out0 = bands[0]->image8[y]; - UINT8 *out1 = bands[1]->image8[y]; - UINT8 *out2 = bands[2]->image8[y]; - x = 0; - for (; x < imIn->xsize - 3; x += 4) { - UINT32 v = MAKE_UINT32(in[0], in[4], in[8], in[12]); - memcpy(out0 + x, &v, sizeof(v)); - v = MAKE_UINT32(in[0 + 1], in[4 + 1], in[8 + 1], in[12 + 1]); - memcpy(out1 + x, &v, sizeof(v)); - v = MAKE_UINT32(in[0 + 2], in[4 + 2], in[8 + 2], in[12 + 2]); - memcpy(out2 + x, &v, sizeof(v)); - in += 16; - } - for (; x < imIn->xsize; x++) { - out0[x] = in[0]; - out1[x] = in[1]; - out2[x] = in[2]; - in += 4; - } - } - } else { - for (y = 0; y < imIn->ysize; y++) { - UINT8 *in = (UINT8 *)imIn->image[y]; - UINT8 *out0 = bands[0]->image8[y]; - UINT8 *out1 = bands[1]->image8[y]; - UINT8 *out2 = bands[2]->image8[y]; - UINT8 *out3 = bands[3]->image8[y]; - x = 0; - for (; x < imIn->xsize - 3; x += 4) { - UINT32 v = MAKE_UINT32(in[0], in[4], in[8], in[12]); - memcpy(out0 + x, &v, sizeof(v)); - v = MAKE_UINT32(in[0 + 1], in[4 + 1], in[8 + 1], in[12 + 1]); - memcpy(out1 + x, &v, sizeof(v)); - v = MAKE_UINT32(in[0 + 2], in[4 + 2], in[8 + 2], in[12 + 2]); - memcpy(out2 + x, &v, sizeof(v)); - v = MAKE_UINT32(in[0 + 3], in[4 + 3], in[8 + 3], in[12 + 3]); - memcpy(out3 + x, &v, sizeof(v)); - in += 16; - } - for (; x < imIn->xsize; x++) { - out0[x] = in[0]; - out1[x] = in[1]; - out2[x] = in[2]; - out3[x] = in[3]; - in += 4; + out[x] = *in; + in += pixelsize; } } } @@ -184,23 +133,19 @@ ImagingPutBand(Imaging imOut, Imaging imIn, int band) { return (Imaging)ImagingError_Mismatch(); } - /* Shortcuts */ + /* Shortcut */ if (imOut->bands == 1) { return ImagingCopy2(imOut, imIn); } - /* Special case for LXXA etc */ - if (imOut->bands == 2 && band == 1) { - band = 3; - } - /* Insert band into image */ + int pixelsize = imOut->pixelsize; for (y = 0; y < imIn->ysize; y++) { UINT8 *in = imIn->image8[y]; UINT8 *out = (UINT8 *)imOut->image[y] + band; for (x = 0; x < imIn->xsize; x++) { *out = in[x]; - out += 4; + out += pixelsize; } } @@ -220,19 +165,15 @@ ImagingFillBand(Imaging imOut, int band, int color) { return (Imaging)ImagingError_ValueError("band index out of range"); } - /* Special case for LXXA etc */ - if (imOut->bands == 2 && band == 1) { - band = 3; - } - color = CLIP8(color); /* Insert color into image */ + int pixelsize = imOut->pixelsize; for (y = 0; y < imOut->ysize; y++) { UINT8 *out = (UINT8 *)imOut->image[y] + band; for (x = 0; x < imOut->xsize; x++) { *out = (UINT8)color; - out += 4; + out += pixelsize; } } @@ -240,73 +181,67 @@ ImagingFillBand(Imaging imOut, int band, int color) { } Imaging -ImagingMerge(const char *mode, Imaging bands[4]) { +ImagingMerge(const char *mode, Imaging *bands) { int i, x, y; - int bandsCount = 0; + int xsize, ysize; + int bandsCount; Imaging imOut; Imaging firstBand; + Imaging band; + /* Check the first band. The size of this band is used as the size of the output image. */ firstBand = bands[0]; if (!firstBand) { return (Imaging)ImagingError_ValueError("wrong number of bands"); } + xsize = firstBand->xsize; + ysize = firstBand->ysize; - for (i = 0; i < 4; ++i) { - if (!bands[i]) { - break; - } - if (bands[i]->bands != 1) { - return (Imaging)ImagingError_ModeError(); - } - if (bands[i]->xsize != firstBand->xsize || - bands[i]->ysize != firstBand->ysize) { - return (Imaging)ImagingError_Mismatch(); - } - } - bandsCount = i; - - imOut = ImagingNewDirty(mode, firstBand->xsize, firstBand->ysize); + /* Allocate memory for the output image. This also allows us to get the number of bands this image should have. */ + imOut = ImagingNewDirty(mode, xsize, ysize); if (!imOut) { return NULL; } + /* Check that the given bands have the right mode and size */ + for (bandsCount = 0; bandsCount < imOut->bands; ++bandsCount) { + band = bands[bandsCount]; + if (!band) { + break; + } + if (band->bands != 1) { + ImagingDelete(imOut); + return (Imaging)ImagingError_ModeError(); + } + if (band->xsize != xsize || band->ysize != ysize) { + ImagingDelete(imOut); + return (Imaging)ImagingError_Mismatch(); + } + } + + /* Check that we have enough bands for the output image */ if (imOut->bands != bandsCount) { ImagingDelete(imOut); return (Imaging)ImagingError_ValueError("wrong number of bands"); } - if (imOut->bands == 1) { + /* TODO: Check that we weren't given too many bands? How? */ + + /* Shortcut */ + if (bandsCount == 1) { return ImagingCopy2(imOut, firstBand); } - if (imOut->bands == 2) { - for (y = 0; y < imOut->ysize; y++) { - UINT8 *in0 = bands[0]->image8[y]; - UINT8 *in1 = bands[1]->image8[y]; - UINT32 *out = (UINT32 *)imOut->image32[y]; - for (x = 0; x < imOut->xsize; x++) { - out[x] = MAKE_UINT32(in0[x], 0, 0, in1[x]); - } - } - } else if (imOut->bands == 3) { - for (y = 0; y < imOut->ysize; y++) { - UINT8 *in0 = bands[0]->image8[y]; - UINT8 *in1 = bands[1]->image8[y]; - UINT8 *in2 = bands[2]->image8[y]; - UINT32 *out = (UINT32 *)imOut->image32[y]; - for (x = 0; x < imOut->xsize; x++) { - out[x] = MAKE_UINT32(in0[x], in1[x], in2[x], 0); - } - } - } else if (imOut->bands == 4) { - for (y = 0; y < imOut->ysize; y++) { - UINT8 *in0 = bands[0]->image8[y]; - UINT8 *in1 = bands[1]->image8[y]; - UINT8 *in2 = bands[2]->image8[y]; - UINT8 *in3 = bands[3]->image8[y]; - UINT32 *out = (UINT32 *)imOut->image32[y]; - for (x = 0; x < imOut->xsize; x++) { - out[x] = MAKE_UINT32(in0[x], in1[x], in2[x], in3[x]); + /* Insert the bands into the image */ + int pixelsize = imOut->pixelsize; + for (i = 0; i < bandsCount; i++) { + band = bands[i]; + for (y = 0; y < ysize; y++) { + UINT8 *in = band->image8[y]; + UINT8 *out = (UINT8 *)imOut->image[y] + i; + for (x = 0; x < xsize; x++) { + *out = in[x]; + out += pixelsize; } } } diff --git a/src/libImaging/Convert.c b/src/libImaging/Convert.c index 5dc17db60..5e7479c50 100644 --- a/src/libImaging/Convert.c +++ b/src/libImaging/Convert.c @@ -57,7 +57,18 @@ round(double x) { static void bit2l(UINT8 *out, const UINT8 *in, int xsize) { int x; - for (x = 0; x < xsize; x++) *out++ = (*in++ != 0) ? 255 : 0; + for (x = 0; x < xsize; x++) { + *out++ = (*in++ != 0) ? 255 : 0; + } +} + +static void +bit2la(UINT8 *out, const UINT8 *in, int xsize) { + int x; + for (x = 0; x < xsize; x++) { + *out++ = (*in++ != 0) ? 255 : 0; + *out++ = 255; + } } static void @@ -106,9 +117,9 @@ bit2hsv(UINT8 *out, const UINT8 *in, int xsize) { } } -/* ----------------- */ -/* RGB/L conversions */ -/* ----------------- */ +/* ---------------- */ +/* L/LA conversions */ +/* ---------------- */ static void l2bit(UINT8 *out, const UINT8 *in, int xsize) { @@ -122,32 +133,28 @@ static void lA2la(UINT8 *out, const UINT8 *in, int xsize) { int x; unsigned int alpha, pixel, tmp; - for (x = 0; x < xsize; x++, in += 4) { - alpha = in[3]; + for (x = 0; x < xsize; x++, in += 2) { + alpha = in[1]; pixel = MULDIV255(in[0], alpha, tmp); *out++ = (UINT8)pixel; - *out++ = (UINT8)pixel; - *out++ = (UINT8)pixel; *out++ = (UINT8)alpha; } } -/* RGBa -> RGBA conversion to remove premultiplication - Needed for correct transforms/resizing on RGBA images */ +/* La -> LA conversion to remove premultiplication + Needed for correct transforms/resizing on LA images */ static void la2lA(UINT8 *out, const UINT8 *in, int xsize) { int x; unsigned int alpha, pixel; - for (x = 0; x < xsize; x++, in += 4) { - alpha = in[3]; + for (x = 0; x < xsize; x++, in += 2) { + alpha = in[1]; if (alpha == 255 || alpha == 0) { pixel = in[0]; } else { pixel = CLIP8((255 * in[0]) / alpha); } *out++ = (UINT8)pixel; - *out++ = (UINT8)pixel; - *out++ = (UINT8)pixel; *out++ = (UINT8)alpha; } } @@ -158,8 +165,6 @@ l2la(UINT8 *out, const UINT8 *in, int xsize) { for (x = 0; x < xsize; x++) { UINT8 v = *in++; *out++ = v; - *out++ = v; - *out++ = v; *out++ = 255; } } @@ -191,7 +196,7 @@ l2hsv(UINT8 *out, const UINT8 *in, int xsize) { static void la2l(UINT8 *out, const UINT8 *in, int xsize) { int x; - for (x = 0; x < xsize; x++, in += 4) { + for (x = 0; x < xsize; x++, in += 2) { *out++ = in[0]; } } @@ -199,27 +204,46 @@ la2l(UINT8 *out, const UINT8 *in, int xsize) { static void la2rgb(UINT8 *out, const UINT8 *in, int xsize) { int x; - for (x = 0; x < xsize; x++, in += 4) { + for (x = 0; x < xsize; x++, in += 2) { UINT8 v = in[0]; *out++ = v; *out++ = v; *out++ = v; - *out++ = in[3]; + *out++ = in[1]; } } static void la2hsv(UINT8 *out, const UINT8 *in, int xsize) { int x; - for (x = 0; x < xsize; x++, in += 4, out += 4) { - UINT8 v = in[0]; + for (x = 0; x < xsize; x++, in += 2, out += 4) { out[0] = 0; out[1] = 0; - out[2] = v; - out[3] = in[3]; + out[2] = in[0]; + out[3] = in[1]; } } +/* + * Conversion of LA + single transparent color to LA, + * where any pixel that matches the color will have the + * alpha channel set to 0 + */ + +static void +laT2la(UINT8 *out, int xsize, UINT8 l) { + int i; + for (i = 0; i < xsize; i++, out += 2) { + if (out[0] == l) { + out[1] = 0; + } + } +} + +/* --------------- */ +/* RGB conversions */ +/* --------------- */ + static void rgb2bit(UINT8 *out, const UINT8 *in, int xsize) { int x; @@ -433,10 +457,10 @@ rgb2rgba(UINT8 *out, const UINT8 *in, int xsize) { static void rgba2la(UINT8 *out, const UINT8 *in, int xsize) { int x; - for (x = 0; x < xsize; x++, in += 4, out += 4) { + for (x = 0; x < xsize; x++, in += 4, out += 2) { /* ITU-R Recommendation 601-2 (assuming nonlinear RGB) */ - out[0] = out[1] = out[2] = L24(in) >> 16; - out[3] = in[3]; + out[0] = L24(in) >> 16; + out[1] = in[3]; } } @@ -531,7 +555,7 @@ l2cmyk(UINT8 *out, const UINT8 *in, int xsize) { static void la2cmyk(UINT8 *out, const UINT8 *in, int xsize) { int x; - for (x = 0; x < xsize; x++, in += 4) { + for (x = 0; x < xsize; x++, in += 2) { *out++ = 0; *out++ = 0; *out++ = 0; @@ -619,6 +643,23 @@ i2l(UINT8 *out, const UINT8 *in_, int xsize) { } } +static void +i2la(UINT8 *out, const UINT8 *in, int xsize) { + int x; + for (x = 0; x < xsize; x++, in += 4) { + INT32 v; + memcpy(&v, in, sizeof(v)); + if (v <= 0) { + *out++ = 0; + } else if (v >= 255) { + *out++ = 255; + } else { + *out++ = (UINT8)v; + } + *out++ = 255; + } +} + static void i2f(UINT8 *out_, const UINT8 *in_, int xsize) { int x; @@ -735,7 +776,7 @@ l2ycbcr(UINT8 *out, const UINT8 *in, int xsize) { static void la2ycbcr(UINT8 *out, const UINT8 *in, int xsize) { int x; - for (x = 0; x < xsize; x++, in += 4) { + for (x = 0; x < xsize; x++, in += 2) { *out++ = in[0]; *out++ = 128; *out++ = 128; @@ -754,9 +795,9 @@ ycbcr2l(UINT8 *out, const UINT8 *in, int xsize) { static void ycbcr2la(UINT8 *out, const UINT8 *in, int xsize) { int x; - for (x = 0; x < xsize; x++, in += 4, out += 4) { - out[0] = out[1] = out[2] = in[0]; - out[3] = 255; + for (x = 0; x < xsize; x++, in += 4, out += 2) { + out[0] = in[0]; + out[1] = 255; } } @@ -873,6 +914,7 @@ static struct { } converters[] = { {"1", "L", bit2l}, + {"1", "LA", bit2la}, {"1", "I", bit2i}, {"1", "F", bit2f}, {"1", "RGB", bit2rgb}, @@ -905,6 +947,7 @@ static struct { {"La", "LA", la2lA}, {"I", "L", i2l}, + {"I", "LA", i2la}, {"I", "F", i2f}, {"I", "RGB", i2rgb}, {"I", "RGBA", i2rgb}, @@ -982,7 +1025,8 @@ static struct { {"I;16L", "F", I16L_F}, {"I;16B", "F", I16B_F}, - {NULL}}; + {NULL} +}; /* FIXME: translate indexed versions to pointer versions below this line */ @@ -1003,7 +1047,7 @@ static void pa2bit(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) { int x; /* FIXME: precalculate greyscale palette? */ - for (x = 0; x < xsize; x++, in += 4) { + for (x = 0; x < xsize; x++, in += 2) { *out++ = (L(&palette->palette[in[0] * 4]) >= 128000) ? 255 : 0; } } @@ -1021,11 +1065,43 @@ static void pa2l(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) { int x; /* FIXME: precalculate greyscale palette? */ - for (x = 0; x < xsize; x++, in += 4) { + for (x = 0; x < xsize; x++, in += 2) { *out++ = L24(&palette->palette[in[0] * 4]) >> 16; } } +static void +p2la(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) { + int x; + /* FIXME: precalculate greyscale palette? */ + for (x = 0; x < xsize; x++, out += 2) { + const UINT8 *rgba = &palette->palette[*in++ * 4]; + out[0] = L24(rgba) >> 16; + out[1] = rgba[3]; + } +} + +static void +pa2la(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) { + int x; + /* FIXME: precalculate greyscale palette? */ + for (x = 0; x < xsize; x++, in += 2, out += 2) { + out[0] = L24(&palette->palette[in[0] * 4]) >> 16; + out[1] = in[1]; + } +} + +static void +pa2p(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) { + int x; + for (x = 0; x < xsize; x++, in += 2) { + UINT8 *rgba = &palette->palette[in[0] * 4]; + *out++ = in[0]; + rgba[3] = in[1]; + } + strncpy(palette->mode, "RGBA", IMAGING_MODE_LENGTH - 1); +} + static void p2pa(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) { int x; @@ -1033,33 +1109,10 @@ p2pa(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) { for (x = 0; x < xsize; x++, in++) { const UINT8 *rgba = &palette->palette[in[0] * 4]; *out++ = in[0]; - *out++ = in[0]; - *out++ = in[0]; *out++ = rgb == 0 ? 255 : rgba[3]; } } -static void -p2la(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) { - int x; - /* FIXME: precalculate greyscale palette? */ - for (x = 0; x < xsize; x++, out += 4) { - const UINT8 *rgba = &palette->palette[*in++ * 4]; - out[0] = out[1] = out[2] = L24(rgba) >> 16; - out[3] = rgba[3]; - } -} - -static void -pa2la(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) { - int x; - /* FIXME: precalculate greyscale palette? */ - for (x = 0; x < xsize; x++, in += 4, out += 4) { - out[0] = out[1] = out[2] = L24(&palette->palette[in[0] * 4]) >> 16; - out[3] = in[3]; - } -} - static void p2i(UINT8 *out_, const UINT8 *in, int xsize, ImagingPalette palette) { int x; @@ -1073,7 +1126,7 @@ static void pa2i(UINT8 *out_, const UINT8 *in, int xsize, ImagingPalette palette) { int x; INT32 *out = (INT32 *)out_; - for (x = 0; x < xsize; x++, in += 4) { + for (x = 0; x < xsize; x++, in += 2) { *out++ = L24(&palette->palette[in[0] * 4]) >> 16; } } @@ -1091,7 +1144,7 @@ static void pa2f(UINT8 *out_, const UINT8 *in, int xsize, ImagingPalette palette) { int x; FLOAT32 *out = (FLOAT32 *)out_; - for (x = 0; x < xsize; x++, in += 4) { + for (x = 0; x < xsize; x++, in += 2) { *out++ = (float)L(&palette->palette[in[0] * 4]) / 1000.0F; } } @@ -1111,7 +1164,7 @@ p2rgb(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) { static void pa2rgb(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) { int x; - for (x = 0; x < xsize; x++, in += 4) { + for (x = 0; x < xsize; x++, in += 2) { const UINT8 *rgb = &palette->palette[in[0] * 4]; *out++ = rgb[0]; *out++ = rgb[1]; @@ -1133,7 +1186,7 @@ p2hsv(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) { static void pa2hsv(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) { int x; - for (x = 0; x < xsize; x++, in += 4, out += 4) { + for (x = 0; x < xsize; x++, in += 2, out += 4) { const UINT8 *rgb = &palette->palette[in[0] * 4]; rgb2hsv_row(out, rgb); out[3] = 255; @@ -1155,25 +1208,39 @@ p2rgba(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) { static void pa2rgba(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) { int x; - for (x = 0; x < xsize; x++, in += 4) { + for (x = 0; x < xsize; x++, in += 2) { const UINT8 *rgb = &palette->palette[in[0] * 4]; *out++ = rgb[0]; *out++ = rgb[1]; *out++ = rgb[2]; - *out++ = in[3]; + *out++ = in[1]; } } static void p2cmyk(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) { - p2rgb(out, in, xsize, palette); - rgb2cmyk(out, out, xsize); + int x; + for (x = 0; x < xsize; x++) { + /* Note: no undercolour removal */ + const UINT8 *rgb = &palette->palette[*in++ * 4]; + *out++ = ~rgb[0]; + *out++ = ~rgb[1]; + *out++ = ~rgb[2]; + *out++ = 0; + } } static void pa2cmyk(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) { - pa2rgb(out, in, xsize, palette); - rgb2cmyk(out, out, xsize); + int x; + for (x = 0; x < xsize; x++, in += 2) { + /* Note: no undercolour removal */ + const UINT8 *rgb = &palette->palette[in[0] * 4]; + *out++ = ~rgb[0]; + *out++ = ~rgb[1]; + *out++ = ~rgb[2]; + *out++ = 0; + } } static void @@ -1195,7 +1262,7 @@ frompalette(Imaging imOut, Imaging imIn, const char *mode) { int y; void (*convert)(UINT8 *, const UINT8 *, int, ImagingPalette); - /* Map palette image to L, RGB, RGBA, or CMYK */ + /* Map palette image to bit, L, LA, P, PA, I, F, RGB, RGBA, RGBX, CMYK, YCbCr, or HSV */ if (!imIn->palette) { return (Imaging)ImagingError_ValueError("no palette"); @@ -1209,7 +1276,15 @@ frompalette(Imaging imOut, Imaging imIn, const char *mode) { convert = alpha ? pa2l : p2l; } else if (strcmp(mode, "LA") == 0) { convert = alpha ? pa2la : p2la; + } else if (strcmp(mode, "P") == 0) { + if (!alpha) { + return ImagingCopy2(imOut, imIn); + } + convert = pa2p; } else if (strcmp(mode, "PA") == 0) { + if (alpha) { + return ImagingCopy2(imOut, imIn); + } convert = p2pa; } else if (strcmp(mode, "I") == 0) { convert = alpha ? pa2i : p2i; @@ -1261,7 +1336,6 @@ topalette( int alpha; int x, y; ImagingPalette palette = inpalette; - ; /* Map L or RGB/RGBX/RGBA to palette image */ if (strcmp(imIn->mode, "L") != 0 && strncmp(imIn->mode, "RGB", 3) != 0) { @@ -1307,7 +1381,6 @@ topalette( } } ImagingSectionLeave(&cookie); - } else { /* colour image */ @@ -1337,7 +1410,7 @@ topalette( int g, g0, g1, g2; int b, b0, b1, b2; UINT8 *in = (UINT8 *)imIn->image[y]; - UINT8 *out = alpha ? (UINT8 *)imOut->image32[y] : imOut->image8[y]; + UINT8 *out = (UINT8 *)imOut->image[y]; int *e = errors; r = r0 = r1 = 0; @@ -1358,8 +1431,8 @@ topalette( ImagingPaletteCacheUpdate(palette, r, g, b); } if (alpha) { - out[x * 4] = out[x * 4 + 1] = out[x * 4 + 2] = (UINT8)cache[0]; - out[x * 4 + 3] = 255; + out[x * 2] = (UINT8)cache[0]; + out[x * 2 + 1] = 255; } else { out[x] = (UINT8)cache[0]; } @@ -1403,14 +1476,13 @@ topalette( } ImagingSectionLeave(&cookie); free(errors); - } else { /* closest colour */ ImagingSectionEnter(&cookie); for (y = 0; y < imIn->ysize; y++) { int r, g, b; UINT8 *in = (UINT8 *)imIn->image[y]; - UINT8 *out = alpha ? (UINT8 *)imOut->image32[y] : imOut->image8[y]; + UINT8 *out = (UINT8 *)imOut->image[y]; for (x = 0; x < imIn->xsize; x++, in += 4) { INT16 *cache; @@ -1425,8 +1497,8 @@ topalette( ImagingPaletteCacheUpdate(palette, r, g, b); } if (alpha) { - out[x * 4] = out[x * 4 + 1] = out[x * 4 + 2] = (UINT8)cache[0]; - out[x * 4 + 3] = 255; + out[x * 2] = (UINT8)cache[0]; + out[x * 2 + 1] = 255; } else { out[x] = (UINT8)cache[0]; } @@ -1634,21 +1706,22 @@ ImagingConvertTransparent(Imaging imIn, const char *mode, int r, int g, int b) { return (Imaging)ImagingError_ModeError(); } - if (strcmp(imIn->mode, "RGB") == 0 && strcmp(mode, "RGBA") == 0) { + int rgbIn = strcmp(mode, "rgb") == 0; + int bitIn = strcmp(mode, "1") == 0; + int iIn = strcmp(mode, "I") == 0; + int lIn = strcmp(mode, "L") == 0; + int rgbaOut = strcmp(mode, "RGBA") == 0; + int laOut = strcmp(mode, "LA") == 0; + + if (rgbIn && rgbaOut) { convert = rgb2rgba; - } else if ((strcmp(imIn->mode, "1") == 0 || - strcmp(imIn->mode, "I") == 0 || - strcmp(imIn->mode, "L") == 0 - ) && ( - strcmp(mode, "RGBA") == 0 || - strcmp(mode, "LA") == 0 - )) { - if (strcmp(imIn->mode, "1") == 0) { - convert = bit2rgb; - } else if (strcmp(imIn->mode, "I") == 0) { - convert = i2rgb; + } else if ((bitIn || iIn || lIn) && (rgbaOut || laOut)) { + if (bitIn) { + convert = rgbaOut ? bit2rgb : bit2la; + } else if (iIn) { + convert = rgbaOut ? i2rgb : i2la; } else { - convert = l2rgb; + convert = rgbaOut ? l2rgb : l2la; } g = b = r; } else { @@ -1668,9 +1741,16 @@ 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); + if (rgbaOut) { + 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); + } + } else { + for (y = 0; y < imIn->ysize; y++) { + (*convert)((UINT8 *)imOut->image[y], (UINT8 *)imIn->image[y], imIn->xsize); + laT2la((UINT8 *)imOut->image[y], imIn->xsize, r); + } } ImagingSectionLeave(&cookie); diff --git a/src/libImaging/Geometry.c b/src/libImaging/Geometry.c index 0c5915792..ad36d9600 100644 --- a/src/libImaging/Geometry.c +++ b/src/libImaging/Geometry.c @@ -442,35 +442,13 @@ quad_transform(double *xout, double *yout, int x, int y, void *data) { /* transform filters (ImagingTransformFilter) */ static int -nearest_filter8(void *out, Imaging im, double xin, double yin) { +nearest_filter(void *out, Imaging im, double xin, double yin) { int x = COORD(xin); int y = COORD(yin); if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) { return 0; } - ((UINT8 *)out)[0] = im->image8[y][x]; - return 1; -} - -static int -nearest_filter16(void *out, Imaging im, double xin, double yin) { - int x = COORD(xin); - int y = COORD(yin); - if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) { - return 0; - } - memcpy(out, im->image8[y] + x * sizeof(INT16), sizeof(INT16)); - return 1; -} - -static int -nearest_filter32(void *out, Imaging im, double xin, double yin) { - int x = COORD(xin); - int y = COORD(yin); - if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) { - return 0; - } - memcpy(out, &im->image32[y][x], sizeof(INT32)); + memcpy(out, (UINT8 *)im->image[y] + x * im->pixelsize, im->pixelsize); return 1; } @@ -512,9 +490,12 @@ nearest_filter32(void *out, Imaging im, double xin, double yin) { static int bilinear_filter8(void *out, Imaging im, double xin, double yin) { + int b, pixelsize = im->pixelsize; BILINEAR_HEAD(UINT8); - BILINEAR_BODY(UINT8, im->image8, 1, 0); - ((UINT8 *)out)[0] = (UINT8)v1; + for (b = 0; b < im->bands; b++) { + BILINEAR_BODY(UINT8, im->image, pixelsize, b); + ((UINT8 *)out)[b] = (UINT8)v1; + } return 1; } @@ -538,29 +519,6 @@ bilinear_filter32F(void *out, Imaging im, double xin, double yin) { return 1; } -static int -bilinear_filter32LA(void *out, Imaging im, double xin, double yin) { - BILINEAR_HEAD(UINT8); - BILINEAR_BODY(UINT8, im->image, 4, 0); - ((UINT8 *)out)[0] = (UINT8)v1; - ((UINT8 *)out)[1] = (UINT8)v1; - ((UINT8 *)out)[2] = (UINT8)v1; - BILINEAR_BODY(UINT8, im->image, 4, 3); - ((UINT8 *)out)[3] = (UINT8)v1; - return 1; -} - -static int -bilinear_filter32RGB(void *out, Imaging im, double xin, double yin) { - int b; - BILINEAR_HEAD(UINT8); - for (b = 0; b < im->bands; b++) { - BILINEAR_BODY(UINT8, im->image, 4, b); - ((UINT8 *)out)[b] = (UINT8)v1; - } - return 1; -} - #undef BILINEAR #undef BILINEAR_HEAD #undef BILINEAR_BODY @@ -624,14 +582,17 @@ bilinear_filter32RGB(void *out, Imaging im, double xin, double yin) { static int bicubic_filter8(void *out, Imaging im, double xin, double yin) { + int b, pixelsize = im->pixelsize; BICUBIC_HEAD(UINT8); - BICUBIC_BODY(UINT8, im->image8, 1, 0); - if (v1 <= 0.0) { - ((UINT8 *)out)[0] = 0; - } else if (v1 >= 255.0) { - ((UINT8 *)out)[0] = 255; - } else { - ((UINT8 *)out)[0] = (UINT8)v1; + for (b = 0; b < im->bands; b++) { + BICUBIC_BODY(UINT8, im->image, pixelsize, b); + if (v1 <= 0.0) { + ((UINT8 *)out)[b] = 0; + } else if (v1 >= 255.0) { + ((UINT8 *)out)[b] = 255; + } else { + ((UINT8 *)out)[b] = (UINT8)v1; + } } return 1; } @@ -656,51 +617,6 @@ bicubic_filter32F(void *out, Imaging im, double xin, double yin) { return 1; } -static int -bicubic_filter32LA(void *out, Imaging im, double xin, double yin) { - BICUBIC_HEAD(UINT8); - BICUBIC_BODY(UINT8, im->image, 4, 0); - if (v1 <= 0.0) { - ((UINT8 *)out)[0] = 0; - ((UINT8 *)out)[1] = 0; - ((UINT8 *)out)[2] = 0; - } else if (v1 >= 255.0) { - ((UINT8 *)out)[0] = 255; - ((UINT8 *)out)[1] = 255; - ((UINT8 *)out)[2] = 255; - } else { - ((UINT8 *)out)[0] = (UINT8)v1; - ((UINT8 *)out)[1] = (UINT8)v1; - ((UINT8 *)out)[2] = (UINT8)v1; - } - BICUBIC_BODY(UINT8, im->image, 4, 3); - if (v1 <= 0.0) { - ((UINT8 *)out)[3] = 0; - } else if (v1 >= 255.0) { - ((UINT8 *)out)[3] = 255; - } else { - ((UINT8 *)out)[3] = (UINT8)v1; - } - return 1; -} - -static int -bicubic_filter32RGB(void *out, Imaging im, double xin, double yin) { - int b; - BICUBIC_HEAD(UINT8); - for (b = 0; b < im->bands; b++) { - BICUBIC_BODY(UINT8, im->image, 4, b); - if (v1 <= 0.0) { - ((UINT8 *)out)[b] = 0; - } else if (v1 >= 255.0) { - ((UINT8 *)out)[b] = 255; - } else { - ((UINT8 *)out)[b] = (UINT8)v1; - } - } - return 1; -} - #undef BICUBIC #undef BICUBIC_HEAD #undef BICUBIC_BODY @@ -709,58 +625,25 @@ static ImagingTransformFilter getfilter(Imaging im, int filterid) { switch (filterid) { case IMAGING_TRANSFORM_NEAREST: - if (im->image8) { - switch (im->type) { - case IMAGING_TYPE_UINT8: - return nearest_filter8; - case IMAGING_TYPE_SPECIAL: - switch (im->pixelsize) { - case 1: - return nearest_filter8; - case 2: - return nearest_filter16; - case 4: - return nearest_filter32; - } - } - } else { - return nearest_filter32; - } - break; + return nearest_filter; case IMAGING_TRANSFORM_BILINEAR: - if (im->image8) { - return bilinear_filter8; - } else if (im->image32) { - switch (im->type) { - case IMAGING_TYPE_UINT8: - if (im->bands == 2) { - return bilinear_filter32LA; - } else { - return bilinear_filter32RGB; - } - case IMAGING_TYPE_INT32: - return bilinear_filter32I; - case IMAGING_TYPE_FLOAT32: - return bilinear_filter32F; - } + switch (im->type) { + case IMAGING_TYPE_UINT8: + return bilinear_filter8; + case IMAGING_TYPE_INT32: + return bilinear_filter32I; + case IMAGING_TYPE_FLOAT32: + return bilinear_filter32F; } break; case IMAGING_TRANSFORM_BICUBIC: - if (im->image8) { - return bicubic_filter8; - } else if (im->image32) { - switch (im->type) { - case IMAGING_TYPE_UINT8: - if (im->bands == 2) { - return bicubic_filter32LA; - } else { - return bicubic_filter32RGB; - } - case IMAGING_TYPE_INT32: - return bicubic_filter32I; - case IMAGING_TYPE_FLOAT32: - return bicubic_filter32F; - } + switch (im->type) { + case IMAGING_TYPE_UINT8: + return bicubic_filter8; + case IMAGING_TYPE_INT32: + return bicubic_filter32I; + case IMAGING_TYPE_FLOAT32: + return bicubic_filter32F; } break; } @@ -786,7 +669,7 @@ ImagingGenericTransform( ImagingScaleAffine where possible. */ ImagingSectionCookie cookie; - int x, y; + int x, y, pixelsize; char *out; double xx, yy; @@ -816,16 +699,17 @@ ImagingGenericTransform( y1 = imOut->ysize; } + pixelsize = imOut->pixelsize; for (y = y0; y < y1; y++) { - out = imOut->image[y] + x0 * imOut->pixelsize; + out = imOut->image[y] + x0 * pixelsize; for (x = x0; x < x1; x++) { if (!transform(&xx, &yy, x - x0, y - y0, transform_data) || !filter(out, imIn, xx, yy)) { if (fill) { - memset(out, 0, imOut->pixelsize); + memset(out, 0, pixelsize); } } - out += imOut->pixelsize; + out += pixelsize; } } diff --git a/src/libImaging/GetBBox.c b/src/libImaging/GetBBox.c index e73153600..929b502a0 100644 --- a/src/libImaging/GetBBox.c +++ b/src/libImaging/GetBBox.c @@ -30,45 +30,57 @@ ImagingGetBBox(Imaging im, int bbox[4]) { bbox[1] = -1; bbox[2] = bbox[3] = 0; -#define GETBBOX(image, mask) \ - for (y = 0; y < im->ysize; y++) { \ - has_data = 0; \ - for (x = 0; x < im->xsize; x++) { \ - if (im->image[y][x] & mask) { \ - has_data = 1; \ - if (x < bbox[0]) { \ - bbox[0] = x; \ - } \ - if (x >= bbox[2]) { \ - bbox[2] = x + 1; \ - } \ - } \ - } \ - if (has_data) { \ - if (bbox[1] < 0) { \ - bbox[1] = y; \ - } \ - bbox[3] = y + 1; \ - } \ +#define GETBBOX(type) \ + for (y = 0; y < im->ysize; y++) { \ + has_data = 0; \ + for (x = 0; x < im->xsize; x++) { \ + if (((type *)im->image[y])[x] & mask) { \ + has_data = 1; \ + if (x < bbox[0]) { \ + bbox[0] = x; \ + } \ + if (x >= bbox[2]) { \ + bbox[2] = x + 1; \ + } \ + } \ + } \ + if (has_data) { \ + if (bbox[1] < 0) { \ + bbox[1] = y; \ + } \ + bbox[3] = y + 1; \ + } \ } - if (im->image8) { - GETBBOX(image8, 0xff); - } else { - INT32 mask = 0xffffffff; - if (im->bands == 3) { - ((UINT8 *)&mask)[3] = 0; - } else if ( - strcmp(im->mode, "RGBa") == 0 || strcmp(im->mode, "RGBA") == 0 || - strcmp(im->mode, "La") == 0 || strcmp(im->mode, "LA") == 0 || - strcmp(im->mode, "PA") == 0) { -#ifdef WORDS_BIGENDIAN - mask = 0x000000ff; -#else - mask = 0xff000000; -#endif + switch (im->pixelsize) { + case 1: { + UINT8 mask = 0xff; + GETBBOX(UINT8); + break; + } + case 2: { + UINT16 mask = 0xffff; + if (strcmp(im->mode, "La") == 0 || + strcmp(im->mode, "LA") == 0 || + strcmp(im->mode, "PA") == 0) { + ((UINT8 *)&mask)[0] = 0; + } + GETBBOX(UINT16); + break; + } + case 4: { + UINT32 mask = 0xffffffff; + if (im->bands == 3) { + ((UINT8 *)&mask)[3] = 0; + } else if ( + strcmp(im->mode, "RGBa") == 0 || + strcmp(im->mode, "RGBA") == 0) { + mask = 0; + ((UINT8 *)&mask)[3] = 0xff; + } + GETBBOX(UINT32); + break; } - GETBBOX(image32, mask); } /* Check that we got a box */ @@ -90,28 +102,39 @@ ImagingGetProjection(Imaging im, UINT8 *xproj, UINT8 *yproj) { memset(xproj, 0, im->xsize); memset(yproj, 0, im->ysize); -#define GETPROJ(image, mask) \ - for (y = 0; y < im->ysize; y++) { \ - has_data = 0; \ - for (x = 0; x < im->xsize; x++) { \ - if (im->image[y][x] & mask) { \ - has_data = 1; \ - xproj[x] = 1; \ - } \ - } \ - if (has_data) { \ - yproj[y] = 1; \ - } \ +#define GETPROJ(type) \ + for (y = 0; y < im->ysize; y++) { \ + has_data = 0; \ + for (x = 0; x < im->xsize; x++) { \ + if (((type *)im->image[y])[x] & mask) { \ + has_data = 1; \ + xproj[x] = 1; \ + } \ + } \ + if (has_data) { \ + yproj[y] = 1; \ + } \ } - if (im->image8) { - GETPROJ(image8, 0xff); - } else { - INT32 mask = 0xffffffff; - if (im->bands == 3) { - ((UINT8 *)&mask)[3] = 0; + switch (im->pixelsize) { + case 1: { + UINT8 mask = 0xff; + GETPROJ(UINT8); + break; + } + case 2: { + UINT16 mask = 0xffff; + GETPROJ(UINT16); + break; + } + case 4: { + UINT32 mask = 0xffffffff; + if (im->bands == 3) { + ((UINT8 *)&mask)[3] = 0; + } + GETPROJ(UINT32); + break; } - GETPROJ(image32, mask); } return 1; /* ok */ diff --git a/src/libImaging/Imaging.h b/src/libImaging/Imaging.h index b65f8eadd..d353ed1f9 100644 --- a/src/libImaging/Imaging.h +++ b/src/libImaging/Imaging.h @@ -39,8 +39,8 @@ extern "C" { * Lab 4 L, a, b, - * * experimental modes (incomplete): - * LA 4 L, -, -, A - * PA 4 P, -, -, A + * LA 2 L, A + * PA 2 P, A * I;16 2 I (16-bit integer, native byte order) * * "P" is an 8-bit palette mode, which should be mapped through the @@ -69,6 +69,7 @@ typedef struct ImagingPaletteInstance *ImagingPalette; #define IMAGING_TYPE_FLOAT32 2 #define IMAGING_TYPE_SPECIAL 3 /* check mode for details */ +/* array size required to store any image mode string */ #define IMAGING_MODE_LENGTH \ 6 + 1 /* Band names ("1", "L", "P", "RGB", "RGBA", "CMYK", "YCbCr", "BGR;xy") */ @@ -108,9 +109,9 @@ struct ImagingMemoryInstance { #define IMAGING_PIXEL_1(im, x, y) ((im)->image8[(y)][(x)]) #define IMAGING_PIXEL_L(im, x, y) ((im)->image8[(y)][(x)]) -#define IMAGING_PIXEL_LA(im, x, y) ((im)->image[(y)][(x)*4]) +#define IMAGING_PIXEL_LA(im, x, y) ((im)->image[(y)][(x)*2]) #define IMAGING_PIXEL_P(im, x, y) ((im)->image8[(y)][(x)]) -#define IMAGING_PIXEL_PA(im, x, y) ((im)->image[(y)][(x)*4]) +#define IMAGING_PIXEL_PA(im, x, y) ((im)->image[(y)][(x)*2]) #define IMAGING_PIXEL_I(im, x, y) ((im)->image32[(y)][(x)]) #define IMAGING_PIXEL_F(im, x, y) (((FLOAT32 *)(im)->image32[y])[x]) #define IMAGING_PIXEL_RGB(im, x, y) ((im)->image[(y)][(x)*4]) diff --git a/src/libImaging/Jpeg2KDecode.c b/src/libImaging/Jpeg2KDecode.c index cff30e2d0..1fefd0f7c 100644 --- a/src/libImaging/Jpeg2KDecode.c +++ b/src/libImaging/Jpeg2KDecode.c @@ -302,6 +302,85 @@ j2ku_graya_la( atiledata = tiledata + csiz * w * h; + for (y = 0; y < h; ++y) { + const UINT8 *data = &tiledata[csiz * y * w]; + const UINT8 *adata = &atiledata[acsiz * y * w]; + UINT8 *row = (UINT8 *)im->image[y0 + y] + x0 * 2; + for (x = 0; x < w; ++x) { + UINT32 word = 0, aword = 0, byte; + + switch (csiz) { + case 1: + word = *data++; + break; + case 2: + word = *(const UINT16 *)data; + data += 2; + break; + case 4: + word = *(const UINT32 *)data; + data += 4; + break; + } + + switch (acsiz) { + case 1: + aword = *adata++; + break; + case 2: + aword = *(const UINT16 *)adata; + adata += 2; + break; + case 4: + aword = *(const UINT32 *)adata; + adata += 4; + break; + } + + byte = j2ku_shift(offset + word, shift); + row[0] = byte; + row[1] = j2ku_shift(aoffset + aword, ashift); + row += 2; + } + } +} + +static void +j2ku_graya_rgba( + opj_image_t *in, + const JPEG2KTILEINFO *tileinfo, + const UINT8 *tiledata, + Imaging im) { + unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0; + unsigned w = tileinfo->x1 - tileinfo->x0; + unsigned h = tileinfo->y1 - tileinfo->y0; + + int shift = 8 - in->comps[0].prec; + int offset = in->comps[0].sgnd ? 1 << (in->comps[0].prec - 1) : 0; + int csiz = (in->comps[0].prec + 7) >> 3; + int ashift = 8 - in->comps[1].prec; + int aoffset = in->comps[1].sgnd ? 1 << (in->comps[1].prec - 1) : 0; + int acsiz = (in->comps[1].prec + 7) >> 3; + const UINT8 *atiledata; + + unsigned x, y; + + if (csiz == 3) { + csiz = 4; + } + if (acsiz == 3) { + acsiz = 4; + } + + if (shift < 0) { + offset += 1 << (-shift - 1); + } + if (ashift < 0) { + aoffset += 1 << (-ashift - 1); + } + + atiledata = tiledata + csiz * w * h; + for (y = 0; y < h; ++y) { const UINT8 *data = &tiledata[csiz * y * w]; const UINT8 *adata = &atiledata[acsiz * y * w]; @@ -625,7 +704,7 @@ static const struct j2k_decode_unpacker j2k_unpackers[] = { {"RGB", OPJ_CLRSPC_SRGB, 4, 1, j2ku_srgb_rgb}, {"RGB", OPJ_CLRSPC_SYCC, 4, 1, j2ku_sycc_rgb}, {"RGBA", OPJ_CLRSPC_GRAY, 1, 0, j2ku_gray_rgb}, - {"RGBA", OPJ_CLRSPC_GRAY, 2, 0, j2ku_graya_la}, + {"RGBA", OPJ_CLRSPC_GRAY, 2, 0, j2ku_graya_rgba}, {"RGBA", OPJ_CLRSPC_SRGB, 3, 1, j2ku_srgb_rgb}, {"RGBA", OPJ_CLRSPC_SYCC, 3, 1, j2ku_sycc_rgb}, {"RGBA", OPJ_CLRSPC_SRGB, 4, 1, j2ku_srgba_rgba}, diff --git a/src/libImaging/Jpeg2KEncode.c b/src/libImaging/Jpeg2KEncode.c index fe5511ba5..37b791b0d 100644 --- a/src/libImaging/Jpeg2KEncode.c +++ b/src/libImaging/Jpeg2KEncode.c @@ -129,11 +129,11 @@ j2k_pack_la(Imaging im, UINT8 *buf, unsigned x0, unsigned y0, unsigned w, unsign UINT8 *ptra = buf + w * h; unsigned x, y; for (y = 0; y < h; ++y) { - UINT8 *data = (UINT8 *)(im->image[y + y0] + 4 * x0); + UINT8 *data = (UINT8 *)(im->image[y + y0] + 2 * x0); for (x = 0; x < w; ++x) { *ptr++ = data[0]; - *ptra++ = data[3]; - data += 4; + *ptra++ = data[1]; + data += 2; } } } diff --git a/src/libImaging/Pack.c b/src/libImaging/Pack.c index 01760e742..970503612 100644 --- a/src/libImaging/Pack.c +++ b/src/libImaging/Pack.c @@ -231,26 +231,14 @@ packL16B(UINT8 *out, const UINT8 *in, int pixels) { } } -static void -packLA(UINT8 *out, const UINT8 *in, int pixels) { - int i; - /* LA, pixel interleaved */ - for (i = 0; i < pixels; i++) { - out[0] = in[R]; - out[1] = in[A]; - out += 2; - in += 4; - } -} - static void packLAL(UINT8 *out, const UINT8 *in, int pixels) { int i; /* LA, line interleaved */ for (i = 0; i < pixels; i++) { - out[i] = in[R]; - out[i + pixels] = in[A]; - in += 4; + out[i] = in[0]; + out[i + pixels] = in[1]; + in += 2; } } @@ -435,6 +423,7 @@ packI16N_I16B(UINT8 *out, const UINT8 *in, int pixels) { tmp += 2; } } + static void packI16N_I16(UINT8 *out, const UINT8 *in, int pixels) { int i; @@ -555,11 +544,11 @@ static struct { {"L", "L;16B", 16, packL16B}, /* greyscale w. alpha */ - {"LA", "LA", 16, packLA}, + {"LA", "LA", 16, copy2}, {"LA", "LA;L", 16, packLAL}, /* greyscale w. alpha premultiplied */ - {"La", "La", 16, packLA}, + {"La", "La", 16, copy2}, /* palette */ {"P", "P;1", 1, pack1}, @@ -568,7 +557,7 @@ static struct { {"P", "P", 8, copy1}, /* palette w. alpha */ - {"PA", "PA", 16, packLA}, + {"PA", "PA", 16, copy2}, {"PA", "PA;L", 16, packLAL}, /* true colour */ diff --git a/src/libImaging/Paste.c b/src/libImaging/Paste.c index fafd8141e..c472a8dc7 100644 --- a/src/libImaging/Paste.c +++ b/src/libImaging/Paste.c @@ -139,6 +139,53 @@ paste_mask_L( } } +static inline void +paste_mask_LA( + Imaging imOut, + Imaging imIn, + Imaging imMask, + int dx, + int dy, + int sx, + int sy, + int xsize, + int ysize, + int pixelsize) { + /* paste with mode "LA" matte */ + + int x, y; + unsigned int tmp1; + + if (imOut->image8) { + for (y = 0; y < ysize; y++) { + UINT8 *out = imOut->image8[y + dy] + dx; + UINT8 *in = imIn->image8[y + sy] + sx; + UINT8 *mask = (UINT8 *)imMask->image[y + sy] + sx * 2 + 1; + for (x = 0; x < xsize; x++) { + *out = BLEND(*mask, *out, *in, tmp1); + out++, in++, mask += 2; + } + } + + } else { + for (y = 0; y < ysize; y++) { + UINT8 *out = (UINT8 *)imOut->image[y + dy] + dx; + UINT8 *in = (UINT8 *)imIn->image[y + sy] + sx; + UINT8 *mask = (UINT8 *)imMask->image[y + sy] + sx * 2; + for (x = 0; x < xsize; x++) { + UINT8 a = mask[1]; + out[0] = BLEND(a, out[0], in[0], tmp1); + out[1] = BLEND(a, out[1], in[1], tmp1); + out[2] = BLEND(a, out[2], in[2], tmp1); + out[3] = BLEND(a, out[3], in[3], tmp1); + out += 4; + in += 4; + mask += 2; + } + } + } +} + static inline void paste_mask_RGBA( Imaging imOut, @@ -295,7 +342,12 @@ ImagingPaste( paste_mask_L(imOut, imIn, imMask, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize); ImagingSectionLeave(&cookie); - } else if (strcmp(imMask->mode, "LA") == 0 || strcmp(imMask->mode, "RGBA") == 0) { + } else if (strcmp(imMask->mode, "LA") == 0) { + ImagingSectionEnter(&cookie); + paste_mask_LA(imOut, imIn, imMask, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize); + ImagingSectionLeave(&cookie); + + } else if (strcmp(imMask->mode, "RGBA") == 0) { ImagingSectionEnter(&cookie); paste_mask_RGBA( imOut, imIn, imMask, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize); @@ -414,44 +466,34 @@ fill_mask_L( int x, y, i; unsigned int tmp1; - if (imOut->image8) { - for (y = 0; y < ysize; y++) { - UINT8 *out = imOut->image8[y + dy] + dx; - if (strncmp(imOut->mode, "I;16", 4) == 0) { - out += dx; - } - UINT8 *mask = imMask->image8[y + sy] + sx; - for (x = 0; x < xsize; x++) { - *out = BLEND(*mask, *out, ink[0], tmp1); - if (strncmp(imOut->mode, "I;16", 4) == 0) { - out++; - *out = BLEND(*mask, *out, ink[0], tmp1); - } - out++, mask++; - } - } + const int isI16 = strncmp(imOut->mode, "I;16", 4) == 0; + const int isRGBA = strcmp(imOut->mode, "RGBa") == 0 || strcmp(imOut->mode, "RGBA") == 0; + const int isXA = strcmp(imOut->mode, "La") == 0 || strcmp(imOut->mode, "LA") == 0 || strcmp(imOut->mode, "PA") == 0; - } else { - for (y = 0; y < ysize; y++) { - UINT8 *out = (UINT8 *)imOut->image[y + dy] + dx * pixelsize; - UINT8 *mask = (UINT8 *)imMask->image[y + sy] + sx; - for (x = 0; x < xsize; x++) { - for (i = 0; i < pixelsize; i++) { - UINT8 channel_mask = *mask; - if ((strcmp(imOut->mode, "RGBa") == 0 || - strcmp(imOut->mode, "RGBA") == 0 || - strcmp(imOut->mode, "La") == 0 || - strcmp(imOut->mode, "LA") == 0 || - strcmp(imOut->mode, "PA") == 0) && - i != 3 && channel_mask != 0) { - channel_mask = - 255 - (255 - channel_mask) * (1 - (255 - out[3]) / 255); - } - out[i] = BLEND(channel_mask, out[i], ink[i], tmp1); + int alphaChannel = -1; + if (isRGBA) { + alphaChannel = 3; + } else if (isXA) { + alphaChannel = 1; + } + + for (y = 0; y < ysize; y++) { + UINT8 *out = (UINT8 *)imOut->image[y + dy] + dx * pixelsize; + UINT8 *mask = (UINT8 *)imMask->image[y + sy] + sx; + for (x = 0; x < xsize; x++) { + for (i = 0; i < pixelsize; i++) { + UINT8 channel_mask = *mask; + if (alphaChannel >= 0 && i != alphaChannel && channel_mask != 0) { + channel_mask = 255 - (255 - channel_mask) * + (1 - (255 - out[alphaChannel]) / 255); } - out += pixelsize; - mask++; + // The I;16 modes use the same "ink" for both bytes because its single + // channel is two bytes wide. + // TODO: Should BGR, F, and I modes do this too? Something more generic? + out[i] = BLEND(channel_mask, out[i], isI16 ? ink[0] : ink[i], tmp1); } + out += pixelsize; + mask++; } } } diff --git a/src/libImaging/Storage.c b/src/libImaging/Storage.c index 76750aaf7..aa02750a1 100644 --- a/src/libImaging/Storage.c +++ b/src/libImaging/Storage.c @@ -76,9 +76,8 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) { } else if (strcmp(mode, "PA") == 0) { /* 8-bit palette with alpha */ - im->bands = 2; - im->pixelsize = 4; /* store in image32 memory */ - im->linesize = xsize * 4; + im->bands = im->pixelsize = 2; + im->linesize = xsize * 2; im->palette = ImagingPaletteNew("RGB"); } else if (strcmp(mode, "L") == 0) { @@ -88,15 +87,13 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) { } else if (strcmp(mode, "LA") == 0) { /* 8-bit greyscale (luminance) with alpha */ - im->bands = 2; - im->pixelsize = 4; /* store in image32 memory */ - im->linesize = xsize * 4; + im->bands = im->pixelsize = 2; + im->linesize = xsize * 2; } else if (strcmp(mode, "La") == 0) { /* 8-bit greyscale (luminance) with premultiplied alpha */ - im->bands = 2; - im->pixelsize = 4; /* store in image32 memory */ - im->linesize = xsize * 4; + im->bands = im->pixelsize = 2; + im->linesize = xsize * 2; } else if (strcmp(mode, "F") == 0) { /* 32-bit floating point images */ diff --git a/src/libImaging/Unpack.c b/src/libImaging/Unpack.c index e426ed74f..cd25efbca 100644 --- a/src/libImaging/Unpack.c +++ b/src/libImaging/Unpack.c @@ -413,24 +413,13 @@ unpackL4IR(UINT8 *out, const UINT8 *in, int pixels) { } static void -unpackLA(UINT8 *_out, const UINT8 *in, int pixels) { - int i; - /* LA, pixel interleaved */ - for (i = 0; i < pixels; i++) { - UINT32 iv = MAKE_UINT32(in[0], in[0], in[0], in[1]); - memcpy(_out, &iv, sizeof(iv)); - in += 2; - _out += 4; - } -} - -static void -unpackLAL(UINT8 *_out, const UINT8 *in, int pixels) { - int i; +unpackLAL(UINT8 *out, const UINT8 *in, int pixels) { + UINT8 *in1 = in; + UINT8 *in2 = in + pixels; /* LA, line interleaved */ - for (i = 0; i < pixels; i++, _out += 4) { - UINT32 iv = MAKE_UINT32(in[i], in[i], in[i], in[i + pixels]); - memcpy(_out, &iv, sizeof(iv)); + for (int i = 0; i < pixels; ++i) { + *out++ = *in1++; + *out++ = *in2++; } } @@ -1528,11 +1517,11 @@ static struct { {"L", "L;16B", 16, unpackL16B}, /* greyscale w. alpha */ - {"LA", "LA", 16, unpackLA}, + {"LA", "LA", 16, copy2}, {"LA", "LA;L", 16, unpackLAL}, /* greyscale w. alpha premultiplied */ - {"La", "La", 16, unpackLA}, + {"La", "La", 16, copy2}, /* palette */ {"P", "P;1", 1, unpackP1}, @@ -1544,7 +1533,7 @@ static struct { {"P", "P;R", 8, unpackLR}, /* palette w. alpha */ - {"PA", "PA", 16, unpackLA}, + {"PA", "PA", 16, copy2}, {"PA", "PA;L", 16, unpackLAL}, /* true colour */