change pixelsize of La/LA/LA modes from 4 to 2

This commit is contained in:
Yay295 2022-08-17 22:45:24 -05:00
parent 5a087ccbb9
commit 2643a3d971
13 changed files with 567 additions and 555 deletions

View File

@ -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,

View File

@ -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);

View File

@ -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;
}
}
}

View File

@ -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,10 +1741,17 @@ ImagingConvertTransparent(Imaging imIn, const char *mode, int r, int g, int b) {
}
ImagingSectionEnter(&cookie);
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);
return imOut;

View File

@ -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);
for (b = 0; b < im->bands; b++) {
BICUBIC_BODY(UINT8, im->image, pixelsize, b);
if (v1 <= 0.0) {
((UINT8 *)out)[0] = 0;
((UINT8 *)out)[b] = 0;
} else if (v1 >= 255.0) {
((UINT8 *)out)[0] = 255;
((UINT8 *)out)[b] = 255;
} else {
((UINT8 *)out)[0] = (UINT8)v1;
((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,59 +625,26 @@ 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;
}
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;
}
return bicubic_filter8;
case IMAGING_TYPE_INT32:
return bicubic_filter32I;
case IMAGING_TYPE_FLOAT32:
return bicubic_filter32F;
}
}
break;
}
/* no such filter */
@ -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;
}
}

View File

@ -30,11 +30,11 @@ ImagingGetBBox(Imaging im, int bbox[4]) {
bbox[1] = -1;
bbox[2] = bbox[3] = 0;
#define GETBBOX(image, mask) \
#define GETBBOX(type) \
for (y = 0; y < im->ysize; y++) { \
has_data = 0; \
for (x = 0; x < im->xsize; x++) { \
if (im->image[y][x] & mask) { \
if (((type *)im->image[y])[x] & mask) { \
has_data = 1; \
if (x < bbox[0]) { \
bbox[0] = x; \
@ -52,23 +52,35 @@ ImagingGetBBox(Imaging im, int bbox[4]) {
} \
}
if (im->image8) {
GETBBOX(image8, 0xff);
} else {
INT32 mask = 0xffffffff;
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 ||
strcmp(im->mode, "La") == 0 || strcmp(im->mode, "LA") == 0 ||
strcmp(im->mode, "PA") == 0) {
#ifdef WORDS_BIGENDIAN
mask = 0x000000ff;
#else
mask = 0xff000000;
#endif
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,11 +102,11 @@ ImagingGetProjection(Imaging im, UINT8 *xproj, UINT8 *yproj) {
memset(xproj, 0, im->xsize);
memset(yproj, 0, im->ysize);
#define GETPROJ(image, mask) \
#define GETPROJ(type) \
for (y = 0; y < im->ysize; y++) { \
has_data = 0; \
for (x = 0; x < im->xsize; x++) { \
if (im->image[y][x] & mask) { \
if (((type *)im->image[y])[x] & mask) { \
has_data = 1; \
xproj[x] = 1; \
} \
@ -104,14 +116,25 @@ ImagingGetProjection(Imaging im, UINT8 *xproj, UINT8 *yproj) {
} \
}
if (im->image8) {
GETPROJ(image8, 0xff);
} else {
INT32 mask = 0xffffffff;
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(image32, mask);
GETPROJ(UINT32);
break;
}
}
return 1; /* ok */

View File

@ -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])

View File

@ -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},

View File

@ -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;
}
}
}

View File

@ -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 */

View File

@ -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,46 +466,36 @@ 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;
int alphaChannel = -1;
if (isRGBA) {
alphaChannel = 3;
} else if (isXA) {
alphaChannel = 1;
}
} 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);
if (alphaChannel >= 0 && i != alphaChannel && channel_mask != 0) {
channel_mask = 255 - (255 - channel_mask) *
(1 - (255 - out[alphaChannel]) / 255);
}
out[i] = BLEND(channel_mask, out[i], ink[i], tmp1);
// 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++;
}
}
}
}
static inline void

View File

@ -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 */

View File

@ -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 */