Skip to content

Commit 95ace8a

Browse files
authored
Merge branch 'master' into fix_jpeg_magic_number
2 parents cebaba1 + 1bc67c9 commit 95ace8a

46 files changed

Lines changed: 619 additions & 220 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/macos-install.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
set -e
44

5-
brew install libtiff libjpeg openjpeg libimagequant webp little-cms2 freetype
5+
brew install libtiff libjpeg openjpeg libimagequant webp little-cms2 freetype openblas
66

77
PYTHONOPTIMIZE=0 pip install cffi
88
pip install coverage
@@ -11,6 +11,8 @@ pip install -U pytest
1111
pip install -U pytest-cov
1212
pip install pyroma
1313
pip install test-image-results
14+
15+
echo -e "[openblas]\nlibraries = openblas\nlibrary_dirs = /usr/local/opt/openblas/lib" >> ~/.numpy-site.cfg
1416
pip install numpy
1517

1618
# extra test images

.github/workflows/test-windows.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ jobs:
5252
python-version: ${{ matrix.python-version }}
5353
architecture: ${{ matrix.architecture }}
5454

55+
- name: Set up TCL
56+
if: "contains(matrix.python-version, 'pypy')"
57+
run: Write-Host "::set-env name=TCL_LIBRARY::$env:pythonLocation\tcl\tcl8.5"
58+
shell: pwsh
59+
5560
- name: Print build system information
5661
run: python .github/workflows/system-info.py
5762

CHANGES.rst

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,24 @@ Changelog (Pillow)
55
7.2.0 (unreleased)
66
------------------
77

8+
- Change STRIPBYTECOUNTS to LONG if necessary when saving #4626
9+
[radarhere, hugovk]
10+
11+
- Write JFIF header when saving JPEG #4639
12+
[radarhere]
13+
14+
- Replaced tiff_jpeg with jpeg compression when saving TIFF images #4627
15+
[radarhere]
16+
17+
- Writing TIFF tags: improved BYTE, added UNDEFINED #4605
18+
[radarhere]
19+
20+
- Consider transparency when pasting text on an RGBA image #4566
21+
[radarhere]
22+
23+
- Added method argument to single frame WebP saving #4547
24+
[radarhere]
25+
826
- Use ImageFileDirectory_v2 in Image.Exif #4637
927
[radarhere]
1028

@@ -44,6 +62,9 @@ Changelog (Pillow)
4462
- Fix pickling WebP #4561
4563
[hugovk, radarhere]
4664

65+
- Replace IOError and WindowsError aliases with OSError #4536
66+
[hugovk, radarhere]
67+
4768
7.1.2 (2020-04-25)
4869
------------------
4970

Tests/images/text_mono.gif

1.52 KB
Loading
1.24 KB
Loading

Tests/test_features.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import io
2+
import re
23

34
import pytest
45
from PIL import features
@@ -21,6 +22,27 @@ def test_check():
2122
assert features.check_feature(feature) == features.check(feature)
2223

2324

25+
def test_version():
26+
# Check the correctness of the convenience function
27+
# and the format of version numbers
28+
29+
def test(name, function):
30+
version = features.version(name)
31+
if not features.check(name):
32+
assert version is None
33+
else:
34+
assert function(name) == version
35+
if name != "PIL":
36+
assert version is None or re.search(r"\d+(\.\d+)*$", version)
37+
38+
for module in features.modules:
39+
test(module, features.version_module)
40+
for codec in features.codecs:
41+
test(codec, features.version_codec)
42+
for feature in features.features:
43+
test(feature, features.version_feature)
44+
45+
2446
@skip_unless_feature("webp")
2547
def test_webp_transparency():
2648
assert features.check("transp_webp") != _webp.WebPDecoderBuggyAlpha()
@@ -37,9 +59,22 @@ def test_webp_anim():
3759
assert features.check("webp_anim") == _webp.HAVE_WEBPANIM
3860

