Merge pull request #2015 from uploadcare/paste-speedup

Speedup paste with masks up to 80%
This commit is contained in:
wiredfool 2016-09-22 10:10:56 +01:00 committed by GitHub
commit 69ee1e35b8
3 changed files with 348 additions and 84 deletions

View File

@ -238,3 +238,12 @@ if sys.platform == 'win32':
IMCONVERT = os.path.join(IMCONVERT, 'convert.exe') IMCONVERT = os.path.join(IMCONVERT, 'convert.exe')
else: else:
IMCONVERT = 'convert' IMCONVERT = 'convert'
class cached_property(object):
def __init__(self, func):
self.func = func
def __get__(self, instance, cls=None):
result = instance.__dict__[self.func.__name__] = self.func(instance)
return result

252
Tests/test_image_paste.py Normal file
View File

@ -0,0 +1,252 @@
from helper import PillowTestCase, cached_property
from PIL import Image
class TestImagingPaste(PillowTestCase):
masks = {}
size = 128
def assert_9points_image(self, im, expected):
expected = [
point[0]
if im.mode == 'L' else
point[:len(im.mode)]
for point in expected
]
px = im.load()
actual = [
px[0, 0],
px[self.size // 2, 0],
px[self.size - 1, 0],
px[0, self.size // 2],
px[self.size // 2, self.size // 2],
px[self.size - 1, self.size // 2],
px[0, self.size - 1],
px[self.size // 2, self.size - 1],
px[self.size - 1, self.size - 1],
]
self.assertEqual(actual, expected)
@cached_property
def mask_1(self):
mask = Image.new('1', (self.size, self.size))
px = mask.load()
for y in range(mask.height):
for x in range(mask.width):
px[y, x] = (x + y) % 2
return mask
@cached_property
def mask_L(self):
return self.gradient_L.transpose(Image.ROTATE_270)
@cached_property
def gradient_L(self):
gradient = Image.new('L', (self.size, self.size))
px = gradient.load()
for y in range(gradient.height):
for x in range(gradient.width):
px[y, x] = (x + y) % 255
return gradient
@cached_property
def gradient_RGB(self):
return Image.merge('RGB', [
self.gradient_L,
self.gradient_L.transpose(Image.ROTATE_90),
self.gradient_L.transpose(Image.ROTATE_180),
])
@cached_property
def gradient_RGBA(self):
return Image.merge('RGBA', [
self.gradient_L,
self.gradient_L.transpose(Image.ROTATE_90),
self.gradient_L.transpose(Image.ROTATE_180),
self.gradient_L.transpose(Image.ROTATE_270),
])
@cached_property
def gradient_RGBa(self):
return Image.merge('RGBa', [
self.gradient_L,
self.gradient_L.transpose(Image.ROTATE_90),
self.gradient_L.transpose(Image.ROTATE_180),
self.gradient_L.transpose(Image.ROTATE_270),
])
def test_image_solid(self):
for mode in ('RGBA', 'RGB', 'L'):
im = Image.new(mode, (200, 200), 'red')
im2 = getattr(self, 'gradient_' + mode)
im.paste(im2, (12, 23))
im = im.crop((12, 23, im2.width + 12, im2.height + 23))
self.assert_image_equal(im, im2)
def test_image_mask_1(self):
for mode in ('RGBA', 'RGB', 'L'):
im = Image.new(mode, (200, 200), 'white')
im2 = getattr(self, 'gradient_' + mode)
im.paste(im2, (0, 0), self.mask_1)
self.assert_9points_image(im, [
(255, 255, 255, 255),
(255, 255, 255, 255),
(127, 254, 127, 0),
(255, 255, 255, 255),
(255, 255, 255, 255),
(191, 190, 63, 64),
(127, 0, 127, 254),
(191, 64, 63, 190),
(255, 255, 255, 255),
])
def test_image_mask_L(self):
for mode in ('RGBA', 'RGB', 'L'):
im = Image.new(mode, (200, 200), 'white')
im2 = getattr(self, 'gradient_' + mode)
im.paste(im2, (0, 0), self.mask_L)
self.assert_9points_image(im, [
(128, 191, 255, 191),
(208, 239, 239, 208),
(255, 255, 255, 255),
(112, 111, 206, 207),
(192, 191, 191, 191),
(239, 239, 207, 207),
(128, 1, 128, 254),
(207, 113, 112, 207),
(255, 191, 128, 191),
])
def test_image_mask_RGBA(self):
for mode in ('RGBA', 'RGB', 'L'):
im = Image.new(mode, (200, 200), 'white')
im2 = getattr(self, 'gradient_' + mode)
im.paste(im2, (0, 0), self.gradient_RGBA)
self.assert_9points_image(im, [
(128, 191, 255, 191),
(208, 239, 239, 208),
(255, 255, 255, 255),
(112, 111, 206, 207),
(192, 191, 191, 191),
(239, 239, 207, 207),
(128, 1, 128, 254),
(207, 113, 112, 207),
(255, 191, 128, 191),
])
def test_image_mask_RGBa(self):
for mode in ('RGBA', 'RGB', 'L'):
im = Image.new(mode, (200, 200), 'white')
im2 = getattr(self, 'gradient_' + mode)
im.paste(im2, (0, 0), self.gradient_RGBa)
self.assert_9points_image(im, [
(128, 255, 126, 255),
(0, 127, 126, 255),
(126, 253, 126, 255),
(128, 127, 254, 255),
(0, 255, 254, 255),
(126, 125, 254, 255),
(128, 1, 128, 255),
(0, 129, 128, 255),
(126, 255, 128, 255),
])
def test_color_solid(self):
for mode in ('RGBA', 'RGB', 'L'):
im = Image.new(mode, (200, 200), 'black')
rect = (12, 23, 128 + 12, 128 + 23)
im.paste('white', rect)
hist = im.crop(rect).histogram()
while hist:
head, hist = hist[:256], hist[256:]
self.assertEqual(head[255], 128 * 128)
self.assertEqual(sum(head[:255]), 0)
def test_color_mask_1(self):
for mode in ('RGBA', 'RGB', 'L'):
im = Image.new(mode, (200, 200), (50, 60, 70, 80)[:len(mode)])
color = (10, 20, 30, 40)[:len(mode)]
im.paste(color, (0, 0), self.mask_1)
self.assert_9points_image(im, [
(50, 60, 70, 80),
(50, 60, 70, 80),
(10, 20, 30, 40),
(50, 60, 70, 80),
(50, 60, 70, 80),
(10, 20, 30, 40),
(10, 20, 30, 40),
(10, 20, 30, 40),
(50, 60, 70, 80),
])
def test_color_mask_L(self):
for mode in ('RGBA', 'RGB', 'L'):
im = getattr(self, 'gradient_' + mode).copy()
color = 'white'
im.paste(color, (0, 0), self.mask_L)
self.assert_9points_image(im, [
(127, 191, 254, 191),
(111, 207, 206, 110),
(127, 254, 127, 0),
(207, 207, 239, 239),
(191, 191, 190, 191),
(207, 206, 111, 112),
(254, 254, 254, 255),
(239, 206, 206, 238),
(254, 191, 127, 191),
])
def test_color_mask_RGBA(self):
for mode in ('RGBA', 'RGB', 'L'):
im = getattr(self, 'gradient_' + mode).copy()
color = 'white'
im.paste(color, (0, 0), self.gradient_RGBA)
self.assert_9points_image(im, [
(127, 191, 254, 191),
(111, 207, 206, 110),
(127, 254, 127, 0),
(207, 207, 239, 239),
(191, 191, 190, 191),
(207, 206, 111, 112),
(254, 254, 254, 255),
(239, 206, 206, 238),
(254, 191, 127, 191),
])
def test_color_mask_RGBa(self):
for mode in ('RGBA', 'RGB', 'L'):
im = getattr(self, 'gradient_' + mode).copy()
color = 'white'
im.paste(color, (0, 0), self.gradient_RGBa)
self.assert_9points_image(im, [
(255, 63, 126, 63),
(47, 143, 142, 46),
(126, 253, 126, 255),
(15, 15, 47, 47),
(63, 63, 62, 63),
(142, 141, 46, 47),
(255, 255, 255, 0),
(48, 15, 15, 47),
(126, 63, 255, 63)
])

View File

@ -5,15 +5,15 @@
* paste image on another image * paste image on another image
* *
* history: * history:
* 96-03-27 fl Created * 96-03-27 fl Created
* 96-07-16 fl Support "1", "L" and "RGBA" masks * 96-07-16 fl Support "1", "L" and "RGBA" masks
* 96-08-16 fl Merged with opaque paste * 96-08-16 fl Merged with opaque paste
* 97-01-17 fl Faster blending, added support for RGBa images * 97-01-17 fl Faster blending, added support for RGBa images
* 97-08-27 fl Faster masking for 32-bit images * 97-08-27 fl Faster masking for 32-bit images
* 98-02-02 fl Fixed MULDIV255 macro for gcc * 98-02-02 fl Fixed MULDIV255 macro for gcc
* 99-02-02 fl Added "RGBa" mask support * 99-02-02 fl Added "RGBa" mask support
* 99-02-06 fl Rewritten. Added support for masked fill operations. * 99-02-06 fl Rewritten. Added support for masked fill operations.
* 99-12-08 fl Fixed matte fill. * 99-12-08 fl Fixed matte fill.
* *
* Copyright (c) Fredrik Lundh 1996-97. * Copyright (c) Fredrik Lundh 1996-97.
* Copyright (c) Secret Labs AB 1997-99. * Copyright (c) Secret Labs AB 1997-99.
@ -24,19 +24,19 @@
#include "Imaging.h" #include "Imaging.h"
/* like (a * b + 127) / 255), but much faster on most platforms */ /* like (a * b + 127) / 255), but much faster on most platforms */
#define MULDIV255NEW(a, b, tmp)\ #define MULDIV255NEW(a, tmp)\
(tmp = (a) * (b) + 128, ((((tmp) >> 8) + (tmp)) >> 8)) (tmp = (a) + 128, ((((tmp) >> 8) + (tmp)) >> 8))
#define MULDIV255OLD(a, b, tmp)\ #define MULDIV255OLD(a, tmp)\
(((a) * (b) + 127) / 255) (((a) + 127) / 255)
#define MULDIV255 MULDIV255NEW #define MULDIV255 MULDIV255NEW
#define BLEND(mask, in1, in2, tmp1, tmp2)\ #define BLEND(mask, in1, in2, tmp1)\
(MULDIV255(in1, 255 - mask, tmp1) + MULDIV255(in2, mask, tmp2)) MULDIV255(in1 * (255 - mask) + in2 * mask, tmp1)
#define PREBLEND(mask, in1, in2, tmp1)\ #define PREBLEND(mask, in1, in2, tmp1)\
(MULDIV255(in1, 255 - mask, tmp1) + in2) (MULDIV255(in1 * (255 - mask), tmp1) + in2)
static inline void static inline void
paste(Imaging imOut, Imaging imIn, int dx, int dy, int sx, int sy, paste(Imaging imOut, Imaging imIn, int dx, int dy, int sx, int sy,
@ -99,8 +99,8 @@ paste_mask_L(Imaging imOut, Imaging imIn, Imaging imMask,
{ {
/* paste with mode "L" matte */ /* paste with mode "L" matte */
int x, y, i; int x, y;
unsigned int tmp1, tmp2; unsigned int tmp1;
if (imOut->image8) { if (imOut->image8) {
@ -109,7 +109,7 @@ paste_mask_L(Imaging imOut, Imaging imIn, Imaging imMask,
UINT8* in = imIn->image8[y+sy]+sx; UINT8* in = imIn->image8[y+sy]+sx;
UINT8* mask = imMask->image8[y+sy]+sx; UINT8* mask = imMask->image8[y+sy]+sx;
for (x = 0; x < xsize; x++) { for (x = 0; x < xsize; x++) {
*out = BLEND(*mask, *out, *in, tmp1, tmp2); *out = BLEND(*mask, *out, *in, tmp1);
out++, in++, mask++; out++, in++, mask++;
} }
} }
@ -117,15 +117,16 @@ paste_mask_L(Imaging imOut, Imaging imIn, Imaging imMask,
} else { } else {
for (y = 0; y < ysize; y++) { for (y = 0; y < ysize; y++) {
UINT8* out = (UINT8*) imOut->image[y+dy]+dx*pixelsize; UINT8* out = (UINT8*) (imOut->image32[y + dy] + dx);
UINT8* in = (UINT8*) imIn->image[y+sy]+sx*pixelsize; UINT8* in = (UINT8*) (imIn->image32[y + sy] + sx);
UINT8* mask = (UINT8*) imMask->image[y+sy]+sx; UINT8* mask = (UINT8*) (imMask->image8[y+sy] + sx);
for (x = 0; x < xsize; x++) { for (x = 0; x < xsize; x++) {
for (i = 0; i < pixelsize; i++) { UINT8 a = mask[0];
*out = BLEND(*mask, *out, *in, tmp1, tmp2); out[0] = BLEND(a, out[0], in[0], tmp1);
out++, in++; out[1] = BLEND(a, out[1], in[1], tmp1);
} out[2] = BLEND(a, out[2], in[2], tmp1);
mask++; out[3] = BLEND(a, out[3], in[3], tmp1);
out += 4; in += 4; mask ++;
} }
} }
} }
@ -138,8 +139,8 @@ paste_mask_RGBA(Imaging imOut, Imaging imIn, Imaging imMask,
{ {
/* paste with mode "RGBA" matte */ /* paste with mode "RGBA" matte */
int x, y, i; int x, y;
unsigned int tmp1, tmp2; unsigned int tmp1;
if (imOut->image8) { if (imOut->image8) {
@ -148,7 +149,7 @@ paste_mask_RGBA(Imaging imOut, Imaging imIn, Imaging imMask,
UINT8* in = imIn->image8[y+sy]+sx; UINT8* in = imIn->image8[y+sy]+sx;
UINT8* mask = (UINT8*) imMask->image[y+sy]+sx*4+3; UINT8* mask = (UINT8*) imMask->image[y+sy]+sx*4+3;
for (x = 0; x < xsize; x++) { for (x = 0; x < xsize; x++) {
*out = BLEND(*mask, *out, *in, tmp1, tmp2); *out = BLEND(*mask, *out, *in, tmp1);
out++, in++, mask += 4; out++, in++, mask += 4;
} }
} }
@ -156,15 +157,16 @@ paste_mask_RGBA(Imaging imOut, Imaging imIn, Imaging imMask,
} else { } else {
for (y = 0; y < ysize; y++) { for (y = 0; y < ysize; y++) {
UINT8* out = (UINT8*) imOut->image[y+dy]+dx*pixelsize; UINT8* out = (UINT8*) (imOut->image32[y + dy] + dx);
UINT8* in = (UINT8*) imIn->image[y+sy]+sx*pixelsize; UINT8* in = (UINT8*) (imIn->image32[y + sy] + sx);
UINT8* mask = (UINT8*) imMask->image[y+sy]+sx*4+3; UINT8* mask = (UINT8*) (imMask->image32[y+sy] + sx);
for (x = 0; x < xsize; x++) { for (x = 0; x < xsize; x++) {
for (i = 0; i < pixelsize; i++) { UINT8 a = mask[3];
*out = BLEND(*mask, *out, *in, tmp1, tmp2); out[0] = BLEND(a, out[0], in[0], tmp1);
out++, in++; out[1] = BLEND(a, out[1], in[1], tmp1);
} out[2] = BLEND(a, out[2], in[2], tmp1);
mask += 4; out[3] = BLEND(a, out[3], in[3], tmp1);
out += 4; in += 4; mask += 4;
} }
} }
} }
@ -178,7 +180,7 @@ paste_mask_RGBa(Imaging imOut, Imaging imIn, Imaging imMask,
{ {
/* paste with mode "RGBa" matte */ /* paste with mode "RGBa" matte */
int x, y, i; int x, y;
unsigned int tmp1; unsigned int tmp1;
if (imOut->image8) { if (imOut->image8) {
@ -196,15 +198,16 @@ paste_mask_RGBa(Imaging imOut, Imaging imIn, Imaging imMask,
} else { } else {
for (y = 0; y < ysize; y++) { for (y = 0; y < ysize; y++) {
UINT8* out = (UINT8*) imOut->image[y+dy]+dx*pixelsize; UINT8* out = (UINT8*) (imOut->image32[y + dy] + dx);
UINT8* in = (UINT8*) imIn->image[y+sy]+sx*pixelsize; UINT8* in = (UINT8*) (imIn->image32[y + sy] + sx);
UINT8* mask = (UINT8*) imMask->image[y+sy]+sx*4+3; UINT8* mask = (UINT8*) (imMask->image32[y+sy] + sx);
for (x = 0; x < xsize; x++) { for (x = 0; x < xsize; x++) {
for (i = 0; i < pixelsize; i++) { UINT8 a = mask[3];
*out = PREBLEND(*mask, *out, *in, tmp1); out[0] = PREBLEND(a, out[0], in[0], tmp1);
out++, in++; out[1] = PREBLEND(a, out[1], in[1], tmp1);
} out[2] = PREBLEND(a, out[2], in[2], tmp1);
mask += 4; out[3] = PREBLEND(a, out[3], in[3], tmp1);
out += 4; in += 4; mask += 4;
} }
} }
} }
@ -212,7 +215,7 @@ paste_mask_RGBa(Imaging imOut, Imaging imIn, Imaging imMask,
int int
ImagingPaste(Imaging imOut, Imaging imIn, Imaging imMask, ImagingPaste(Imaging imOut, Imaging imIn, Imaging imMask,
int dx0, int dy0, int dx1, int dy1) int dx0, int dy0, int dx1, int dy1)
{ {
int xsize, ysize; int xsize, ysize;
int pixelsize; int pixelsize;
@ -220,8 +223,8 @@ ImagingPaste(Imaging imOut, Imaging imIn, Imaging imMask,
ImagingSectionCookie cookie; ImagingSectionCookie cookie;
if (!imOut || !imIn) { if (!imOut || !imIn) {
(void) ImagingError_ModeError(); (void) ImagingError_ModeError();
return -1; return -1;
} }
pixelsize = imOut->pixelsize; pixelsize = imOut->pixelsize;
@ -231,28 +234,28 @@ ImagingPaste(Imaging imOut, Imaging imIn, Imaging imMask,
if (xsize != imIn->xsize || ysize != imIn->ysize || if (xsize != imIn->xsize || ysize != imIn->ysize ||
pixelsize != imIn->pixelsize) { pixelsize != imIn->pixelsize) {
(void) ImagingError_Mismatch(); (void) ImagingError_Mismatch();
return -1; return -1;
} }
if (imMask && (xsize != imMask->xsize || ysize != imMask->ysize)) { if (imMask && (xsize != imMask->xsize || ysize != imMask->ysize)) {
(void) ImagingError_Mismatch(); (void) ImagingError_Mismatch();
return -1; return -1;
} }
/* Determine which region to copy */ /* Determine which region to copy */
sx0 = sy0 = 0; sx0 = sy0 = 0;
if (dx0 < 0) if (dx0 < 0)
xsize += dx0, sx0 = -dx0, dx0 = 0; xsize += dx0, sx0 = -dx0, dx0 = 0;
if (dx0 + xsize > imOut->xsize) if (dx0 + xsize > imOut->xsize)
xsize = imOut->xsize - dx0; xsize = imOut->xsize - dx0;
if (dy0 < 0) if (dy0 < 0)
ysize += dy0, sy0 = -dy0, dy0 = 0; ysize += dy0, sy0 = -dy0, dy0 = 0;
if (dy0 + ysize > imOut->ysize) if (dy0 + ysize > imOut->ysize)
ysize = imOut->ysize - dy0; ysize = imOut->ysize - dy0;
if (xsize <= 0 || ysize <= 0) if (xsize <= 0 || ysize <= 0)
return 0; return 0;
if (!imMask) { if (!imMask) {
ImagingSectionEnter(&cookie); ImagingSectionEnter(&cookie);
@ -284,8 +287,8 @@ ImagingPaste(Imaging imOut, Imaging imIn, Imaging imMask,
ImagingSectionLeave(&cookie); ImagingSectionLeave(&cookie);
} else { } else {
(void) ImagingError_ValueError("bad transparency mask"); (void) ImagingError_ValueError("bad transparency mask");
return -1; return -1;
} }
return 0; return 0;
@ -308,15 +311,15 @@ fill(Imaging imOut, const void* ink_, int dx, int dy,
dx *= pixelsize; dx *= pixelsize;
xsize *= pixelsize; xsize *= pixelsize;
for (y = 0; y < ysize; y++) for (y = 0; y < ysize; y++)
memset(imOut->image[y+dy]+dx, ink8, xsize); memset(imOut->image[y+dy]+dx, ink8, xsize);
} else { } else {
for (y = 0; y < ysize; y++) { for (y = 0; y < ysize; y++) {
INT32* out = imOut->image32[y+dy]+dx; INT32* out = imOut->image32[y+dy]+dx;
for (x = 0; x < xsize; x++) for (x = 0; x < xsize; x++)
out[x] = ink32; out[x] = ink32;
} }
} }
@ -370,7 +373,7 @@ fill_mask_L(Imaging imOut, const UINT8* ink, Imaging imMask,
/* fill with mode "L" matte */ /* fill with mode "L" matte */
int x, y, i; int x, y, i;
unsigned int tmp1, tmp2; unsigned int tmp1;
if (imOut->image8) { if (imOut->image8) {
@ -378,7 +381,7 @@ fill_mask_L(Imaging imOut, const UINT8* ink, Imaging imMask,
UINT8* out = imOut->image8[y+dy]+dx; UINT8* out = imOut->image8[y+dy]+dx;
UINT8* mask = imMask->image8[y+sy]+sx; UINT8* mask = imMask->image8[y+sy]+sx;
for (x = 0; x < xsize; x++) { for (x = 0; x < xsize; x++) {
*out = BLEND(*mask, *out, ink[0], tmp1, tmp2); *out = BLEND(*mask, *out, ink[0], tmp1);
out++, mask++; out++, mask++;
} }
} }
@ -390,7 +393,7 @@ fill_mask_L(Imaging imOut, const UINT8* ink, Imaging imMask,
UINT8* mask = (UINT8*) imMask->image[y+sy]+sx; UINT8* mask = (UINT8*) imMask->image[y+sy]+sx;
for (x = 0; x < xsize; x++) { for (x = 0; x < xsize; x++) {
for (i = 0; i < pixelsize; i++) { for (i = 0; i < pixelsize; i++) {
*out = BLEND(*mask, *out, ink[i], tmp1, tmp2); *out = BLEND(*mask, *out, ink[i], tmp1);
out++; out++;
} }
mask++; mask++;
@ -407,7 +410,7 @@ fill_mask_RGBA(Imaging imOut, const UINT8* ink, Imaging imMask,
/* fill with mode "RGBA" matte */ /* fill with mode "RGBA" matte */
int x, y, i; int x, y, i;
unsigned int tmp1, tmp2; unsigned int tmp1;
if (imOut->image8) { if (imOut->image8) {
@ -416,7 +419,7 @@ fill_mask_RGBA(Imaging imOut, const UINT8* ink, Imaging imMask,
UINT8* out = imOut->image8[y+dy]+dx; UINT8* out = imOut->image8[y+dy]+dx;
UINT8* mask = (UINT8*) imMask->image[y+sy]+sx; UINT8* mask = (UINT8*) imMask->image[y+sy]+sx;
for (x = 0; x < xsize; x++) { for (x = 0; x < xsize; x++) {
*out = BLEND(*mask, *out, ink[0], tmp1, tmp2); *out = BLEND(*mask, *out, ink[0], tmp1);
out++, mask += 4; out++, mask += 4;
} }
} }
@ -430,7 +433,7 @@ fill_mask_RGBA(Imaging imOut, const UINT8* ink, Imaging imMask,
UINT8* mask = (UINT8*) imMask->image[y+sy]+sx; UINT8* mask = (UINT8*) imMask->image[y+sy]+sx;
for (x = 0; x < xsize; x++) { for (x = 0; x < xsize; x++) {
for (i = 0; i < pixelsize; i++) { for (i = 0; i < pixelsize; i++) {
*out = BLEND(*mask, *out, ink[i], tmp1, tmp2); *out = BLEND(*mask, *out, ink[i], tmp1);
out++; out++;
} }
mask += 4; mask += 4;
@ -489,8 +492,8 @@ ImagingFill2(Imaging imOut, const void* ink, Imaging imMask,
int sx0, sy0; int sx0, sy0;
if (!imOut || !ink) { if (!imOut || !ink) {
(void) ImagingError_ModeError(); (void) ImagingError_ModeError();
return -1; return -1;
} }
pixelsize = imOut->pixelsize; pixelsize = imOut->pixelsize;
@ -499,23 +502,23 @@ ImagingFill2(Imaging imOut, const void* ink, Imaging imMask,
ysize = dy1 - dy0; ysize = dy1 - dy0;
if (imMask && (xsize != imMask->xsize || ysize != imMask->ysize)) { if (imMask && (xsize != imMask->xsize || ysize != imMask->ysize)) {
(void) ImagingError_Mismatch(); (void) ImagingError_Mismatch();
return -1; return -1;
} }
/* Determine which region to fill */ /* Determine which region to fill */
sx0 = sy0 = 0; sx0 = sy0 = 0;
if (dx0 < 0) if (dx0 < 0)
xsize += dx0, sx0 = -dx0, dx0 = 0; xsize += dx0, sx0 = -dx0, dx0 = 0;
if (dx0 + xsize > imOut->xsize) if (dx0 + xsize > imOut->xsize)
xsize = imOut->xsize - dx0; xsize = imOut->xsize - dx0;
if (dy0 < 0) if (dy0 < 0)
ysize += dy0, sy0 = -dy0, dy0 = 0; ysize += dy0, sy0 = -dy0, dy0 = 0;
if (dy0 + ysize > imOut->ysize) if (dy0 + ysize > imOut->ysize)
ysize = imOut->ysize - dy0; ysize = imOut->ysize - dy0;
if (xsize <= 0 || ysize <= 0) if (xsize <= 0 || ysize <= 0)
return 0; return 0;
if (!imMask) { if (!imMask) {
ImagingSectionEnter(&cookie); ImagingSectionEnter(&cookie);
@ -547,8 +550,8 @@ ImagingFill2(Imaging imOut, const void* ink, Imaging imMask,
ImagingSectionLeave(&cookie); ImagingSectionLeave(&cookie);
} else { } else {
(void) ImagingError_ValueError("bad transparency mask"); (void) ImagingError_ValueError("bad transparency mask");
return -1; return -1;
} }
return 0; return 0;