transpose() with multi-band format

This commit is contained in:
Junxiao Shi 2024-06-22 13:41:57 +00:00
parent 5bdda4c012
commit df98223fb5
2 changed files with 135 additions and 172 deletions

View File

@ -903,14 +903,23 @@ class TestFileTiff:
im.load() im.load()
check_image(im, 10, 10, pixel) check_image(im, 10, 10, pixel)
im1 = im.copy() copy = im.copy()
check_image(im1, 10, 10, pixel) check_image(copy, 10, 10, pixel)
im2 = im.crop((2, 2, 7, 7)) cropped = im.crop((2, 2, 8, 7))
check_image(im2, 5, 5, pixel) check_image(cropped, 6, 5, pixel)
im3 = im.transpose(Image.Transpose.FLIP_LEFT_RIGHT) for method, [w, h] in {
check_image(im3, 10, 10, pixel) Image.Transpose.FLIP_LEFT_RIGHT: (6, 5),
Image.Transpose.FLIP_TOP_BOTTOM: (6, 5),
Image.Transpose.ROTATE_90: (5, 6),
Image.Transpose.ROTATE_180: (6, 5),
Image.Transpose.ROTATE_270: (5, 6),
Image.Transpose.TRANSPOSE: (5, 6),
Image.Transpose.TRANSVERSE: (5, 6),
}.items():
transposed = cropped.transpose(method)
check_image(transposed, w, h, pixel)
@pytest.mark.skipif(not is_win32(), reason="Windows only") @pytest.mark.skipif(not is_win32(), reason="Windows only")

View File

