mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-08-09 06:44:45 +03:00
Merge
This commit is contained in:
commit
d9cd57a5f7
|
@ -20,7 +20,8 @@ install:
|
|||
- "travis_retry sudo apt-get -qq install libfreetype6-dev liblcms2-dev python-qt4 ghostscript libffi-dev libjpeg-turbo-progs cmake imagemagick"
|
||||
- "travis_retry pip install cffi"
|
||||
- "travis_retry pip install coverage nose"
|
||||
- "travis_retry pip install pyroma"
|
||||
# Pyroma tests sometimes hang on PyPy; skip for PyPy
|
||||
- if [ $TRAVIS_PYTHON_VERSION != "pypy" ]; then travis_retry pip install pyroma; fi
|
||||
|
||||
- if [ "$TRAVIS_PYTHON_VERSION" == "2.6" ]; then travis_retry pip install unittest2; fi
|
||||
|
||||
|
|
18
CHANGES.rst
18
CHANGES.rst
|
@ -4,6 +4,18 @@ Changelog (Pillow)
|
|||
2.9.0 (Unreleased)
|
||||
------------------
|
||||
|
||||
- Provide n_frames attribute to multi-frame formats #1261
|
||||
[anntzer, radarhere]
|
||||
|
||||
- Add duration and loop set to GifImagePlugin #1172
|
||||
[radarhere]
|
||||
|
||||
- Ico files are little endian #1232
|
||||
[wiredfool]
|
||||
|
||||
- Upgrade olefile from 0.30 to 0.42b #1226
|
||||
[radarhere, decalage2]
|
||||
|
||||
- Setting transparency value to 0 when the tRNS contains only null byte(s) #1239
|
||||
[juztin]
|
||||
|
||||
|
@ -31,6 +43,12 @@ Changelog (Pillow)
|
|||
- Tiff: allow writing floating point tag values #1113
|
||||
[bpedersen2]
|
||||
|
||||
2.8.2 (2015-06-06)
|
||||
------------------
|
||||
|
||||
- Bug fix: Fixed Tiff handling of bad EXIF data
|
||||
[radarhere]
|
||||
|
||||
2.8.1 (2015-04-02)
|
||||
------------------
|
||||
|
||||
|
|
105
Makefile
105
Makefile
|
@ -1,28 +1,5 @@
|
|||
.PHONY: pre clean install test inplace coverage test-dep help docs livedocs
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " clean remove build products"
|
||||
@echo " install make and install"
|
||||
@echo " test run tests on installed pillow"
|
||||
@echo " inplace make inplace extension"
|
||||
@echo " coverage run coverage test (in progress)"
|
||||
@echo " docs make html docs"
|
||||
@echo " docserver run an http server on the docs directory"
|
||||
@echo " test-dep install coveraget and test dependencies"
|
||||
|
||||
pre:
|
||||
virtualenv .
|
||||
bin/pip install -r requirements.txt
|
||||
bin/python setup.py develop
|
||||
bin/python selftest.py
|
||||
bin/nosetests Tests/test_*.py
|
||||
bin/python setup.py install
|
||||
bin/python test-installed.py
|
||||
check-manifest
|
||||
pyroma .
|
||||
viewdoc
|
||||
# https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html
|
||||
.PHONY: clean coverage doc docserve help inplace install install-req release-test sdist test upload upload-test
|
||||
|
||||
clean:
|
||||
python setup.py clean
|
||||
|
@ -30,46 +7,70 @@ clean:
|
|||
rm -r build || true
|
||||
find . -name __pycache__ | xargs rm -r || true
|
||||
|
||||
install:
|
||||
python setup.py install
|
||||
python selftest.py --installed
|
||||
|
||||
test:
|
||||
python test-installed.py
|
||||
|
||||
inplace: clean
|
||||
python setup.py build_ext --inplace
|
||||
|
||||
coverage:
|
||||
# requires nose-cov
|
||||
coverage erase
|
||||
coverage run --parallel-mode --include=PIL/* selftest.py
|
||||
nosetests --with-cov --cov='PIL/' --cov-report=html Tests/test_*.py
|
||||
# doesn't combine properly before report,
|
||||
# writing report instead of displaying invalid report
|
||||
# Doesn't combine properly before report, writing report instead of displaying invalid report.
|
||||
rm -r htmlcov || true
|
||||
coverage combine
|
||||
coverage report
|
||||
|
||||
test-dep:
|
||||
pip install coveralls nose nose-cov pep8 pyflakes
|
||||
|
||||
docs:
|
||||
doc:
|
||||
$(MAKE) -C docs html
|
||||
|
||||
docserver:
|
||||
docserve:
|
||||
cd docs/_build/html && python -mSimpleHTTPServer 2> /dev/null&
|
||||
|
||||
# Test sdist upload via test.pythonpackages.com, no creds required
|
||||
# .pypirc:
|
||||
help:
|
||||
@echo "Welcome to Pillow development. Please use \`make <target>' where <target> is one of"
|
||||
@echo " clean remove build products"
|
||||
@echo " coverage run coverage test (in progress)"
|
||||
@echo " doc make html docs"
|
||||
@echo " docserve run an http server on the docs directory"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " inplace make inplace extension"
|
||||
@echo " install make and install"
|
||||
@echo " install-req install documentation and test dependencies"
|
||||
@echo " release-test run code and package tests before release"
|
||||
@echo " test run tests on installed pillow"
|
||||
@echo " upload build and upload sdists to PyPI"
|
||||
@echo " upload-test build and upload sdists to test.pythonpackages.com"
|
||||
|
||||
inplace: clean
|
||||
python setup.py build_ext --inplace
|
||||
|
||||
install:
|
||||
python setup.py install
|
||||
python selftest.py --installed
|
||||
|
||||
install-req:
|
||||
pip install -r requirements.txt
|
||||
|
||||
release-test:
|
||||
$(MAKE) install-req
|
||||
python setup.py develop
|
||||
python selftest.py
|
||||
nosetests Tests/test_*.py
|
||||
python setup.py install
|
||||
python test-installed.py
|
||||
check-manifest
|
||||
pyroma .
|
||||
viewdoc
|
||||
|
||||
sdist:
|
||||
python setup.py sdist --format=gztar,zip
|
||||
|
||||
test:
|
||||
python test-installed.py
|
||||
|
||||
# https://docs.python.org/2/distutils/packageindex.html#the-pypirc-file
|
||||
upload-test:
|
||||
# [test]
|
||||
# username:
|
||||
# password:
|
||||
# repository = http://test.pythonpackages.com
|
||||
sdisttest:
|
||||
python setup.py sdist --format=zip upload -r test
|
||||
sdistup:
|
||||
python setup.py sdist --format=zip upload
|
||||
python setup.py sdist upload
|
||||
sdist:
|
||||
python setup.py sdist --format=zip
|
||||
python setup.py sdist --format=gztar,zip upload -r test
|
||||
|
||||
upload:
|
||||
python setup.py sdist --format=gztar,zip upload
|
||||
|
|
|
@ -62,6 +62,10 @@ class DcxImageFile(PcxImageFile):
|
|||
self.__fp = self.fp
|
||||
self.seek(0)
|
||||
|
||||
@property
|
||||
def n_frames(self):
|
||||
return len(self._offset)
|
||||
|
||||
def seek(self, frame):
|
||||
if frame >= len(self._offset):
|
||||
raise EOFError("attempt to seek outside DCX directory")
|
||||
|
|
|
@ -86,9 +86,10 @@ class FliImageFile(ImageFile.ImageFile):
|
|||
self.palette = ImagePalette.raw("RGB", b"".join(palette))
|
||||
|
||||
# set things up to decode first frame
|
||||
self.frame = -1
|
||||
self.__frame = -1
|
||||
self.__fp = self.fp
|
||||
|
||||
self.__rewind = self.fp.tell()
|
||||
self._n_frames = None
|
||||
self.seek(0)
|
||||
|
||||
def _palette(self, palette, shift):
|
||||
|
@ -109,11 +110,35 @@ class FliImageFile(ImageFile.ImageFile):
|
|||
palette[i] = (r, g, b)
|
||||
i += 1
|
||||
|
||||
def seek(self, frame):
|
||||
@property
|
||||
def n_frames(self):
|
||||
if self._n_frames is None:
|
||||
current = self.tell()
|
||||
try:
|
||||
while True:
|
||||
self.seek(self.tell() + 1)
|
||||
except EOFError:
|
||||
self._n_frames = self.tell() + 1
|
||||
self.seek(current)
|
||||
return self._n_frames
|
||||
|
||||
if frame != self.frame + 1:
|
||||
def seek(self, frame):
|
||||
if frame == self.__frame:
|
||||
return
|
||||
if frame < self.__frame:
|
||||
self._seek(0)
|
||||
for f in range(self.__frame + 1, frame + 1):
|
||||
self._seek(f)
|
||||
|
||||
def _seek(self, frame):
|
||||
if frame == 0:
|
||||
self.__frame = -1
|
||||
self.__fp.seek(self.__rewind)
|
||||
self.__offset = 128
|
||||
|
||||
if frame != self.__frame + 1:
|
||||
raise ValueError("cannot seek to frame %d" % frame)
|
||||
self.frame = frame
|
||||
self.__frame = frame
|
||||
|
||||
# move to next frame
|
||||
self.fp = self.__fp
|
||||
|
@ -128,11 +153,10 @@ class FliImageFile(ImageFile.ImageFile):
|
|||
self.decodermaxblock = framesize
|
||||
self.tile = [("fli", (0, 0)+self.size, self.__offset, None)]
|
||||
|
||||
self.__offset = self.__offset + framesize
|
||||
self.__offset += framesize
|
||||
|
||||
def tell(self):
|
||||
|
||||
return self.frame
|
||||
return self.__frame
|
||||
|
||||
#
|
||||
# registry
|
||||
|
|
|
@ -87,9 +87,30 @@ class GifImageFile(ImageFile.ImageFile):
|
|||
|
||||
self.__fp = self.fp # FIXME: hack
|
||||
self.__rewind = self.fp.tell()
|
||||
self.seek(0) # get ready to read first frame
|
||||
self._n_frames = None
|
||||
self._seek(0) # get ready to read first frame
|
||||
|
||||
@property
|
||||
def n_frames(self):
|
||||
if self._n_frames is None:
|
||||
current = self.tell()
|
||||
try:
|
||||
while True:
|
||||
self.seek(self.tell() + 1)
|
||||
except EOFError:
|
||||
self._n_frames = self.tell() + 1
|
||||
self.seek(current)
|
||||
return self._n_frames
|
||||
|
||||
def seek(self, frame):
|
||||
if frame == self.__frame:
|
||||
return
|
||||
if frame < self.__frame:
|
||||
self._seek(0)
|
||||
for f in range(self.__frame + 1, frame + 1):
|
||||
self._seek(f)
|
||||
|
||||
def _seek(self, frame):
|
||||
|
||||
if frame == 0:
|
||||
# rewind
|
||||
|
@ -292,57 +313,10 @@ def _save(im, fp, filename):
|
|||
for s in header:
|
||||
fp.write(s)
|
||||
|
||||
flags = 0
|
||||
|
||||
try:
|
||||
interlace = im.encoderinfo["interlace"]
|
||||
except KeyError:
|
||||
interlace = 1
|
||||
|
||||
# workaround for @PIL153
|
||||
if min(im.size) < 16:
|
||||
interlace = 0
|
||||
|
||||
if interlace:
|
||||
flags = flags | 64
|
||||
|
||||
try:
|
||||
transparency = im.encoderinfo["transparency"]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
transparency = int(transparency)
|
||||
# optimize the block away if transparent color is not used
|
||||
transparent_color_exists = True
|
||||
# adjust the transparency index after optimize
|
||||
if used_palette_colors is not None and len(used_palette_colors) < 256:
|
||||
for i in range(len(used_palette_colors)):
|
||||
if used_palette_colors[i] == transparency:
|
||||
transparency = i
|
||||
transparent_color_exists = True
|
||||
break
|
||||
else:
|
||||
transparent_color_exists = False
|
||||
|
||||
# transparency extension block
|
||||
if transparent_color_exists:
|
||||
fp.write(b"!" +
|
||||
o8(249) + # extension intro
|
||||
o8(4) + # length
|
||||
o8(1) + # transparency info present
|
||||
o16(0) + # duration
|
||||
o8(transparency) + # transparency index
|
||||
o8(0))
|
||||
|
||||
# local image header
|
||||
fp.write(b"," +
|
||||
o16(0) + o16(0) + # bounding box
|
||||
o16(im.size[0]) + # size
|
||||
o16(im.size[1]) +
|
||||
o8(flags) + # flags
|
||||
o8(8)) # bits
|
||||
get_local_header(fp, im)
|
||||
|
||||
im_out.encoderconfig = (8, interlace)
|
||||
im_out.encoderconfig = (8, get_interlace(im))
|
||||
ImageFile._save(im_out, fp, [("gif", (0, 0)+im.size, 0,
|
||||
RAWMODE[im_out.mode])])
|
||||
|
||||
|
@ -356,6 +330,85 @@ def _save(im, fp, filename):
|
|||
pass
|
||||
|
||||
|
||||
def get_interlace(im):
|
||||
try:
|
||||
interlace = im.encoderinfo["interlace"]
|
||||
except KeyError:
|
||||
interlace = 1
|
||||
|
||||
# workaround for @PIL153
|
||||
if min(im.size) < 16:
|
||||
interlace = 0
|
||||
|
||||
return interlace
|
||||
|
||||
|
||||
def get_local_header(fp, im, offset=(0, 0)):
|
||||
transparent_color_exists = False
|
||||
try:
|
||||
transparency = im.encoderinfo["transparency"]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
transparency = int(transparency)
|
||||
# optimize the block away if transparent color is not used
|
||||
transparent_color_exists = True
|
||||
|
||||
if _get_optimize(im, im.encoderinfo):
|
||||
used_palette_colors = _get_used_palette_colors(im)
|
||||
|
||||
# adjust the transparency index after optimize
|
||||
if len(used_palette_colors) < 256:
|
||||
for i in range(len(used_palette_colors)):
|
||||
if used_palette_colors[i] == transparency:
|
||||
transparency = i
|
||||
transparent_color_exists = True
|
||||
break
|
||||
else:
|
||||
transparent_color_exists = False
|
||||
|
||||
if "duration" in im.encoderinfo:
|
||||
duration = int(im.encoderinfo["duration"] / 10)
|
||||
else:
|
||||
duration = 0
|
||||
if transparent_color_exists or duration != 0:
|
||||
transparency_flag = 1 if transparent_color_exists else 0
|
||||
if not transparent_color_exists:
|
||||
transparency = 0
|
||||
|
||||
fp.write(b"!" +
|
||||
o8(249) + # extension intro
|
||||
o8(4) + # length
|
||||
o8(transparency_flag) + # transparency info present
|
||||
o16(duration) + # duration
|
||||
o8(transparency) + # transparency index
|
||||
o8(0))
|
||||
|
||||
if "loop" in im.encoderinfo:
|
||||
number_of_loops = im.encoderinfo["loop"]
|
||||
fp.write(b"!" +
|
||||
o8(255) + # extension intro
|
||||
o8(11) +
|
||||
b"NETSCAPE2.0" +
|
||||
o8(3) +
|
||||
o8(1) +
|
||||
o16(number_of_loops) + # number of loops
|
||||
o8(0))
|
||||
|
||||
flags = 0
|
||||
|
||||
if get_interlace(im):
|
||||
flags = flags | 64
|
||||
|
||||
fp.write(b"," +
|
||||
o16(offset[0]) + # offset
|
||||
o16(offset[1]) +
|
||||
o16(im.size[0]) + # size
|
||||
o16(im.size[1]) +
|
||||
o8(flags) + # flags
|
||||
o8(8)) # bits
|
||||
|
||||
|
||||
def _save_netpbm(im, fp, filename):
|
||||
|
||||
#
|
||||
|
@ -405,11 +458,26 @@ def _save_netpbm(im, fp, filename):
|
|||
# --------------------------------------------------------------------
|
||||
# GIF utilities
|
||||
|
||||
def _get_optimize(im, info):
|
||||
return im.mode in ("P", "L") and info and info.get("optimize", 0)
|
||||
|
||||
|
||||
def _get_used_palette_colors(im):
|
||||
used_palette_colors = []
|
||||
|
||||
# check which colors are used
|
||||
i = 0
|
||||
for count in im.histogram():
|
||||
if count:
|
||||
used_palette_colors.append(i)
|
||||
i += 1
|
||||
|
||||
return used_palette_colors
|
||||
|
||||
|
||||
def getheader(im, palette=None, info=None):
|
||||
"""Return a list of strings representing a GIF header"""
|
||||
|
||||
optimize = info and info.get("optimize", 0)
|
||||
|
||||
# Header Block
|
||||
# http://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp
|
||||
header = [
|
||||
|
@ -431,15 +499,8 @@ def getheader(im, palette=None, info=None):
|
|||
|
||||
used_palette_colors = palette_bytes = None
|
||||
|
||||
if im.mode in ("P", "L") and optimize:
|
||||
used_palette_colors = []
|
||||
|
||||
# check which colors are used
|
||||
i = 0
|
||||
for count in im.histogram():
|
||||
if count:
|
||||
used_palette_colors.append(i)
|
||||
i += 1
|
||||
if _get_optimize(im, info):
|
||||
used_palette_colors = _get_used_palette_colors(im)
|
||||
|
||||
# create the new palette if not every color is used
|
||||
if len(used_palette_colors) < 256:
|
||||
|
@ -510,13 +571,7 @@ def getdata(im, offset=(0, 0), **params):
|
|||
im.encoderinfo = params
|
||||
|
||||
# local image header
|
||||
fp.write(b"," +
|
||||
o16(offset[0]) + # offset
|
||||
o16(offset[1]) +
|
||||
o16(im.size[0]) + # size
|
||||
o16(im.size[1]) +
|
||||
o8(0) + # flags
|
||||
o8(8)) # bits
|
||||
get_local_header(fp, im, offset)
|
||||
|
||||
ImageFile._save(im, fp, [("gif", (0, 0)+im.size, 0, RAWMODE[im.mode])])
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ def _save(im, fp, filename):
|
|||
width, height = im.size
|
||||
filter(lambda x: False if (x[0] > width or x[1] > height or
|
||||
x[0] > 255 or x[1] > 255) else True, sizes)
|
||||
fp.write(struct.pack("H", len(sizes))) # idCount(2)
|
||||
fp.write(struct.pack("<H", len(sizes))) # idCount(2)
|
||||
offset = fp.tell() + len(sizes)*16
|
||||
for size in sizes:
|
||||
width, height = size
|
||||
|
@ -57,7 +57,7 @@ def _save(im, fp, filename):
|
|||
fp.write(b"\0") # bColorCount(1)
|
||||
fp.write(b"\0") # bReserved(1)
|
||||
fp.write(b"\0\0") # wPlanes(2)
|
||||
fp.write(struct.pack("H", 32)) # wBitCount(2)
|
||||
fp.write(struct.pack("<H", 32)) # wBitCount(2)
|
||||
|
||||
image_io = BytesIO()
|
||||
tmp = im.copy()
|
||||
|
@ -66,8 +66,8 @@ def _save(im, fp, filename):
|
|||
image_io.seek(0)
|
||||
image_bytes = image_io.read()
|
||||
bytes_len = len(image_bytes)
|
||||
fp.write(struct.pack("I", bytes_len)) # dwBytesInRes(4)
|
||||
fp.write(struct.pack("I", offset)) # dwImageOffset(4)
|
||||
fp.write(struct.pack("<I", bytes_len)) # dwBytesInRes(4)
|
||||
fp.write(struct.pack("<I", offset)) # dwImageOffset(4)
|
||||
current = fp.tell()
|
||||
fp.seek(offset)
|
||||
fp.write(image_bytes)
|
||||
|
|
|
@ -260,6 +260,10 @@ class ImImageFile(ImageFile.ImageFile):
|
|||
self.tile = [("raw", (0, 0)+self.size, offs,
|
||||
(self.rawmode, 0, -1))]
|
||||
|
||||
@property
|
||||
def n_frames(self):
|
||||
return self.info[FRAMES]
|
||||
|
||||
def seek(self, frame):
|
||||
|
||||
if frame < 0 or frame >= self.info[FRAMES]:
|
||||
|
|
|
@ -1810,7 +1810,7 @@ class Image(object):
|
|||
self.readonly = 0
|
||||
self.pyaccess = None
|
||||
|
||||
# FIXME: the different tranform methods need further explanation
|
||||
# FIXME: the different transform methods need further explanation
|
||||
# instead of bloating the method docs, add a separate chapter.
|
||||
def transform(self, size, method, data=None, resample=NEAREST, fill=1):
|
||||
"""
|
||||
|
|
|
@ -64,7 +64,7 @@ pyCMS
|
|||
|
||||
0.0.2 alpha Jan 6, 2002
|
||||
|
||||
Added try/except statements arount type() checks of
|
||||
Added try/except statements around type() checks of
|
||||
potential CObjects... Python won't let you use type()
|
||||
on them, and raises a TypeError (stupid, if you ask
|
||||
me!)
|
||||
|
@ -123,8 +123,8 @@ FLAGS = {
|
|||
"NOTCACHE": 64, # Inhibit 1-pixel cache
|
||||
"NOTPRECALC": 256,
|
||||
"NULLTRANSFORM": 512, # Don't transform anyway
|
||||
"HIGHRESPRECALC": 1024, # Use more memory to give better accurancy
|
||||
"LOWRESPRECALC": 2048, # Use less memory to minimize resouces
|
||||
"HIGHRESPRECALC": 1024, # Use more memory to give better accuracy
|
||||
"LOWRESPRECALC": 2048, # Use less memory to minimize resources
|
||||
"WHITEBLACKCOMPENSATION": 8192,
|
||||
"BLACKPOINTCOMPENSATION": 8192,
|
||||
"GAMUTCHECK": 4096, # Out of Gamut alarm
|
||||
|
@ -573,7 +573,7 @@ def applyTransform(im, transform, inPlace=0):
|
|||
This function applies a pre-calculated transform (from
|
||||
ImageCms.buildTransform() or ImageCms.buildTransformFromOpenProfiles())
|
||||
to an image. The transform can be used for multiple images, saving
|
||||
considerable calcuation time if doing the same conversion multiple times.
|
||||
considerable calculation time if doing the same conversion multiple times.
|
||||
|
||||
If you want to modify im in-place instead of receiving a new image as
|
||||
the return value, set inPlace to TRUE. This can only be done if
|
||||
|
@ -858,7 +858,7 @@ def getDefaultIntent(profile):
|
|||
If an error occurs while trying to obtain the default intent, a
|
||||
PyCMSError is raised.
|
||||
|
||||
Use this function to determine the default (and usually best optomized)
|
||||
Use this function to determine the default (and usually best optimized)
|
||||
rendering intent for this profile. Most profiles support multiple
|
||||
rendering intents, but are intended mostly for one type of conversion.
|
||||
If you wish to use a different intent than returned, use
|
||||
|
@ -914,7 +914,7 @@ def isIntentSupported(profile, intent, direction):
|
|||
|
||||
see the pyCMS documentation for details on rendering intents and what
|
||||
they do.
|
||||
:param direction: Integer specifing if the profile is to be used for input,
|
||||
:param direction: Integer specifying if the profile is to be used for input,
|
||||
output, or proof
|
||||
|
||||
INPUT = 0 (or use ImageCms.DIRECTION_INPUT)
|
||||
|
|
|
@ -73,7 +73,7 @@ class Contrast(_Enhance):
|
|||
class Brightness(_Enhance):
|
||||
"""Adjust image brightness.
|
||||
|
||||
This class can be used to control the brighntess of an image. An
|
||||
This class can be used to control the brightness of an image. An
|
||||
enhancement factor of 0.0 gives a black image. A factor of 1.0 gives the
|
||||
original image.
|
||||
"""
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#
|
||||
# JPEG (JFIF) file handling
|
||||
#
|
||||
# See "Digital Compression and Coding of Continous-Tone Still Images,
|
||||
# See "Digital Compression and Coding of Continuous-Tone Still Images,
|
||||
# Part 1, Requirements and Guidelines" (CCITT T.81 / ISO 10918-1)
|
||||
#
|
||||
# History:
|
||||
|
|
|
@ -71,6 +71,10 @@ class MicImageFile(TiffImagePlugin.TiffImageFile):
|
|||
|
||||
self.seek(0)
|
||||
|
||||
@property
|
||||
def n_frames(self):
|
||||
return len(self.images)
|
||||
|
||||
def seek(self, frame):
|
||||
|
||||
try:
|
||||
|
|
|
@ -62,6 +62,10 @@ class MpoImageFile(JpegImagePlugin.JpegImageFile):
|
|||
def load_seek(self, pos):
|
||||
self.__fp.seek(pos)
|
||||
|
||||
@property
|
||||
def n_frames(self):
|
||||
return self.__framecount
|
||||
|
||||
def seek(self, frame):
|
||||
if frame < 0 or frame >= self.__framecount:
|
||||
raise EOFError("no more images in MPO file")
|
||||
|
|
684
PIL/OleFileIO.py
684
PIL/OleFileIO.py
File diff suppressed because it is too large
Load Diff
|
@ -132,6 +132,10 @@ class PsdImageFile(ImageFile.ImageFile):
|
|||
self._fp = self.fp
|
||||
self.frame = 0
|
||||
|
||||
@property
|
||||
def n_frames(self):
|
||||
return len(self.layers)
|
||||
|
||||
def seek(self, layer):
|
||||
# seek to given layer (1..max)
|
||||
if layer == self.frame:
|
||||
|
|
|
@ -127,12 +127,12 @@ class SpiderImageFile(ImageFile.ImageFile):
|
|||
if self.istack == 0 and self.imgnumber == 0:
|
||||
# stk=0, img=0: a regular 2D image
|
||||
offset = hdrlen
|
||||
self.nimages = 1
|
||||
self._nimages = 1
|
||||
elif self.istack > 0 and self.imgnumber == 0:
|
||||
# stk>0, img=0: Opening the stack for the first time
|
||||
self.imgbytes = int(h[12]) * int(h[2]) * 4
|
||||
self.hdrlen = hdrlen
|
||||
self.nimages = int(h[26])
|
||||
self._nimages = int(h[26])
|
||||
# Point to the first image in the stack
|
||||
offset = hdrlen * 2
|
||||
self.imgnumber = 1
|
||||
|
@ -154,6 +154,10 @@ class SpiderImageFile(ImageFile.ImageFile):
|
|||
(self.rawmode, 0, 1))]
|
||||
self.__fp = self.fp # FIXME: hack
|
||||
|
||||
@property
|
||||
def n_frames(self):
|
||||
return self._nimages
|
||||
|
||||
# 1st image index is zero (although SPIDER imgnumber starts at 1)
|
||||
def tell(self):
|
||||
if self.imgnumber < 1:
|
||||
|
@ -164,7 +168,7 @@ class SpiderImageFile(ImageFile.ImageFile):
|
|||
def seek(self, frame):
|
||||
if self.istack == 0:
|
||||
return
|
||||
if frame >= self.nimages:
|
||||
if frame >= self._nimages:
|
||||
raise EOFError("attempt to seek past end of file")
|
||||
self.stkoffset = self.hdrlen + frame * (self.hdrlen + self.imgbytes)
|
||||
self.fp = self.__fp
|
||||
|
|
|
@ -294,7 +294,7 @@ class ImageFileDirectory(collections.MutableMapping):
|
|||
|
||||
def named(self):
|
||||
"""
|
||||
Returns the complete tag dictionary, with named tags where posible.
|
||||
Returns the complete tag dictionary, with named tags where possible.
|
||||
"""
|
||||
from PIL import TiffTags
|
||||
result = {}
|
||||
|
@ -426,6 +426,11 @@ class ImageFileDirectory(collections.MutableMapping):
|
|||
for i in range(i16(fp.read(2))):
|
||||
|
||||
ifd = fp.read(12)
|
||||
if len(ifd) != 12:
|
||||
warnings.warn("Possibly corrupt EXIF data. "
|
||||
"Expecting to read 12 bytes but only got %d."
|
||||
% (len(ifd)))
|
||||
continue
|
||||
|
||||
tag, typ = i16(ifd), i16(ifd, 2)
|
||||
|
||||
|
@ -476,7 +481,14 @@ class ImageFileDirectory(collections.MutableMapping):
|
|||
else:
|
||||
print("- value:", self[tag])
|
||||
|
||||
self.next = i32(fp.read(4))
|
||||
ifd = fp.read(4)
|
||||
if len(ifd) != 4:
|
||||
warnings.warn("Possibly corrupt EXIF data. "
|
||||
"Expecting to read 4 bytes but only got %d."
|
||||
% (len(ifd)))
|
||||
return
|
||||
|
||||
self.next = i32(ifd)
|
||||
|
||||
# save primitives
|
||||
|
||||
|
@ -636,6 +648,8 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
self.__first = self.__next = self.ifd.i32(ifh, 4)
|
||||
self.__frame = -1
|
||||
self.__fp = self.fp
|
||||
self._frame_pos = []
|
||||
self._n_frames = None
|
||||
|
||||
if Image.DEBUG:
|
||||
print("*** TiffImageFile._open ***")
|
||||
|
@ -645,28 +659,30 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
# and load the first frame
|
||||
self._seek(0)
|
||||
|
||||
@property
|
||||
def n_frames(self):
|
||||
if self._n_frames is None:
|
||||
current = self.tell()
|
||||
try:
|
||||
while True:
|
||||
self._seek(self.tell() + 1)
|
||||
except EOFError:
|
||||
self._n_frames = self.tell() + 1
|
||||
self.seek(current)
|
||||
return self._n_frames
|
||||
|
||||
def seek(self, frame):
|
||||
"Select a given frame as current image"
|
||||
if frame < 0:
|
||||
frame = 0
|
||||
self._seek(frame)
|
||||
self._seek(max(frame, 0)) # Questionable backwards compatibility.
|
||||
# Create a new core image object on second and
|
||||
# subsequent frames in the image. Image may be
|
||||
# different size/mode.
|
||||
Image._decompression_bomb_check(self.size)
|
||||
self.im = Image.core.new(self.mode, self.size)
|
||||
|
||||
def tell(self):
|
||||
"Return the current frame number"
|
||||
return self._tell()
|
||||
|
||||
def _seek(self, frame):
|
||||
self.fp = self.__fp
|
||||
if frame < self.__frame:
|
||||
# rewind file
|
||||
self.__frame = -1
|
||||
self.__next = self.__first
|
||||
while self.__frame < frame:
|
||||
while len(self._frame_pos) <= frame:
|
||||
if not self.__next:
|
||||
raise EOFError("no more images in TIFF file")
|
||||
if Image.DEBUG:
|
||||
|
@ -676,14 +692,19 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
# was passed to libtiff, invalidating the buffer
|
||||
self.fp.tell()
|
||||
self.fp.seek(self.__next)
|
||||
self._frame_pos.append(self.__next)
|
||||
if Image.DEBUG:
|
||||
print("Loading tags, location: %s" % self.fp.tell())
|
||||
self.tag.load(self.fp)
|
||||
self.__next = self.tag.next
|
||||
self.__frame += 1
|
||||
self.fp.seek(self._frame_pos[frame])
|
||||
self.tag.load(self.fp)
|
||||
self.__frame = frame
|
||||
self._setup()
|
||||
|
||||
def _tell(self):
|
||||
def tell(self):
|
||||
"Return the current frame number"
|
||||
return self.__frame
|
||||
|
||||
def _decoder(self, rawmode, layer, tile=None):
|
||||
|
@ -749,7 +770,7 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
#
|
||||
# Rearranging for supporting byteio items, since they have a fileno
|
||||
# that returns an IOError if there's no underlying fp. Easier to
|
||||
# dea. with here by reordering.
|
||||
# deal with here by reordering.
|
||||
if Image.DEBUG:
|
||||
print("have getvalue. just sending in a string from getvalue")
|
||||
n, err = decoder.decode(self.fp.getvalue())
|
||||
|
@ -985,7 +1006,7 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
# Write TIFF files
|
||||
|
||||
# little endian is default except for image modes with
|
||||
# explict big endian byte-order
|
||||
# explicit big endian byte-order
|
||||
|
||||
SAVE_INFO = {
|
||||
# mode => rawmode, byteorder, photometrics,
|
||||
|
|
12
README.rst
12
README.rst
|
@ -6,19 +6,23 @@ Python Imaging Library (Fork)
|
|||
|
||||
Pillow is the "friendly PIL fork" by `Alex Clark and Contributors <https://github.com/python-pillow/Pillow/graphs/contributors>`_. PIL is the Python Imaging Library by Fredrik Lundh and Contributors.
|
||||
|
||||
.. image:: https://travis-ci.org/python-pillow/Pillow.svg?branch=master
|
||||
..
|
||||
image:: https://travis-ci.org/python-pillow/Pillow.svg?branch=master
|
||||
:target: https://travis-ci.org/python-pillow/Pillow
|
||||
:alt: Travis CI build status (Linux)
|
||||
|
||||
.. image:: https://travis-ci.org/python-pillow/pillow-wheels.svg?branch=latest
|
||||
..
|
||||
image:: https://travis-ci.org/python-pillow/pillow-wheels.svg?branch=latest
|
||||
:target: https://travis-ci.org/python-pillow/pillow-wheels
|
||||
:alt: Travis CI build status (OS X)
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/pillow.svg
|
||||
..
|
||||
image:: https://img.shields.io/pypi/v/pillow.svg
|
||||
:target: https://pypi.python.org/pypi/Pillow/
|
||||
:alt: Latest PyPI version
|
||||
|
||||
.. image:: https://img.shields.io/pypi/dm/pillow.svg
|
||||
..
|
||||
image:: https://img.shields.io/pypi/dm/pillow.svg
|
||||
:target: https://pypi.python.org/pypi/Pillow/
|
||||
:alt: Number of PyPI downloads
|
||||
|
||||
|
|
|
@ -75,8 +75,8 @@ def makedelta(fp, sequence):
|
|||
|
||||
for im in sequence:
|
||||
|
||||
#
|
||||
# FIXME: write graphics control block before each frame
|
||||
# To specify duration, add the time in milliseconds to getdata(),
|
||||
# e.g. getdata(im, duration=1000)
|
||||
|
||||
if not previous:
|
||||
|
||||
|
|
BIN
Tests/images/hopper.im
Normal file
BIN
Tests/images/hopper.im
Normal file
Binary file not shown.
BIN
Tests/images/hopper_bad_exif.jpg
Normal file
BIN
Tests/images/hopper_bad_exif.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 126 KiB |
BIN
Tests/images/hopper_merged.psd
Normal file
BIN
Tests/images/hopper_merged.psd
Normal file
Binary file not shown.
|
@ -30,6 +30,10 @@ class TestFileDcx(PillowTestCase):
|
|||
# Assert
|
||||
self.assertEqual(frame, 0)
|
||||
|
||||
def test_n_frames(self):
|
||||
im = Image.open(TEST_FILE)
|
||||
self.assertEqual(im.n_frames, 1)
|
||||
|
||||
def test_seek_too_far(self):
|
||||
# Arrange
|
||||
im = Image.open(TEST_FILE)
|
||||
|
|
|
@ -18,6 +18,10 @@ class TestFileFli(PillowTestCase):
|
|||
self.assertEqual(im.size, (128, 128))
|
||||
self.assertEqual(im.format, "FLI")
|
||||
|
||||
def test_n_frames(self):
|
||||
im = Image.open(test_file)
|
||||
self.assertEqual(im.n_frames, 2)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -134,6 +134,10 @@ class TestFileGif(PillowTestCase):
|
|||
except EOFError:
|
||||
self.assertEqual(framecount, 5)
|
||||
|
||||
def test_n_frames(self):
|
||||
im = Image.open("Tests/images/iss634.gif")
|
||||
self.assertEqual(im.n_frames, 43)
|
||||
|
||||
def test_dispose_none(self):
|
||||
img = Image.open("Tests/images/dispose_none.gif")
|
||||
try:
|
||||
|
@ -169,6 +173,33 @@ class TestFileGif(PillowTestCase):
|
|||
# first frame
|
||||
self.assertEqual(img.histogram()[img.info['transparency']], 0)
|
||||
|
||||
def test_duration(self):
|
||||
duration = 1000
|
||||
|
||||
out = self.tempfile('temp.gif')
|
||||
fp = open(out, "wb")
|
||||
im = Image.new('L', (100, 100), '#000')
|
||||
for s in GifImagePlugin.getheader(im)[0] + GifImagePlugin.getdata(im, duration=duration):
|
||||
fp.write(s)
|
||||
fp.write(b";")
|
||||
fp.close()
|
||||
reread = Image.open(out)
|
||||
|
||||
self.assertEqual(reread.info['duration'], duration)
|
||||
|
||||
def test_number_of_loops(self):
|
||||
number_of_loops = 2
|
||||
|
||||
out = self.tempfile('temp.gif')
|
||||
fp = open(out, "wb")
|
||||
im = Image.new('L', (100, 100), '#000')
|
||||
for s in GifImagePlugin.getheader(im)[0] + GifImagePlugin.getdata(im, loop=number_of_loops):
|
||||
fp.write(s)
|
||||
fp.write(b";")
|
||||
fp.close()
|
||||
reread = Image.open(out)
|
||||
|
||||
self.assertEqual(reread.info['loop'], number_of_loops)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
33
Tests/test_file_im.py
Normal file
33
Tests/test_file_im.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
from helper import unittest, PillowTestCase, hopper
|
||||
|
||||
from PIL import Image
|
||||
|
||||
# sample im
|
||||
TEST_IM = "Tests/images/hopper.im"
|
||||
|
||||
|
||||
class TestFileIm(PillowTestCase):
|
||||
|
||||
def test_sanity(self):
|
||||
im = Image.open(TEST_IM)
|
||||
im.load()
|
||||
self.assertEqual(im.mode, "RGB")
|
||||
self.assertEqual(im.size, (128, 128))
|
||||
self.assertEqual(im.format, "IM")
|
||||
|
||||
def test_n_frames(self):
|
||||
im = Image.open(TEST_IM)
|
||||
self.assertEqual(im.n_frames, 1)
|
||||
|
||||
def test_roundtrip(self):
|
||||
out = self.tempfile('temp.im')
|
||||
im = hopper()
|
||||
im.save(out)
|
||||
reread = Image.open(out)
|
||||
|
||||
self.assert_image_equal(reread, im)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
# End of file
|
|
@ -95,6 +95,10 @@ class TestFileMpo(PillowTestCase):
|
|||
im.seek(0)
|
||||
self.assertEqual(im.tell(), 0)
|
||||
|
||||
def test_n_frames(self):
|
||||
im = Image.open("Tests/images/sugarshack.mpo")
|
||||
self.assertEqual(im.n_frames, 2)
|
||||
|
||||
def test_image_grab(self):
|
||||
for test_file in test_files:
|
||||
im = Image.open(test_file)
|
||||
|
|
|
@ -16,6 +16,13 @@ class TestImagePsd(PillowTestCase):
|
|||
self.assertEqual(im.size, (128, 128))
|
||||
self.assertEqual(im.format, "PSD")
|
||||
|
||||
def test_n_frames(self):
|
||||
im = Image.open("Tests/images/hopper_merged.psd")
|
||||
self.assertEqual(im.n_frames, 1)
|
||||
|
||||
im = Image.open(test_file)
|
||||
self.assertEqual(im.n_frames, 2)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -42,6 +42,10 @@ class TestImageSpider(PillowTestCase):
|
|||
# Assert
|
||||
self.assertEqual(index, 0)
|
||||
|
||||
def test_n_frames(self):
|
||||
im = Image.open(TEST_FILE)
|
||||
self.assertEqual(im.n_frames, 1)
|
||||
|
||||
def test_loadImageSeries(self):
|
||||
# Arrange
|
||||
not_spider_file = "Tests/images/hopper.ppm"
|
||||
|
|
|
@ -3,6 +3,8 @@ from helper import unittest, PillowTestCase, hopper, py3
|
|||
|
||||
from PIL import Image, TiffImagePlugin
|
||||
|
||||
import struct
|
||||
|
||||
|
||||
class TestFileTiff(PillowTestCase):
|
||||
|
||||
|
@ -77,6 +79,12 @@ class TestFileTiff(PillowTestCase):
|
|||
im._setup()
|
||||
self.assertEqual(im.info['dpi'], (72., 72.))
|
||||
|
||||
def test_bad_exif(self):
|
||||
try:
|
||||
Image.open('Tests/images/hopper_bad_exif.jpg')._getexif()
|
||||
except struct.error:
|
||||
self.fail("Bad EXIF data should not pass incorrect values to _binary unpack")
|
||||
|
||||
def test_little_endian(self):
|
||||
im = Image.open('Tests/images/16bit.cropped.tif')
|
||||
self.assertEqual(im.getpixel((0, 0)), 480)
|
||||
|
@ -142,6 +150,13 @@ class TestFileTiff(PillowTestCase):
|
|||
self.assertEqual(
|
||||
im.getextrema(), (-3.140936851501465, 3.140684127807617))
|
||||
|
||||
def test_n_frames(self):
|
||||
im = Image.open('Tests/images/multipage-lastframe.tif')
|
||||
self.assertEqual(im.n_frames, 1)
|
||||
|
||||
im = Image.open('Tests/images/multipage.tiff')
|
||||
self.assertEqual(im.n_frames, 3)
|
||||
|
||||
def test_multipage(self):
|
||||
# issue #862
|
||||
im = Image.open('Tests/images/multipage.tiff')
|
||||
|
|
|
@ -54,7 +54,7 @@ class TestImagingCoreResize(PillowTestCase):
|
|||
# Make an image with one colored pixel, in one channel.
|
||||
# When resized, that channel should be the same as a GS image.
|
||||
# Other channels should be unaffected.
|
||||
# The R and A channels should not swap, which is indicitive of
|
||||
# The R and A channels should not swap, which is indicative of
|
||||
# an endianness issues.
|
||||
|
||||
samples = {
|
||||
|
|
|
@ -300,32 +300,32 @@ class TestImageDraw(PillowTestCase):
|
|||
img, draw = self.create_base_image_draw((20, 20))
|
||||
draw.line((5, 5, 14, 5), BLACK, 2)
|
||||
self.assert_image_equal(
|
||||
img, expected, 'line straigth horizontal normal 2px wide failed')
|
||||
img, expected, 'line straight horizontal normal 2px wide failed')
|
||||
expected = Image.open(os.path.join(IMAGES_PATH,
|
||||
'line_horizontal_w2px_inverted.png'))
|
||||
expected.load()
|
||||
img, draw = self.create_base_image_draw((20, 20))
|
||||
draw.line((14, 5, 5, 5), BLACK, 2)
|
||||
self.assert_image_equal(
|
||||
img, expected, 'line straigth horizontal inverted 2px wide failed')
|
||||
img, expected, 'line straight horizontal inverted 2px wide failed')
|
||||
expected = Image.open(os.path.join(IMAGES_PATH,
|
||||
'line_horizontal_w3px.png'))
|
||||
expected.load()
|
||||
img, draw = self.create_base_image_draw((20, 20))
|
||||
draw.line((5, 5, 14, 5), BLACK, 3)
|
||||
self.assert_image_equal(
|
||||
img, expected, 'line straigth horizontal normal 3px wide failed')
|
||||
img, expected, 'line straight horizontal normal 3px wide failed')
|
||||
img, draw = self.create_base_image_draw((20, 20))
|
||||
draw.line((14, 5, 5, 5), BLACK, 3)
|
||||
self.assert_image_equal(
|
||||
img, expected, 'line straigth horizontal inverted 3px wide failed')
|
||||
img, expected, 'line straight horizontal inverted 3px wide failed')
|
||||
expected = Image.open(os.path.join(IMAGES_PATH,
|
||||
'line_horizontal_w101px.png'))
|
||||
expected.load()
|
||||
img, draw = self.create_base_image_draw((200, 110))
|
||||
draw.line((5, 55, 195, 55), BLACK, 101)
|
||||
self.assert_image_equal(
|
||||
img, expected, 'line straigth horizontal 101px wide failed')
|
||||
img, expected, 'line straight horizontal 101px wide failed')
|
||||
|
||||
def test_line_h_s1_w2(self):
|
||||
self.skipTest('failing')
|
||||
|
@ -344,32 +344,32 @@ class TestImageDraw(PillowTestCase):
|
|||
img, draw = self.create_base_image_draw((20, 20))
|
||||
draw.line((5, 5, 5, 14), BLACK, 2)
|
||||
self.assert_image_equal(
|
||||
img, expected, 'line straigth vertical normal 2px wide failed')
|
||||
img, expected, 'line straight vertical normal 2px wide failed')
|
||||
expected = Image.open(os.path.join(IMAGES_PATH,
|
||||
'line_vertical_w2px_inverted.png'))
|
||||
expected.load()
|
||||
img, draw = self.create_base_image_draw((20, 20))
|
||||
draw.line((5, 14, 5, 5), BLACK, 2)
|
||||
self.assert_image_equal(
|
||||
img, expected, 'line straigth vertical inverted 2px wide failed')
|
||||
img, expected, 'line straight vertical inverted 2px wide failed')
|
||||
expected = Image.open(os.path.join(IMAGES_PATH,
|
||||
'line_vertical_w3px.png'))
|
||||
expected.load()
|
||||
img, draw = self.create_base_image_draw((20, 20))
|
||||
draw.line((5, 5, 5, 14), BLACK, 3)
|
||||
self.assert_image_equal(
|
||||
img, expected, 'line straigth vertical normal 3px wide failed')
|
||||
img, expected, 'line straight vertical normal 3px wide failed')
|
||||
img, draw = self.create_base_image_draw((20, 20))
|
||||
draw.line((5, 14, 5, 5), BLACK, 3)
|
||||
self.assert_image_equal(
|
||||
img, expected, 'line straigth vertical inverted 3px wide failed')
|
||||
img, expected, 'line straight vertical inverted 3px wide failed')
|
||||
expected = Image.open(os.path.join(IMAGES_PATH,
|
||||
'line_vertical_w101px.png'))
|
||||
expected.load()
|
||||
img, draw = self.create_base_image_draw((110, 200))
|
||||
draw.line((55, 5, 55, 195), BLACK, 101)
|
||||
self.assert_image_equal(img, expected,
|
||||
'line straigth vertical 101px wide failed')
|
||||
'line straight vertical 101px wide failed')
|
||||
expected = Image.open(os.path.join(IMAGES_PATH,
|
||||
'line_vertical_slope1px_w2px.png'))
|
||||
expected.load()
|
||||
|
|
|
@ -278,7 +278,7 @@ findLCMStype(char* PILmode)
|
|||
return TYPE_YCbCr_8;
|
||||
}
|
||||
else if (strcmp(PILmode, "LAB") == 0) {
|
||||
// LabX equvalent like ALab, but not reversed -- no #define in lcms2
|
||||
// LabX equivalent like ALab, but not reversed -- no #define in lcms2
|
||||
return (COLORSPACE_SH(PT_LabV2)|CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1));
|
||||
}
|
||||
|
||||
|
|
|
@ -572,7 +572,7 @@ setup_module(PyObject* m) {
|
|||
PyType_Ready(&Font_Type);
|
||||
|
||||
if (FT_Init_FreeType(&library))
|
||||
return 0; /* leave it uninitalized */
|
||||
return 0; /* leave it uninitialized */
|
||||
|
||||
FT_Library_Version(library, &major, &minor, &patch);
|
||||
|
||||
|
|
2
encode.c
2
encode.c
|
@ -737,7 +737,7 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
// While failes on 64 bit machines, complains that pos is an int instead of a Py_ssize_t
|
||||
// While fails on 64 bit machines, complains that pos is an int instead of a Py_ssize_t
|
||||
// while (PyDict_Next(dir, &pos, &key, &value)) {
|
||||
for (pos=0;pos<d_size;pos++){
|
||||
key = PyList_GetItem(keys,pos);
|
||||
|
|
|
@ -345,7 +345,7 @@ int quantize_octree(Pixel *pixelData,
|
|||
/*
|
||||
Create two color cubes, one fine grained with 8x16x8=1024
|
||||
colors buckets and a coarse with 4x4x4=64 color buckets.
|
||||
The coarse one guarantes that there are color buckets available for
|
||||
The coarse one guarantees that there are color buckets available for
|
||||
the whole color range (assuming nQuantPixels > 64).
|
||||
|
||||
For a quantization to 256 colors all 64 coarse colors will be used
|
||||
|
@ -421,7 +421,7 @@ int quantize_octree(Pixel *pixelData,
|
|||
/* add fine colors to the lookup cube */
|
||||
add_lookup_buckets(lookupCube, paletteBuckets, nFineColors, nCoarseColors);
|
||||
|
||||
/* create result pixles and map palatte indices */
|
||||
/* create result pixels and map palette indices */
|
||||
qp = malloc(sizeof(Pixel)*nPixels);
|
||||
if (!qp) goto error;
|
||||
map_image_pixels(pixelData, nPixels, lookupCube, qp);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* The Python Imaging Library
|
||||
* $Id$
|
||||
*
|
||||
* Pillow image resamling support
|
||||
* Pillow image resampling support
|
||||
*
|
||||
* history:
|
||||
* 2002-03-09 fl Created (for PIL 1.1.3)
|
||||
|
|
|
@ -245,7 +245,7 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, int
|
|||
// back in. Can't use read encoded stripe.
|
||||
|
||||
// This thing pretty much requires that I have the whole image in one shot.
|
||||
// Prehaps a stub version would work better???
|
||||
// Perhaps a stub version would work better???
|
||||
while(state->y < state->ysize){
|
||||
if (TIFFReadScanline(tiff, (tdata_t)state->buffer, (uint32)state->y, 0) == -1) {
|
||||
TRACE(("Decode Error, row %d\n", state->y));
|
||||
|
|
|
@ -808,7 +808,7 @@ unpackI12_I16(UINT8* out, const UINT8* in, int pixels){
|
|||
|
||||
FillOrder = 2 should be used only when BitsPerSample = 1 and
|
||||
the data is either uncompressed or compressed using CCITT 1D
|
||||
or 2D compression, to avoid potentially ambigous situations.
|
||||
or 2D compression, to avoid potentially ambiguous situations.
|
||||
|
||||
Yeah. I thought so. We'll see how well people read the spec.
|
||||
We've got several fillorder=2 modes in TiffImagePlugin.py
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
# Testing reqs
|
||||
# Testing and documentation requirements
|
||||
-e .
|
||||
-r docs/requirements.txt
|
||||
coveralls
|
||||
nose
|
||||
nose-cov
|
||||
pep8
|
||||
pyflakes
|
||||
|
|
Loading…
Reference in New Issue
Block a user