Skip to content

Commit be48bcb

Browse files
authored
Correct background color when using P mode images with ImageOps.pad() (#9795)
1 parent 78be7e8 commit be48bcb

2 files changed

Lines changed: 39 additions & 17 deletions

File tree

Tests/test_imageops.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,23 @@ def test_pad_round() -> None:
171171
assert new_im.getpixel((0, 2)) == 1
172172

173173

174+
def test_pad_palette() -> None:
175+
with Image.open("Tests/images/p_16.tga") as im:
176+
im_padded = ImageOps.pad(im, (im.width * 2, im.height), color=(255, 0, 0))
177+
im_rgb = im_padded.convert("RGB")
178+
179+
# Verify that the left and right sides are now red
180+
px = im_rgb.load()
181+
assert px is not None
182+
for y in range(im_rgb.height):
183+
for x in range(im.width // 2):
184+
assert px[x, y] == (255, 0, 0)
185+
assert px[im_rgb.width - 1 - x, y] == (255, 0, 0)
186+
187+
im_cropped = im_rgb.crop((im.width * 0.5, 0, im.width * 1.5, im.height))
188+
assert_image_equal(im_cropped, im.convert("RGB"))
189+
190+
174191
@pytest.mark.parametrize("mode", ("P", "PA"))
175192
def test_palette(mode: str) -> None:
176193
im = hopper(mode)

src/PIL/ImageOps.py

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ def _border(border: int | tuple[int, ...]) -> tuple[int, int, int, int]:
4444
return left, top, right, bottom
4545

4646

47-
def _color(color: str | int | tuple[int, ...], mode: str) -> int | tuple[int, ...]:
47+
def _color(
48+
color: str | int | tuple[int, ...] | None, mode: str
49+
) -> int | tuple[int, ...] | None:
4850
if isinstance(color, str):
4951
from . import ImageColor
5052

@@ -331,6 +333,23 @@ def cover(
331333
return image.resize(size, resample=method)
332334

333335

336+
def _new_with_fill(
337+
image: Image.Image, size: tuple[int, int], fill: str | int | tuple[int, ...] | None
338+
) -> Image.Image:
339+
color = _color(fill, image.mode)
340+
if image.palette:
341+
mode = image.palette.mode
342+
palette = ImagePalette.ImagePalette(mode, image.getpalette(mode))
343+
if isinstance(color, tuple) and len(color) in (3, 4):
344+
color = palette.getcolor(color)
345+
else:
346+
palette = None
347+
out = Image.new(image.mode, size, color)
348+
if palette:
349+
out.putpalette(palette.palette, mode)
350+
return out
351+
352+
334353
def pad(
335354
image: Image.Image,
336355
size: tuple[int, int],
@@ -363,11 +382,7 @@ def pad(
363382
if resized.size == size:
364383
out = resized
365384
else:
366-
out = Image.new(image.mode, size, color)
367-
if resized.palette:
368-
palette = resized.getpalette()
369-
if palette is not None:
370-
out.putpalette(palette)
385+
out = _new_with_fill(resized, size, color)
371386
if resized.width != size[0]:
372387
x = round((size[0] - resized.width) * max(0, min(centering[0], 1)))
373388
out.paste(resized, (x, 0))
@@ -500,17 +515,7 @@ def expand(
500515
left, top, right, bottom = _border(border)
501516
width = left + image.size[0] + right
502517
height = top + image.size[1] + bottom
503-
color = _color(fill, image.mode)
504-
if image.palette:
505-
mode = image.palette.mode
506-
palette = ImagePalette.ImagePalette(mode, image.getpalette(mode))
507-
if isinstance(color, tuple) and (len(color) == 3 or len(color) == 4):
508-
color = palette.getcolor(color)
509-
else:
510-
palette = None
511-
out = Image.new(image.mode, (width, height), color)
512-
if palette:
513-
out.putpalette(palette.palette, mode)
518+
out = _new_with_fill(image, (width, height), fill)
514519
out.paste(image, (left, top))
515520
return out
516521

0 commit comments

Comments
 (0)