diff --git a/.github/workflows/wheels-dependencies.sh b/.github/workflows/wheels-dependencies.sh index 2605664eb..3ec314873 100755 --- a/.github/workflows/wheels-dependencies.sh +++ b/.github/workflows/wheels-dependencies.sh @@ -22,7 +22,7 @@ JPEGTURBO_VERSION=3.0.1 OPENJPEG_VERSION=2.5.0 XZ_VERSION=5.4.5 TIFF_VERSION=4.6.0 -LCMS2_VERSION=2.15 +LCMS2_VERSION=2.16 if [[ -n "$IS_MACOS" ]]; then GIFLIB_VERSION=5.1.4 else diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8b2dc06ae..f6b8c349c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,12 +1,12 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.4 + rev: v0.1.6 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] - repo: https://github.com/psf/black-pre-commit-mirror - rev: 23.10.1 + rev: 23.11.0 hooks: - id: black @@ -42,12 +42,12 @@ repos: exclude: ^.github/.*TEMPLATE|^Tests/(fonts|images)/ - repo: https://github.com/sphinx-contrib/sphinx-lint - rev: v0.8.1 + rev: v0.9.0 hooks: - id: sphinx-lint - repo: https://github.com/tox-dev/pyproject-fmt - rev: 1.4.1 + rev: 1.5.3 hooks: - id: pyproject-fmt diff --git a/CHANGES.rst b/CHANGES.rst index 251917654..b378571c3 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,7 +5,19 @@ Changelog (Pillow) 10.2.0 (unreleased) ------------------- -- Raise ValueError when TrueType font size is not greater than zero #7584 +- Added support for reading DX10 BC4 DDS images #7603 + [sambvfx, radarhere] + +- Optimized ImageStat.Stat.count #7599 + [florath] + +- Correct PDF palette size when saving #7555 + [radarhere] + +- Fixed closing file pointer with olefile 0.47 #7594 + [radarhere] + +- Raise ValueError when TrueType font size is not greater than zero #7584, #7587 [akx, radarhere] - If absent, do not try to close fp when closing image #7557 diff --git a/RELEASING.md b/RELEASING.md index 8b0673203..74f427f03 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -94,7 +94,6 @@ Released as needed privately to individual vendors for critical security-related ## Source and Binary Distributions -### macOS and Linux * [ ] Download sdist and wheels from the [GitHub Actions "Wheels" workflow](https://github.com/python-pillow/Pillow/actions/workflows/wheels.yml) and copy into `dist/`. For example using [GitHub CLI](https://github.com/cli/cli): ```bash @@ -104,14 +103,6 @@ Released as needed privately to individual vendors for critical security-related * [ ] Download the Linux aarch64 wheels created by Travis CI from [GitHub releases](https://github.com/python-pillow/Pillow/releases) and copy into `dist`. -### Windows -* [ ] Download the artifacts from the [GitHub Actions "Test Windows" workflow](https://github.com/python-pillow/Pillow/actions/workflows/test-windows.yml) - and copy into `dist/`. For example using [GitHub CLI](https://github.com/cli/cli): - ```bash - gh run download --dir dist - # select dist-x.y.z - ``` - ## Publicize Release * [ ] Announce release availability via [Twitter](https://twitter.com/pythonpillow) and [Mastodon](https://fosstodon.org/@pillow) e.g. https://twitter.com/PythonPillow/status/1013789184354603010 diff --git a/Tests/images/bc4_typeless.dds b/Tests/images/bc4_typeless.dds new file mode 100644 index 000000000..27f87889f Binary files /dev/null and b/Tests/images/bc4_typeless.dds differ diff --git a/Tests/images/bc4_unorm.dds b/Tests/images/bc4_unorm.dds new file mode 100644 index 000000000..13da711bd Binary files /dev/null and b/Tests/images/bc4_unorm.dds differ diff --git a/Tests/images/bc4_unorm.png b/Tests/images/bc4_unorm.png new file mode 100644 index 000000000..71d536c84 Binary files /dev/null and b/Tests/images/bc4_unorm.png differ diff --git a/Tests/test_file_dds.py b/Tests/test_file_dds.py index 3a9cc4f10..0dd3d5bb9 100644 --- a/Tests/test_file_dds.py +++ b/Tests/test_file_dds.py @@ -12,6 +12,8 @@ TEST_FILE_DXT3 = "Tests/images/dxt3-argb-8bbp-explicitalpha_MipMaps-1.dds" TEST_FILE_DXT5 = "Tests/images/dxt5-argb-8bbp-interpolatedalpha_MipMaps-1.dds" TEST_FILE_ATI1 = "Tests/images/ati1.dds" TEST_FILE_ATI2 = "Tests/images/ati2.dds" +TEST_FILE_DX10_BC4_TYPELESS = "Tests/images/bc4_typeless.dds" +TEST_FILE_DX10_BC4_UNORM = "Tests/images/bc4_unorm.dds" TEST_FILE_DX10_BC5_TYPELESS = "Tests/images/bc5_typeless.dds" TEST_FILE_DX10_BC5_UNORM = "Tests/images/bc5_unorm.dds" TEST_FILE_DX10_BC5_SNORM = "Tests/images/bc5_snorm.dds" @@ -102,6 +104,27 @@ def test_sanity_ati1_bc4u(image_path): assert_image_equal_tofile(im, TEST_FILE_ATI1.replace(".dds", ".png")) +@pytest.mark.parametrize( + "image_path", + ( + TEST_FILE_DX10_BC4_UNORM, + # hexeditted to be typeless + TEST_FILE_DX10_BC4_TYPELESS, + ), +) +def test_dx10_bc4(image_path): + """Check DX10 BC4 images can be opened""" + + with Image.open(image_path) as im: + im.load() + + assert im.format == "DDS" + assert im.mode == "L" + assert im.size == (64, 64) + + assert_image_equal_tofile(im, TEST_FILE_DX10_BC4_UNORM.replace(".dds", ".png")) + + @pytest.mark.parametrize( "image_path", ( diff --git a/docs/installation.rst b/docs/installation.rst index 78900aa57..fbcfbb907 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -95,11 +95,10 @@ and :pypi:`olefile` for Pillow to read FPX and MIC images:: .. tab:: Windows - .. warning:: Pillow > 9.5.0 no longer includes 32-bit wheels. - - We provide Pillow binaries for Windows compiled for the matrix of - supported Pythons in 64-bit versions in the wheel format. These binaries include - support for all optional libraries except libimagequant and libxcb. Raqm support + We provide Pillow binaries for Windows compiled for the matrix of supported + Pythons in the wheel format. These include x86, x86-64 and arm64 versions + (with the exception of Python 3.8 on arm64). These binaries include support + for all optional libraries except libimagequant and libxcb. Raqm support requires FriBiDi to be installed separately:: python3 -m pip install --upgrade pip @@ -176,7 +175,7 @@ Many of Pillow's features require external libraries: * **littlecms** provides color management * Pillow version 2.2.1 and below uses liblcms1, Pillow 2.3.0 and - above uses liblcms2. Tested with **1.19** and **2.7-2.15**. + above uses liblcms2. Tested with **1.19** and **2.7-2.16**. * **libwebp** provides the WebP format. diff --git a/src/PIL/DdsImagePlugin.py b/src/PIL/DdsImagePlugin.py index c09a8db3b..08d6b839e 100644 --- a/src/PIL/DdsImagePlugin.py +++ b/src/PIL/DdsImagePlugin.py @@ -415,6 +415,10 @@ class DdsImageFile(ImageFile.ImageFile): self._mode = "RGBA" self.pixel_format = "BC1" n = 1 + elif dxgi_format in (DXGI_FORMAT.BC4_TYPELESS, DXGI_FORMAT.BC4_UNORM): + self._mode = "L" + self.pixel_format = "BC4" + n = 4 elif dxgi_format in (DXGI_FORMAT.BC5_TYPELESS, DXGI_FORMAT.BC5_UNORM): self._mode = "RGB" self.pixel_format = "BC5" diff --git a/src/PIL/ImageFont.py b/src/PIL/ImageFont.py index 0331a5c45..18de10375 100644 --- a/src/PIL/ImageFont.py +++ b/src/PIL/ImageFont.py @@ -188,6 +188,10 @@ class FreeTypeFont: def __init__(self, font=None, size=10, index=0, encoding="", layout_engine=None): # FIXME: use service provider instead + if size <= 0: + msg = "font size must be greater than 0" + raise ValueError(msg) + self.path = font self.size = size self.index = index @@ -791,10 +795,6 @@ def truetype(font=None, size=10, index=0, encoding="", layout_engine=None): :exception ValueError: If the font size is not greater than zero. """ - if size <= 0: - msg = "font size must be greater than 0" - raise ValueError(msg) - def freetype(font): return FreeTypeFont(font, size, index, encoding, layout_engine) diff --git a/src/PIL/ImageStat.py b/src/PIL/ImageStat.py index b7ebddf06..c0f647024 100644 --- a/src/PIL/ImageStat.py +++ b/src/PIL/ImageStat.py @@ -21,9 +21,7 @@ # See the README file for information on usage and redistribution. # -import functools import math -import operator class Stat: @@ -69,10 +67,7 @@ class Stat: def _getcount(self): """Get total number of pixels in each layer""" - v = [] - for i in range(0, len(self.h), 256): - v.append(functools.reduce(operator.add, self.h[i : i + 256])) - return v + return [sum(self.h[i : i + 256]) for i in range(0, len(self.h), 256)] def _getsum(self): """Get sum of all pixels in each layer""" diff --git a/src/PIL/PdfImagePlugin.py b/src/PIL/PdfImagePlugin.py index 09fc0c7e6..b6bb60911 100644 --- a/src/PIL/PdfImagePlugin.py +++ b/src/PIL/PdfImagePlugin.py @@ -96,7 +96,7 @@ def _write_image(im, filename, existing_pdf, image_refs): dict_obj["ColorSpace"] = [ PdfParser.PdfName("Indexed"), PdfParser.PdfName("DeviceRGB"), - 255, + len(palette) // 3 - 1, PdfParser.PdfBinary(palette), ] procset = "ImageI" # indexed color diff --git a/winbuild/build_prepare.py b/winbuild/build_prepare.py index c5c9441d4..f7e145fb9 100644 --- a/winbuild/build_prepare.py +++ b/winbuild/build_prepare.py @@ -279,10 +279,10 @@ DEPS = { "libs": [r"objs\{msbuild_arch}\Release Static\freetype.lib"], }, "lcms2": { - "url": SF_PROJECTS + "/lcms/files/lcms/2.15/lcms2-2.15.tar.gz/download", - "filename": "lcms2-2.15.tar.gz", - "dir": "lcms2-2.15", - "license": "COPYING", + "url": SF_PROJECTS + "/lcms/files/lcms/2.16/lcms2-2.16.tar.gz/download", + "filename": "lcms2-2.16.tar.gz", + "dir": "lcms2-2.16", + "license": "LICENSE", "patch": { r"Projects\VC2022\lcms2_static\lcms2_static.vcxproj": { # default is /MD for x86 and /MT for x64, we need /MD always