mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-07-10 16:22:22 +03:00
Merge pull request #364 from wiredfool/premultiply
Alpha Premultiplication support for transform and resize
This commit is contained in:
commit
056690792e
|
@ -1309,6 +1309,9 @@ class Image:
|
||||||
if self.mode in ("1", "P"):
|
if self.mode in ("1", "P"):
|
||||||
resample = NEAREST
|
resample = NEAREST
|
||||||
|
|
||||||
|
if self.mode == 'RGBA':
|
||||||
|
return self.convert('RGBa').resize(size, resample).convert('RGBA')
|
||||||
|
|
||||||
if resample == ANTIALIAS:
|
if resample == ANTIALIAS:
|
||||||
# requires stretch support (imToolkit & PIL 1.1.3)
|
# requires stretch support (imToolkit & PIL 1.1.3)
|
||||||
try:
|
try:
|
||||||
|
@ -1606,6 +1609,9 @@ class Image:
|
||||||
:returns: An Image object.
|
:returns: An Image object.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if self.mode == 'RGBA':
|
||||||
|
return self.convert('RGBa').transform(size, method, data, resample, fill).convert('RGBA')
|
||||||
|
|
||||||
if isinstance(method, ImageTransformHandler):
|
if isinstance(method, ImageTransformHandler):
|
||||||
return method.transform(size, self, resample=resample, fill=fill)
|
return method.transform(size, self, resample=resample, fill=fill)
|
||||||
if hasattr(method, "getdata"):
|
if hasattr(method, "getdata"):
|
||||||
|
@ -1613,6 +1619,7 @@ class Image:
|
||||||
method, data = method.getdata()
|
method, data = method.getdata()
|
||||||
if data is None:
|
if data is None:
|
||||||
raise ValueError("missing method data")
|
raise ValueError("missing method data")
|
||||||
|
|
||||||
im = new(self.mode, size, None)
|
im = new(self.mode, size, None)
|
||||||
if method == MESH:
|
if method == MESH:
|
||||||
# list of quads
|
# list of quads
|
||||||
|
@ -1620,7 +1627,7 @@ class Image:
|
||||||
im.__transformer(box, self, QUAD, quad, resample, fill)
|
im.__transformer(box, self, QUAD, quad, resample, fill)
|
||||||
else:
|
else:
|
||||||
im.__transformer((0, 0)+size, self, method, data, resample, fill)
|
im.__transformer((0, 0)+size, self, method, data, resample, fill)
|
||||||
|
|
||||||
return im
|
return im
|
||||||
|
|
||||||
def __transformer(self, box, image, method, data,
|
def __transformer(self, box, image, method, data,
|
||||||
|
|
|
@ -57,6 +57,40 @@ def test_mesh():
|
||||||
assert_image_equal(blank, transformed.crop((w//2,0,w,h//2)))
|
assert_image_equal(blank, transformed.crop((w//2,0,w,h//2)))
|
||||||
assert_image_equal(blank, transformed.crop((0,h//2,w//2,h)))
|
assert_image_equal(blank, transformed.crop((0,h//2,w//2,h)))
|
||||||
|
|
||||||
|
def _test_alpha_premult(op):
|
||||||
|
# create image with half white, half black, with the black half transparent.
|
||||||
|
# do op,
|
||||||
|
# there should be no darkness in the white section.
|
||||||
|
im = Image.new('RGBA', (10,10), (0,0,0,0));
|
||||||
|
im2 = Image.new('RGBA', (5,10), (255,255,255,255));
|
||||||
|
im.paste(im2, (0,0))
|
||||||
|
|
||||||
|
im = op(im, (40,10))
|
||||||
|
im_background = Image.new('RGB', (40,10), (255,255,255))
|
||||||
|
im_background.paste(im, (0,0), im)
|
||||||
|
|
||||||
|
hist = im_background.histogram()
|
||||||
|
assert_equal(40*10, hist[-1])
|
||||||
|
|
||||||
|
|
||||||
|
def test_alpha_premult_resize():
|
||||||
|
|
||||||
|
def op (im, sz):
|
||||||
|
return im.resize(sz, Image.LINEAR)
|
||||||
|
|
||||||
|
_test_alpha_premult(op)
|
||||||
|
|
||||||
|
def test_alpha_premult_transform():
|
||||||
|
|
||||||
|
def op(im, sz):
|
||||||
|
(w,h) = im.size
|
||||||
|
return im.transform(sz, Image.EXTENT,
|
||||||
|
(0,0,
|
||||||
|
w,h),
|
||||||
|
Image.BILINEAR)
|
||||||
|
|
||||||
|
_test_alpha_premult(op)
|
||||||
|
|
||||||
|
|
||||||
def test_blank_fill():
|
def test_blank_fill():
|
||||||
# attempting to hit
|
# attempting to hit
|
||||||
|
|
|
@ -289,6 +289,31 @@ rgba2rgba(UINT8* out, const UINT8* in, int xsize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* RGBa -> RGBA conversion to remove premultiplication
|
||||||
|
Needed for correct transforms/resizing on RGBA images */
|
||||||
|
static void
|
||||||
|
rgba2rgbA(UINT8* out, const UINT8* in, int xsize)
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
unsigned int alpha;
|
||||||
|
for (x = 0; x < xsize; x++, in+=4) {
|
||||||
|
alpha = in[3];
|
||||||
|
if (alpha) {
|
||||||
|
*out++ = CLIP((255 * in[0]) / alpha);
|
||||||
|
*out++ = CLIP((255 * in[1]) / alpha);
|
||||||
|
*out++ = CLIP((255 * in[2]) / alpha);
|
||||||
|
} else {
|
||||||
|
*out++ = in[0];
|
||||||
|
*out++ = in[1];
|
||||||
|
*out++ = in[2];
|
||||||
|
}
|
||||||
|
*out++ = in[3];
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ---------------- */
|
/* ---------------- */
|
||||||
/* CMYK conversions */
|
/* CMYK conversions */
|
||||||
/* ---------------- */
|
/* ---------------- */
|
||||||
|
@ -619,6 +644,8 @@ static struct {
|
||||||
{ "RGBA", "CMYK", rgb2cmyk },
|
{ "RGBA", "CMYK", rgb2cmyk },
|
||||||
{ "RGBA", "YCbCr", ImagingConvertRGB2YCbCr },
|
{ "RGBA", "YCbCr", ImagingConvertRGB2YCbCr },
|
||||||
|
|
||||||
|
{ "RGBa", "RGBA", rgba2rgbA },
|
||||||
|
|
||||||
{ "RGBX", "1", rgb2bit },
|
{ "RGBX", "1", rgb2bit },
|
||||||
{ "RGBX", "L", rgb2l },
|
{ "RGBX", "L", rgb2l },
|
||||||
{ "RGBA", "I", rgb2i },
|
{ "RGBA", "I", rgb2i },
|
||||||
|
|
Loading…
Reference in New Issue
Block a user