Skip to content

Commit

Permalink
Merge branch 'main' into int_def
Browse files Browse the repository at this point in the history
  • Loading branch information
radarhere committed Jun 13, 2023
2 parents f6b516b + 8f3ccff commit 7ccc420
Show file tree
Hide file tree
Showing 40 changed files with 342 additions and 187 deletions.
5 changes: 3 additions & 2 deletions .ci/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ set -e
if [[ $(uname) != CYGWIN* ]]; then
sudo apt-get -qq install libfreetype6-dev liblcms2-dev python3-tk\
ghostscript libffi-dev libjpeg-turbo-progs libopenjp2-7-dev\
cmake meson imagemagick libharfbuzz-dev libfribidi-dev
cmake meson imagemagick libharfbuzz-dev libfribidi-dev\
sway wl-clipboard
fi

python3 -m pip install --upgrade pip
Expand All @@ -41,7 +42,7 @@ if [[ $(uname) != CYGWIN* ]]; then
if ! [ "$GHA_PYTHON_VERSION" == "3.12-dev" ]; then python3 -m pip install numpy ; fi

# PyQt6 doesn't support PyPy3
if [[ $GHA_PYTHON_VERSION == 3.* ]]; then
if [[ "$GHA_PYTHON_VERSION" != "3.12-dev" && $GHA_PYTHON_VERSION == 3.* ]]; then
sudo apt-get -qq install libegl1 libxcb-cursor0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-shape0 libxkbcommon-x11-0
python3 -m pip install pyqt6
fi
Expand Down
4 changes: 0 additions & 4 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@ indent_style = space

trim_trailing_whitespace = true

[*.rst]
# Four-space indentation
indent_size = 4

[*.yml]
# Two-space indentation
indent_size = 2
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/test-docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ jobs:
centos-stream-8-amd64,
centos-stream-9-amd64,
debian-11-bullseye-x86,
debian-12-bookworm-x86,
fedora-37-amd64,
fedora-38-amd64,
gentoo,
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/test-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ jobs:
- name: Print build system information
run: python3 .github/workflows/system-info.py

- name: python3 -m pip install wheel pytest pytest-cov pytest-timeout defusedxml
run: python3 -m pip install wheel pytest pytest-cov pytest-timeout defusedxml
- name: python3 -m pip install setuptools wheel pytest pytest-cov pytest-timeout defusedxml
run: python3 -m pip install setuptools wheel pytest pytest-cov pytest-timeout defusedxml

- name: Install dependencies
id: install
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,9 @@ jobs:
python3 -m pip install pytest-reverse
fi
if [ "${{ matrix.os }}" = "ubuntu-latest" ]; then
xvfb-run -s '-screen 0 1024x768x24' .ci/test.sh
xvfb-run -s '-screen 0 1024x768x24' sway&
export WAYLAND_DISPLAY=wayland-1
.ci/test.sh
else
.ci/test.sh
fi
Expand Down
3 changes: 0 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ repos:
hooks:
- id: black
args: [--target-version=py38]
# Only .py files, until https://github.com/psf/black/issues/402 resolved
files: \.py$
types: []

- repo: https://github.com/PyCQA/isort
rev: 5.12.0
Expand Down
24 changes: 24 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,30 @@ Changelog (Pillow)
10.0.0 (unreleased)
-------------------

- Fixed combining single duration across duplicate APNG frames #7146
[radarhere]

- Remove temporary file when error is raised #7148
[radarhere]

- Do not use temporary file when grabbing clipboard on Linux #7200
[radarhere]

- If the clipboard fails to open on Windows, wait and try again #7141
[radarhere]

- Fixed saving multiple 1 mode frames to GIF #7181
[radarhere]

- Replaced absolute PIL import with relative import #7173
[radarhere]

- Replaced deprecated Py_FileSystemDefaultEncoding for Python >= 3.12 #7192
[radarhere]

- Improved wl-paste mimetype handling in ImageGrab #7094
[rrcgat, radarhere]

- Added _repr_jpeg_() for IPython display_jpeg #7135
[n3011, radarhere, nulano]

Expand Down
11 changes: 11 additions & 0 deletions Tests/test_file_apng.py
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,17 @@ def test_apng_save_duration_loop(tmp_path):
assert im.info.get("duration") == 750


def test_apng_save_duplicate_duration(tmp_path):
test_file = str(tmp_path / "temp.png")
frame = Image.new("RGB", (1, 1))

# Test a single duration is correctly combined across duplicate frames
frame.save(test_file, save_all=True, append_images=[frame, frame], duration=500)
with Image.open(test_file) as im:
assert im.n_frames == 1
assert im.info.get("duration") == 1500


