Skip to content

Commit

Permalink
Merge branch 'main' into image_mode_size_delegation
Browse files Browse the repository at this point in the history
  • Loading branch information
radarhere authored Jul 31, 2023
2 parents 88cad58 + c1c474a commit e311a46
Show file tree
Hide file tree
Showing 65 changed files with 252 additions and 183 deletions.
20 changes: 13 additions & 7 deletions .github/workflows/test-cygwin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,17 +76,23 @@ jobs:
with:
dirs: 'C:\cygwin\bin;C:\cygwin\lib\lapack'

- name: Select Python version
run: |
ln -sf c:/cygwin/bin/python3.${{ matrix.python-minor-version }} c:/cygwin/bin/python3
- name: Get latest NumPy version
id: latest-numpy
shell: bash.exe -eo pipefail -o igncr "{0}"
run: |
python3 -m pip list --outdated | grep numpy | sed -r 's/ +/ /g' | cut -d ' ' -f 3 | sed 's/^/version=/' >> $GITHUB_OUTPUT
- name: pip cache
uses: actions/cache@v3
with:
path: 'C:\cygwin\home\runneradmin\.cache\pip'
key: ${{ runner.os }}-cygwin-pip3.${{ matrix.python-minor-version }}-${{ hashFiles('.ci/install.sh') }}
key: ${{ runner.os }}-cygwin-pip3.${{ matrix.python-minor-version }}-numpy${{ steps.latest-numpy.outputs.version }}-${{ hashFiles('.ci/install.sh') }}
restore-keys: |
${{ runner.os }}-cygwin-pip3.${{ matrix.python-minor-version }}-
- name: Select Python version
run: |
ln -sf c:/cygwin/bin/python3.${{ matrix.python-minor-version }} c:/cygwin/bin/python3
${{ runner.os }}-cygwin-pip3.${{ matrix.python-minor-version }}-numpy${{ steps.latest-numpy.outputs.version }}-
- name: Build system information
run: |
Expand All @@ -96,7 +102,7 @@ jobs:
run: |
bash.exe .ci/install.sh
- name: Install a different NumPy
- name: Install latest NumPy
shell: dash.exe -l "{0}"
run: |
python3 -m pip install -U numpy
Expand Down
6 changes: 6 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ Changelog (Pillow)
10.1.0 (unreleased)
-------------------

- Silence exceptions in _repr_jpeg_ and _repr_png_ #7266
[mtreinish, radarhere]

- Do not use transparency when saving GIF if it has been removed when normalizing mode #7284
[radarhere]

- Fix missing symbols when libtiff depends on libjpeg #7270
[heitbaum]

Expand Down
15 changes: 15 additions & 0 deletions Tests/test_file_gif.py
Original file line number Diff line number Diff line change
Expand Up @@ -1086,6 +1086,21 @@ def test_transparent_optimize(tmp_path):
assert reloaded.info["transparency"] == reloaded.getpixel((252, 0))


def test_removed_transparency(tmp_path):
out = str(tmp_path / "temp.gif")
im = Image.new("RGB", (256, 1))

for x in range(256):
im.putpixel((x, 0), (x, 0, 0))

im.info["transparency"] = (255, 255, 255)
with pytest.warns(UserWarning):
im.save(out)

with Image.open(out) as reloaded:
assert "transparency" not in reloaded.info


def test_rgb_transparency(tmp_path):
out = str(tmp_path / "temp.gif")

Expand Down
5 changes: 2 additions & 3 deletions Tests/test_file_jpeg.py
Original file line number Diff line number Diff line change
Expand Up @@ -929,11 +929,10 @@ def test_repr_jpeg(self):
assert repr_jpeg.format == "JPEG"
assert_image_similar(im, repr_jpeg, 17)

def test_repr_jpeg_error(self):
def test_repr_jpeg_error_returns_none(self):
im = hopper("F")

with pytest.raises(ValueError):
im._repr_jpeg_()
assert im._repr_jpeg_() is None


@pytest.mark.skipif(not is_win32(), reason="Windows only")
Expand Down
18 changes: 8 additions & 10 deletions Tests/test_file_jpeg2k.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,17 +274,15 @@ def test_sgnd(tmp_path):
assert reloaded_signed.getpixel((0, 0)) == 128


def test_rgba():
@pytest.mark.parametrize("ext", (".j2k", ".jp2"))
def test_rgba(ext):
# Arrange
with Image.open("Tests/images/rgb_trns_ycbc.j2k") as j2k:
with Image.open("Tests/images/rgb_trns_ycbc.jp2") as jp2:
# Act
j2k.load()
jp2.load()

# Assert
assert j2k.mode == "RGBA"
assert jp2.mode == "RGBA"
with Image.open("Tests/images/rgb_trns_ycbc" + ext) as im:
# Act
im.load()

# Assert
assert im.mode == "RGBA"


