Skip to content

Commit 9149509

Browse files
authored
Merge pull request #4989 from gofr/4962-jpeg-zigzag
De-zigzag JPEG's DQT when loading; deprecate convert_dict_qtables
2 parents 1b74bdd + dfeb49c commit 9149509

File tree

5 files changed

+57
-41
lines changed

5 files changed

+57
-41
lines changed

Tests/test_file_jpeg.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ def _n_qtables_helper(n, test_file):
466466
assert len(im.quantization) == n
467467
reloaded = self.roundtrip(im, qtables="keep")
468468
assert im.quantization == reloaded.quantization
469-
assert reloaded.quantization[0].typecode == "B"
469+
assert max(reloaded.quantization[0]) <= 255
470470

471471
with Image.open("Tests/images/hopper.jpg") as im:
472472
qtables = im.quantization
@@ -478,7 +478,8 @@ def _n_qtables_helper(n, test_file):
478478

479479
# valid bounds for baseline qtable
480480
bounds_qtable = [int(s) for s in ("255 1 " * 32).split(None)]
481-
self.roundtrip(im, qtables=[bounds_qtable])
481+
im2 = self.roundtrip(im, qtables=[bounds_qtable])
482+
assert im2.quantization == {0: bounds_qtable}
482483

483484
# values from wizard.txt in jpeg9-a src package.
484485
standard_l_qtable = [
@@ -589,6 +590,12 @@ def test_save_low_quality_baseline_qtables(self):
589590
assert max(im2.quantization[0]) <= 255
590591
assert max(im2.quantization[1]) <= 255
591592

593+
def test_convert_dict_qtables_deprecation(self):
594+
with pytest.warns(DeprecationWarning):
595+
qtable = {0: [1, 2, 3, 4]}
596+
qtable2 = JpegImagePlugin.convert_dict_qtables(qtable)
597+
assert qtable == qtable2
598+
592599
@pytest.mark.skipif(not djpeg_available(), reason="djpeg not available")
593600
def test_load_djpeg(self):
594601
with Image.open(TEST_FILE) as img:

docs/deprecations.rst

+30-20
Original file line numberDiff line numberDiff line change
@@ -25,26 +25,6 @@ vulnerability introduced in FreeType 2.6 (:cve:`CVE-2020-15999`).
2525

2626
.. _2.10.4: https://sourceforge.net/projects/freetype/files/freetype2/2.10.4/
2727

28-
Tk/Tcl 8.4
29-
~~~~~~~~~~
30-
31-
.. deprecated:: 8.2.0
32-
33-
Support for Tk/Tcl 8.4 is deprecated and will be removed in Pillow 10.0.0 (2023-01-02),
34-
when Tk/Tcl 8.5 will be the minimum supported.
35-
36-
Categories
37-
~~~~~~~~~~
38-
39-
.. deprecated:: 8.2.0
40-
41-
``im.category`` is deprecated and will be removed in Pillow 10.0.0 (2023-01-02),
42-
along with the related ``Image.NORMAL``, ``Image.SEQUENCE`` and
43-
``Image.CONTAINER`` attributes.
44-
45-
To determine if an image has multiple frames or not,
46-
``getattr(im, "is_animated", False)`` can be used instead.
47-
4828
Image.show command parameter
4929
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5030

@@ -82,6 +62,36 @@ Use ``__version__`` instead.
8262
It was initially removed in Pillow 7.0.0, but brought back in 7.1.0 to give projects
8363
more time to upgrade.
8464

65+
Tk/Tcl 8.4
66+
~~~~~~~~~~
67+
68+
.. deprecated:: 8.2.0
69+
70+
Support for Tk/Tcl 8.4 is deprecated and will be removed in Pillow 10.0.0 (2023-01-02),
71+
when Tk/Tcl 8.5 will be the minimum supported.
72+
73+
Categories
74+
~~~~~~~~~~
75+
76+
.. deprecated:: 8.2.0
77+
78+
``im.category`` is deprecated and will be removed in Pillow 10.0.0 (2023-01-02),
79+
along with the related ``Image.NORMAL``, ``Image.SEQUENCE`` and
80+
``Image.CONTAINER`` attributes.
81+
82+
To determine if an image has multiple frames or not,
83+
``getattr(im, "is_animated", False)`` can be used instead.
84+
85+
JpegImagePlugin.convert_dict_qtables
86+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
87+
88+
.. deprecated:: 8.3.0
89+
90+
JPEG ``quantization`` is now automatically converted, but still returned as a
91+
dictionary. The :py:attr:`~PIL.JpegImagePlugin.convert_dict_qtables` method no longer
92+
performs any operations on the data given to it, has been deprecated and will be
93+
removed in Pillow 10.0.0 (2023-01-02).
94+
8595
Removed features
8696
----------------
8797

docs/releasenotes/8.3.0.rst

+6-3
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44
Deprecations
55
============
66

7-
TODO
8-
^^^^
7+
JpegImagePlugin.convert_dict_qtables
8+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
99

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

1215
API Changes
1316
===========

src/PIL/JpegImagePlugin.py

+9-5
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ def DQT(self, marker):
254254
data = array.array("B" if precision == 1 else "H", s[1:qt_length])
255255
if sys.byteorder == "little" and precision > 1:
256256
data.byteswap() # the values are always big-endian
257-
self.quantization[v & 15] = data
257+
self.quantization[v & 15] = [data[i] for i in zigzag_index]
258258
s = s[qt_length:]
259259

260260

@@ -601,9 +601,11 @@ def _getmp(self):
601601

602602

603603
def convert_dict_qtables(qtables):
604-
qtables = [qtables[key] for key in range(len(qtables)) if key in qtables]
605-
for idx, table in enumerate(qtables):
606-
qtables[idx] = [table[i] for i in zigzag_index]
604+
warnings.warn(
605+
"convert_dict_qtables is deprecated and will be removed in Pillow 10"
606+
"(2023-01-02). Conversion is no longer needed.",
607+
DeprecationWarning,
608+
)
607609
return qtables
608610

609611

@@ -684,7 +686,9 @@ def validate_qtables(qtables):
684686
qtables = [lines[s : s + 64] for s in range(0, len(lines), 64)]
685687
if isinstance(qtables, (tuple, list, dict)):
686688
if isinstance(qtables, dict):
687-
qtables = convert_dict_qtables(qtables)
689+
qtables = [
690+
qtables[key] for key in range(len(qtables)) if key in qtables
691+
]
688692
elif isinstance(qtables, tuple):
689693
qtables = list(qtables)
690694
if not (0 < len(qtables) < 5):

src/PIL/JpegPresets.py

+3-11
Original file line numberDiff line numberDiff line change
@@ -52,19 +52,11 @@
5252
5353
im.quantization
5454
55-
This will return a dict with a number of arrays. You can pass this dict
55+
This will return a dict with a number of lists. You can pass this dict
5656
directly as the qtables argument when saving a JPEG.
5757
58-
The tables format between im.quantization and quantization in presets differ in
59-
3 ways:
60-
61-
1. The base container of the preset is a list with sublists instead of dict.
62-
dict[0] -> list[0], dict[1] -> list[1], ...
63-
2. Each table in a preset is a list instead of an array.
64-
3. The zigzag order is remove in the preset (needed by libjpeg >= 6a).
65-
66-
You can convert the dict format to the preset format with the
67-
:func:`.JpegImagePlugin.convert_dict_qtables()` function.
58+
The quantization table format in presets is a list with sublists. These formats
59+
are interchangeable.
6860
6961
Libjpeg ref.:
7062
https://web.archive.org/web/20120328125543/http://www.jpegcameras.com/libjpeg/libjpeg-3.html

0 commit comments

Comments
 (0)