mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-08-09 23:04:45 +03:00
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.
This commit is contained in:
parent
95257dff87
commit
919dbbe1f1
|
@ -662,7 +662,7 @@ class TestImage:
|
|||
blank_pa.palette = None
|
||||
|
||||
def _make_new(base_image, im, palette_result=None):
|
||||
new_im = base_image._new(im)
|
||||
new_im = base_image._new(im.im)
|
||||
assert new_im.mode == im.mode
|
||||
assert new_im.size == im.size
|
||||
assert new_im.info == base_image.info
|
||||
|
|
|
@ -328,8 +328,8 @@ class GifImageFile(ImageFile.ImageFile):
|
|||
self._mode = "RGBA"
|
||||
del self.info["transparency"]
|
||||
else:
|
||||
self._mode = "RGB"
|
||||
self.im = self.im.convert("RGB", Image.Dither.FLOYDSTEINBERG)
|
||||
self._mode = "RGB"
|
||||
|
||||
def _rgb(color):
|
||||
if self._frame_palette:
|
||||
|
|
|
@ -261,11 +261,7 @@ class IcnsImageFile(ImageFile.ImageFile):
|
|||
self.best_size[1] * self.best_size[2],
|
||||
)
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
return self._size
|
||||
|
||||
@size.setter
|
||||
@Image.Image.size.setter
|
||||
def size(self, value):
|
||||
info_size = value
|
||||
if info_size not in self.info["sizes"] and len(info_size) == 2:
|
||||
|
@ -283,7 +279,10 @@ class IcnsImageFile(ImageFile.ImageFile):
|
|||
if info_size not in self.info["sizes"]:
|
||||
msg = "This is not one of the allowed sizes of this image"
|
||||
raise ValueError(msg)
|
||||
self._size = value
|
||||
if value != self.size:
|
||||
self.im = None
|
||||
self.pyaccess = None
|
||||
self._size = value
|
||||
|
||||
def load(self):
|
||||
if len(self.size) == 3:
|
||||
|
@ -306,7 +305,7 @@ class IcnsImageFile(ImageFile.ImageFile):
|
|||
|
||||
self.im = im.im
|
||||
self._mode = im.mode
|
||||
self.size = im.size
|
||||
self._size = im.size
|
||||
|
||||
return px
|
||||
|
||||
|
|
|
@ -310,36 +310,36 @@ class IcoImageFile(ImageFile.ImageFile):
|
|||
self.size = self.ico.entry[0]["dim"]
|
||||
self.load()
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
return self._size
|
||||
|
||||
@size.setter
|
||||
@Image.Image.size.setter
|
||||
def size(self, value):
|
||||
if value not in self.info["sizes"]:
|
||||
msg = "This is not one of the allowed sizes of this image"
|
||||
raise ValueError(msg)
|
||||
self._size = value
|
||||
if value != self.size:
|
||||
self.im = None
|
||||
self.pyaccess = None
|
||||
self._size = value
|
||||
|
||||
def load(self):
|
||||
if self.im is not None and self.im.size == self.size:
|
||||
# Already loaded
|
||||
return Image.Image.load(self)
|
||||
im = self.ico.getimage(self.size)
|
||||
size_to_load = self.size
|
||||
im = self.ico.getimage(size_to_load)
|
||||
# if tile is PNG, it won't really be loaded yet
|
||||
im.load()
|
||||
self.im = im.im
|
||||
self.pyaccess = None
|
||||
self._mode = im.mode
|
||||
if im.size != self.size:
|
||||
if im.size != size_to_load:
|
||||
warnings.warn("Image was not the expected size")
|
||||
|
||||
index = self.ico.getentryindex(self.size)
|
||||
index = self.ico.getentryindex(size_to_load)
|
||||
sizes = list(self.info["sizes"])
|
||||
sizes[index] = im.size
|
||||
self.info["sizes"] = set(sizes)
|
||||
|
||||
self.size = im.size
|
||||
self._size = im.size
|
||||
|
||||
def load_seek(self):
|
||||
# Flag the ImageFile.Parser so that it
|
||||
|
|
|
@ -480,16 +480,21 @@ class Image:
|
|||
|
||||
def __init__(self):
|
||||
# FIXME: take "new" parameters / other image?
|
||||
# FIXME: turn mode and size into delegating properties?
|
||||
self.im = None
|
||||
self._mode = ""
|
||||
self._size = (0, 0)
|
||||
# do not directly change __mode; use _mode instead
|
||||
self.__mode = ""
|
||||
# do not directly change __size; use _size instead
|
||||
self.__size = (0, 0)
|
||||
self.palette = None
|
||||
self.info = {}
|
||||
self.readonly = 0
|
||||
self.pyaccess = None
|
||||
self._exif = None
|
||||
|
||||
def _use_im_values(self):
|
||||
''' Whether or not to try using values from self.im in addition to the values in this class. '''
|
||||
return self.im is not None
|
||||
|
||||
@property
|
||||
def width(self):
|
||||
return self.size[0]
|
||||
|
@ -502,10 +507,36 @@ class Image:
|
|||
def size(self):
|
||||
return self._size
|
||||
|
||||
@property
|
||||
def _size(self):
|
||||
if self._use_im_values():
|
||||
return self.im.size
|
||||
return self.__size
|
||||
|
||||
@_size.setter
|
||||
def _size(self, value):
|
||||
# set im.size first in case it raises an excepton
|
||||
if self._use_im_values():
|
||||
self.im.size = value
|
||||
self.__size = value
|
||||
|
||||
@property
|
||||
def mode(self):
|
||||
return self._mode
|
||||
|
||||
@property
|
||||
def _mode(self):
|
||||
if self._use_im_values():
|
||||
return self.im.mode
|
||||
return self.__mode
|
||||
|
||||
@_mode.setter
|
||||
def _mode(self, value):
|
||||
# set im.mode first in case it raises an excepton
|
||||
if self._use_im_values():
|
||||
self.im.mode = value
|
||||
self.__mode = value
|
||||
|
||||
def _new(self, im):
|
||||
new = Image()
|
||||
new.im = im
|
||||
|
|
|
@ -139,6 +139,9 @@ class ImageFile(Image.Image):
|
|||
if self.format is not None:
|
||||
return Image.MIME.get(self.format.upper())
|
||||
|
||||
def _use_im_values(self):
|
||||
return self.tile is None and self.im is not None
|
||||
|
||||
def __setstate__(self, state):
|
||||
self.tile = []
|
||||
super().__setstate__(state)
|
||||
|
|
|
@ -3646,11 +3646,49 @@ _getattr_mode(ImagingObject *self, void *closure) {
|
|||
return PyUnicode_FromString(self->image->mode);
|
||||
}
|
||||
|
||||
static int
|
||||
_setattr_mode(ImagingObject *self, PyObject *value, void *closure) {
|
||||
if (value == NULL) {
|
||||
self->image->mode[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *mode = PyUnicode_AsUTF8(value);
|
||||
if (mode == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (strlen(mode) >= IMAGING_MODE_LENGTH) {
|
||||
PyErr_SetString(PyExc_ValueError, "given mode name is too long");
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(self->image->mode, mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
_getattr_size(ImagingObject *self, void *closure) {
|
||||
return Py_BuildValue("ii", self->image->xsize, self->image->ysize);
|
||||
}
|
||||
|
||||
static int
|
||||
_setattr_size(ImagingObject *self, PyObject *value, void *closure) {
|
||||
if (value == NULL) {
|
||||
self->image->xsize = 0;
|
||||
self->image->ysize = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xsize, ysize;
|
||||
if (!PyArg_ParseTuple(value, "ii", &xsize, &ysize)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
self->image->xsize = xsize;
|
||||
self->image->ysize = ysize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
_getattr_bands(ImagingObject *self, void *closure) {
|
||||
return PyLong_FromLong(self->image->bands);
|
||||
|
@ -3679,13 +3717,14 @@ _getattr_unsafe_ptrs(ImagingObject *self, void *closure) {
|
|||
};
|
||||
|
||||
static struct PyGetSetDef getsetters[] = {
|
||||
{"mode", (getter)_getattr_mode},
|
||||
{"size", (getter)_getattr_size},
|
||||
{"mode", (getter)_getattr_mode, (setter)_setattr_mode},
|
||||
{"size", (getter)_getattr_size, (setter)_setattr_size},
|
||||
{"bands", (getter)_getattr_bands},
|
||||
{"id", (getter)_getattr_id},
|
||||
{"ptr", (getter)_getattr_ptr},
|
||||
{"unsafe_ptrs", (getter)_getattr_unsafe_ptrs},
|
||||
{NULL}};
|
||||
{NULL}
|
||||
};
|
||||
|
||||
/* basic sequence semantics */
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user