@pytest.mark.parametrize("ext", (".j2k", ".jp2"))
Expand Down
5 changes: 2 additions & 3 deletions Tests/test_file_png.py
Original file line number Diff line number Diff line change
Expand Up @@ -532,11 +532,10 @@ def test_repr_png(self):
assert repr_png.format == "PNG"
assert_image_equal(im, repr_png)

def test_repr_png_error(self):
def test_repr_png_error_returns_none(self):
im = hopper("F")

with pytest.raises(ValueError):
im._repr_png_()
assert im._repr_png_() is None

def test_chunk_order(self, tmp_path):
with Image.open("Tests/images/icc_profile.png") as im:
Expand Down
6 changes: 6 additions & 0 deletions Tests/test_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@ def test_width_height(self):
with pytest.raises(AttributeError):
im.size = (3, 4)

def test_set_mode(self):
im = Image.new("RGB", (1, 1))

with pytest.raises(AttributeError):
im.mode = "P"

def test_invalid_image(self):
im = io.BytesIO(b"")
with pytest.raises(UnidentifiedImageError):
Expand Down
4 changes: 2 additions & 2 deletions Tests/test_imagefile.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ def test_no_format(self):

class DummyImageFile(ImageFile.ImageFile):
def _open(self):
self.mode = "RGB"
self._mode = "RGB"
self._size = (1, 1)

im = DummyImageFile(buf)
Expand Down Expand Up @@ -217,7 +217,7 @@ def cleanup(self):
class MockImageFile(ImageFile.ImageFile):
def _open(self):
self.rawmode = "RGBA"
self.mode = "RGBA"
self._mode = "RGBA"
self._size = (200, 200)
self.tile = [("MOCK", (xoff, yoff, xoff + xsize, yoff + ysize), 32, None)]

Expand Down
4 changes: 2 additions & 2 deletions Tests/test_pickle.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,13 @@ def test_pickle_la_mode_with_palette(tmp_path):

# Act / Assert
for protocol in range(0, pickle.HIGHEST_PROTOCOL + 1):
im.mode = "LA"
im._mode = "LA"
with open(filename, "wb") as f:
pickle.dump(im, f, protocol)
with open(filename, "rb") as f:
loaded_im = pickle.load(f)

im.mode = "PA"
im._mode = "PA"
assert im == loaded_im


Expand Down
2 changes: 1 addition & 1 deletion docs/example/DdsImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ def _open(self):

flags, height, width = struct.unpack("<3I", header.read(12))
self._size = (width, height)
self.mode = "RGBA"
self._mode = "RGBA"

pitch, depth, mipmaps = struct.unpack("<3I", header.read(12))
struct.unpack("<11I", header.read(44)) # reserved
Expand Down
4 changes: 4 additions & 0 deletions docs/handbook/image-file-formats.rst
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,10 @@ PPM
Pillow reads and writes PBM, PGM, PPM and PNM files containing ``1``, ``L``, ``I`` or
``RGB`` data.

"Raw" (P4 to P6) formats can be read, and are used when writing.

Since Pillow 9.2.0, "plain" (P1 to P3) formats can be read as well.

SGI
^^^

Expand Down
6 changes: 3 additions & 3 deletions docs/handbook/writing-your-own-image-plugin.rst
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ true color.
# mode setting
bits = int(header[3])
if bits == 1:
self.mode = "1"
self._mode = "1"
elif bits == 8:
self.mode = "L"
self._mode = "L"
elif bits == 24:
self.mode = "RGB"
self._mode = "RGB"
else:
msg = "unknown number of bits"
raise SyntaxError(msg)
Expand Down
15 changes: 8 additions & 7 deletions docs/newer-versions.csv
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
Python,3.11,3.10,3.9,3.8,3.7,3.6,3.5
Pillow >= 10,Yes,Yes,Yes,Yes,,,
Pillow 9.3 - 9.5,Yes,Yes,Yes,Yes,Yes,,
Pillow 9.0 - 9.2,,Yes,Yes,Yes,Yes,,
Pillow 8.3.2 - 8.4,,Yes,Yes,Yes,Yes,Yes,
Pillow 8.0 - 8.3.1,,,Yes,Yes,Yes,Yes,
Pillow 7.0 - 7.2,,,,Yes,Yes,Yes,Yes
Python,3.12,3.11,3.10,3.9,3.8,3.7,3.6,3.5
Pillow >= 10.1,Yes,Yes,Yes,Yes,Yes,,,
Pillow 10.0,,Yes,Yes,Yes,Yes,,,
Pillow 9.3 - 9.5,,Yes,Yes,Yes,Yes,Yes,,
Pillow 9.0 - 9.2,,,Yes,Yes,Yes,Yes,,
Pillow 8.3.2 - 8.4,,,Yes,Yes,Yes,Yes,Yes,
Pillow 8.0 - 8.3.1,,,,Yes,Yes,Yes,Yes,
Pillow 7.0 - 7.2,,,,,Yes,Yes,Yes,Yes
2 changes: 1 addition & 1 deletion docs/reference/ImageDraw.rst
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,7 @@ Methods
It should be a `BCP 47 language code`_.
Requires libraqm.
:param embedded_color: Whether to use font embedded color glyphs (COLR, CBDT, SBIX).
:return: Width for horizontal, height for vertical text.
:return: Either width for horizontal text, or height for vertical text.

