Skip to content

Commit

Permalink
Merge branch 'main' into init
Browse files Browse the repository at this point in the history
  • Loading branch information
radarhere committed Oct 17, 2023
2 parents 50a5bc8 + f790878 commit d29383b
Show file tree
Hide file tree
Showing 38 changed files with 724 additions and 184 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/cifuzz.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ name: CIFuzz

on:
push:
branches:
- "**"
paths:
- ".github/workflows/cifuzz.yml"
- "**.c"
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ name: Docs

on:
push:
branches:
- "**"
paths:
- ".github/workflows/docs.yml"
- "docs/**"
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/test-cygwin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ name: Test Cygwin

on:
push:
branches:
- "**"
paths-ignore:
- ".github/workflows/docs.yml"
- ".github/workflows/wheels*"
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/test-docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ name: Test Docker

on:
push:
branches:
- "**"
paths-ignore:
- ".github/workflows/docs.yml"
- ".github/workflows/wheels*"
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/test-mingw.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ name: Test MinGW

on:
push:
branches:
- "**"
paths-ignore:
- ".github/workflows/docs.yml"
- ".github/workflows/wheels*"
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/test-valgrind.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
name: Test Valgrind

# like the docker tests, but running valgrind only on *.c/*.h changes.
# like the Docker tests, but running valgrind only on *.c/*.h changes.

on:
push:
branches:
- "**"
paths:
- ".github/workflows/test-valgrind.yml"
- "**.c"
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ name: Test

on:
push:
branches:
- "**"
paths-ignore:
- ".github/workflows/docs.yml"
- ".github/workflows/wheels*"
Expand Down
17 changes: 16 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,24 @@
Changelog (Pillow)
==================

10.1.0 (unreleased)
10.1.0 (2023-10-15)
-------------------

- Added TrueType default font to allow for different sizes #7354
[radarhere]

- Fixed invalid argument warning #7442
[radarhere]

- Added ImageOps cover method #7412
[radarhere, hugovk]

- Catch struct.error from truncated EXIF when reading JPEG DPI #7458
[radarhere]

- Consider default image when selecting mode for PNG save_all #7437
[radarhere]

- Support BGR;15, BGR;16 and BGR;24 access, unpacking and putdata #7303
[radarhere]

