Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/PIL/ImageTk.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,7 @@ def paste(self, im: Image.Image) -> None:
ptr = im.getim()
image = im.im
if not image.isblock() or im.mode != self.__mode:
block = Image.core.new_block(self.__mode, im.size)
image.convert_into(block) # convert directly between buffers
block = image.convert_block(self.__mode) # contiguous, for Tk
ptr = block.ptr

_pyimagingtkcall("PyImagingPhoto", self.__photo, ptr)
Expand Down
35 changes: 6 additions & 29 deletions src/_imaging.c
Original file line number Diff line number Diff line change
Expand Up @@ -761,20 +761,6 @@ _new(PyObject *self, PyObject *args) {
return PyImagingNew(ImagingNew(mode, xsize, ysize));
}

static PyObject *
_new_block(PyObject *self, PyObject *args) {
char *mode_name;
int xsize, ysize;

if (!PyArg_ParseTuple(args, "s(ii)", &mode_name, &xsize, &ysize)) {
return NULL;
}

const ModeID mode = findModeID(mode_name);

return PyImagingNew(ImagingNewBlock(mode, xsize, ysize));
}

static PyObject *
_linear_gradient(PyObject *self, PyObject *args) {
char *mode_name;
Expand Down Expand Up @@ -1038,26 +1024,18 @@ _convert(ImagingObject *self, PyObject *args) {
const ModeID mode = findModeID(mode_name);

return PyImagingNew(ImagingConvert(
NULL,
self->image,
mode,
paletteimage ? paletteimage->image->palette : NULL,
dither
self->image, mode, paletteimage ? paletteimage->image->palette : NULL, dither
));
}

static PyObject *
_convert_into(ImagingObject *self, PyObject *args) {
ImagingObject *imagep;
if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) {
return NULL;
}

if (!ImagingConvert(imagep->image, self->image, imagep->image->mode, NULL, 0)) {
_convert_block(ImagingObject *self, PyObject *args) {
char *mode_name;
if (!PyArg_ParseTuple(args, "s", &mode_name)) {
return NULL;
}

Py_RETURN_NONE;
return PyImagingNew(ImagingConvertBlock(self->image, findModeID(mode_name)));
}

static PyObject *
Expand Down Expand Up @@ -3731,7 +3709,7 @@ static struct PyMethodDef methods[] = {
/* Standard processing methods (Image) */
{"color_lut_3d", (PyCFunction)_color_lut_3d, METH_VARARGS},
{"convert", (PyCFunction)_convert, METH_VARARGS},
{"convert_into", (PyCFunction)_convert_into, METH_VARARGS},
{"convert_block", (PyCFunction)_convert_block, METH_VARARGS},
{"convert_matrix", (PyCFunction)_convert_matrix, METH_VARARGS},
{"convert_transparent", (PyCFunction)_convert_transparent, METH_VARARGS},
{"copy", (PyCFunction)_copy, METH_VARARGS},
Expand Down Expand Up @@ -4240,7 +4218,6 @@ static PyMethodDef functions[] = {
{"blend", (PyCFunction)_blend, METH_VARARGS},
{"fill", (PyCFunction)_fill, METH_VARARGS},
{"new", (PyCFunction)_new, METH_VARARGS},
{"new_block", (PyCFunction)_new_block, METH_VARARGS},
{"new_arrow", (PyCFunction)_new_arrow, METH_VARARGS},
{"merge", (PyCFunction)_merge, METH_VARARGS},

Expand Down
4 changes: 2 additions & 2 deletions src/libImaging/Bands.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ ImagingPutBand(Imaging imOut, Imaging imIn, int band) {

/* Shortcuts */
if (imOut->bands == 1) {
return ImagingCopy2(imOut, imIn);
return ImagingCopyInto(imOut, imIn);
}

/* Special case for LXXA etc */
Expand Down Expand Up @@ -320,7 +320,7 @@ ImagingMerge(const ModeID mode, Imaging bands[4]) {
}

if (bandsCount == 1) {
return ImagingCopy2(imOut, firstBand);
return ImagingCopyInto(imOut, firstBand);
}

// restrict safe: the input bands are read-only and imOut is a fresh
Expand Down
2 changes: 1 addition & 1 deletion src/libImaging/BoxBlur.c
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ ImagingBoxBlur(Imaging imOut, Imaging imIn, float xradius, float yradius, int n)
ImagingDelete(imTransposed);
}
if (xradius == 0 && yradius == 0) {
if (!ImagingCopy2(imOut, imIn)) {
if (!ImagingCopyInto(imOut, imIn)) {
return NULL;
}
}
Expand Down
93 changes: 62 additions & 31 deletions src/libImaging/Convert.c
Original file line number Diff line number Diff line change
Expand Up @@ -1062,8 +1062,10 @@ pa2ycbcr(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
ImagingConvertRGB2YCbCr(out, out, xsize);
}

typedef Imaging (*ImagingAllocator)(ModeID mode, int xsize, int ysize);

static Imaging
frompalette(Imaging imOut, Imaging imIn, const ModeID mode) {
frompalette(Imaging imIn, const ModeID mode, ImagingAllocator new_image) {
ImagingSectionCookie cookie;
int alpha;
int y;
Expand Down Expand Up @@ -1105,7 +1107,7 @@ frompalette(Imaging imOut, Imaging imIn, const ModeID mode) {
return (Imaging)ImagingError_ValueError("conversion not supported");
}

imOut = ImagingNew2Dirty(mode, imOut, imIn);
Imaging imOut = new_image(mode, imIn->xsize, imIn->ysize);
if (!imOut) {
return NULL;
}
Expand Down Expand Up @@ -1133,7 +1135,11 @@ frompalette(Imaging imOut, Imaging imIn, const ModeID mode) {
#endif
static Imaging
topalette(
Imaging imOut, Imaging imIn, const ModeID mode, ImagingPalette inpalette, int dither
Imaging imIn,
const ModeID mode,
ImagingPalette inpalette,
int dither,
ImagingAllocator new_image
) {
ImagingSectionCookie cookie;
int alpha;
Expand Down Expand Up @@ -1169,7 +1175,7 @@ topalette(
return (Imaging)ImagingError_ValueError("no palette");
}

imOut = ImagingNew2Dirty(mode, imOut, imIn);
Imaging imOut = new_image(mode, imIn->xsize, imIn->ysize);
if (!imOut) {
if (palette != inpalette) {
ImagingPaletteDelete(palette);
Expand Down Expand Up @@ -1333,7 +1339,7 @@ topalette(
}

static Imaging
tobilevel(Imaging imOut, Imaging imIn) {
tobilevel(Imaging imIn, ImagingAllocator new_image) {
ImagingSectionCookie cookie;
int x, y;
int *errors;
Expand All @@ -1343,7 +1349,7 @@ tobilevel(Imaging imOut, Imaging imIn) {
return (Imaging)ImagingError_ValueError("conversion not supported");
}

imOut = ImagingNew2Dirty(IMAGING_MODE_1, imOut, imIn);
Imaging imOut = new_image(IMAGING_MODE_1, imIn->xsize, imIn->ysize);
if (!imOut) {
return NULL;
}
Expand Down Expand Up @@ -1574,28 +1580,17 @@ static struct {
#endif
};

/**
* Convert imIn to `mode`.
* If imIn is already in `mode`, this performs a copy into imOut
* (or a newly allocated image if imOut is NULL).
*
* @param imOut Existing image to write into
* (must already be in `mode` and the same size as imIn),
* or NULL to allocate a new image for the result.
* @param imIn Source image to convert.
* @param mode Target mode.
* @param palette Target palette for conversions to "P" or "PA";
* NULL to use a default palette.
* @param dither Nonzero to dither when converting to "P", "PA" or "1".
* @return The resulting Imaging object,
* or NULL with a Python exception set on failure.
*/
Imaging
ImagingConvert(
Imaging imOut, Imaging imIn, ModeID mode, ImagingPalette palette, int dither
static Imaging
_convert_impl(
Imaging imIn,
ModeID mode,
ImagingPalette palette,
int dither,
ImagingAllocator new_image
) {
ImagingSectionCookie cookie;
ImagingShuffler convert;
Imaging imOut;

if (!imIn) {
return (Imaging)ImagingError_ModeError();
Expand All @@ -1610,22 +1605,27 @@ ImagingConvert(
} else {
/* Same mode? */
if (imIn->mode == mode) {
return ImagingCopy2(imOut, imIn);
imOut = new_image(mode, imIn->xsize, imIn->ysize);
if (imOut && !ImagingCopyInto(imOut, imIn)) {
ImagingDelete(imOut);
return NULL;
}
return imOut;
}
}

/* test for special conversions */

if (imIn->mode == IMAGING_MODE_P || imIn->mode == IMAGING_MODE_PA) {
return frompalette(imOut, imIn, mode);
return frompalette(imIn, mode, new_image);
}

if (mode == IMAGING_MODE_P || mode == IMAGING_MODE_PA) {
return topalette(imOut, imIn, mode, palette, dither);
return topalette(imIn, mode, palette, dither, new_image);
}

if (dither && mode == IMAGING_MODE_1) {
return tobilevel(imOut, imIn);
return tobilevel(imIn, new_image);
}

/* standard conversion machinery */
Expand All @@ -1647,7 +1647,7 @@ ImagingConvert(
);
}

imOut = ImagingNew2Dirty(mode, imOut, imIn);
imOut = new_image(mode, imIn->xsize, imIn->ysize);
if (!imOut) {
return NULL;
}
Expand All @@ -1661,6 +1661,37 @@ ImagingConvert(
return imOut;
}

/**
* Convert imIn to `mode`, returning a new image.
* If imIn is already in `mode`, this returns a copy.
*
* @param imIn Source image to convert.
* @param mode Target mode.
* @param palette Target palette for conversions to "P" or "PA";
* NULL to use a default palette.
* @param dither Nonzero to dither when converting to "P", "PA" or "1".
* @return A new image owned by the caller,
* or NULL with a Python exception set on failure.
*/
Imaging
ImagingConvert(Imaging imIn, ModeID mode, ImagingPalette palette, int dither) {
return _convert_impl(imIn, mode, palette, dither, ImagingNewDirty);
}

/**
* Like ImagingConvert (without palette or dithering),
* but the new image is always allocated as a single contiguous block.
*
* @param imIn Source image to convert.
* @param mode Target mode.
* @return A new image owned by the caller,
* or NULL with a Python exception set on failure.
*/
Imaging
ImagingConvertBlock(Imaging imIn, ModeID mode) {
return _convert_impl(imIn, mode, NULL, 0, ImagingNewBlock);
}

Imaging
ImagingConvertTransparent(Imaging imIn, const ModeID mode, int r, int g, int b) {
ImagingSectionCookie cookie;
Expand Down Expand Up @@ -1715,7 +1746,7 @@ ImagingConvertTransparent(Imaging imIn, const ModeID mode, int r, int g, int b)
);
}

imOut = ImagingNew2Dirty(mode, imOut, imIn);
imOut = ImagingNewDirty(mode, imIn->xsize, imIn->ysize);
if (!imOut) {
return NULL;
}
Expand Down
61 changes: 46 additions & 15 deletions src/libImaging/Copy.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,18 @@

#include "Imaging.h"

static Imaging
/**
* Copy imIn into imOut.
* This internal function requires that imOut matches imIn in mode and size.
*
* @param imOut Caller-owned image to copy into.
* @param imIn Image to copy from.
*/
static void
_copy(Imaging imOut, Imaging imIn) {
ImagingSectionCookie cookie;
int y;

if (!imIn) {
return (Imaging)ImagingError_ValueError(NULL);
}

imOut = ImagingNew2Dirty(imIn->mode, imOut, imIn);
if (!imOut) {
return NULL;
}

ImagingCopyPalette(imOut, imIn);

ImagingSectionEnter(&cookie);
Expand All @@ -42,16 +40,49 @@ _copy(Imaging imOut, Imaging imIn) {
}
}
ImagingSectionLeave(&cookie);

return imOut;
}

/**
* Create a new image by copying imIn. The caller owns the returned image.
*
* The new image is allocated with the current default allocation strategy.
*
* @param imIn Image to copy from.
* @return A new image on success, or NULL on error with a Python exception set.
*/
Imaging
ImagingCopy(Imaging imIn) {
return _copy(NULL, imIn);
if (!imIn) {
return (Imaging)ImagingError_ValueError(NULL);
}

Imaging imOut = ImagingNewDirty(imIn->mode, imIn->xsize, imIn->ysize);
if (!imOut) {
return NULL;
}

_copy(imOut, imIn);
return imOut;
}

/**
* Copy imIn into the caller-owned imOut, which must match it in mode and size.
*
* @param imOut Caller-owned image to copy into.
* @param imIn Image to copy from.
* @return imOut on success, or NULL on error with a Python exception set.
*/
Imaging
ImagingCopy2(Imaging imOut, Imaging imIn) {
return _copy(imOut, imIn);
ImagingCopyInto(Imaging imOut, Imaging imIn) {
if (!imIn || !imOut) {
return (Imaging)ImagingError_ValueError(NULL);
}

if (imOut->mode != imIn->mode || imOut->xsize != imIn->xsize ||
imOut->ysize != imIn->ysize) {
return ImagingError_Mismatch();
}

_copy(imOut, imIn);
return imOut;
}
Loading
Loading