From 1c2d46558920e0007deec64a5f6e3f0d6822cd0b Mon Sep 17 00:00:00 2001 From: Bryant Mairs Date: Mon, 18 Apr 2016 19:56:26 -0700 Subject: [PATCH 01/23] Add tests for opening 2-5 layer uint16 greyscale TIFFs. --- Tests/images/uint16_2_4660.tif | Bin 0 -> 558 bytes Tests/images/uint16_3_4660.tif | Bin 0 -> 770 bytes Tests/images/uint16_4_4660.tif | Bin 0 -> 980 bytes Tests/images/uint16_5_4660.tif | Bin 0 -> 1186 bytes Tests/test_file_tiff.py | 13 +++++++++++++ 5 files changed, 13 insertions(+) create mode 100644 Tests/images/uint16_2_4660.tif create mode 100644 Tests/images/uint16_3_4660.tif create mode 100644 Tests/images/uint16_4_4660.tif create mode 100644 Tests/images/uint16_5_4660.tif diff --git a/Tests/images/uint16_2_4660.tif b/Tests/images/uint16_2_4660.tif new file mode 100644 index 0000000000000000000000000000000000000000..188ff2af7b1caf7c0b512fcb76dcbd426a8df8f4 GIT binary patch literal 558 zcmebD)MDUZU|`^3U|?isU<9(bfS3`9%>-mK0mTG>kQpitQpbkG7Gz`r>zxM_7ln$0 s^oT*(AT!0GY9;_R%OL3ug0g{17=nRpkUmDRX$%Y|LZ(8ac<_V)01aF^xc~qF literal 0 HcmV?d00001 diff --git a/Tests/images/uint16_3_4660.tif b/Tests/images/uint16_3_4660.tif new file mode 100644 index 0000000000000000000000000000000000000000..3c2bc86587ef6ce3b1d2a558ba8dd040b221b900 GIT binary patch literal 770 zcmebD)MDUZU|`^3U|?isU<9(bfS3`9%>-mK1I6Y6F*8&gq>c@VEy&0M*1HNQE(#R~ z=@EmnL1v0W)kH8cFvuY34Fa-(LSPUKWP|iAf${|yK#&m(O@vH^%!EeC(GZ|+2mk=6 C?N|i> literal 0 HcmV?d00001 diff --git a/Tests/images/uint16_4_4660.tif b/Tests/images/uint16_4_4660.tif new file mode 100644 index 0000000000000000000000000000000000000000..ae8252d78a721e796e3a16445db3d7c50374873b GIT binary patch literal 980 zcmebD)MDUZU|`^3U|?isU<9(bfS3`9%>-n#0LA73F*8&gq>c@VEy&0M*1H8LE(#R~ z=@EmnL1v0W)hIACFvuY34Fa-(LJZ4*I2gzV>01NDARqvR5FR7Y4iGdEG8HltG8Y=9 MN5f$>9bo1I0ISP&9{>OV literal 0 HcmV?d00001 diff --git a/Tests/images/uint16_5_4660.tif b/Tests/images/uint16_5_4660.tif new file mode 100644 index 0000000000000000000000000000000000000000..df92724c35989846d14183fa9648f2948806528f GIT binary patch literal 1186 zcmebD)MDUZU|`^3U|?isU<9(bfS3`9%>-n#0>$P5F*8&gq>c@VEy&0M*1HQRE(#R~ z=@EmnL1v0W)x2P4V30x58w6yt0OeNzaWIe#(zgMKK|lZwA$*|A;Lt?KRLD%oT*yLb OlrF{<^=!(YLf5( literal 0 HcmV?d00001 diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index 84fdd0f4965..245959d3a5d 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -450,6 +450,19 @@ def test_save_tiff_with_jpegtables(self): # Should not raise UnicodeDecodeError or anything else im.save(outfile) + def test_open_tiff_uint16_multiband(self): + """Test opening multiband TIFFs and reading all channels.""" + base_value = 4660 + for i in range(2, 6): + infile = "Tests/images/uint16_{}_{}.tif".format(i, base_value) + im = Image.open(infile) + im.load() + pixel = [base_value + j for j in range(0, i)] + actual_pixel = im.getpixel((0,0)) + if type(actual_pixel) is int: + actual_pixel = [actual_pixel] + self.assertEqual(actual_pixel, pixel) + if __name__ == '__main__': unittest.main() From e0bb623438a0e9632d59b9165a5dfff0b0c2647f Mon Sep 17 00:00:00 2001 From: Bryant Mairs Date: Tue, 19 Apr 2016 08:02:13 -0700 Subject: [PATCH 02/23] Add open() support for 2-5 band uint16 TIFFs. This only gets us to opening the first band, it doesn't actually allow the other bands to be retrieved. --- PIL/TiffImagePlugin.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/PIL/TiffImagePlugin.py b/PIL/TiffImagePlugin.py index 99beb0f97ca..670962e689f 100644 --- a/PIL/TiffImagePlugin.py +++ b/PIL/TiffImagePlugin.py @@ -176,6 +176,10 @@ (II, 1, (1,), 1, (12,), ()): ("I;16", "I;12"), (II, 1, (1,), 1, (16,), ()): ("I;16", "I;16"), + (II, 1, (1,), 1, (16,16), (0,)): ("I;16", "I;16"), + (II, 1, (1,), 1, (16,16,16), (0,0,)): ("I;16", "I;16"), + (II, 1, (1,), 1, (16,16,16,16), (0,0,0,)): ("I;16", "I;16"), + (II, 1, (1,), 1, (16,16,16,16,16), (0,0,0,0,)): ("I;16", "I;16"), (MM, 1, (1,), 1, (16,), ()): ("I;16B", "I;16B"), (II, 1, (2,), 1, (16,), ()): ("I;16S", "I;16S"), (MM, 1, (2,), 1, (16,), ()): ("I;16BS", "I;16BS"), From 90840ae38cc42e1cbb3d13f9c01d1fc287161a9a Mon Sep 17 00:00:00 2001 From: Junxiao Shi Date: Sat, 1 Jun 2024 14:34:24 +0000 Subject: [PATCH 03/23] XXX disable PyImaging_MapBuffer --- src/PIL/ImageFile.py | 3 +++ src/_imaging.c | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/PIL/ImageFile.py b/src/PIL/ImageFile.py index 33467fc4fbe..c0224782acf 100644 --- a/src/PIL/ImageFile.py +++ b/src/PIL/ImageFile.py @@ -204,6 +204,9 @@ def load(self): except AttributeError: seek = self.fp.seek + # XXX hack202406 disable unmodified code path + use_mmap = False + if use_mmap: # try memory mapping decoder_name, extents, offset, args = self.tile[0] diff --git a/src/_imaging.c b/src/_imaging.c index c565c21bb15..69a012107fd 100644 --- a/src/_imaging.c +++ b/src/_imaging.c @@ -96,7 +96,8 @@ /* Configuration stuff. Feel free to undef things you don't need. */ #define WITH_IMAGECHOPS /* ImageChops support */ #define WITH_IMAGEDRAW /* ImageDraw support */ -#define WITH_MAPPING /* use memory mapping to read some file formats */ +// XXX hack202406 disable unmodified code path +// #define WITH_MAPPING /* use memory mapping to read some file formats */ #define WITH_IMAGEPATH /* ImagePath stuff */ #define WITH_ARROW /* arrow graphics stuff (experimental) */ #define WITH_EFFECTS /* special effects */ From 03df35777cc3ba9ab80afecbf79c6a9d978ad3ce Mon Sep 17 00:00:00 2001 From: Junxiao Shi Date: Sat, 1 Jun 2024 14:56:34 +0000 Subject: [PATCH 04/23] TIFF sample format table --- src/PIL/TiffImagePlugin.py | 17 ++++++----------- src/_imaging.c | 4 ++-- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index e70f1252608..8f795870296 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -60,6 +60,7 @@ from .TiffTags import TYPES logger = logging.getLogger(__name__) +logger.setLevel(logging.DEBUG) # XXX hack202406 # Set these to true to force use of libtiff for reading or writing. READ_LIBTIFF = False @@ -182,11 +183,11 @@ (II, 1, (1,), 1, (12,), ()): ("I;16", "I;12"), (II, 0, (1,), 1, (16,), ()): ("I;16", "I;16"), (II, 1, (1,), 1, (16,), ()): ("I;16", "I;16"), - (II, 1, (1,), 1, (16, 16), (0,)): ("I;16", "I;16"), + (II, 1, (1, 1), 1, (16, 16), (0,)): ("I;16", "I;16"), ( II, 1, - (1,), + (1, 1, 1), 1, (16, 16, 16), ( @@ -197,7 +198,7 @@ ( II, 1, - (1,), + (1, 1, 1, 1), 1, (16, 16, 16, 16), ( @@ -209,7 +210,7 @@ ( II, 1, - (1,), + (1, 1, 1, 1, 1), 1, (16, 16, 16, 16, 16), ( @@ -1416,13 +1417,7 @@ def _setup(self): logger.debug("- size: %s", self.size) sample_format = self.tag_v2.get(SAMPLEFORMAT, (1,)) - if len(sample_format) > 1 and max(sample_format) == min(sample_format) == 1: - # SAMPLEFORMAT is properly per band, so an RGB image will - # be (1,1,1). But, we don't support per band pixel types, - # and anything more than one band is a uint8. So, just - # take the first element. Revisit this if adding support - # for more exotic images. - sample_format = (1,) + logger.debug("- sample_format: %s", sample_format) bps_tuple = self.tag_v2.get(BITSPERSAMPLE, (1,)) extra_tuple = self.tag_v2.get(EXTRASAMPLES, ()) diff --git a/src/_imaging.c b/src/_imaging.c index 69a012107fd..756768b75c6 100644 --- a/src/_imaging.c +++ b/src/_imaging.c @@ -94,8 +94,8 @@ #include /* Configuration stuff. Feel free to undef things you don't need. */ -#define WITH_IMAGECHOPS /* ImageChops support */ -#define WITH_IMAGEDRAW /* ImageDraw support */ +#define WITH_IMAGECHOPS /* ImageChops support */ +#define WITH_IMAGEDRAW /* ImageDraw support */ // XXX hack202406 disable unmodified code path // #define WITH_MAPPING /* use memory mapping to read some file formats */ #define WITH_IMAGEPATH /* ImagePath stuff */ From 936439b48130d6a95abfa2021a9a2dd820d5ce30 Mon Sep 17 00:00:00 2001 From: Junxiao Shi Date: Sat, 1 Jun 2024 18:06:14 +0000 Subject: [PATCH 05/23] introduce multi-band format (TIFF only) --- Tests/test_file_tiff.py | 6 ++--- src/PIL/ImageFile.py | 4 +++- src/PIL/TiffImagePlugin.py | 13 +++++++---- src/_imaging.c | 46 ++++++++++++++++++++++++++++++++----- src/decode.c | 25 +++++++++++++++++++- src/libImaging/Access.c | 11 +++++++++ src/libImaging/Imaging.h | 16 +++++++++---- src/libImaging/Point.c | 4 ++-- src/libImaging/RankFilter.c | 3 ++- src/libImaging/RawDecode.c | 5 ++-- src/libImaging/Storage.c | 33 ++++++++++++++++++-------- src/map.c | 3 ++- 12 files changed, 132 insertions(+), 37 deletions(-) diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index 8a54f07568f..fc98901a4bc 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -877,14 +877,14 @@ def test_oom(self, test_file: str) -> None: def test_open_tiff_uint16_multiband(self): """Test opening multiband TIFFs and reading all channels.""" base_value = 4660 - for i in range(2, 6): + for i in range(1, 6): infile = f"Tests/images/uint16_{i}_{base_value}.tif" im = Image.open(infile) im.load() - pixel = [base_value + j for j in range(0, i)] + pixel = tuple([base_value + j for j in range(0, i)]) actual_pixel = im.getpixel((0, 0)) if isinstance(actual_pixel, int): - actual_pixel = [actual_pixel] + actual_pixel = (actual_pixel,) assert actual_pixel == pixel diff --git a/src/PIL/ImageFile.py b/src/PIL/ImageFile.py index c0224782acf..6c92ea4f532 100644 --- a/src/PIL/ImageFile.py +++ b/src/PIL/ImageFile.py @@ -117,6 +117,8 @@ def __init__(self, fp=None, filename=None): self.readonly = 1 # until we know better + self.newconfig = () + self.decoderconfig = () self.decodermaxblock = MAXBLOCK @@ -317,7 +319,7 @@ def load(self): def load_prepare(self) -> None: # create image memory if necessary if not self.im or self.im.mode != self.mode or self.im.size != self.size: - self.im = Image.core.new(self.mode, self.size) + self.im = Image.core.new(self.mode, self.size, *self.newconfig) # create palette (optional) if self.mode == "P": Image.Image.load(self) diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index 8f795870296..a829e8db535 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -60,7 +60,7 @@ from .TiffTags import TYPES logger = logging.getLogger(__name__) -logger.setLevel(logging.DEBUG) # XXX hack202406 +logger.setLevel(logging.DEBUG) # XXX hack202406 # Set these to true to force use of libtiff for reading or writing. READ_LIBTIFF = False @@ -183,7 +183,7 @@ (II, 1, (1,), 1, (12,), ()): ("I;16", "I;12"), (II, 0, (1,), 1, (16,), ()): ("I;16", "I;16"), (II, 1, (1,), 1, (16,), ()): ("I;16", "I;16"), - (II, 1, (1, 1), 1, (16, 16), (0,)): ("I;16", "I;16"), + (II, 1, (1, 1), 1, (16, 16), (0,)): ("MB", "MB"), ( II, 1, @@ -194,7 +194,7 @@ 0, 0, ), - ): ("I;16", "I;16"), + ): ("MB", "MB"), ( II, 1, @@ -206,7 +206,7 @@ 0, 0, ), - ): ("I;16", "I;16"), + ): ("MB", "MB"), ( II, 1, @@ -219,7 +219,7 @@ 0, 0, ), - ): ("I;16", "I;16"), + ): ("MB", "MB"), (MM, 1, (1,), 1, (16,), ()): ("I;16B", "I;16B"), (II, 1, (1,), 2, (16,), ()): ("I;16", "I;16R"), (II, 1, (2,), 1, (16,), ()): ("I", "I;16S"), @@ -1474,6 +1474,9 @@ def _setup(self): logger.debug("- raw mode: %s", rawmode) logger.debug("- pil mode: %s", self.mode) + if self.mode == "MB": + assert max(bps_tuple) == min(bps_tuple) + self.newconfig = (max(bps_tuple), samples_per_pixel) self.info["compression"] = self._compression diff --git a/src/_imaging.c b/src/_imaging.c index 756768b75c6..4eee912f67a 100644 --- a/src/_imaging.c +++ b/src/_imaging.c @@ -310,7 +310,7 @@ getbands(const char *mode) { int bands; /* FIXME: add primitive to libImaging to avoid extra allocation */ - im = ImagingNew(mode, 0, 0); + im = ImagingNew(mode, 0, 0, -1, -1); if (!im) { return -1; } @@ -434,6 +434,35 @@ float16tofloat32(const FLOAT16 in) { return out[0]; } +static inline PyObject * +getpixel_mb(Imaging im, ImagingAccess access, int x, int y) { + UINT8 pixel[im->pixelsize]; + access->get_pixel(im, x, y, &pixel); + + PyObject *tuple = PyTuple_New(im->bands); + if (tuple == NULL) { + return NULL; + } + + UINT8 *pos = pixel; + for (int i = 0; i < im->bands; ++i) { + switch (im->depth) { + case CHAR_BIT: + PyTuple_SET_ITEM(tuple, i, PyLong_FromLong(*pos)); + break; + case 2 * CHAR_BIT: + PyTuple_SET_ITEM(tuple, i, PyLong_FromLong(*(UINT16 *)pos)); + break; + case 4 * CHAR_BIT: + PyTuple_SET_ITEM(tuple, i, PyLong_FromLong(*(INT32 *)pos)); + break; + } + pos += im->depth / CHAR_BIT; + } + + return tuple; +} + static inline PyObject * getpixel(Imaging im, ImagingAccess access, int x, int y) { union { @@ -455,6 +484,10 @@ getpixel(Imaging im, ImagingAccess access, int x, int y) { return NULL; } + if (im->type == IMAGING_TYPE_MB) { + return getpixel_mb(im, access, x, y); + } + access->get_pixel(im, x, y, &pixel); switch (im->type) { @@ -685,13 +718,13 @@ _fill(PyObject *self, PyObject *args) { static PyObject * _new(PyObject *self, PyObject *args) { char *mode; - int xsize, ysize; + int xsize, ysize, depth = -1, bands = -1; - if (!PyArg_ParseTuple(args, "s(ii)", &mode, &xsize, &ysize)) { + if (!PyArg_ParseTuple(args, "s(ii)|ii", &mode, &xsize, &ysize, &depth, &bands)) { return NULL; } - return PyImagingNew(ImagingNew(mode, xsize, ysize)); + return PyImagingNew(ImagingNew(mode, xsize, ysize, depth, bands)); } static PyObject * @@ -1714,7 +1747,8 @@ _quantize(ImagingObject *self, PyObject *args) { if (!self->image->xsize || !self->image->ysize) { /* no content; return an empty image */ - return PyImagingNew(ImagingNew("P", self->image->xsize, self->image->ysize)); + return PyImagingNew( + ImagingNew("P", self->image->xsize, self->image->ysize, -1, -1)); } return PyImagingNew(ImagingQuantize(self->image, colours, method, kmeans)); @@ -2782,7 +2816,7 @@ _font_getmask(ImagingFontObject *self, PyObject *args) { return NULL; } - im = ImagingNew(self->bitmap->mode, textwidth(self, text), self->ysize); + im = ImagingNew(self->bitmap->mode, textwidth(self, text), self->ysize, -1, -1); if (!im) { free(text); return ImagingError_MemoryError(); diff --git a/src/decode.c b/src/decode.c index ea2f3af8012..af08010188a 100644 --- a/src/decode.c +++ b/src/decode.c @@ -291,11 +291,33 @@ static PyTypeObject ImagingDecoderType = { /* -------------------------------------------------------------------- */ -int +static void +mb_shuffle_passthru(UINT8 *dst, const UINT8 *src, Imaging im, ImagingCodecState state) { + state->shuffle(dst, src, state->xsize); +} + +static void +shuffle_mb_unavail(UINT8 *dst, const UINT8 *src, int pixels) { + abort(); +} + +static void +mb_shuffle(UINT8 *dst, const UINT8 *src, Imaging im, ImagingCodecState state) { + memcpy(dst, src, state->xsize * im->pixelsize); +} + +static int get_unpacker(ImagingDecoderObject *decoder, const char *mode, const char *rawmode) { int bits; ImagingShuffler unpack; + if (strcmp(mode, IMAGING_MODE_MB) == 0) { + decoder->state.shuffle = shuffle_mb_unavail; + decoder->state.mb_shuffle = mb_shuffle; + decoder->state.bits = -1; + return 0; + } + unpack = ImagingFindUnpacker(mode, rawmode, &bits); if (!unpack) { Py_DECREF(decoder); @@ -304,6 +326,7 @@ get_unpacker(ImagingDecoderObject *decoder, const char *mode, const char *rawmod } decoder->state.shuffle = unpack; + decoder->state.mb_shuffle = mb_shuffle_passthru; decoder->state.bits = bits; return 0; diff --git a/src/libImaging/Access.c b/src/libImaging/Access.c index 3a5e918e837..f567bdbabdb 100644 --- a/src/libImaging/Access.c +++ b/src/libImaging/Access.c @@ -133,6 +133,11 @@ get_pixel_32B(Imaging im, int x, int y, void *color) { #endif } +static void +get_pixel_mb(Imaging im, int x, int y, void *color) { + memcpy(color, &im->image[y][x * im->pixelsize], im->pixelsize); +} + /* store individual pixel */ static void @@ -183,6 +188,11 @@ put_pixel_32(Imaging im, int x, int y, const void *color) { memcpy(&im->image32[y][x], color, sizeof(INT32)); } +static void +put_pixel_mb(Imaging im, int x, int y, void *color) { + memcpy(&im->image[y][x * im->pixelsize], color, im->pixelsize); +} + void ImagingAccessInit() { #define ADD(mode_, get_pixel_, put_pixel_) \ @@ -222,6 +232,7 @@ ImagingAccessInit() { ADD("YCbCr", get_pixel_32, put_pixel_32); ADD("LAB", get_pixel_32, put_pixel_32); ADD("HSV", get_pixel_32, put_pixel_32); + ADD("MB", get_pixel_mb, put_pixel_mb); } ImagingAccess diff --git a/src/libImaging/Imaging.h b/src/libImaging/Imaging.h index 1f2c03e934f..ee2f6ea9d17 100644 --- a/src/libImaging/Imaging.h +++ b/src/libImaging/Imaging.h @@ -68,10 +68,13 @@ typedef struct ImagingPaletteInstance *ImagingPalette; #define IMAGING_TYPE_INT32 1 #define IMAGING_TYPE_FLOAT32 2 #define IMAGING_TYPE_SPECIAL 3 /* check mode for details */ +#define IMAGING_TYPE_MB 4 /* multi-band format */ #define IMAGING_MODE_LENGTH \ 6 + 1 /* Band names ("1", "L", "P", "RGB", "RGBA", "CMYK", "YCbCr", "BGR;xy") */ +#define IMAGING_MODE_MB "MB" /* multi-band format */ + typedef struct { char *ptr; int size; @@ -80,9 +83,9 @@ typedef struct { struct ImagingMemoryInstance { /* Format */ char mode[IMAGING_MODE_LENGTH]; /* Band names ("1", "L", "P", "RGB", "RGBA", "CMYK", - "YCbCr", "BGR;xy") */ + "YCbCr", "BGR;xy", "MB") */ int type; /* Data type (IMAGING_TYPE_*) */ - int depth; /* Depth (ignored in this version) */ + int depth; /* Sample size (1, 2, or 4) in multi-band format */ int bands; /* Number of bands (1, 2, 3, or 4) */ int xsize; /* Image dimension. */ int ysize; @@ -173,7 +176,7 @@ extern void ImagingMemoryClearCache(ImagingMemoryArena arena, int new_size); extern Imaging -ImagingNew(const char *mode, int xsize, int ysize); +ImagingNew(const char *mode, int xsize, int ysize, int depth, int bands); extern Imaging ImagingNewDirty(const char *mode, int xsize, int ysize); extern Imaging @@ -185,9 +188,10 @@ extern Imaging ImagingNewBlock(const char *mode, int xsize, int ysize); extern Imaging -ImagingNewPrologue(const char *mode, int xsize, int ysize); +ImagingNewPrologue(const char *mode, int xsize, int ysize, int depth, int bands); extern Imaging -ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int structure_size); +ImagingNewPrologueSubtype( + const char *mode, int xsize, int ysize, int depth, int bands, int structure_size); extern void ImagingCopyPalette(Imaging destination, Imaging source); @@ -663,6 +667,8 @@ struct ImagingCodecStateInstance { int ystep; int xsize, ysize, xoff, yoff; ImagingShuffler shuffle; + void (*mb_shuffle)( + UINT8 *dst, const UINT8 *src, Imaging im, ImagingCodecState state); int bits, bytes; UINT8 *buffer; void *context; diff --git a/src/libImaging/Point.c b/src/libImaging/Point.c index dd06f3940d1..3d54008cbc3 100644 --- a/src/libImaging/Point.c +++ b/src/libImaging/Point.c @@ -152,7 +152,7 @@ ImagingPoint(Imaging imIn, const char *mode, const void *table) { goto mode_mismatch; } - imOut = ImagingNew(mode, imIn->xsize, imIn->ysize); + imOut = ImagingNew(mode, imIn->xsize, imIn->ysize, -1, -1); if (!imOut) { return NULL; } @@ -214,7 +214,7 @@ ImagingPointTransform(Imaging imIn, double scale, double offset) { return (Imaging)ImagingError_ModeError(); } - imOut = ImagingNew(imIn->mode, imIn->xsize, imIn->ysize); + imOut = ImagingNew(imIn->mode, imIn->xsize, imIn->ysize, -1, -1); if (!imOut) { return NULL; } diff --git a/src/libImaging/RankFilter.c b/src/libImaging/RankFilter.c index 73a6baecbb2..da40c892f11 100644 --- a/src/libImaging/RankFilter.c +++ b/src/libImaging/RankFilter.c @@ -84,7 +84,8 @@ MakeRankFunction(UINT8) MakeRankFunction(INT32) MakeRankFunction(FLOAT32) return (Imaging)ImagingError_ValueError("bad rank value"); } - imOut = ImagingNew(im->mode, im->xsize - 2 * margin, im->ysize - 2 * margin); + imOut = + ImagingNew(im->mode, im->xsize - 2 * margin, im->ysize - 2 * margin, -1, -1); if (!imOut) { return NULL; } diff --git a/src/libImaging/RawDecode.c b/src/libImaging/RawDecode.c index 24abe48041f..8d8d240512e 100644 --- a/src/libImaging/RawDecode.c +++ b/src/libImaging/RawDecode.c @@ -71,10 +71,11 @@ ImagingRawDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t byt } /* Unpack data */ - state->shuffle( + state->mb_shuffle( (UINT8 *)im->image[state->y + state->yoff] + state->xoff * im->pixelsize, ptr, - state->xsize); + im, + state); ptr += state->bytes; bytes -= state->bytes; diff --git a/src/libImaging/Storage.c b/src/libImaging/Storage.c index b27195a3587..cdf62ceb3c7 100644 --- a/src/libImaging/Storage.c +++ b/src/libImaging/Storage.c @@ -42,7 +42,8 @@ */ Imaging -ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) { +ImagingNewPrologueSubtype( + const char *mode, int xsize, int ysize, int depth, int bands, int size) { Imaging im; /* linesize overflow check, roughly the current largest space req'd */ @@ -190,6 +191,17 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) { im->pixelsize = 4; im->linesize = xsize * 4; + } else if (strcmp(mode, IMAGING_MODE_MB) == 0) { + if (bands <= 0 || depth <= 0) { + return (Imaging)ImagingError_ValueError( + "multi-band missing bands and depth"); + } + im->bands = bands; + im->depth = depth; + im->pixelsize = depth * bands; + im->linesize = xsize * im->pixelsize; + im->type = IMAGING_TYPE_MB; + } else { free(im); return (Imaging)ImagingError_ValueError("unrecognized image mode"); @@ -225,9 +237,9 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) { } Imaging -ImagingNewPrologue(const char *mode, int xsize, int ysize) { +ImagingNewPrologue(const char *mode, int xsize, int ysize, int depth, int bands) { return ImagingNewPrologueSubtype( - mode, xsize, ysize, sizeof(struct ImagingMemoryInstance)); + mode, xsize, ysize, depth, bands, sizeof(struct ImagingMemoryInstance)); } void @@ -485,15 +497,16 @@ ImagingAllocateBlock(Imaging im) { * Create a new, internally allocated, image. */ -Imaging -ImagingNewInternal(const char *mode, int xsize, int ysize, int dirty) { +static Imaging +ImagingNewInternal( + const char *mode, int xsize, int ysize, int depth, int bands, int dirty) { Imaging im; if (xsize < 0 || ysize < 0) { return (Imaging)ImagingError_ValueError("bad image size"); } - im = ImagingNewPrologue(mode, xsize, ysize); + im = ImagingNewPrologue(mode, xsize, ysize, depth, bands); if (!im) { return NULL; } @@ -514,13 +527,13 @@ ImagingNewInternal(const char *mode, int xsize, int ysize, int dirty) { } Imaging -ImagingNew(const char *mode, int xsize, int ysize) { - return ImagingNewInternal(mode, xsize, ysize, 0); +ImagingNew(const char *mode, int xsize, int ysize, int depth, int bands) { + return ImagingNewInternal(mode, xsize, ysize, depth, bands, 0); } Imaging ImagingNewDirty(const char *mode, int xsize, int ysize) { - return ImagingNewInternal(mode, xsize, ysize, 1); + return ImagingNewInternal(mode, xsize, ysize, -1, -1, 1); } Imaging @@ -531,7 +544,7 @@ ImagingNewBlock(const char *mode, int xsize, int ysize) { return (Imaging)ImagingError_ValueError("bad image size"); } - im = ImagingNewPrologue(mode, xsize, ysize); + im = ImagingNewPrologue(mode, xsize, ysize, -1, -1); if (!im) { return NULL; } diff --git a/src/map.c b/src/map.c index c298bd1482a..7b4514751f6 100644 --- a/src/map.c +++ b/src/map.c @@ -119,7 +119,8 @@ PyImaging_MapBuffer(PyObject *self, PyObject *args) { return NULL; } - im = ImagingNewPrologueSubtype(mode, xsize, ysize, sizeof(ImagingBufferInstance)); + im = ImagingNewPrologueSubtype( + mode, xsize, ysize, -1, -1, sizeof(ImagingBufferInstance)); if (!im) { PyBuffer_Release(&view); return NULL; From a4fab132d0b61f1be736b5865dd504f5a4b35c8b Mon Sep 17 00:00:00 2001 From: Junxiao Shi Date: Sat, 1 Jun 2024 20:32:41 +0000 Subject: [PATCH 06/23] re-enable PyImaging_MapBuffer --- src/PIL/ImageFile.py | 5 +---- src/PIL/TiffImagePlugin.py | 2 -- src/_imaging.c | 7 +++---- src/map.c | 15 ++++++++++----- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/PIL/ImageFile.py b/src/PIL/ImageFile.py index 6c92ea4f532..967bd392bce 100644 --- a/src/PIL/ImageFile.py +++ b/src/PIL/ImageFile.py @@ -206,9 +206,6 @@ def load(self): except AttributeError: seek = self.fp.seek - # XXX hack202406 disable unmodified code path - use_mmap = False - if use_mmap: # try memory mapping decoder_name, extents, offset, args = self.tile[0] @@ -230,7 +227,7 @@ def load(self): msg = "buffer is not large enough" raise OSError(msg) self.im = Image.core.map_buffer( - self.map, self.size, decoder_name, offset, args + self.map, self.size, decoder_name, offset, args, *self.newconfig ) readonly = 1 # After trashing self.im, diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index a829e8db535..efc14e78363 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -1417,8 +1417,6 @@ def _setup(self): logger.debug("- size: %s", self.size) sample_format = self.tag_v2.get(SAMPLEFORMAT, (1,)) - logger.debug("- sample_format: %s", sample_format) - bps_tuple = self.tag_v2.get(BITSPERSAMPLE, (1,)) extra_tuple = self.tag_v2.get(EXTRASAMPLES, ()) if photo in (2, 6, 8): # RGB, YCbCr, LAB diff --git a/src/_imaging.c b/src/_imaging.c index 4eee912f67a..6bd2a1aaa4b 100644 --- a/src/_imaging.c +++ b/src/_imaging.c @@ -94,10 +94,9 @@ #include /* Configuration stuff. Feel free to undef things you don't need. */ -#define WITH_IMAGECHOPS /* ImageChops support */ -#define WITH_IMAGEDRAW /* ImageDraw support */ -// XXX hack202406 disable unmodified code path -// #define WITH_MAPPING /* use memory mapping to read some file formats */ +#define WITH_IMAGECHOPS /* ImageChops support */ +#define WITH_IMAGEDRAW /* ImageDraw support */ +#define WITH_MAPPING /* use memory mapping to read some file formats */ #define WITH_IMAGEPATH /* ImagePath stuff */ #define WITH_ARROW /* arrow graphics stuff (experimental) */ #define WITH_EFFECTS /* special effects */ diff --git a/src/map.c b/src/map.c index 7b4514751f6..46db0aedee2 100644 --- a/src/map.c +++ b/src/map.c @@ -61,10 +61,11 @@ PyImaging_MapBuffer(PyObject *self, PyObject *args) { int xsize, ysize; int stride; int ystep; + int depth = -1, bands = -1; if (!PyArg_ParseTuple( args, - "O(ii)sn(sii)", + "O(ii)sn(sii)|ii", &target, &xsize, &ysize, @@ -72,7 +73,9 @@ PyImaging_MapBuffer(PyObject *self, PyObject *args) { &offset, &mode, &stride, - &ystep)) { + &ystep, + &depth, + &bands)) { return NULL; } @@ -82,10 +85,12 @@ PyImaging_MapBuffer(PyObject *self, PyObject *args) { } if (stride <= 0) { - if (!strcmp(mode, "L") || !strcmp(mode, "P")) { + if (strcmp(mode, "L") == 0 || strcmp(mode, "P") == 0) { stride = xsize; - } else if (!strncmp(mode, "I;16", 4)) { + } else if (strncmp(mode, "I;16", 4) == 0) { stride = xsize * 2; + } else if (strcmp(mode, IMAGING_MODE_MB) == 0) { + stride = xsize * depth * bands; } else { stride = xsize * 4; } @@ -120,7 +125,7 @@ PyImaging_MapBuffer(PyObject *self, PyObject *args) { } im = ImagingNewPrologueSubtype( - mode, xsize, ysize, -1, -1, sizeof(ImagingBufferInstance)); + mode, xsize, ysize, depth, bands, sizeof(ImagingBufferInstance)); if (!im) { PyBuffer_Release(&view); return NULL; From 76d336d21ab97e57139cf9012824391eacc903b0 Mon Sep 17 00:00:00 2001 From: Junxiao Shi Date: Sat, 1 Jun 2024 21:29:37 +0000 Subject: [PATCH 07/23] TIFF more entries in OPEN_INFO --- src/PIL/TiffImagePlugin.py | 9 +++++++++ src/libImaging/Access.c | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index efc14e78363..f17bf6db6a3 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -234,7 +234,9 @@ (II, 1, (1,), 1, (8, 8), (2,)): ("LA", "LA"), (MM, 1, (1,), 1, (8, 8), (2,)): ("LA", "LA"), (II, 2, (1,), 1, (8, 8, 8), ()): ("RGB", "RGB"), + (II, 2, (1, 1, 1), 1, (8, 8, 8), ()): ("RGB", "RGB"), (MM, 2, (1,), 1, (8, 8, 8), ()): ("RGB", "RGB"), + (MM, 2, (1, 1, 1), 1, (8, 8, 8), ()): ("RGB", "RGB"), (II, 2, (1,), 2, (8, 8, 8), ()): ("RGB", "RGB;R"), (MM, 2, (1,), 2, (8, 8, 8), ()): ("RGB", "RGB;R"), (II, 2, (1,), 1, (8, 8, 8, 8), ()): ("RGBA", "RGBA"), # missing ExtraSamples @@ -247,11 +249,13 @@ (MM, 2, (1,), 1, (8, 8, 8, 8, 8, 8), (0, 0, 0)): ("RGBX", "RGBXXX"), (II, 2, (1,), 1, (8, 8, 8, 8), (1,)): ("RGBA", "RGBa"), (MM, 2, (1,), 1, (8, 8, 8, 8), (1,)): ("RGBA", "RGBa"), + (MM, 2, (1, 1, 1, 1), 1, (8, 8, 8, 8), (1,)): ("RGBA", "RGBa"), (II, 2, (1,), 1, (8, 8, 8, 8, 8), (1, 0)): ("RGBA", "RGBaX"), (MM, 2, (1,), 1, (8, 8, 8, 8, 8), (1, 0)): ("RGBA", "RGBaX"), (II, 2, (1,), 1, (8, 8, 8, 8, 8, 8), (1, 0, 0)): ("RGBA", "RGBaXX"), (MM, 2, (1,), 1, (8, 8, 8, 8, 8, 8), (1, 0, 0)): ("RGBA", "RGBaXX"), (II, 2, (1,), 1, (8, 8, 8, 8), (2,)): ("RGBA", "RGBA"), + (II, 2, (1, 1, 1, 1), 1, (8, 8, 8, 8), (2,)): ("RGBA", "RGBA"), (MM, 2, (1,), 1, (8, 8, 8, 8), (2,)): ("RGBA", "RGBA"), (II, 2, (1,), 1, (8, 8, 8, 8, 8), (2, 0)): ("RGBA", "RGBAX"), (MM, 2, (1,), 1, (8, 8, 8, 8, 8), (2, 0)): ("RGBA", "RGBAX"), @@ -260,13 +264,16 @@ (II, 2, (1,), 1, (8, 8, 8, 8), (999,)): ("RGBA", "RGBA"), # Corel Draw 10 (MM, 2, (1,), 1, (8, 8, 8, 8), (999,)): ("RGBA", "RGBA"), # Corel Draw 10 (II, 2, (1,), 1, (16, 16, 16), ()): ("RGB", "RGB;16L"), + (II, 2, (1, 1, 1), 1, (16, 16, 16), ()): ("RGB", "RGB;16L"), (MM, 2, (1,), 1, (16, 16, 16), ()): ("RGB", "RGB;16B"), (II, 2, (1,), 1, (16, 16, 16, 16), ()): ("RGBA", "RGBA;16L"), (MM, 2, (1,), 1, (16, 16, 16, 16), ()): ("RGBA", "RGBA;16B"), (II, 2, (1,), 1, (16, 16, 16, 16), (0,)): ("RGBX", "RGBX;16L"), (MM, 2, (1,), 1, (16, 16, 16, 16), (0,)): ("RGBX", "RGBX;16B"), (II, 2, (1,), 1, (16, 16, 16, 16), (1,)): ("RGBA", "RGBa;16L"), + (II, 2, (1, 1, 1, 1), 1, (16, 16, 16, 16), (1,)): ("RGBA", "RGBa;16L"), (MM, 2, (1,), 1, (16, 16, 16, 16), (1,)): ("RGBA", "RGBa;16B"), + (MM, 2, (1, 1, 1, 1), 1, (16, 16, 16, 16), (1,)): ("RGBA", "RGBa;16B"), (II, 2, (1,), 1, (16, 16, 16, 16), (2,)): ("RGBA", "RGBA;16L"), (MM, 2, (1,), 1, (16, 16, 16, 16), (2,)): ("RGBA", "RGBA;16B"), (II, 3, (1,), 1, (1,), ()): ("P", "P;1"), @@ -300,9 +307,11 @@ # JPEG compressed images handled by LibTiff and auto-converted to RGBX # Minimal Baseline TIFF requires YCbCr images to have 3 SamplesPerPixel (II, 6, (1,), 1, (8, 8, 8), ()): ("RGB", "RGBX"), + (II, 6, (1, 1, 1), 1, (8, 8, 8), ()): ("RGB", "RGBX"), (MM, 6, (1,), 1, (8, 8, 8), ()): ("RGB", "RGBX"), (II, 8, (1,), 1, (8, 8, 8), ()): ("LAB", "LAB"), (MM, 8, (1,), 1, (8, 8, 8), ()): ("LAB", "LAB"), + # XXX hack202406 these entries allow all TIFF tests to pass, but more may be needed } MAX_SAMPLESPERPIXEL = max(len(key_tp[4]) for key_tp in OPEN_INFO) diff --git a/src/libImaging/Access.c b/src/libImaging/Access.c index f567bdbabdb..1a5603a140b 100644 --- a/src/libImaging/Access.c +++ b/src/libImaging/Access.c @@ -189,7 +189,7 @@ put_pixel_32(Imaging im, int x, int y, const void *color) { } static void -put_pixel_mb(Imaging im, int x, int y, void *color) { +put_pixel_mb(Imaging im, int x, int y, const void *color) { memcpy(&im->image[y][x * im->pixelsize], color, im->pixelsize); } From ed15ed97377b923d4aee62763892844047e30c5d Mon Sep 17 00:00:00 2001 From: Junxiao Shi Date: Sat, 1 Jun 2024 22:41:57 +0000 Subject: [PATCH 08/23] cgetpixel_mb constant size buffer --- src/_imaging.c | 3 ++- src/libImaging/Storage.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/_imaging.c b/src/_imaging.c index 6bd2a1aaa4b..617acf503ce 100644 --- a/src/_imaging.c +++ b/src/_imaging.c @@ -435,7 +435,8 @@ float16tofloat32(const FLOAT16 in) { static inline PyObject * getpixel_mb(Imaging im, ImagingAccess access, int x, int y) { - UINT8 pixel[im->pixelsize]; + UINT8 pixel[sizeof(INT32) * 6]; + assert(im->pixelsize <= sizeof(pixel)); access->get_pixel(im, x, y, &pixel); PyObject *tuple = PyTuple_New(im->bands); diff --git a/src/libImaging/Storage.c b/src/libImaging/Storage.c index cdf62ceb3c7..382dbfa49be 100644 --- a/src/libImaging/Storage.c +++ b/src/libImaging/Storage.c @@ -198,7 +198,7 @@ ImagingNewPrologueSubtype( } im->bands = bands; im->depth = depth; - im->pixelsize = depth * bands; + im->pixelsize = depth / CHAR_BIT * bands; im->linesize = xsize * im->pixelsize; im->type = IMAGING_TYPE_MB; From fb7702f638b300a07fae22601caf24156dd336ae Mon Sep 17 00:00:00 2001 From: Junxiao Shi Date: Sat, 1 Jun 2024 22:42:11 +0000 Subject: [PATCH 09/23] mb_shuffle big endian --- src/decode.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/decode.c b/src/decode.c index af08010188a..3a9c77c611b 100644 --- a/src/decode.c +++ b/src/decode.c @@ -303,7 +303,33 @@ shuffle_mb_unavail(UINT8 *dst, const UINT8 *src, int pixels) { static void mb_shuffle(UINT8 *dst, const UINT8 *src, Imaging im, ImagingCodecState state) { - memcpy(dst, src, state->xsize * im->pixelsize); + int size = state->xsize * im->pixelsize; +#ifdef WORDS_BIGENDIAN + switch (im->depth) { + default: + abort(); + return; + case 4 * CHAR_BIT: { + for (int i = 0; i < size; i += 4) { + dst[i] = src[i + 3]; + dst[i + 1] = src[i + 2]; + dst[i + 2] = src[i + 1]; + dst[i + 3] = src[i]; + } + return; + } + case 2 * CHAR_BIT: { + for (int i = 0; i < size; i += 2) { + dst[i] = src[i + 1]; + dst[i + 1] = src[i]; + } + return; + case CHAR_BIT: + // fallthrough + } + } +#endif + memcpy(dst, src, size); } static int From 86e7fc6b820dd7543d11848ed47944f318888cc3 Mon Sep 17 00:00:00 2001 From: Junxiao Shi Date: Sun, 2 Jun 2024 12:27:51 +0000 Subject: [PATCH 10/23] copy() with multi-band format --- Tests/test_file_tiff.py | 18 +++++-- src/_imaging.c | 31 +++++++----- src/libImaging/AlphaComposite.c | 3 +- src/libImaging/Bands.c | 7 +-- src/libImaging/Blend.c | 3 +- src/libImaging/BoxBlur.c | 3 +- src/libImaging/Chops.c | 2 +- src/libImaging/Crop.c | 2 +- src/libImaging/Effects.c | 6 +-- src/libImaging/Fill.c | 4 +- src/libImaging/Filter.c | 5 +- src/libImaging/Imaging.h | 16 ++++-- src/libImaging/Matrix.c | 4 +- src/libImaging/ModeFilter.c | 2 +- src/libImaging/Negative.c | 2 +- src/libImaging/Offset.c | 2 +- src/libImaging/Point.c | 4 +- src/libImaging/Quant.c | 2 +- src/libImaging/RankFilter.c | 4 +- src/libImaging/Reduce.c | 4 +- src/libImaging/Resample.c | 5 +- src/libImaging/Storage.c | 90 ++++++++++++++++----------------- src/map.c | 4 +- 23 files changed, 126 insertions(+), 97 deletions(-) diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index fc98901a4bc..ccef7a5137d 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -876,16 +876,24 @@ def test_oom(self, test_file: str) -> None: def test_open_tiff_uint16_multiband(self): """Test opening multiband TIFFs and reading all channels.""" + + def getpixel00(im: Image.Image): + actual_pixel = im.getpixel((0, 0)) + if isinstance(actual_pixel, int): + actual_pixel = (actual_pixel,) + return actual_pixel + base_value = 4660 for i in range(1, 6): + pixel = tuple([base_value + j for j in range(0, i)]) infile = f"Tests/images/uint16_{i}_{base_value}.tif" im = Image.open(infile) + im.load() - pixel = tuple([base_value + j for j in range(0, i)]) - actual_pixel = im.getpixel((0, 0)) - if isinstance(actual_pixel, int): - actual_pixel = (actual_pixel,) - assert actual_pixel == pixel + assert getpixel00(im) == pixel + + im.copy() + assert getpixel00(im) == pixel @pytest.mark.skipif(not is_win32(), reason="Windows only") diff --git a/src/_imaging.c b/src/_imaging.c index 617acf503ce..8e2df33ab01 100644 --- a/src/_imaging.c +++ b/src/_imaging.c @@ -309,7 +309,7 @@ getbands(const char *mode) { int bands; /* FIXME: add primitive to libImaging to avoid extra allocation */ - im = ImagingNew(mode, 0, 0, -1, -1); + im = ImagingNew(mode, (ImagingNewParams){0, 0}); if (!im) { return -1; } @@ -697,7 +697,7 @@ _fill(PyObject *self, PyObject *args) { return NULL; } - im = ImagingNewDirty(mode, xsize, ysize); + im = ImagingNewDirty(mode, (ImagingNewParams){xsize, ysize}); if (!im) { return NULL; } @@ -724,7 +724,8 @@ _new(PyObject *self, PyObject *args) { return NULL; } - return PyImagingNew(ImagingNew(mode, xsize, ysize, depth, bands)); + return PyImagingNew( + ImagingNew(mode, (ImagingNewParams){xsize, ysize, depth, bands})); } static PyObject * @@ -940,7 +941,8 @@ _color_lut_3d(ImagingObject *self, PyObject *args) { return NULL; } - imOut = ImagingNewDirty(mode, self->image->xsize, self->image->ysize); + imOut = ImagingNewDirty( + mode, (ImagingNewParams){self->image->xsize, self->image->ysize}); if (!imOut) { free(prepared_table); return NULL; @@ -1127,7 +1129,7 @@ _gaussian_blur(ImagingObject *self, PyObject *args) { } imIn = self->image; - imOut = ImagingNewDirty(imIn->mode, imIn->xsize, imIn->ysize); + imOut = ImagingNewDirty(imIn->mode, (ImagingNewParams){imIn->xsize, imIn->ysize}); if (!imOut) { return NULL; } @@ -1747,8 +1749,8 @@ _quantize(ImagingObject *self, PyObject *args) { if (!self->image->xsize || !self->image->ysize) { /* no content; return an empty image */ - return PyImagingNew( - ImagingNew("P", self->image->xsize, self->image->ysize, -1, -1)); + return PyImagingNew(ImagingNew( + "P", (ImagingNewParams){self->image->xsize, self->image->ysize})); } return PyImagingNew(ImagingQuantize(self->image, colours, method, kmeans)); @@ -1955,7 +1957,7 @@ _resize(ImagingObject *self, PyObject *args) { a[2] = box[0]; a[5] = box[1]; - imOut = ImagingNewDirty(imIn->mode, xsize, ysize); + imOut = ImagingNewDirty(imIn->mode, (ImagingNewParams){xsize, ysize}); imOut = ImagingTransform( imOut, imIn, IMAGING_TRANSFORM_AFFINE, 0, 0, xsize, ysize, a, filter, 1); @@ -2140,13 +2142,15 @@ _transpose(ImagingObject *self, PyObject *args) { case 0: /* flip left right */ case 1: /* flip top bottom */ case 3: /* rotate 180 */ - imOut = ImagingNewDirty(imIn->mode, imIn->xsize, imIn->ysize); + imOut = ImagingNewDirty( + imIn->mode, (ImagingNewParams){imIn->xsize, imIn->ysize}); break; case 2: /* rotate 90 */ case 4: /* rotate 270 */ case 5: /* transpose */ case 6: /* transverse */ - imOut = ImagingNewDirty(imIn->mode, imIn->ysize, imIn->xsize); + imOut = ImagingNewDirty( + imIn->mode, (ImagingNewParams){imIn->ysize, imIn->xsize}); break; default: PyErr_SetString(PyExc_ValueError, "No such transpose operation"); @@ -2195,7 +2199,7 @@ _unsharp_mask(ImagingObject *self, PyObject *args) { } imIn = self->image; - imOut = ImagingNewDirty(imIn->mode, imIn->xsize, imIn->ysize); + imOut = ImagingNewDirty(imIn->mode, (ImagingNewParams){imIn->xsize, imIn->ysize}); if (!imOut) { return NULL; } @@ -2220,7 +2224,7 @@ _box_blur(ImagingObject *self, PyObject *args) { } imIn = self->image; - imOut = ImagingNewDirty(imIn->mode, imIn->xsize, imIn->ysize); + imOut = ImagingNewDirty(imIn->mode, (ImagingNewParams){imIn->xsize, imIn->ysize}); if (!imOut) { return NULL; } @@ -2816,7 +2820,8 @@ _font_getmask(ImagingFontObject *self, PyObject *args) { return NULL; } - im = ImagingNew(self->bitmap->mode, textwidth(self, text), self->ysize, -1, -1); + im = ImagingNew( + self->bitmap->mode, (ImagingNewParams){textwidth(self, text), self->ysize}); if (!im) { free(text); return ImagingError_MemoryError(); diff --git a/src/libImaging/AlphaComposite.c b/src/libImaging/AlphaComposite.c index 6d728f9088b..b47441a6a48 100644 --- a/src/libImaging/AlphaComposite.c +++ b/src/libImaging/AlphaComposite.c @@ -36,7 +36,8 @@ ImagingAlphaComposite(Imaging imDst, Imaging imSrc) { return ImagingError_Mismatch(); } - imOut = ImagingNewDirty(imDst->mode, imDst->xsize, imDst->ysize); + imOut = + ImagingNewDirty(imDst->mode, (ImagingNewParams){imDst->xsize, imDst->ysize}); if (!imOut) { return NULL; } diff --git a/src/libImaging/Bands.c b/src/libImaging/Bands.c index e1b16b34ac0..d9b31ce1dc0 100644 --- a/src/libImaging/Bands.c +++ b/src/libImaging/Bands.c @@ -41,7 +41,7 @@ ImagingGetBand(Imaging imIn, int band) { band = 3; } - imOut = ImagingNewDirty("L", imIn->xsize, imIn->ysize); + imOut = ImagingNewDirty("L", (ImagingNewParams){imIn->xsize, imIn->ysize}); if (!imOut) { return NULL; } @@ -82,7 +82,7 @@ ImagingSplit(Imaging imIn, Imaging bands[4]) { } for (i = 0; i < imIn->bands; i++) { - bands[i] = ImagingNewDirty("L", imIn->xsize, imIn->ysize); + bands[i] = ImagingNewDirty("L", (ImagingNewParams){imIn->xsize, imIn->ysize}); if (!bands[i]) { for (j = 0; j < i; ++j) { ImagingDelete(bands[j]); @@ -265,7 +265,8 @@ ImagingMerge(const char *mode, Imaging bands[4]) { } bandsCount = i; - imOut = ImagingNewDirty(mode, firstBand->xsize, firstBand->ysize); + imOut = + ImagingNewDirty(mode, (ImagingNewParams){firstBand->xsize, firstBand->ysize}); if (!imOut) { return NULL; } diff --git a/src/libImaging/Blend.c b/src/libImaging/Blend.c index a53ae0fad53..444bf7f4074 100644 --- a/src/libImaging/Blend.c +++ b/src/libImaging/Blend.c @@ -41,7 +41,8 @@ ImagingBlend(Imaging imIn1, Imaging imIn2, float alpha) { return ImagingCopy(imIn2); } - imOut = ImagingNewDirty(imIn1->mode, imIn1->xsize, imIn1->ysize); + imOut = + ImagingNewDirty(imIn1->mode, (ImagingNewParams){imIn1->xsize, imIn1->ysize}); if (!imOut) { return NULL; } diff --git a/src/libImaging/BoxBlur.c b/src/libImaging/BoxBlur.c index 4ea9c77178a..366e81ee6f2 100644 --- a/src/libImaging/BoxBlur.c +++ b/src/libImaging/BoxBlur.c @@ -269,7 +269,8 @@ ImagingBoxBlur(Imaging imOut, Imaging imIn, float xradius, float yradius, int n) } } if (yradius != 0) { - imTransposed = ImagingNewDirty(imIn->mode, imIn->ysize, imIn->xsize); + imTransposed = + ImagingNewDirty(imIn->mode, (ImagingNewParams){imIn->ysize, imIn->xsize}); if (!imTransposed) { return NULL; } diff --git a/src/libImaging/Chops.c b/src/libImaging/Chops.c index f9c005efe3a..580568dc1e3 100644 --- a/src/libImaging/Chops.c +++ b/src/libImaging/Chops.c @@ -74,7 +74,7 @@ create(Imaging im1, Imaging im2, char *mode) { xsize = (im1->xsize < im2->xsize) ? im1->xsize : im2->xsize; ysize = (im1->ysize < im2->ysize) ? im1->ysize : im2->ysize; - return ImagingNewDirty(im1->mode, xsize, ysize); + return ImagingNewDirty(im1->mode, (ImagingNewParams){xsize, ysize}); } Imaging diff --git a/src/libImaging/Crop.c b/src/libImaging/Crop.c index 2425b4cd589..630028d0e16 100644 --- a/src/libImaging/Crop.c +++ b/src/libImaging/Crop.c @@ -37,7 +37,7 @@ ImagingCrop(Imaging imIn, int sx0, int sy0, int sx1, int sy1) { ysize = 0; } - imOut = ImagingNewDirty(imIn->mode, xsize, ysize); + imOut = ImagingNewDirty(imIn->mode, (ImagingNewParams){xsize, ysize}); if (!imOut) { return NULL; } diff --git a/src/libImaging/Effects.c b/src/libImaging/Effects.c index 93e7af0bce9..3d8a2e984f5 100644 --- a/src/libImaging/Effects.c +++ b/src/libImaging/Effects.c @@ -36,7 +36,7 @@ ImagingEffectMandelbrot(int xsize, int ysize, double extent[4], int quality) { return (Imaging)ImagingError_ValueError(NULL); } - im = ImagingNewDirty("L", xsize, ysize); + im = ImagingNewDirty("L", (ImagingNewParams){xsize, ysize}); if (!im) { return NULL; } @@ -80,7 +80,7 @@ ImagingEffectNoise(int xsize, int ysize, float sigma) { int nextok; double this, next; - imOut = ImagingNewDirty("L", xsize, ysize); + imOut = ImagingNewDirty("L", (ImagingNewParams){xsize, ysize}); if (!imOut) { return NULL; } @@ -120,7 +120,7 @@ ImagingEffectSpread(Imaging imIn, int distance) { Imaging imOut; int x, y; - imOut = ImagingNewDirty(imIn->mode, imIn->xsize, imIn->ysize); + imOut = ImagingNewDirty(imIn->mode, (ImagingNewParams){imIn->xsize, imIn->ysize}); if (!imOut) { return NULL; diff --git a/src/libImaging/Fill.c b/src/libImaging/Fill.c index 5b6bfb89cd8..0090c23ab6a 100644 --- a/src/libImaging/Fill.c +++ b/src/libImaging/Fill.c @@ -76,7 +76,7 @@ ImagingFillLinearGradient(const char *mode) { return (Imaging)ImagingError_ModeError(); } - im = ImagingNewDirty(mode, 256, 256); + im = ImagingNewDirty(mode, (ImagingNewParams){256, 256}); if (!im) { return NULL; } @@ -111,7 +111,7 @@ ImagingFillRadialGradient(const char *mode) { return (Imaging)ImagingError_ModeError(); } - im = ImagingNewDirty(mode, 256, 256); + im = ImagingNewDirty(mode, (ImagingNewParams){256, 256}); if (!im) { return NULL; } diff --git a/src/libImaging/Filter.c b/src/libImaging/Filter.c index 85de77fcbbc..87928acc8ee 100644 --- a/src/libImaging/Filter.c +++ b/src/libImaging/Filter.c @@ -59,7 +59,8 @@ ImagingExpand(Imaging imIn, int xmargin, int ymargin) { } imOut = ImagingNewDirty( - imIn->mode, imIn->xsize + 2 * xmargin, imIn->ysize + 2 * ymargin); + imIn->mode, + (ImagingNewParams){imIn->xsize + 2 * xmargin, imIn->ysize + 2 * ymargin}); if (!imOut) { return NULL; } @@ -393,7 +394,7 @@ ImagingFilter(Imaging im, int xsize, int ysize, const FLOAT32 *kernel, FLOAT32 o return (Imaging)ImagingError_ValueError("bad kernel size"); } - imOut = ImagingNewDirty(im->mode, im->xsize, im->ysize); + imOut = ImagingNewDirty(im->mode, (ImagingNewParams){im->xsize, im->ysize}); if (!imOut) { return NULL; } diff --git a/src/libImaging/Imaging.h b/src/libImaging/Imaging.h index ee2f6ea9d17..6dc14ee1c99 100644 --- a/src/libImaging/Imaging.h +++ b/src/libImaging/Imaging.h @@ -75,6 +75,13 @@ typedef struct ImagingPaletteInstance *ImagingPalette; #define IMAGING_MODE_MB "MB" /* multi-band format */ +typedef struct { + int xsize; + int ysize; + int depth; + int bands; +} ImagingNewParams; + typedef struct { char *ptr; int size; @@ -176,9 +183,9 @@ extern void ImagingMemoryClearCache(ImagingMemoryArena arena, int new_size); extern Imaging -ImagingNew(const char *mode, int xsize, int ysize, int depth, int bands); +ImagingNew(const char *mode, ImagingNewParams p); extern Imaging -ImagingNewDirty(const char *mode, int xsize, int ysize); +ImagingNewDirty(const char *mode, ImagingNewParams p); extern Imaging ImagingNew2Dirty(const char *mode, Imaging imOut, Imaging imIn); extern void @@ -188,10 +195,9 @@ extern Imaging ImagingNewBlock(const char *mode, int xsize, int ysize); extern Imaging -ImagingNewPrologue(const char *mode, int xsize, int ysize, int depth, int bands); +ImagingNewPrologue(const char *mode, ImagingNewParams p); extern Imaging -ImagingNewPrologueSubtype( - const char *mode, int xsize, int ysize, int depth, int bands, int structure_size); +ImagingNewPrologueSubtype(const char *mode, ImagingNewParams p, int structure_size); extern void ImagingCopyPalette(Imaging destination, Imaging source); diff --git a/src/libImaging/Matrix.c b/src/libImaging/Matrix.c index ec7f4d93e06..45cc486473f 100644 --- a/src/libImaging/Matrix.c +++ b/src/libImaging/Matrix.c @@ -29,7 +29,7 @@ ImagingConvertMatrix(Imaging im, const char *mode, float m[]) { } if (strcmp(mode, "L") == 0) { - imOut = ImagingNewDirty("L", im->xsize, im->ysize); + imOut = ImagingNewDirty("L", (ImagingNewParams){im->xsize, im->ysize}); if (!imOut) { return NULL; } @@ -48,7 +48,7 @@ ImagingConvertMatrix(Imaging im, const char *mode, float m[]) { ImagingSectionLeave(&cookie); } else if (strlen(mode) == 3) { - imOut = ImagingNewDirty(mode, im->xsize, im->ysize); + imOut = ImagingNewDirty(mode, (ImagingNewParams){im->xsize, im->ysize}); if (!imOut) { return NULL; } diff --git a/src/libImaging/ModeFilter.c b/src/libImaging/ModeFilter.c index 757cbc3fb86..0178fbef06e 100644 --- a/src/libImaging/ModeFilter.c +++ b/src/libImaging/ModeFilter.c @@ -28,7 +28,7 @@ ImagingModeFilter(Imaging im, int size) { return (Imaging)ImagingError_ModeError(); } - imOut = ImagingNewDirty(im->mode, im->xsize, im->ysize); + imOut = ImagingNewDirty(im->mode, (ImagingNewParams){im->xsize, im->ysize}); if (!imOut) { return NULL; } diff --git a/src/libImaging/Negative.c b/src/libImaging/Negative.c index 70b96c39772..88755813079 100644 --- a/src/libImaging/Negative.c +++ b/src/libImaging/Negative.c @@ -27,7 +27,7 @@ ImagingNegative(Imaging im) { return (Imaging)ImagingError_ModeError(); } - imOut = ImagingNewDirty(im->mode, im->xsize, im->ysize); + imOut = ImagingNewDirty(im->mode, (ImagingNewParams){im->xsize, im->ysize}); if (!imOut) { return NULL; } diff --git a/src/libImaging/Offset.c b/src/libImaging/Offset.c index 91ee91083cc..9bc74a4fed6 100644 --- a/src/libImaging/Offset.c +++ b/src/libImaging/Offset.c @@ -25,7 +25,7 @@ ImagingOffset(Imaging im, int xoffset, int yoffset) { return (Imaging)ImagingError_ModeError(); } - imOut = ImagingNewDirty(im->mode, im->xsize, im->ysize); + imOut = ImagingNewDirty(im->mode, (ImagingNewParams){im->xsize, im->ysize}); if (!imOut) { return NULL; } diff --git a/src/libImaging/Point.c b/src/libImaging/Point.c index 3d54008cbc3..bf4b6c8efbd 100644 --- a/src/libImaging/Point.c +++ b/src/libImaging/Point.c @@ -152,7 +152,7 @@ ImagingPoint(Imaging imIn, const char *mode, const void *table) { goto mode_mismatch; } - imOut = ImagingNew(mode, imIn->xsize, imIn->ysize, -1, -1); + imOut = ImagingNew(mode, (ImagingNewParams){imIn->xsize, imIn->ysize}); if (!imOut) { return NULL; } @@ -214,7 +214,7 @@ ImagingPointTransform(Imaging imIn, double scale, double offset) { return (Imaging)ImagingError_ModeError(); } - imOut = ImagingNew(imIn->mode, imIn->xsize, imIn->ysize, -1, -1); + imOut = ImagingNew(imIn->mode, (ImagingNewParams){imIn->xsize, imIn->ysize}); if (!imOut) { return NULL; } diff --git a/src/libImaging/Quant.c b/src/libImaging/Quant.c index cdc614536da..8912bbd1be1 100644 --- a/src/libImaging/Quant.c +++ b/src/libImaging/Quant.c @@ -1799,7 +1799,7 @@ ImagingQuantize(Imaging im, int colors, int mode, int kmeans) { ImagingSectionLeave(&cookie); if (result > 0) { - imOut = ImagingNewDirty("P", im->xsize, im->ysize); + imOut = ImagingNewDirty("P", (ImagingNewParams){im->xsize, im->ysize}); ImagingSectionEnter(&cookie); for (i = y = 0; y < im->ysize; y++) { diff --git a/src/libImaging/RankFilter.c b/src/libImaging/RankFilter.c index da40c892f11..9389a7bf562 100644 --- a/src/libImaging/RankFilter.c +++ b/src/libImaging/RankFilter.c @@ -84,8 +84,8 @@ MakeRankFunction(UINT8) MakeRankFunction(INT32) MakeRankFunction(FLOAT32) return (Imaging)ImagingError_ValueError("bad rank value"); } - imOut = - ImagingNew(im->mode, im->xsize - 2 * margin, im->ysize - 2 * margin, -1, -1); + imOut = ImagingNew( + im->mode, (ImagingNewParams){im->xsize - 2 * margin, im->ysize - 2 * margin}); if (!imOut) { return NULL; } diff --git a/src/libImaging/Reduce.c b/src/libImaging/Reduce.c index 61566f0c506..bb1a86848c8 100644 --- a/src/libImaging/Reduce.c +++ b/src/libImaging/Reduce.c @@ -1427,7 +1427,9 @@ ImagingReduce(Imaging imIn, int xscale, int yscale, int box[4]) { } imOut = ImagingNewDirty( - imIn->mode, (box[2] + xscale - 1) / xscale, (box[3] + yscale - 1) / yscale); + imIn->mode, + (ImagingNewParams){ + (box[2] + xscale - 1) / xscale, (box[3] + yscale - 1) / yscale}); if (!imOut) { return NULL; } diff --git a/src/libImaging/Resample.c b/src/libImaging/Resample.c index 59c27b3f421..526c892fb82 100644 --- a/src/libImaging/Resample.c +++ b/src/libImaging/Resample.c @@ -659,7 +659,8 @@ ImagingResampleInner( bounds_vert[i * 2] -= ybox_first; } - imTemp = ImagingNewDirty(imIn->mode, xsize, ybox_last - ybox_first); + imTemp = ImagingNewDirty( + imIn->mode, (ImagingNewParams){xsize, ybox_last - ybox_first}); if (imTemp) { ResampleHorizontal( imTemp, imIn, ybox_first, ksize_horiz, bounds_horiz, kk_horiz); @@ -680,7 +681,7 @@ ImagingResampleInner( /* vertical pass */ if (need_vertical) { - imOut = ImagingNewDirty(imIn->mode, imIn->xsize, ysize); + imOut = ImagingNewDirty(imIn->mode, (ImagingNewParams){imIn->xsize, ysize}); if (imOut) { /* imIn can be the original image or horizontally resampled one */ ResampleVertical(imOut, imIn, 0, ksize_vert, bounds_vert, kk_vert); diff --git a/src/libImaging/Storage.c b/src/libImaging/Storage.c index 382dbfa49be..788366161ab 100644 --- a/src/libImaging/Storage.c +++ b/src/libImaging/Storage.c @@ -42,12 +42,11 @@ */ Imaging -ImagingNewPrologueSubtype( - const char *mode, int xsize, int ysize, int depth, int bands, int size) { +ImagingNewPrologueSubtype(const char *mode, ImagingNewParams p, int size) { Imaging im; /* linesize overflow check, roughly the current largest space req'd */ - if (xsize > (INT_MAX / 4) - 1) { + if (p.xsize > (INT_MAX / 4) - 1) { return (Imaging)ImagingError_MemoryError(); } @@ -57,58 +56,58 @@ ImagingNewPrologueSubtype( } /* Setup image descriptor */ - im->xsize = xsize; - im->ysize = ysize; + im->xsize = p.xsize; + im->ysize = p.ysize; im->type = IMAGING_TYPE_UINT8; if (strcmp(mode, "1") == 0) { /* 1-bit images */ im->bands = im->pixelsize = 1; - im->linesize = xsize; + im->linesize = p.xsize; } else if (strcmp(mode, "P") == 0) { /* 8-bit palette mapped images */ im->bands = im->pixelsize = 1; - im->linesize = xsize; + im->linesize = p.xsize; im->palette = ImagingPaletteNew("RGB"); } 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->linesize = p.xsize * 4; im->palette = ImagingPaletteNew("RGB"); } else if (strcmp(mode, "L") == 0) { /* 8-bit grayscale (luminance) images */ im->bands = im->pixelsize = 1; - im->linesize = xsize; + im->linesize = p.xsize; } else if (strcmp(mode, "LA") == 0) { /* 8-bit grayscale (luminance) with alpha */ im->bands = 2; im->pixelsize = 4; /* store in image32 memory */ - im->linesize = xsize * 4; + im->linesize = p.xsize * 4; } else if (strcmp(mode, "La") == 0) { /* 8-bit grayscale (luminance) with premultiplied alpha */ im->bands = 2; im->pixelsize = 4; /* store in image32 memory */ - im->linesize = xsize * 4; + im->linesize = p.xsize * 4; } else if (strcmp(mode, "F") == 0) { /* 32-bit floating point images */ im->bands = 1; im->pixelsize = 4; - im->linesize = xsize * 4; + im->linesize = p.xsize * 4; im->type = IMAGING_TYPE_FLOAT32; } else if (strcmp(mode, "I") == 0) { /* 32-bit integer images */ im->bands = 1; im->pixelsize = 4; - im->linesize = xsize * 4; + im->linesize = p.xsize * 4; im->type = IMAGING_TYPE_INT32; } else if ( @@ -118,21 +117,21 @@ ImagingNewPrologueSubtype( /* 16-bit raw integer images */ im->bands = 1; im->pixelsize = 2; - im->linesize = xsize * 2; + im->linesize = p.xsize * 2; im->type = IMAGING_TYPE_SPECIAL; } else if (strcmp(mode, "RGB") == 0) { /* 24-bit true colour images */ im->bands = 3; im->pixelsize = 4; - im->linesize = xsize * 4; + im->linesize = p.xsize * 4; } else if (strcmp(mode, "BGR;15") == 0) { /* EXPERIMENTAL */ /* 15-bit reversed true colour */ im->bands = 3; im->pixelsize = 2; - im->linesize = (xsize * 2 + 3) & -4; + im->linesize = (p.xsize * 2 + 3) & -4; im->type = IMAGING_TYPE_SPECIAL; } else if (strcmp(mode, "BGR;16") == 0) { @@ -140,7 +139,7 @@ ImagingNewPrologueSubtype( /* 16-bit reversed true colour */ im->bands = 3; im->pixelsize = 2; - im->linesize = (xsize * 2 + 3) & -4; + im->linesize = (p.xsize * 2 + 3) & -4; im->type = IMAGING_TYPE_SPECIAL; } else if (strcmp(mode, "BGR;24") == 0) { @@ -148,58 +147,58 @@ ImagingNewPrologueSubtype( /* 24-bit reversed true colour */ im->bands = 3; im->pixelsize = 3; - im->linesize = (xsize * 3 + 3) & -4; + im->linesize = (p.xsize * 3 + 3) & -4; im->type = IMAGING_TYPE_SPECIAL; } else if (strcmp(mode, "RGBX") == 0) { /* 32-bit true colour images with padding */ im->bands = im->pixelsize = 4; - im->linesize = xsize * 4; + im->linesize = p.xsize * 4; } else if (strcmp(mode, "RGBA") == 0) { /* 32-bit true colour images with alpha */ im->bands = im->pixelsize = 4; - im->linesize = xsize * 4; + im->linesize = p.xsize * 4; } else if (strcmp(mode, "RGBa") == 0) { /* 32-bit true colour images with premultiplied alpha */ im->bands = im->pixelsize = 4; - im->linesize = xsize * 4; + im->linesize = p.xsize * 4; } else if (strcmp(mode, "CMYK") == 0) { /* 32-bit colour separation */ im->bands = im->pixelsize = 4; - im->linesize = xsize * 4; + im->linesize = p.xsize * 4; } else if (strcmp(mode, "YCbCr") == 0) { /* 24-bit video format */ im->bands = 3; im->pixelsize = 4; - im->linesize = xsize * 4; + im->linesize = p.xsize * 4; } else if (strcmp(mode, "LAB") == 0) { /* 24-bit color, luminance, + 2 color channels */ /* L is uint8, a,b are int8 */ im->bands = 3; im->pixelsize = 4; - im->linesize = xsize * 4; + im->linesize = p.xsize * 4; } else if (strcmp(mode, "HSV") == 0) { /* 24-bit color, luminance, + 2 color channels */ /* L is uint8, a,b are int8 */ im->bands = 3; im->pixelsize = 4; - im->linesize = xsize * 4; + im->linesize = p.xsize * 4; } else if (strcmp(mode, IMAGING_MODE_MB) == 0) { - if (bands <= 0 || depth <= 0) { + if (p.bands <= 0 || p.depth <= 0) { return (Imaging)ImagingError_ValueError( "multi-band missing bands and depth"); } - im->bands = bands; - im->depth = depth; - im->pixelsize = depth / CHAR_BIT * bands; - im->linesize = xsize * im->pixelsize; + im->bands = p.bands; + im->depth = p.depth; + im->pixelsize = p.depth / CHAR_BIT * p.bands; + im->linesize = p.xsize * im->pixelsize; im->type = IMAGING_TYPE_MB; } else { @@ -212,7 +211,7 @@ ImagingNewPrologueSubtype( /* Pointer array (allocate at least one line, to avoid MemoryError exceptions on platforms where calloc(0, x) returns NULL) */ - im->image = (char **)calloc((ysize > 0) ? ysize : 1, sizeof(void *)); + im->image = (char **)calloc((p.ysize > 0) ? p.ysize : 1, sizeof(void *)); if (!im->image) { free(im); @@ -237,9 +236,8 @@ ImagingNewPrologueSubtype( } Imaging -ImagingNewPrologue(const char *mode, int xsize, int ysize, int depth, int bands) { - return ImagingNewPrologueSubtype( - mode, xsize, ysize, depth, bands, sizeof(struct ImagingMemoryInstance)); +ImagingNewPrologue(const char *mode, ImagingNewParams p) { + return ImagingNewPrologueSubtype(mode, p, sizeof(struct ImagingMemoryInstance)); } void @@ -498,15 +496,14 @@ ImagingAllocateBlock(Imaging im) { */ static Imaging -ImagingNewInternal( - const char *mode, int xsize, int ysize, int depth, int bands, int dirty) { +ImagingNewInternal(const char *mode, ImagingNewParams p, int dirty) { Imaging im; - if (xsize < 0 || ysize < 0) { + if (p.xsize < 0 || p.ysize < 0) { return (Imaging)ImagingError_ValueError("bad image size"); } - im = ImagingNewPrologue(mode, xsize, ysize, depth, bands); + im = ImagingNewPrologue(mode, p); if (!im) { return NULL; } @@ -527,13 +524,13 @@ ImagingNewInternal( } Imaging -ImagingNew(const char *mode, int xsize, int ysize, int depth, int bands) { - return ImagingNewInternal(mode, xsize, ysize, depth, bands, 0); +ImagingNew(const char *mode, ImagingNewParams p) { + return ImagingNewInternal(mode, p, 0); } Imaging -ImagingNewDirty(const char *mode, int xsize, int ysize) { - return ImagingNewInternal(mode, xsize, ysize, -1, -1, 1); +ImagingNewDirty(const char *mode, ImagingNewParams p) { + return ImagingNewInternal(mode, p, 1); } Imaging @@ -544,7 +541,7 @@ ImagingNewBlock(const char *mode, int xsize, int ysize) { return (Imaging)ImagingError_ValueError("bad image size"); } - im = ImagingNewPrologue(mode, xsize, ysize, -1, -1); + im = ImagingNewPrologue(mode, (ImagingNewParams){xsize, ysize}); if (!im) { return NULL; } @@ -564,12 +561,15 @@ ImagingNew2Dirty(const char *mode, Imaging imOut, Imaging imIn) { if (imOut) { /* make sure images match */ if (strcmp(imOut->mode, mode) != 0 || imOut->xsize != imIn->xsize || - imOut->ysize != imIn->ysize) { + imOut->ysize != imIn->ysize || imOut->depth != imIn->depth || + imOut->bands != imIn->bands) { return ImagingError_Mismatch(); } } else { /* create new image */ - imOut = ImagingNewDirty(mode, imIn->xsize, imIn->ysize); + imOut = ImagingNewDirty( + mode, + (ImagingNewParams){imIn->xsize, imIn->ysize, imIn->depth, imIn->bands}); if (!imOut) { return NULL; } diff --git a/src/map.c b/src/map.c index 46db0aedee2..acbac156222 100644 --- a/src/map.c +++ b/src/map.c @@ -125,7 +125,9 @@ PyImaging_MapBuffer(PyObject *self, PyObject *args) { } im = ImagingNewPrologueSubtype( - mode, xsize, ysize, depth, bands, sizeof(ImagingBufferInstance)); + mode, + (ImagingNewParams){xsize, ysize, depth, bands}, + sizeof(ImagingBufferInstance)); if (!im) { PyBuffer_Release(&view); return NULL; From 587bb9854024b1c6f371347dd0c40e4f16bb147f Mon Sep 17 00:00:00 2001 From: Junxiao Shi Date: Sun, 2 Jun 2024 12:40:32 +0000 Subject: [PATCH 11/23] crop() with multi-band format --- Tests/test_file_tiff.py | 20 +++++++++++++++----- src/libImaging/Crop.c | 3 ++- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index ccef7a5137d..81872fdc80c 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -877,11 +877,18 @@ def test_oom(self, test_file: str) -> None: def test_open_tiff_uint16_multiband(self): """Test opening multiband TIFFs and reading all channels.""" - def getpixel00(im: Image.Image): + def check_pixel(im: Image.Image, expected_pixel, pos: tuple[int, int]): actual_pixel = im.getpixel((0, 0)) if isinstance(actual_pixel, int): actual_pixel = (actual_pixel,) - return actual_pixel + assert actual_pixel == expected_pixel + + def check_image(im: Image.Image, width: int, height: int, expected_pixel): + assert im.width == width + assert im.height == height + for x in range(im.width): + for y in range(im.height): + check_pixel(im, expected_pixel, (x, y)) base_value = 4660 for i in range(1, 6): @@ -890,10 +897,13 @@ def getpixel00(im: Image.Image): im = Image.open(infile) im.load() - assert getpixel00(im) == pixel + check_image(im, 10, 10, pixel) + + im1 = im.copy() + check_image(im1, 10, 10, pixel) - im.copy() - assert getpixel00(im) == pixel + im2 = im.crop((2, 2, 7, 7)) + check_image(im2, 5, 5, pixel) @pytest.mark.skipif(not is_win32(), reason="Windows only") diff --git a/src/libImaging/Crop.c b/src/libImaging/Crop.c index 630028d0e16..52f9b0a431f 100644 --- a/src/libImaging/Crop.c +++ b/src/libImaging/Crop.c @@ -37,7 +37,8 @@ ImagingCrop(Imaging imIn, int sx0, int sy0, int sx1, int sy1) { ysize = 0; } - imOut = ImagingNewDirty(imIn->mode, (ImagingNewParams){xsize, ysize}); + imOut = ImagingNewDirty( + imIn->mode, (ImagingNewParams){xsize, ysize, imIn->depth, imIn->bands}); if (!imOut) { return NULL; } From 0df0935bb447a909b8cb22ef9e3db1581baa335c Mon Sep 17 00:00:00 2001 From: Junxiao Shi Date: Sun, 2 Jun 2024 13:07:58 +0000 Subject: [PATCH 12/23] ImagingNew2Dirty update mismatch condition --- src/libImaging/Storage.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libImaging/Storage.c b/src/libImaging/Storage.c index 788366161ab..6aa49a9080f 100644 --- a/src/libImaging/Storage.c +++ b/src/libImaging/Storage.c @@ -561,8 +561,9 @@ ImagingNew2Dirty(const char *mode, Imaging imOut, Imaging imIn) { if (imOut) { /* make sure images match */ if (strcmp(imOut->mode, mode) != 0 || imOut->xsize != imIn->xsize || - imOut->ysize != imIn->ysize || imOut->depth != imIn->depth || - imOut->bands != imIn->bands) { + imOut->ysize != imIn->ysize || + (strcmp(mode, IMAGING_MODE_MB) == 0 && + (imOut->depth != imIn->depth || imOut->bands != imIn->bands))) { return ImagingError_Mismatch(); } } else { From c4434df6a189f72c63ece424768410b296edeecf Mon Sep 17 00:00:00 2001 From: Junxiao Shi Date: Sun, 2 Jun 2024 17:38:27 +0000 Subject: [PATCH 13/23] FLIP_LEFT_RIGHT with multi-band format --- Tests/test_file_tiff.py | 3 +++ src/_imaging.c | 6 ++++-- src/libImaging/Geometry.c | 30 ++++++++---------------------- 3 files changed, 15 insertions(+), 24 deletions(-) diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index 81872fdc80c..6f00afdac49 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -905,6 +905,9 @@ def check_image(im: Image.Image, width: int, height: int, expected_pixel): im2 = im.crop((2, 2, 7, 7)) check_image(im2, 5, 5, pixel) + im3 = im.transpose(Image.Transpose.FLIP_LEFT_RIGHT) + check_image(im3, 10, 10, pixel) + @pytest.mark.skipif(not is_win32(), reason="Windows only") class TestFileTiffW32: diff --git a/src/_imaging.c b/src/_imaging.c index 8e2df33ab01..efcbf55c2aa 100644 --- a/src/_imaging.c +++ b/src/_imaging.c @@ -2143,14 +2143,16 @@ _transpose(ImagingObject *self, PyObject *args) { case 1: /* flip top bottom */ case 3: /* rotate 180 */ imOut = ImagingNewDirty( - imIn->mode, (ImagingNewParams){imIn->xsize, imIn->ysize}); + imIn->mode, + (ImagingNewParams){imIn->xsize, imIn->ysize, imIn->depth, imIn->bands}); break; case 2: /* rotate 90 */ case 4: /* rotate 270 */ case 5: /* transpose */ case 6: /* transverse */ imOut = ImagingNewDirty( - imIn->mode, (ImagingNewParams){imIn->ysize, imIn->xsize}); + imIn->mode, + (ImagingNewParams){imIn->ysize, imIn->xsize, imIn->depth, imIn->bands}); break; default: PyErr_SetString(PyExc_ValueError, "No such transpose operation"); diff --git a/src/libImaging/Geometry.c b/src/libImaging/Geometry.c index cf3bc997942..abc91fc1c11 100644 --- a/src/libImaging/Geometry.c +++ b/src/libImaging/Geometry.c @@ -17,7 +17,7 @@ Imaging ImagingFlipLeftRight(Imaging imOut, Imaging imIn) { ImagingSectionCookie cookie; - int x, y, xr; + // int x, y, xr; if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) { return (Imaging)ImagingError_ModeError(); @@ -28,32 +28,18 @@ ImagingFlipLeftRight(Imaging imOut, Imaging imIn) { ImagingCopyPalette(imOut, imIn); -#define FLIP_LEFT_RIGHT(INT, image) \ - for (y = 0; y < imIn->ysize; y++) { \ - INT *in = (INT *)imIn->image[y]; \ - INT *out = (INT *)imOut->image[y]; \ - xr = imIn->xsize - 1; \ - for (x = 0; x < imIn->xsize; x++, xr--) { \ - out[xr] = in[x]; \ - } \ - } - ImagingSectionEnter(&cookie); - - if (imIn->image8) { - if (strncmp(imIn->mode, "I;16", 4) == 0) { - FLIP_LEFT_RIGHT(UINT16, image8) - } else { - FLIP_LEFT_RIGHT(UINT8, image8) + for (int y = 0; y < imIn->ysize; ++y) { + char *in = imIn->image[y]; + char *out = imOut->image[y]; + int xr = imIn->linesize - imIn->pixelsize; + for (int x = 0; x < imIn->linesize; + x += imIn->pixelsize, xr -= imIn->pixelsize) { + memcpy(out + xr, in + x, imIn->pixelsize); } - } else { - FLIP_LEFT_RIGHT(INT32, image32) } - ImagingSectionLeave(&cookie); -#undef FLIP_LEFT_RIGHT - return imOut; } From c5ebc81dc33dc91ea358bb3d09cc32ff601d2142 Mon Sep 17 00:00:00 2001 From: Junxiao Shi Date: Sun, 2 Jun 2024 19:56:57 +0000 Subject: [PATCH 14/23] explain how mode=MB is stored --- src/libImaging/Imaging.h | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/libImaging/Imaging.h b/src/libImaging/Imaging.h index 6dc14ee1c99..976fe85e62f 100644 --- a/src/libImaging/Imaging.h +++ b/src/libImaging/Imaging.h @@ -42,11 +42,21 @@ extern "C" { * LA 4 L, -, -, A * PA 4 P, -, -, A * I;16 2 I (16-bit integer, native byte order) + * MB variable * * "P" is an 8-bit palette mode, which should be mapped through the * palette member to get an output image. Check palette->mode to * find the corresponding "real" mode. * + * "MB" is an experimental multi-band mode for multi-channel image where each sample is + * more than UINT8. In this mode, + * - im->depth is size of each sample in bits. Valid values are 8, 16, and 32. Currently + * each sample is assumed to be a uint; further refactoring will be needed to support + * int and float. + * - im->type is set to IMAGING_TYPE_MB. + * - Neither im->image8 nor im->image32 is set. All operators must access im->image + * directly. + * * For information on how to access Imaging objects from your own C * extensions, see http://www.effbot.org/zone/pil-extending.htm */ @@ -75,11 +85,12 @@ typedef struct ImagingPaletteInstance *ImagingPalette; #define IMAGING_MODE_MB "MB" /* multi-band format */ +/* Parameters of various ImagingNew* functions. */ typedef struct { int xsize; int ysize; - int depth; - int bands; + int depth; /** MB mode only. */ + int bands; /** MB mode only. */ } ImagingNewParams; typedef struct { From e0a5d81127819bf5d51c2b78dd4f2cc1191adb4a Mon Sep 17 00:00:00 2001 From: "Jeffrey A. Clark (Alex)" Date: Thu, 20 Jun 2024 09:23:30 -0400 Subject: [PATCH 15/23] hack202406 - requested changes --- src/PIL/ImageFile.py | 6 +++--- src/PIL/TiffImagePlugin.py | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/PIL/ImageFile.py b/src/PIL/ImageFile.py index 967bd392bce..e07a34f17f6 100644 --- a/src/PIL/ImageFile.py +++ b/src/PIL/ImageFile.py @@ -117,7 +117,7 @@ def __init__(self, fp=None, filename=None): self.readonly = 1 # until we know better - self.newconfig = () + self.mb_config = () self.decoderconfig = () self.decodermaxblock = MAXBLOCK @@ -227,7 +227,7 @@ def load(self): msg = "buffer is not large enough" raise OSError(msg) self.im = Image.core.map_buffer( - self.map, self.size, decoder_name, offset, args, *self.newconfig + self.map, self.size, decoder_name, offset, args, *self.mb_config ) readonly = 1 # After trashing self.im, @@ -316,7 +316,7 @@ def load(self): def load_prepare(self) -> None: # create image memory if necessary if not self.im or self.im.mode != self.mode or self.im.size != self.size: - self.im = Image.core.new(self.mode, self.size, *self.newconfig) + self.im = Image.core.new(self.mode, self.size, *self.mb_config) # create palette (optional) if self.mode == "P": Image.Image.load(self) diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index f17bf6db6a3..35cf4ef7efd 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -60,7 +60,6 @@ from .TiffTags import TYPES logger = logging.getLogger(__name__) -logger.setLevel(logging.DEBUG) # XXX hack202406 # Set these to true to force use of libtiff for reading or writing. READ_LIBTIFF = False @@ -1483,7 +1482,7 @@ def _setup(self): logger.debug("- pil mode: %s", self.mode) if self.mode == "MB": assert max(bps_tuple) == min(bps_tuple) - self.newconfig = (max(bps_tuple), samples_per_pixel) + self.mb_config = (max(bps_tuple), samples_per_pixel) self.info["compression"] = self._compression From 44da8b64c2d93efe1cf0deec3e1d092d724b5419 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 21 Jun 2024 21:38:06 +1000 Subject: [PATCH 16/23] Added type hints --- Tests/test_file_tiff.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index 6f00afdac49..d562b6fd09b 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -874,16 +874,20 @@ def test_oom(self, test_file: str) -> None: with Image.open(test_file): pass - def test_open_tiff_uint16_multiband(self): + def test_open_tiff_uint16_multiband(self) -> None: """Test opening multiband TIFFs and reading all channels.""" - def check_pixel(im: Image.Image, expected_pixel, pos: tuple[int, int]): + def check_pixel( + im: Image.Image, expected_pixel: tuple[int, ...], pos: tuple[int, int] + ) -> None: actual_pixel = im.getpixel((0, 0)) if isinstance(actual_pixel, int): actual_pixel = (actual_pixel,) assert actual_pixel == expected_pixel - def check_image(im: Image.Image, width: int, height: int, expected_pixel): + def check_image( + im: Image.Image, width: int, height: int, expected_pixel: tuple[int, ...] + ) -> None: assert im.width == width assert im.height == height for x in range(im.width): @@ -892,7 +896,7 @@ def check_image(im: Image.Image, width: int, height: int, expected_pixel): base_value = 4660 for i in range(1, 6): - pixel = tuple([base_value + j for j in range(0, i)]) + pixel = tuple(base_value + j for j in range(i)) infile = f"Tests/images/uint16_{i}_{base_value}.tif" im = Image.open(infile) From 5bdda4c012ea522078185c1bc6c9d2ed219a6062 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 22 Jun 2024 18:14:38 +1000 Subject: [PATCH 17/23] Declare variables at start of function --- src/libImaging/Geometry.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/libImaging/Geometry.c b/src/libImaging/Geometry.c index abc91fc1c11..a74fba7cfd0 100644 --- a/src/libImaging/Geometry.c +++ b/src/libImaging/Geometry.c @@ -17,7 +17,7 @@ Imaging ImagingFlipLeftRight(Imaging imOut, Imaging imIn) { ImagingSectionCookie cookie; - // int x, y, xr; + int x, y, xr; if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) { return (Imaging)ImagingError_ModeError(); @@ -29,12 +29,11 @@ ImagingFlipLeftRight(Imaging imOut, Imaging imIn) { ImagingCopyPalette(imOut, imIn); ImagingSectionEnter(&cookie); - for (int y = 0; y < imIn->ysize; ++y) { + for (y = 0; y < imIn->ysize; ++y) { char *in = imIn->image[y]; char *out = imOut->image[y]; - int xr = imIn->linesize - imIn->pixelsize; - for (int x = 0; x < imIn->linesize; - x += imIn->pixelsize, xr -= imIn->pixelsize) { + xr = imIn->linesize - imIn->pixelsize; + for (x = 0; x < imIn->linesize; x += imIn->pixelsize, xr -= imIn->pixelsize) { memcpy(out + xr, in + x, imIn->pixelsize); } } From df98223fb5a3a000be7c28b9d688afbaca2d8376 Mon Sep 17 00:00:00 2001 From: Junxiao Shi Date: Sat, 22 Jun 2024 13:41:57 +0000 Subject: [PATCH 18/23] transpose() with multi-band format --- Tests/test_file_tiff.py | 25 ++-- src/libImaging/Geometry.c | 286 ++++++++++++++++---------------------- 2 files changed, 137 insertions(+), 174 deletions(-) diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index d562b6fd09b..5fd8a6f6c3f 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -903,14 +903,23 @@ def check_image( im.load() check_image(im, 10, 10, pixel) - im1 = im.copy() - check_image(im1, 10, 10, pixel) - - im2 = im.crop((2, 2, 7, 7)) - check_image(im2, 5, 5, pixel) - - im3 = im.transpose(Image.Transpose.FLIP_LEFT_RIGHT) - check_image(im3, 10, 10, pixel) + copy = im.copy() + check_image(copy, 10, 10, pixel) + + cropped = im.crop((2, 2, 8, 7)) + check_image(cropped, 6, 5, pixel) + + for method, [w, h] in { + 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") diff --git a/src/libImaging/Geometry.c b/src/libImaging/Geometry.c index a74fba7cfd0..1cb64c63349 100644 --- a/src/libImaging/Geometry.c +++ b/src/libImaging/Geometry.c @@ -19,7 +19,8 @@ ImagingFlipLeftRight(Imaging imOut, Imaging imIn) { ImagingSectionCookie cookie; 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(); } if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize) { @@ -47,7 +48,8 @@ ImagingFlipTopBottom(Imaging imOut, Imaging imIn) { ImagingSectionCookie cookie; 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(); } 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 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(); } if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) { @@ -83,48 +86,38 @@ ImagingRotate90(Imaging imOut, Imaging 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); - if (imIn->image8) { - if (strncmp(imIn->mode, "I;16", 4) == 0) { - ROTATE_90(UINT16, image8); - } else { - ROTATE_90(UINT8, image8); + 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++) { + 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); -#undef ROTATE_90 - return imOut; } @@ -134,7 +127,8 @@ ImagingTranspose(Imaging imOut, Imaging imIn) { int x, y, xx, yy, xxsize, yysize; 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(); } if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) { @@ -143,47 +137,37 @@ ImagingTranspose(Imaging imOut, Imaging 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); - if (imIn->image8) { - if (strncmp(imIn->mode, "I;16", 4) == 0) { - TRANSPOSE(UINT16, image8); - } else { - TRANSPOSE(UINT8, image8); + 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++) { + 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); -#undef TRANSPOSE - return imOut; } @@ -193,7 +177,8 @@ ImagingTransverse(Imaging imOut, Imaging imIn) { int x, y, xr, yr, xx, yy, xxsize, yysize; 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(); } if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) { @@ -202,49 +187,39 @@ ImagingTransverse(Imaging imOut, Imaging 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); - if (imIn->image8) { - if (strncmp(imIn->mode, "I;16", 4) == 0) { - TRANSVERSE(UINT16, image8); - } else { - TRANSVERSE(UINT8, image8); + 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--) { + 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); -#undef TRANSVERSE - return imOut; } @@ -253,7 +228,8 @@ ImagingRotate180(Imaging imOut, Imaging imIn) { ImagingSectionCookie cookie; 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(); } if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize) { @@ -262,33 +238,20 @@ ImagingRotate180(Imaging imOut, Imaging 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); yr = imIn->ysize - 1; - if (imIn->image8) { - if (strncmp(imIn->mode, "I;16", 4) == 0) { - ROTATE_180(UINT16, image8) - } else { - ROTATE_180(UINT8, image8) + for (y = 0; y < imIn->ysize; y++, yr--) { + char *in = imIn->image[y]; + char *out = imOut->image[yr]; + xr = imIn->linesize - imIn->pixelsize; + 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); -#undef ROTATE_180 - return imOut; } @@ -298,7 +261,8 @@ ImagingRotate270(Imaging imOut, Imaging imIn) { int x, y, xx, yy, yr, xxsize, yysize; 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(); } if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) { @@ -307,48 +271,38 @@ ImagingRotate270(Imaging imOut, Imaging 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); - if (imIn->image8) { - if (strncmp(imIn->mode, "I;16", 4) == 0) { - ROTATE_270(UINT16, image8); - } else { - ROTATE_270(UINT8, image8); + 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--) { + 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); -#undef ROTATE_270 - return imOut; } From 3cf311bc6c36c4701a96a38816fe93782e7b1ebb Mon Sep 17 00:00:00 2001 From: Junxiao Shi Date: Wed, 10 Jul 2024 22:13:31 +0000 Subject: [PATCH 19/23] fix mypy warning in test_open_tiff_uint16_multiband() --- Tests/test_file_tiff.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index ef0e846b7d3..f7793a35c15 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -898,9 +898,11 @@ def test_open_tiff_uint16_multiband(self) -> None: def check_pixel( im: Image.Image, expected_pixel: tuple[int, ...], pos: tuple[int, int] ) -> None: - actual_pixel = im.getpixel((0, 0)) - if isinstance(actual_pixel, int): - actual_pixel = (actual_pixel,) + actual_pixel = im.getpixel(pos) + if actual_pixel is None: + actual_pixel = (-1,) + elif not isinstance(actual_pixel, tuple): + actual_pixel = (int(actual_pixel),) assert actual_pixel == expected_pixel def check_image( From d5053fb50ecdee8c5e88e6747a12a7040c64d002 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 19 Jul 2024 12:29:15 +0000 Subject: [PATCH 20/23] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/_imaging.c | 21 +++++++++++++-------- src/libImaging/Crop.c | 3 ++- src/libImaging/Geometry.c | 12 ++++++++---- src/libImaging/Imaging.h | 3 ++- src/libImaging/RankFilter.c | 3 ++- src/libImaging/Reduce.c | 4 ++-- src/libImaging/Resample.c | 3 ++- src/libImaging/Storage.c | 12 +++++------- src/map.c | 3 ++- 9 files changed, 38 insertions(+), 26 deletions(-) diff --git a/src/_imaging.c b/src/_imaging.c index 46304b9e80a..1f8ca0c2702 100644 --- a/src/_imaging.c +++ b/src/_imaging.c @@ -730,8 +730,8 @@ _new(PyObject *self, PyObject *args) { return NULL; } - return PyImagingNew( - ImagingNew(mode, (ImagingNewParams){xsize, ysize, depth, bands})); + return PyImagingNew(ImagingNew(mode, (ImagingNewParams){xsize, ysize, depth, bands}) + ); } static PyObject * @@ -953,7 +953,8 @@ _color_lut_3d(ImagingObject *self, PyObject *args) { } imOut = ImagingNewDirty( - mode, (ImagingNewParams){self->image->xsize, self->image->ysize}); + mode, (ImagingNewParams){self->image->xsize, self->image->ysize} + ); if (!imOut) { free(prepared_table); return NULL; @@ -1765,8 +1766,9 @@ _quantize(ImagingObject *self, PyObject *args) { if (!self->image->xsize || !self->image->ysize) { /* no content; return an empty image */ - return PyImagingNew(ImagingNew( - "P", (ImagingNewParams){self->image->xsize, self->image->ysize})); + return PyImagingNew( + ImagingNew("P", (ImagingNewParams){self->image->xsize, self->image->ysize}) + ); } return PyImagingNew(ImagingQuantize(self->image, colours, method, kmeans)); @@ -2159,7 +2161,8 @@ _transpose(ImagingObject *self, PyObject *args) { case 3: /* rotate 180 */ imOut = ImagingNewDirty( imIn->mode, - (ImagingNewParams){imIn->xsize, imIn->ysize, imIn->depth, imIn->bands}); + (ImagingNewParams){imIn->xsize, imIn->ysize, imIn->depth, imIn->bands} + ); break; case 2: /* rotate 90 */ case 4: /* rotate 270 */ @@ -2167,7 +2170,8 @@ _transpose(ImagingObject *self, PyObject *args) { case 6: /* transverse */ imOut = ImagingNewDirty( imIn->mode, - (ImagingNewParams){imIn->ysize, imIn->xsize, imIn->depth, imIn->bands}); + (ImagingNewParams){imIn->ysize, imIn->xsize, imIn->depth, imIn->bands} + ); break; default: PyErr_SetString(PyExc_ValueError, "No such transpose operation"); @@ -2848,7 +2852,8 @@ _font_getmask(ImagingFontObject *self, PyObject *args) { } im = ImagingNew( - self->bitmap->mode, (ImagingNewParams){textwidth(self, text), self->ysize}); + self->bitmap->mode, (ImagingNewParams){textwidth(self, text), self->ysize} + ); if (!im) { free(text); return ImagingError_MemoryError(); diff --git a/src/libImaging/Crop.c b/src/libImaging/Crop.c index 52f9b0a431f..60d10c99b83 100644 --- a/src/libImaging/Crop.c +++ b/src/libImaging/Crop.c @@ -38,7 +38,8 @@ ImagingCrop(Imaging imIn, int sx0, int sy0, int sx1, int sy1) { } imOut = ImagingNewDirty( - imIn->mode, (ImagingNewParams){xsize, ysize, imIn->depth, imIn->bands}); + imIn->mode, (ImagingNewParams){xsize, ysize, imIn->depth, imIn->bands} + ); if (!imOut) { return NULL; } diff --git a/src/libImaging/Geometry.c b/src/libImaging/Geometry.c index 979576a7b7b..f719869ed91 100644 --- a/src/libImaging/Geometry.c +++ b/src/libImaging/Geometry.c @@ -108,7 +108,8 @@ ImagingRotate90(Imaging imOut, Imaging imIn) { memcpy( out + yyy * imIn->pixelsize, in + xxx * imIn->pixelsize, - imIn->pixelsize); + imIn->pixelsize + ); } } } @@ -158,7 +159,8 @@ ImagingTranspose(Imaging imOut, Imaging imIn) { memcpy( out + yyy * imIn->pixelsize, in + xxx * imIn->pixelsize, - imIn->pixelsize); + imIn->pixelsize + ); } } } @@ -210,7 +212,8 @@ ImagingTransverse(Imaging imOut, Imaging imIn) { memcpy( out + yr * imIn->pixelsize, in + xxx * imIn->pixelsize, - imIn->pixelsize); + imIn->pixelsize + ); } } } @@ -293,7 +296,8 @@ ImagingRotate270(Imaging imOut, Imaging imIn) { memcpy( out + yr * imIn->pixelsize, in + xxx * imIn->pixelsize, - imIn->pixelsize); + imIn->pixelsize + ); } } } diff --git a/src/libImaging/Imaging.h b/src/libImaging/Imaging.h index c2e3bb25049..5f412fef931 100644 --- a/src/libImaging/Imaging.h +++ b/src/libImaging/Imaging.h @@ -705,7 +705,8 @@ struct ImagingCodecStateInstance { int xsize, ysize, xoff, yoff; ImagingShuffler shuffle; void (*mb_shuffle)( - UINT8 *dst, const UINT8 *src, Imaging im, ImagingCodecState state); + UINT8 *dst, const UINT8 *src, Imaging im, ImagingCodecState state + ); int bits, bytes; UINT8 *buffer; void *context; diff --git a/src/libImaging/RankFilter.c b/src/libImaging/RankFilter.c index d09b5cc6d10..8aac66b420b 100644 --- a/src/libImaging/RankFilter.c +++ b/src/libImaging/RankFilter.c @@ -85,7 +85,8 @@ MakeRankFunction(UINT8) MakeRankFunction(INT32) MakeRankFunction(FLOAT32) } imOut = ImagingNew( - im->mode, (ImagingNewParams){im->xsize - 2 * margin, im->ysize - 2 * margin}); + im->mode, (ImagingNewParams){im->xsize - 2 * margin, im->ysize - 2 * margin} + ); if (!imOut) { return NULL; } diff --git a/src/libImaging/Reduce.c b/src/libImaging/Reduce.c index 60c87ea900c..bb8ddb92c56 100644 --- a/src/libImaging/Reduce.c +++ b/src/libImaging/Reduce.c @@ -1462,8 +1462,8 @@ ImagingReduce(Imaging imIn, int xscale, int yscale, int box[4]) { imOut = ImagingNewDirty( imIn->mode, - (ImagingNewParams){ - (box[2] + xscale - 1) / xscale, (box[3] + yscale - 1) / yscale} + (ImagingNewParams + ){(box[2] + xscale - 1) / xscale, (box[3] + yscale - 1) / yscale} ); if (!imOut) { return NULL; diff --git a/src/libImaging/Resample.c b/src/libImaging/Resample.c index d4fcdad07b1..3b1e70a6c63 100644 --- a/src/libImaging/Resample.c +++ b/src/libImaging/Resample.c @@ -671,7 +671,8 @@ ImagingResampleInner( } imTemp = ImagingNewDirty( - imIn->mode, (ImagingNewParams){xsize, ybox_last - ybox_first}); + imIn->mode, (ImagingNewParams){xsize, ybox_last - ybox_first} + ); if (imTemp) { ResampleHorizontal( imTemp, imIn, ybox_first, ksize_horiz, bounds_horiz, kk_horiz diff --git a/src/libImaging/Storage.c b/src/libImaging/Storage.c index d74d8a0c1bb..3c2f53f2e58 100644 --- a/src/libImaging/Storage.c +++ b/src/libImaging/Storage.c @@ -191,8 +191,8 @@ ImagingNewPrologueSubtype(const char *mode, ImagingNewParams p, int size) { } else if (strcmp(mode, IMAGING_MODE_MB) == 0) { if (p.bands <= 0 || p.depth <= 0) { - return (Imaging)ImagingError_ValueError( - "multi-band missing bands and depth"); + return (Imaging)ImagingError_ValueError("multi-band missing bands and depth" + ); } im->bands = p.bands; im->depth = p.depth; @@ -236,9 +236,7 @@ ImagingNewPrologueSubtype(const char *mode, ImagingNewParams p, int size) { Imaging ImagingNewPrologue(const char *mode, ImagingNewParams p) { - return ImagingNewPrologueSubtype( - mode, p, sizeof(struct ImagingMemoryInstance) - ); + return ImagingNewPrologueSubtype(mode, p, sizeof(struct ImagingMemoryInstance)); } void @@ -570,8 +568,8 @@ ImagingNew2Dirty(const char *mode, Imaging imOut, Imaging imIn) { } else { /* create new image */ imOut = ImagingNewDirty( - mode, - (ImagingNewParams){imIn->xsize, imIn->ysize, imIn->depth, imIn->bands}); + mode, (ImagingNewParams){imIn->xsize, imIn->ysize, imIn->depth, imIn->bands} + ); if (!imOut) { return NULL; } diff --git a/src/map.c b/src/map.c index c44b19dc092..f3a3ab85d59 100644 --- a/src/map.c +++ b/src/map.c @@ -128,7 +128,8 @@ PyImaging_MapBuffer(PyObject *self, PyObject *args) { im = ImagingNewPrologueSubtype( mode, (ImagingNewParams){xsize, ysize, depth, bands}, - sizeof(ImagingBufferInstance)); + sizeof(ImagingBufferInstance) + ); if (!im) { PyBuffer_Release(&view); return NULL; From 282e7ec8c0838e26b96e5e0ff256e8bd81e0b69a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 14 Oct 2024 11:30:36 +0000 Subject: [PATCH 21/23] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/libImaging/Reduce.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libImaging/Reduce.c b/src/libImaging/Reduce.c index bb8ddb92c56..563a8288ba5 100644 --- a/src/libImaging/Reduce.c +++ b/src/libImaging/Reduce.c @@ -1462,8 +1462,8 @@ ImagingReduce(Imaging imIn, int xscale, int yscale, int box[4]) { imOut = ImagingNewDirty( imIn->mode, - (ImagingNewParams - ){(box[2] + xscale - 1) / xscale, (box[3] + yscale - 1) / yscale} + (ImagingNewParams){(box[2] + xscale - 1) / xscale, + (box[3] + yscale - 1) / yscale} ); if (!imOut) { return NULL; From 605c4083e13994164192f8fad66b4bb9f370325e Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 14 Oct 2024 22:33:03 +1100 Subject: [PATCH 22/23] Added type hint --- src/PIL/ImageFile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PIL/ImageFile.py b/src/PIL/ImageFile.py index db31f45b949..ff899559500 100644 --- a/src/PIL/ImageFile.py +++ b/src/PIL/ImageFile.py @@ -124,7 +124,7 @@ def __init__( self.readonly = 1 # until we know better - self.mb_config = () + self.mb_config: tuple[int, ...] = () self.decoderconfig: tuple[Any, ...] = () self.decodermaxblock = MAXBLOCK From e79b88ea5ff3729ce8ce62d87833a9245a289c44 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 14 Oct 2024 22:35:25 +1100 Subject: [PATCH 23/23] Use mb_config when creating core images --- src/PIL/TiffImagePlugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index 20e06adeba1..ffe8fadb445 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -1326,7 +1326,7 @@ def load(self) -> Image.core.PixelAccess | None: def load_prepare(self) -> None: if self._im is None: Image._decompression_bomb_check(self._tile_size) - self.im = Image.core.new(self.mode, self._tile_size) + self.im = Image.core.new(self.mode, self._tile_size, *self.mb_config) ImageFile.ImageFile.load_prepare(self) def load_end(self) -> None: