Skip to content
62 changes: 23 additions & 39 deletions Tests/test_imagedraw.py
Original file line number Diff line number Diff line change
Expand Up @@ -625,18 +625,6 @@ def test_point(points: Coords) -> None:
assert_image_equal_tofile(im, "Tests/images/imagedraw_point.png")


def test_point_I16() -> None:
# Arrange
im = Image.new("I;16", (1, 1))
draw = ImageDraw.Draw(im)

# Act
draw.point((0, 0), fill=0x1234)

# Assert
assert im.getpixel((0, 0)) == 0x1234


@pytest.mark.parametrize("points", POINTS)
def test_polygon(points: Coords) -> None:
# Arrange
Expand All @@ -650,19 +638,6 @@ def test_polygon(points: Coords) -> None:
assert_image_equal_tofile(im, "Tests/images/imagedraw_polygon.png")


@pytest.mark.parametrize("points", POINTS)
def test_polygon_width_I16(points: Coords) -> None:
# Arrange
im = Image.new("I;16", (W, H))
draw = ImageDraw.Draw(im)

# Act
draw.polygon(points, outline=0xFFFF, width=2)

# Assert
assert_image_equal_tofile(im, "Tests/images/imagedraw_polygon_width_I.tiff")


@pytest.mark.parametrize("mode", ("RGB", "L"))
@pytest.mark.parametrize("kite_points", KITE_POINTS)
def test_polygon_kite(
Expand Down Expand Up @@ -791,20 +766,6 @@ def test_rectangle_zero_width(bbox: Coords) -> None:
assert_image_equal_tofile(im, "Tests/images/imagedraw_rectangle_zero_width.png")


@pytest.mark.parametrize("bbox", BBOX)
def test_rectangle_I16(bbox: Coords) -> None:
# Arrange
im = Image.new("I;16", (W, H))
draw = ImageDraw.Draw(im)

# Act
draw.rectangle(bbox, outline=0xCDEF)

# Assert
assert im.getpixel((X0, Y0)) == 0xCDEF
assert_image_equal_tofile(im, "Tests/images/imagedraw_rectangle_I.tiff")


@pytest.mark.parametrize("bbox", BBOX)
def test_rectangle_translucent_outline(bbox: Coords) -> None:
# Arrange
Expand Down Expand Up @@ -1169,6 +1130,29 @@ def test_line_horizontal() -> None:
)


def test_line_horizontal_w1px_direction() -> None:
# Drawing right-to-left must paint the same pixels as left-to-right.
im_lr = Image.new("L", (20, 3))
ImageDraw.Draw(im_lr).line((2, 1, 17, 1), fill=255)
assert [im_lr.getpixel((x, 1)) for x in range(20)] == [
255 if 2 <= x <= 17 else 0 for x in range(20)
]

im_rl = Image.new("L", (20, 3))
ImageDraw.Draw(im_rl).line((17, 1, 2, 1), fill=255)
assert_image_equal(im_rl, im_lr)


def test_line_joints_blend_once() -> None:
# Pixels shared by consecutive polyline segments
# (and the final endpoint, which is drawn separately)
# must be blended exactly once.
im = Image.new("RGB", (20, 3))
draw = ImageDraw.Draw(im, "RGBA")
draw.line([(0, 1), (10, 1), (19, 1)], fill=(255, 255, 255, 128))
assert {im.getpixel((x, 1)) for x in range(20)} == {(128, 128, 128)}


@pytest.mark.xfail(reason="failing test")
def test_line_h_s1_w2() -> None:
img, draw = create_base_image_draw((20, 20))
Expand Down
95 changes: 95 additions & 0 deletions Tests/test_imagedraw_i16.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
from __future__ import annotations

import pytest

from PIL import Image, ImageDraw
from Tests.helper import assert_image_equal_tofile
from Tests.test_imagedraw import BBOX, POINTS, X0, Y0, H, W

TYPE_CHECKING = False

if TYPE_CHECKING:
from PIL._typing import Coords

I16_MODES = ("I;16", "I;16L", "I;16B", "I;16N")
I16_INK = 0x1234


def create_I16_image_draw(mode: str) -> tuple[Image.Image, ImageDraw.ImageDraw]:
img = Image.new(mode, (8, 8))
return img, ImageDraw.Draw(img)


@pytest.mark.parametrize("points", POINTS)
def test_polygon_width_I16(points: Coords) -> None:
# Arrange
im = Image.new("I;16", (W, H))
draw = ImageDraw.Draw(im)

# Act
draw.polygon(points, outline=0xFFFF, width=2)

# Assert
assert_image_equal_tofile(im, "Tests/images/imagedraw_polygon_width_I.tiff")


@pytest.mark.parametrize("bbox", BBOX)
def test_rectangle_I16(bbox: Coords) -> None:
# Arrange
im = Image.new("I;16", (W, H))
draw = ImageDraw.Draw(im)

# Act
draw.rectangle(bbox, outline=0xCDEF)

# Assert
assert im.getpixel((X0, Y0)) == 0xCDEF
assert_image_equal_tofile(im, "Tests/images/imagedraw_rectangle_I.tiff")


@pytest.mark.parametrize("mode", I16_MODES)
def test_point_I16(mode: str) -> None:
img, draw = create_I16_image_draw(mode)
draw.point((4, 4), fill=I16_INK)
assert img.getpixel((4, 4)) == I16_INK


@pytest.mark.parametrize("mode", I16_MODES)
@pytest.mark.parametrize(
"xy",
# horizontal, vertical, diagonal
((0, 4, 7, 4), (4, 0, 4, 7), (0, 0, 7, 7)),
)
def test_line_I16(mode: str, xy: tuple[int, int, int, int]) -> None:
img, draw = create_I16_image_draw(mode)
draw.line(xy, fill=I16_INK)
assert img.getpixel((4, 4)) == I16_INK


@pytest.mark.parametrize("mode", I16_MODES)
def test_rectangle_fill_I16(mode: str) -> None:
img, draw = create_I16_image_draw(mode)
draw.rectangle((0, 0, 7, 7), fill=I16_INK)
assert img.getpixel((4, 4)) == I16_INK


@pytest.mark.parametrize("mode", I16_MODES)
def test_polygon_I16(mode: str) -> None:
img, draw = create_I16_image_draw(mode)
draw.polygon([(0, 0), (7, 0), (7, 7), (0, 7)], fill=I16_INK)
assert img.getpixel((4, 4)) == I16_INK


@pytest.mark.parametrize("mode", I16_MODES)
def test_masked_polygon_I16(mode: str) -> None:
# A polygon outline wider than one pixel is drawn through a mask.
img, draw = create_I16_image_draw(mode)
draw.polygon([(0, 0), (7, 0), (7, 7), (0, 7)], outline=I16_INK, width=8)
assert img.getpixel((4, 4)) == I16_INK


@pytest.mark.parametrize("mode", I16_MODES)
def test_ellipse_I16(mode: str) -> None:
img, draw = create_I16_image_draw(mode)
draw.ellipse((0, 0, 7, 7), fill=I16_INK)
assert img.getpixel((4, 4)) == I16_INK
6 changes: 6 additions & 0 deletions docs/releasenotes/13.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,12 @@ Preserved transparency when padding or expanding images in ImageOps
pixels in L, P and RGB images previously became opaque when a border was added.
New palette colors are allocated without using reserved transparency entries.

Drawing on I;16B images
^^^^^^^^^^^^^^^^^^^^^^^

When drawing on an ``I;16B`` image, some drawing methods wrote in the wrong byte order.
All drawing operations now use the byte order of the image mode.

Restore image position if ImageSequence.all_frames() fails
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
Loading
Loading