Skip to content

Commit

Permalink
Merge branch 'main' into context_manager
Browse files Browse the repository at this point in the history
  • Loading branch information
radarhere committed Dec 31, 2024
2 parents 5ad234c + c3fac1d commit 9c0bd08
Show file tree
Hide file tree
Showing 16 changed files with 101 additions and 26 deletions.
2 changes: 1 addition & 1 deletion .ci/requirements-mypy.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
mypy==1.14.0
mypy==1.14.1
IceSpringPySideStubs-PyQt6
IceSpringPySideStubs-PySide6
ipython
Expand Down
2 changes: 0 additions & 2 deletions .github/workflows/wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,6 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: "3.x"
cache: pip
cache-dependency-path: "Makefile"

- run: make sdist

Expand Down
9 changes: 7 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.1
rev: v0.8.4
hooks:
- id: ruff
args: [--exit-non-zero-on-fix]
Expand All @@ -24,7 +24,7 @@ repos:
exclude: (Makefile$|\.bat$|\.cmake$|\.eps$|\.fits$|\.gd$|\.opt$)

- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v19.1.4
rev: v19.1.5
hooks:
- id: clang-format
types: [c]
Expand Down Expand Up @@ -56,6 +56,11 @@ repos:
- id: check-readthedocs
- id: check-renovate

- repo: https://github.com/woodruffw/zizmor-pre-commit
rev: v0.10.0
hooks:
- id: zizmor

- repo: https://github.com/sphinx-contrib/sphinx-lint
rev: v1.0.0
hooks:
Expand Down
Binary file added Tests/images/jfif_unit_cm.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions Tests/test_file_jpeg.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@ def test(xdpi: int, ydpi: int | None = None) -> tuple[int, int] | None:
assert test(100, 200) == (100, 200)
assert test(0) is None # square pixels

def test_dpi_jfif_cm(self):
with Image.open("Tests/images/jfif_unit_cm.jpg") as im:
assert im.info["dpi"] == (2.54, 5.08)

@mark_if_feature_version(
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
)
Expand Down
12 changes: 12 additions & 0 deletions Tests/test_file_jpeg2k.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,18 @@ def test_cmyk() -> None:
assert im.getpixel((0, 0)) == (185, 134, 0, 0)


@pytest.mark.skipif(
not os.path.exists(EXTRA_DIR), reason="Extra image files not installed"
)
@skip_unless_feature_version("jpg_2000", "2.5.3")
def test_cmyk_save() -> None:
with Image.open(f"{EXTRA_DIR}/issue205.jp2") as jp2:
assert jp2.mode == "CMYK"

im = roundtrip(jp2)
assert_image_equal(im, jp2)


@pytest.mark.parametrize("ext", (".j2k", ".jp2"))
def test_16bit_monochrome_has_correct_mode(ext: str) -> None:
with Image.open("Tests/images/16bit.cropped" + ext) as im:
Expand Down
4 changes: 4 additions & 0 deletions Tests/test_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,10 @@ def test_empty_get_ifd(self) -> None:
ifd[36864] = b"0220"
assert exif.get_ifd(0x8769) == {36864: b"0220"}

reloaded_exif = Image.Exif()
reloaded_exif.load(exif.tobytes())
assert reloaded_exif.get_ifd(0x8769) == {36864: b"0220"}

@mark_if_feature_version(
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
)
Expand Down
8 changes: 8 additions & 0 deletions docs/deprecations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,14 @@ deprecated and will be removed in Pillow 12 (2025-10-15). They were used for obt
raw pointers to ``ImagingCore`` internals. To interact with C code, you can use
``Image.Image.getim()``, which returns a ``Capsule`` object.

ExifTags.IFD.Makernote
^^^^^^^^^^^^^^^^^^^^^^

.. deprecated:: 11.1.0

``ExifTags.IFD.Makernote`` has been deprecated. Instead, use
``ExifTags.IFD.MakerNote``.

Removed features
----------------