@ -19,7 +19,8 @@ ImagingFlipLeftRight(Imaging imOut, Imaging imIn) {
ImagingSectionCookie cookie; ImagingSectionCookie cookie;
int x, y, xr; int x, y, xr;
if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) { if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0 ||
imIn->pixelsize != imOut->pixelsize) {
return (Imaging)ImagingError_ModeError(); return (Imaging)ImagingError_ModeError();
} }
if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize) { if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize) {
@ -47,7 +48,8 @@ ImagingFlipTopBottom(Imaging imOut, Imaging imIn) {
ImagingSectionCookie cookie; ImagingSectionCookie cookie;
int y, yr; int y, yr;
if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) { if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0 ||
imIn->pixelsize != imOut->pixelsize) {
return (Imaging)ImagingError_ModeError(); return (Imaging)ImagingError_ModeError();
} }
if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize) { if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize) {
@ -74,7 +76,8 @@ ImagingRotate90(Imaging imOut, Imaging imIn) {
int x, y, xx, yy, xr, xxsize, yysize; int x, y, xx, yy, xr, xxsize, yysize;
int xxx, yyy, xxxsize, yyysize; int xxx, yyy, xxxsize, yyysize;
if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) { if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0 ||
imIn->pixelsize != imOut->pixelsize) {
return (Imaging)ImagingError_ModeError(); return (Imaging)ImagingError_ModeError();
} }
if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) { if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) {
@ -83,48 +86,38 @@ ImagingRotate90(Imaging imOut, Imaging imIn) {
ImagingCopyPalette(imOut, imIn); ImagingCopyPalette(imOut, imIn);
#define ROTATE_90(INT, image) \
for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \
for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \
yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \
xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \
for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \
for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \
yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize \
? yy + ROTATE_SMALL_CHUNK \
: imIn->ysize; \
xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize \
? xx + ROTATE_SMALL_CHUNK \
: imIn->xsize; \
for (yyy = yy; yyy < yyysize; yyy++) { \
INT *in = (INT *)imIn->image[yyy]; \
xr = imIn->xsize - 1 - xx; \
for (xxx = xx; xxx < xxxsize; xxx++, xr--) { \
INT *out = (INT *)imOut->image[xr]; \
out[yyy] = in[xxx]; \
} \
} \
} \
} \
} \
}
ImagingSectionEnter(&cookie); ImagingSectionEnter(&cookie);
if (imIn->image8) { for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) {
if (strncmp(imIn->mode, "I;16", 4) == 0) { for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) {
ROTATE_90(UINT16, image8); yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize;
} else { xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize;
ROTATE_90(UINT8, image8); for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) {
for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) {
yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize
? yy + ROTATE_SMALL_CHUNK
: imIn->ysize;
xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize
? xx + ROTATE_SMALL_CHUNK
: imIn->xsize;
for (yyy = yy; yyy < yyysize; yyy++) {
char *in = imIn->image[yyy];
xr = imIn->xsize - 1 - xx;
for (xxx = xx; xxx < xxxsize; xxx++, xr--) {
char *out = imOut->image[xr];
memcpy(
out + yyy * imIn->pixelsize,
in + xxx * imIn->pixelsize,
imIn->pixelsize);
}
}
}
}
} }
} else {
ROTATE_90(INT32, image32);
} }
ImagingSectionLeave(&cookie); ImagingSectionLeave(&cookie);
#undef ROTATE_90
return imOut; return imOut;
} }
@ -134,7 +127,8 @@ ImagingTranspose(Imaging imOut, Imaging imIn) {
int x, y, xx, yy, xxsize, yysize; int x, y, xx, yy, xxsize, yysize;
int xxx, yyy, xxxsize, yyysize; int xxx, yyy, xxxsize, yyysize;
if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) { if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0 ||
imIn->pixelsize != imOut->pixelsize) {
return (Imaging)ImagingError_ModeError(); return (Imaging)ImagingError_ModeError();
} }
if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) { if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) {
@ -143,47 +137,37 @@ ImagingTranspose(Imaging imOut, Imaging imIn) {
ImagingCopyPalette(imOut, imIn); ImagingCopyPalette(imOut, imIn);
#define TRANSPOSE(INT, image) \
for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \
for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \
yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \
xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \
for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \
for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \
yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize \
? yy + ROTATE_SMALL_CHUNK \
: imIn->ysize; \
xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize \
? xx + ROTATE_SMALL_CHUNK \
: imIn->xsize; \
for (yyy = yy; yyy < yyysize; yyy++) { \
INT *in = (INT *)imIn->image[yyy]; \
for (xxx = xx; xxx < xxxsize; xxx++) { \
INT *out = (INT *)imOut->image[xxx]; \
out[yyy] = in[xxx]; \
} \
} \
} \
} \
} \
}
ImagingSectionEnter(&cookie); ImagingSectionEnter(&cookie);
if (imIn->image8) { for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) {
if (strncmp(imIn->mode, "I;16", 4) == 0) { for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) {
TRANSPOSE(UINT16, image8); yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize;
} else { xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize;
TRANSPOSE(UINT8, image8); for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) {
for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) {
yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize
? yy + ROTATE_SMALL_CHUNK
: imIn->ysize;
xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize
? xx + ROTATE_SMALL_CHUNK
: imIn->xsize;
for (yyy = yy; yyy < yyysize; yyy++) {
char *in = imIn->image[yyy];
for (xxx = xx; xxx < xxxsize; xxx++) {
char *out = imOut->image[xxx];
memcpy(
out + yyy * imIn->pixelsize,
in + xxx * imIn->pixelsize,
imIn->pixelsize);
}
}
}
}
} }
} else {
TRANSPOSE(INT32, image32);
} }
ImagingSectionLeave(&cookie); ImagingSectionLeave(&cookie);
#undef TRANSPOSE
return imOut; return imOut;
} }
@ -193,7 +177,8 @@ ImagingTransverse(Imaging imOut, Imaging imIn) {
int x, y, xr, yr, xx, yy, xxsize, yysize; int x, y, xr, yr, xx, yy, xxsize, yysize;
int xxx, yyy, xxxsize, yyysize; int xxx, yyy, xxxsize, yyysize;
if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) { if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0 ||
imIn->pixelsize != imOut->pixelsize) {
return (Imaging)ImagingError_ModeError(); return (Imaging)ImagingError_ModeError();
} }
if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) { if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) {
@ -202,49 +187,39 @@ ImagingTransverse(Imaging imOut, Imaging imIn) {
ImagingCopyPalette(imOut, imIn); ImagingCopyPalette(imOut, imIn);
#define TRANSVERSE(INT, image) \
for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \
for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \
yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \
xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \
for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \
for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \
yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize \
? yy + ROTATE_SMALL_CHUNK \
: imIn->ysize; \
xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize \
? xx + ROTATE_SMALL_CHUNK \
: imIn->xsize; \
yr = imIn->ysize - 1 - yy; \
for (yyy = yy; yyy < yyysize; yyy++, yr--) { \
INT *in = (INT *)imIn->image[yyy]; \
xr = imIn->xsize - 1 - xx; \
for (xxx = xx; xxx < xxxsize; xxx++, xr--) { \
INT *out = (INT *)imOut->image[xr]; \
out[yr] = in[xxx]; \
} \
} \
} \
} \
} \
}
ImagingSectionEnter(&cookie); ImagingSectionEnter(&cookie);
if (imIn->image8) { for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) {
if (strncmp(imIn->mode, "I;16", 4) == 0) { for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) {
TRANSVERSE(UINT16, image8); yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize;
} else { xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize;
TRANSVERSE(UINT8, image8); for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) {
for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) {
yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize
? yy + ROTATE_SMALL_CHUNK
: imIn->ysize;
xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize
? xx + ROTATE_SMALL_CHUNK
: imIn->xsize;
yr = imIn->ysize - 1 - yy;
for (yyy = yy; yyy < yyysize; yyy++, yr--) {
char *in = imIn->image[yyy];
xr = imIn->xsize - 1 - xx;
for (xxx = xx; xxx < xxxsize; xxx++, xr--) {
char *out = imOut->image[xr];
memcpy(
out + yr * imIn->pixelsize,
in + xxx * imIn->pixelsize,
imIn->pixelsize);
}
}
}
}
} }
} else {
TRANSVERSE(INT32, image32);
} }
ImagingSectionLeave(&cookie); ImagingSectionLeave(&cookie);
#undef TRANSVERSE
return imOut; return imOut;
} }
@ -253,7 +228,8 @@ ImagingRotate180(Imaging imOut, Imaging imIn) {
ImagingSectionCookie cookie; ImagingSectionCookie cookie;
int x, y, xr, yr; int x, y, xr, yr;
if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) { if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0 ||
imIn->pixelsize != imOut->pixelsize) {
return (Imaging)ImagingError_ModeError(); return (Imaging)ImagingError_ModeError();
} }
if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize) { if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize) {
@ -262,33 +238,20 @@ ImagingRotate180(Imaging imOut, Imaging imIn) {
ImagingCopyPalette(imOut, imIn); ImagingCopyPalette(imOut, imIn);
#define ROTATE_180(INT, image) \
for (y = 0; y < imIn->ysize; y++, yr--) { \
INT *in = (INT *)imIn->image[y]; \
INT *out = (INT *)imOut->image[yr]; \
xr = imIn->xsize - 1; \
for (x = 0; x < imIn->xsize; x++, xr--) { \
out[xr] = in[x]; \
} \
}
ImagingSectionEnter(&cookie); ImagingSectionEnter(&cookie);
yr = imIn->ysize - 1; yr = imIn->ysize - 1;
if (imIn->image8) { for (y = 0; y < imIn->ysize; y++, yr--) {
if (strncmp(imIn->mode, "I;16", 4) == 0) { char *in = imIn->image[y];
ROTATE_180(UINT16, image8) char *out = imOut->image[yr];
} else { xr = imIn->linesize - imIn->pixelsize;
ROTATE_180(UINT8, image8) for (x = 0; x < imIn->linesize; x += imIn->pixelsize, xr -= imIn->pixelsize) {
memcpy(out + xr, in + x, imIn->pixelsize);
} }
} else {
ROTATE_180(INT32, image32)
} }
ImagingSectionLeave(&cookie); ImagingSectionLeave(&cookie);
#undef ROTATE_180
return imOut; return imOut;
} }
@ -298,7 +261,8 @@ ImagingRotate270(Imaging imOut, Imaging imIn) {
int x, y, xx, yy, yr, xxsize, yysize; int x, y, xx, yy, yr, xxsize, yysize;
int xxx, yyy, xxxsize, yyysize; int xxx, yyy, xxxsize, yyysize;
if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) { if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0 ||
imIn->pixelsize != imOut->pixelsize) {
return (Imaging)ImagingError_ModeError(); return (Imaging)ImagingError_ModeError();
} }
if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) { if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) {
@ -307,48 +271,38 @@ ImagingRotate270(Imaging imOut, Imaging imIn) {
ImagingCopyPalette(imOut, imIn); ImagingCopyPalette(imOut, imIn);
#define ROTATE_270(INT, image) \
for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \
for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \
yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \
xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \
for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \
for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \
yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize \
? yy + ROTATE_SMALL_CHUNK \
: imIn->ysize; \
xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize \
? xx + ROTATE_SMALL_CHUNK \
: imIn->xsize; \
yr = imIn->ysize - 1 - yy; \
for (yyy = yy; yyy < yyysize; yyy++, yr--) { \
INT *in = (INT *)imIn->image[yyy]; \
for (xxx = xx; xxx < xxxsize; xxx++) { \
INT *out = (INT *)imOut->image[xxx]; \
out[yr] = in[xxx]; \
} \
} \
} \
} \
} \
}
ImagingSectionEnter(&cookie); ImagingSectionEnter(&cookie);
if (imIn->image8) { for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) {
if (strncmp(imIn->mode, "I;16", 4) == 0) { for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) {
ROTATE_270(UINT16, image8); yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize;
} else { xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize;
ROTATE_270(UINT8, image8); for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) {
for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) {
yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize
? yy + ROTATE_SMALL_CHUNK
: imIn->ysize;
xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize
? xx + ROTATE_SMALL_CHUNK
: imIn->xsize;
yr = imIn->ysize - 1 - yy;
for (yyy = yy; yyy < yyysize; yyy++, yr--) {
char *in = imIn->image[yyy];
for (xxx = xx; xxx < xxxsize; xxx++) {
char *out = imOut->image[xxx];
memcpy(
out + yr * imIn->pixelsize,
in + xxx * imIn->pixelsize,
imIn->pixelsize);
}
}
}
}
} }
} else {
ROTATE_270(INT32, image32);
} }
ImagingSectionLeave(&cookie); ImagingSectionLeave(&cookie);
#undef ROTATE_270
return imOut; return imOut;
} }