Skip to content

Commit 919dbbe

Browse files
committed
delegate Image.mode and Image.size to the values on Image.im when available
When setting the values on Image also try to update the values on Image.im. There isn't currently a way to update values in the other direction.
1 parent 95257df commit 919dbbe

File tree

7 files changed

+97
-25
lines changed

7 files changed

+97
-25
lines changed

Tests/test_image.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,7 @@ def test__new(self):
662662
blank_pa.palette = None
663663

664664
def _make_new(base_image, im, palette_result=None):
665-
new_im = base_image._new(im)
665+
new_im = base_image._new(im.im)
666666
assert new_im.mode == im.mode
667667
assert new_im.size == im.size
668668
assert new_im.info == base_image.info

src/PIL/GifImagePlugin.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,8 +328,8 @@ def _seek(self, frame, update_image=True):
328328
self._mode = "RGBA"
329329
del self.info["transparency"]
330330
else:
331-
self._mode = "RGB"
332331
self.im = self.im.convert("RGB", Image.Dither.FLOYDSTEINBERG)
332+
self._mode = "RGB"
333333

334334
def _rgb(color):
335335
if self._frame_palette:

src/PIL/IcnsImagePlugin.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -261,11 +261,7 @@ def _open(self):
261261
self.best_size[1] * self.best_size[2],
262262
)
263263

264-
@property
265-
def size(self):
266-
return self._size
267-
268-
@size.setter
264+
@Image.Image.size.setter
269265
def size(self, value):
270266
info_size = value
271267
if info_size not in self.info["sizes"] and len(info_size) == 2:
@@ -283,7 +279,10 @@ def size(self, value):
283279
if info_size not in self.info["sizes"]:
284280
msg = "This is not one of the allowed sizes of this image"
285281
raise ValueError(msg)
286-
self._size = value
282+
if value != self.size:
283+
self.im = None
284+
self.pyaccess = None
285+
self._size = value
287286

288287
def load(self):
289288
if len(self.size) == 3:
@@ -306,7 +305,7 @@ def load(self):
306305

307306
self.im = im.im
308307
self._mode = im.mode
309-
self.size = im.size
308+
self._size = im.size
310309

311310
return px
312311

src/PIL/IcoImagePlugin.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -310,36 +310,36 @@ def _open(self):
310310
self.size = self.ico.entry[0]["dim"]
311311
self.load()
312312

313-
@property
314-
def size(self):
315-
return self._size
316-
317-
@size.setter
313+
@Image.Image.size.setter
318314
def size(self, value):
319315
if value not in self.info["sizes"]:
320316
msg = "This is not one of the allowed sizes of this image"
321317
raise ValueError(msg)
322-
self._size = value
318+
if value != self.size:
319+
self.im = None
320+
self.pyaccess = None
321+
self._size = value
323322

324323
def load(self):
325324
if self.im is not None and self.im.size == self.size:
326325
# Already loaded
327326
return Image.Image.load(self)
328-
im = self.ico.getimage(self.size)
327+
size_to_load = self.size
328+
im = self.ico.getimage(size_to_load)
329329
# if tile is PNG, it won't really be loaded yet
330330
im.load()
331331
self.im = im.im
332332
self.pyaccess = None
333333
self._mode = im.mode
334-
if im.size != self.size:
334+
if im.size != size_to_load:
335335
warnings.warn("Image was not the expected size")
336336

337-
index = self.ico.getentryindex(self.size)
337+
index = self.ico.getentryindex(size_to_load)
338338
sizes = list(self.info["sizes"])
339339
sizes[index] = im.size
340340
self.info["sizes"] = set(sizes)
341341

342-
self.size = im.size
342+
self._size = im.size
343343

344344
def load_seek(self):
345345
# Flag the ImageFile.Parser so that it

src/PIL/Image.py

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -480,16 +480,21 @@ class Image:
480480

481481
def __init__(self):
482482
# FIXME: take "new" parameters / other image?
483-
# FIXME: turn mode and size into delegating properties?
484483
self.im = None
485-
self._mode = ""
486-
self._size = (0, 0)
484+
# do not directly change __mode; use _mode instead
485+
self.__mode = ""
486+
# do not directly change __size; use _size instead
487+
self.__size = (0, 0)
487488
self.palette = None
488489
self.info = {}
489490
self.readonly = 0
490491
self.pyaccess = None
491492
self._exif = None
492493