Expand Down
17 changes: 13 additions & 4 deletions docs/handbook/image-file-formats.rst
Original file line number Diff line number Diff line change
Expand Up @@ -572,10 +572,19 @@ JPEG 2000
Pillow reads and writes JPEG 2000 files containing ``L``, ``LA``, ``RGB``,
``RGBA``, or ``YCbCr`` data. When reading, ``YCbCr`` data is converted to
``RGB`` or ``RGBA`` depending on whether or not there is an alpha channel.
Beginning with version 8.3.0, Pillow can read (but not write) ``RGB``,
``RGBA``, and ``YCbCr`` images with subsampled components. Pillow supports
JPEG 2000 raw codestreams (``.j2k`` files), as well as boxed JPEG 2000 files
(``.jp2`` or ``.jpx`` files).

.. versionadded:: 8.3.0
Pillow can read (but not write) ``RGB``, ``RGBA``, and ``YCbCr`` images with
subsampled components.

.. versionadded:: 10.4.0
Pillow can read ``CMYK`` images with OpenJPEG 2.5.1 and later.

.. versionadded:: 11.1.0
Pillow can write ``CMYK`` images with OpenJPEG 2.5.3 and later.

Pillow supports JPEG 2000 raw codestreams (``.j2k`` files), as well as boxed
JPEG 2000 files (``.jp2`` or ``.jpx`` files).

When loading, if you set the ``mode`` on the image prior to the
:py:meth:`~PIL.Image.Image.load` method being invoked, you can ask Pillow to
Expand Down
34 changes: 28 additions & 6 deletions docs/releasenotes/11.1.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,35 @@ TODO
Deprecations
============

TODO
^^^^
ExifTags.IFD.Makernote
^^^^^^^^^^^^^^^^^^^^^^

TODO
``ExifTags.IFD.Makernote`` has been deprecated. Instead, use
``ExifTags.IFD.MakerNote``.

API Changes
===========

TODO
^^^^
Writing XMP bytes to JPEG and MPO
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

TODO
Pillow 11.0.0 added writing XMP data to JPEG and MPO images::

im.info["xmp"] = b"test"
im.save("out.jpg")

However, this meant that XMP data was automatically kept from an opened image,
which is inconsistent with the rest of Pillow's behaviour. This functionality
has been removed. To write XMP data, the ``xmp`` argument can still be used for
JPEG files::

im.save("out.jpg", xmp=b"test")

To save XMP data to the second frame of an MPO image, ``encoderinfo`` can now
be used::

second_im.encoderinfo = {"xmp": b"test"}
im.save("out.mpo", save_all=True, append_images=[second_im])

API Additions
=============
Expand All @@ -58,6 +75,11 @@ Reading JPEG 2000 comments
When opening a JPEG 2000 image, the comment may now be read into
:py:attr:`~PIL.Image.Image.info` for J2K images, not just JP2 images.

Saving JPEG 2000 CMYK images
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

With OpenJPEG 2.5.3 or later, Pillow can now save CMYK images as JPEG 2000 files.

zlib-ng in wheels
^^^^^^^^^^^^^^^^^

Expand Down
1 change: 1 addition & 0 deletions src/PIL/ExifTags.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ class IFD(IntEnum):
Exif = 0x8769
GPSInfo = 0x8825
MakerNote = 0x927C
Makernote = 0x927C # Deprecated
Interop = 0xA005
IFD1 = -1

Expand Down
3 changes: 3 additions & 0 deletions src/PIL/Image.py
Original file line number Diff line number Diff line change
Expand Up @@ -3966,6 +3966,9 @@ def tobytes(self, offset: int = 8) -> bytes:

head = self._get_head()
ifd = TiffImagePlugin.ImageFileDirectory_v2(ifh=head)
for tag, ifd_dict in self._ifds.items():
if tag not in self:
ifd[tag] = ifd_dict
for tag, value in self.items():
if tag in [
ExifTags.IFD.Exif,
Expand Down
3 changes: 3 additions & 0 deletions src/PIL/JpegImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ def APP(self: JpegImageFile, marker: int) -> None:
else:
if jfif_unit == 1:
self.info["dpi"] = jfif_density
elif jfif_unit == 2: # cm
# 1 dpcm = 2.54 dpi
self.info["dpi"] = tuple(d * 2.54 for d in jfif_density)
self.info["jfif_unit"] = jfif_unit
self.info["jfif_density"] = jfif_density
elif marker == 0xFFE1 and s[:6] == b"Exif\0\0":
Expand Down
19 changes: 8 additions & 11 deletions src/PIL/TiffImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -1563,17 +1563,6 @@ def _setup(self) -> None:
# fillorder==2 modes have a corresponding
# fillorder=1 mode
self._mode, rawmode = OPEN_INFO[key]
# libtiff always returns the bytes in native order.
# we're expecting image byte order. So, if the rawmode
# contains I;16, we need to convert from native to image
# byte order.
if rawmode == "I;16":
rawmode = "I;16N"
if ";16B" in rawmode:
rawmode = rawmode.replace(";16B", ";16N")
if ";16L" in rawmode:
rawmode = rawmode.replace(";16L", ";16N")

# YCbCr images with new jpeg compression with pixels in one plane
# unpacked straight into RGB values
if (
Expand All @@ -1582,6 +1571,14 @@ def _setup(self) -> None:
and self._planar_configuration == 1
):
rawmode = "RGB"
# libtiff always returns the bytes in native order.
# we're expecting image byte order. So, if the rawmode
# contains I;16, we need to convert from native to image
# byte order.
elif rawmode == "I;16":
rawmode = "I;16N"
elif rawmode.endswith(";16B") or rawmode.endswith(";16L"):
rawmode = rawmode[:-1] + "N"

# Offset in the tile tuple is 0, we go from 0,0 to
# w,h, and we only do this once -- eds
Expand Down
7 changes: 7 additions & 0 deletions src/libImaging/Jpeg2KEncode.c
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,13 @@ j2k_encode_entry(Imaging im, ImagingCodecState state) {
components = 4;
color_space = OPJ_CLRSPC_SRGB;
pack = j2k_pack_rgba;
#if ((OPJ_VERSION_MAJOR == 2 && OPJ_VERSION_MINOR == 5 && OPJ_VERSION_BUILD >= 3) || \
(OPJ_VERSION_MAJOR == 2 && OPJ_VERSION_MINOR > 5) || OPJ_VERSION_MAJOR > 2)
} else if (strcmp(im->mode, "CMYK") == 0) {
components = 4;
color_space = OPJ_CLRSPC_CMYK;
pack = j2k_pack_rgba;
#endif
} else {
state->errcode = IMAGING_CODEC_BROKEN;
state->state = J2K_STATE_FAILED;
Expand Down
2 changes: 2 additions & 0 deletions src/libImaging/Unpack.c
Original file line number Diff line number Diff line change
Expand Up @@ -1695,6 +1695,7 @@ static struct {

#ifdef WORDS_BIGENDIAN
{"RGB", "RGB;16N", 48, unpackRGB16B},
{"RGB", "RGBX;16N", 64, unpackRGBA16B},
{"RGBA", "RGBa;16N", 64, unpackRGBa16B},
{"RGBA", "RGBA;16N", 64, unpackRGBA16B},
{"RGBX", "RGBX;16N", 64, unpackRGBA16B},
Expand All @@ -1708,6 +1709,7 @@ static struct {
{"RGBA", "A;16N", 16, band316B},
#else
{"RGB", "RGB;16N", 48, unpackRGB16L},
{"RGB", "RGBX;16N", 64, unpackRGBA16L},
{"RGBA", "RGBa;16N", 64, unpackRGBa16L},
{"RGBA", "RGBA;16N", 64, unpackRGBA16L},
{"RGBX", "RGBX;16N", 64, unpackRGBA16L},
Expand Down

0 comments on commit 9c0bd08

Please sign in to comment.