mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-04-09 20:04:14 +03:00
Merge e79b88ea5f
into 7d50816f0a
This commit is contained in:
commit
101060bc55
Tests
src
BIN
Tests/images/uint16_2_4660.tif
Normal file
BIN
Tests/images/uint16_2_4660.tif
Normal file
Binary file not shown.
BIN
Tests/images/uint16_3_4660.tif
Normal file
BIN
Tests/images/uint16_3_4660.tif
Normal file
Binary file not shown.
BIN
Tests/images/uint16_4_4660.tif
Normal file
BIN
Tests/images/uint16_4_4660.tif
Normal file
Binary file not shown.
BIN
Tests/images/uint16_5_4660.tif
Normal file
BIN
Tests/images/uint16_5_4660.tif
Normal file
Binary file not shown.
|
@ -1008,6 +1008,55 @@ class TestFileTiff:
|
|||
with Image.open(test_file):
|
||||
pass
|
||||
|
||||
def test_open_tiff_uint16_multiband(self) -> None:
|
||||
"""Test opening multiband TIFFs and reading all channels."""
|
||||
|
||||
def check_pixel(
|
||||
im: Image.Image, expected_pixel: tuple[int, ...], pos: tuple[int, int]
|
||||
) -> None:
|
||||
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(
|
||||
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):
|
||||
for y in range(im.height):
|
||||
check_pixel(im, expected_pixel, (x, y))
|
||||
|
||||
base_value = 4660
|
||||
for i in range(1, 6):
|
||||
pixel = tuple(base_value + j for j in range(i))
|
||||
infile = f"Tests/images/uint16_{i}_{base_value}.tif"
|
||||
im = Image.open(infile)
|
||||
|
||||
im.load()
|
||||
check_image(im, 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")
|
||||
class TestFileTiffW32:
|
||||
|
|
|
@ -127,6 +127,8 @@ class ImageFile(Image.Image):
|
|||
|
||||
self.readonly = 1 # until we know better
|
||||
|
||||
self.mb_config: tuple[int, ...] = ()
|
||||
|
||||
self.decoderconfig: tuple[Any, ...] = ()
|
||||
self.decodermaxblock = MAXBLOCK
|
||||
|
||||
|
@ -317,7 +319,7 @@ class ImageFile(Image.Image):
|
|||
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.mb_config
|
||||
)
|
||||
readonly = 1
|
||||
# After trashing self.im,
|
||||
|
@ -408,7 +410,7 @@ class ImageFile(Image.Image):
|
|||
def load_prepare(self) -> None:
|
||||
# create image memory if necessary
|
||||
if self._im is None:
|
||||
self.im = Image.core.new(self.mode, self.size)
|
||||
self.im = Image.core.new(self.mode, self.size, *self.mb_config)
|
||||
# create palette (optional)
|
||||
if self.mode == "P":
|
||||
Image.Image.load(self)
|
||||
|
|
|
@ -187,6 +187,43 @@ OPEN_INFO = {
|
|||
(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,)): ("MB", "MB"),
|
||||
(
|
||||
II,
|
||||
1,
|
||||
(1, 1, 1),
|
||||
1,
|
||||
(16, 16, 16),
|
||||
(
|
||||
0,
|
||||
0,
|
||||
),
|
||||
): ("MB", "MB"),
|
||||
(
|
||||
II,
|
||||
1,
|
||||
(1, 1, 1, 1),
|
||||
1,
|
||||
(16, 16, 16, 16),
|
||||
(
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
),
|
||||
): ("MB", "MB"),
|
||||
(
|
||||
II,
|
||||
1,
|
||||
(1, 1, 1, 1, 1),
|
||||
1,
|
||||
(16, 16, 16, 16, 16),
|
||||
(
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
),
|
||||
): ("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"),
|
||||
|
@ -201,7 +238,9 @@ OPEN_INFO = {
|
|||
(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
|
||||
|
@ -214,11 +253,13 @@ OPEN_INFO = {
|
|||
(MM, 2, (1,), 1, (8, 8, 8, 8, 8, 8), (0, 0, 0)): ("RGB", "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"),
|
||||
|
@ -227,13 +268,16 @@ OPEN_INFO = {
|
|||
(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,)): ("RGB", "RGBX;16L"),
|
||||
(MM, 2, (1,), 1, (16, 16, 16, 16), (0,)): ("RGB", "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"),
|
||||
|
@ -268,9 +312,11 @@ OPEN_INFO = {
|
|||
# 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)
|
||||
|
@ -1301,7 +1347,7 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
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:
|
||||
|
@ -1465,14 +1511,6 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
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,)
|
||||
|
||||
bps_tuple = self.tag_v2.get(BITSPERSAMPLE, (1,))
|
||||
extra_tuple = self.tag_v2.get(EXTRASAMPLES, ())
|
||||
if photo in (2, 6, 8): # RGB, YCbCr, LAB
|
||||
|
@ -1528,6 +1566,9 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
|
||||
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.mb_config = (max(bps_tuple), samples_per_pixel)
|
||||
|
||||
self.info["compression"] = self._compression
|
||||
|
||||
|
|
|
@ -297,7 +297,7 @@ getbands(const char *mode) {
|
|||
int bands;
|
||||
|
||||
/* FIXME: add primitive to libImaging to avoid extra allocation */
|
||||
im = ImagingNew(mode, 0, 0);
|
||||
im = ImagingNew(mode, (ImagingNewParams){0, 0});
|
||||
if (!im) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -421,6 +421,36 @@ float16tofloat32(const FLOAT16 in) {
|
|||
return out[0];
|
||||
}
|
||||
|
||||
static inline PyObject *
|
||||
getpixel_mb(Imaging im, ImagingAccess access, int x, int y) {
|
||||
UINT8 pixel[sizeof(INT32) * 6];
|
||||
assert(im->pixelsize <= sizeof(pixel));
|
||||
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 {
|
||||
|
@ -442,6 +472,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) {
|
||||
|
@ -655,7 +689,7 @@ _fill(PyObject *self, PyObject *args) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
im = ImagingNewDirty(mode, xsize, ysize);
|
||||
im = ImagingNewDirty(mode, (ImagingNewParams){xsize, ysize});
|
||||
if (!im) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -676,13 +710,14 @@ _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, (ImagingNewParams){xsize, ysize, depth, bands})
|
||||
);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
@ -903,7 +938,9 @@ _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;
|
||||
|
@ -1084,7 +1121,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;
|
||||
}
|
||||
|
@ -1697,7 +1734,9 @@ _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", (ImagingNewParams){self->image->xsize, self->image->ysize})
|
||||
);
|
||||
}
|
||||
|
||||
return PyImagingNew(ImagingQuantize(self->image, colours, method, kmeans));
|
||||
|
@ -1899,7 +1938,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
|
||||
|
@ -2079,13 +2118,19 @@ _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, imIn->depth, imIn->bands}
|
||||
);
|
||||
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, imIn->depth, imIn->bands}
|
||||
);
|
||||
break;
|
||||
default:
|
||||
PyErr_SetString(PyExc_ValueError, "No such transpose operation");
|
||||
|
@ -2133,7 +2178,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;
|
||||
}
|
||||
|
@ -2157,7 +2202,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;
|
||||
}
|
||||
|
@ -2754,7 +2799,9 @@ _font_getmask(ImagingFontObject *self, PyObject *args) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
im = ImagingNew(self->bitmap->mode, textwidth(self, text), self->ysize);
|
||||
im = ImagingNew(
|
||||
self->bitmap->mode, (ImagingNewParams){textwidth(self, text), self->ysize}
|
||||
);
|
||||
if (!im) {
|
||||
free(text);
|
||||
return ImagingError_MemoryError();
|
||||
|
|
51
src/decode.c
51
src/decode.c
|
@ -265,11 +265,59 @@ 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) {
|
||||
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
|
||||
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);
|
||||
|
@ -278,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;
|
||||
|
|
|
@ -134,6 +134,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
|
||||
|
@ -184,6 +189,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, const void *color) {
|
||||
memcpy(&im->image[y][x * im->pixelsize], color, im->pixelsize);
|
||||
}
|
||||
|
||||
void
|
||||
ImagingAccessInit(void) {
|
||||
#define ADD(mode_, get_pixel_, put_pixel_) \
|
||||
|
@ -223,6 +233,7 @@ ImagingAccessInit(void) {
|
|||
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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -276,7 +276,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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -37,7 +37,9 @@ 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, imIn->depth, imIn->bands}
|
||||
);
|
||||
if (!imOut) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -61,7 +61,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;
|
||||
|
@ -473,7 +474,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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
@ -28,32 +29,17 @@ 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 (y = 0; y < imIn->ysize; ++y) {
|
||||
char *in = imIn->image[y];
|
||||
char *out = imOut->image[y];
|
||||
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 {
|
||||
FLIP_LEFT_RIGHT(INT32, image32)
|
||||
}
|
||||
|
||||
ImagingSectionLeave(&cookie);
|
||||
|
||||
#undef FLIP_LEFT_RIGHT
|
||||
|
||||
return imOut;
|
||||
}
|
||||
|
||||
|
@ -62,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) {
|
||||
|
@ -89,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) {
|
||||
|
@ -98,48 +86,39 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -149,7 +128,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) {
|
||||
|
@ -158,47 +138,38 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -208,7 +179,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) {
|
||||
|
@ -217,49 +189,40 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -268,7 +231,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) {
|
||||
|
@ -277,33 +241,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;
|
||||
}
|
||||
|
||||
|
@ -313,7 +264,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) {
|
||||
|
@ -322,48 +274,39 @@ 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
@ -68,10 +78,21 @@ 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 */
|
||||
|
||||
/* Parameters of various ImagingNew* functions. */
|
||||
typedef struct {
|
||||
int xsize;
|
||||
int ysize;
|
||||
int depth; /** MB mode only. */
|
||||
int bands; /** MB mode only. */
|
||||
} ImagingNewParams;
|
||||
|
||||
typedef struct {
|
||||
char *ptr;
|
||||
int size;
|
||||
|
@ -80,9 +101,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;
|
||||
|
@ -176,9 +197,9 @@ extern void
|
|||
ImagingMemoryClearCache(ImagingMemoryArena arena, int new_size);
|
||||
|
||||
extern Imaging
|
||||
ImagingNew(const char *mode, int xsize, int ysize);
|
||||
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,9 +209,9 @@ extern Imaging
|
|||
ImagingNewBlock(const char *mode, int xsize, int ysize);
|
||||
|
||||
extern Imaging
|
||||
ImagingNewPrologue(const char *mode, int xsize, int ysize);
|
||||
ImagingNewPrologue(const char *mode, ImagingNewParams p);
|
||||
extern Imaging
|
||||
ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int structure_size);
|
||||
ImagingNewPrologueSubtype(const char *mode, ImagingNewParams p, int structure_size);
|
||||
|
||||
extern void
|
||||
ImagingCopyPalette(Imaging destination, Imaging source);
|
||||
|
@ -684,6 +705,9 @@ 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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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, (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);
|
||||
imOut = ImagingNew(imIn->mode, (ImagingNewParams){imIn->xsize, imIn->ysize});
|
||||
if (!imOut) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -1830,7 +1830,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++) {
|
||||
|
|
|
@ -84,7 +84,9 @@ 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, (ImagingNewParams){im->xsize - 2 * margin, im->ysize - 2 * margin}
|
||||
);
|
||||
if (!imOut) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1461,7 +1461,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;
|
||||
|
|
|
@ -752,7 +752,9 @@ 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
|
||||
|
@ -774,7 +776,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);
|
||||
|
|
|
@ -42,11 +42,11 @@
|
|||
*/
|
||||
|
||||
Imaging
|
||||
ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, 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();
|
||||
}
|
||||
|
||||
|
@ -56,58 +56,58 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) {
|
|||
}
|
||||
|
||||
/* 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 (strcmp(mode, "I;16") == 0 || strcmp(mode, "I;16L") == 0 ||
|
||||
|
@ -116,21 +116,21 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) {
|
|||
/* 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) {
|
||||
|
@ -138,7 +138,7 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) {
|
|||
/* 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) {
|
||||
|
@ -146,48 +146,59 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) {
|
|||
/* 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 (p.bands <= 0 || p.depth <= 0) {
|
||||
return (Imaging)ImagingError_ValueError("multi-band missing bands and depth"
|
||||
);
|
||||
}
|
||||
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 {
|
||||
free(im);
|
||||
|
@ -199,7 +210,7 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) {
|
|||
|
||||
/* 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);
|
||||
|
@ -226,10 +237,8 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) {
|
|||
}
|
||||
|
||||
Imaging
|
||||
ImagingNewPrologue(const char *mode, int xsize, int ysize) {
|
||||
return ImagingNewPrologueSubtype(
|
||||
mode, xsize, ysize, sizeof(struct ImagingMemoryInstance)
|
||||
);
|
||||
ImagingNewPrologue(const char *mode, ImagingNewParams p) {
|
||||
return ImagingNewPrologueSubtype(mode, p, sizeof(struct ImagingMemoryInstance));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -491,15 +500,15 @@ 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, 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);
|
||||
im = ImagingNewPrologue(mode, p);
|
||||
if (!im) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -528,13 +537,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, ImagingNewParams p) {
|
||||
return ImagingNewInternal(mode, p, 0);
|
||||
}
|
||||
|
||||
Imaging
|
||||
ImagingNewDirty(const char *mode, int xsize, int ysize) {
|
||||
return ImagingNewInternal(mode, xsize, ysize, 1);
|
||||
ImagingNewDirty(const char *mode, ImagingNewParams p) {
|
||||
return ImagingNewInternal(mode, p, 1);
|
||||
}
|
||||
|
||||
Imaging
|
||||
|
@ -545,7 +554,7 @@ ImagingNewBlock(const char *mode, int xsize, int ysize) {
|
|||
return (Imaging)ImagingError_ValueError("bad image size");
|
||||
}
|
||||
|
||||
im = ImagingNewPrologue(mode, xsize, ysize);
|
||||
im = ImagingNewPrologue(mode, (ImagingNewParams){xsize, ysize});
|
||||
if (!im) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -565,12 +574,16 @@ 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 ||
|
||||
(strcmp(mode, IMAGING_MODE_MB) == 0 &&
|
||||
(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;
|
||||
}
|
||||
|
|
19
src/map.c
19
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;
|
||||
}
|
||||
|
@ -83,10 +86,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,11 @@ PyImaging_MapBuffer(PyObject *self, PyObject *args) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
im = ImagingNewPrologueSubtype(mode, xsize, ysize, sizeof(ImagingBufferInstance));
|
||||
im = ImagingNewPrologueSubtype(
|
||||
mode,
|
||||
(ImagingNewParams){xsize, ysize, depth, bands},
|
||||
sizeof(ImagingBufferInstance)
|
||||
);
|
||||
if (!im) {
|
||||
PyBuffer_Release(&view);
|
||||
return NULL;
|
||||
|
|
Loading…
Reference in New Issue
Block a user