Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions Tests/test_image_paste.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,21 @@ def test_image_solid(self, mode: str) -> None:
im = im.crop((12, 23, im2.width + 12, im2.height + 23))
assert_image_equal(im, im2)

@pytest.mark.parametrize("y", [10, -10])
@pytest.mark.parametrize("mode", ["L", "RGB"])
@pytest.mark.parametrize("mask_mode", ["", "1", "L", "LA", "RGBa"])
def test_image_self(self, y: int, mode: str, mask_mode: str) -> None:
im = getattr(self, "gradient_" + mode)
mask = Image.new(mask_mode, im.size, 0xFFFFFFFF) if mask_mode else None

im_self = im.copy()
im_self.paste(im_self, (0, y), mask)

im_copy = im.copy()
im_copy.paste(im_copy.copy(), (0, y), mask)

assert_image_equal(im_self, im_copy)

@pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
def test_image_mask_1(self, mode: str) -> None:
im = Image.new(mode, (200, 200), "white")
Expand Down
45 changes: 30 additions & 15 deletions src/libImaging/Paste.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@

#include "Imaging.h"

#define PREPARE_PASTE_LOOP() \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be a function instead?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

radarhere@be8209e is what would be required. I don't think it's as neat, but let me know if you disagree.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, let's go with this PR version.

int y, y_end, offset; \
if (imOut == imIn && dy > sy) { \
y = ysize - 1; \
y_end = -1; \
offset = -1; \
} else { \
y = 0; \
y_end = ysize; \
offset = 1; \
}

static inline void
paste(
Imaging imOut,
Expand All @@ -37,14 +49,13 @@
) {
/* paste opaque region */

int y;

dx *= pixelsize;
sx *= pixelsize;

xsize *= pixelsize;

for (y = 0; y < ysize; y++) {
PREPARE_PASTE_LOOP();

Check warning on line 57 in src/libImaging/Paste.c

View check run for this annotation

Codecov / codecov/patch

src/libImaging/Paste.c#L57

Added line #L57 was not covered by tests
for (; y != y_end; y += offset) {
memcpy(imOut->image[y + dy] + dx, imIn->image[y + sy] + sx, xsize);
}
}
Expand All @@ -64,12 +75,13 @@
) {
/* paste with mode "1" mask */

int x, y;
int x;

PREPARE_PASTE_LOOP();

Check warning on line 80 in src/libImaging/Paste.c

View check run for this annotation

Codecov / codecov/patch

src/libImaging/Paste.c#L80

Added line #L80 was not covered by tests
if (imOut->image8) {
int in_i16 = strncmp(imIn->mode, "I;16", 4) == 0;
int out_i16 = strncmp(imOut->mode, "I;16", 4) == 0;
for (y = 0; y < ysize; y++) {
for (; y != y_end; y += offset) {
UINT8 *out = imOut->image8[y + dy] + dx;
if (out_i16) {
out += dx;
Expand Down Expand Up @@ -97,7 +109,7 @@
}

} else {
for (y = 0; y < ysize; y++) {
for (; y != y_end; y += offset) {
INT32 *out = imOut->image32[y + dy] + dx;
INT32 *in = imIn->image32[y + sy] + sx;
UINT8 *mask = imMask->image8[y + sy] + sx;
Expand Down Expand Up @@ -126,11 +138,12 @@
) {
/* paste with mode "L" matte */

int x, y;
int x;
unsigned int tmp1;

PREPARE_PASTE_LOOP();

Check warning on line 144 in src/libImaging/Paste.c

View check run for this annotation

Codecov / codecov/patch

src/libImaging/Paste.c#L144

Added line #L144 was not covered by tests
if (imOut->image8) {
for (y = 0; y < ysize; y++) {
for (; y != y_end; y += offset) {
UINT8 *out = imOut->image8[y + dy] + dx;
UINT8 *in = imIn->image8[y + sy] + sx;
UINT8 *mask = imMask->image8[y + sy] + sx;
Expand All @@ -141,7 +154,7 @@
}

} else {
for (y = 0; y < ysize; y++) {
for (; y != y_end; y += offset) {
UINT8 *out = (UINT8 *)(imOut->image32[y + dy] + dx);
UINT8 *in = (UINT8 *)(imIn->image32[y + sy] + sx);
UINT8 *mask = (UINT8 *)(imMask->image8[y + sy] + sx);
Expand Down Expand Up @@ -174,11 +187,12 @@
) {
/* paste with mode "RGBA" matte */

int x, y;
int x;
unsigned int tmp1;

PREPARE_PASTE_LOOP();

Check warning on line 193 in src/libImaging/Paste.c

View check run for this annotation

Codecov / codecov/patch

src/libImaging/Paste.c#L193

Added line #L193 was not covered by tests
if (imOut->image8) {
for (y = 0; y < ysize; y++) {
for (; y != y_end; y += offset) {
UINT8 *out = imOut->image8[y + dy] + dx;
UINT8 *in = imIn->image8[y + sy] + sx;
UINT8 *mask = (UINT8 *)imMask->image[y + sy] + sx * 4 + 3;
Expand All @@ -189,7 +203,7 @@
}

} else {
for (y = 0; y < ysize; y++) {
for (; y != y_end; y += offset) {
UINT8 *out = (UINT8 *)(imOut->image32[y + dy] + dx);
UINT8 *in = (UINT8 *)(imIn->image32[y + sy] + sx);
UINT8 *mask = (UINT8 *)(imMask->image32[y + sy] + sx);
Expand Down Expand Up @@ -222,11 +236,12 @@
) {
/* paste with mode "RGBa" matte */

int x, y;
int x;
unsigned int tmp1;

PREPARE_PASTE_LOOP();

Check warning on line 242 in src/libImaging/Paste.c

View check run for this annotation

Codecov / codecov/patch

src/libImaging/Paste.c#L242

Added line #L242 was not covered by tests
if (imOut->image8) {
for (y = 0; y < ysize; y++) {
for (; y != y_end; y += offset) {
UINT8 *out = imOut->image8[y + dy] + dx;
UINT8 *in = imIn->image8[y + sy] + sx;
UINT8 *mask = (UINT8 *)imMask->image[y + sy] + sx * 4 + 3;
Expand All @@ -237,7 +252,7 @@
}

} else {
for (y = 0; y < ysize; y++) {
for (; y != y_end; y += offset) {
UINT8 *out = (UINT8 *)(imOut->image32[y + dy] + dx);
UINT8 *in = (UINT8 *)(imIn->image32[y + sy] + sx);
UINT8 *mask = (UINT8 *)(imMask->image32[y + sy] + sx);
Expand Down
Loading