mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-05-02 23:13:40 +03:00
Merge remote-tracking branch 'upstream/master' into hopper4
This commit is contained in:
commit
0ccc445ebf
22
.travis.yml
22
.travis.yml
|
@ -16,14 +16,14 @@ python:
|
||||||
- 3.4
|
- 3.4
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- "sudo apt-get -qq install libfreetype6-dev liblcms2-dev python-qt4 ghostscript libffi-dev libjpeg-turbo-progs cmake imagemagick"
|
- "travis_retry sudo apt-get -qq install libfreetype6-dev liblcms2-dev python-qt4 ghostscript libffi-dev libjpeg-turbo-progs cmake imagemagick"
|
||||||
- "pip install cffi"
|
- "travis_retry pip install cffi"
|
||||||
- "pip install coverage nose"
|
- "travis_retry pip install coverage nose"
|
||||||
|
|
||||||
# Pyroma installation is slow on Py3, so just do it for Py2.
|
# Pyroma installation is slow on Py3, so just do it for Py2.
|
||||||
- if [ ${TRAVIS_PYTHON_VERSION:0:1} == "2" ]; then travis_retry pip install pyroma; fi
|
- if [ ${TRAVIS_PYTHON_VERSION:0:1} == "2" ]; then travis_retry pip install pyroma; fi
|
||||||
|
|
||||||
- if [ "$TRAVIS_PYTHON_VERSION" == "2.6" ]; then pip install unittest2; fi
|
- if [ "$TRAVIS_PYTHON_VERSION" == "2.6" ]; then travis_retry pip install unittest2; fi
|
||||||
|
|
||||||
# webp
|
# webp
|
||||||
- pushd depends && ./install_webp.sh && popd
|
- pushd depends && ./install_webp.sh && popd
|
||||||
|
@ -37,26 +37,24 @@ script:
|
||||||
- CFLAGS="-coverage" python setup.py build_ext --inplace
|
- CFLAGS="-coverage" python setup.py build_ext --inplace
|
||||||
|
|
||||||
- coverage run --append --include=PIL/* selftest.py
|
- coverage run --append --include=PIL/* selftest.py
|
||||||
# FIXME: re-add -x option to fail fast
|
- coverage run --append --include=PIL/* -m nose -vx Tests/test_*.py
|
||||||
# - coverage run --append --include=PIL/* -m nose -vx Tests/test_*.py
|
|
||||||
- coverage run --append --include=PIL/* -m nose -v Tests/test_*.py
|
|
||||||
|
|
||||||
after_success:
|
after_success:
|
||||||
# gather the coverage data
|
# gather the coverage data
|
||||||
- sudo apt-get -qq install lcov
|
- travis_retry sudo apt-get -qq install lcov
|
||||||
- lcov --capture --directory . -b . --output-file coverage.info
|
- lcov --capture --directory . -b . --output-file coverage.info
|
||||||
# filter to remove system headers
|
# filter to remove system headers
|
||||||
- lcov --remove coverage.info '/usr/*' -o coverage.filtered.info
|
- lcov --remove coverage.info '/usr/*' -o coverage.filtered.info
|
||||||
# convert to json
|
# convert to json
|
||||||
- gem install coveralls-lcov
|
- travis_retry gem install coveralls-lcov
|
||||||
- coveralls-lcov -v -n coverage.filtered.info > coverage.c.json
|
- coveralls-lcov -v -n coverage.filtered.info > coverage.c.json
|
||||||
|
|
||||||
- coverage report
|
- coverage report
|
||||||
- pip install coveralls-merge
|
- travis_retry pip install coveralls-merge
|
||||||
- coveralls-merge coverage.c.json
|
- coveralls-merge coverage.c.json
|
||||||
|
|
||||||
|
|
||||||
- pip install pep8 pyflakes
|
- travis_retry pip install pep8 pyflakes
|
||||||
- pep8 --statistics --count PIL/*.py
|
- pep8 --statistics --count PIL/*.py
|
||||||
- pep8 --statistics --count Tests/*.py
|
- pep8 --statistics --count Tests/*.py
|
||||||
- pyflakes PIL/*.py | tee >(wc -l)
|
- pyflakes PIL/*.py | tee >(wc -l)
|
||||||
|
@ -67,3 +65,5 @@ after_success:
|
||||||
# (Installation is very slow on Py3, so just do it for Py2.)
|
# (Installation is very slow on Py3, so just do it for Py2.)
|
||||||
- if [ ${TRAVIS_PYTHON_VERSION:0:1} == "2" ]; then Scripts/diffcover-install.sh; fi
|
- if [ ${TRAVIS_PYTHON_VERSION:0:1} == "2" ]; then Scripts/diffcover-install.sh; fi
|
||||||
- if [ ${TRAVIS_PYTHON_VERSION:0:1} == "2" ]; then Scripts/diffcover-run.sh; fi
|
- if [ ${TRAVIS_PYTHON_VERSION:0:1} == "2" ]; then Scripts/diffcover-run.sh; fi
|
||||||
|
matrix:
|
||||||
|
fast_finish: true
|
||||||
|
|
27
CHANGES.rst
27
CHANGES.rst
|
@ -4,10 +4,31 @@ Changelog (Pillow)
|
||||||
2.6.0 (unreleased)
|
2.6.0 (unreleased)
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
- Fix for reading multipage TIFFs #885
|
- On Windows, do not execute convert.exe without specifying path #912
|
||||||
[kostrom, wiredfool]
|
[cgohlke]
|
||||||
|
|
||||||
- Correctly handle saving gray and CMYK JPEGs with quality-keep #857
|
- Fix msvc build error #911
|
||||||
|
[cgohlke]
|
||||||
|
|
||||||
|
- Fix for handling P + transparency -> RGBA conversions #904
|
||||||
|
[wiredfool]
|
||||||
|
|
||||||
|
- Retain alpha in ImageEnhance operations #909
|
||||||
|
[wiredfool]
|
||||||
|
|
||||||
|
- Jpeg2k Decode/encode memory leak fix #898
|
||||||
|
[joshware, wiredfool]
|
||||||
|
|
||||||
|
- EpsFilePlugin Speed improvements #886
|
||||||
|
[wiredfool, karstenw]
|
||||||
|
|
||||||
|
- Don't resize if already the right size #892
|
||||||
|
[radarhere]
|
||||||
|
|
||||||
|
- Fix for reading multipage TIFFs #885
|
||||||
|
[kostrom, wiredfool]
|
||||||
|
|
||||||
|
- Correctly handle saving gray and CMYK JPEGs with quality=keep #857
|
||||||
[etienned]
|
[etienned]
|
||||||
|
|
||||||
- Correct duplicate Tiff Metadata and Exif tag values
|
- Correct duplicate Tiff Metadata and Exif tag values
|
||||||
|
|
|
@ -7,7 +7,7 @@ Send a pull request. We'll generally want documentation and [tests](Tests/README
|
||||||
- Fork the repo
|
- Fork the repo
|
||||||
- Make a branch
|
- Make a branch
|
||||||
- Add your changes + Tests
|
- Add your changes + Tests
|
||||||
- Run the test suite. Try to run on both Python 2.x and 3.x, or you'll get tripped up. You can enable [Travis CI on your repo](https://travis-ci.org/profile/) to catch test failures prior to the pull request.
|
- Run the test suite. Try to run on both Python 2.x and 3.x, or you'll get tripped up. You can enable [Travis CI on your repo](https://travis-ci.org/profile/) to catch test failures prior to the pull request, and [Coveralls](https://coveralls.io/repos/new) to see if the changed code is covered by tests.
|
||||||
- Push to your fork, and make a pull request.
|
- Push to your fork, and make a pull request.
|
||||||
|
|
||||||
A few guidelines:
|
A few guidelines:
|
||||||
|
|
|
@ -86,26 +86,32 @@ def Ghostscript(tile, size, fp, scale=1):
|
||||||
|
|
||||||
out_fd, outfile = tempfile.mkstemp()
|
out_fd, outfile = tempfile.mkstemp()
|
||||||
os.close(out_fd)
|
os.close(out_fd)
|
||||||
in_fd, infile = tempfile.mkstemp()
|
|
||||||
os.close(in_fd)
|
|
||||||
|
|
||||||
# ignore length and offset!
|
infile_temp = None
|
||||||
# ghostscript can read it
|
if hasattr(fp, 'name') and os.path.exists(fp.name):
|
||||||
# copy whole file to read in ghostscript
|
infile = fp.name
|
||||||
with open(infile, 'wb') as f:
|
else:
|
||||||
# fetch length of fp
|
in_fd, infile_temp = tempfile.mkstemp()
|
||||||
fp.seek(0, 2)
|
os.close(in_fd)
|
||||||
fsize = fp.tell()
|
infile = infile_temp
|
||||||
# ensure start position
|
|
||||||
# go back
|
# ignore length and offset!
|
||||||
fp.seek(0)
|
# ghostscript can read it
|
||||||
lengthfile = fsize
|
# copy whole file to read in ghostscript
|
||||||
while lengthfile > 0:
|
with open(infile_temp, 'wb') as f:
|
||||||
s = fp.read(min(lengthfile, 100*1024))
|
# fetch length of fp
|
||||||
if not s:
|
fp.seek(0, 2)
|
||||||
break
|
fsize = fp.tell()
|
||||||
length -= len(s)
|
# ensure start position
|
||||||
f.write(s)
|
# go back
|
||||||
|
fp.seek(0)
|
||||||
|
lengthfile = fsize
|
||||||
|
while lengthfile > 0:
|
||||||
|
s = fp.read(min(lengthfile, 100*1024))
|
||||||
|
if not s:
|
||||||
|
break
|
||||||
|
lengthfile -= len(s)
|
||||||
|
f.write(s)
|
||||||
|
|
||||||
# Build ghostscript command
|
# Build ghostscript command
|
||||||
command = ["gs",
|
command = ["gs",
|
||||||
|
@ -136,49 +142,36 @@ def Ghostscript(tile, size, fp, scale=1):
|
||||||
finally:
|
finally:
|
||||||
try:
|
try:
|
||||||
os.unlink(outfile)
|
os.unlink(outfile)
|
||||||
os.unlink(infile)
|
if infile_temo:
|
||||||
|
os.unlink(infile_temp)
|
||||||
except: pass
|
except: pass
|
||||||
|
|
||||||
return im
|
return im
|
||||||
|
|
||||||
|
|
||||||
class PSFile:
|
class PSFile:
|
||||||
"""Wrapper that treats either CR or LF as end of line."""
|
"""Wrapper for bytesio object that treats either CR or LF as end of line."""
|
||||||
def __init__(self, fp):
|
def __init__(self, fp):
|
||||||
self.fp = fp
|
self.fp = fp
|
||||||
self.char = None
|
self.char = None
|
||||||
def __getattr__(self, id):
|
|
||||||
v = getattr(self.fp, id)
|
|
||||||
setattr(self, id, v)
|
|
||||||
return v
|
|
||||||
def seek(self, offset, whence=0):
|
def seek(self, offset, whence=0):
|
||||||
self.char = None
|
self.char = None
|
||||||
self.fp.seek(offset, whence)
|
self.fp.seek(offset, whence)
|
||||||
def read(self, count):
|
|
||||||
return self.fp.read(count).decode('latin-1')
|
|
||||||
def readbinary(self, count):
|
|
||||||
return self.fp.read(count)
|
|
||||||
def tell(self):
|
|
||||||
pos = self.fp.tell()
|
|
||||||
if self.char:
|
|
||||||
pos -= 1
|
|
||||||
return pos
|
|
||||||
def readline(self):
|
def readline(self):
|
||||||
s = b""
|
s = self.char or b""
|
||||||
if self.char:
|
self.char = None
|
||||||
c = self.char
|
|
||||||
self.char = None
|
c = self.fp.read(1)
|
||||||
else:
|
|
||||||
c = self.fp.read(1)
|
|
||||||
while c not in b"\r\n":
|
while c not in b"\r\n":
|
||||||
s = s + c
|
s = s + c
|
||||||
c = self.fp.read(1)
|
c = self.fp.read(1)
|
||||||
if c == b"\r":
|
|
||||||
self.char = self.fp.read(1)
|
|
||||||
if self.char == b"\n":
|
|
||||||
self.char = None
|
|
||||||
return s.decode('latin-1') + "\n"
|
|
||||||
|
|
||||||
|
self.char = self.fp.read(1)
|
||||||
|
# line endings can be 1 or 2 of \r \n, in either order
|
||||||
|
if self.char in b"\r\n":
|
||||||
|
self.char = None
|
||||||
|
|
||||||
|
return s.decode('latin-1')
|
||||||
|
|
||||||
def _accept(prefix):
|
def _accept(prefix):
|
||||||
return prefix[:4] == b"%!PS" or i32(prefix) == 0xC6D3D0C5
|
return prefix[:4] == b"%!PS" or i32(prefix) == 0xC6D3D0C5
|
||||||
|
@ -193,32 +186,23 @@ class EpsImageFile(ImageFile.ImageFile):
|
||||||
format = "EPS"
|
format = "EPS"
|
||||||
format_description = "Encapsulated Postscript"
|
format_description = "Encapsulated Postscript"
|
||||||
|
|
||||||
|
mode_map = { 1:"L", 2:"LAB", 3:"RGB" }
|
||||||
|
|
||||||
def _open(self):
|
def _open(self):
|
||||||
|
(length, offset) = self._find_offset(self.fp)
|
||||||
|
|
||||||
fp = PSFile(self.fp)
|
# Rewrap the open file pointer in something that will
|
||||||
|
# convert line endings and decode to latin-1.
|
||||||
# FIX for: Some EPS file not handled correctly / issue #302
|
try:
|
||||||
# EPS can contain binary data
|
if bytes is str:
|
||||||
# or start directly with latin coding
|
# Python2, no encoding conversion necessary
|
||||||
# read header in both ways to handle both
|
fp = open(self.fp.name, "Ur")
|
||||||
# file types
|
else:
|
||||||
# more info see http://partners.adobe.com/public/developer/en/ps/5002.EPSF_Spec.pdf
|
# Python3, can use bare open command.
|
||||||
|
fp = open(self.fp.name, "Ur", encoding='latin-1')
|
||||||
# for HEAD without binary preview
|
except Exception as msg:
|
||||||
s = fp.read(4)
|
# Expect this for bytesio/stringio
|
||||||
# for HEAD with binary preview
|
fp = PSFile(self.fp)
|
||||||
fp.seek(0)
|
|
||||||
sb = fp.readbinary(160)
|
|
||||||
|
|
||||||
if s[:4] == "%!PS":
|
|
||||||
fp.seek(0, 2)
|
|
||||||
length = fp.tell()
|
|
||||||
offset = 0
|
|
||||||
elif i32(sb[0:4]) == 0xC6D3D0C5:
|
|
||||||
offset = i32(sb[4:8])
|
|
||||||
length = i32(sb[8:12])
|
|
||||||
else:
|
|
||||||
raise SyntaxError("not an EPS file")
|
|
||||||
|
|
||||||
# go to offset - start of "%!PS"
|
# go to offset - start of "%!PS"
|
||||||
fp.seek(offset)
|
fp.seek(offset)
|
||||||
|
@ -231,18 +215,12 @@ class EpsImageFile(ImageFile.ImageFile):
|
||||||
#
|
#
|
||||||
# Load EPS header
|
# Load EPS header
|
||||||
|
|
||||||
s = fp.readline()
|
s = fp.readline().strip('\r\n')
|
||||||
|
|
||||||
while s:
|
while s:
|
||||||
|
|
||||||
if len(s) > 255:
|
if len(s) > 255:
|
||||||
raise SyntaxError("not an EPS file")
|
raise SyntaxError("not an EPS file")
|
||||||
|
|
||||||
if s[-2:] == '\r\n':
|
|
||||||
s = s[:-2]
|
|
||||||
elif s[-1:] == '\n':
|
|
||||||
s = s[:-1]
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
m = split.match(s)
|
m = split.match(s)
|
||||||
except re.error as v:
|
except re.error as v:
|
||||||
|
@ -264,9 +242,7 @@ class EpsImageFile(ImageFile.ImageFile):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
m = field.match(s)
|
m = field.match(s)
|
||||||
|
|
||||||
if m:
|
if m:
|
||||||
k = m.group(1)
|
k = m.group(1)
|
||||||
|
|
||||||
|
@ -276,16 +252,16 @@ class EpsImageFile(ImageFile.ImageFile):
|
||||||
self.info[k[:8]] = k[9:]
|
self.info[k[:8]] = k[9:]
|
||||||
else:
|
else:
|
||||||
self.info[k] = ""
|
self.info[k] = ""
|
||||||
elif s[0:1] == '%':
|
elif s[0] == '%':
|
||||||
# handle non-DSC Postscript comments that some
|
# handle non-DSC Postscript comments that some
|
||||||
# tools mistakenly put in the Comments section
|
# tools mistakenly put in the Comments section
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
raise IOError("bad EPS header")
|
raise IOError("bad EPS header")
|
||||||
|
|
||||||
s = fp.readline()
|
s = fp.readline().strip('\r\n')
|
||||||
|
|
||||||
if s[:1] != "%":
|
if s[0] != "%":
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
|
@ -297,63 +273,48 @@ class EpsImageFile(ImageFile.ImageFile):
|
||||||
if len(s) > 255:
|
if len(s) > 255:
|
||||||
raise SyntaxError("not an EPS file")
|
raise SyntaxError("not an EPS file")
|
||||||
|
|
||||||
if s[-2:] == '\r\n':
|
|
||||||
s = s[:-2]
|
|
||||||
elif s[-1:] == '\n':
|
|
||||||
s = s[:-1]
|
|
||||||
|
|
||||||
if s[:11] == "%ImageData:":
|
if s[:11] == "%ImageData:":
|
||||||
|
# Encoded bitmapped image.
|
||||||
|
[x, y, bi, mo, z3, z4, en, id] = s[11:].split(None, 7)
|
||||||
|
|
||||||
[x, y, bi, mo, z3, z4, en, id] =\
|
if int(bi) != 8:
|
||||||
s[11:].split(None, 7)
|
|
||||||
|
|
||||||
x = int(x); y = int(y)
|
|
||||||
|
|
||||||
bi = int(bi)
|
|
||||||
mo = int(mo)
|
|
||||||
|
|
||||||
en = int(en)
|
|
||||||
|
|
||||||
if en == 1:
|
|
||||||
decoder = "eps_binary"
|
|
||||||
elif en == 2:
|
|
||||||
decoder = "eps_hex"
|
|
||||||
else:
|
|
||||||
break
|
break
|
||||||
if bi != 8:
|
try:
|
||||||
break
|
self.mode = self.mode_map[int(mo)]
|
||||||
if mo == 1:
|
except:
|
||||||
self.mode = "L"
|
|
||||||
elif mo == 2:
|
|
||||||
self.mode = "LAB"
|
|
||||||
elif mo == 3:
|
|
||||||
self.mode = "RGB"
|
|
||||||
else:
|
|
||||||
break
|
break
|
||||||
|
|
||||||
if id[:1] == id[-1:] == '"':
|
self.size = int(x), int(y)
|
||||||
id = id[1:-1]
|
return
|
||||||
|
|
||||||
# Scan forward to the actual image data
|
s = fp.readline().strip('\r\n')
|
||||||
while True:
|
|
||||||
s = fp.readline()
|
|
||||||
if not s:
|
|
||||||
break
|
|
||||||
if s[:len(id)] == id:
|
|
||||||
self.size = x, y
|
|
||||||
self.tile2 = [(decoder,
|
|
||||||
(0, 0, x, y),
|
|
||||||
fp.tell(),
|
|
||||||
0)]
|
|
||||||
return
|
|
||||||
|
|
||||||
s = fp.readline()
|
|
||||||
if not s:
|
if not s:
|
||||||
break
|
break
|
||||||
|
|
||||||
if not box:
|
if not box:
|
||||||
raise IOError("cannot determine EPS bounding box")
|
raise IOError("cannot determine EPS bounding box")
|
||||||
|
|
||||||
|
def _find_offset(self, fp):
|
||||||
|
|
||||||
|
s = fp.read(160)
|
||||||
|
|
||||||
|
if s[:4] == b"%!PS":
|
||||||
|
# for HEAD without binary preview
|
||||||
|
fp.seek(0, 2)
|
||||||
|
length = fp.tell()
|
||||||
|
offset = 0
|
||||||
|
elif i32(s[0:4]) == 0xC6D3D0C5:
|
||||||
|
# FIX for: Some EPS file not handled correctly / issue #302
|
||||||
|
# EPS can contain binary data
|
||||||
|
# or start directly with latin coding
|
||||||
|
# more info see http://partners.adobe.com/public/developer/en/ps/5002.EPSF_Spec.pdf
|
||||||
|
offset = i32(s[4:8])
|
||||||
|
length = i32(s[8:12])
|
||||||
|
else:
|
||||||
|
raise SyntaxError("not an EPS file")
|
||||||
|
|
||||||
|
return (length, offset)
|
||||||
|
|
||||||
def load(self, scale=1):
|
def load(self, scale=1):
|
||||||
# Load EPS via Ghostscript
|
# Load EPS via Ghostscript
|
||||||
if not self.tile:
|
if not self.tile:
|
||||||
|
|
15
PIL/Image.py
15
PIL/Image.py
|
@ -530,7 +530,7 @@ class Image:
|
||||||
"""
|
"""
|
||||||
Closes the file pointer, if possible.
|
Closes the file pointer, if possible.
|
||||||
|
|
||||||
This operation will destroy the image core and release it's memory.
|
This operation will destroy the image core and release its memory.
|
||||||
The image data will be unusable afterward.
|
The image data will be unusable afterward.
|
||||||
|
|
||||||
This function is only required to close images that have not
|
This function is only required to close images that have not
|
||||||
|
@ -867,8 +867,18 @@ class Image:
|
||||||
trns = trns_im.getpixel((0,0))
|
trns = trns_im.getpixel((0,0))
|
||||||
|
|
||||||
elif self.mode == 'P' and mode == 'RGBA':
|
elif self.mode == 'P' and mode == 'RGBA':
|
||||||
|
t = self.info['transparency']
|
||||||
delete_trns = True
|
delete_trns = True
|
||||||
|
|
||||||
|
if isinstance(t, bytes):
|
||||||
|
self.im.putpalettealphas(t)
|
||||||
|
elif isinstance(t, int):
|
||||||
|
self.im.putpalettealpha(t,0)
|
||||||
|
else:
|
||||||
|
raise ValueError("Transparency for P mode should" +
|
||||||
|
" be bytes or int")
|
||||||
|
|
||||||
|
|
||||||
if mode == "P" and palette == ADAPTIVE:
|
if mode == "P" and palette == ADAPTIVE:
|
||||||
im = self.im.quantize(colors)
|
im = self.im.quantize(colors)
|
||||||
new = self._new(im)
|
new = self._new(im)
|
||||||
|
@ -1514,6 +1524,9 @@ class Image:
|
||||||
|
|
||||||
self.load()
|
self.load()
|
||||||
|
|
||||||
|
if self.size == size:
|
||||||
|
return self._new(self.im)
|
||||||
|
|
||||||
if self.mode in ("1", "P"):
|
if self.mode in ("1", "P"):
|
||||||
resample = NEAREST
|
resample = NEAREST
|
||||||
|
|
||||||
|
|
|
@ -47,8 +47,11 @@ class Color(_Enhance):
|
||||||
"""
|
"""
|
||||||
def __init__(self, image):
|
def __init__(self, image):
|
||||||
self.image = image
|
self.image = image
|
||||||
self.degenerate = image.convert("L").convert(image.mode)
|
self.intermediate_mode = 'L'
|
||||||
|
if 'A' in image.getbands():
|
||||||
|
self.intermediate_mode = 'LA'
|
||||||
|
|
||||||
|
self.degenerate = image.convert(self.intermediate_mode).convert(image.mode)
|
||||||
|
|
||||||
class Contrast(_Enhance):
|
class Contrast(_Enhance):
|
||||||
"""Adjust image contrast.
|
"""Adjust image contrast.
|
||||||
|
@ -62,6 +65,9 @@ class Contrast(_Enhance):
|
||||||
mean = int(ImageStat.Stat(image.convert("L")).mean[0] + 0.5)
|
mean = int(ImageStat.Stat(image.convert("L")).mean[0] + 0.5)
|
||||||
self.degenerate = Image.new("L", image.size, mean).convert(image.mode)
|
self.degenerate = Image.new("L", image.size, mean).convert(image.mode)
|
||||||
|
|
||||||
|
if 'A' in image.getbands():
|
||||||
|
self.degenerate.putalpha(image.split()[-1])
|
||||||
|
|
||||||
|
|
||||||
class Brightness(_Enhance):
|
class Brightness(_Enhance):
|
||||||
"""Adjust image brightness.
|
"""Adjust image brightness.
|
||||||
|
@ -74,6 +80,9 @@ class Brightness(_Enhance):
|
||||||
self.image = image
|
self.image = image
|
||||||
self.degenerate = Image.new(image.mode, image.size, 0)
|
self.degenerate = Image.new(image.mode, image.size, 0)
|
||||||
|
|
||||||
|
if 'A' in image.getbands():
|
||||||
|
self.degenerate.putalpha(image.split()[-1])
|
||||||
|
|
||||||
|
|
||||||
class Sharpness(_Enhance):
|
class Sharpness(_Enhance):
|
||||||
"""Adjust image sharpness.
|
"""Adjust image sharpness.
|
||||||
|
@ -85,3 +94,6 @@ class Sharpness(_Enhance):
|
||||||
def __init__(self, image):
|
def __init__(self, image):
|
||||||
self.image = image
|
self.image = image
|
||||||
self.degenerate = image.filter(ImageFilter.SMOOTH)
|
self.degenerate = image.filter(ImageFilter.SMOOTH)
|
||||||
|
|
||||||
|
if 'A' in image.getbands():
|
||||||
|
self.degenerate.putalpha(image.split()[-1])
|
||||||
|
|
|
@ -227,6 +227,8 @@ class ImageFile(Image.Image):
|
||||||
break
|
break
|
||||||
b = b[n:]
|
b = b[n:]
|
||||||
t = t + n
|
t = t + n
|
||||||
|
# Need to cleanup here to prevent leaks in PyPy
|
||||||
|
d.cleanup()
|
||||||
|
|
||||||
self.tile = []
|
self.tile = []
|
||||||
self.readonly = readonly
|
self.readonly = readonly
|
||||||
|
@ -471,6 +473,7 @@ def _save(im, fp, tile, bufsize=0):
|
||||||
break
|
break
|
||||||
if s < 0:
|
if s < 0:
|
||||||
raise IOError("encoder error %d when writing image file" % s)
|
raise IOError("encoder error %d when writing image file" % s)
|
||||||
|
e.cleanup()
|
||||||
else:
|
else:
|
||||||
# slight speedup: compress to real file object
|
# slight speedup: compress to real file object
|
||||||
for e, b, o, a in tile:
|
for e, b, o, a in tile:
|
||||||
|
@ -481,6 +484,7 @@ def _save(im, fp, tile, bufsize=0):
|
||||||
s = e.encode_to_file(fh, bufsize)
|
s = e.encode_to_file(fh, bufsize)
|
||||||
if s < 0:
|
if s < 0:
|
||||||
raise IOError("encoder error %d when writing image file" % s)
|
raise IOError("encoder error %d when writing image file" % s)
|
||||||
|
e.cleanup()
|
||||||
try:
|
try:
|
||||||
fp.flush()
|
fp.flush()
|
||||||
except: pass
|
except: pass
|
||||||
|
|
|
@ -17,6 +17,9 @@
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
|
import sys
|
||||||
|
if sys.platform != "win32":
|
||||||
|
raise ImportError("ImageGrab is Windows only")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# built-in driver (1.1.3 and later)
|
# built-in driver (1.1.3 and later)
|
||||||
|
@ -40,7 +43,7 @@ def grab(bbox=None):
|
||||||
|
|
||||||
|
|
||||||
def grabclipboard():
|
def grabclipboard():
|
||||||
debug = 0 # temporary interface
|
debug = 0 # temporary interface
|
||||||
data = Image.core.grabclipboard(debug)
|
data = Image.core.grabclipboard(debug)
|
||||||
if isinstance(data, bytes):
|
if isinstance(data, bytes):
|
||||||
from PIL import BmpImagePlugin
|
from PIL import BmpImagePlugin
|
||||||
|
|
|
@ -19,4 +19,3 @@ Pillow is the "friendly" PIL fork by `Alex Clark and Contributors <https://githu
|
||||||
|
|
||||||
.. image:: https://coveralls.io/repos/python-pillow/Pillow/badge.png?branch=master
|
.. image:: https://coveralls.io/repos/python-pillow/Pillow/badge.png?branch=master
|
||||||
:target: https://coveralls.io/r/python-pillow/Pillow?branch=master
|
:target: https://coveralls.io/r/python-pillow/Pillow?branch=master
|
||||||
|
|
||||||
|
|
42
Tests/check_j2k_leaks.py
Executable file
42
Tests/check_j2k_leaks.py
Executable file
|
@ -0,0 +1,42 @@
|
||||||
|
from helper import unittest, PillowTestCase
|
||||||
|
import sys
|
||||||
|
from PIL import Image
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
|
# Limits for testing the leak
|
||||||
|
mem_limit = 1024*1048576
|
||||||
|
stack_size = 8*1048576
|
||||||
|
iterations = int((mem_limit/stack_size)*2)
|
||||||
|
codecs = dir(Image.core)
|
||||||
|
test_file = "Tests/images/rgb_trns_ycbc.jp2"
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipIf(sys.platform.startswith('win32'), "requires Unix or MacOS")
|
||||||
|
class TestJpegLeaks(PillowTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
if "jpeg2k_encoder" not in codecs or "jpeg2k_decoder" not in codecs:
|
||||||
|
self.skipTest('JPEG 2000 support not available')
|
||||||
|
|
||||||
|
def test_leak_load(self):
|
||||||
|
from resource import setrlimit, RLIMIT_AS, RLIMIT_STACK
|
||||||
|
setrlimit(RLIMIT_STACK, (stack_size, stack_size))
|
||||||
|
setrlimit(RLIMIT_AS, (mem_limit, mem_limit))
|
||||||
|
for count in range(iterations):
|
||||||
|
with Image.open(test_file) as im:
|
||||||
|
im.load()
|
||||||
|
|
||||||
|
def test_leak_save(self):
|
||||||
|
from resource import setrlimit, RLIMIT_AS, RLIMIT_STACK
|
||||||
|
setrlimit(RLIMIT_STACK, (stack_size, stack_size))
|
||||||
|
setrlimit(RLIMIT_AS, (mem_limit, mem_limit))
|
||||||
|
for count in range(iterations):
|
||||||
|
with Image.open(test_file) as im:
|
||||||
|
im.load()
|
||||||
|
test_output = BytesIO()
|
||||||
|
im.save(test_output, "JPEG2000")
|
||||||
|
test_output.seek(0)
|
||||||
|
output = test_output.read()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
|
@ -155,7 +155,7 @@ class PillowTestCase(unittest.TestCase):
|
||||||
raise IOError()
|
raise IOError()
|
||||||
|
|
||||||
outfile = self.tempfile("temp.png")
|
outfile = self.tempfile("temp.png")
|
||||||
if command_succeeds(['convert', f, outfile]):
|
if command_succeeds([IMCONVERT, f, outfile]):
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
return Image.open(outfile)
|
return Image.open(outfile)
|
||||||
raise IOError()
|
raise IOError()
|
||||||
|
@ -251,6 +251,14 @@ def netpbm_available():
|
||||||
|
|
||||||
|
|
||||||
def imagemagick_available():
|
def imagemagick_available():
|
||||||
return command_succeeds(['convert', '-version'])
|
return IMCONVERT and command_succeeds([IMCONVERT, '-version'])
|
||||||
|
|
||||||
|
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
IMCONVERT = os.environ.get('MAGICK_HOME', '')
|
||||||
|
if IMCONVERT:
|
||||||
|
IMCONVERT = os.path.join(IMCONVERT, 'convert.exe')
|
||||||
|
else:
|
||||||
|
IMCONVERT = 'convert'
|
||||||
|
|
||||||
# End of file
|
# End of file
|
||||||
|
|
|
@ -63,6 +63,17 @@ class TestFileEps(PillowTestCase):
|
||||||
with io.open(self.tempfile('temp_iobase.eps'), 'wb') as fh:
|
with io.open(self.tempfile('temp_iobase.eps'), 'wb') as fh:
|
||||||
image1.save(fh, 'EPS')
|
image1.save(fh, 'EPS')
|
||||||
|
|
||||||
|
def test_bytesio_object(self):
|
||||||
|
with open(file1, 'rb') as f:
|
||||||
|
img_bytes = io.BytesIO(f.read())
|
||||||
|
|
||||||
|
img = Image.open(img_bytes)
|
||||||
|
img.load()
|
||||||
|
|
||||||
|
image1_scale1_compare = Image.open(file1_compare).convert("RGB")
|
||||||
|
image1_scale1_compare.load()
|
||||||
|
self.assert_image_similar(img, image1_scale1_compare, 5)
|
||||||
|
|
||||||
def test_render_scale1(self):
|
def test_render_scale1(self):
|
||||||
# We need png support for these render test
|
# We need png support for these render test
|
||||||
codecs = dir(Image.core)
|
codecs = dir(Image.core)
|
||||||
|
@ -137,6 +148,83 @@ class TestFileEps(PillowTestCase):
|
||||||
# open image with binary preview
|
# open image with binary preview
|
||||||
Image.open(file3)
|
Image.open(file3)
|
||||||
|
|
||||||
|
def _test_readline(self,t, ending):
|
||||||
|
ending = "Failure with line ending: %s" %("".join("%s" %ord(s) for s in ending))
|
||||||
|
self.assertEqual(t.readline().strip('\r\n'), 'something', ending)
|
||||||
|
self.assertEqual(t.readline().strip('\r\n'), 'else', ending)
|
||||||
|
self.assertEqual(t.readline().strip('\r\n'), 'baz', ending)
|
||||||
|
self.assertEqual(t.readline().strip('\r\n'), 'bif', ending)
|
||||||
|
|
||||||
|
def _test_readline_stringio(self, test_string, ending):
|
||||||
|
# check all the freaking line endings possible
|
||||||
|
try:
|
||||||
|
import StringIO
|
||||||
|
except:
|
||||||
|
# don't skip, it skips everything in the parent test
|
||||||
|
return
|
||||||
|
t = StringIO.StringIO(test_string)
|
||||||
|
self._test_readline(t, ending)
|
||||||
|
|
||||||
|
def _test_readline_io(self, test_string, ending):
|
||||||
|
import io
|
||||||
|
if str is bytes:
|
||||||
|
t = io.StringIO(unicode(test_string))
|
||||||
|
else:
|
||||||
|
t = io.StringIO(test_string)
|
||||||
|
self._test_readline(t, ending)
|
||||||
|
|
||||||
|
def _test_readline_file_universal(self, test_string, ending):
|
||||||
|
f = self.tempfile('temp.txt')
|
||||||
|
with open(f,'wb') as w:
|
||||||
|
if str is bytes:
|
||||||
|
w.write(test_string)
|
||||||
|
else:
|
||||||
|
w.write(test_string.encode('UTF-8'))
|
||||||
|
|
||||||
|
with open(f,'rU') as t:
|
||||||
|
self._test_readline(t, ending)
|
||||||
|
|
||||||
|
def _test_readline_file_psfile(self, test_string, ending):
|
||||||
|
f = self.tempfile('temp.txt')
|
||||||
|
with open(f,'wb') as w:
|
||||||
|
if str is bytes:
|
||||||
|
w.write(test_string)
|
||||||
|
else:
|
||||||
|
w.write(test_string.encode('UTF-8'))
|
||||||
|
|
||||||
|
with open(f,'rb') as r:
|
||||||
|
t = EpsImagePlugin.PSFile(r)
|
||||||
|
self._test_readline(t, ending)
|
||||||
|
|
||||||
|
def test_readline(self):
|
||||||
|
# check all the freaking line endings possible from the spec
|
||||||
|
#test_string = u'something\r\nelse\n\rbaz\rbif\n'
|
||||||
|
line_endings = ['\r\n', '\n']
|
||||||
|
not_working_endings = ['\n\r', '\r']
|
||||||
|
strings = ['something', 'else', 'baz', 'bif']
|
||||||
|
|
||||||
|
for ending in line_endings:
|
||||||
|
s = ending.join(strings)
|
||||||
|
# Native python versions will pass these endings.
|
||||||
|
#self._test_readline_stringio(s, ending)
|
||||||
|
#self._test_readline_io(s, ending)
|
||||||
|
#self._test_readline_file_universal(s, ending)
|
||||||
|
|
||||||
|
self._test_readline_file_psfile(s, ending)
|
||||||
|
|
||||||
|
for ending in not_working_endings:
|
||||||
|
# these only work with the PSFile, while they're in spec,
|
||||||
|
# they're not likely to be used
|
||||||
|
s = ending.join(strings)
|
||||||
|
|
||||||
|
# Native python versions may fail on these endings.
|
||||||
|
#self._test_readline_stringio(s, ending)
|
||||||
|
#self._test_readline_io(s, ending)
|
||||||
|
#self._test_readline_file_universal(s, ending)
|
||||||
|
|
||||||
|
self._test_readline_file_psfile(s, ending)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
||||||
|
|
|
@ -347,8 +347,8 @@ class TestFilePng(PillowTestCase):
|
||||||
im2 = Image.open(f)
|
im2 = Image.open(f)
|
||||||
self.assertIn('transparency', im2.info)
|
self.assertIn('transparency', im2.info)
|
||||||
|
|
||||||
self.assert_image_similar(im2.convert('RGBA'), im.convert('RGBA'),
|
self.assert_image_equal(im2.convert('RGBA'),
|
||||||
16)
|
im.convert('RGBA'))
|
||||||
|
|
||||||
def test_save_icc_profile_none(self):
|
def test_save_icc_profile_none(self):
|
||||||
# check saving files with an ICC profile set to None (omit profile)
|
# check saving files with an ICC profile set to None (omit profile)
|
||||||
|
|
|
@ -2,13 +2,13 @@ from helper import unittest, PillowTestCase, fromstring, tostring
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
codecs = dir(Image.core)
|
CODECS = dir(Image.core)
|
||||||
fihopperme = "Tests/images/hopper.jpg"
|
FILENAME = "Tests/images/hopper.jpg"
|
||||||
data = tostring(Image.open(fihopperme).resize((512, 512)), "JPEG")
|
DATA = tostring(Image.open(FILENAME).resize((512, 512)), "JPEG")
|
||||||
|
|
||||||
|
|
||||||
def draft(mode, size):
|
def draft(mode, size):
|
||||||
im = fromstring(data)
|
im = fromstring(DATA)
|
||||||
im.draft(mode, size)
|
im.draft(mode, size)
|
||||||
return im
|
return im
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ def draft(mode, size):
|
||||||
class TestImageDraft(PillowTestCase):
|
class TestImageDraft(PillowTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs:
|
if "jpeg_encoder" not in CODECS or "jpeg_decoder" not in CODECS:
|
||||||
self.skipTest("jpeg support not available")
|
self.skipTest("jpeg support not available")
|
||||||
|
|
||||||
def test_size(self):
|
def test_size(self):
|
||||||
|
|
|
@ -22,6 +22,34 @@ class TestImageEnhance(PillowTestCase):
|
||||||
ImageEnhance.Sharpness(im).enhance(0.5)
|
ImageEnhance.Sharpness(im).enhance(0.5)
|
||||||
|
|
||||||
|
|
||||||
|
def _half_transparent_image(self):
|
||||||
|
# returns an image, half transparent, half solid
|
||||||
|
im = hopper('RGB')
|
||||||
|
|
||||||
|
transparent = Image.new('L', im.size, 0)
|
||||||
|
solid = Image.new('L', (im.size[0]//2, im.size[1]), 255)
|
||||||
|
transparent.paste(solid, (0,0))
|
||||||
|
im.putalpha(transparent)
|
||||||
|
|
||||||
|
return im
|
||||||
|
|
||||||
|
def _check_alpha(self,im, original, op, amount):
|
||||||
|
self.assertEqual(im.getbands(), original.getbands())
|
||||||
|
self.assert_image_equal(im.split()[-1], original.split()[-1],
|
||||||
|
"Diff on %s: %s" % (op, amount))
|
||||||
|
|
||||||
|
def test_alpha(self):
|
||||||
|
# Issue https://github.com/python-pillow/Pillow/issues/899
|
||||||
|
# Is alpha preserved through image enhancement?
|
||||||
|
|
||||||
|
original = self._half_transparent_image()
|
||||||
|
|
||||||
|
for op in ['Color', 'Brightness', 'Contrast', 'Sharpness']:
|
||||||
|
for amount in [0,0.5,1.0]:
|
||||||
|
self._check_alpha(getattr(ImageEnhance,op)(original).enhance(amount),
|
||||||
|
original, op, amount)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
from helper import unittest, PillowTestCase
|
from helper import unittest, PillowTestCase
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from PIL import ImageGrab
|
from PIL import ImageGrab
|
||||||
|
|
||||||
|
@ -19,6 +21,27 @@ except ImportError:
|
||||||
self.skipTest("ImportError")
|
self.skipTest("ImportError")
|
||||||
|
|
||||||
|
|
||||||
|
class TestImageGrabImport(PillowTestCase):
|
||||||
|
|
||||||
|
def test_import(self):
|
||||||
|
# Arrange
|
||||||
|
exception = None
|
||||||
|
|
||||||
|
# Act
|
||||||
|
try:
|
||||||
|
from PIL import ImageGrab
|
||||||
|
ImageGrab.__name__ # dummy to prevent Pyflakes warning
|
||||||
|
except Exception as e:
|
||||||
|
exception = e
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
self.assertIsNone(exception, None)
|
||||||
|
else:
|
||||||
|
self.assertIsInstance(exception, ImportError)
|
||||||
|
self.assertEqual(str(exception), "ImageGrab is Windows only")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
||||||
|
|
|
@ -39,10 +39,10 @@ class TestModeI16(PillowTestCase):
|
||||||
imOut = imIn.transform((w, h), Image.EXTENT, (0, 0, w, h))
|
imOut = imIn.transform((w, h), Image.EXTENT, (0, 0, w, h))
|
||||||
self.verify(imOut) # transform
|
self.verify(imOut) # transform
|
||||||
|
|
||||||
fihopperme = self.tempfile("temp.im")
|
filename = self.tempfile("temp.im")
|
||||||
imIn.save(fihopperme)
|
imIn.save(filename)
|
||||||
|
|
||||||
imOut = Image.open(fihopperme)
|
imOut = Image.open(filename)
|
||||||
|
|
||||||
self.verify(imIn)
|
self.verify(imIn)
|
||||||
self.verify(imOut)
|
self.verify(imOut)
|
||||||
|
|
|
@ -6,13 +6,14 @@ from PIL import Image
|
||||||
class TestPickle(PillowTestCase):
|
class TestPickle(PillowTestCase):
|
||||||
|
|
||||||
def helper_pickle_file(self, pickle, protocol=0):
|
def helper_pickle_file(self, pickle, protocol=0):
|
||||||
|
# Arrange
|
||||||
im = Image.open('Tests/images/hopper.jpg')
|
im = Image.open('Tests/images/hopper.jpg')
|
||||||
fihopperme = self.tempfile('temp.pkl')
|
filename = self.tempfile('temp.pkl')
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
with open(fihopperme, 'wb') as f:
|
with open(filename, 'wb') as f:
|
||||||
pickle.dump(im, f, protocol)
|
pickle.dump(im, f, protocol)
|
||||||
with open(fihopperme, 'rb') as f:
|
with open(filename, 'rb') as f:
|
||||||
loaded_im = pickle.load(f)
|
loaded_im = pickle.load(f)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
|
|
2
decode.c
2
decode.c
|
@ -103,6 +103,8 @@ PyImaging_DecoderNew(int contextsize)
|
||||||
static void
|
static void
|
||||||
_dealloc(ImagingDecoderObject* decoder)
|
_dealloc(ImagingDecoderObject* decoder)
|
||||||
{
|
{
|
||||||
|
if (decoder->cleanup)
|
||||||
|
decoder->cleanup(&decoder->state);
|
||||||
free(decoder->state.buffer);
|
free(decoder->state.buffer);
|
||||||
free(decoder->state.context);
|
free(decoder->state.context);
|
||||||
Py_XDECREF(decoder->lock);
|
Py_XDECREF(decoder->lock);
|
||||||
|
|
|
@ -670,6 +670,7 @@ files, using either JPEG or HEX encoding depending on the image mode (and
|
||||||
whether JPEG support is available or not).
|
whether JPEG support is available or not).
|
||||||
|
|
||||||
PIXAR (read only)
|
PIXAR (read only)
|
||||||
|
^^^^
|
||||||
|
|
||||||
PIL provides limited support for PIXAR raster files. The library can identify
|
PIL provides limited support for PIXAR raster files. The library can identify
|
||||||
and read “dumped” RGB files.
|
and read “dumped” RGB files.
|
||||||
|
|
13
encode.c
13
encode.c
|
@ -99,6 +99,18 @@ _dealloc(ImagingEncoderObject* encoder)
|
||||||
PyObject_Del(encoder);
|
PyObject_Del(encoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
_encode_cleanup(ImagingEncoderObject* encoder, PyObject* args)
|
||||||
|
{
|
||||||
|
int status = 0;
|
||||||
|
|
||||||
|
if (encoder->cleanup){
|
||||||
|
status = encoder->cleanup(&encoder->state);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Py_BuildValue("i", status);
|
||||||
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_encode(ImagingEncoderObject* encoder, PyObject* args)
|
_encode(ImagingEncoderObject* encoder, PyObject* args)
|
||||||
{
|
{
|
||||||
|
@ -239,6 +251,7 @@ _setimage(ImagingEncoderObject* encoder, PyObject* args)
|
||||||
|
|
||||||
static struct PyMethodDef methods[] = {
|
static struct PyMethodDef methods[] = {
|
||||||
{"encode", (PyCFunction)_encode, 1},
|
{"encode", (PyCFunction)_encode, 1},
|
||||||
|
{"cleanup", (PyCFunction)_encode_cleanup, 1},
|
||||||
{"encode_to_file", (PyCFunction)_encode_to_file, 1},
|
{"encode_to_file", (PyCFunction)_encode_to_file, 1},
|
||||||
{"setimage", (PyCFunction)_setimage, 1},
|
{"setimage", (PyCFunction)_setimage, 1},
|
||||||
{NULL, NULL} /* sentinel */
|
{NULL, NULL} /* sentinel */
|
||||||
|
|
|
@ -800,6 +800,11 @@ ImagingJpeg2KDecodeCleanup(ImagingCodecState state) {
|
||||||
if (context->decoder)
|
if (context->decoder)
|
||||||
ImagingIncrementalCodecDestroy(context->decoder);
|
ImagingIncrementalCodecDestroy(context->decoder);
|
||||||
|
|
||||||
|
context->error_msg = NULL;
|
||||||
|
|
||||||
|
/* Prevent multiple calls to ImagingIncrementalCodecDestroy */
|
||||||
|
context->decoder = NULL;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
7
libImaging/Jpeg2KEncode.c
Normal file → Executable file
7
libImaging/Jpeg2KEncode.c
Normal file → Executable file
|
@ -576,15 +576,20 @@ int
|
||||||
ImagingJpeg2KEncodeCleanup(ImagingCodecState state) {
|
ImagingJpeg2KEncodeCleanup(ImagingCodecState state) {
|
||||||
JPEG2KENCODESTATE *context = (JPEG2KENCODESTATE *)state->context;
|
JPEG2KENCODESTATE *context = (JPEG2KENCODESTATE *)state->context;
|
||||||
|
|
||||||
if (context->quality_layers)
|
if (context->quality_layers && context->encoder)
|
||||||
Py_DECREF(context->quality_layers);
|
Py_DECREF(context->quality_layers);
|
||||||
|
|
||||||
if (context->error_msg)
|
if (context->error_msg)
|
||||||
free ((void *)context->error_msg);
|
free ((void *)context->error_msg);
|
||||||
|
|
||||||
|
context->error_msg = NULL;
|
||||||
|
|
||||||
if (context->encoder)
|
if (context->encoder)
|
||||||
ImagingIncrementalCodecDestroy(context->encoder);
|
ImagingIncrementalCodecDestroy(context->encoder);
|
||||||
|
|
||||||
|
/* Prevent multiple calls to ImagingIncrementalCodecDestroy */
|
||||||
|
context->encoder = NULL;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -221,9 +221,10 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, int
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clientstate->ifd){
|
if (clientstate->ifd){
|
||||||
unsigned int ifdoffset = clientstate->ifd;
|
int rv;
|
||||||
|
unsigned int ifdoffset = clientstate->ifd;
|
||||||
TRACE(("reading tiff ifd %d\n", ifdoffset));
|
TRACE(("reading tiff ifd %d\n", ifdoffset));
|
||||||
int rv = TIFFSetSubDirectory(tiff, ifdoffset);
|
rv = TIFFSetSubDirectory(tiff, ifdoffset);
|
||||||
if (!rv){
|
if (!rv){
|
||||||
TRACE(("error in TIFFSetSubDirectory"));
|
TRACE(("error in TIFFSetSubDirectory"));
|
||||||
return -1;
|
return -1;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user