3961

62+
@skip_unless_feature("libjpeg_turbo")
63+
def test_libjpeg_turbo_version():
64+
assert re.search(r"\d+\.\d+\.\d+$", features.version("libjpeg_turbo"))
65+
66+
67+
@skip_unless_feature("libimagequant")
68+
def test_libimagequant_version():
69+
assert re.search(r"\d+\.\d+\.\d+$", features.version("libimagequant"))
70+
71+
4072
def test_check_modules():
4173
for feature in features.modules:
4274
assert features.check_module(feature) in [True, False]
75+
76+
77+
def test_check_codecs():
4378
for feature in features.codecs:
4479
assert features.check_codec(feature) in [True, False]
4580

@@ -64,6 +99,8 @@ def test_unsupported_codec():
6499
# Act / Assert
65100
with pytest.raises(ValueError):
66101
features.check_codec(codec)
102+
with pytest.raises(ValueError):
103+
features.version_codec(codec)
67104

68105

69106
def test_unsupported_module():
@@ -72,6 +109,8 @@ def test_unsupported_module():
72109
# Act / Assert
73110
with pytest.raises(ValueError):
74111
features.check_module(module)
112+
with pytest.raises(ValueError):
113+
features.version_module(module)
75114

76115

77116
def test_pilinfo():

Tests/test_file_icns.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22
import sys
33

44
import pytest
5-
from PIL import IcnsImagePlugin, Image
5+
from PIL import IcnsImagePlugin, Image, features
66

77
from .helper import assert_image_equal, assert_image_similar
88

99
# sample icon file
1010
TEST_FILE = "Tests/images/pillow.icns"
1111

12-
ENABLE_JPEG2K = hasattr(Image.core, "jp2klib_version")
12+
ENABLE_JPEG2K = features.check_codec("jpg_2000")
1313

1414

1515
def test_sanity():

Tests/test_file_jpeg.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from io import BytesIO
44

55
import pytest
6-
from PIL import ExifTags, Image, ImageFile, JpegImagePlugin, UnidentifiedImageError
6+
from PIL import ExifTags, Image, ImageFile, JpegImagePlugin, UnidentifiedImageError, features
77

88
from .helper import (
99
assert_image,
@@ -41,7 +41,7 @@ def gen_random_image(self, size, mode="RGB"):
4141
def test_sanity(self):
4242

4343
# internal version number
44-
assert re.search(r"\d+\.\d+$", Image.core.jpeglib_version)
44+
assert re.search(r"\d+\.\d+$", features.version_codec("jpg"))
4545

4646
with Image.open(TEST_FILE) as im:
4747
im.load()
@@ -90,9 +90,12 @@ def test_cmyk(self):
9090
]
9191
assert k > 0.9
9292

93-
def test_dpi(self):
93+
@pytest.mark.parametrize(
94+
"test_image_path", [TEST_FILE, "Tests/images/pil_sample_cmyk.jpg"],
95+
)
96+
def test_dpi(self, test_image_path):
9497
def test(xdpi, ydpi=None):
95-
with Image.open(TEST_FILE) as im:
98+
with Image.open(test_image_path) as im:
9699
im = self.roundtrip(im, dpi=(xdpi, ydpi or xdpi))
97100
return im.info.get("dpi")
98101

Tests/test_file_jpeg2k.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from io import BytesIO
33

44
import pytest
5-
from PIL import Image, ImageFile, Jpeg2KImagePlugin
5+
from PIL import Image, ImageFile, Jpeg2KImagePlugin, features
66

