Skip to content

Commit

Permalink
Merge pull request #665 from hugovk/transparency
Browse files Browse the repository at this point in the history
Remove transparency resource after converting P->RGBA, Fixes #664
  • Loading branch information
wiredfool committed May 20, 2014
2 parents fc55580 + 5c24952 commit fb164d0
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 41 deletions.
39 changes: 20 additions & 19 deletions PIL/Image.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def __getattr__(self, id):
import numbers

# works everywhere, win for pypy, not cpython
USE_CFFI_ACCESS = hasattr(sys, 'pypy_version_info')
USE_CFFI_ACCESS = hasattr(sys, 'pypy_version_info')
try:
import cffi
HAS_CFFI=True
Expand Down Expand Up @@ -233,7 +233,7 @@ def isImageType(t):
"CMYK": ('|u1', 4),
"YCbCr": ('|u1', 3),
"LAB": ('|u1', 3), # UNDONE - unsigned |u1i1i1
# I;16 == I;16L, and I;32 == I;32L
# I;16 == I;16L, and I;32 == I;32L
"I;16": ('<u2', None),
"I;16B": ('>u2', None),
"I;16L": ('<u2', None),
Expand Down Expand Up @@ -502,7 +502,7 @@ def __enter__(self):
return self
def __exit__(self, *args):
self.close()