def test_apng_save_disposal(tmp_path):
test_file = str(tmp_path / "temp.png")
size = (128, 64)
Expand Down
13 changes: 13 additions & 0 deletions Tests/test_file_gif.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,19 @@ def test_roundtrip_save_all(tmp_path):
assert reread.n_frames == 5


def test_roundtrip_save_all_1(tmp_path):
out = str(tmp_path / "temp.gif")
im = Image.new("1", (1, 1))
im2 = Image.new("1", (1, 1), 1)
im.save(out, save_all=True, append_images=[im2])

with Image.open(out) as reloaded:
assert reloaded.getpixel((0, 0)) == 0

reloaded.seek(1)
assert reloaded.getpixel((0, 0)) == 255


@pytest.mark.parametrize(
"path, mode",
(
Expand Down
9 changes: 8 additions & 1 deletion Tests/test_file_tiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,17 @@ def test_mac_tiff(self):

assert_image_similar_tofile(im, "Tests/images/pil136.png", 1)

def test_bigtiff(self):
def test_bigtiff(self, tmp_path):
with Image.open("Tests/images/hopper_bigtiff.tif") as im:
assert_image_equal_tofile(im, "Tests/images/hopper.tif")

with Image.open("Tests/images/hopper_bigtiff.tif") as im:
# multistrip support not yet implemented
del im.tag_v2[273]

outfile = str(tmp_path / "temp.tif")
im.save(outfile, save_all=True, append_images=[im], tiffinfo=im.tag_v2)

def test_set_legacy_api(self):
ifd = TiffImagePlugin.ImageFileDirectory_v2()
with pytest.raises(Exception) as e:
Expand Down
8 changes: 8 additions & 0 deletions Tests/test_image_putpalette.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ def palette(mode):
with pytest.raises(ValueError):
palette("YCbCr")

with Image.open("Tests/images/hopper_gray.jpg") as im:
assert im.mode == "L"
im.putpalette(list(range(256)) * 3)

with Image.open("Tests/images/la.tga") as im:
assert im.mode == "LA"
im.putpalette(list(range(256)) * 3)


def test_imagepalette():
im = hopper("P")
Expand Down
5 changes: 5 additions & 0 deletions Tests/test_imagefont.py
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,11 @@ def test_default_font():
assert_image_equal_tofile(im, "Tests/images/default_font.png")


@pytest.mark.parametrize("mode", (None, "1", "RGBA"))
def test_getbbox(font, mode):
assert (0, 4, 12, 16) == font.getbbox("A", mode)


def test_getbbox_empty(font):
# issue #2614, should not crash.
assert (0, 0, 0, 0) == font.getbbox("")
Expand Down
15 changes: 15 additions & 0 deletions Tests/test_imagegrab.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,18 @@ def test_grabclipboard_png(self):

im = ImageGrab.grabclipboard()
assert_image_equal_tofile(im, "Tests/images/hopper.png")

@pytest.mark.skipif(
(
sys.platform != "linux"
or not all(shutil.which(cmd) for cmd in ("wl-paste", "wl-copy"))
),
reason="Linux with wl-clipboard only",
)
@pytest.mark.parametrize("ext", ("gif", "png", "ico"))
def test_grabclipboard_wl_clipboard(self, ext):
image_path = "Tests/images/hopper." + ext
with open(image_path, "rb") as fp:
subprocess.call(["wl-copy"], stdin=fp)
im = ImageGrab.grabclipboard()
assert_image_equal_tofile(im, image_path)
4 changes: 2 additions & 2 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Documentation: https://docs.codecov.io/docs/codecov-yaml
# Documentation: https://docs.codecov.com/docs/codecov-yaml

codecov:
# Avoid "Missing base report" due to committing CHANGES.rst with "[CI skip]"
# https://github.com/codecov/support/issues/363
# https://docs.codecov.io/docs/comparing-commits
# https://docs.codecov.com/docs/comparing-commits
allow_coverage_offsets: true

comment: false
Expand Down
8 changes: 4 additions & 4 deletions docs/Guardfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from livereload.compiler import shell
from livereload.task import Task

Task.add('*.rst', shell('make html'))
Task.add('*/*.rst', shell('make html'))
Task.add('Makefile', shell('make html'))
Task.add('conf.py', shell('make html'))
Task.add("*.rst", shell("make html"))
Task.add("*/*.rst", shell("make html"))
Task.add("Makefile", shell("make html"))
Task.add("conf.py", shell("make html"))
5 changes: 2 additions & 3 deletions docs/handbook/concepts.rst
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,8 @@ in the upper left corner. Note that the coordinates refer to the implied pixel
corners; the centre of a pixel addressed as (0, 0) actually lies at (0.5, 0.5).

Coordinates are usually passed to the library as 2-tuples (x, y). Rectangles
are represented as 4-tuples, with the upper left corner given first. For
example, a rectangle covering all of an 800x600 pixel image is written as (0,
0, 800, 600).
are represented as 4-tuples, (x1, y1, x2, y2), with the upper left corner given
first.

Palette
-------
Expand Down
2 changes: 2 additions & 0 deletions docs/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,8 @@ These platforms are built and tested for every change.
+----------------------------------+----------------------------+---------------------+
| Debian 11 Bullseye | 3.9 | x86 |
+----------------------------------+----------------------------+---------------------+
| Debian 12 Bookworm | 3.11 | x86 |
+----------------------------------+----------------------------+---------------------+
| Fedora 37 | 3.11 | x86-64 |
+----------------------------------+----------------------------+---------------------+
| Fedora 38 | 3.11 | x86-64 |
Expand Down
8 changes: 7 additions & 1 deletion src/PIL/EpsImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,13 @@ def Ghostscript(tile, size, fp, scale=1, transparency=False):

if gs_windows_binary is not None:
if not gs_windows_binary:
try:
os.unlink(outfile)
if infile_temp:
os.unlink(infile_temp)
except OSError:
pass

msg = "Unable to locate Ghostscript on paths"
raise OSError(msg)
command[0] = gs_windows_binary
Expand Down Expand Up @@ -354,7 +361,6 @@ def check_required_header_comments():
check_required_header_comments()

if not self._size:
self._size = 1, 1 # errors if this isn't set. why (1,1)?
msg = "cannot determine EPS bounding box"
raise OSError(msg)

Expand Down
2 changes: 1 addition & 1 deletion src/PIL/GifImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -879,7 +879,7 @@ def _get_palette_bytes(im):
:param im: Image object
:returns: Bytes, len<=768 suitable for inclusion in gif header
"""
return im.palette.palette
return im.palette.palette if im.palette else b""


def _get_background(im, info_background):
Expand Down
4 changes: 2 additions & 2 deletions src/PIL/IcnsImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@
import struct
import sys

from PIL import Image, ImageFile, PngImagePlugin, features
from . import Image, ImageFile, PngImagePlugin, features

enable_jpeg2k = features.check_codec("jpg_2000")
if enable_jpeg2k:
from PIL import Jpeg2KImagePlugin
from . import Jpeg2KImagePlugin

MAGIC = b"icns"
HEADERSIZE = 8
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/Image.py
Original file line number Diff line number Diff line change
Expand Up @@ -1254,7 +1254,7 @@ def _expand(self, xmargin, ymargin=None):
if ymargin is None:
ymargin = xmargin
self.load()
return self._new(self.im.expand(xmargin, ymargin, 0))
return self._new(self.im.expand(xmargin, ymargin))

def filter(self, filter):
"""
Expand Down
6 changes: 3 additions & 3 deletions src/PIL/ImageCms.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@
import sys
from enum import IntEnum

from PIL import Image
from . import Image

try:
from PIL import _imagingcms
from . import _imagingcms
except ImportError as ex:
# Allow error import for doc purposes, but error out when accessing
# anything in core.
Expand Down Expand Up @@ -271,7 +271,7 @@ def get_display_profile(handle=None):
if sys.platform != "win32":
return None

from PIL import ImageWin
from . import ImageWin

if isinstance(handle, ImageWin.HDC):
profile = core.get_display_profile_win32(handle, 1)
Expand Down
7 changes: 4 additions & 3 deletions src/PIL/ImageFilter.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,18 @@ def filter(self, image):

class Kernel(BuiltinFilter):
"""
Create a convolution kernel. The current version only
Create a convolution kernel. The current version only
supports 3x3 and 5x5 integer and floating point kernels.
In the current version, kernels can only be applied to
"L" and "RGB" images.
:param size: Kernel size, given as (width, height). In the current
version, this must be (3,3) or (5,5).
:param kernel: A sequence containing kernel weights.
:param kernel: A sequence containing kernel weights. The kernel will
be flipped vertically before being applied to the image.
:param scale: Scale factor. If given, the result for each pixel is
divided by this value. The default is the sum of the
divided by this value. The default is the sum of the
kernel weights.
:param offset: Offset. If given, this value is added to the result,
after it has been divided by the scale factor.
Expand Down
Loading

0 comments on commit 7ccc420

Please sign in to comment.