.. py:method:: ImageDraw.textbbox(xy, text, font=None, anchor=None, spacing=4, align="left", direction=None, features=None, language=None, stroke_width=0, embedded_color=False)
Expand Down
54 changes: 54 additions & 0 deletions docs/releasenotes/10.1.0.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
10.1.0
------

Backwards Incompatible Changes
==============================

Setting image mode
^^^^^^^^^^^^^^^^^^

If you attempt to set the mode of an image directly, e.g.
``im.mode = "RGBA"``, you will now receive an ``AttributeError``. This is
not about removing existing functionality, but instead about raising an
explicit error to prevent later consequences. The ``convert`` method is the
correct way to change an image's mode.

Deprecations
============

TODO
^^^^

TODO

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

TODO
^^^^

TODO

API Additions
=============

TODO
^^^^

TODO

Security
========

TODO
^^^^

TODO

Other Changes
=============

TODO
^^^^

TODO
1 change: 1 addition & 0 deletions docs/releasenotes/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ expected to be backported to earlier versions.
.. toctree::
:maxdepth: 2

10.1.0
10.0.0
9.5.0
9.4.0
Expand Down
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ classifiers =
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: 3.11
Programming Language :: Python :: 3.12
Programming Language :: Python :: Implementation :: CPython
Programming Language :: Python :: Implementation :: PyPy
Topic :: Multimedia :: Graphics
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def get_version():
ZLIB_ROOT = None
FUZZING_BUILD = "LIB_FUZZING_ENGINE" in os.environ

if sys.platform == "win32" and sys.version_info >= (3, 12):
if sys.platform == "win32" and sys.version_info >= (3, 13):
import atexit

atexit.register(
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/BlpImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ def _open(self):
msg = f"Bad BLP magic {repr(self.magic)}"
raise BLPFormatError(msg)

self.mode = "RGBA" if self._blp_alpha_depth else "RGB"
self._mode = "RGBA" if self._blp_alpha_depth else "RGB"
self.tile = [(decoder, (0, 0) + self.size, 0, (self.mode, 0, 1))]


Expand Down
10 changes: 5 additions & 5 deletions src/PIL/BmpImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ def _bitmap(self, header=0, offset=0):
offset += 4 * file_info["colors"]

# ---------------------- Check bit depth for unusual unsupported values
self.mode, raw_mode = BIT2MODE.get(file_info["bits"], (None, None))
self._mode, raw_mode = BIT2MODE.get(file_info["bits"], (None, None))
if self.mode is None:
msg = f"Unsupported BMP pixel depth ({file_info['bits']})"
raise OSError(msg)
Expand Down Expand Up @@ -200,7 +200,7 @@ def _bitmap(self, header=0, offset=0):
and file_info["rgba_mask"] in SUPPORTED[file_info["bits"]]
):
raw_mode = MASK_MODES[(file_info["bits"], file_info["rgba_mask"])]
self.mode = "RGBA" if "A" in raw_mode else self.mode
self._mode = "RGBA" if "A" in raw_mode else self.mode
elif (
file_info["bits"] in (24, 16)
and file_info["rgb_mask"] in SUPPORTED[file_info["bits"]]
Expand All @@ -214,7 +214,7 @@ def _bitmap(self, header=0, offset=0):
raise OSError(msg)
elif file_info["compression"] == self.RAW:
if file_info["bits"] == 32 and header == 22: # 32-bit .cur offset
raw_mode, self.mode = "BGRA", "RGBA"
raw_mode, self._mode = "BGRA", "RGBA"
elif file_info["compression"] in (self.RLE8, self.RLE4):
decoder_name = "bmp_rle"
else:
Expand Down Expand Up @@ -245,10 +245,10 @@ def _bitmap(self, header=0, offset=0):

# ------- If all colors are grey, white or black, ditch palette
if greyscale:
self.mode = "1" if file_info["colors"] == 2 else "L"
self._mode = "1" if file_info["colors"] == 2 else "L"
raw_mode = self.mode
else:
self.mode = "P"
self._mode = "P"
self.palette = ImagePalette.raw(
"BGRX" if padding == 4 else "BGR", palette
)
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/BufrStubImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def _open(self):
self.fp.seek(offset)

# make something up
self.mode = "F"
self._mode = "F"
self._size = 1, 1

loader = self._load()
Expand Down
Loading

0 comments on commit e311a46

Please sign in to comment.