def close(self):
"""
Closes the file pointer, if possible.
Expand All @@ -524,7 +524,7 @@ def close(self):
# deferred error that will better explain that the core image
# object is gone.
self.im = deferred_error(ValueError("Operation on closed image"))


def _copy(self):
self.load()
Expand All @@ -540,7 +540,7 @@ def _dump(self, file=None, format=None):
if not file:
f, file = tempfile.mkstemp(suffix)
os.close(f)

self.load()
if not format or format == "PPM":
self.im.save_ppm(file)
Expand Down Expand Up @@ -672,7 +672,7 @@ def load(self):
normal cases, you don't need to call this method, since the
Image class automatically loads an opened image when it is
accessed for the first time. This method will close the file
associated with the image.
associated with the image.
:returns: An image access object.
"""
Expand Down Expand Up @@ -777,7 +777,7 @@ def convert(self, mode=None, matrix=None, dither=None,
if "transparency" in self.info and self.info['transparency'] is not None:
if self.mode in ('L', 'RGB') and mode == 'RGBA':
# Use transparent conversion to promote from transparent
# color to an alpha channel.
# color to an alpha channel.
return self._new(self.im.convert_transparent(
mode, self.info['transparency']))
elif self.mode in ('L', 'RGB', 'P') and mode in ('L', 'RGB', 'P'):
Expand All @@ -799,19 +799,20 @@ def convert(self, mode=None, matrix=None, dither=None,
trns_im = trns_im.convert(mode)
else:
# can't just retrieve the palette number, got to do it
# after quantization.
# after quantization.
trns_im = trns_im.convert('RGB')
trns = trns_im.getpixel((0,0))


elif self.mode == 'P' and mode == 'RGBA':
delete_trns = True

if mode == "P" and palette == ADAPTIVE:
im = self.im.quantize(colors)
new = self._new(im)
from PIL import ImagePalette
new.palette = ImagePalette.raw("RGB", new.im.getpalette("RGB"))
if delete_trns:
# This could possibly happen if we requantize to fewer colors.
# The transparency would be totally off in that case.
# The transparency would be totally off in that case.
del(new.info['transparency'])
if trns is not None:
try:
Expand All @@ -826,7 +827,7 @@ def convert(self, mode=None, matrix=None, dither=None,
# colorspace conversion
if dither is None:
dither = FLOYDSTEINBERG

try:
im = self.im.convert(mode, dither)
except ValueError:
Expand Down Expand Up @@ -863,18 +864,18 @@ def quantize(self, colors=256, method=None, kmeans=0, palette=None):
# quantizer interface in a later version of PIL.

self.load()

if method is None:
# defaults:
method = 0
if self.mode == 'RGBA':
method = 2

if self.mode == 'RGBA' and method != 2:
# Caller specified an invalid mode.
# Caller specified an invalid mode.
raise ValueError('Fast Octree (method == 2) is the ' +
' only valid method for quantizing RGBA images')

if palette:
# use palette from reference image
palette.load()
Expand Down Expand Up @@ -928,7 +929,7 @@ def crop(self, box=None):
def draft(self, mode, size):
"""
NYI
Configures the image file loader so it returns a version of the
image that as closely as possible matches the given mode and
size. For example, you can use this method to convert a color
Expand Down Expand Up @@ -1277,7 +1278,7 @@ def point(self, lut, mode=None):
if self.mode in ("I", "I;16", "F"):
# check if the function can be used with point_transform
# UNDONE wiredfool -- I think this prevents us from ever doing
# a gamma function point transform on > 8bit images.
# a gamma function point transform on > 8bit images.
scale, offset = _getscaleoffset(lut)
return self._new(self.im.point_transform(scale, offset))
# for other modes, convert the function to a table
Expand Down Expand Up @@ -1420,8 +1421,8 @@ def putpixel(self, xy, value):
self._copy()
self.pyaccess = None
self.load()
if self.pyaccess:

if self.pyaccess:
return self.pyaccess.putpixel(xy,value)
return self.im.putpixel(xy, value)

Expand Down
62 changes: 40 additions & 22 deletions Tests/test_image_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from PIL import Image


def test_sanity():

def convert(im, mode):
Expand All @@ -16,6 +17,7 @@ def convert(im, mode):
for mode in modes:
yield_test(convert, im, mode)


def test_default():

im = lena("P")
Expand All @@ -26,26 +28,29 @@ def test_default():
assert_image(im, "RGB", im.size)



# ref https://github.com/python-imaging/Pillow/issues/274

def _test_float_conversion(im):
orig = im.getpixel((5,5))
converted = im.convert('F').getpixel((5,5))
orig = im.getpixel((5, 5))
converted = im.convert('F').getpixel((5, 5))
assert_equal(orig, converted)


def test_8bit():
im = Image.open('Images/lena.jpg')
_test_float_conversion(im.convert('L'))


def test_16bit():
im = Image.open('Tests/images/16bit.cropped.tif')
_test_float_conversion(im)


def test_16bit_workaround():
im = Image.open('Tests/images/16bit.cropped.tif')
_test_float_conversion(im.convert('I'))



def test_rgba_p():
im = lena('RGBA')
im.putalpha(lena('L'))
Expand All @@ -54,59 +59,72 @@ def test_rgba_p():
comparable = converted.convert('RGBA')

assert_image_similar(im, comparable, 20)

def test_trns_p():


def test_trns_p():
im = lena('P')
im.info['transparency']=0
im.info['transparency'] = 0

f = tempfile('temp.png')

l = im.convert('L')
assert_equal(l.info['transparency'], 0) # undone
assert_equal(l.info['transparency'], 0) # undone
assert_no_exception(lambda: l.save(f))


rgb = im.convert('RGB')
assert_equal(rgb.info['transparency'], (0,0,0)) # undone
assert_equal(rgb.info['transparency'], (0, 0, 0)) # undone
assert_no_exception(lambda: rgb.save(f))



# ref https://github.com/python-imaging/Pillow/issues/664

def test_trns_p_rgba():
# Arrange
im = lena('P')
im.info['transparency'] = 128

# Act
rgba = im.convert('RGBA')

# Assert
assert_false('transparency' in rgba.info)


def test_trns_l():
im = lena('L')
im.info['transparency'] = 128

f = tempfile('temp.png')

rgb = im.convert('RGB')
assert_equal(rgb.info['transparency'], (128,128,128)) # undone
assert_equal(rgb.info['transparency'], (128, 128, 128)) # undone
assert_no_exception(lambda: rgb.save(f))

p = im.convert('P')
assert_true('transparency' in p.info)
assert_no_exception(lambda: p.save(f))

p = assert_warning(UserWarning,
lambda: im.convert('P', palette = Image.ADAPTIVE))
lambda: im.convert('P', palette=Image.ADAPTIVE))
assert_false('transparency' in p.info)
assert_no_exception(lambda: p.save(f))


def test_trns_RGB():
im = lena('RGB')
im.info['transparency'] = im.getpixel((0,0))
im.info['transparency'] = im.getpixel((0, 0))

f = tempfile('temp.png')

l = im.convert('L')
assert_equal(l.info['transparency'], l.getpixel((0,0))) # undone
assert_equal(l.info['transparency'], l.getpixel((0, 0))) # undone
assert_no_exception(lambda: l.save(f))

p = im.convert('P')
assert_true('transparency' in p.info)
assert_no_exception(lambda: p.save(f))

p = assert_warning(UserWarning,
lambda: im.convert('P', palette = Image.ADAPTIVE))
lambda: im.convert('P', palette=Image.ADAPTIVE))
assert_false('transparency' in p.info)
assert_no_exception(lambda: p.save(f))


0 comments on commit fb164d0

Please sign in to comment.