77
from .helper import (
88
assert_image_equal,
@@ -35,7 +35,7 @@ def roundtrip(im, **options):
3535

3636
def test_sanity():
3737
# Internal version number
38-
assert re.search(r"\d+\.\d+\.\d+$", Image.core.jp2klib_version)
38+
assert re.search(r"\d+\.\d+\.\d+$", features.version_codec("jpg_2000"))
3939

4040
with Image.open("Tests/images/test-card-lossless.jp2") as im:
4141
px = im.load()

Tests/test_file_libtiff.py

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
import itertools
44
import logging
55
import os
6+
import re
67
from collections import namedtuple
78
from ctypes import c_float
89

910
import pytest
10-
from PIL import Image, ImageFilter, TiffImagePlugin, TiffTags
11+
from PIL import Image, ImageFilter, TiffImagePlugin, TiffTags, features
1112

1213
from .helper import (
1314
assert_image_equal,
@@ -47,6 +48,9 @@ def _assert_noerr(self, tmp_path, im):
4748

4849

4950
class TestFileLibTiff(LibTiffTestCase):
51+
def test_version(self):
52+
assert re.search(r"\d+\.\d+\.\d+$", features.version_codec("libtiff"))
53+
5054
def test_g4_tiff(self, tmp_path):
5155
"""Test the ordinary file path load path"""
5256

@@ -299,9 +303,6 @@ def check_tags(tiffinfo):
299303
)
300304
continue
301305

302-
if libtiff and isinstance(value, bytes):
303-
value = value.decode()
304-
305306
assert reloaded_value == value
306307

307308
# Test with types
@@ -322,6 +323,17 @@ def check_tags(tiffinfo):
322323
)
323324
TiffImagePlugin.WRITE_LIBTIFF = False
324325

326+
def test_xmlpacket_tag(self, tmp_path):
327+
TiffImagePlugin.WRITE_LIBTIFF = True
328+
329+
out = str(tmp_path / "temp.tif")
330+
hopper().save(out, tiffinfo={700: b"xmlpacket tag"})
331+
TiffImagePlugin.WRITE_LIBTIFF = False
332+
333+
with Image.open(out) as reloaded:
334+
if 700 in reloaded.tag_v2:
335+
assert reloaded.tag_v2[700] == b"xmlpacket tag"
336+
325337
def test_int_dpi(self, tmp_path):
326338
# issue #1765
327339
im = hopper("RGB")
@@ -448,6 +460,14 @@ def test_compressions(self, tmp_path):
448460
assert size_compressed > size_jpeg
449461
assert size_jpeg > size_jpeg_30
450462

463+
def test_tiff_jpeg_compression(self, tmp_path):
464+
im = hopper("RGB")
465+
out = str(tmp_path / "temp.tif")
466+
im.save(out, compression="tiff_jpeg")
467+
468+
with Image.open(out) as reloaded:
469+
assert reloaded.info["compression"] == "jpeg"
470+
451471
def test_quality(self, tmp_path):
452472
im = hopper("RGB")
453473
out = str(tmp_path / "temp.tif")
@@ -667,6 +687,26 @@ def test_read_icc(self):
667687
TiffImagePlugin.READ_LIBTIFF = False
668688
assert icc == icc_libtiff
669689

690+
def test_write_icc(self, tmp_path):
691+
def check_write(libtiff):
692+
TiffImagePlugin.WRITE_LIBTIFF = libtiff
693+
694+
with Image.open("Tests/images/hopper.iccprofile.tif") as img:
695+
icc_profile = img.info["icc_profile"]
696+
697+
out = str(tmp_path / "temp.tif")
698+
img.save(out, icc_profile=icc_profile)
699+
with Image.open(out) as reloaded:
700+
assert icc_profile == reloaded.info["icc_profile"]
701+
702+
libtiffs = []
703+
if Image.core.libtiff_support_custom_tags:
704+
libtiffs.append(True)
705+
libtiffs.append(False)
706+
707+
for libtiff in libtiffs:
708+
check_write(libtiff)
709+
670710
def test_multipage_compression(self):
671711
with Image.open("Tests/images/compression.tif") as im:
672712

0 commit comments

Comments
 (0)