mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-25 01:16:16 +03:00
Merge branch 'master' into license
This commit is contained in:
commit
5d9c975c46
136
.travis.yml
136
.travis.yml
|
@ -6,104 +6,55 @@ notifications:
|
|||
# Run slow PyPy* first, to give them a headstart and reduce waiting time.
|
||||
# Run latest 3.x and 2.x next, to get quick compatibility results.
|
||||
# Then run the remainder.
|
||||
python:
|
||||
- "pypy"
|
||||
- "pypy3"
|
||||
- 3.5
|
||||
- 2.7
|
||||
- 2.6
|
||||
- "2.7_with_system_site_packages" # For PyQt4
|
||||
- 3.2
|
||||
- 3.3
|
||||
- 3.4
|
||||
- nightly
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
allow_failures:
|
||||
- python: nightly
|
||||
include:
|
||||
- python: "pypy"
|
||||
- python: "pypy3"
|
||||
- python: '3.6'
|
||||
- python: '2.7'
|
||||
- env: DOCKER="alpine"
|
||||
- env: DOCKER="ubuntu-trusty-x86"
|
||||
- env: DOCKER="ubuntu-xenial-amd64"
|
||||
- env: DOCKER="ubuntu-precise-amd64"
|
||||
- python: "2.7_with_system_site_packages" # For PyQt4
|
||||
- python: '3.5'
|
||||
- python: '3.4'
|
||||
- python: '3.3'
|
||||
- python: 'nightly'
|
||||
|
||||
dist: trusty
|
||||
|
||||
sudo: required
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
install:
|
||||
- "travis_retry pip install pycparser!=2.14" # TEMPORARY, WORKAROUND FOR https://github.com/eliben/pycparser/issues/147
|
||||
- "travis_retry sudo apt-get update"
|
||||
- "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 nose"
|
||||
- "travis_retry pip install check-manifest"
|
||||
# Pyroma tests sometimes hang on PyPy and Python 2.6; skip for those
|
||||
- if [ $TRAVIS_PYTHON_VERSION != "pypy" && $TRAVIS_PYTHON_VERSION != "2.6" ]; then travis_retry pip install pyroma; fi
|
||||
- if [ "$DOCKER" == "" ]; then .travis/install.sh; fi
|
||||
|
||||
- if [ "$TRAVIS_PYTHON_VERSION" == "2.6" ]; then travis_retry pip install unittest2; fi
|
||||
before_install:
|
||||
- if [ "$DOCKER" ]; then docker pull pythonpillow/$DOCKER; fi
|
||||
|
||||
# Coverage 4.0 doesn't support Python 3.2
|
||||
- if [ "$TRAVIS_PYTHON_VERSION" == "3.2" ]; then travis_retry pip install coverage==3.7.1; fi
|
||||
- if [ "$TRAVIS_PYTHON_VERSION" != "3.2" ]; then travis_retry pip install coverage; fi
|
||||
|
||||
# docs only on python 2.7
|
||||
- if [ "$TRAVIS_PYTHON_VERSION" == "2.7" ]; then travis_retry pip install -r requirements.txt ; fi
|
||||
|
||||
# clean checkout for manifest
|
||||
- mkdir /tmp/check-manifest && cp -a . /tmp/check-manifest
|
||||
|
||||
# webp
|
||||
- pushd depends && ./install_webp.sh && popd
|
||||
|
||||
# openjpeg
|
||||
- pushd depends && ./install_openjpeg.sh && popd
|
||||
|
||||
# libimagequant
|
||||
- pushd depends && ./install_imagequant.sh && popd
|
||||
before_script:
|
||||
# Qt needs a display for some of the tests, and it's only run on the system site packages install
|
||||
- "export DISPLAY=:99.0"
|
||||
- "sh -e /etc/init.d/xvfb start"
|
||||
|
||||
script:
|
||||
- if [ "$TRAVIS_PYTHON_VERSION" != "nightly" ]; then coverage erase; fi
|
||||
- python setup.py clean
|
||||
- CFLAGS="-coverage" python setup.py build_ext --inplace
|
||||
|
||||
- if [ "$TRAVIS_PYTHON_VERSION" != "nightly" ]; then coverage run --append --include=PIL/* selftest.py; fi
|
||||
- if [ "$TRAVIS_PYTHON_VERSION" != "nightly" ]; then coverage run --append --include=PIL/* -m nose -vx Tests/test_*.py; fi
|
||||
- pushd /tmp/check-manifest && check-manifest --ignore ".coveragerc,.editorconfig,*.yml,*.yaml,tox.ini" && popd
|
||||
|
||||
# Docs
|
||||
- if [ "$TRAVIS_PYTHON_VERSION" == "2.7" ]; then make install && make doccheck; fi
|
||||
- |
|
||||
if [ "$DOCKER" == "" ]; then
|
||||
.travis/script.sh
|
||||
else
|
||||
docker run -v $TRAVIS_BUILD_DIR:/Pillow pythonpillow/$DOCKER
|
||||
fi
|
||||
|
||||
after_success:
|
||||
# gather the coverage data
|
||||
- travis_retry sudo apt-get -qq install lcov
|
||||
- lcov --capture --directory . -b . --output-file coverage.info
|
||||
# filter to remove system headers
|
||||
- lcov --remove coverage.info '/usr/*' -o coverage.filtered.info
|
||||
# convert to json
|
||||
- travis_retry gem install coveralls-lcov
|
||||
- coveralls-lcov -v -n coverage.filtered.info > coverage.c.json
|
||||
|
||||
- coverage report
|
||||
- travis_retry pip install coveralls-merge
|
||||
- coveralls-merge coverage.c.json
|
||||
|
||||
- travis_retry pip install pep8 pyflakes
|
||||
- pep8 --statistics --count PIL/*.py
|
||||
- pep8 --statistics --count Tests/*.py
|
||||
- pyflakes *.py | tee >(wc -l)
|
||||
- pyflakes PIL/*.py | tee >(wc -l)
|
||||
- pyflakes Tests/*.py | tee >(wc -l)
|
||||
|
||||
# Coverage and quality reports on just the latest diff.
|
||||
# (Installation is very slow on Py3, so just do it for Py2.)
|
||||
- if [ ${TRAVIS_PYTHON_VERSION:0:1} == "2" ]; then depends/diffcover-install.sh; fi
|
||||
- if [ ${TRAVIS_PYTHON_VERSION:0:1} == "2" ]; then depends/diffcover-run.sh; fi
|
||||
|
||||
# after_all
|
||||
- |
|
||||
if [ "$TRAVIS_REPO_SLUG" = "python-pillow/Pillow" ] && [ "$TRAVIS_BRANCH" = "master" ] && [ "$TRAVIS_PULL_REQUEST" = "false" ]; then
|
||||
curl -Lo travis_after_all.py https://raw.github.com/dmakhno/travis_after_all/master/travis_after_all.py
|
||||
python travis_after_all.py
|
||||
export $(cat .to_export_back)
|
||||
if [ "$BUILD_LEADER" = "YES" ]; then
|
||||
if [ "$BUILD_AGGREGATE_STATUS" = "others_succeeded" ]; then
|
||||
echo "All jobs succeded! Triggering macOS build..."
|
||||
# Trigger a macOS build at the pillow-wheels repo
|
||||
./build_children.sh
|
||||
else
|
||||
echo "Some jobs failed"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
- .travis/after_success.sh
|
||||
|
||||
after_failure:
|
||||
- |
|
||||
if [ "$TRAVIS_REPO_SLUG" = "python-pillow/Pillow" ] && [ "$TRAVIS_BRANCH" = "master" ] && [ "$TRAVIS_PULL_REQUEST" = "false" ]; then
|
||||
|
@ -125,11 +76,6 @@ after_script:
|
|||
echo leader=$BUILD_LEADER status=$BUILD_AGGREGATE_STATUS
|
||||
fi
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
allow_failures:
|
||||
- python: nightly
|
||||
|
||||
env:
|
||||
global:
|
||||
# travis encrypt AUTH_TOKEN=
|
||||
|
|
46
.travis/after_success.sh
Executable file
46
.travis/after_success.sh
Executable file
|
@ -0,0 +1,46 @@
|
|||
#!/bin/bash
|
||||
|
||||
# gather the coverage data
|
||||
sudo apt-get -qq install lcov
|
||||
lcov --capture --directory . -b . --output-file coverage.info
|
||||
# filter to remove system headers
|
||||
lcov --remove coverage.info '/usr/*' -o coverage.filtered.info
|
||||
# convert to json
|
||||
gem install coveralls-lcov
|
||||
coveralls-lcov -v -n coverage.filtered.info > coverage.c.json
|
||||
|
||||
coverage report
|
||||
pip install coveralls-merge
|
||||
coveralls-merge coverage.c.json
|
||||
|
||||
if [ "$DOCKER" == "" ]; then
|
||||
pip install pep8 pyflakes
|
||||
pep8 --statistics --count PIL/*.py
|
||||
pep8 --statistics --count Tests/*.py
|
||||
pyflakes *.py | tee >(wc -l)
|
||||
pyflakes PIL/*.py | tee >(wc -l)
|
||||
pyflakes Tests/*.py | tee >(wc -l)
|
||||
fi
|
||||
|
||||
if [ "$TRAVIS_PYTHON_VERSION" == "2.7" ] && [ "$DOCKER" == "" ]; then
|
||||
# Coverage and quality reports on just the latest diff.
|
||||
# (Installation is very slow on Py3, so just do it for Py2.)
|
||||
depends/diffcover-install.sh
|
||||
depends/diffcover-run.sh
|
||||
fi
|
||||
|
||||
# after_all
|
||||
|
||||
if [ "$TRAVIS_REPO_SLUG" = "python-pillow/Pillow" ] && [ "$TRAVIS_BRANCH" = "master" ] && [ "$TRAVIS_PULL_REQUEST" = "false" ]; then
|
||||
curl -Lo travis_after_all.py https://raw.github.com/dmakhno/travis_after_all/master/travis_after_all.py
|
||||
python travis_after_all.py
|
||||
export $(cat .to_export_back)
|
||||
if [ "$BUILD_LEADER" = "YES" ]; then
|
||||
if [ "$BUILD_AGGREGATE_STATUS" = "others_succeeded" ]; then
|
||||
echo "All jobs succeded! Triggering macOS build..."
|
||||
# Trigger a macOS build at the pillow-wheels repo
|
||||
./build_children.sh
|
||||
else
|
||||
echo "Some jobs failed"
|
||||
fi
|
||||
fi
|
34
.travis/install.sh
Executable file
34
.travis/install.sh
Executable file
|
@ -0,0 +1,34 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
sudo apt-get update
|
||||
sudo apt-get -qq install libfreetype6-dev liblcms2-dev\
|
||||
python-qt4 ghostscript libffi-dev libjpeg-turbo-progs cmake imagemagick
|
||||
pip install cffi
|
||||
pip install nose
|
||||
pip install check-manifest
|
||||
pip install olefile
|
||||
# Pyroma tests sometimes hang on PyPy; skip
|
||||
if [ "$TRAVIS_PYTHON_VERSION" != "pypy" ]; then pip install pyroma; fi
|
||||
|
||||
pip install coverage
|
||||
|
||||
# docs only on python 2.7
|
||||
if [ "$TRAVIS_PYTHON_VERSION" == "2.7" ]; then pip install -r requirements.txt ; fi
|
||||
|
||||
# clean checkout for manifest
|
||||
mkdir /tmp/check-manifest && cp -a . /tmp/check-manifest
|
||||
|
||||
# webp
|
||||
pushd depends && ./install_webp.sh && popd
|
||||
|
||||
# openjpeg
|
||||
pushd depends && ./install_openjpeg.sh && popd
|
||||
|
||||
# libimagequant
|
||||
pushd depends && ./install_imagequant.sh && popd
|
||||
|
||||
# extra test images
|
||||
pushd depends && ./install_extra_test_images.sh && popd
|
||||
|
14
.travis/script.sh
Executable file
14
.travis/script.sh
Executable file
|
@ -0,0 +1,14 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
coverage erase
|
||||
python setup.py clean
|
||||
CFLAGS="-coverage" python setup.py build_ext --inplace
|
||||
|
||||
coverage run --append --include=PIL/* selftest.py
|
||||
coverage run --append --include=PIL/* -m nose -vx Tests/test_*.py
|
||||
pushd /tmp/check-manifest && check-manifest --ignore ".coveragerc,.editorconfig,*.yml,*.yaml,tox.ini" && popd
|
||||
|
||||
# Docs
|
||||
if [ "$TRAVIS_PYTHON_VERSION" == "2.7" ]; then make install && make doccheck; fi
|
598
CHANGES.rst
598
CHANGES.rst
File diff suppressed because it is too large
Load Diff
2
LICENSE
2
LICENSE
|
@ -5,7 +5,7 @@ The Python Imaging Library (PIL) is
|
|||
|
||||
Pillow is the friendly PIL fork. It is
|
||||
|
||||
Copyright © 2012-2016 by Alex Clark and contributors
|
||||
Copyright © 2010-2017 by Alex Clark and contributors
|
||||
|
||||
Like PIL, Pillow is licensed under the open source PIL Software License:
|
||||
|
||||
|
|
7
Makefile
7
Makefile
|
@ -58,6 +58,13 @@ install:
|
|||
python setup.py install
|
||||
python selftest.py --installed
|
||||
|
||||
debug:
|
||||
# make a debug version if we don't have a -dbg python. Leaves in symbols
|
||||
# for our stuff, kills optimization, and redirects to dev null so we
|
||||
# see any build failures.
|
||||
make clean > /dev/null
|
||||
CFLAGS='-g -O0' python setup.py build_ext install > /dev/null
|
||||
|
||||
install-req:
|
||||
pip install -r requirements.txt
|
||||
|
||||
|
|
|
@ -17,8 +17,9 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from PIL import Image
|
||||
from PIL import FontFile
|
||||
from __future__ import print_function
|
||||
|
||||
from . import Image, FontFile
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
@ -119,9 +120,9 @@ class BdfFontFile(FontFile.FontFile):
|
|||
|
||||
# fontname = ";".join(font[1:])
|
||||
|
||||
# print "#", fontname
|
||||
# print("#", fontname)
|
||||
# for i in comments:
|
||||
# print "#", i
|
||||
# print("#", i)
|
||||
|
||||
while True:
|
||||
c = bdf_char(fp)
|
||||
|
|
|
@ -24,18 +24,13 @@
|
|||
#
|
||||
|
||||
|
||||
from PIL import Image, ImageFile, ImagePalette, _binary
|
||||
from . import Image, ImageFile, ImagePalette
|
||||
from ._binary import i8, i16le as i16, i32le as i32, \
|
||||
o8, o16le as o16, o32le as o32
|
||||
import math
|
||||
|
||||
__version__ = "0.7"
|
||||
|
||||
i8 = _binary.i8
|
||||
i16 = _binary.i16le
|
||||
i32 = _binary.i32le
|
||||
o8 = _binary.o8
|
||||
o16 = _binary.o16le
|
||||
o32 = _binary.o32le
|
||||
|
||||
#
|
||||
# --------------------------------------------------------------------
|
||||
# Read BMP file
|
||||
|
@ -73,7 +68,7 @@ class BmpImageFile(ImageFile.ImageFile):
|
|||
read, seek = self.fp.read, self.fp.seek
|
||||
if header:
|
||||
seek(header)
|
||||
file_info = dict()
|
||||
file_info = {}
|
||||
file_info['header_size'] = i32(read(4)) # read bmp header size @offset 14 (this is part of the header size)
|
||||
file_info['direction'] = -1
|
||||
# --------------------- If requested, read header at a specific position
|
||||
|
@ -136,12 +131,13 @@ class BmpImageFile(ImageFile.ImageFile):
|
|||
# ----------------- Process BMP with Bitfields compression (not palette)
|
||||
if file_info['compression'] == self.BITFIELDS:
|
||||
SUPPORTED = {
|
||||
32: [(0xff0000, 0xff00, 0xff, 0x0), (0xff0000, 0xff00, 0xff, 0xff000000), (0x0, 0x0, 0x0, 0x0)],
|
||||
32: [(0xff0000, 0xff00, 0xff, 0x0), (0xff0000, 0xff00, 0xff, 0xff000000), (0x0, 0x0, 0x0, 0x0), (0xff000000, 0xff0000, 0xff00, 0x0) ],
|
||||
24: [(0xff0000, 0xff00, 0xff)],
|
||||
16: [(0xf800, 0x7e0, 0x1f), (0x7c00, 0x3e0, 0x1f)]
|
||||
}
|
||||
MASK_MODES = {
|
||||
(32, (0xff0000, 0xff00, 0xff, 0x0)): "BGRX",
|
||||
(32, (0xff000000, 0xff0000, 0xff00, 0x0)): "XBGR",
|
||||
(32, (0xff0000, 0xff00, 0xff, 0xff000000)): "BGRA",
|
||||
(32, (0x0, 0x0, 0x0, 0x0)): "BGRA",
|
||||
(24, (0xff0000, 0xff00, 0xff)): "BGR",
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from PIL import Image, ImageFile
|
||||
from . import Image, ImageFile
|
||||
|
||||
_handler = None
|
||||
|
||||
|
|
|
@ -16,18 +16,16 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
from PIL import Image, BmpImagePlugin, _binary
|
||||
from . import Image, BmpImagePlugin
|
||||
from ._binary import i8, i16le as i16, i32le as i32
|
||||
|
||||
__version__ = "0.1"
|
||||
|
||||
#
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
i8 = _binary.i8
|
||||
i16 = _binary.i16le
|
||||
i32 = _binary.i32le
|
||||
|
||||
|
||||
def _accept(prefix):
|
||||
return prefix[:4] == b"\0\0\2\0"
|
||||
|
@ -58,14 +56,14 @@ class CurImageFile(BmpImagePlugin.BmpImageFile):
|
|||
m = s
|
||||
elif i8(s[0]) > i8(m[0]) and i8(s[1]) > i8(m[1]):
|
||||
m = s
|
||||
# print "width", i8(s[0])
|
||||
# print "height", i8(s[1])
|
||||
# print "colors", i8(s[2])
|
||||
# print "reserved", i8(s[3])
|
||||
# print "hotspot x", i16(s[4:])
|
||||
# print "hotspot y", i16(s[6:])
|
||||
# print "bytes", i32(s[8:])
|
||||
# print "offset", i32(s[12:])
|
||||
# print("width", i8(s[0]))
|
||||
# print("height", i8(s[1]))
|
||||
# print("colors", i8(s[2]))
|
||||
# print("reserved", i8(s[3]))
|
||||
# print("hotspot x", i16(s[4:]))
|
||||
# print("hotspot y", i16(s[6:]))
|
||||
# print("bytes", i32(s[8:]))
|
||||
# print("offset", i32(s[12:]))
|
||||
if not m:
|
||||
raise TypeError("No cursors were found")
|
||||
|
||||
|
|
|
@ -21,15 +21,14 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from PIL import Image, _binary
|
||||
from PIL.PcxImagePlugin import PcxImageFile
|
||||
from . import Image
|
||||
from ._binary import i32le as i32
|
||||
from .PcxImagePlugin import PcxImageFile
|
||||
|
||||
__version__ = "0.2"
|
||||
|
||||
MAGIC = 0x3ADE68B1 # QUIZ: what's this value, then?
|
||||
|
||||
i32 = _binary.i32le
|
||||
|
||||
|
||||
def _accept(prefix):
|
||||
return len(prefix) >= 4 and i32(prefix) == MAGIC
|
||||
|
|
|
@ -12,7 +12,7 @@ Full text of the CC0 license:
|
|||
|
||||
import struct
|
||||
from io import BytesIO
|
||||
from PIL import Image, ImageFile
|
||||
from . import Image, ImageFile
|
||||
|
||||
|
||||
# Magic ("DDS ")
|
||||
|
|
|
@ -23,16 +23,14 @@
|
|||
import re
|
||||
import io
|
||||
import sys
|
||||
from PIL import Image, ImageFile, _binary
|
||||
from . import Image, ImageFile
|
||||
from ._binary import i32le as i32, o32le as o32
|
||||
|
||||
__version__ = "0.5"
|
||||
|
||||
#
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
i32 = _binary.i32le
|
||||
o32 = _binary.o32le
|
||||
|
||||
split = re.compile(r"^%%([^:]*):[ \t]*(.*)[ \t]*$")
|
||||
field = re.compile(r"^%[%!\w]([^:]*)[ \t]*$")
|
||||
|
||||
|
@ -145,7 +143,8 @@ def Ghostscript(tile, size, fp, scale=1):
|
|||
status = gs.wait()
|
||||
if status:
|
||||
raise IOError("gs failed (status %d)" % status)
|
||||
im = Image.core.open_ppm(outfile)
|
||||
im = Image.open(outfile)
|
||||
im.load()
|
||||
finally:
|
||||
try:
|
||||
os.unlink(outfile)
|
||||
|
@ -154,7 +153,7 @@ def Ghostscript(tile, size, fp, scale=1):
|
|||
except OSError:
|
||||
pass
|
||||
|
||||
return im
|
||||
return im.im.copy()
|
||||
|
||||
|
||||
class PSFile(object):
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from PIL import Image, ImageFile
|
||||
from . import Image, ImageFile
|
||||
|
||||
_handler = None
|
||||
|
||||
|
|
|
@ -16,15 +16,11 @@
|
|||
#
|
||||
|
||||
|
||||
from PIL import Image, ImageFile, ImagePalette, _binary
|
||||
from . import Image, ImageFile, ImagePalette
|
||||
from ._binary import i8, i16le as i16, i32le as i32, o8
|
||||
|
||||
__version__ = "0.2"
|
||||
|
||||
i8 = _binary.i8
|
||||
i16 = _binary.i16le
|
||||
i32 = _binary.i32le
|
||||
o8 = _binary.o8
|
||||
|
||||
|
||||
#
|
||||
# decoder
|
||||
|
|
|
@ -14,8 +14,10 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
from PIL import Image, _binary
|
||||
from . import Image, _binary
|
||||
|
||||
WIDTH = 800
|
||||
|
||||
|
@ -88,7 +90,7 @@ class FontFile(object):
|
|||
x = xx
|
||||
s = src[0] + x0, src[1] + y0, src[2] + x0, src[3] + y0
|
||||
self.bitmap.paste(im.crop(src), s)
|
||||
# print chr(i), dst, s
|
||||
# print(chr(i), dst, s)
|
||||
self.metrics[i] = d, dst, s
|
||||
|
||||
def save(self, filename):
|
||||
|
@ -100,14 +102,13 @@ class FontFile(object):
|
|||
self.bitmap.save(os.path.splitext(filename)[0] + ".pbm", "PNG")
|
||||
|
||||
# font metrics
|
||||
fp = open(os.path.splitext(filename)[0] + ".pil", "wb")
|
||||
fp.write(b"PILfont\n")
|
||||
fp.write((";;;;;;%d;\n" % self.ysize).encode('ascii')) # HACK!!!
|
||||
fp.write(b"DATA\n")
|
||||
for id in range(256):
|
||||
m = self.metrics[id]
|
||||
if not m:
|
||||
puti16(fp, [0] * 10)
|
||||
else:
|
||||
puti16(fp, m[0] + m[1] + m[2])
|
||||
fp.close()
|
||||
with open(os.path.splitext(filename)[0] + ".pil", "wb") as fp:
|
||||
fp.write(b"PILfont\n")
|
||||
fp.write((";;;;;;%d;\n" % self.ysize).encode('ascii')) # HACK!!!
|
||||
fp.write(b"DATA\n")
|
||||
for id in range(256):
|
||||
m = self.metrics[id]
|
||||
if not m:
|
||||
puti16(fp, [0] * 10)
|
||||
else:
|
||||
puti16(fp, m[0] + m[1] + m[2])
|
||||
|
|
|
@ -15,13 +15,15 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
from PIL import Image, ImageFile
|
||||
from PIL.OleFileIO import i8, i32, MAGIC, OleFileIO
|
||||
from . import Image, ImageFile
|
||||
from ._binary import i32le as i32, i8
|
||||
|
||||
import olefile
|
||||
|
||||
__version__ = "0.1"
|
||||
|
||||
|
||||
# we map from colour field tuples to (mode, rawmode) descriptors
|
||||
MODES = {
|
||||
# opacity
|
||||
|
@ -42,7 +44,7 @@ MODES = {
|
|||
# --------------------------------------------------------------------
|
||||
|
||||
def _accept(prefix):
|
||||
return prefix[:8] == MAGIC
|
||||
return prefix[:8] == olefile.MAGIC
|
||||
|
||||
|
||||
##
|
||||
|
@ -59,7 +61,7 @@ class FpxImageFile(ImageFile.ImageFile):
|
|||
# to be a FlashPix file
|
||||
|
||||
try:
|
||||
self.ole = OleFileIO(self.fp)
|
||||
self.ole = olefile.OleFileIO(self.fp)
|
||||
except IOError:
|
||||
raise SyntaxError("not an FPX file; invalid OLE file")
|
||||
|
||||
|
@ -112,7 +114,7 @@ class FpxImageFile(ImageFile.ImageFile):
|
|||
if id in prop:
|
||||
self.jpeg[i] = prop[id]
|
||||
|
||||
# print len(self.jpeg), "tables loaded"
|
||||
# print(len(self.jpeg), "tables loaded")
|
||||
|
||||
self._open_subimage(1, self.maxid)
|
||||
|
||||
|
@ -141,7 +143,7 @@ class FpxImageFile(ImageFile.ImageFile):
|
|||
offset = i32(s, 28)
|
||||
length = i32(s, 32)
|
||||
|
||||
# print size, self.mode, self.rawmode
|
||||
# print(size, self.mode, self.rawmode)
|
||||
|
||||
if size != self.size:
|
||||
raise IOError("subimage mismatch")
|
||||
|
|
|
@ -13,7 +13,7 @@ packed custom format called FTEX. This file format uses file extensions FTC and
|
|||
* FTC files are compressed textures (using standard texture compression).
|
||||
* FTU files are not compressed.
|
||||
Texture File Format
|
||||
The FTC and FTU texture files both use the same format, called. This
|
||||
The FTC and FTU texture files both use the same format. This
|
||||
has the following structure:
|
||||
{header}
|
||||
{format_directory}
|
||||
|
@ -42,7 +42,7 @@ Note: All data is stored in little-Endian (Intel) byte order.
|
|||
|
||||
import struct
|
||||
from io import BytesIO
|
||||
from PIL import Image, ImageFile
|
||||
from . import Image, ImageFile
|
||||
|
||||
|
||||
MAGIC = b"FTEX"
|
||||
|
|
|
@ -24,9 +24,8 @@
|
|||
# Version 3 files have a format specifier of 18 for 16bit floats in
|
||||
# the color depth field. This is currently unsupported by Pillow.
|
||||
|
||||
from PIL import Image, ImageFile, _binary
|
||||
|
||||
i32 = _binary.i32be
|
||||
from . import Image, ImageFile
|
||||
from ._binary import i32be as i32
|
||||
|
||||
|
||||
def _accept(prefix):
|
||||
|
|
|
@ -23,8 +23,9 @@
|
|||
# purposes only.
|
||||
|
||||
|
||||
from PIL import ImageFile, ImagePalette, _binary
|
||||
from PIL._util import isPath
|
||||
from . import ImageFile, ImagePalette
|
||||
from ._binary import i16be as i16
|
||||
from ._util import isPath
|
||||
|
||||
__version__ = "0.1"
|
||||
|
||||
|
@ -34,8 +35,6 @@ except ImportError:
|
|||
import __builtin__
|
||||
builtins = __builtin__
|
||||
|
||||
i16 = _binary.i16be
|
||||
|
||||
|
||||
##
|
||||
# Image plugin for the GD uncompressed format. Note that this format
|
||||
|
|
|
@ -24,8 +24,9 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from PIL import Image, ImageFile, ImagePalette, \
|
||||
ImageChops, ImageSequence, _binary
|
||||
from . import Image, ImageFile, ImagePalette, \
|
||||
ImageChops, ImageSequence
|
||||
from ._binary import i8, i16le as i16, o8, o16le as o16
|
||||
|
||||
__version__ = "0.9"
|
||||
|
||||
|
@ -33,11 +34,6 @@ __version__ = "0.9"
|
|||
# --------------------------------------------------------------------
|
||||
# Helpers
|
||||
|
||||
i8 = _binary.i8
|
||||
i16 = _binary.i16le
|
||||
o8 = _binary.o8
|
||||
o16 = _binary.o16le
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Identify/read GIF files
|
||||
|
@ -352,10 +348,18 @@ def _save(im, fp, filename, save_all=False):
|
|||
|
||||
first_frame = None
|
||||
append_images = im.encoderinfo.get("append_images", [])
|
||||
if "duration" in im.encoderinfo:
|
||||
duration = im.encoderinfo["duration"]
|
||||
else:
|
||||
duration = None
|
||||
frame_count = 0
|
||||
for imSequence in [im]+append_images:
|
||||
for im_frame in ImageSequence.Iterator(imSequence):
|
||||
encoderinfo = im.encoderinfo.copy()
|
||||
im_frame = _convert_mode(im_frame)
|
||||
if isinstance(duration, (list, tuple)):
|
||||
encoderinfo["duration"] = duration[frame_count]
|
||||
frame_count += 1
|
||||
|
||||
# To specify duration, add the time in milliseconds to getdata(),
|
||||
# e.g. getdata(im_frame, duration=1000)
|
||||
|
@ -434,18 +438,16 @@ def _get_local_header(fp, im, offset, flags):
|
|||
# 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)
|
||||
|
||||
used_palette_colors = _get_optimize(im, im.encoderinfo)
|
||||
if used_palette_colors is not None:
|
||||
# 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
|
||||
for i, palette_color in enumerate(used_palette_colors):
|
||||
if palette_color == transparency:
|
||||
transparency = i
|
||||
transparent_color_exists = True
|
||||
break
|
||||
else:
|
||||
transparent_color_exists = False
|
||||
|
||||
if "duration" in im.encoderinfo:
|
||||
duration = int(im.encoderinfo["duration"] / 10)
|
||||
|
@ -515,22 +517,20 @@ def _save_netpbm(im, fp, filename):
|
|||
import tempfile
|
||||
file = im._dump()
|
||||
|
||||
if im.mode != "RGB":
|
||||
with open(filename, 'wb') as f:
|
||||
stderr = tempfile.TemporaryFile()
|
||||
check_call(["ppmtogif", file], stdout=f, stderr=stderr)
|
||||
else:
|
||||
with open(filename, 'wb') as f:
|
||||
|
||||
with open(filename, 'wb') as f:
|
||||
if im.mode != "RGB":
|
||||
with tempfile.TemporaryFile() as stderr:
|
||||
check_call(["ppmtogif", file], stdout=f, stderr=stderr)
|
||||
else:
|
||||
# Pipe ppmquant output into ppmtogif
|
||||
# "ppmquant 256 %s | ppmtogif > %s" % (file, filename)
|
||||
quant_cmd = ["ppmquant", "256", file]
|
||||
togif_cmd = ["ppmtogif"]
|
||||
stderr = tempfile.TemporaryFile()
|
||||
quant_proc = Popen(quant_cmd, stdout=PIPE, stderr=stderr)
|
||||
stderr = tempfile.TemporaryFile()
|
||||
togif_proc = Popen(togif_cmd, stdin=quant_proc.stdout, stdout=f,
|
||||
stderr=stderr)
|
||||
with tempfile.TemporaryFile() as stderr:
|
||||
quant_proc = Popen(quant_cmd, stdout=PIPE, stderr=stderr)
|
||||
with tempfile.TemporaryFile() as stderr:
|
||||
togif_proc = Popen(togif_cmd, stdin=quant_proc.stdout,
|
||||
stdout=f, stderr=stderr)
|
||||
|
||||
# Allow ppmquant to receive SIGPIPE if ppmtogif exits
|
||||
quant_proc.stdout.close()
|
||||
|
@ -552,9 +552,28 @@ 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)
|
||||
# Force optimization so that we can test performance against
|
||||
# cases where it took lots of memory and time previously.
|
||||
_FORCE_OPTIMIZE = False
|
||||
|
||||
def _get_optimize(im, info):
|
||||
if im.mode in ("P", "L") and info and info.get("optimize", 0):
|
||||
# Potentially expensive operation.
|
||||
|
||||
# The palette saves 3 bytes per color not used, but palette
|
||||
# lengths are restricted to 3*(2**N) bytes. Max saving would
|
||||
# be 768 -> 6 bytes if we went all the way down to 2 colors.
|
||||
# * If we're over 128 colors, we can't save any space.
|
||||
# * If there aren't any holes, it's not worth collapsing.
|
||||
# * If we have a 'large' image, the palette is in the noise.
|
||||
|
||||
# create the new palette if not every color is used
|
||||
used_palette_colors = _get_used_palette_colors(im)
|
||||
if _FORCE_OPTIMIZE or im.mode == 'L' or \
|
||||
(len(used_palette_colors) <= 128 and
|
||||
max(used_palette_colors) > len(used_palette_colors) and
|
||||
im.width * im.height < 512 * 512):
|
||||
return used_palette_colors
|
||||
|
||||
def _get_used_palette_colors(im):
|
||||
used_palette_colors = []
|
||||
|
@ -586,10 +605,6 @@ def _get_header_palette(palette_bytes):
|
|||
palette_bytes += o8(0) * 3 * actual_target_size_diff
|
||||
return palette_bytes
|
||||
|
||||
# Force optimization so that we can test performance against
|
||||
# cases where it took lots of memory and time previously.
|
||||
_FORCE_OPTIMIZE = False
|
||||
|
||||
def _get_palette_bytes(im, palette, info):
|
||||
if im.mode == "P":
|
||||
if palette and isinstance(palette, bytes):
|
||||
|
@ -600,81 +615,66 @@ def _get_palette_bytes(im, palette, info):
|
|||
if palette and isinstance(palette, bytes):
|
||||
source_palette = palette[:768]
|
||||
else:
|
||||
source_palette = bytearray([i//3 for i in range(768)])
|
||||
source_palette = bytearray(i//3 for i in range(768))
|
||||
|
||||
used_palette_colors = palette_bytes = None
|
||||
palette_bytes = None
|
||||
|
||||
if _get_optimize(im, info):
|
||||
used_palette_colors = _get_used_palette_colors(im)
|
||||
used_palette_colors = _get_optimize(im, info)
|
||||
if used_palette_colors is not None:
|
||||
palette_bytes = b""
|
||||
new_positions = [0]*256
|
||||
|
||||
# Potentially expensive operation.
|
||||
# pick only the used colors from the palette
|
||||
for i, oldPosition in enumerate(used_palette_colors):
|
||||
palette_bytes += source_palette[oldPosition*3:oldPosition*3+3]
|
||||
new_positions[oldPosition] = i
|
||||
|
||||
# The palette saves 3 bytes per color not used, but palette
|
||||
# lengths are restricted to 3*(2**N) bytes. Max saving would
|
||||
# be 768 -> 6 bytes if we went all the way down to 2 colors.
|
||||
# * If we're over 128 colors, we can't save any space.
|
||||
# * If there aren't any holes, it's not worth collapsing.
|
||||
# * If we have a 'large' image, the palette is in the noise.
|
||||
# replace the palette color id of all pixel with the new id
|
||||
|
||||
# create the new palette if not every color is used
|
||||
if _FORCE_OPTIMIZE or im.mode == 'L' or \
|
||||
(len(used_palette_colors) <= 128 and
|
||||
max(used_palette_colors) > len(used_palette_colors) and
|
||||
im.width * im.height < 512 * 512):
|
||||
palette_bytes = b""
|
||||
new_positions = [0]*256
|
||||
# Palette images are [0..255], mapped through a 1 or 3
|
||||
# byte/color map. We need to remap the whole image
|
||||
# from palette 1 to palette 2. New_positions is
|
||||
# an array of indexes into palette 1. Palette 2 is
|
||||
# palette 1 with any holes removed.
|
||||
|
||||
# pick only the used colors from the palette
|
||||
for i, oldPosition in enumerate(used_palette_colors):
|
||||
palette_bytes += source_palette[oldPosition*3:oldPosition*3+3]
|
||||
new_positions[oldPosition] = i
|
||||
# We're going to leverage the convert mechanism to use the
|
||||
# C code to remap the image from palette 1 to palette 2,
|
||||
# by forcing the source image into 'L' mode and adding a
|
||||
# mapping 'L' mode palette, then converting back to 'L'
|
||||
# sans palette thus converting the image bytes, then
|
||||
# assigning the optimized RGB palette.
|
||||
|
||||
# replace the palette color id of all pixel with the new id
|
||||
# perf reference, 9500x4000 gif, w/~135 colors
|
||||
# 14 sec prepatch, 1 sec postpatch with optimization forced.
|
||||
|
||||
# Palette images are [0..255], mapped through a 1 or 3
|
||||
# byte/color map. We need to remap the whole image
|
||||
# from palette 1 to palette 2. New_positions is
|
||||
# an array of indexes into palette 1. Palette 2 is
|
||||
# palette 1 with any holes removed.
|
||||
mapping_palette = bytearray(new_positions)
|
||||
|
||||
# We're going to leverage the convert mechanism to use the
|
||||
# C code to remap the image from palette 1 to palette 2,
|
||||
# by forcing the source image into 'L' mode and adding a
|
||||
# mapping 'L' mode palette, then converting back to 'L'
|
||||
# sans palette thus converting the image bytes, then
|
||||
# assigning the optimized RGB palette.
|
||||
m_im = im.copy()
|
||||
m_im.mode = 'P'
|
||||
|
||||
# perf reference, 9500x4000 gif, w/~135 colors
|
||||
# 14 sec prepatch, 1 sec postpatch with optimization forced.
|
||||
m_im.palette = ImagePalette.ImagePalette("RGB",
|
||||
palette=mapping_palette*3,
|
||||
size=768)
|
||||
#possibly set palette dirty, then
|
||||
#m_im.putpalette(mapping_palette, 'L') # converts to 'P'
|
||||
# or just force it.
|
||||
# UNDONE -- this is part of the general issue with palettes
|
||||
m_im.im.putpalette(*m_im.palette.getdata())
|
||||
|
||||
mapping_palette = bytearray(new_positions)
|
||||
m_im = m_im.convert('L')
|
||||
|
||||
m_im = im.copy()
|
||||
m_im.mode = 'P'
|
||||
# Internally, we require 768 bytes for a palette.
|
||||
new_palette_bytes = (palette_bytes +
|
||||
(768 - len(palette_bytes)) * b'\x00')
|
||||
m_im.putpalette(new_palette_bytes)
|
||||
m_im.palette = ImagePalette.ImagePalette("RGB",
|
||||
palette=palette_bytes,
|
||||
size=len(palette_bytes))
|
||||
|
||||
m_im.palette = ImagePalette.ImagePalette("RGB",
|
||||
palette=mapping_palette*3,
|
||||
size=768)
|
||||
#possibly set palette dirty, then
|
||||
#m_im.putpalette(mapping_palette, 'L') # converts to 'P'
|
||||
# or just force it.
|
||||
# UNDONE -- this is part of the general issue with palettes
|
||||
m_im.im.putpalette(*m_im.palette.getdata())
|
||||
|
||||
m_im = m_im.convert('L')
|
||||
|
||||
# Internally, we require 768 bytes for a palette.
|
||||
new_palette_bytes = (palette_bytes +
|
||||
(768 - len(palette_bytes)) * b'\x00')
|
||||
m_im.putpalette(new_palette_bytes)
|
||||
m_im.palette = ImagePalette.ImagePalette("RGB",
|
||||
palette=palette_bytes,
|
||||
size=len(palette_bytes))
|
||||
# oh gawd, this is modifying the image in place so I can pass by ref.
|
||||
# REFACTOR SOONEST
|
||||
im.frombytes(m_im.tobytes())
|
||||
|
||||
# oh gawd, this is modifying the image in place so I can pass by ref.
|
||||
# REFACTOR SOONEST
|
||||
im.frombytes(m_im.tobytes())
|
||||
|
||||
if not palette_bytes:
|
||||
palette_bytes = source_palette
|
||||
|
||||
|
@ -696,7 +696,7 @@ def getheader(im, palette=None, info=None):
|
|||
version = b"89a"
|
||||
break
|
||||
else:
|
||||
if im.info.get("version") == "89a":
|
||||
if im.info.get("version") == b"89a":
|
||||
version = b"89a"
|
||||
|
||||
header = [
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#
|
||||
|
||||
from math import pi, log, sin, sqrt
|
||||
from PIL._binary import o8
|
||||
from ._binary import o8
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Stuff to translate curve segments to palette values (derived from
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#
|
||||
|
||||
import re
|
||||
from PIL._binary import o8
|
||||
from ._binary import o8
|
||||
|
||||
|
||||
##
|
||||
|
@ -41,7 +41,7 @@ class GimpPaletteFile(object):
|
|||
if not s:
|
||||
break
|
||||
# skip fields and comment lines
|
||||
if re.match(b"\w+:|#", s):
|
||||
if re.match(br"\w+:|#", s):
|
||||
continue
|
||||
if len(s) > 100:
|
||||
raise SyntaxError("bad palette file")
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from PIL import Image, ImageFile
|
||||
from . import Image, ImageFile
|
||||
|
||||
_handler = None
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from PIL import Image, ImageFile
|
||||
from . import Image, ImageFile
|
||||
|
||||
_handler = None
|
||||
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from PIL import Image, ImageFile, PngImagePlugin, _binary
|
||||
from PIL import Image, ImageFile, PngImagePlugin
|
||||
from PIL._binary import i8
|
||||
import io
|
||||
import os
|
||||
import shutil
|
||||
|
@ -27,8 +28,6 @@ enable_jpeg2k = hasattr(Image.core, 'jp2klib_version')
|
|||
if enable_jpeg2k:
|
||||
from PIL import Jpeg2KImagePlugin
|
||||
|
||||
i8 = _binary.i8
|
||||
|
||||
HEADERSIZE = 8
|
||||
|
||||
|
||||
|
@ -330,8 +329,8 @@ def _save(im, fp, filename):
|
|||
from subprocess import Popen, PIPE, CalledProcessError
|
||||
|
||||
convert_cmd = ["iconutil", "-c", "icns", "-o", filename, iconset]
|
||||
stderr = tempfile.TemporaryFile()
|
||||
convert_proc = Popen(convert_cmd, stdout=PIPE, stderr=stderr)
|
||||
with tempfile.TemporaryFile() as stderr:
|
||||
convert_proc = Popen(convert_cmd, stdout=PIPE, stderr=stderr)
|
||||
|
||||
convert_proc.stdout.close()
|
||||
|
||||
|
|
|
@ -25,7 +25,8 @@
|
|||
import struct
|
||||
from io import BytesIO
|
||||
|
||||
from PIL import Image, ImageFile, BmpImagePlugin, PngImagePlugin, _binary
|
||||
from . import Image, ImageFile, BmpImagePlugin, PngImagePlugin
|
||||
from ._binary import i8, i16le as i16, i32le as i32
|
||||
from math import log, ceil
|
||||
|
||||
__version__ = "0.1"
|
||||
|
@ -33,10 +34,6 @@ __version__ = "0.1"
|
|||
#
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
i8 = _binary.i8
|
||||
i16 = _binary.i16le
|
||||
i32 = _binary.i32le
|
||||
|
||||
_MAGIC = b"\0\0\1\0"
|
||||
|
||||
|
||||
|
@ -44,16 +41,19 @@ def _save(im, fp, filename):
|
|||
fp.write(_MAGIC) # (2+2)
|
||||
sizes = im.encoderinfo.get("sizes",
|
||||
[(16, 16), (24, 24), (32, 32), (48, 48),
|
||||
(64, 64), (128, 128), (255, 255)])
|
||||
(64, 64), (128, 128), (256, 256)])
|
||||
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)
|
||||
sizes = filter(lambda x: False if (x[0] > width or x[1] > height or
|
||||
x[0] > 256 or x[1] > 256) else True,
|
||||
sizes)
|
||||
sizes = list(sizes)
|
||||
fp.write(struct.pack("<H", len(sizes))) # idCount(2)
|
||||
offset = fp.tell() + len(sizes)*16
|
||||
for size in sizes:
|
||||
width, height = size
|
||||
fp.write(struct.pack("B", width)) # bWidth(1)
|
||||
fp.write(struct.pack("B", height)) # bHeight(1)
|
||||
# 0 means 256
|
||||
fp.write(struct.pack("B", width if width < 256 else 0)) # bWidth(1)
|
||||
fp.write(struct.pack("B", height if height < 256 else 0)) # bHeight(1)
|
||||
fp.write(b"\0") # bColorCount(1)
|
||||
fp.write(b"\0") # bReserved(1)
|
||||
fp.write(b"\0\0") # wPlanes(2)
|
||||
|
@ -139,7 +139,7 @@ class IcoFile(object):
|
|||
"""
|
||||
Get a list of all available icon sizes and color depths.
|
||||
"""
|
||||
return set((h['width'], h['height']) for h in self.entry)
|
||||
return {(h['width'], h['height']) for h in self.entry}
|
||||
|
||||
def getimage(self, size, bpp=False):
|
||||
"""
|
||||
|
@ -215,13 +215,13 @@ class IcoFile(object):
|
|||
total_bytes = int((w * im.size[1]) / 8)
|
||||
|
||||
self.buf.seek(and_mask_offset)
|
||||
maskData = self.buf.read(total_bytes)
|
||||
mask_data = self.buf.read(total_bytes)
|
||||
|
||||
# convert raw data to image
|
||||
mask = Image.frombuffer(
|
||||
'1', # 1 bpp
|
||||
im.size, # (w, h)
|
||||
maskData, # source chars
|
||||
mask_data, # source chars
|
||||
'raw', # raw decoder
|
||||
('1;I', int(w/8), -1) # 1bpp inverted, padded, reversed
|
||||
)
|
||||
|
@ -278,6 +278,7 @@ class IcoImageFile(ImageFile.ImageFile):
|
|||
#
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
|
||||
Image.register_open(IcoImageFile.format, IcoImageFile, _accept)
|
||||
Image.register_save(IcoImageFile.format, _save)
|
||||
Image.register_extension(IcoImageFile.format, ".ico")
|
||||
|
|
|
@ -27,8 +27,8 @@
|
|||
|
||||
|
||||
import re
|
||||
from PIL import Image, ImageFile, ImagePalette
|
||||
from PIL._binary import i8
|
||||
from . import Image, ImageFile, ImagePalette
|
||||
from ._binary import i8
|
||||
|
||||
__version__ = "0.7"
|
||||
|
||||
|
|
176
PIL/Image.py
176
PIL/Image.py
|
@ -26,7 +26,7 @@
|
|||
|
||||
from __future__ import print_function
|
||||
|
||||
from PIL import VERSION, PILLOW_VERSION, _plugins
|
||||
from . import VERSION, PILLOW_VERSION, _plugins
|
||||
|
||||
import logging
|
||||
import warnings
|
||||
|
@ -46,7 +46,7 @@ class _imaging_not_installed(object):
|
|||
|
||||
|
||||
# Limit to around a quarter gigabyte for a 24 bit (3 bpp) image
|
||||
MAX_IMAGE_PIXELS = int(1024 * 1024 * 1024 / 4 / 3)
|
||||
MAX_IMAGE_PIXELS = int(1024 * 1024 * 1024 // 4 // 3)
|
||||
|
||||
try:
|
||||
# give Tk a chance to set up the environment, in case we're
|
||||
|
@ -64,10 +64,10 @@ try:
|
|||
# import Image and use the Image.core variable instead.
|
||||
# Also note that Image.core is not a publicly documented interface,
|
||||
# and should be considered private and subject to change.
|
||||
from PIL import _imaging as core
|
||||
from . import _imaging as core
|
||||
if PILLOW_VERSION != getattr(core, 'PILLOW_VERSION', None):
|
||||
raise ImportError("The _imaging extension was built for another "
|
||||
" version of Pillow or PIL")
|
||||
"version of Pillow or PIL")
|
||||
|
||||
except ImportError as v:
|
||||
core = _imaging_not_installed()
|
||||
|
@ -109,11 +109,9 @@ except ImportError:
|
|||
import __builtin__
|
||||
builtins = __builtin__
|
||||
|
||||
from PIL import ImageMode
|
||||
from PIL._binary import i8
|
||||
from PIL._util import isPath
|
||||
from PIL._util import isStringType
|
||||
from PIL._util import deferred_error
|
||||
from . import ImageMode
|
||||
from ._binary import i8
|
||||
from ._util import isPath, isStringType, deferred_error
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
@ -355,23 +353,23 @@ def preinit():
|
|||
return
|
||||
|
||||
try:
|
||||
from PIL import BmpImagePlugin
|
||||
from . import BmpImagePlugin
|
||||
except ImportError:
|
||||
pass
|
||||
try:
|
||||
from PIL import GifImagePlugin
|
||||
from . import GifImagePlugin
|
||||
except ImportError:
|
||||
pass
|
||||
try:
|
||||
from PIL import JpegImagePlugin
|
||||
from . import JpegImagePlugin
|
||||
except ImportError:
|
||||
pass
|
||||
try:
|
||||
from PIL import PpmImagePlugin
|
||||
from . import PpmImagePlugin
|
||||
except ImportError:
|
||||
pass
|
||||
try:
|
||||
from PIL import PngImagePlugin
|
||||
from . import PngImagePlugin
|
||||
except ImportError:
|
||||
pass
|
||||
# try:
|
||||
|
@ -525,13 +523,11 @@ class Image(object):
|
|||
if self.palette:
|
||||
new.palette = self.palette.copy()
|
||||
if im.mode == "P" and not new.palette:
|
||||
from PIL import ImagePalette
|
||||
from . import ImagePalette
|
||||
new.palette = ImagePalette.ImagePalette()
|
||||
new.info = self.info.copy()
|
||||
return new
|
||||
|
||||
_makeself = _new # compatibility
|
||||
|
||||
# Context Manager Support
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
@ -777,7 +773,7 @@ class Image(object):
|
|||
if HAS_CFFI and USE_CFFI_ACCESS:
|
||||
if self.pyaccess:
|
||||
return self.pyaccess
|
||||
from PIL import PyAccess
|
||||
from . import PyAccess
|
||||
self.pyaccess = PyAccess.new(self, self.readonly)
|
||||
if self.pyaccess:
|
||||
return self.pyaccess
|
||||
|
@ -879,7 +875,7 @@ class Image(object):
|
|||
trns_im = Image()._new(core.new(self.mode, (1, 1)))
|
||||
if self.mode == 'P':
|
||||
trns_im.putpalette(self.palette)
|
||||
if type(t) == tuple:
|
||||
if isinstance(t, tuple):
|
||||
try:
|
||||
t = trns_im.palette.getcolor(t)
|
||||
except:
|
||||
|
@ -910,7 +906,7 @@ class Image(object):
|
|||
if mode == "P" and palette == ADAPTIVE:
|
||||
im = self.im.quantize(colors)
|
||||
new = self._new(im)
|
||||
from PIL import ImagePalette
|
||||
from . import ImagePalette
|
||||
new.palette = ImagePalette.raw("RGB", new.im.getpalette("RGB"))
|
||||
if delete_trns:
|
||||
# This could possibly happen if we requantize to fewer colors.
|
||||
|
@ -997,7 +993,7 @@ class Image(object):
|
|||
"only RGB or L mode images can be quantized to a palette"
|
||||
)
|
||||
im = self.im.convert("P", 1, palette.im)
|
||||
return self._makeself(im)
|
||||
return self._new(im)
|
||||
|
||||
return self._new(self.im.quantize(colors, method, kmeans))
|
||||
|
||||
|
@ -1020,7 +1016,7 @@ class Image(object):
|
|||
4-tuple defining the left, upper, right, and lower pixel
|
||||
coordinate.
|
||||
|
||||
Note: Prior to Pillow 3.4.0, this was a lazy operation.
|
||||
Note: Prior to Pillow 3.4.0, this was a lazy operation.
|
||||
|
||||
:param box: The crop rectangle, as a (left, upper, right, lower)-tuple.
|
||||
:rtype: :py:class:`~PIL.Image.Image`
|
||||
|
@ -1307,8 +1303,7 @@ class Image(object):
|
|||
box = None
|
||||
|
||||
if box is None:
|
||||
# cover all of self
|
||||
box = (0, 0) + self.size
|
||||
box = (0, 0)
|
||||
|
||||
if len(box) == 2:
|
||||
# upper left corner given; get size from image or mask
|
||||
|
@ -1321,10 +1316,10 @@ class Image(object):
|
|||
raise ValueError(
|
||||
"cannot determine region size; use 4-item box"
|
||||
)
|
||||
box = box + (box[0]+size[0], box[1]+size[1])
|
||||
box += (box[0]+size[0], box[1]+size[1])
|
||||
|
||||
if isStringType(im):
|
||||
from PIL import ImageColor
|
||||
from . import ImageColor
|
||||
im = ImageColor.getcolor(im, self.mode)
|
||||
|
||||
elif isImageType(im):
|
||||
|
@ -1471,7 +1466,7 @@ class Image(object):
|
|||
|
||||
:param data: A palette sequence (either a list or a string).
|
||||
"""
|
||||
from PIL import ImagePalette
|
||||
from . import ImagePalette
|
||||
|
||||
if self.mode not in ("L", "P"):
|
||||
raise ValueError("illegal image mode")
|
||||
|
@ -1545,7 +1540,7 @@ class Image(object):
|
|||
|
||||
size = tuple(size)
|
||||
if self.size == size:
|
||||
return self._new(self.im)
|
||||
return self.copy()
|
||||
|
||||
if self.mode in ("1", "P"):
|
||||
resample = NEAREST
|
||||
|
@ -1558,7 +1553,7 @@ class Image(object):
|
|||
|
||||
return self._new(self.im.resize(size, resample))
|
||||
|
||||
def rotate(self, angle, resample=NEAREST, expand=0):
|
||||
def rotate(self, angle, resample=NEAREST, expand=0, center=None, translate=None):
|
||||
"""
|
||||
Returns a rotated copy of this image. This method returns a
|
||||
copy of this image, rotated the given number of degrees counter
|
||||
|
@ -1575,48 +1570,81 @@ class Image(object):
|
|||
:param expand: Optional expansion flag. If true, expands the output
|
||||
image to make it large enough to hold the entire rotated image.
|
||||
If false or omitted, make the output image the same size as the
|
||||
input image.
|
||||
input image. Note that the expand flag assumes rotation around
|
||||
the center and no translation.
|
||||
:param center: Optional center of rotation (a 2-tuple). Origin is
|
||||
the upper left corner. Default is the center of the image.
|
||||
:param translate: An optional post-rotate translation (a 2-tuple).
|
||||
:returns: An :py:class:`~PIL.Image.Image` object.
|
||||
"""
|
||||
|
||||
angle = angle % 360.0
|
||||
|
||||
# Fast paths regardless of filter
|
||||
if angle == 0:
|
||||
return self.copy()
|
||||
if angle == 180:
|
||||
return self.transpose(ROTATE_180)
|
||||
if angle == 90 and expand:
|
||||
return self.transpose(ROTATE_90)
|
||||
if angle == 270 and expand:
|
||||
return self.transpose(ROTATE_270)
|
||||
# Fast paths regardless of filter, as long as we're not
|
||||
# translating or changing the center.
|
||||
if not (center or translate):
|
||||
if angle == 0:
|
||||
return self.copy()
|
||||
if angle == 180:
|
||||
return self.transpose(ROTATE_180)
|
||||
if angle == 90 and expand:
|
||||
return self.transpose(ROTATE_90)
|
||||
if angle == 270 and expand:
|
||||
return self.transpose(ROTATE_270)
|
||||
|
||||
# Calculate the affine matrix. Note that this is the reverse
|
||||
# transformation (from destination image to source) because we
|
||||
# want to interpolate the (discrete) destination pixel from
|
||||
# the local area around the (floating) source pixel.
|
||||
|
||||
# The matrix we actually want (note that it operates from the right):
|
||||
# (1, 0, tx) (1, 0, cx) ( cos a, sin a, 0) (1, 0, -cx)
|
||||
# (0, 1, ty) * (0, 1, cy) * (-sin a, cos a, 0) * (0, 1, -cy)
|
||||
# (0, 0, 1) (0, 0, 1) ( 0, 0, 1) (0, 0, 1)
|
||||
|
||||
# The reverse matrix is thus:
|
||||
# (1, 0, cx) ( cos -a, sin -a, 0) (1, 0, -cx) (1, 0, -tx)
|
||||
# (0, 1, cy) * (-sin -a, cos -a, 0) * (0, 1, -cy) * (0, 1, -ty)
|
||||
# (0, 0, 1) ( 0, 0, 1) (0, 0, 1) (0, 0, 1)
|
||||
|
||||
# In any case, the final translation may be updated at the end to
|
||||
# compensate for the expand flag.
|
||||
|
||||
w, h = self.size
|
||||
|
||||
if translate is None:
|
||||
translate = [0, 0]
|
||||
if center is None:
|
||||
center = [w / 2.0, h / 2.0]
|
||||
|
||||
angle = - math.radians(angle)
|
||||
matrix = [
|
||||
round(math.cos(angle), 15), round(math.sin(angle), 15), 0.0,
|
||||
round(-math.sin(angle), 15), round(math.cos(angle), 15), 0.0
|
||||
]
|
||||
|
||||
def transform(x, y, matrix=matrix):
|
||||
]
|
||||
def transform(x, y, matrix):
|
||||
(a, b, c, d, e, f) = matrix
|
||||
return a*x + b*y + c, d*x + e*y + f
|
||||
matrix[2], matrix[5] = transform(-center[0] - translate[0], -center[1] - translate[1], matrix)
|
||||
matrix[2] += center[0]
|
||||
matrix[5] += center[1]
|
||||
|
||||
w, h = self.size
|
||||
if expand:
|
||||
# calculate output size
|
||||
xx = []
|
||||
yy = []
|
||||
for x, y in ((0, 0), (w, 0), (w, h), (0, h)):
|
||||
x, y = transform(x, y)
|
||||
x, y = transform(x, y, matrix)
|
||||
xx.append(x)
|
||||
yy.append(y)
|
||||
w = int(math.ceil(max(xx)) - math.floor(min(xx)))
|
||||
h = int(math.ceil(max(yy)) - math.floor(min(yy)))
|
||||
nw = int(math.ceil(max(xx)) - math.floor(min(xx)))
|
||||
nh = int(math.ceil(max(yy)) - math.floor(min(yy)))
|
||||
|
||||
# adjust center
|
||||
x, y = transform(w / 2.0, h / 2.0)
|
||||
matrix[2] = self.size[0] / 2.0 - x
|
||||
matrix[5] = self.size[1] / 2.0 - y
|
||||
# We multiply a translation matrix from the right. Because of its
|
||||
# special form, this is the same as taking the image of the translation vector
|
||||
# as new translation vector.
|
||||
matrix[2], matrix[5] = transform(-(nw - w) / 2.0, -(nh - h) / 2.0, matrix)
|
||||
w, h = nw, nh
|
||||
|
||||
return self.transform((w, h), AFFINE, matrix, resample)
|
||||
|
||||
|
@ -1660,7 +1688,7 @@ class Image(object):
|
|||
if isinstance(fp, Path):
|
||||
filename = str(fp)
|
||||
open_fp = True
|
||||
elif hasattr(fp, "name") and isPath(fp.name):
|
||||
if not filename and hasattr(fp, "name") and isPath(fp.name):
|
||||
# only set the name for metadata purposes
|
||||
filename = fp.name
|
||||
|
||||
|
@ -1947,14 +1975,14 @@ class Image(object):
|
|||
|
||||
def toqimage(self):
|
||||
"""Returns a QImage copy of this image"""
|
||||
from PIL import ImageQt
|
||||
from . import ImageQt
|
||||
if not ImageQt.qt_is_installed:
|
||||
raise ImportError("Qt bindings are not installed")
|
||||
return ImageQt.toqimage(self)
|
||||
|
||||
def toqpixmap(self):
|
||||
"""Returns a QPixmap copy of this image"""
|
||||
from PIL import ImageQt
|
||||
from . import ImageQt
|
||||
if not ImageQt.qt_is_installed:
|
||||
raise ImportError("Qt bindings are not installed")
|
||||
return ImageQt.toqpixmap(self)
|
||||
|
@ -1985,6 +2013,22 @@ def _wedge():
|
|||
|
||||
return Image()._new(core.wedge("L"))
|
||||
|
||||
def _check_size(size):
|
||||
"""
|
||||
Common check to enforce type and sanity check on size tuples
|
||||
|
||||
:param size: Should be a 2 tuple of (width, height)
|
||||
:returns: True, or raises a ValueError
|
||||
"""
|
||||
|
||||
if not isinstance(size, (list, tuple)):
|
||||
raise ValueError("Size must be a tuple")
|
||||
if len(size) != 2:
|
||||
raise ValueError("Size must be a tuple of length 2")
|
||||
if size[0] < 0 or size[1] < 0:
|
||||
raise ValueError("Width and Height must be => 0")
|
||||
|
||||
return True
|
||||
|
||||
def new(mode, size, color=0):
|
||||
"""
|
||||
|
@ -2002,6 +2046,8 @@ def new(mode, size, color=0):
|
|||
:returns: An :py:class:`~PIL.Image.Image` object.
|
||||
"""
|
||||
|
||||
_check_size(size)
|
||||
|
||||
if color is None:
|
||||
# don't initialize
|
||||
return Image()._new(core.new(mode, size))
|
||||
|
@ -2009,7 +2055,7 @@ def new(mode, size, color=0):
|
|||
if isStringType(color):
|
||||
# css3-style specifier
|
||||
|
||||
from PIL import ImageColor
|
||||
from . import ImageColor
|
||||
color = ImageColor.getcolor(color, mode)
|
||||
|
||||
return Image()._new(core.fill(mode, size, color))
|
||||
|
@ -2039,6 +2085,8 @@ def frombytes(mode, size, data, decoder_name="raw", *args):
|
|||
:returns: An :py:class:`~PIL.Image.Image` object.
|
||||
"""
|
||||
|
||||
_check_size(size)
|
||||
|
||||
# may pass tuple instead of argument list
|
||||
if len(args) == 1 and isinstance(args[0], tuple):
|
||||
args = args[0]
|
||||
|
@ -2091,6 +2139,8 @@ def frombuffer(mode, size, data, decoder_name="raw", *args):
|
|||
.. versionadded:: 1.1.4
|
||||
"""
|
||||
|
||||
_check_size(size)
|
||||
|
||||
# may pass tuple instead of argument list
|
||||
if len(args) == 1 and isinstance(args[0], tuple):
|
||||
args = args[0]
|
||||
|
@ -2142,7 +2192,7 @@ def fromarray(obj, mode=None):
|
|||
typekey = (1, 1) + shape[2:], arr['typestr']
|
||||
mode, rawmode = _fromarray_typemap[typekey]
|
||||
except KeyError:
|
||||
# print typekey
|
||||
# print(typekey)
|
||||
raise TypeError("Cannot handle this data type")
|
||||
else:
|
||||
rawmode = mode
|
||||
|
@ -2167,7 +2217,7 @@ def fromarray(obj, mode=None):
|
|||
|
||||
def fromqimage(im):
|
||||
"""Creates an image instance from a QImage image"""
|
||||
from PIL import ImageQt
|
||||
from . import ImageQt
|
||||
if not ImageQt.qt_is_installed:
|
||||
raise ImportError("Qt bindings are not installed")
|
||||
return ImageQt.fromqimage(im)
|
||||
|
@ -2175,7 +2225,7 @@ def fromqimage(im):
|
|||
|
||||
def fromqpixmap(im):
|
||||
"""Creates an image instance from a QPixmap image"""
|
||||
from PIL import ImageQt
|
||||
from . import ImageQt
|
||||
if not ImageQt.qt_is_installed:
|
||||
raise ImportError("Qt bindings are not installed")
|
||||
return ImageQt.fromqpixmap(im)
|
||||
|
@ -2460,6 +2510,16 @@ def register_extension(id, extension):
|
|||
EXTENSION[extension.lower()] = id.upper()
|
||||
|
||||
|
||||
def registered_extensions():
|
||||
"""
|
||||
Returns a dictionary containing all file extensions belonging
|
||||
to registered plugins
|
||||
"""
|
||||
if not bool(EXTENSION):
|
||||
init()
|
||||
return EXTENSION
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Simple display support. User code may override this.
|
||||
|
||||
|
@ -2469,7 +2529,7 @@ def _show(image, **options):
|
|||
|
||||
|
||||
def _showxv(image, title=None, **options):
|
||||
from PIL import ImageShow
|
||||
from . import ImageShow
|
||||
ImageShow.show(image, title, **options)
|
||||
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from PIL import Image
|
||||
from . import Image
|
||||
|
||||
|
||||
def constant(image, value):
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from PIL import Image
|
||||
from . import Image
|
||||
import re
|
||||
|
||||
|
||||
|
|
|
@ -33,8 +33,8 @@
|
|||
import numbers
|
||||
import warnings
|
||||
|
||||
from PIL import Image, ImageColor
|
||||
from PIL._util import isStringType
|
||||
from . import Image, ImageColor
|
||||
from ._util import isStringType
|
||||
|
||||
"""
|
||||
A simple 2D drawing interface for PIL images.
|
||||
|
@ -105,7 +105,7 @@ class ImageDraw(object):
|
|||
"""Get the current default font."""
|
||||
if not self.font:
|
||||
# FIXME: should add a font repository
|
||||
from PIL import ImageFont
|
||||
from . import ImageFont
|
||||
self.font = ImageFont.load_default()
|
||||
return self.font
|
||||
|
||||
|
@ -208,12 +208,12 @@ class ImageDraw(object):
|
|||
|
||||
def _multiline_check(self, text):
|
||||
"""Draw text."""
|
||||
split_character = "\n" if isinstance(text, type("")) else b"\n"
|
||||
split_character = "\n" if isinstance(text, str) else b"\n"
|
||||
|
||||
return split_character in text
|
||||
|
||||
def _multiline_split(self, text):
|
||||
split_character = "\n" if isinstance(text, type("")) else b"\n"
|
||||
split_character = "\n" if isinstance(text, str) else b"\n"
|
||||
|
||||
return text.split(split_character)
|
||||
|
||||
|
@ -319,11 +319,11 @@ def getdraw(im=None, hints=None):
|
|||
handler = None
|
||||
if not hints or "nicest" in hints:
|
||||
try:
|
||||
from PIL import _imagingagg as handler
|
||||
from . import _imagingagg as handler
|
||||
except ImportError:
|
||||
pass
|
||||
if handler is None:
|
||||
from PIL import ImageDraw2 as handler
|
||||
from . import ImageDraw2 as handler
|
||||
if im:
|
||||
im = handler.Draw(im)
|
||||
return im, handler
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from PIL import Image, ImageColor, ImageDraw, ImageFont, ImagePath
|
||||
from . import Image, ImageColor, ImageDraw, ImageFont, ImagePath
|
||||
|
||||
|
||||
class Pen(object):
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from PIL import Image, ImageFilter, ImageStat
|
||||
from . import Image, ImageFilter, ImageStat
|
||||
|
||||
|
||||
class _Enhance(object):
|
||||
|
|
|
@ -27,8 +27,8 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from PIL import Image
|
||||
from PIL._util import isPath
|
||||
from . import Image
|
||||
from ._util import isPath
|
||||
import io
|
||||
import os
|
||||
import sys
|
||||
|
@ -150,15 +150,16 @@ class ImageFile(Image.Image):
|
|||
|
||||
if use_mmap:
|
||||
# try memory mapping
|
||||
d, e, o, a = self.tile[0]
|
||||
if d == "raw" and a[0] == self.mode and a[0] in Image._MAPMODES:
|
||||
decoder_name, extents, offset, args = self.tile[0]
|
||||
if decoder_name == "raw" and len(args) >= 3 and args[0] == self.mode \
|
||||
and args[0] in Image._MAPMODES:
|
||||
try:
|
||||
if hasattr(Image.core, "map"):
|
||||
# use built-in mapper
|
||||
# use built-in mapper WIN32 only
|
||||
self.map = Image.core.map(self.filename)
|
||||
self.map.seek(o)
|
||||
self.map.seek(offset)
|
||||
self.im = self.map.readimage(
|
||||
self.mode, self.size, a[1], a[2]
|
||||
self.mode, self.size, args[1], args[2]
|
||||
)
|
||||
else:
|
||||
# use mmap, if possible
|
||||
|
@ -167,7 +168,7 @@ class ImageFile(Image.Image):
|
|||
size = os.path.getsize(self.filename)
|
||||
self.map = mmap.mmap(fp.fileno(), size, access=mmap.ACCESS_READ)
|
||||
self.im = Image.core.map_buffer(
|
||||
self.map, self.size, d, e, o, a
|
||||
self.map, self.size, decoder_name, extents, offset, args
|
||||
)
|
||||
readonly = 1
|
||||
# After trashing self.im, we might need to reload the palette data.
|
||||
|
@ -210,7 +211,7 @@ class ImageFile(Image.Image):
|
|||
else:
|
||||
raise IOError("image file is truncated")
|
||||
|
||||
if not s and not decoder.handles_eof: # truncated jpeg
|
||||
if not s: # truncated jpeg
|
||||
self.tile = []
|
||||
|
||||
# JpegDecode needs to clean things up here either way
|
||||
|
@ -242,12 +243,6 @@ class ImageFile(Image.Image):
|
|||
# still raised if decoder fails to return anything
|
||||
raise_ioerror(err_code)
|
||||
|
||||
# post processing
|
||||
if hasattr(self, "tile_post_rotate"):
|
||||
# FIXME: This is a hack to handle rotated PCD's
|
||||
self.im = self.im.rotate(self.tile_post_rotate)
|
||||
self.size = self.im.size
|
||||
|
||||
self.load_end()
|
||||
|
||||
return Image.Image.load(self)
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from PIL import Image
|
||||
from PIL._util import isDirectory, isPath
|
||||
from . import Image
|
||||
from ._util import isDirectory, isPath
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
@ -37,7 +37,7 @@ class _imagingft_not_installed(object):
|
|||
raise ImportError("The _imagingft C module is not installed")
|
||||
|
||||
try:
|
||||
from PIL import _imagingft as core
|
||||
from . import _imagingft as core
|
||||
except ImportError:
|
||||
core = _imagingft_not_installed()
|
||||
|
||||
|
@ -62,23 +62,22 @@ class ImageFont(object):
|
|||
|
||||
def _load_pilfont(self, filename):
|
||||
|
||||
fp = open(filename, "rb")
|
||||
|
||||
for ext in (".png", ".gif", ".pbm"):
|
||||
try:
|
||||
fullname = os.path.splitext(filename)[0] + ext
|
||||
image = Image.open(fullname)
|
||||
except:
|
||||
pass
|
||||
with open(filename, "rb") as fp:
|
||||
for ext in (".png", ".gif", ".pbm"):
|
||||
try:
|
||||
fullname = os.path.splitext(filename)[0] + ext
|
||||
image = Image.open(fullname)
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
if image and image.mode in ("1", "L"):
|
||||
break
|
||||
else:
|
||||
if image and image.mode in ("1", "L"):
|
||||
break
|
||||
else:
|
||||
raise IOError("cannot find glyph data file")
|
||||
raise IOError("cannot find glyph data file")
|
||||
|
||||
self.file = fullname
|
||||
self.file = fullname
|
||||
|
||||
return self._load_pilfont_data(fp, image)
|
||||
return self._load_pilfont_data(fp, image)
|
||||
|
||||
def _load_pilfont_data(self, file, image):
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from PIL import Image
|
||||
from . import Image
|
||||
|
||||
import sys
|
||||
if sys.platform not in ["win32", "darwin"]:
|
||||
|
@ -41,7 +41,7 @@ def grab(bbox=None):
|
|||
size, data = grabber()
|
||||
im = Image.frombytes(
|
||||
"RGB", size, data,
|
||||
# RGB, 32-bit line padding, origo in lower left corner
|
||||
# RGB, 32-bit line padding, origin lower left corner
|
||||
"raw", "BGR", (size[0]*3 + 3) & -4, -1
|
||||
)
|
||||
if bbox:
|
||||
|
@ -75,7 +75,7 @@ def grabclipboard():
|
|||
debug = 0 # temporary interface
|
||||
data = Image.core.grabclipboard(debug)
|
||||
if isinstance(data, bytes):
|
||||
from PIL import BmpImagePlugin
|
||||
from . import BmpImagePlugin
|
||||
import io
|
||||
return BmpImagePlugin.DibImageFile(io.BytesIO(data))
|
||||
return data
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from PIL import Image
|
||||
from PIL import _imagingmath
|
||||
from . import Image, _imagingmath
|
||||
|
||||
try:
|
||||
import builtins
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#
|
||||
|
||||
# mode descriptor cache
|
||||
_modes = {}
|
||||
_modes = None
|
||||
|
||||
|
||||
class ModeDescriptor(object):
|
||||
|
@ -32,19 +32,24 @@ class ModeDescriptor(object):
|
|||
|
||||
def getmode(mode):
|
||||
"""Gets a mode descriptor for the given mode."""
|
||||
global _modes
|
||||
if not _modes:
|
||||
# initialize mode cache
|
||||
from PIL import Image
|
||||
|
||||
from . import Image
|
||||
modes = {}
|
||||
# core modes
|
||||
for m, (basemode, basetype, bands) in Image._MODEINFO.items():
|
||||
_modes[m] = ModeDescriptor(m, bands, basemode, basetype)
|
||||
modes[m] = ModeDescriptor(m, bands, basemode, basetype)
|
||||
# extra experimental modes
|
||||
_modes["RGBa"] = ModeDescriptor("RGBa", ("R", "G", "B", "a"), "RGB", "L")
|
||||
_modes["LA"] = ModeDescriptor("LA", ("L", "A"), "L", "L")
|
||||
_modes["La"] = ModeDescriptor("La", ("L", "a"), "L", "L")
|
||||
_modes["PA"] = ModeDescriptor("PA", ("P", "A"), "RGB", "L")
|
||||
modes["RGBa"] = ModeDescriptor("RGBa", ("R", "G", "B", "a"), "RGB", "L")
|
||||
modes["LA"] = ModeDescriptor("LA", ("L", "A"), "L", "L")
|
||||
modes["La"] = ModeDescriptor("La", ("L", "a"), "L", "L")
|
||||
modes["PA"] = ModeDescriptor("PA", ("P", "A"), "RGB", "L")
|
||||
# mapping modes
|
||||
_modes["I;16"] = ModeDescriptor("I;16", "I", "L", "L")
|
||||
_modes["I;16L"] = ModeDescriptor("I;16L", "I", "L", "L")
|
||||
_modes["I;16B"] = ModeDescriptor("I;16B", "I", "L", "L")
|
||||
modes["I;16"] = ModeDescriptor("I;16", "I", "L", "L")
|
||||
modes["I;16L"] = ModeDescriptor("I;16L", "I", "L", "L")
|
||||
modes["I;16B"] = ModeDescriptor("I;16B", "I", "L", "L")
|
||||
# set global mode cache atomically
|
||||
_modes = modes
|
||||
return _modes[mode]
|
||||
|
|
|
@ -5,8 +5,9 @@
|
|||
#
|
||||
# Copyright (c) 2014 Dov Grobgeld <dov.grobgeld@gmail.com>
|
||||
|
||||
from PIL import Image
|
||||
from PIL import _imagingmorph
|
||||
from __future__ import print_function
|
||||
|
||||
from . import Image, _imagingmorph
|
||||
import re
|
||||
|
||||
LUT_SIZE = 1 << 9
|
||||
|
@ -78,7 +79,7 @@ class LutBuilder(object):
|
|||
def build_default_lut(self):
|
||||
symbols = [0, 1]
|
||||
m = 1 << 4 # pos of current pixel
|
||||
self.lut = bytearray([symbols[(i & m) > 0] for i in range(LUT_SIZE)])
|
||||
self.lut = bytearray(symbols[(i & m) > 0] for i in range(LUT_SIZE))
|
||||
|
||||
def get_lut(self):
|
||||
return self.lut
|
||||
|
@ -88,7 +89,7 @@ class LutBuilder(object):
|
|||
string permuted according to the permutation list.
|
||||
"""
|
||||
assert(len(permutation) == 9)
|
||||
return ''.join([pattern[p] for p in permutation])
|
||||
return ''.join(pattern[p] for p in permutation)
|
||||
|
||||
def _pattern_permute(self, basic_pattern, options, basic_result):
|
||||
"""pattern_permute takes a basic pattern and its result and clones
|
||||
|
@ -152,14 +153,14 @@ class LutBuilder(object):
|
|||
|
||||
# # Debugging
|
||||
# for p,r in patterns:
|
||||
# print p,r
|
||||
# print '--'
|
||||
# print(p,r)
|
||||
# print('--')
|
||||
|
||||
# compile the patterns into regular expressions for speed
|
||||
for i in range(len(patterns)):
|
||||
p = patterns[i][0].replace('.', 'X').replace('X', '[01]')
|
||||
for i, pattern in enumerate(patterns):
|
||||
p = pattern[0].replace('.', 'X').replace('X', '[01]')
|
||||
p = re.compile(p)
|
||||
patterns[i] = (p, patterns[i][1])
|
||||
patterns[i] = (p, pattern[1])
|
||||
|
||||
# Step through table and find patterns that match.
|
||||
# Note that all the patterns are searched. The last one
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from PIL import Image
|
||||
from PIL._util import isStringType
|
||||
from . import Image
|
||||
from ._util import isStringType
|
||||
import operator
|
||||
import functools
|
||||
|
||||
|
@ -39,7 +39,7 @@ def _border(border):
|
|||
|
||||
def _color(color, mode):
|
||||
if isStringType(color):
|
||||
from PIL import ImageColor
|
||||
from . import ImageColor
|
||||
color = ImageColor.getcolor(color, mode)
|
||||
return color
|
||||
|
||||
|
@ -206,7 +206,8 @@ def deform(image, deformer, resample=Image.BILINEAR):
|
|||
:param image: The image to deform.
|
||||
:param deformer: A deformer object. Any object that implements a
|
||||
**getmesh** method can be used.
|
||||
:param resample: What resampling filter to use.
|
||||
:param resample: An optional resampling filter. Same values possible as
|
||||
in the PIL.Image.transform function.
|
||||
:return: An image.
|
||||
"""
|
||||
return image.transform(
|
||||
|
|
|
@ -17,10 +17,7 @@
|
|||
#
|
||||
|
||||
import array
|
||||
from PIL import ImageColor
|
||||
from PIL import GimpPaletteFile
|
||||
from PIL import GimpGradientFile
|
||||
from PIL import PaletteFile
|
||||
from . import ImageColor, GimpPaletteFile, GimpGradientFile, PaletteFile
|
||||
|
||||
|
||||
class ImagePalette(object):
|
||||
|
@ -197,23 +194,23 @@ def load(filename):
|
|||
|
||||
# FIXME: supports GIMP gradients only
|
||||
|
||||
fp = open(filename, "rb")
|
||||
with open(filename, "rb") as fp:
|
||||
|
||||
for paletteHandler in [
|
||||
GimpPaletteFile.GimpPaletteFile,
|
||||
GimpGradientFile.GimpGradientFile,
|
||||
PaletteFile.PaletteFile
|
||||
]:
|
||||
try:
|
||||
fp.seek(0)
|
||||
lut = paletteHandler(fp).getpalette()
|
||||
if lut:
|
||||
break
|
||||
except (SyntaxError, ValueError):
|
||||
# import traceback
|
||||
# traceback.print_exc()
|
||||
pass
|
||||
else:
|
||||
raise IOError("cannot load palette")
|
||||
for paletteHandler in [
|
||||
GimpPaletteFile.GimpPaletteFile,
|
||||
GimpGradientFile.GimpGradientFile,
|
||||
PaletteFile.PaletteFile
|
||||
]:
|
||||
try:
|
||||
fp.seek(0)
|
||||
lut = paletteHandler(fp).getpalette()
|
||||
if lut:
|
||||
break
|
||||
except (SyntaxError, ValueError):
|
||||
# import traceback
|
||||
# traceback.print_exc()
|
||||
pass
|
||||
else:
|
||||
raise IOError("cannot load palette")
|
||||
|
||||
return lut # data, rawmode
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from PIL import Image
|
||||
from . import Image
|
||||
|
||||
|
||||
# the Python class below is overridden by the C implementation.
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from PIL import Image
|
||||
from PIL._util import isPath
|
||||
from . import Image
|
||||
from ._util import isPath
|
||||
from io import BytesIO
|
||||
|
||||
qt_is_installed = True
|
||||
|
@ -157,7 +157,6 @@ def _toqclass_helper(im):
|
|||
else:
|
||||
raise ValueError("unsupported image mode %r" % im.mode)
|
||||
|
||||
# must keep a reference, or Qt will crash!
|
||||
__data = data or align8to32(im.tobytes(), im.size[0], im.mode)
|
||||
return {
|
||||
'data': __data, 'im': im, 'format': format, 'colortable': colortable
|
||||
|
@ -175,8 +174,13 @@ if qt_is_installed:
|
|||
string or a PyQt string object).
|
||||
"""
|
||||
im_data = _toqclass_helper(im)
|
||||
# must keep a reference, or Qt will crash!
|
||||
# All QImage constructors that take data operate on an existing
|
||||
# buffer, so this buffer has to hang on for the life of the image.
|
||||
# Fixes https://github.com/python-pillow/Pillow/issues/1370
|
||||
self.__data = im_data['data']
|
||||
QImage.__init__(self,
|
||||
im_data['data'], im_data['im'].size[0],
|
||||
self.__data, im_data['im'].size[0],
|
||||
im_data['im'].size[1], im_data['format'])
|
||||
if im_data['colortable']:
|
||||
self.setColorTable(im_data['colortable'])
|
||||
|
|
|
@ -32,7 +32,14 @@ except ImportError:
|
|||
tkinter = Tkinter
|
||||
del Tkinter
|
||||
|
||||
from PIL import Image
|
||||
# required for pypy, which always has cffi installed
|
||||
try:
|
||||
from cffi import FFI
|
||||
ffi = FFI()
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
from . import Image
|
||||
from io import BytesIO
|
||||
|
||||
|
||||
|
@ -182,9 +189,15 @@ class PhotoImage(object):
|
|||
except tkinter.TclError:
|
||||
# activate Tkinter hook
|
||||
try:
|
||||
from PIL import _imagingtk
|
||||
from . import _imagingtk
|
||||
try:
|
||||
_imagingtk.tkinit(tk.interpaddr(), 1)
|
||||
if hasattr(tk, 'interp'):
|
||||
# Pypy is using a ffi cdata element
|
||||
# (Pdb) self.tk.interp
|
||||
# <cdata 'Tcl_Interp *' 0x3061b50>
|
||||
_imagingtk.tkinit(int(ffi.cast("uintptr_t", tk.interp)), 1)
|
||||
else:
|
||||
_imagingtk.tkinit(tk.interpaddr(), 1)
|
||||
except AttributeError:
|
||||
_imagingtk.tkinit(id(tk), 0)
|
||||
tk.call("PyImagingPhoto", self.__photo, block.id)
|
||||
|
@ -264,6 +277,8 @@ class BitmapImage(object):
|
|||
|
||||
|
||||
def getimage(photo):
|
||||
""" This function is unimplemented """
|
||||
|
||||
"""Copies the contents of a PhotoImage to a PIL image memory."""
|
||||
photo.tk.call("PyImagingPhotoGet", photo)
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from PIL import Image
|
||||
from . import Image
|
||||
|
||||
|
||||
class Transform(Image.ImageTransformHandler):
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from PIL import Image
|
||||
from . import Image
|
||||
|
||||
|
||||
class HDC(object):
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
import re
|
||||
|
||||
from PIL import Image, ImageFile
|
||||
from . import Image, ImageFile
|
||||
|
||||
__version__ = "0.2"
|
||||
|
||||
|
@ -69,7 +69,7 @@ class ImtImageFile(ImageFile.ImageFile):
|
|||
s = s + self.fp.readline()
|
||||
if len(s) == 1 or len(s) > 100:
|
||||
break
|
||||
if s[0] == b"*":
|
||||
if s[0] == ord(b"*"):
|
||||
continue # comment
|
||||
|
||||
m = field.match(s)
|
||||
|
|
|
@ -17,17 +17,13 @@
|
|||
|
||||
from __future__ import print_function
|
||||
|
||||
from PIL import Image, ImageFile, _binary
|
||||
from . import Image, ImageFile
|
||||
from ._binary import i8, i16be as i16, i32be as i32, o8
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
__version__ = "0.3"
|
||||
|
||||
i8 = _binary.i8
|
||||
i16 = _binary.i16be
|
||||
i32 = _binary.i32be
|
||||
o8 = _binary.o8
|
||||
|
||||
COMPRESSION = {
|
||||
1: "raw",
|
||||
5: "jpeg"
|
||||
|
@ -107,7 +103,7 @@ class IptcImageFile(ImageFile.ImageFile):
|
|||
else:
|
||||
self.info[tag] = tagdata
|
||||
|
||||
# print tag, self.info[tag]
|
||||
# print(tag, self.info[tag])
|
||||
|
||||
# mode
|
||||
layers = i8(self.info[(3, 60)][0])
|
||||
|
@ -168,14 +164,9 @@ class IptcImageFile(ImageFile.ImageFile):
|
|||
o.close()
|
||||
|
||||
try:
|
||||
try:
|
||||
# fast
|
||||
self.im = Image.core.open_ppm(outfile)
|
||||
except:
|
||||
# slightly slower
|
||||
im = Image.open(outfile)
|
||||
im.load()
|
||||
self.im = im.im
|
||||
_im = Image.open(outfile)
|
||||
_im.load()
|
||||
self.im = _im.im
|
||||
finally:
|
||||
try:
|
||||
os.unlink(outfile)
|
||||
|
@ -196,7 +187,7 @@ def getiptcinfo(im):
|
|||
:returns: A dictionary containing IPTC information, or None if
|
||||
no IPTC information block was found.
|
||||
"""
|
||||
from PIL import TiffImagePlugin, JpegImagePlugin
|
||||
from . import TiffImagePlugin, JpegImagePlugin
|
||||
import io
|
||||
|
||||
data = None
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#
|
||||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
from PIL import Image, ImageFile
|
||||
from . import Image, ImageFile
|
||||
import struct
|
||||
import os
|
||||
import io
|
||||
|
|
|
@ -32,19 +32,16 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import array
|
||||
import struct
|
||||
import io
|
||||
import warnings
|
||||
from struct import unpack_from
|
||||
from PIL import Image, ImageFile, TiffImagePlugin, _binary
|
||||
from PIL.JpegPresets import presets
|
||||
from PIL._util import isStringType
|
||||
|
||||
i8 = _binary.i8
|
||||
o8 = _binary.o8
|
||||
i16 = _binary.i16be
|
||||
i32 = _binary.i32be
|
||||
from . import Image, ImageFile, TiffImagePlugin
|
||||
from ._binary import i8, o8, i16be as i16, i32be as i32
|
||||
from .JpegPresets import presets
|
||||
from ._util import isStringType
|
||||
|
||||
__version__ = "0.6"
|
||||
|
||||
|
@ -316,7 +313,7 @@ class JpegImageFile(ImageFile.ImageFile):
|
|||
|
||||
if i in MARKER:
|
||||
name, description, handler = MARKER[i]
|
||||
# print hex(i), name, description
|
||||
# print(hex(i), name, description)
|
||||
if handler is not None:
|
||||
handler(self, i)
|
||||
if i == 0xFFDA: # start of scan
|
||||
|
@ -341,6 +338,10 @@ class JpegImageFile(ImageFile.ImageFile):
|
|||
if len(self.tile) != 1:
|
||||
return
|
||||
|
||||
# Protect from second call
|
||||
if self.decoderconfig:
|
||||
return
|
||||
|
||||
d, e, o, a = self.tile[0]
|
||||
scale = 0
|
||||
|
||||
|
@ -349,7 +350,7 @@ class JpegImageFile(ImageFile.ImageFile):
|
|||
a = mode, ""
|
||||
|
||||
if size:
|
||||
scale = max(self.size[0] // size[0], self.size[1] // size[1])
|
||||
scale = min(self.size[0] // size[0], self.size[1] // size[1])
|
||||
for s in [8, 4, 2, 1]:
|
||||
if scale >= s:
|
||||
break
|
||||
|
@ -377,7 +378,9 @@ class JpegImageFile(ImageFile.ImageFile):
|
|||
raise ValueError("Invalid Filename")
|
||||
|
||||
try:
|
||||
self.im = Image.core.open_ppm(path)
|
||||
_im = Image.open(path)
|
||||
_im.load()
|
||||
self.im = _im.im
|
||||
finally:
|
||||
try:
|
||||
os.unlink(path)
|
||||
|
@ -406,7 +409,7 @@ def _fixup_dict(src_dict):
|
|||
except: pass
|
||||
return value
|
||||
|
||||
return dict([(k, _fixup(v)) for k, v in src_dict.items()])
|
||||
return {k: _fixup(v) for k, v in src_dict.items()}
|
||||
|
||||
|
||||
def _getexif(self):
|
||||
|
@ -485,8 +488,8 @@ def _getmp(self):
|
|||
try:
|
||||
rawmpentries = mp[0xB002]
|
||||
for entrynum in range(0, quant):
|
||||
unpackedentry = unpack_from(
|
||||
'{0}LLLHH'.format(endianness), rawmpentries, entrynum * 16)
|
||||
unpackedentry = struct.unpack_from(
|
||||
'{}LLLHH'.format(endianness), rawmpentries, entrynum * 16)
|
||||
labels = ('Attribute', 'Size', 'DataOffset', 'EntryNo1',
|
||||
'EntryNo2')
|
||||
mpentry = dict(zip(labels, unpackedentry))
|
||||
|
@ -710,8 +713,11 @@ def _save(im, fp, filename):
|
|||
# https://github.com/matthewwithanm/django-imagekit/issues/50
|
||||
bufsize = 0
|
||||
if optimize or progressive:
|
||||
# CMYK can be bigger
|
||||
if im.mode == 'CMYK':
|
||||
bufsize = 4 * im.size[0] * im.size[1]
|
||||
# keep sets quality to 0, but the actual value may be high.
|
||||
if quality >= 95 or quality == 0:
|
||||
elif quality >= 95 or quality == 0:
|
||||
bufsize = 2 * im.size[0] * im.size[1]
|
||||
else:
|
||||
bufsize = im.size[0] * im.size[1]
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#
|
||||
|
||||
import struct
|
||||
from PIL import Image, ImageFile
|
||||
from . import Image, ImageFile
|
||||
|
||||
__version__ = "0.2"
|
||||
|
||||
|
|
|
@ -17,8 +17,9 @@
|
|||
#
|
||||
|
||||
|
||||
from PIL import Image, TiffImagePlugin
|
||||
from PIL.OleFileIO import MAGIC, OleFileIO
|
||||
from . import Image, TiffImagePlugin
|
||||
|
||||
import olefile
|
||||
|
||||
__version__ = "0.1"
|
||||
|
||||
|
@ -28,7 +29,7 @@ __version__ = "0.1"
|
|||
|
||||
|
||||
def _accept(prefix):
|
||||
return prefix[:8] == MAGIC
|
||||
return prefix[:8] == olefile.MAGIC
|
||||
|
||||
|
||||
##
|
||||
|
@ -45,7 +46,7 @@ class MicImageFile(TiffImagePlugin.TiffImageFile):
|
|||
# to be a Microsoft Image Composer file
|
||||
|
||||
try:
|
||||
self.ole = OleFileIO(self.fp)
|
||||
self.ole = olefile.OleFileIO(self.fp)
|
||||
except IOError:
|
||||
raise SyntaxError("not an MIC file; invalid OLE file")
|
||||
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
#
|
||||
|
||||
|
||||
from PIL import Image, ImageFile
|
||||
from PIL._binary import i8
|
||||
from . import Image, ImageFile
|
||||
from ._binary import i8
|
||||
|
||||
__version__ = "0.1"
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from PIL import Image, JpegImagePlugin
|
||||
from . import Image, JpegImagePlugin
|
||||
|
||||
__version__ = "0.1"
|
||||
|
||||
|
|
|
@ -17,7 +17,8 @@
|
|||
#
|
||||
|
||||
|
||||
from PIL import Image, ImageFile, _binary
|
||||
from . import Image, ImageFile
|
||||
from ._binary import i16le as i16, o16le as o16
|
||||
|
||||
__version__ = "0.1"
|
||||
|
||||
|
@ -25,8 +26,6 @@ __version__ = "0.1"
|
|||
#
|
||||
# read MSP files
|
||||
|
||||
i16 = _binary.i16le
|
||||
|
||||
|
||||
def _accept(prefix):
|
||||
return prefix[:4] in [b"DanM", b"LinS"]
|
||||
|
@ -66,8 +65,6 @@ class MspImageFile(ImageFile.ImageFile):
|
|||
#
|
||||
# write MSP files (uncompressed only)
|
||||
|
||||
o16 = _binary.o16le
|
||||
|
||||
|
||||
def _save(im, fp, filename):
|
||||
|
||||
|
|
|
@ -1,180 +0,0 @@
|
|||
olefile (formerly OleFileIO_PL)
|
||||
===============================
|
||||
|
||||
[olefile](http://www.decalage.info/olefile) is a Python package to parse, read and write
|
||||
[Microsoft OLE2 files](http://en.wikipedia.org/wiki/Compound_File_Binary_Format)
|
||||
(also called Structured Storage, Compound File Binary Format or Compound Document File Format),
|
||||
such as Microsoft Office 97-2003 documents, vbaProject.bin in MS Office 2007+ files, Image Composer
|
||||
and FlashPix files, Outlook messages, StickyNotes, several Microscopy file formats, McAfee antivirus quarantine files,
|
||||
etc.
|
||||
|
||||
|
||||
**Quick links:** [Home page](http://www.decalage.info/olefile) -
|
||||
[Download/Install](https://bitbucket.org/decalage/olefileio_pl/wiki/Install) -
|
||||
[Documentation](https://bitbucket.org/decalage/olefileio_pl/wiki) -
|
||||
[Report Issues/Suggestions/Questions](https://bitbucket.org/decalage/olefileio_pl/issues?status=new&status=open) -
|
||||
[Contact the author](http://decalage.info/contact) -
|
||||
[Repository](https://bitbucket.org/decalage/olefileio_pl) -
|
||||
[Updates on Twitter](https://twitter.com/decalage2)
|
||||
|
||||
|
||||
News
|
||||
----
|
||||
|
||||
Follow all updates and news on Twitter: <https://twitter.com/decalage2>
|
||||
|
||||
- **2015-01-25 v0.42**: improved handling of special characters in stream/storage names on Python 2.x (using UTF-8
|
||||
instead of Latin-1), fixed bug in listdir with empty storages.
|
||||
- 2014-11-25 v0.41: OleFileIO.open and isOleFile now support OLE files stored in byte strings, fixed installer for
|
||||
python 3, added support for Jython (Niko Ehrenfeuchter)
|
||||
- 2014-10-01 v0.40: renamed OleFileIO_PL to olefile, added initial write support for streams >4K, updated doc and
|
||||
license, improved the setup script.
|
||||
- 2014-07-27 v0.31: fixed support for large files with 4K sectors, thanks to Niko Ehrenfeuchter, Martijn Berger and
|
||||
Dave Jones. Added test scripts from Pillow (by hugovk). Fixed setup for Python 3 (Martin Panter)
|
||||
- 2014-02-04 v0.30: now compatible with Python 3.x, thanks to Martin Panter who did most of the hard work.
|
||||
- 2013-07-24 v0.26: added methods to parse stream/storage timestamps, improved listdir to include storages, fixed
|
||||
parsing of direntry timestamps
|
||||
- 2013-05-27 v0.25: improved metadata extraction, properties parsing and exception handling, fixed
|
||||
[issue #12](https://bitbucket.org/decalage/olefileio_pl/issue/12/error-when-converting-timestamps-in-ole)
|
||||
- 2013-05-07 v0.24: new features to extract metadata (get\_metadata method and OleMetadata class), improved
|
||||
getproperties to convert timestamps to Python datetime
|
||||
- 2012-10-09: published [python-oletools](http://www.decalage.info/python/oletools), a package of analysis tools based
|
||||
on OleFileIO_PL
|
||||
- 2012-09-11 v0.23: added support for file-like objects, fixed [issue #8](https://bitbucket.org/decalage/olefileio_pl/issue/8/bug-with-file-object)
|
||||
- 2012-02-17 v0.22: fixed issues #7 (bug in getproperties) and #2 (added close method)
|
||||
- 2011-10-20: code hosted on bitbucket to ease contributions and bug tracking
|
||||
- 2010-01-24 v0.21: fixed support for big-endian CPUs, such as PowerPC Macs.
|
||||
- 2009-12-11 v0.20: small bugfix in OleFileIO.open when filename is not plain str.
|
||||
- 2009-12-10 v0.19: fixed support for 64 bits platforms (thanks to Ben G. and Martijn for reporting the bug)
|
||||
- see changelog in source code for more info.
|
||||
|
||||
Download/Install
|
||||
----------------
|
||||
|
||||
If you have pip or setuptools installed (pip is included in Python 2.7.9+), you may simply run **pip install olefile**
|
||||
or **easy_install olefile** for the first installation.
|
||||
|
||||
To update olefile, run **pip install -U olefile**.
|
||||
|
||||
Otherwise, see https://bitbucket.org/decalage/olefileio_pl/wiki/Install
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
- Parse, read and write any OLE file such as Microsoft Office 97-2003 legacy document formats (Word .doc, Excel .xls,
|
||||
PowerPoint .ppt, Visio .vsd, Project .mpp), Image Composer and FlashPix files, Outlook messages, StickyNotes,
|
||||
Zeiss AxioVision ZVI files, Olympus FluoView OIB files, etc
|
||||
- List all the streams and storages contained in an OLE file
|
||||
- Open streams as files
|
||||
- Parse and read property streams, containing metadata of the file
|
||||
- Portable, pure Python module, no dependency
|
||||
|
||||
olefile can be used as an independent package or with PIL/Pillow.
|
||||
|
||||
olefile is mostly meant for developers. If you are looking for tools to analyze OLE files or to extract data (especially
|
||||
for security purposes such as malware analysis and forensics), then please also check my
|
||||
[python-oletools](http://www.decalage.info/python/oletools), which are built upon olefile and provide a higher-level interface.
|
||||
|
||||
|
||||
History
|
||||
-------
|
||||
|
||||
olefile is based on the OleFileIO module from [PIL](http://www.pythonware.com/products/pil/index.htm), the excellent
|
||||
Python Imaging Library, created and maintained by Fredrik Lundh. The olefile API is still compatible with PIL, but
|
||||
since 2005 I have improved the internal implementation significantly, with new features, bugfixes and a more robust
|
||||
design. From 2005 to 2014 the project was called OleFileIO_PL, and in 2014 I changed its name to olefile to celebrate
|
||||
its 9 years and its new write features.
|
||||
|
||||
As far as I know, olefile is the most complete and robust Python implementation to read MS OLE2 files, portable on
|
||||
several operating systems. (please tell me if you know other similar Python modules)
|
||||
|
||||
Since 2014 olefile/OleFileIO_PL has been integrated into [Pillow](http://python-pillow.org), the friendly fork
|
||||
of PIL. olefile will continue to be improved as a separate project, and new versions will be merged into Pillow
|
||||
regularly.
|
||||
|
||||
|
||||
Main improvements over the original version of OleFileIO in PIL:
|
||||
----------------------------------------------------------------
|
||||
|
||||
- Compatible with Python 3.x and 2.6+
|
||||
- Many bug fixes
|
||||
- Support for files larger than 6.8MB
|
||||
- Support for 64 bits platforms and big-endian CPUs
|
||||
- Robust: many checks to detect malformed files
|
||||
- Runtime option to choose if malformed files should be parsed or raise exceptions
|
||||
- Improved API
|
||||
- Metadata extraction, stream/storage timestamps (e.g. for document forensics)
|
||||
- Can open file-like objects
|
||||
- Added setup.py and install.bat to ease installation
|
||||
- More convenient slash-based syntax for stream paths
|
||||
- Write features
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
Please see the [online documentation](https://bitbucket.org/decalage/olefileio_pl/wiki) for more information,
|
||||
especially the [OLE overview](https://bitbucket.org/decalage/olefileio_pl/wiki/OLE_Overview) and the
|
||||
[API page](https://bitbucket.org/decalage/olefileio_pl/wiki/API) which describe how to use olefile in Python applications.
|
||||
A copy of the same documentation is also provided in the doc subfolder of the olefile package.
|
||||
|
||||
|
||||
## Real-life examples ##
|
||||
|
||||
A real-life example: [using OleFileIO_PL for malware analysis and forensics](http://blog.gregback.net/2011/03/using-remnux-for-forensic-puzzle-6/).
|
||||
|
||||
See also [this paper](https://computer-forensics.sans.org/community/papers/gcfa/grow-forensic-tools-taxonomy-python-libraries-helpful-forensic-analysis_6879) about python tools for forensics, which features olefile.
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
olefile (formerly OleFileIO_PL) is copyright (c) 2005-2015 Philippe Lagadec
|
||||
([http://www.decalage.info](http://www.decalage.info))
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
----------
|
||||
|
||||
olefile is based on source code from the OleFileIO module of the Python Imaging Library (PIL) published by Fredrik
|
||||
Lundh under the following license:
|
||||
|
||||
The Python Imaging Library (PIL) is
|
||||
|
||||
Copyright © 1997-2011 by Secret Labs AB
|
||||
Copyright © 1995-2011 by Fredrik Lundh
|
||||
|
||||
By obtaining, using, and/or copying this software and/or its associated documentation, you agree that you have read,
|
||||
understood, and will comply with the following terms and conditions:
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and its associated documentation for any purpose and
|
||||
without fee is hereby granted, provided that the above copyright notice appears in all copies, and that both that
|
||||
copyright notice and this permission notice appear in supporting documentation, and that the name of Secret Labs AB or
|
||||
the author not be used in advertising or publicity pertaining to distribution of the software without specific, written
|
||||
prior permission.
|
||||
|
||||
SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
||||
CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
SOFTWARE.
|
2309
PIL/OleFileIO.py
Executable file → Normal file
2309
PIL/OleFileIO.py
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
|
@ -15,7 +15,7 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from PIL import EpsImagePlugin
|
||||
from . import EpsImagePlugin
|
||||
import sys
|
||||
|
||||
##
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from PIL._binary import o8
|
||||
from ._binary import o8
|
||||
|
||||
|
||||
##
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
# Image plugin for Palm pixmap images (output only).
|
||||
##
|
||||
|
||||
from PIL import Image, ImageFile, _binary
|
||||
from . import Image, ImageFile
|
||||
from ._binary import o8, o16be as o16b
|
||||
|
||||
__version__ = "1.0"
|
||||
|
||||
|
@ -80,13 +81,12 @@ _Palm8BitColormapValues = (
|
|||
|
||||
# so build a prototype image to be used for palette resampling
|
||||
def build_prototype_image():
|
||||
image = Image.new("L", (1, len(_Palm8BitColormapValues),))
|
||||
image = Image.new("L", (1, len(_Palm8BitColormapValues)))
|
||||
image.putdata(list(range(len(_Palm8BitColormapValues))))
|
||||
palettedata = ()
|
||||
for i in range(len(_Palm8BitColormapValues)):
|
||||
palettedata = palettedata + _Palm8BitColormapValues[i]
|
||||
for i in range(256 - len(_Palm8BitColormapValues)):
|
||||
palettedata = palettedata + (0, 0, 0)
|
||||
for colormapValue in _Palm8BitColormapValues:
|
||||
palettedata += colormapValue
|
||||
palettedata += (0, 0, 0)*(256 - len(_Palm8BitColormapValues))
|
||||
image.putpalette(palettedata)
|
||||
return image
|
||||
|
||||
|
@ -109,9 +109,6 @@ _COMPRESSION_TYPES = {
|
|||
"scanline": 0x00,
|
||||
}
|
||||
|
||||
o8 = _binary.o8
|
||||
o16b = _binary.o16be
|
||||
|
||||
|
||||
#
|
||||
# --------------------------------------------------------------------
|
||||
|
|
|
@ -15,12 +15,11 @@
|
|||
#
|
||||
|
||||
|
||||
from PIL import Image, ImageFile, _binary
|
||||
from . import Image, ImageFile
|
||||
from ._binary import i8
|
||||
|
||||
__version__ = "0.1"
|
||||
|
||||
i8 = _binary.i8
|
||||
|
||||
|
||||
##
|
||||
# Image plugin for PhotoCD images. This plugin only reads the 768x512
|
||||
|
@ -42,8 +41,9 @@ class PcdImageFile(ImageFile.ImageFile):
|
|||
raise SyntaxError("not a PCD file")
|
||||
|
||||
orientation = i8(s[1538]) & 3
|
||||
self.tile_post_rotate = None
|
||||
if orientation == 1:
|
||||
self.tile_post_rotate = 90 # hack
|
||||
self.tile_post_rotate = 90
|
||||
elif orientation == 3:
|
||||
self.tile_post_rotate = -90
|
||||
|
||||
|
@ -51,6 +51,13 @@ class PcdImageFile(ImageFile.ImageFile):
|
|||
self.size = 768, 512 # FIXME: not correct for rotated images!
|
||||
self.tile = [("pcd", (0, 0)+self.size, 96*2048, None)]
|
||||
|
||||
def load_end(self):
|
||||
if self.tile_post_rotate:
|
||||
# Handle rotated PCDs
|
||||
self.im = self.im.rotate(self.tile_post_rotate)
|
||||
self.size = self.im.size
|
||||
|
||||
|
||||
#
|
||||
# registry
|
||||
|
||||
|
|
|
@ -16,9 +16,8 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from PIL import Image
|
||||
from PIL import FontFile
|
||||
from PIL import _binary
|
||||
from . import Image, FontFile
|
||||
from ._binary import i8, i16le as l16, i32le as l32, i16be as b16, i32be as b32
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# declarations
|
||||
|
@ -42,12 +41,6 @@ BYTES_PER_ROW = [
|
|||
lambda bits: ((bits+63) >> 3) & ~7,
|
||||
]
|
||||
|
||||
i8 = _binary.i8
|
||||
l16 = _binary.i16le
|
||||
l32 = _binary.i32le
|
||||
b16 = _binary.i16be
|
||||
b32 = _binary.i32be
|
||||
|
||||
|
||||
def sz(s, o):
|
||||
return s[o:s.index(b"\0", o)]
|
||||
|
|
|
@ -28,14 +28,11 @@
|
|||
from __future__ import print_function
|
||||
|
||||
import logging
|
||||
from PIL import Image, ImageFile, ImagePalette, _binary
|
||||
from . import Image, ImageFile, ImagePalette
|
||||
from ._binary import i8, i16le as i16, o8, o16le as o16
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
i8 = _binary.i8
|
||||
i16 = _binary.i16le
|
||||
o8 = _binary.o8
|
||||
|
||||
__version__ = "0.6"
|
||||
|
||||
|
||||
|
@ -123,8 +120,6 @@ SAVE = {
|
|||
"RGB": (5, 8, 3, "RGB;L"),
|
||||
}
|
||||
|
||||
o16 = _binary.o16le
|
||||
|
||||
|
||||
def _save(im, fp, filename, check=0):
|
||||
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
# Image plugin for PDF images (output only).
|
||||
##
|
||||
|
||||
from PIL import Image, ImageFile
|
||||
from PIL._binary import i8
|
||||
from . import Image, ImageFile
|
||||
from ._binary import i8
|
||||
import io
|
||||
|
||||
__version__ = "0.4"
|
||||
|
|
|
@ -19,16 +19,14 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from PIL import Image, ImageFile, _binary
|
||||
from . import Image, ImageFile
|
||||
from ._binary import i16le as i16
|
||||
|
||||
__version__ = "0.1"
|
||||
|
||||
#
|
||||
# helpers
|
||||
|
||||
i16 = _binary.i16le
|
||||
|
||||
|
||||
def _accept(prefix):
|
||||
return prefix[:4] == b"\200\350\000\000"
|
||||
|
||||
|
|
|
@ -38,17 +38,14 @@ import re
|
|||
import zlib
|
||||
import struct
|
||||
|
||||
from PIL import Image, ImageFile, ImagePalette, _binary
|
||||
from . import Image, ImageFile, ImagePalette
|
||||
from ._binary import i8, i16be as i16, i32be as i32, o8, o16be as o16, o32be as o32
|
||||
|
||||
__version__ = "0.9"
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
i8 = _binary.i8
|
||||
i16 = _binary.i16be
|
||||
i32 = _binary.i32be
|
||||
|
||||
is_cid = re.compile(b"\w\w\w\w").match
|
||||
is_cid = re.compile(br"\w\w\w\w").match
|
||||
|
||||
|
||||
_MAGIC = b"\211PNG\r\n\032\n"
|
||||
|
@ -132,7 +129,7 @@ class ChunkStream(object):
|
|||
def call(self, cid, pos, length):
|
||||
"Call the appropriate chunk handler"
|
||||
|
||||
logger.debug("STREAM %s %s %s", cid, pos, length)
|
||||
logger.debug("STREAM %r %s %s", cid, pos, length)
|
||||
return getattr(self, "chunk_" + cid.decode('ascii'))(pos, length)
|
||||
|
||||
def crc(self, cid, data):
|
||||
|
@ -148,10 +145,10 @@ class ChunkStream(object):
|
|||
crc1 = Image.core.crc32(data, Image.core.crc32(cid))
|
||||
crc2 = i16(self.fp.read(2)), i16(self.fp.read(2))
|
||||
if crc1 != crc2:
|
||||
raise SyntaxError("broken PNG file (bad header checksum in %s)"
|
||||
raise SyntaxError("broken PNG file (bad header checksum in %r)"
|
||||
% cid)
|
||||
except struct.error:
|
||||
raise SyntaxError("broken PNG file (incomplete checksum in %s)"
|
||||
raise SyntaxError("broken PNG file (incomplete checksum in %r)"
|
||||
% cid)
|
||||
|
||||
def crc_skip(self, cid, data):
|
||||
|
@ -309,7 +306,7 @@ class PngStream(ChunkStream):
|
|||
# Compression method 1 byte (0)
|
||||
# Compressed profile n bytes (zlib with deflate compression)
|
||||
i = s.find(b"\0")
|
||||
logger.debug("iCCP profile name %s", s[:i])
|
||||
logger.debug("iCCP profile name %r", s[:i])
|
||||
logger.debug("Compression method %s", i8(s[i]))
|
||||
comp_method = i8(s[i])
|
||||
if comp_method != 0:
|
||||
|
@ -539,7 +536,7 @@ class PngImageFile(ImageFile.ImageFile):
|
|||
except EOFError:
|
||||
break
|
||||
except AttributeError:
|
||||
logger.debug("%s %s %s (unknown)", cid, pos, length)
|
||||
logger.debug("%r %s %s (unknown)", cid, pos, length)
|
||||
s = ImageFile._safe_read(self.fp, length)
|
||||
|
||||
self.png.crc(cid, s)
|
||||
|
@ -621,10 +618,6 @@ class PngImageFile(ImageFile.ImageFile):
|
|||
# --------------------------------------------------------------------
|
||||
# PNG writer
|
||||
|
||||
o8 = _binary.o8
|
||||
o16 = _binary.o16be
|
||||
o32 = _binary.o32be
|
||||
|
||||
_OUTMODES = {
|
||||
# supported PIL modes, and corresponding rawmodes/bits/color combinations
|
||||
"1": ("1", b'\x01\x00'),
|
||||
|
@ -722,6 +715,32 @@ def _save(im, fp, filename, chunk=putchunk, check=0):
|
|||
b'\0', # 11: filter category
|
||||
b'\0') # 12: interlace flag
|
||||
|
||||
chunks = [b"cHRM", b"gAMA", b"sBIT", b"sRGB", b"tIME"]
|
||||
|
||||
icc = im.encoderinfo.get("icc_profile", im.info.get("icc_profile"))
|
||||
if icc:
|
||||
# ICC profile
|
||||
# according to PNG spec, the iCCP chunk contains:
|
||||
# Profile name 1-79 bytes (character string)
|
||||
# Null separator 1 byte (null character)
|
||||
# Compression method 1 byte (0)
|
||||
# Compressed profile n bytes (zlib with deflate compression)
|
||||
name = b"ICC Profile"
|
||||
data = name + b"\0\0" + zlib.compress(icc)
|
||||
chunk(fp, b"iCCP", data)
|
||||
else:
|
||||
chunks.remove(b"sRGB")
|
||||
|
||||
info = im.encoderinfo.get("pnginfo")
|
||||
if info:
|
||||
chunks_multiple_allowed = [b"sPLT", b"iTXt", b"tEXt", b"zTXt"]
|
||||
for cid, data in info.chunks:
|
||||
if cid in chunks:
|
||||
chunks.remove(cid)
|
||||
chunk(fp, cid, data)
|
||||
elif cid in chunks_multiple_allowed:
|
||||
chunk(fp, cid, data)
|
||||
|
||||
if im.mode == "P":
|
||||
palette_byte_number = (2 ** bits) * 3
|
||||
palette_bytes = im.im.getpalette("RGB")[:palette_byte_number]
|
||||
|
@ -768,20 +787,11 @@ def _save(im, fp, filename, chunk=putchunk, check=0):
|
|||
|
||||
info = im.encoderinfo.get("pnginfo")
|
||||
if info:
|
||||
chunks = [b"bKGD", b"hIST"]
|
||||
for cid, data in info.chunks:
|
||||
chunk(fp, cid, data)
|
||||
|
||||
icc = im.encoderinfo.get("icc_profile", im.info.get("icc_profile"))
|
||||
if icc:
|
||||
# ICC profile
|
||||
# according to PNG spec, the iCCP chunk contains:
|
||||
# Profile name 1-79 bytes (character string)
|
||||
# Null separator 1 byte (null character)
|
||||
# Compression method 1 byte (0)
|
||||
# Compressed profile n bytes (zlib with deflate compression)
|
||||
name = b"ICC Profile"
|
||||
data = name + b"\0\0" + zlib.compress(icc)
|
||||
chunk(fp, b"iCCP", data)
|
||||
if cid in chunks:
|
||||
chunks.remove(cid)
|
||||
chunk(fp, cid, data)
|
||||
|
||||
ImageFile._save(im, _idat(fp, chunk),
|
||||
[("zip", (0, 0)+im.size, 0, rawmode)])
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
import string
|
||||
|
||||
from PIL import Image, ImageFile
|
||||
from . import Image, ImageFile
|
||||
|
||||
__version__ = "0.2"
|
||||
|
||||
|
@ -123,11 +123,6 @@ class PpmImageFile(ImageFile.ImageFile):
|
|||
self.fp.tell(),
|
||||
(rawmode, 0, 1))]
|
||||
|
||||
# ALTERNATIVE: load via builtin debug function
|
||||
# self.im = Image.core.open_ppm(self.filename)
|
||||
# self.mode = self.im.mode
|
||||
# self.size = self.im.size
|
||||
|
||||
|
||||
#
|
||||
# --------------------------------------------------------------------
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
|
||||
__version__ = "0.4"
|
||||
|
||||
from PIL import Image, ImageFile, ImagePalette, _binary
|
||||
from . import Image, ImageFile, ImagePalette
|
||||
from ._binary import i8, i16be as i16, i32be as i32
|
||||
|
||||
MODES = {
|
||||
# (photoshop mode, bits) -> (pil mode, required channels)
|
||||
|
@ -33,13 +34,6 @@ MODES = {
|
|||
(9, 8): ("LAB", 3)
|
||||
}
|
||||
|
||||
#
|
||||
# helpers
|
||||
|
||||
i8 = _binary.i8
|
||||
i16 = _binary.i16be
|
||||
i32 = _binary.i32be
|
||||
|
||||
|
||||
# --------------------------------------------------------------------.
|
||||
# read PSD images
|
||||
|
|
|
@ -7,9 +7,12 @@
|
|||
# See "The SGI Image File Format (Draft version 0.97)", Paul Haeberli.
|
||||
# <ftp://ftp.sgi.com/graphics/SGIIMAGESPEC>
|
||||
#
|
||||
#
|
||||
# History:
|
||||
# 2016-16-10 mb Add save method without compression
|
||||
# 1995-09-10 fl Created
|
||||
#
|
||||
# Copyright (c) 2016 by Mickael Bonfill.
|
||||
# Copyright (c) 2008 by Karsten Hiddemann.
|
||||
# Copyright (c) 1997 by Secret Labs AB.
|
||||
# Copyright (c) 1995 by Fredrik Lundh.
|
||||
|
@ -18,12 +21,12 @@
|
|||
#
|
||||
|
||||
|
||||
from PIL import Image, ImageFile, _binary
|
||||
from . import Image, ImageFile
|
||||
from ._binary import i8, o8, i16be as i16
|
||||
import struct
|
||||
import os
|
||||
|
||||
__version__ = "0.2"
|
||||
|
||||
i8 = _binary.i8
|
||||
i16 = _binary.i16be
|
||||
__version__ = "0.3"
|
||||
|
||||
|
||||
def _accept(prefix):
|
||||
|
@ -76,12 +79,79 @@ class SgiImageFile(ImageFile.ImageFile):
|
|||
elif compression == 1:
|
||||
raise ValueError("SGI RLE encoding not supported")
|
||||
|
||||
|
||||
def _save(im, fp, filename):
|
||||
if im.mode != "RGB" and im.mode != "RGBA" and im.mode != "L":
|
||||
raise ValueError("Unsupported SGI image mode")
|
||||
|
||||
# Flip the image, since the origin of SGI file is the bottom-left corner
|
||||
im = im.transpose(Image.FLIP_TOP_BOTTOM)
|
||||
# Define the file as SGI File Format
|
||||
magicNumber = 474
|
||||
# Run-Length Encoding Compression - Unsupported at this time
|
||||
rle = 0
|
||||
# Byte-per-pixel precision, 1 = 8bits per pixel
|
||||
bpc = 1
|
||||
# Number of dimensions (x,y,z)
|
||||
dim = 3
|
||||
# X Dimension = width / Y Dimension = height
|
||||
x, y = im.size
|
||||
if im.mode == "L" and y == 1:
|
||||
dim = 1
|
||||
elif im.mode == "L":
|
||||
dim = 2
|
||||
# Z Dimension: Number of channels
|
||||
z = len(im.mode)
|
||||
if dim == 1 or dim == 2:
|
||||
z = 1
|
||||
# Minimum Byte value
|
||||
pinmin = 0
|
||||
# Maximum Byte value (255 = 8bits per pixel)
|
||||
pinmax = 255
|
||||
# Image name (79 characters max, truncated below in write)
|
||||
imgName = os.path.splitext(os.path.basename(filename))[0]
|
||||
if str is not bytes:
|
||||
imgName = imgName.encode('ascii', 'ignore')
|
||||
# Standard representation of pixel in the file
|
||||
colormap = 0
|
||||
fp.write(struct.pack('>h', magicNumber))
|
||||
fp.write(o8(rle))
|
||||
fp.write(o8(bpc))
|
||||
fp.write(struct.pack('>H', dim))
|
||||
fp.write(struct.pack('>H', x))
|
||||
fp.write(struct.pack('>H', y))
|
||||
fp.write(struct.pack('>H', z))
|
||||
fp.write(struct.pack('>l', pinmin))
|
||||
fp.write(struct.pack('>l', pinmax))
|
||||
|
||||
fp.write(struct.pack('4s', b'')) # dummy
|
||||
fp.write(struct.pack('79s', imgName)) # truncates to 79 chars
|
||||
fp.write(struct.pack('s', b'')) # force null byte after imgname
|
||||
fp.write(struct.pack('>l', colormap))
|
||||
|
||||
fp.write(struct.pack('404s', b'')) # dummy
|
||||
|
||||
#assert we've got the right number of bands.
|
||||
if len(im.getbands()) != z:
|
||||
raise ValueError("incorrect number of bands in SGI write: %s vs %s" %
|
||||
(z, len(im.getbands())))
|
||||
|
||||
for channel in im.split():
|
||||
fp.write(channel.tobytes())
|
||||
|
||||
fp.close()
|
||||
|
||||
|
||||
#
|
||||
# registry
|
||||
|
||||
Image.register_open(SgiImageFile.format, SgiImageFile, _accept)
|
||||
|
||||
Image.register_save(SgiImageFile.format, _save)
|
||||
Image.register_mime(SgiImageFile.format, "image/sgi")
|
||||
Image.register_mime(SgiImageFile.format, "image/rgb")
|
||||
Image.register_extension(SgiImageFile.format, ".bw")
|
||||
Image.register_extension(SgiImageFile.format, ".rgb")
|
||||
Image.register_extension(SgiImageFile.format, ".rgba")
|
||||
Image.register_extension(SgiImageFile.format, ".sgi")
|
||||
|
||||
# End of file
|
||||
|
|
|
@ -58,7 +58,7 @@ iforms = [1, 3, -11, -12, -21, -22]
|
|||
|
||||
# There is no magic number to identify Spider files, so just check a
|
||||
# series of header locations to see if they have reasonable values.
|
||||
# Returns no.of bytes in the header, if it is a valid Spider header,
|
||||
# Returns no. of bytes in the header, if it is a valid Spider header,
|
||||
# otherwise returns 0
|
||||
|
||||
def isSpiderHeader(t):
|
||||
|
@ -75,7 +75,7 @@ def isSpiderHeader(t):
|
|||
labrec = int(h[13]) # no. records in file header
|
||||
labbyt = int(h[22]) # total no. of bytes in header
|
||||
lenbyt = int(h[23]) # record length in bytes
|
||||
# print "labrec = %d, labbyt = %d, lenbyt = %d" % (labrec,labbyt,lenbyt)
|
||||
# print("labrec = %d, labbyt = %d, lenbyt = %d" % (labrec,labbyt,lenbyt))
|
||||
if labbyt != (labrec * lenbyt):
|
||||
return 0
|
||||
# looks like a valid header
|
||||
|
@ -83,9 +83,8 @@ def isSpiderHeader(t):
|
|||
|
||||
|
||||
def isSpiderImage(filename):
|
||||
fp = open(filename, 'rb')
|
||||
f = fp.read(92) # read 23 * 4 bytes
|
||||
fp.close()
|
||||
with open(filename, 'rb') as fp:
|
||||
f = fp.read(92) # read 23 * 4 bytes
|
||||
t = struct.unpack('>23f', f) # try big-endian first
|
||||
hdrlen = isSpiderHeader(t)
|
||||
if hdrlen == 0:
|
||||
|
|
|
@ -17,12 +17,11 @@
|
|||
#
|
||||
|
||||
|
||||
from PIL import Image, ImageFile, ImagePalette, _binary
|
||||
from . import Image, ImageFile, ImagePalette
|
||||
from ._binary import i32be as i32
|
||||
|
||||
__version__ = "0.3"
|
||||
|
||||
i32 = _binary.i32be
|
||||
|
||||
|
||||
def _accept(prefix):
|
||||
return len(prefix) >= 4 and i32(prefix) == 0x59a66a95
|
||||
|
@ -38,6 +37,21 @@ class SunImageFile(ImageFile.ImageFile):
|
|||
|
||||
def _open(self):
|
||||
|
||||
# The Sun Raster file header is 32 bytes in length and has the following format:
|
||||
|
||||
# typedef struct _SunRaster
|
||||
# {
|
||||
# DWORD MagicNumber; /* Magic (identification) number */
|
||||
# DWORD Width; /* Width of image in pixels */
|
||||
# DWORD Height; /* Height of image in pixels */
|
||||
# DWORD Depth; /* Number of bits per pixel */
|
||||
# DWORD Length; /* Size of image data in bytes */
|
||||
# DWORD Type; /* Type of raster file */
|
||||
# DWORD ColorMapType; /* Type of color map */
|
||||
# DWORD ColorMapLength; /* Size of the color map in bytes */
|
||||
# } SUNRASTER;
|
||||
|
||||
|
||||
# HEAD
|
||||
s = self.fp.read(32)
|
||||
if i32(s) != 0x59a66a95:
|
||||
|
@ -48,30 +62,70 @@ class SunImageFile(ImageFile.ImageFile):
|
|||
self.size = i32(s[4:8]), i32(s[8:12])
|
||||
|
||||
depth = i32(s[12:16])
|
||||
data_length = i32(s[16:20]) # unreliable, ignore.
|
||||
file_type = i32(s[20:24])
|
||||
palette_type = i32(s[24:28]) # 0: None, 1: RGB, 2: Raw/arbitrary
|
||||
palette_length = i32(s[28:32])
|
||||
|
||||
if depth == 1:
|
||||
self.mode, rawmode = "1", "1;I"
|
||||
elif depth == 4:
|
||||
self.mode, rawmode = "L", "L;4"
|
||||
elif depth == 8:
|
||||
self.mode = rawmode = "L"
|
||||
elif depth == 24:
|
||||
self.mode, rawmode = "RGB", "BGR"
|
||||
if file_type == 3:
|
||||
self.mode, rawmode = "RGB", "RGB"
|
||||
else:
|
||||
self.mode, rawmode = "RGB", "BGR"
|
||||
elif depth == 32:
|
||||
if file_type == 3:
|
||||
self.mode, rawmode = 'RGB', 'RGBX'
|
||||
else:
|
||||
self.mode, rawmode = 'RGB', 'BGRX'
|
||||
else:
|
||||
raise SyntaxError("unsupported mode")
|
||||
raise SyntaxError("Unsupported Mode/Bit Depth")
|
||||
|
||||
compression = i32(s[20:24])
|
||||
if palette_length:
|
||||
if palette_length > 1024:
|
||||
raise SyntaxError("Unsupported Color Palette Length")
|
||||
|
||||
if i32(s[24:28]) != 0:
|
||||
length = i32(s[28:32])
|
||||
offset = offset + length
|
||||
self.palette = ImagePalette.raw("RGB;L", self.fp.read(length))
|
||||
if palette_type != 1:
|
||||
raise SyntaxError("Unsupported Palette Type")
|
||||
|
||||
offset = offset + palette_length
|
||||
self.palette = ImagePalette.raw("RGB;L", self.fp.read(palette_length))
|
||||
if self.mode == "L":
|
||||
self.mode = rawmode = "P"
|
||||
self.mode = "P"
|
||||
rawmode = rawmode.replace('L', 'P')
|
||||
|
||||
stride = (((self.size[0] * depth + 7) // 8) + 3) & (~3)
|
||||
# 16 bit boundaries on stride
|
||||
stride = ((self.size[0] * depth + 15) // 16) * 2
|
||||
|
||||
if compression == 1:
|
||||
# file type: Type is the version (or flavor) of the bitmap
|
||||
# file. The following values are typically found in the Type
|
||||
# field:
|
||||
# 0000h Old
|
||||
# 0001h Standard
|
||||
# 0002h Byte-encoded
|
||||
# 0003h RGB format
|
||||
# 0004h TIFF format
|
||||
# 0005h IFF format
|
||||
# FFFFh Experimental
|
||||
|
||||
# Old and standard are the same, except for the length tag.
|
||||
# byte-encoded is run-length-encoded
|
||||
# RGB looks similar to standard, but RGB byte order
|
||||
# TIFF and IFF mean that they were converted from T/IFF
|
||||
# Experimental means that it's something else.
|
||||
# (http://www.fileformat.info/format/sunraster/egff.htm)
|
||||
|
||||
if file_type in (0, 1, 3, 4, 5):
|
||||
self.tile = [("raw", (0, 0)+self.size, offset, (rawmode, stride))]
|
||||
elif compression == 2:
|
||||
elif file_type == 2:
|
||||
self.tile = [("sun_rle", (0, 0)+self.size, offset, rawmode)]
|
||||
else:
|
||||
raise SyntaxError('Unsupported Sun Raster file type')
|
||||
|
||||
#
|
||||
# registry
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from PIL import ContainerIO
|
||||
from . import ContainerIO
|
||||
|
||||
|
||||
##
|
||||
|
|
|
@ -17,7 +17,8 @@
|
|||
#
|
||||
|
||||
|
||||
from PIL import Image, ImageFile, ImagePalette, _binary
|
||||
from . import Image, ImageFile, ImagePalette
|
||||
from ._binary import i8, i16le as i16, o8, o16le as o16, o32le as o32
|
||||
|
||||
__version__ = "0.3"
|
||||
|
||||
|
@ -26,9 +27,6 @@ __version__ = "0.3"
|
|||
# --------------------------------------------------------------------
|
||||
# Read RGA file
|
||||
|
||||
i8 = _binary.i8
|
||||
i16 = _binary.i16le
|
||||
|
||||
|
||||
MODES = {
|
||||
# map imagetype/depth to rawmode
|
||||
|
@ -132,10 +130,6 @@ class TgaImageFile(ImageFile.ImageFile):
|
|||
# --------------------------------------------------------------------
|
||||
# Write TGA file
|
||||
|
||||
o8 = _binary.o8
|
||||
o16 = _binary.o16le
|
||||
o32 = _binary.o32le
|
||||
|
||||
SAVE = {
|
||||
"1": ("1", 1, 0, 3),
|
||||
"L": ("L", 8, 0, 3),
|
||||
|
|
|
@ -41,10 +41,8 @@
|
|||
|
||||
from __future__ import division, print_function
|
||||
|
||||
from PIL import Image, ImageFile
|
||||
from PIL import ImagePalette
|
||||
from PIL import _binary
|
||||
from PIL import TiffTags
|
||||
from . import Image, ImageFile, ImagePalette, TiffTags
|
||||
from ._binary import i8, o8
|
||||
|
||||
import collections
|
||||
from fractions import Fraction
|
||||
|
@ -71,9 +69,6 @@ IFD_LEGACY_API = True
|
|||
II = b"II" # little-endian (Intel style)
|
||||
MM = b"MM" # big-endian (Motorola style)
|
||||
|
||||
i8 = _binary.i8
|
||||
o8 = _binary.o8
|
||||
|
||||
#
|
||||
# --------------------------------------------------------------------
|
||||
# Read TIFF files
|
||||
|
@ -132,7 +127,7 @@ COMPRESSION_INFO = {
|
|||
34677: "tiff_sgilog24",
|
||||
}
|
||||
|
||||
COMPRESSION_INFO_REV = dict([(v, k) for (k, v) in COMPRESSION_INFO.items()])
|
||||
COMPRESSION_INFO_REV = {v: k for k, v in COMPRESSION_INFO.items()}
|
||||
|
||||
OPEN_INFO = {
|
||||
# (ByteOrder, PhotoInterpretation, SampleFormat, FillOrder, BitsPerSample,
|
||||
|
@ -278,12 +273,12 @@ class IFDRational(Rational):
|
|||
self._numerator = value
|
||||
self._val = float(1)
|
||||
|
||||
if type(value) == Fraction:
|
||||
if isinstance(value, Fraction):
|
||||
self._numerator = value.numerator
|
||||
self._denominator = value.denominator
|
||||
self._val = value
|
||||
|
||||
if type(value) == IFDRational:
|
||||
if isinstance(value, IFDRational):
|
||||
self._denominator = value.denominator
|
||||
self._numerator = value.numerator
|
||||
self._val = value._val
|
||||
|
@ -294,11 +289,7 @@ class IFDRational(Rational):
|
|||
return
|
||||
|
||||
elif denominator == 1:
|
||||
if sys.hexversion < 0x2070000 and type(value) == float:
|
||||
# python 2.6 is different.
|
||||
self._val = Fraction.from_float(value)
|
||||
else:
|
||||
self._val = Fraction(value)
|
||||
self._val = Fraction(value)
|
||||
else:
|
||||
self._val = Fraction(value, denominator)
|
||||
|
||||
|
@ -342,7 +333,7 @@ class IFDRational(Rational):
|
|||
'rfloordiv','mod','rmod', 'pow','rpow', 'pos', 'neg',
|
||||
'abs', 'trunc', 'lt', 'gt', 'le', 'ge', 'nonzero',
|
||||
'ceil', 'floor', 'round']
|
||||
print "\n".join("__%s__ = _delegate('__%s__')" % (s,s) for s in a)
|
||||
print("\n".join("__%s__ = _delegate('__%s__')" % (s,s) for s in a))
|
||||
"""
|
||||
|
||||
__add__ = _delegate('__add__')
|
||||
|
@ -573,7 +564,7 @@ class ImageFileDirectory_v2(collections.MutableMapping):
|
|||
|
||||
def _register_loader(idx, size):
|
||||
def decorator(func):
|
||||
from PIL.TiffTags import TYPES
|
||||
from .TiffTags import TYPES
|
||||
if func.__name__.startswith("load_"):
|
||||
TYPES[idx] = func.__name__[5:].replace("_", " ")
|
||||
_load_dispatch[idx] = size, func
|
||||
|
@ -587,12 +578,12 @@ class ImageFileDirectory_v2(collections.MutableMapping):
|
|||
return decorator
|
||||
|
||||
def _register_basic(idx_fmt_name):
|
||||
from PIL.TiffTags import TYPES
|
||||
from .TiffTags import TYPES
|
||||
idx, fmt, name = idx_fmt_name
|
||||
TYPES[idx] = name
|
||||
size = struct.calcsize("=" + fmt)
|
||||
_load_dispatch[idx] = size, lambda self, data, legacy_api=True: (
|
||||
self._unpack("{0}{1}".format(len(data) // size, fmt), data))
|
||||
self._unpack("{}{}".format(len(data) // size, fmt), data))
|
||||
_write_dispatch[idx] = lambda self, *values: (
|
||||
b"".join(self._pack(fmt, value) for value in values))
|
||||
|
||||
|
@ -624,7 +615,7 @@ class ImageFileDirectory_v2(collections.MutableMapping):
|
|||
|
||||
@_register_loader(5, 8)
|
||||
def load_rational(self, data, legacy_api=True):
|
||||
vals = self._unpack("{0}L".format(len(data) // 4), data)
|
||||
vals = self._unpack("{}L".format(len(data) // 4), data)
|
||||
combine = lambda a, b: (a, b) if legacy_api else IFDRational(a, b)
|
||||
return tuple(combine(num, denom)
|
||||
for num, denom in zip(vals[::2], vals[1::2]))
|
||||
|
@ -644,7 +635,7 @@ class ImageFileDirectory_v2(collections.MutableMapping):
|
|||
|
||||
@_register_loader(10, 8)
|
||||
def load_signed_rational(self, data, legacy_api=True):
|
||||
vals = self._unpack("{0}l".format(len(data) // 4), data)
|
||||
vals = self._unpack("{}l".format(len(data) // 4), data)
|
||||
combine = lambda a, b: (a, b) if legacy_api else IFDRational(a, b)
|
||||
return tuple(combine(num, denom)
|
||||
for num, denom in zip(vals[::2], vals[1::2]))
|
||||
|
@ -804,7 +795,7 @@ class ImageFileDirectory_v1(ImageFileDirectory_v2):
|
|||
ifd = ImageFileDirectory_v1()
|
||||
ifd[key] = 'Some Data'
|
||||
ifd.tagtype[key] = 2
|
||||
print ifd[key]
|
||||
print(ifd[key])
|
||||
('Some Data',)
|
||||
|
||||
Also contains a dictionary of tag types as read from the tiff image file,
|
||||
|
@ -1010,9 +1001,6 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
# Section 14: Differencing Predictor
|
||||
self.decoderconfig = (self.tag_v2[PREDICTOR],)
|
||||
|
||||
if ICCPROFILE in self.tag_v2:
|
||||
self.info['icc_profile'] = self.tag_v2[ICCPROFILE]
|
||||
|
||||
return args
|
||||
|
||||
def load(self):
|
||||
|
@ -1056,7 +1044,7 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
# io.BytesIO have a fileno, but returns an IOError if
|
||||
# it doesn't use a file descriptor.
|
||||
fp = False
|
||||
|
||||
|
||||
if fp:
|
||||
args[2] = fp
|
||||
|
||||
|
@ -1175,11 +1163,15 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
yres = self.tag_v2.get(Y_RESOLUTION, 1)
|
||||
|
||||
if xres and yres:
|
||||
resunit = self.tag_v2.get(RESOLUTION_UNIT, 1)
|
||||
resunit = self.tag_v2.get(RESOLUTION_UNIT)
|
||||
if resunit == 2: # dots per inch
|
||||
self.info["dpi"] = xres, yres
|
||||
elif resunit == 3: # dots per centimeter. convert to dpi
|
||||
self.info["dpi"] = xres * 2.54, yres * 2.54
|
||||
elif resunit == None: # used to default to 1, but now 2)
|
||||
self.info["dpi"] = xres, yres
|
||||
# For backward compatibility, we also preserve the old behavior.
|
||||
self.info["resolution"] = xres, yres
|
||||
else: # No absolute unit of measurement
|
||||
self.info["resolution"] = xres, yres
|
||||
|
||||
|
@ -1201,7 +1193,7 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
"tiff_sgilog24",
|
||||
"tiff_raw_16"]:
|
||||
# if DEBUG:
|
||||
# print "Activating g4 compression for whole file"
|
||||
# print("Activating g4 compression for whole file")
|
||||
|
||||
# Decoder expects entire file as one tile.
|
||||
# There's a buffer size limit in load (64k)
|
||||
|
@ -1246,12 +1238,12 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
a = None
|
||||
|
||||
else:
|
||||
for i in range(len(offsets)):
|
||||
for i, offset in enumerate(offsets):
|
||||
a = self._decoder(rawmode, l, i)
|
||||
self.tile.append(
|
||||
(self._compression,
|
||||
(0, min(y, ysize), w, min(y+h, ysize)),
|
||||
offsets[i], a))
|
||||
offset, a))
|
||||
if DEBUG:
|
||||
print("tiles: ", self.tile)
|
||||
y = y + h
|
||||
|
@ -1285,6 +1277,10 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
print("- unsupported data organization")
|
||||
raise SyntaxError("unknown data organization")
|
||||
|
||||
# Fix up info.
|
||||
if ICCPROFILE in self.tag_v2:
|
||||
self.info['icc_profile'] = self.tag_v2[ICCPROFILE]
|
||||
|
||||
# fixup palette descriptor
|
||||
|
||||
if self.mode == "P":
|
||||
|
@ -1366,10 +1362,10 @@ def _save(im, fp, filename):
|
|||
ifd[key] = im.tag_v2[key]
|
||||
ifd.tagtype[key] = im.tag_v2.tagtype[key]
|
||||
|
||||
# preserve ICC profile (should also work when saving other formats
|
||||
# which support profiles as TIFF) -- 2008-06-06 Florian Hoech
|
||||
if "icc_profile" in im.info:
|
||||
ifd[ICCPROFILE] = im.info["icc_profile"]
|
||||
# preserve ICC profile (should also work when saving other formats
|
||||
# which support profiles as TIFF) -- 2008-06-06 Florian Hoech
|
||||
if "icc_profile" in im.info:
|
||||
ifd[ICCPROFILE] = im.info["icc_profile"]
|
||||
|
||||
for key, name in [(IMAGEDESCRIPTION, "description"),
|
||||
(X_RESOLUTION, "resolution"),
|
||||
|
@ -1518,7 +1514,7 @@ class AppendingTiffWriter:
|
|||
# JPEGQTables = 519
|
||||
# JPEGDCTables = 520
|
||||
# JPEGACTables = 521
|
||||
Tags = set((273, 288, 324, 519, 520, 521))
|
||||
Tags = {273, 288, 324, 519, 520, 521}
|
||||
|
||||
def __init__(self, fn, new=False):
|
||||
if hasattr(fn, 'read'):
|
||||
|
|
|
@ -418,13 +418,13 @@ TYPES = {}
|
|||
|
||||
# some of these are not in our TAGS_V2 dict and were included from tiff.h
|
||||
|
||||
LIBTIFF_CORE = set([255, 256, 257, 258, 259, 262, 263, 266, 274, 277,
|
||||
278, 280, 281, 340, 341, 282, 283, 284, 286, 287,
|
||||
296, 297, 321, 320, 338, 32995, 322, 323, 32998,
|
||||
32996, 339, 32997, 330, 531, 530, 301, 532, 333,
|
||||
# as above
|
||||
269 # this has been in our tests forever, and works
|
||||
])
|
||||
LIBTIFF_CORE = {255, 256, 257, 258, 259, 262, 263, 266, 274, 277,
|
||||
278, 280, 281, 340, 341, 282, 283, 284, 286, 287,
|
||||
296, 297, 321, 320, 338, 32995, 322, 323, 32998,
|
||||
32996, 339, 32997, 330, 531, 530, 301, 532, 333,
|
||||
# as above
|
||||
269 # this has been in our tests forever, and works
|
||||
}
|
||||
|
||||
LIBTIFF_CORE.remove(320) # Array of short, crashes
|
||||
LIBTIFF_CORE.remove(301) # Array of short, crashes
|
||||
|
|
|
@ -23,7 +23,8 @@
|
|||
|
||||
from __future__ import print_function
|
||||
|
||||
from PIL import Image, _binary
|
||||
from . import Image
|
||||
from ._binary import i32le as i32
|
||||
|
||||
try:
|
||||
import builtins
|
||||
|
@ -31,8 +32,6 @@ except ImportError:
|
|||
import __builtin__
|
||||
builtins = __builtin__
|
||||
|
||||
i32 = _binary.i32le
|
||||
|
||||
|
||||
def open(filename):
|
||||
"""
|
||||
|
@ -47,33 +46,35 @@ def open(filename):
|
|||
# FIXME: modify to return a WalImageFile instance instead of
|
||||
# plain Image object ?
|
||||
|
||||
def imopen(fp):
|
||||
# read header fields
|
||||
header = fp.read(32+24+32+12)
|
||||
size = i32(header, 32), i32(header, 36)
|
||||
offset = i32(header, 40)
|
||||
|
||||
# load pixel data
|
||||
fp.seek(offset)
|
||||
|
||||
Image._decompression_bomb_check(size)
|
||||
im = Image.frombytes("P", size, fp.read(size[0] * size[1]))
|
||||
im.putpalette(quake2palette)
|
||||
|
||||
im.format = "WAL"
|
||||
im.format_description = "Quake2 Texture"
|
||||
|
||||
# strings are null-terminated
|
||||
im.info["name"] = header[:32].split(b"\0", 1)[0]
|
||||
next_name = header[56:56+32].split(b"\0", 1)[0]
|
||||
if next_name:
|
||||
im.info["next_name"] = next_name
|
||||
|
||||
return im
|
||||
|
||||
if hasattr(filename, "read"):
|
||||
fp = filename
|
||||
return imopen(filename)
|
||||
else:
|
||||
fp = builtins.open(filename, "rb")
|
||||
|
||||
# read header fields
|
||||
header = fp.read(32+24+32+12)
|
||||
size = i32(header, 32), i32(header, 36)
|
||||
offset = i32(header, 40)
|
||||
|
||||
# load pixel data
|
||||
fp.seek(offset)
|
||||
|
||||
im = Image.frombytes("P", size, fp.read(size[0] * size[1]))
|
||||
im.putpalette(quake2palette)
|
||||
|
||||
im.format = "WAL"
|
||||
im.format_description = "Quake2 Texture"
|
||||
|
||||
# strings are null-terminated
|
||||
im.info["name"] = header[:32].split(b"\0", 1)[0]
|
||||
next_name = header[56:56+32].split(b"\0", 1)[0]
|
||||
if next_name:
|
||||
im.info["next_name"] = next_name
|
||||
|
||||
return im
|
||||
|
||||
with builtins.open(filename, "rb") as fp:
|
||||
return imopen(fp)
|
||||
|
||||
quake2palette = (
|
||||
# default palette taken from piffo 0.93 by Hans Häggström
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
from PIL import Image
|
||||
from PIL import ImageFile
|
||||
from . import Image, ImageFile, _webp
|
||||
from io import BytesIO
|
||||
from PIL import _webp
|
||||
|
||||
|
||||
_VALID_WEBP_MODES = {
|
||||
|
@ -43,7 +41,7 @@ class WebPImageFile(ImageFile.ImageFile):
|
|||
self.tile = [("raw", (0, 0) + self.size, 0, self.mode)]
|
||||
|
||||
def _getexif(self):
|
||||
from PIL.JpegImagePlugin import _getexif
|
||||
from .JpegImagePlugin import _getexif
|
||||
return _getexif(self)
|
||||
|
||||
|
||||
|
|
|
@ -14,8 +14,17 @@
|
|||
#
|
||||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
# WMF/EMF reference documentation:
|
||||
# https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-WMF/[MS-WMF].pdf
|
||||
# http://wvware.sourceforge.net/caolan/index.html
|
||||
# http://wvware.sourceforge.net/caolan/ora-wmf.html
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
from . import Image, ImageFile
|
||||
from ._binary import i16le as word, si16le as short, i32le as dword, si32le as _long
|
||||
|
||||
|
||||
from PIL import Image, ImageFile, _binary
|
||||
|
||||
__version__ = "0.2"
|
||||
|
||||
|
@ -53,20 +62,6 @@ if hasattr(Image.core, "drawwmf"):
|
|||
|
||||
register_handler(WmfHandler())
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
word = _binary.i16le
|
||||
|
||||
|
||||
def short(c, o=0):
|
||||
v = word(c, o)
|
||||
if v >= 32768:
|
||||
v -= 65536
|
||||
return v
|
||||
|
||||
dword = _binary.i32le
|
||||
|
||||
|
||||
#
|
||||
# --------------------------------------------------------------------
|
||||
# Read WMF file
|
||||
|
@ -111,7 +106,7 @@ class WmfStubImageFile(ImageFile.StubImageFile):
|
|||
|
||||
self.info["dpi"] = 72
|
||||
|
||||
# print self.mode, self.size, self.info
|
||||
# print(self.mode, self.size, self.info)
|
||||
|
||||
# sanity check (standard metafile header)
|
||||
if s[22:26] != b"\x01\x00\t\x00":
|
||||
|
@ -121,13 +116,13 @@ class WmfStubImageFile(ImageFile.StubImageFile):
|
|||
# enhanced metafile
|
||||
|
||||
# get bounding box
|
||||
x0 = dword(s, 8)
|
||||
y0 = dword(s, 12)
|
||||
x1 = dword(s, 16)
|
||||
y1 = dword(s, 20)
|
||||
x0 = _long(s, 8)
|
||||
y0 = _long(s, 12)
|
||||
x1 = _long(s, 16)
|
||||
y1 = _long(s, 20)
|
||||
|
||||
# get frame (in 0.01 millimeter units)
|
||||
frame = dword(s, 24), dword(s, 28), dword(s, 32), dword(s, 36)
|
||||
frame = _long(s, 24), _long(s, 28), _long(s, 32), _long(s, 36)
|
||||
|
||||
# normalize size to 72 dots per inch
|
||||
size = x1 - x0, y1 - y0
|
||||
|
|
|
@ -17,12 +17,11 @@
|
|||
# FIXME: make save work (this requires quantization support)
|
||||
#
|
||||
|
||||
from PIL import Image, ImageFile, ImagePalette, _binary
|
||||
from . import Image, ImageFile, ImagePalette
|
||||
from ._binary import o8
|
||||
|
||||
__version__ = "0.1"
|
||||
|
||||
o8 = _binary.o8
|
||||
|
||||
_MAGIC = b"P7 332"
|
||||
|
||||
# standard color palette for thumbnails (RGB332)
|
||||
|
|
|
@ -20,13 +20,13 @@
|
|||
#
|
||||
|
||||
import re
|
||||
from PIL import Image, ImageFile
|
||||
from . import Image, ImageFile
|
||||
|
||||
__version__ = "0.6"
|
||||
|
||||
# XBM header
|
||||
xbm_head = re.compile(
|
||||
b"\s*#define[ \t]+.*_width[ \t]+(?P<width>[0-9]+)[\r\n]+"
|
||||
br"\s*#define[ \t]+.*_width[ \t]+(?P<width>[0-9]+)[\r\n]+"
|
||||
b"#define[ \t]+.*_height[ \t]+(?P<height>[0-9]+)[\r\n]+"
|
||||
b"(?P<hotspot>"
|
||||
b"#define[ \t]+[^_]*_x_hot[ \t]+(?P<xhot>[0-9]+)[\r\n]+"
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
|
||||
|
||||
import re
|
||||
from PIL import Image, ImageFile, ImagePalette
|
||||
from PIL._binary import i8, o8
|
||||
from . import Image, ImageFile, ImagePalette
|
||||
from ._binary import i8, o8
|
||||
|
||||
__version__ = "0.2"
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
# ;-)
|
||||
|
||||
VERSION = '1.1.7' # PIL version
|
||||
PILLOW_VERSION = '3.4.0.dev0' # Pillow
|
||||
PILLOW_VERSION = '4.1.0.dev0' # Pillow
|
||||
|
||||
__version__ = PILLOW_VERSION
|
||||
|
||||
|
|
|
@ -28,26 +28,43 @@ else:
|
|||
|
||||
|
||||
# Input, le = little endian, be = big endian
|
||||
# TODO: replace with more readable struct.unpack equivalent
|
||||
def i16le(c, o=0):
|
||||
"""
|
||||
Converts a 2-bytes (16 bits) string to an integer.
|
||||
Converts a 2-bytes (16 bits) string to an unsigned integer.
|
||||
|
||||
c: string containing bytes to convert
|
||||
o: offset of bytes to convert in string
|
||||
"""
|
||||
return unpack("<H", c[o:o+2])[0]
|
||||
|
||||
def si16le(c, o=0):
|
||||
"""
|
||||
Converts a 2-bytes (16 bits) string to a signed integer.
|
||||
|
||||
c: string containing bytes to convert
|
||||
o: offset of bytes to convert in string
|
||||
"""
|
||||
return unpack("<h", c[o:o+2])[0]
|
||||
|
||||
|
||||
def i32le(c, o=0):
|
||||
"""
|
||||
Converts a 4-bytes (32 bits) string to an integer.
|
||||
Converts a 4-bytes (32 bits) string to an unsigned integer.
|
||||
|
||||
c: string containing bytes to convert
|
||||
o: offset of bytes to convert in string
|
||||
"""
|
||||
return unpack("<I", c[o:o+4])[0]
|
||||
|
||||
def si32le(c, o=0):
|
||||
"""
|
||||
Converts a 4-bytes (32 bits) string to a signed integer.
|
||||
|
||||
c: string containing bytes to convert
|
||||
o: offset of bytes to convert in string
|
||||
"""
|
||||
return unpack("<i", c[o:o+4])[0]
|
||||
|
||||
|
||||
def i16be(c, o=0):
|
||||
return unpack(">H", c[o:o+2])[0]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from PIL import Image
|
||||
from . import Image
|
||||
|
||||
modules = {
|
||||
"pil": "PIL._imaging",
|
||||
|
@ -17,7 +17,7 @@ def check_module(feature):
|
|||
module = modules[feature]
|
||||
|
||||
method_to_call = None
|
||||
if type(module) is tuple:
|
||||
if isinstance(module, tuple):
|
||||
module, method_to_call = module
|
||||
|
||||
try:
|
||||
|
|
|
@ -10,10 +10,6 @@ Install::
|
|||
|
||||
pip install coverage nose
|
||||
|
||||
If you're using Python 2.6, there's one additional dependency::
|
||||
|
||||
pip install unittest2
|
||||
|
||||
Execution
|
||||
---------
|
||||
|
||||
|
|
|
@ -7,13 +7,8 @@ class TestJ2kEncodeOverflow(PillowTestCase):
|
|||
|
||||
im = Image.new('RGBA', (1024, 131584))
|
||||
target = self.tempfile('temp.jpc')
|
||||
try:
|
||||
with self.assertRaises(IOError):
|
||||
im.save(target)
|
||||
self.assertTrue(False, "Expected IOError, save succeeded?")
|
||||
except IOError as err:
|
||||
self.assertTrue(True, "IOError is expected")
|
||||
except Exception as err:
|
||||
self.assertTrue(False, "Expected IOError, got %s" % type(err))
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -10,13 +10,9 @@ class TestLibtiffSegfault(PillowTestCase):
|
|||
libtiff >= 4.0.0
|
||||
"""
|
||||
|
||||
try:
|
||||
with self.assertRaises(IOError):
|
||||
im = Image.open(TEST_FILE)
|
||||
im.load()
|
||||
except IOError:
|
||||
self.assertTrue(True, "Got expected IOError")
|
||||
except Exception:
|
||||
self.fail("Should have returned IOError")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -5,11 +5,22 @@ from __future__ import print_function
|
|||
import sys
|
||||
import tempfile
|
||||
import os
|
||||
import unittest
|
||||
|
||||
if sys.version_info[:2] <= (2, 6):
|
||||
import unittest2 as unittest
|
||||
else:
|
||||
import unittest
|
||||
from PIL import Image, ImageMath
|
||||
|
||||
|
||||
def convert_to_comparable(a, b):
|
||||
new_a, new_b = a, b
|
||||
if a.mode == 'P':
|
||||
new_a = Image.new('L', a.size)
|
||||
new_b = Image.new('L', b.size)
|
||||
new_a.putdata(a.getdata())
|
||||
new_b.putdata(b.getdata())
|
||||
elif a.mode == 'I;16':
|
||||
new_a = a.convert('I')
|
||||
new_b = b.convert('I')
|
||||
return new_a, new_b
|
||||
|
||||
|
||||
class PillowTestCase(unittest.TestCase):
|
||||
|
@ -49,7 +60,7 @@ class PillowTestCase(unittest.TestCase):
|
|||
len(a), len(b),
|
||||
msg or "got length %s, expected %s" % (len(a), len(b)))
|
||||
self.assertTrue(
|
||||
all([x == y for x, y in zip(a, b)]),
|
||||
all(x == y for x, y in zip(a, b)),
|
||||
msg or "got %s, expected %s" % (a, b))
|
||||
except:
|
||||
self.assertEqual(a, b, msg)
|
||||
|
@ -84,14 +95,13 @@ class PillowTestCase(unittest.TestCase):
|
|||
a.size, b.size,
|
||||
msg or "got size %r, expected %r" % (a.size, b.size))
|
||||
|
||||
a, b = convert_to_comparable(a, b)
|
||||
|
||||
diff = 0
|
||||
try:
|
||||
ord(b'0')
|
||||
for abyte, bbyte in zip(a.tobytes(), b.tobytes()):
|
||||
diff += abs(ord(abyte)-ord(bbyte))
|
||||
except:
|
||||
for abyte, bbyte in zip(a.tobytes(), b.tobytes()):
|
||||
diff += abs(abyte-bbyte)
|
||||
for ach, bch in zip(a.split(), b.split()):
|
||||
chdiff = ImageMath.eval("abs(a - b)", a=ach, b=bch).convert('L')
|
||||
diff += sum(i * num for i, num in enumerate(chdiff.histogram()))
|
||||
|
||||
ave_diff = float(diff)/(a.size[0]*a.size[1])
|
||||
self.assertGreaterEqual(
|
||||
epsilon, ave_diff,
|
||||
|
@ -139,9 +149,13 @@ class PillowTestCase(unittest.TestCase):
|
|||
if skip:
|
||||
self.skipTest(msg or "Known Bad Test")
|
||||
|
||||
def shortDescription(self):
|
||||
# Prevents `nose -v` printing docstrings
|
||||
return None
|
||||
|
||||
def tempfile(self, template):
|
||||
assert template[:5] in ("temp.", "temp_")
|
||||
(fd, path) = tempfile.mkstemp(template[4:], template[:4])
|
||||
fd, path = tempfile.mkstemp(template[4:], template[:4])
|
||||
os.close(fd)
|
||||
|
||||
self.addCleanup(self.delete_tempfile, path)
|
||||
|
|
BIN
Tests/images/bmp/q/rgb32bf-xbgr.bmp
Normal file
BIN
Tests/images/bmp/q/rgb32bf-xbgr.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
BIN
Tests/images/drawing.emf
Normal file
BIN
Tests/images/drawing.emf
Normal file
Binary file not shown.
BIN
Tests/images/drawing.wmf
Normal file
BIN
Tests/images/drawing.wmf
Normal file
Binary file not shown.
BIN
Tests/images/drawing_emf_ref.png
Normal file
BIN
Tests/images/drawing_emf_ref.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
BIN
Tests/images/drawing_wmf_ref.png
Normal file
BIN
Tests/images/drawing_wmf_ref.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 531 B |
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Tests/images/hopper.sgi
Normal file
BIN
Tests/images/hopper.sgi
Normal file
Binary file not shown.
BIN
Tests/images/hopper_256x256.ico
Normal file
BIN
Tests/images/hopper_256x256.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 200 KiB |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user