mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-26 18:06:18 +03:00
Merge pull request #1912 from uploadcare/premultiplied-luminosity
Premultiplied luminosity
This commit is contained in:
commit
761f470b92
|
@ -1539,6 +1539,9 @@ class Image(object):
|
|||
if self.mode in ("1", "P"):
|
||||
resample = NEAREST
|
||||
|
||||
if self.mode == 'LA':
|
||||
return self.convert('La').resize(size, resample).convert('LA')
|
||||
|
||||
if self.mode == 'RGBA':
|
||||
return self.convert('RGBa').resize(size, resample).convert('RGBA')
|
||||
|
||||
|
@ -1829,6 +1832,10 @@ class Image(object):
|
|||
:returns: An :py:class:`~PIL.Image.Image` object.
|
||||
"""
|
||||
|
||||
if self.mode == 'LA':
|
||||
return self.convert('La').transform(
|
||||
size, method, data, resample, fill).convert('LA')
|
||||
|
||||
if self.mode == 'RGBA':
|
||||
return self.convert('RGBa').transform(
|
||||
size, method, data, resample, fill).convert('RGBA')
|
||||
|
|
|
@ -278,6 +278,7 @@ mode_map = {'1': _PyAccess8,
|
|||
'L': _PyAccess8,
|
||||
'P': _PyAccess8,
|
||||
'LA': _PyAccess32_2,
|
||||
'La': _PyAccess32_2,
|
||||
'PA': _PyAccess32_2,
|
||||
'RGB': _PyAccess32_3,
|
||||
'LAB': _PyAccess32_3,
|
||||
|
|
|
@ -4,7 +4,7 @@ from __future__ import print_function
|
|||
|
||||
modes = [
|
||||
"1",
|
||||
"L", "LA",
|
||||
"L", "LA", "La",
|
||||
"I", "I;16", "I;16L", "I;16B", "I;32L", "I;32B",
|
||||
"F",
|
||||
"P", "PA",
|
||||
|
|
|
@ -186,5 +186,70 @@ class CoreResampleConsistencyTest(PillowTestCase):
|
|||
self.run_case(self.make_case('F', 1.192093e-07))
|
||||
|
||||
|
||||
class CoreResampleAlphaCorrectTest(PillowTestCase):
|
||||
def make_levels_case(self, mode):
|
||||
i = Image.new(mode, (256, 16))
|
||||
px = i.load()
|
||||
for y in range(i.size[1]):
|
||||
for x in range(i.size[0]):
|
||||
pix = [x] * len(mode)
|
||||
pix[-1] = 255 - y * 16
|
||||
px[x, y] = tuple(pix)
|
||||
return i
|
||||
|
||||
def run_levels_case(self, i):
|
||||
px = i.load()
|
||||
for y in range(i.size[1]):
|
||||
used_colors = set(px[x, y][0] for x in range(i.size[0]))
|
||||
self.assertEqual(256, len(used_colors),
|
||||
'All colors should present in resized image. '
|
||||
'Only {0} on {1} line.'.format(len(used_colors), y))
|
||||
|
||||
@unittest.skip("current implementation isn't precise enough")
|
||||
def test_levels_rgba(self):
|
||||
case = self.make_levels_case('RGBA')
|
||||
self.run_levels_case(case.resize((512, 32), Image.BILINEAR))
|
||||
self.run_levels_case(case.resize((512, 32), Image.BICUBIC))
|
||||
self.run_levels_case(case.resize((512, 32), Image.LANCZOS))
|
||||
|
||||
@unittest.skip("current implementation isn't precise enough")
|
||||
def test_levels_la(self):
|
||||
case = self.make_levels_case('LA')
|
||||
self.run_levels_case(case.resize((512, 32), Image.BILINEAR))
|
||||
self.run_levels_case(case.resize((512, 32), Image.BICUBIC))
|
||||
self.run_levels_case(case.resize((512, 32), Image.LANCZOS))
|
||||
|
||||
def make_dity_case(self, mode, clean_pixel, dirty_pixel):
|
||||
i = Image.new(mode, (64, 64), dirty_pixel)
|
||||
px = i.load()
|
||||
xdiv4 = i.size[0] // 4
|
||||
ydiv4 = i.size[1] // 4
|
||||
for y in range(ydiv4 * 2):
|
||||
for x in range(xdiv4 * 2):
|
||||
px[x + xdiv4, y + ydiv4] = clean_pixel
|
||||
return i
|
||||
|
||||
def run_dity_case(self, i, clean_pixel):
|
||||
px = i.load()
|
||||
for y in range(i.size[1]):
|
||||
for x in range(i.size[0]):
|
||||
if px[x, y][-1] != 0 and px[x, y][:-1] != clean_pixel:
|
||||
message = 'pixel at ({0}, {1}) is differ:\n{2}\n{3}'\
|
||||
.format(x, y, px[x, y], clean_pixel)
|
||||
self.assertEqual(px[x, y][:3], clean_pixel, message)
|
||||
|
||||
def test_dirty_pixels_rgba(self):
|
||||
case = self.make_dity_case('RGBA', (255, 255, 0, 128), (0, 0, 255, 0))
|
||||
self.run_dity_case(case.resize((20, 20), Image.BILINEAR), (255, 255, 0))
|
||||
self.run_dity_case(case.resize((20, 20), Image.BICUBIC), (255, 255, 0))
|
||||
self.run_dity_case(case.resize((20, 20), Image.LANCZOS), (255, 255, 0))
|
||||
|
||||
def test_dirty_pixels_la(self):
|
||||
case = self.make_dity_case('LA', (255, 128), (0, 0))
|
||||
self.run_dity_case(case.resize((20, 20), Image.BILINEAR), (255,))
|
||||
self.run_dity_case(case.resize((20, 20), Image.BICUBIC), (255,))
|
||||
self.run_dity_case(case.resize((20, 20), Image.LANCZOS), (255,))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -222,6 +222,7 @@ ImagingAccessInit()
|
|||
ADD("1", line_8, get_pixel_8, put_pixel_8);
|
||||
ADD("L", line_8, get_pixel_8, put_pixel_8);
|
||||
ADD("LA", line_32, get_pixel, put_pixel);
|
||||
ADD("La", line_32, get_pixel, put_pixel);
|
||||
ADD("I", line_32, get_pixel_32, put_pixel_32);
|
||||
ADD("I;16", line_16, get_pixel_16L, put_pixel_16L);
|
||||
ADD("I;16L", line_16, get_pixel_16L, put_pixel_16L);
|
||||
|
|
|
@ -116,6 +116,42 @@ l2bit(UINT8* out, const UINT8* in, int xsize)
|
|||
*out++ = (*in++ >= 128) ? 255 : 0;
|
||||
}
|
||||
|
||||
static void
|
||||
lA2la(UINT8* out, const UINT8* in, int xsize)
|
||||
{
|
||||
int x;
|
||||
unsigned int alpha, pixel, tmp;
|
||||
for (x = 0; x < xsize; x++, in += 4) {
|
||||
alpha = in[3];
|
||||
pixel = MULDIV255(in[0], alpha, tmp);
|
||||
*out++ = (UINT8) pixel;
|
||||
*out++ = (UINT8) pixel;
|
||||
*out++ = (UINT8) pixel;
|
||||
*out++ = (UINT8) alpha;
|
||||
}
|
||||
}
|
||||
|
||||
/* RGBa -> RGBA conversion to remove premultiplication
|
||||
Needed for correct transforms/resizing on RGBA images */
|
||||
static void
|
||||
la2lA(UINT8* out, const UINT8* in, int xsize)
|
||||
{
|
||||
int x;
|
||||
unsigned int alpha, pixel;
|
||||
for (x = 0; x < xsize; x++, in+=4) {
|
||||
alpha = in[3];
|
||||
if (alpha == 255 || alpha == 0) {
|
||||
pixel = in[0];
|
||||
} else {
|
||||
pixel = CLIP((255 * in[0]) / alpha);
|
||||
}
|
||||
*out++ = (UINT8) pixel;
|
||||
*out++ = (UINT8) pixel;
|
||||
*out++ = (UINT8) pixel;
|
||||
*out++ = (UINT8) alpha;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
l2la(UINT8* out, const UINT8* in, int xsize)
|
||||
{
|
||||
|
@ -405,7 +441,7 @@ rgba2rgb(UINT8* out, const UINT8* in, int xsize)
|
|||
}
|
||||
|
||||
static void
|
||||
rgba2rgba(UINT8* out, const UINT8* in, int xsize)
|
||||
rgbA2rgba(UINT8* out, const UINT8* in, int xsize)
|
||||
{
|
||||
int x;
|
||||
unsigned int alpha, tmp;
|
||||
|
@ -427,17 +463,16 @@ rgba2rgbA(UINT8* out, const UINT8* in, int xsize)
|
|||
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 {
|
||||
if (alpha == 255 || alpha == 0) {
|
||||
*out++ = in[0];
|
||||
*out++ = in[1];
|
||||
*out++ = in[2];
|
||||
} else {
|
||||
*out++ = CLIP((255 * in[0]) / alpha);
|
||||
*out++ = CLIP((255 * in[1]) / alpha);
|
||||
*out++ = CLIP((255 * in[2]) / alpha);
|
||||
}
|
||||
*out++ = in[3];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -765,10 +800,13 @@ static struct {
|
|||
{ "L", "YCbCr", l2ycbcr },
|
||||
|
||||
{ "LA", "L", la2l },
|
||||
{ "LA", "La", lA2la },
|
||||
{ "LA", "RGB", la2rgb },
|
||||
{ "LA", "RGBX", la2rgb },
|
||||
{ "LA", "RGBA", la2rgb },
|
||||
|
||||
{ "La", "LA", la2lA },
|
||||
|
||||
{ "I", "L", i2l },
|
||||
{ "I", "F", i2f },
|
||||
|
||||
|
@ -795,7 +833,7 @@ static struct {
|
|||
{ "RGBA", "I", rgb2i },
|
||||
{ "RGBA", "F", rgb2f },
|
||||
{ "RGBA", "RGB", rgba2rgb },
|
||||
{ "RGBA", "RGBa", rgba2rgba },
|
||||
{ "RGBA", "RGBa", rgbA2rgba },
|
||||
{ "RGBA", "RGBX", rgb2rgba },
|
||||
{ "RGBA", "CMYK", rgb2cmyk },
|
||||
{ "RGBA", "YCbCr", ImagingConvertRGB2YCbCr },
|
||||
|
|
|
@ -91,6 +91,12 @@ ImagingNewPrologueSubtype(const char *mode, unsigned xsize, unsigned ysize,
|
|||
im->pixelsize = 4; /* store in image32 memory */
|
||||
im->linesize = xsize * 4;
|
||||
|
||||
} else if (strcmp(mode, "La") == 0) {
|
||||
/* 8-bit greyscale (luminance) with premultiplied alpha */
|
||||
im->bands = 2;
|
||||
im->pixelsize = 4; /* store in image32 memory */
|
||||
im->linesize = xsize * 4;
|
||||
|
||||
} else if (strcmp(mode, "F") == 0) {
|
||||
/* 32-bit floating point images */
|
||||
im->bands = 1;
|
||||
|
|
Loading…
Reference in New Issue
Block a user