Merge branch 'box-in-thumbnail' into reduce-in-resize-2

This commit is contained in:
Alexander 2019-12-17 02:27:44 +03:00
commit 2db5406626
6 changed files with 46 additions and 13 deletions

View File

@ -13,7 +13,11 @@ class TestImageDraft(PillowTestCase):
im = Image.new(in_mode, in_size) im = Image.new(in_mode, in_size)
data = tostring(im, "JPEG") data = tostring(im, "JPEG")
im = fromstring(data) im = fromstring(data)
im.draft(req_mode, req_size) mode, box = im.draft(req_mode, req_size)
scale, _ = im.decoderconfig
self.assertEqual(box[:2], (0, 0))
self.assertTrue((im.width - scale) < box[2] <= im.width)
self.assertTrue((im.height - scale) < box[3] <= im.height)
return im return im
def test_size(self): def test_size(self):

View File

@ -1,6 +1,6 @@
from PIL import Image from PIL import Image
from .helper import PillowTestCase, hopper from .helper import PillowTestCase, fromstring, hopper, tostring
class TestImageThumbnail(PillowTestCase): class TestImageThumbnail(PillowTestCase):
@ -53,3 +53,15 @@ class TestImageThumbnail(PillowTestCase):
with Image.open("Tests/images/hopper.jpg") as im: with Image.open("Tests/images/hopper.jpg") as im:
im.thumbnail((64, 64)) im.thumbnail((64, 64))
self.assertEqual(im.size, (64, 64)) self.assertEqual(im.size, (64, 64))
def test_DCT_scaling_edges(self):
# Make an image with red borders and size (N * 8) + 1 to cross DCT grid
im = Image.new("RGB", (257, 257), "red")
im.paste(Image.new("RGB", (235, 235)), (11, 11))
thumb = fromstring(tostring(im, "JPEG", quality=99, subsampling=0))
thumb.thumbnail((32, 32), Image.BICUBIC)
ref = im.resize((32, 32), Image.BICUBIC)
# This is still JPEG, some error is present. Without the fix it is 11.5
self.assert_image_similar(thumb, ref, 1.5)

View File

@ -47,6 +47,20 @@ Setting the size of TIFF images
Setting the size of a TIFF image directly (eg. ``im.size = (256, 256)``) throws Setting the size of a TIFF image directly (eg. ``im.size = (256, 256)``) throws
an error. Use ``Image.resize`` instead. an error. Use ``Image.resize`` instead.
Image.draft() return value
^^^^^^^^^^^^^^^^^^^^^^^^^^
The ``Image.draft()`` method used to return ``None`` or the image itself.
Unlike other `chain methods`_, ``draft()`` modifies the image in-place
rather than returning a modified version.
In the new version, ``draft()`` returns ``None`` if it has no effect or
a tuple of new image mode and the box of original coordinates in the
bounds of resulting image otherwise
(the box could be useful in subsequent ``resize()`` call).
.. _chain methods: https://en.wikipedia.org/wiki/Method_chaining
API Changes API Changes
=========== ===========

View File

@ -1126,12 +1126,15 @@ class Image:
""" """
Configures the image file loader so it returns a version of the Configures the image file loader so it returns a version of the
image that as closely as possible matches the given mode and image that as closely as possible matches the given mode and
size. For example, you can use this method to convert a color size. For example, you can use this method to convert a color
JPEG to greyscale while loading it, or to extract a 128x192 JPEG to greyscale while loading it, or to extract a 128x192
version from a PCD file. version from a PCD file.
If any changes are made, returns a tuple with the chosen ``mode`` and
``box`` with coordinates of the original image within the altered one.
Note that this method modifies the :py:class:`~PIL.Image.Image` object Note that this method modifies the :py:class:`~PIL.Image.Image` object
in place. If the image has already been loaded, this method has no in place. If the image has already been loaded, this method has no
effect. effect.
Note: This method is not implemented for most images. It is Note: This method is not implemented for most images. It is
@ -2176,14 +2179,17 @@ class Image:
x = max(round(x * size[1] / y), 1) x = max(round(x * size[1] / y), 1)
y = size[1] y = size[1]
size = x, y size = x, y
box = None
if size == self.size: if size == self.size:
return return
self.draft(None, size) res = self.draft(None, size)
if res is not None:
box = res[1]
if self.size != size: if self.size != size:
im = self.resize(size, resample) im = self.resize(size, resample, box=box)
self.im = im.im self.im = im.im
self._size = size self._size = size

View File

@ -122,11 +122,6 @@ class ImageFile(Image.Image):
self.fp.close() self.fp.close()
raise raise
def draft(self, mode, size):
"""Set draft mode"""
pass
def get_format_mimetype(self): def get_format_mimetype(self):
if self.custom_mimetype: if self.custom_mimetype:
return self.custom_mimetype return self.custom_mimetype

View File

@ -412,7 +412,8 @@ class JpegImageFile(ImageFile.ImageFile):
return return
d, e, o, a = self.tile[0] d, e, o, a = self.tile[0]
scale = 0 scale = 1
original_size = self.size
if a[0] == "RGB" and mode in ["L", "YCbCr"]: if a[0] == "RGB" and mode in ["L", "YCbCr"]:
self.mode = mode self.mode = mode
@ -435,7 +436,8 @@ class JpegImageFile(ImageFile.ImageFile):
self.tile = [(d, e, o, a)] self.tile = [(d, e, o, a)]
self.decoderconfig = (scale, 0) self.decoderconfig = (scale, 0)
return self box = (0, 0, original_size[0] / float(scale), original_size[1] / float(scale))
return (self.mode, box)
def load_djpeg(self): def load_djpeg(self):