Expand Down
2 changes: 1 addition & 1 deletion RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ Released as needed privately to individual vendors for critical security-related
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
# select wheels
```
* [ ] Download the Linux aarch64 wheels created by Travis CI from [GitHub releases](https://github.com/python-pillow/Pillow/releases)
and copy into `dist`.
Expand Down
Binary file added Tests/images/default_font_freetype.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Tests/images/imagedraw_default_font_size.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Tests/images/truncated_exif_dpi.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 8 additions & 2 deletions Tests/test_file_apng.py
Original file line number Diff line number Diff line change
Expand Up @@ -673,10 +673,16 @@ def test_seek_after_close():


@pytest.mark.parametrize("mode", ("RGBA", "RGB", "P"))
def test_different_modes_in_later_frames(mode, tmp_path):
@pytest.mark.parametrize("default_image", (True, False))
def test_different_modes_in_later_frames(mode, default_image, tmp_path):
test_file = str(tmp_path / "temp.png")

im = Image.new("L", (1, 1))
im.save(test_file, save_all=True, append_images=[Image.new(mode, (1, 1))])
im.save(
test_file,
save_all=True,
default_image=default_image,
append_images=[Image.new(mode, (1, 1))],
)
with Image.open(test_file) as reloaded:
assert reloaded.mode == mode
7 changes: 7 additions & 0 deletions Tests/test_file_jpeg.py
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,13 @@ def test_dpi_exif_string(self):
# This should return the default
assert im.info.get("dpi") == (72, 72)

def test_dpi_exif_truncated(self):
# Arrange
with Image.open("Tests/images/truncated_exif_dpi.jpg") as im:
# Act / Assert
# This should return the default
assert im.info.get("dpi") == (72, 72)

def test_no_dpi_in_exif(self):
# Arrange
# This is photoshop-200dpi.jpg with resolution removed from EXIF:
Expand Down
31 changes: 29 additions & 2 deletions Tests/test_imagedraw.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import contextlib
import os.path

import pytest

from PIL import Image, ImageColor, ImageDraw, ImageFont
from PIL import Image, ImageColor, ImageDraw, ImageFont, features

from .helper import (
assert_image_equal,
Expand Down Expand Up @@ -1353,7 +1354,33 @@ def test_setting_default_font():
assert draw.getfont() == font
finally:
ImageDraw.ImageDraw.font = None
assert isinstance(draw.getfont(), ImageFont.ImageFont)
assert isinstance(draw.getfont(), ImageFont.load_default().__class__)


def test_default_font_size():
freetype_support = features.check_module("freetype2")
text = "Default font at a specific size."

im = Image.new("RGB", (220, 25))
draw = ImageDraw.Draw(im)
with contextlib.nullcontext() if freetype_support else pytest.raises(ImportError):
draw.text((0, 0), text, font_size=16)
assert_image_equal_tofile(im, "Tests/images/imagedraw_default_font_size.png")

with contextlib.nullcontext() if freetype_support else pytest.raises(ImportError):
assert draw.textlength(text, font_size=16) == 216

with contextlib.nullcontext() if freetype_support else pytest.raises(ImportError):
assert draw.textbbox((0, 0), text, font_size=16) == (0, 3, 216, 19)

im = Image.new("RGB", (220, 25))
draw = ImageDraw.Draw(im)
with contextlib.nullcontext() if freetype_support else pytest.raises(ImportError):
draw.multiline_text((0, 0), text, font_size=16)
assert_image_equal_tofile(im, "Tests/images/imagedraw_default_font_size.png")

with contextlib.nullcontext() if freetype_support else pytest.raises(ImportError):
assert draw.multiline_textbbox((0, 0), text, font_size=16) == (0, 3, 216, 19)


@pytest.mark.parametrize("bbox", BBOX)
Expand Down
23 changes: 5 additions & 18 deletions Tests/test_imagefont.py
Original file line number Diff line number Diff line change
Expand Up @@ -453,16 +453,19 @@ def test_load_non_font_bytes():

def test_default_font():
# Arrange
txt = 'This is a "better than nothing" default font.'
txt = "This is a default font using FreeType support."
im = Image.new(mode="RGB", size=(300, 100))
draw = ImageDraw.Draw(im)

# Act
default_font = ImageFont.load_default()
draw.text((10, 10), txt, font=default_font)

larger_default_font = ImageFont.load_default(size=14)
draw.text((10, 60), txt, font=larger_default_font)

# Assert
assert_image_equal_tofile(im, "Tests/images/default_font.png")
assert_image_equal_tofile(im, "Tests/images/default_font_freetype.png")


@pytest.mark.parametrize("mode", (None, "1", "RGBA"))
Expand All @@ -485,14 +488,6 @@ def test_render_empty(font):
assert_image_equal(im, target)


def test_unicode_pilfont():
# should not segfault, should return UnicodeDecodeError
# issue #2826
font = ImageFont.load_default()
with pytest.raises(UnicodeEncodeError):
font.getbbox("’")


def test_unicode_extended(layout_engine):
# issue #3777
text = "A\u278A\U0001F12B"
Expand Down Expand Up @@ -722,14 +717,6 @@ def test_variation_set_by_axes(font):
_check_text(font, "Tests/images/variation_tiny_axes.png", 32.5)


def test_textbbox_non_freetypefont():
im = Image.new("RGB", (200, 200))
d = ImageDraw.Draw(im)
default_font = ImageFont.load_default()
assert d.textlength("test", font=default_font) == 24
assert d.textbbox((0, 0), "test", font=default_font) == (0, 0, 24, 11)


@pytest.mark.parametrize(
"anchor, left, top",
(
Expand Down
45 changes: 45 additions & 0 deletions Tests/test_imagefontpil.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import pytest

from PIL import Image, ImageDraw, ImageFont, features

from .helper import assert_image_equal_tofile

pytestmark = pytest.mark.skipif(
features.check_module("freetype2"),
reason="PILfont superseded if FreeType is supported",
)


def test_default_font():
# Arrange
txt = 'This is a "better than nothing" default font.'
im = Image.new(mode="RGB", size=(300, 100))
draw = ImageDraw.Draw(im)

# Act
default_font = ImageFont.load_default()
draw.text((10, 10), txt, font=default_font)

# Assert
assert_image_equal_tofile(im, "Tests/images/default_font.png")


def test_size_without_freetype():
with pytest.raises(ImportError):
ImageFont.load_default(size=14)


def test_unicode():
# should not segfault, should return UnicodeDecodeError
# issue #2826
font = ImageFont.load_default()
with pytest.raises(UnicodeEncodeError):
font.getbbox("’")


def test_textbbox():
im = Image.new("RGB", (200, 200))
d = ImageDraw.Draw(im)
default_font = ImageFont.load_default()
assert d.textlength("test", font=default_font) == 24
assert d.textbbox((0, 0), "test", font=default_font) == (0, 0, 24, 11)
17 changes: 17 additions & 0 deletions Tests/test_imageops.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ def test_sanity():
ImageOps.contain(hopper("L"), (128, 128))
ImageOps.contain(hopper("RGB"), (128, 128))

ImageOps.cover(hopper("L"), (128, 128))
ImageOps.cover(hopper("RGB"), (128, 128))

ImageOps.crop(hopper("L"), 1)
ImageOps.crop(hopper("RGB"), 1)

Expand Down Expand Up @@ -119,6 +122,20 @@ def test_contain_round():
assert new_im.height == 5


@pytest.mark.parametrize(
"image_name, expected_size",
(
("colr_bungee.png", (1024, 256)), # landscape
("imagedraw_stroke_multiline.png", (256, 640)), # portrait
("hopper.png", (256, 256)), # square
),
)
def test_cover(image_name, expected_size):
with Image.open("Tests/images/" + image_name) as im:
new_im = ImageOps.cover(im, (256, 256))
assert new_im.size == expected_size


def test_pad():
# Same ratio
im = hopper()
Expand Down
2 changes: 1 addition & 1 deletion depends/install_imagequant.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash
# install libimagequant

archive=libimagequant-4.2.1
archive=libimagequant-4.2.2

./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/main/$archive.tar.gz

Expand Down
Binary file added docs/example/image_thumbnail.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/example/imageops_contain.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/example/imageops_cover.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/example/imageops_fit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/example/imageops_pad.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 31 additions & 0 deletions docs/handbook/tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,37 @@ true, to provide for the same changes to the image's size.
A more general form of image transformations can be carried out via the
:py:meth:`~PIL.Image.Image.transform` method.

Relative resizing
^^^^^^^^^^^^^^^^^

Instead of calculating the size of the new image when resizing, you can also
choose to resize relative to a given size.

::

from PIL import Image, ImageOps
size = (100, 150)
with Image.open("Tests/images/hopper.png") as im:
ImageOps.contain(im, size).save("imageops_contain.png")
ImageOps.cover(im, size).save("imageops_cover.png")
ImageOps.fit(im, size).save("imageops_fit.png")
ImageOps.pad(im, size, color="#f00").save("imageops_pad.png")

# thumbnail() can also be used,
# but will modify the image object in place
im.thumbnail(size)
im.save("imageops_thumbnail.png")

+----------------+-------------------------------------------+--------------------------------------------+------------------------------------------+----------------------------------------+----------------------------------------+
| | :py:meth:`~PIL.Image.Image.thumbnail` | :py:meth:`~PIL.ImageOps.contain` | :py:meth:`~PIL.ImageOps.cover` | :py:meth:`~PIL.ImageOps.fit` | :py:meth:`~PIL.ImageOps.pad` |
+================+===========================================+============================================+==========================================+========================================+========================================+
|Given size | ``(100, 150)`` | ``(100, 150)`` | ``(100, 150)`` | ``(100, 150)`` | ``(100, 150)`` |
+----------------+-------------------------------------------+--------------------------------------------+------------------------------------------+----------------------------------------+----------------------------------------+
|Resulting image | .. image:: ../example/image_thumbnail.png | .. image:: ../example/imageops_contain.png | .. image:: ../example/imageops_cover.png | .. image:: ../example/imageops_fit.png | .. image:: ../example/imageops_pad.png |
+----------------+-------------------------------------------+--------------------------------------------+------------------------------------------+----------------------------------------+----------------------------------------+
|Resulting size | ``100×100`` | ``100×100`` | ``150×150`` | ``100×150`` | ``100×150`` |
+----------------+-------------------------------------------+--------------------------------------------+------------------------------------------+----------------------------------------+----------------------------------------+

.. _color-transforms:

Color transforms
Expand Down
Loading

0 comments on commit d29383b

Please sign in to comment.