Merge pull request #4989 from gofr/4962-jpeg-zigzag

De-zigzag JPEG's DQT when loading; deprecate convert_dict_qtables
This commit is contained in:
mergify[bot] 2021-06-30 12:37:26 +00:00 committed by GitHub
commit 914950959b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 57 additions and 41 deletions

View File

@ -466,7 +466,7 @@ class TestFileJpeg:
assert len(im.quantization) == n assert len(im.quantization) == n
reloaded = self.roundtrip(im, qtables="keep") reloaded = self.roundtrip(im, qtables="keep")
assert im.quantization == reloaded.quantization assert im.quantization == reloaded.quantization
assert reloaded.quantization[0].typecode == "B" assert max(reloaded.quantization[0]) <= 255
with Image.open("Tests/images/hopper.jpg") as im: with Image.open("Tests/images/hopper.jpg") as im:
qtables = im.quantization qtables = im.quantization
@ -478,7 +478,8 @@ class TestFileJpeg:
# valid bounds for baseline qtable # valid bounds for baseline qtable
bounds_qtable = [int(s) for s in ("255 1 " * 32).split(None)] bounds_qtable = [int(s) for s in ("255 1 " * 32).split(None)]
self.roundtrip(im, qtables=[bounds_qtable]) im2 = self.roundtrip(im, qtables=[bounds_qtable])
assert im2.quantization == {0: bounds_qtable}
# values from wizard.txt in jpeg9-a src package. # values from wizard.txt in jpeg9-a src package.
standard_l_qtable = [ standard_l_qtable = [
@ -589,6 +590,12 @@ class TestFileJpeg:
assert max(im2.quantization[0]) <= 255 assert max(im2.quantization[0]) <= 255
assert max(im2.quantization[1]) <= 255 assert max(im2.quantization[1]) <= 255
def test_convert_dict_qtables_deprecation(self):
with pytest.warns(DeprecationWarning):
qtable = {0: [1, 2, 3, 4]}
qtable2 = JpegImagePlugin.convert_dict_qtables(qtable)
assert qtable == qtable2
@pytest.mark.skipif(not djpeg_available(), reason="djpeg not available") @pytest.mark.skipif(not djpeg_available(), reason="djpeg not available")
def test_load_djpeg(self): def test_load_djpeg(self):
with Image.open(TEST_FILE) as img: with Image.open(TEST_FILE) as img:

View File

@ -25,26 +25,6 @@ vulnerability introduced in FreeType 2.6 (:cve:`CVE-2020-15999`).
.. _2.10.4: https://sourceforge.net/projects/freetype/files/freetype2/2.10.4/ .. _2.10.4: https://sourceforge.net/projects/freetype/files/freetype2/2.10.4/
Tk/Tcl 8.4
~~~~~~~~~~
.. deprecated:: 8.2.0
Support for Tk/Tcl 8.4 is deprecated and will be removed in Pillow 10.0.0 (2023-01-02),
when Tk/Tcl 8.5 will be the minimum supported.
Categories
~~~~~~~~~~
.. deprecated:: 8.2.0
``im.category`` is deprecated and will be removed in Pillow 10.0.0 (2023-01-02),
along with the related ``Image.NORMAL``, ``Image.SEQUENCE`` and
``Image.CONTAINER`` attributes.
To determine if an image has multiple frames or not,
``getattr(im, "is_animated", False)`` can be used instead.
Image.show command parameter Image.show command parameter
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -82,6 +62,36 @@ Use ``__version__`` instead.
It was initially removed in Pillow 7.0.0, but brought back in 7.1.0 to give projects It was initially removed in Pillow 7.0.0, but brought back in 7.1.0 to give projects
more time to upgrade. more time to upgrade.
Tk/Tcl 8.4
~~~~~~~~~~
.. deprecated:: 8.2.0
Support for Tk/Tcl 8.4 is deprecated and will be removed in Pillow 10.0.0 (2023-01-02),
when Tk/Tcl 8.5 will be the minimum supported.
Categories
~~~~~~~~~~
.. deprecated:: 8.2.0
``im.category`` is deprecated and will be removed in Pillow 10.0.0 (2023-01-02),
along with the related ``Image.NORMAL``, ``Image.SEQUENCE`` and
``Image.CONTAINER`` attributes.
To determine if an image has multiple frames or not,
``getattr(im, "is_animated", False)`` can be used instead.
JpegImagePlugin.convert_dict_qtables
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. deprecated:: 8.3.0
JPEG ``quantization`` is now automatically converted, but still returned as a
dictionary. The :py:attr:`~PIL.JpegImagePlugin.convert_dict_qtables` method no longer
performs any operations on the data given to it, has been deprecated and will be
removed in Pillow 10.0.0 (2023-01-02).
Removed features Removed features
---------------- ----------------

View File

@ -4,10 +4,13 @@
Deprecations Deprecations
============ ============
TODO JpegImagePlugin.convert_dict_qtables
^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TODO JPEG ``quantization`` is now automatically converted, but still returned as a
dictionary. The :py:attr:`~PIL.JpegImagePlugin.convert_dict_qtables` method no longer
performs any operations on the data given to it, has been deprecated and will be
removed in Pillow 10.0.0 (2023-01-02).
API Changes API Changes
=========== ===========

View File

@ -254,7 +254,7 @@ def DQT(self, marker):
data = array.array("B" if precision == 1 else "H", s[1:qt_length]) data = array.array("B" if precision == 1 else "H", s[1:qt_length])
if sys.byteorder == "little" and precision > 1: if sys.byteorder == "little" and precision > 1:
data.byteswap() # the values are always big-endian data.byteswap() # the values are always big-endian
self.quantization[v & 15] = data self.quantization[v & 15] = [data[i] for i in zigzag_index]
s = s[qt_length:] s = s[qt_length:]
@ -601,9 +601,11 @@ samplings = {
def convert_dict_qtables(qtables): def convert_dict_qtables(qtables):
qtables = [qtables[key] for key in range(len(qtables)) if key in qtables] warnings.warn(
for idx, table in enumerate(qtables): "convert_dict_qtables is deprecated and will be removed in Pillow 10"
qtables[idx] = [table[i] for i in zigzag_index] "(2023-01-02). Conversion is no longer needed.",
DeprecationWarning,
)
return qtables return qtables
@ -684,7 +686,9 @@ def _save(im, fp, filename):
qtables = [lines[s : s + 64] for s in range(0, len(lines), 64)] qtables = [lines[s : s + 64] for s in range(0, len(lines), 64)]
if isinstance(qtables, (tuple, list, dict)): if isinstance(qtables, (tuple, list, dict)):
if isinstance(qtables, dict): if isinstance(qtables, dict):
qtables = convert_dict_qtables(qtables) qtables = [
qtables[key] for key in range(len(qtables)) if key in qtables
]
elif isinstance(qtables, tuple): elif isinstance(qtables, tuple):
qtables = list(qtables) qtables = list(qtables)
if not (0 < len(qtables) < 5): if not (0 < len(qtables) < 5):

View File

@ -52,19 +52,11 @@ You can get the quantization tables of a JPEG with::
im.quantization im.quantization
This will return a dict with a number of arrays. You can pass this dict This will return a dict with a number of lists. You can pass this dict
directly as the qtables argument when saving a JPEG. directly as the qtables argument when saving a JPEG.
The tables format between im.quantization and quantization in presets differ in The quantization table format in presets is a list with sublists. These formats
3 ways: are interchangeable.
1. The base container of the preset is a list with sublists instead of dict.
dict[0] -> list[0], dict[1] -> list[1], ...
2. Each table in a preset is a list instead of an array.
3. The zigzag order is remove in the preset (needed by libjpeg >= 6a).
You can convert the dict format to the preset format with the
:func:`.JpegImagePlugin.convert_dict_qtables()` function.
Libjpeg ref.: Libjpeg ref.:
https://web.archive.org/web/20120328125543/http://www.jpegcameras.com/libjpeg/libjpeg-3.html https://web.archive.org/web/20120328125543/http://www.jpegcameras.com/libjpeg/libjpeg-3.html