494+
def _use_im_values(self):
495+
''' Whether or not to try using values from self.im in addition to the values in this class. '''
496+
return self.im is not None
497+
493498
@property
494499
def width(self):
495500
return self.size[0]
@@ -502,10 +507,36 @@ def height(self):
502507
def size(self):
503508
return self._size
504509

510+
@property
511+
def _size(self):
512+
if self._use_im_values():
513+
return self.im.size
514+
return self.__size
515+
516+
@_size.setter
517+
def _size(self, value):
518+
# set im.size first in case it raises an excepton
519+
if self._use_im_values():
520+
self.im.size = value
521+
self.__size = value
522+
505523
@property
506524
def mode(self):
507525
return self._mode
508526

527+
@property
528+
def _mode(self):
529+
if self._use_im_values():
530+
return self.im.mode
531+
return self.__mode
532+
533+
@_mode.setter
534+
def _mode(self, value):
535+
# set im.mode first in case it raises an excepton
536+
if self._use_im_values():
537+
self.im.mode = value
538+
self.__mode = value
539+
509540
def _new(self, im):
510541
new = Image()
511542
new.im = im

src/PIL/ImageFile.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,9 @@ def get_format_mimetype(self):
139139
if self.format is not None:
140140
return Image.MIME.get(self.format.upper())
141141

142+
def _use_im_values(self):
143+
return self.tile is None and self.im is not None
144+
142145
def __setstate__(self, state):
143146
self.tile = []
144147
super().__setstate__(state)

src/_imaging.c

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3646,11 +3646,49 @@ _getattr_mode(ImagingObject *self, void *closure) {
36463646
return PyUnicode_FromString(self->image->mode);
36473647
}
36483648

3649+
static int
3650+
_setattr_mode(ImagingObject *self, PyObject *value, void *closure) {
3651+
if (value == NULL) {
3652+
self->image->mode[0] = '\0';
3653+
return 0;
3654+
}
3655+
3656+
const char *mode = PyUnicode_AsUTF8(value);
3657+
if (mode == NULL) {
3658+
return -1;
3659+
}
3660+
if (strlen(mode) >= IMAGING_MODE_LENGTH) {
3661+
PyErr_SetString(PyExc_ValueError, "given mode name is too long");
3662+
return -1;
3663+
}
3664+
3665+
strcpy(self->image->mode, mode);
3666+
return 0;
3667+
}
3668+
36493669
static PyObject *
36503670
_getattr_size(ImagingObject *self, void *closure) {
36513671
return Py_BuildValue("ii", self->image->xsize, self->image->ysize);
36523672
}
36533673

3674+
static int
3675+
_setattr_size(ImagingObject *self, PyObject *value, void *closure) {
3676+
if (value == NULL) {
3677+
self->image->xsize = 0;
3678+
self->image->ysize = 0;
3679+
return 0;
3680+
}
3681+
3682+
int xsize, ysize;
3683+
if (!PyArg_ParseTuple(value, "ii", &xsize, &ysize)) {
3684+
return -1;
3685+
}
3686+
3687+
self->image->xsize = xsize;
3688+
self->image->ysize = ysize;
3689+
return 0;
3690+
}
3691+
36543692
static PyObject *
36553693
_getattr_bands(ImagingObject *self, void *closure) {
36563694
return PyLong_FromLong(self->image->bands);
@@ -3679,13 +3717,14 @@ _getattr_unsafe_ptrs(ImagingObject *self, void *closure) {
36793717
};
36803718

36813719
static struct PyGetSetDef getsetters[] = {
3682-
{"mode", (getter)_getattr_mode},
3683-
{"size", (getter)_getattr_size},
3720+
{"mode", (getter)_getattr_mode, (setter)_setattr_mode},
3721+
{"size", (getter)_getattr_size, (setter)_setattr_size},
36843722
{"bands", (getter)_getattr_bands},
36853723
{"id", (getter)_getattr_id},
36863724
{"ptr", (getter)_getattr_ptr},
36873725
{"unsafe_ptrs", (getter)_getattr_unsafe_ptrs},
3688-
{NULL}};
3726+
{NULL}
3727+
};
36893728

36903729
/* basic sequence semantics */
36913730

0 commit comments

Comments
 (0)