Just for fun, yapf-formatting of PIL/*.py

And amazingly all tests pass! https://github.com/google/yapf
This commit is contained in:
Alex Clark 2015-04-02 06:24:51 -04:00
parent d754598f14
commit 3bb6b14313
82 changed files with 1653 additions and 2014 deletions

View File

@ -20,7 +20,6 @@
from PIL import Image
from PIL import FontFile
# --------------------------------------------------------------------
# parse X Bitmap Distribution Format (BDF)
# --------------------------------------------------------------------
@ -34,11 +33,7 @@ bdf_slant = {
"OT": "Other"
}
bdf_spacing = {
"P": "Proportional",
"M": "Monospaced",
"C": "Cell"
}
bdf_spacing = {"P": "Proportional", "M": "Monospaced", "C": "Cell"}
def bdf_char(f):
@ -82,12 +77,11 @@ def bdf_char(f):
return id, int(props["ENCODING"]), bbox, im
##
# Font file plugin for the X11 BDF format.
class BdfFontFile(FontFile.FontFile):
class BdfFontFile(FontFile.FontFile):
def __init__(self, fp):
FontFile.FontFile.__init__(self)

View File

@ -23,14 +23,11 @@
# See the README file for information on usage and redistribution.
#
__version__ = "0.7"
from PIL import Image, ImageFile, ImagePalette, _binary
import math
i8 = _binary.i8
i16 = _binary.i16le
i32 = _binary.i32le
@ -67,7 +64,14 @@ class BmpImageFile(ImageFile.ImageFile):
format_description = "Windows Bitmap"
format = "BMP"
# --------------------------------------------------- BMP Compression values
COMPRESSIONS = {'RAW': 0, 'RLE8': 1, 'RLE4': 2, 'BITFIELDS': 3, 'JPEG': 4, 'PNG': 5}
COMPRESSIONS = {
'RAW': 0,
'RLE8': 1,
'RLE4': 2,
'BITFIELDS': 3,
'JPEG': 4,
'PNG': 5
}
RAW, RLE8, RLE4, BITFIELDS, JPEG, PNG = 0, 1, 2, 3, 4, 5
def _bitmap(self, header=0, offset=0):
@ -76,10 +80,14 @@ class BmpImageFile(ImageFile.ImageFile):
if header:
seek(header)
file_info = dict()
file_info['header_size'] = i32(read(4)) # read bmp header size @offset 14 (this is part of the header size)
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
header_data = ImageFile._safe_read(self.fp, file_info['header_size'] - 4) # read the rest of the bmp header, without its size
header_data = ImageFile._safe_read(
self.fp, file_info['header_size'] - 4
) # read the rest of the bmp header, without its size
# --------------------------------------------------- IBM OS/2 Bitmap v1
# ------ This format has different offsets because of width/height types
if file_info['header_size'] == 12:
@ -90,59 +98,87 @@ class BmpImageFile(ImageFile.ImageFile):
file_info['compression'] = self.RAW
file_info['palette_padding'] = 3
# ---------------------------------------------- Windows Bitmap v2 to v5
elif file_info['header_size'] in (40, 64, 108, 124): # v3, OS/2 v2, v4, v5
elif file_info['header_size'] in (40, 64, 108,
124): # v3, OS/2 v2, v4, v5
if file_info['header_size'] >= 40: # v3 and OS/2
file_info['y_flip'] = i8(header_data[7]) == 0xff
file_info['direction'] = 1 if file_info['y_flip'] else -1
file_info['width'] = i32(header_data[0:4])
file_info['height'] = i32(header_data[4:8]) if not file_info['y_flip'] else 2**32 - i32(header_data[4:8])
file_info['height'] = i32(header_data[4:8]) if not file_info[
'y_flip'
] else 2 ** 32 - i32(header_data[4:8])
file_info['planes'] = i16(header_data[8:10])
file_info['bits'] = i16(header_data[10:12])
file_info['compression'] = i32(header_data[12:16])
file_info['data_size'] = i32(header_data[16:20]) # byte size of pixel data
file_info['pixels_per_meter'] = (i32(header_data[20:24]), i32(header_data[24:28]))
file_info['data_size'] = i32(header_data[16:20]
) # byte size of pixel data
file_info['pixels_per_meter'] = (i32(header_data[20:24]),
i32(header_data[24:28]))
file_info['colors'] = i32(header_data[28:32])
file_info['palette_padding'] = 4
self.info["dpi"] = tuple(map(lambda x: math.ceil(x / 39.3701), file_info['pixels_per_meter']))
self.info["dpi"] = tuple(map(lambda x: math.ceil(x / 39.3701),
file_info['pixels_per_meter']))
if file_info['compression'] == self.BITFIELDS:
if len(header_data) >= 52:
for idx, mask in enumerate(['r_mask', 'g_mask', 'b_mask', 'a_mask']):
file_info[mask] = i32(header_data[36+idx*4:40+idx*4])
for idx, mask in enumerate(['r_mask', 'g_mask',
'b_mask', 'a_mask']):
file_info[mask] = i32(
header_data[36 + idx * 4:40 + idx * 4])
else:
for mask in ['r_mask', 'g_mask', 'b_mask', 'a_mask']:
file_info[mask] = i32(read(4))
file_info['rgb_mask'] = (file_info['r_mask'], file_info['g_mask'], file_info['b_mask'])
file_info['rgba_mask'] = (file_info['r_mask'], file_info['g_mask'], file_info['b_mask'], file_info['a_mask'])
file_info['rgb_mask'] = (file_info['r_mask'],
file_info['g_mask'],
file_info['b_mask'])
file_info['rgba_mask'] = (
file_info['r_mask'], file_info['g_mask'],
file_info['b_mask'], file_info['a_mask'])
else:
raise IOError("Unsupported BMP header type (%d)" % file_info['header_size'])
raise IOError(
"Unsupported BMP header type (%d)" % file_info['header_size'])
# ------------------ Special case : header is reported 40, which
# ---------------------- is shorter than real size for bpp >= 16
self.size = file_info['width'], file_info['height']
# -------- If color count was not found in the header, compute from bits
file_info['colors'] = file_info['colors'] if file_info.get('colors', 0) else (1 << file_info['bits'])
file_info['colors'] = file_info['colors'] if file_info.get(
'colors', 0) else (1 << file_info['bits'])
# -------------------------------- Check abnormal values for DOS attacks
if file_info['width'] * file_info['height'] > 2 ** 31:
raise IOError("Unsupported BMP Size: (%dx%d)" % self.size)
# ----------------------- Check bit depth for unusual unsupported values
self.mode, raw_mode = BIT2MODE.get(file_info['bits'], (None, None))
if self.mode is None:
raise IOError("Unsupported BMP pixel depth (%d)" % file_info['bits'])
raise IOError(
"Unsupported BMP pixel depth (%d)" % file_info['bits'])
# ----------------- 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)],
24: [(0xff0000, 0xff00, 0xff)],
16: [(0xf800, 0x7e0, 0x1f), (0x7c00, 0x3e0, 0x1f)]}
16: [(0xf800, 0x7e0, 0x1f), (0x7c00, 0x3e0, 0x1f)]
}
MASK_MODES = {
(32, (0xff0000, 0xff00, 0xff, 0x0)): "BGRX", (32, (0xff0000, 0xff00, 0xff, 0xff000000)): "BGRA", (32, (0x0, 0x0, 0x0, 0x0)): "BGRA",
(32, (0xff0000, 0xff00, 0xff, 0x0)): "BGRX",
(32, (0xff0000, 0xff00, 0xff, 0xff000000)): "BGRA",
(32, (0x0, 0x0, 0x0, 0x0)): "BGRA",
(24, (0xff0000, 0xff00, 0xff)): "BGR",
(16, (0xf800, 0x7e0, 0x1f)): "BGR;16", (16, (0x7c00, 0x3e0, 0x1f)): "BGR;15"}
(16, (0xf800, 0x7e0, 0x1f)): "BGR;16",
(16, (0x7c00, 0x3e0, 0x1f)): "BGR;15"
}
if file_info['bits'] in SUPPORTED:
if file_info['bits'] == 32 and file_info['rgba_mask'] in SUPPORTED[file_info['bits']]:
raw_mode = MASK_MODES[(file_info['bits'], file_info['rgba_mask'])]
if file_info['bits'] == 32 and file_info[
'rgba_mask'
] in SUPPORTED[file_info['bits']]:
raw_mode = MASK_MODES[(file_info['bits'],
file_info['rgba_mask'])]
self.mode = "RGBA" if raw_mode in ("BGRA", ) else self.mode
elif file_info['bits'] in (24, 16) and file_info['rgb_mask'] in SUPPORTED[file_info['bits']]:
raw_mode = MASK_MODES[(file_info['bits'], file_info['rgb_mask'])]
elif file_info['bits'] in (
24, 16
) and file_info['rgb_mask'] in SUPPORTED[file_info['bits']]:
raw_mode = MASK_MODES[(file_info['bits'],
file_info['rgb_mask'])]
else:
raise IOError("Unsupported BMP bitfields layout")
else:
@ -151,17 +187,20 @@ class BmpImageFile(ImageFile.ImageFile):
if file_info['bits'] == 32 and header == 22: # 32-bit .cur offset
raw_mode, self.mode = "BGRA", "RGBA"
else:
raise IOError("Unsupported BMP compression (%d)" % file_info['compression'])
raise IOError(
"Unsupported BMP compression (%d)" % file_info['compression'])
# ---------------- Once the header is processed, process the palette/LUT
if self.mode == "P": # Paletted for 1, 4 and 8 bit images
# ----------------------------------------------------- 1-bit images
if not (0 < file_info['colors'] <= 65536):
raise IOError("Unsupported BMP Palette size (%d)" % file_info['colors'])
raise IOError(
"Unsupported BMP Palette size (%d)" % file_info['colors'])
else:
padding = file_info['palette_padding']
palette = read(padding * file_info['colors'])
greyscale = True
indices = (0, 255) if file_info['colors'] == 2 else list(range(file_info['colors']))
indices = (0, 255) if file_info['colors'] == 2 else list(
range(file_info['colors']))
# ------------------ Check if greyscale and ignore palette if so
for ind, val in enumerate(indices):
rgb = palette[ind * padding:ind * padding + 3]
@ -173,13 +212,16 @@ class BmpImageFile(ImageFile.ImageFile):
raw_mode = self.mode
else:
self.mode = "P"
self.palette = ImagePalette.raw("BGRX" if padding == 4 else "BGR", palette)
self.palette = ImagePalette.raw("BGRX" if padding == 4 else
"BGR", palette)
# ----------------------------- Finally set the tile data for the plugin
self.info['compression'] = file_info['compression']
self.tile = [('raw', (0, 0, file_info['width'], file_info['height']), offset or self.fp.tell(),
(raw_mode, ((file_info['width'] * file_info['bits'] + 31) >> 3) & (~3), file_info['direction'])
)]
self.tile = [('raw', (0, 0, file_info['width'], file_info['height']),
offset or self.fp.tell(),
(raw_mode,
((file_info['width'] * file_info['bits'] + 31) >> 3) &
(~3), file_info['direction']))]
def _open(self):
""" Open file, check magic number and read header """

View File

@ -13,20 +13,20 @@ from PIL import Image, ImageFile
_handler = None
##
# Install application-specific BUFR image handler.
#
# @param handler Handler object.
def register_handler(handler):
global _handler
_handler = handler
# --------------------------------------------------------------------
# Image adapter
def _accept(prefix):
return prefix[:4] == b"BUFR" or prefix[:4] == b"ZCZC"
@ -62,7 +62,6 @@ def _save(im, fp, filename):
raise IOError("BUFR save handler not installed")
_handler.save(im, fp, filename)
# --------------------------------------------------------------------
# Registry

View File

@ -16,12 +16,10 @@
# See the README file for information on usage and redistribution.
#
__version__ = "0.1"
from PIL import Image, BmpImagePlugin, _binary
#
# --------------------------------------------------------------------
@ -33,10 +31,10 @@ i32 = _binary.i32le
def _accept(prefix):
return prefix[:4] == b"\0\0\2\0"
##
# Image plugin for Windows Cursor files.
class CurImageFile(BmpImagePlugin.BmpImageFile):
format = "CUR"
@ -78,7 +76,6 @@ class CurImageFile(BmpImagePlugin.BmpImageFile):
return
#
# --------------------------------------------------------------------

View File

@ -35,10 +35,10 @@ i32 = _binary.i32le
def _accept(prefix):
return i32(prefix) == MAGIC
##
# Image plugin for the Intel DCX format.
class DcxImageFile(PcxImageFile):
format = "DCX"

View File

@ -119,8 +119,7 @@ def Ghostscript(tile, size, fp, scale=1):
f.write(s)
# Build ghostscript command
command = ["gs",
"-q", # quiet mode
command = ["gs", "-q", # quiet mode
"-g%dx%d" % size, # set output geometry (pixels)
"-r%fx%f" % res, # set input DPI (dots per inch)
"-dNOPAUSE -dSAFER", # don't pause between pages,
@ -139,7 +138,8 @@ def Ghostscript(tile, size, fp, scale=1):
# push data through ghostscript
try:
gs = subprocess.Popen(command, stdin=subprocess.PIPE,
gs = subprocess.Popen(command,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
gs.stdin.close()
status = gs.wait()
@ -161,6 +161,7 @@ class PSFile:
"""
Wrapper for bytesio object that treats either CR or LF as end of line.
"""
def __init__(self, fp):
self.fp = fp
self.char = None
@ -343,10 +344,10 @@ class EpsImageFile(ImageFile.ImageFile):
# use our custom load method by defining this method.
pass
#
# --------------------------------------------------------------------
def _save(im, fp, filename, eps=1):
"""EPS Writer for the Python Imaging Library."""

View File

@ -18,7 +18,6 @@
# Maps EXIF tags to tag names.
TAGS = {
# possibly incomplete
0x00fe: "NewSubfileType",
0x00ff: "SubfileType",
@ -151,7 +150,6 @@ TAGS = {
0xa434: "LensModel",
0xa435: "LensSerialNumber",
0xa500: "Gamma",
}
##

View File

@ -18,6 +18,7 @@ _handler = None
#
# @param handler Handler object.
def register_handler(handler):
global _handler
_handler = handler
@ -25,9 +26,11 @@ def register_handler(handler):
# --------------------------------------------------------------------
# Image adapter
def _accept(prefix):
return prefix[:6] == b"SIMPLE"
class FITSStubImageFile(ImageFile.StubImageFile):
format = "FITS"
@ -62,7 +65,6 @@ def _save(im, fp, filename):
raise IOError("FITS save handler not installed")
_handler.save(im, fp, filename)
# --------------------------------------------------------------------
# Registry

View File

@ -15,7 +15,6 @@
# See the README file for information on usage and redistribution.
#
__version__ = "0.2"
from PIL import Image, ImageFile, ImagePalette, _binary
@ -25,18 +24,18 @@ i16 = _binary.i16le
i32 = _binary.i32le
o8 = _binary.o8
#
# decoder
def _accept(prefix):
return i16(prefix[4:6]) in [0xAF11, 0xAF12]
##
# Image plugin for the FLI/FLC animation format. Use the <b>seek</b>
# method to load individual frames.
class FliImageFile(ImageFile.ImageFile):
format = "FLI"
@ -47,8 +46,8 @@ class FliImageFile(ImageFile.ImageFile):
# HEAD
s = self.fp.read(128)
magic = i16(s[4:6])
if not (magic in [0xAF11, 0xAF12] and
i16(s[14:16]) in [0, 3] and # flags
if not (magic in [0xAF11, 0xAF12] and i16(s[14:16]) in [0, 3] and
# flags
s[20:22] == b"\x00\x00"): # reserved
raise SyntaxError("not an FLI/FLC file")

View File

@ -32,10 +32,10 @@ def puti16(fp, values):
v += 65536
fp.write(_binary.o16be(v))
##
# Base class for raster font file handlers.
class FontFile:
bitmap = None

View File

@ -15,14 +15,11 @@
# See the README file for information on usage and redistribution.
#
__version__ = "0.1"
from PIL import Image, ImageFile
from PIL.OleFileIO import i8, i32, MAGIC, OleFileIO
# we map from colour field tuples to (mode, rawmode) descriptors
MODES = {
# opacity
@ -38,17 +35,17 @@ MODES = {
(0x00038000, 0x00038001, 0x00038002, 0x00037ffe): ("RGBA", "RGBA"),
}
#
# --------------------------------------------------------------------
def _accept(prefix):
return prefix[:8] == MAGIC
##
# Image plugin for the FlashPix images.
class FpxImageFile(ImageFile.ImageFile):
format = "FPX"
@ -73,10 +70,8 @@ class FpxImageFile(ImageFile.ImageFile):
#
# get the Image Contents Property Set
prop = self.ole.getproperties([
"Data Object Store %06d" % index,
"\005Image Contents"
])
prop = self.ole.getproperties(["Data Object Store %06d" % index,
"\005Image Contents"])
# size (highest resolution)
@ -121,11 +116,8 @@ class FpxImageFile(ImageFile.ImageFile):
#
# setup tile descriptors for a given subimage
stream = [
"Data Object Store %06d" % index,
"Resolution %04d" % subimage,
"Subimage 0000 Header"
]
stream = ["Data Object Store %06d" % index,
"Resolution %04d" % subimage, "Subimage 0000 Header"]
fp = self.ole.openstream(stream)
@ -214,8 +206,8 @@ class FpxImageFile(ImageFile.ImageFile):
def load(self):
if not self.fp:
self.fp = self.ole.openstream(self.stream[:2] +
["Subimage 0000 Data"])
self.fp = self.ole.openstream(
self.stream[:2] + ["Subimage 0000 Data"])
ImageFile.ImageFile.load(self)

View File

@ -21,10 +21,10 @@ i32 = _binary.i32be
def _accept(prefix):
return i32(prefix) >= 20 and i32(prefix[4:8]) == 1
##
# Image plugin for the GIMP brush format.
class GbrImageFile(ImageFile.ImageFile):
format = "GBR"

View File

@ -13,7 +13,6 @@
# See the README file for information on usage and redistribution.
#
# NOTE: This format cannot be automatically recognized, so the
# class is not registered for use with Image.open(). To open a
# gd file, use the GdImageFile.open() function instead.
@ -22,7 +21,6 @@
# implementation is provided for convenience and demonstrational
# purposes only.
__version__ = "0.1"
from PIL import ImageFile, ImagePalette, _binary
@ -36,13 +34,13 @@ except ImportError:
i16 = _binary.i16be
##
# Image plugin for the GD uncompressed format. Note that this format
# is not supported by the standard <b>Image.open</b> function. To use
# this plugin, you have to import the <b>GdImageFile</b> module and
# use the <b>GdImageFile.open</b> function.
class GdImageFile(ImageFile.ImageFile):
format = "GD"
@ -65,7 +63,6 @@ class GdImageFile(ImageFile.ImageFile):
self.tile = [("raw", (0, 0) + self.size, 775, ("L", 0, -1))]
##
# Load texture from a GD image file.
#
@ -75,6 +72,7 @@ class GdImageFile(ImageFile.ImageFile):
# @return An image instance.
# @exception IOError If the image could not be read.
def open(fp, mode="r"):
if mode != "r":

View File

@ -28,7 +28,6 @@ from PIL import Image, ImageFile, ImagePalette, _binary
__version__ = "0.9"
# --------------------------------------------------------------------
# Helpers
@ -37,18 +36,18 @@ i16 = _binary.i16le
o8 = _binary.o8
o16 = _binary.o16le
# --------------------------------------------------------------------
# Identify/read GIF files
def _accept(prefix):
return prefix[:6] in [b"GIF87a", b"GIF89a"]
##
# Image plugin for GIF images. This plugin supports both GIF87 and
# GIF89 images.
class GifImageFile(ImageFile.ImageFile):
format = "GIF"
@ -189,9 +188,7 @@ class GifImageFile(ImageFile.ImageFile):
# image data
bits = i8(self.fp.read(1))
self.__offset = self.fp.tell()
self.tile = [("gif",
(x0, y0, x1, y1),
self.__offset,
self.tile = [("gif", (x0, y0, x1, y1), self.__offset,
(bits, interlace))]
break
@ -251,11 +248,7 @@ try:
except ImportError:
_imaging_gif = None
RAWMODE = {
"1": "L",
"L": "L",
"P": "P",
}
RAWMODE = {"1": "L", "L": "L", "P": "P", }
def _save(im, fp, filename):
@ -326,8 +319,7 @@ def _save(im, fp, filename):
# transparency extension block
if transparent_color_exists:
fp.write(b"!" +
o8(249) + # extension intro
fp.write(b"!" + o8(249) + # extension intro
o8(4) + # length
o8(1) + # transparency info present
o16(0) + # duration
@ -335,11 +327,9 @@ def _save(im, fp, filename):
o8(0))
# local image header
fp.write(b"," +
o16(0) + o16(0) + # bounding box
fp.write(b"," + o16(0) + o16(0) + # bounding box
o16(im.size[0]) + # size
o16(im.size[1]) +
o8(flags) + # flags
o16(im.size[1]) + o8(flags) + # flags
o8(8)) # bits
im_out.encoderconfig = (8, interlace)
@ -382,7 +372,9 @@ def _save_netpbm(im, fp, filename):
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,
togif_proc = Popen(togif_cmd,
stdin=quant_proc.stdout,
stdout=f,
stderr=stderr)
# Allow ppmquant to receive SIGPIPE if ppmtogif exits
@ -401,10 +393,10 @@ def _save_netpbm(im, fp, filename):
except:
pass
# --------------------------------------------------------------------
# GIF utilities
def getheader(im, palette=None, info=None):
"""Return a list of strings representing a GIF header"""
@ -412,8 +404,7 @@ def getheader(im, palette=None, info=None):
# Header Block
# http://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp
header = [
b"GIF87a" + # signature + version
header = [b"GIF87a" + # signature + version
o16(im.size[0]) + # canvas width
o16(im.size[1]) # canvas height
]
@ -449,7 +440,8 @@ def getheader(im, palette=None, info=None):
i = 0
# pick only the used colors from the palette
for oldPosition in used_palette_colors:
palette_bytes += source_palette[oldPosition*3:oldPosition*3+3]
palette_bytes += source_palette[oldPosition * 3:oldPosition * 3
+ 3]
new_positions[oldPosition] = i
i += 1
@ -510,15 +502,13 @@ def getdata(im, offset=(0, 0), **params):
im.encoderinfo = params
# local image header
fp.write(b"," +
o16(offset[0]) + # offset
o16(offset[1]) +
o16(im.size[0]) + # size
o16(im.size[1]) +
o8(0) + # flags
fp.write(b"," + o16(offset[0]) + # offset
o16(offset[1]) + o16(im.size[0]) + # size
o16(im.size[1]) + o8(0) + # flags
o8(8)) # bits
ImageFile._save(im, fp, [("gif", (0, 0)+im.size, 0, RAWMODE[im.mode])])
ImageFile._save(im, fp, [("gif",
(0, 0) + im.size, 0, RAWMODE[im.mode])])
fp.write(b"\0") # end of image data
@ -527,7 +517,6 @@ def getdata(im, offset=(0, 0), **params):
return fp.data
# --------------------------------------------------------------------
# Registry
@ -539,5 +528,4 @@ Image.register_mime(GifImageFile.format, "image/gif")
#
# Uncomment the following line if you wish to use NETPBM/PBMPLUS
# instead of the built-in "uncompressed" GIF encoder
# Image.register_save(GifImageFile.format, _save_netpbm)

View File

@ -55,6 +55,7 @@ def sphere_increasing(middle, pos):
def sphere_decreasing(middle, pos):
return 1.0 - sqrt(1.0 - linear(middle, pos) ** 2)
SEGMENTS = [linear, curved, sine, sphere_increasing, sphere_decreasing]
@ -95,12 +96,11 @@ class GradientFile:
return b"".join(palette), "RGBA"
##
# File handler for GIMP's gradient format.
class GimpGradientFile(GradientFile):
class GimpGradientFile(GradientFile):
def __init__(self, fp):
if fp.readline()[:13] != b"GIMP Gradient":

View File

@ -17,10 +17,10 @@
import re
from PIL._binary import o8
##
# File handler for GIMP's palette format.
class GimpPaletteFile:
rawmode = "RGB"

View File

@ -13,20 +13,20 @@ from PIL import Image, ImageFile
_handler = None
##
# Install application-specific GRIB image handler.
#
# @param handler Handler object.
def register_handler(handler):
global _handler
_handler = handler
# --------------------------------------------------------------------
# Image adapter
def _accept(prefix):
return prefix[0:4] == b"GRIB" and prefix[7] == b'\x01'
@ -62,7 +62,6 @@ def _save(im, fp, filename):
raise IOError("GRIB save handler not installed")
_handler.save(im, fp, filename)
# --------------------------------------------------------------------
# Registry

View File

@ -13,20 +13,20 @@ from PIL import Image, ImageFile
_handler = None
##
# Install application-specific HDF5 image handler.
#
# @param handler Handler object.
def register_handler(handler):
global _handler
_handler = handler
# --------------------------------------------------------------------
# Image adapter
def _accept(prefix):
return prefix[:8] == b"\x89HDF\r\n\x1a\n"
@ -62,7 +62,6 @@ def _save(im, fp, filename):
raise IOError("HDF5 save handler not installed")
_handler.save(im, fp, filename)
# --------------------------------------------------------------------
# Registry

View File

@ -79,11 +79,9 @@ def read_32(fobj, start_length, size):
break
if bytesleft != 0:
raise SyntaxError(
"Error reading channel [%r left]" % bytesleft
)
band = Image.frombuffer(
"L", pixel_size, b"".join(data), "raw", "L", 0, 1
)
"Error reading channel [%r left]" % bytesleft)
band = Image.frombuffer("L", pixel_size, b"".join(data), "raw",
"L", 0, 1)
im.im.putband(band.im, band_ix)
return {"RGB": im}
@ -94,9 +92,8 @@ def read_mk(fobj, start_length, size):
fobj.seek(start)
pixel_size = (size[0] * size[2], size[1] * size[2])
sizesq = pixel_size[0] * pixel_size[1]
band = Image.frombuffer(
"L", pixel_size, fobj.read(sizesq), "raw", "L", 0, 1
)
band = Image.frombuffer("L", pixel_size, fobj.read(sizesq), "raw", "L", 0,
1)
return {"A": band}
@ -129,49 +126,25 @@ def read_png_or_jpeg2000(fobj, start_length, size):
class IcnsFile:
SIZES = {
(512, 512, 2): [
(b'ic10', read_png_or_jpeg2000),
],
(512, 512, 1): [
(b'ic09', read_png_or_jpeg2000),
],
(256, 256, 2): [
(b'ic14', read_png_or_jpeg2000),
],
(256, 256, 1): [
(b'ic08', read_png_or_jpeg2000),
],
(128, 128, 2): [
(b'ic13', read_png_or_jpeg2000),
],
(128, 128, 1): [
(b'ic07', read_png_or_jpeg2000),
(512, 512, 2): [(b'ic10', read_png_or_jpeg2000), ],
(512, 512, 1): [(b'ic09', read_png_or_jpeg2000), ],
(256, 256, 2): [(b'ic14', read_png_or_jpeg2000), ],
(256, 256, 1): [(b'ic08', read_png_or_jpeg2000), ],
(128, 128, 2): [(b'ic13', read_png_or_jpeg2000), ],
(128, 128, 1): [(b'ic07', read_png_or_jpeg2000),
(b'it32', read_32t),
(b't8mk', read_mk),
],
(64, 64, 1): [
(b'icp6', read_png_or_jpeg2000),
],
(32, 32, 2): [
(b'ic12', read_png_or_jpeg2000),
],
(48, 48, 1): [
(b'ih32', read_32),
(b'h8mk', read_mk),
],
(32, 32, 1): [
(b'icp5', read_png_or_jpeg2000),
(b't8mk', read_mk), ],
(64, 64, 1): [(b'icp6', read_png_or_jpeg2000), ],
(32, 32, 2): [(b'ic12', read_png_or_jpeg2000), ],
(48, 48, 1): [(b'ih32', read_32),
(b'h8mk', read_mk), ],
(32, 32, 1): [(b'icp5', read_png_or_jpeg2000),
(b'il32', read_32),
(b'l8mk', read_mk),
],
(16, 16, 2): [
(b'ic11', read_png_or_jpeg2000),
],
(16, 16, 1): [
(b'icp4', read_png_or_jpeg2000),
(b'l8mk', read_mk), ],
(16, 16, 2): [(b'ic11', read_png_or_jpeg2000), ],
(16, 16, 1): [(b'icp4', read_png_or_jpeg2000),
(b'is32', read_32),
(b's8mk', read_mk),
],
(b's8mk', read_mk), ],
}
def __init__(self, fobj):
@ -241,10 +214,10 @@ class IcnsFile:
pass
return im
##
# Image plugin for Mac OS icons.
class IcnsImageFile(ImageFile.ImageFile):
"""
PIL read-only image support for Mac OS .icns files.
@ -293,6 +266,7 @@ class IcnsImageFile(ImageFile.ImageFile):
self.tile = ()
self.load_end()
Image.register_open("ICNS", IcnsImageFile, lambda x: x[:4] == b'icns')
Image.register_extension("ICNS", '.icns')

View File

@ -21,7 +21,6 @@
# * http://en.wikipedia.org/wiki/ICO_(file_format)
# * http://msdn.microsoft.com/en-us/library/ms997538.aspx
__version__ = "0.1"
import struct
@ -46,8 +45,9 @@ def _save(im, fp, filename):
[(16, 16), (24, 24), (32, 32), (48, 48),
(64, 64), (128, 128), (255, 255)])
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)
filter(lambda x: False
if (x[0] > width or x[1] > height or x[0] > 255 or x[1] > 255) else
True, sizes)
sizes = sorted(sizes, key=lambda x: x[0])
fp.write(struct.pack("H", len(sizes))) # idCount(2)
offset = fp.tell() + len(sizes) * 16
@ -119,14 +119,15 @@ class IcoFile:
# See Wikipedia notes about color depth.
# We need this just to differ images with equal sizes
icon_header['color_depth'] = (icon_header['bpp'] or
icon_header['color_depth'] = (
icon_header['bpp'] or
(icon_header['nb_color'] != 0 and
ceil(log(icon_header['nb_color'],
2))) or 256)
ceil(log(icon_header['nb_color'], 2))) or 256)
icon_header['dim'] = (icon_header['width'], icon_header['height'])
icon_header['square'] = (icon_header['width'] *
icon_header['height'])
icon_header['square'] = (
icon_header['width'] * icon_header['height']
)
self.entry.append(icon_header)
@ -235,10 +236,10 @@ class IcoFile:
return im
##
# Image plugin for Windows Icon files.
class IcoImageFile(ImageFile.ImageFile):
"""
PIL read-only image support for Microsoft Windows .ico files.

View File

@ -25,14 +25,12 @@
# See the README file for information on usage and redistribution.
#
__version__ = "0.7"
import re
from PIL import Image, ImageFile, ImagePalette
from PIL._binary import i8
# --------------------------------------------------------------------
# Standard tags
@ -46,8 +44,17 @@ SCALE = "Scale (x,y)"
SIZE = "Image size (x*y)"
MODE = "Image type"
TAGS = {COMMENT: 0, DATE: 0, EQUIPMENT: 0, FRAMES: 0, LUT: 0, NAME: 0,
SCALE: 0, SIZE: 0, MODE: 0}
TAGS = {
COMMENT: 0,
DATE: 0,
EQUIPMENT: 0,
FRAMES: 0,
LUT: 0,
NAME: 0,
SCALE: 0,
SIZE: 0,
MODE: 0
}
OPEN = {
# ifunc93/p3cfunc formats
@ -88,7 +95,6 @@ for i in ["32S"]:
for i in range(2, 33):
OPEN["L*%s image" % i] = ("F", "F;%s" % i)
# --------------------------------------------------------------------
# Read IM directory
@ -101,10 +107,10 @@ def number(s):
except ValueError:
return float(s)
##
# Image plugin for the IFUNC IM file format.
class ImImageFile(ImageFile.ImageFile):
format = "IM"
@ -188,8 +194,8 @@ class ImImageFile(ImageFile.ImageFile):
else:
raise SyntaxError("Syntax error in IM header: " +
s.decode('ascii', 'replace'))
raise SyntaxError(
"Syntax error in IM header: " + s.decode('ascii', 'replace'))
if not n:
raise SyntaxError("Not an IM file")
@ -253,8 +259,10 @@ class ImImageFile(ImageFile.ImageFile):
# ever stumbled upon such a file ;-)
size = self.size[0] * self.size[1]
self.tile = [("raw", (0, 0) + self.size, offs, ("G", 0, -1)),
("raw", (0, 0)+self.size, offs+size, ("R", 0, -1)),
("raw", (0, 0)+self.size, offs+2*size, ("B", 0, -1))]
("raw", (0, 0) + self.size, offs + size,
("R", 0, -1)), ("raw",
(0, 0) + self.size, offs + 2 * size,
("B", 0, -1))]
else:
# LabEye/IFUNC files
self.tile = [("raw", (0, 0) + self.size, offs,
@ -292,21 +300,12 @@ class ImImageFile(ImageFile.ImageFile):
SAVE = {
# mode: (im type, raw mode)
"1": ("0 1", "1"),
"L": ("Greyscale", "L"),
"LA": ("LA", "LA;L"),
"P": ("Greyscale", "P"),
"PA": ("LA", "PA;L"),
"I": ("L 32S", "I;32S"),
"I;16": ("L 16", "I;16"),
"I;16L": ("L 16L", "I;16L"),
"I;16B": ("L 16B", "I;16B"),
"F": ("L 32F", "F;32F"),
"RGB": ("RGB", "RGB;L"),
"RGBA": ("RGBA", "RGBA;L"),
"RGBX": ("RGBX", "RGBX;L"),
"CMYK": ("CMYK", "CMYK;L"),
"YCbCr": ("YCC", "YCbCr;L")
"1": ("0 1", "1"), "L": ("Greyscale", "L"), "LA": ("LA", "LA;L"), "P": (
"Greyscale", "P"), "PA": ("LA", "PA;L"), "I": ("L 32S", "I;32S"
), "I;16": ("L 16", "I;16"), "I;16L": ("L 16L", "I;16L"), "I;16B": (
"L 16B", "I;16B"), "F": ("L 32F", "F;32F"), "RGB": ("RGB", "RGB;L"
), "RGBA": ("RGBA", "RGBA;L"), "RGBX": ("RGBX", "RGBX;L"), "CMYK": (
"CMYK", "CMYK;L"), "YCbCr": ("YCC", "YCbCr;L")
}

View File

@ -40,7 +40,6 @@ class _imaging_not_installed:
def __getattr__(self, id):
raise ImportError("The _imaging C module is not installed")
# Limit to around a quarter gigabyte for a 24 bit (3 bpp) image
MAX_IMAGE_PIXELS = int(1024 * 1024 * 1024 / 4 / 3)
@ -72,25 +71,20 @@ except ImportError as v:
# The _imaging C module is present, but not compiled for
# the right version (windows only). Print a warning, if
# possible.
warnings.warn(
"The _imaging extension was built for another version "
"of Python.",
RuntimeWarning
)
warnings.warn("The _imaging extension was built for another version "
"of Python.", RuntimeWarning)
elif str(v).startswith("The _imaging extension"):
warnings.warn(str(v), RuntimeWarning)
elif "Symbol not found: _PyUnicodeUCS2_FromString" in str(v):
warnings.warn(
"The _imaging extension was built for Python with UCS2 support; "
"recompile PIL or build Python --without-wide-unicode. ",
RuntimeWarning
)
RuntimeWarning)
elif "Symbol not found: _PyUnicodeUCS4_FromString" in str(v):
warnings.warn(
"The _imaging extension was built for Python with UCS4 support; "
"recompile PIL or build Python --with-wide-unicode. ",
RuntimeWarning
)
RuntimeWarning)
# Fail here anyway. Don't let people run with a mostly broken Pillow.
# see docs/porting-pil-to-pillow.rst
raise
@ -195,7 +189,6 @@ if hasattr(core, 'DEFAULT_STRATEGY'):
RLE = core.RLE
FIXED = core.FIXED
# --------------------------------------------------------------------
# Registries
@ -211,25 +204,22 @@ EXTENSION = {}
_MODEINFO = {
# NOTE: this table will be removed in future versions. use
# getmode* functions or ImageMode descriptors instead.
# official modes
"1": ("L", "L", ("1",)),
"L": ("L", "L", ("L",)),
"I": ("L", "I", ("I",)),
"F": ("L", "F", ("F",)),
"P": ("RGB", "L", ("P",)),
"RGB": ("RGB", "L", ("R", "G", "B")),
"RGBX": ("RGB", "L", ("R", "G", "B", "X")),
"RGBA": ("RGB", "L", ("R", "G", "B", "A")),
"CMYK": ("RGB", "L", ("C", "M", "Y", "K")),
"YCbCr": ("RGB", "L", ("Y", "Cb", "Cr")),
"LAB": ("RGB", "L", ("L", "A", "B")),
"HSV": ("RGB", "L", ("H", "S", "V")),
"1": ("L", "L", ("1", )), "L": ("L", "L", ("L", )), "I": ("L", "I", ("I", )
), "F": ("L", "F",
("F", )), "P": ("RGB", "L",
("P", )), "RGB": ("RGB", "L", ("R", "G", "B")
), "RGBX": ("RGB", "L",
("R", "G", "B", "X")), "RGBA": ("RGB", "L",
("R", "G", "B", "A")
), "CMYK": ("RGB", "L",
("C", "M", "Y", "K")), "YCbCr": ("RGB", "L",
("Y", "Cb", "Cr")
), "LAB": ("RGB", "L", ("L", "A", "B")), "HSV": ("RGB", "L",
("H", "S", "V")),
# Experimental modes include I;16, I;16L, I;16B, RGBa, BGR;15, and
# BGR;24. Use these modes only if you know exactly what you're
# doing...
}
if sys.byteorder == 'little':
@ -397,10 +387,10 @@ def init():
_initialized = 2
return 1
# --------------------------------------------------------------------
# Codec factories (used by tobytes/frombytes and ImageFile.load)
def _getdecoder(mode, decoder_name, args, extra=()):
# tweak arguments
@ -434,10 +424,10 @@ def _getencoder(mode, encoder_name, args, extra=()):
except AttributeError:
raise IOError("encoder %s not available" % encoder_name)
# --------------------------------------------------------------------
# Simple expression analyzer
def coerce_e(value):
return value if isinstance(value, _E) else _E(value)
@ -473,10 +463,10 @@ def _getscaleoffset(expr):
pass
raise ValueError("illegal expression")
# --------------------------------------------------------------------
# Implementation wrapper
class Image:
"""
This class represents an image object. To create
@ -594,10 +584,8 @@ class Image:
def __repr__(self):
return "<%s.%s image mode=%s size=%dx%d at 0x%X>" % (
self.__class__.__module__, self.__class__.__name__,
self.mode, self.size[0], self.size[1],
id(self)
)
self.__class__.__module__, self.__class__.__name__, self.mode,
self.size[0], self.size[1], id(self))
def _repr_png_(self):
""" iPython display hook support
@ -621,11 +609,7 @@ class Image:
raise AttributeError(name)
def __getstate__(self):
return [
self.info,
self.mode,
self.size,
self.getpalette(),
return [self.info, self.mode, self.size, self.getpalette(),
self.tobytes()]
def __setstate__(self, state):
@ -685,8 +669,7 @@ class Image:
warnings.warn(
'tostring() is deprecated. Please call tobytes() instead.',
DeprecationWarning,
stacklevel=2,
)
stacklevel=2, )
return self.tobytes(*args, **kw)
def tobitmap(self, name="image"):
@ -704,11 +687,11 @@ class Image:
if self.mode != "1":
raise ValueError("not a bitmap")
data = self.tobytes("xbm")
return b"".join([
("#define %s_width %d\n" % (name, self.size[0])).encode('ascii'),
return b"".join(
[("#define %s_width %d\n" % (name, self.size[0])).encode('ascii'),
("#define %s_height %d\n" % (name, self.size[1])).encode('ascii'),
("static char %s_bits[] = {\n" % name).encode('ascii'), data, b"};"
])
("static char %s_bits[] = {\n" % name).encode('ascii'), data,
b"};"])
def frombytes(self, data, decoder_name="raw", *args):
"""
@ -791,8 +774,12 @@ class Image:
"""
pass
def convert(self, mode=None, matrix=None, dither=None,
palette=WEB, colors=256):
def convert(self,
mode=None,
matrix=None,
dither=None,
palette=WEB,
colors=256):
"""
Returns a converted copy of this image. For the "P" mode, this
method translates pixels through the palette. If mode is
@ -895,9 +882,8 @@ class Image:
elif isinstance(t, int):
self.im.putpalettealpha(t, 0)
else:
raise ValueError("Transparency for P mode should" +
" be bytes or int")
raise ValueError(
"Transparency for P mode should" + " be bytes or int")
if mode == "P" and palette == ADAPTIVE:
im = self.im.quantize(colors)
@ -915,8 +901,8 @@ class Image:
# if we can't make a transparent color, don't leave the old
# transparency hanging around to mess us up.
del (new.info['transparency'])
warnings.warn("Couldn't allocate palette entry " +
"for transparency")
warnings.warn(
"Couldn't allocate palette entry " + "for transparency")
return new
# colorspace conversion
@ -943,8 +929,8 @@ class Image:
new_im.info['transparency'] = new_im.palette.getcolor(trns)
except:
del (new_im.info['transparency'])
warnings.warn("Couldn't allocate palette entry " +
"for transparency")
warnings.warn(
"Couldn't allocate palette entry " + "for transparency")
else:
new_im.info['transparency'] = trns
return new_im
@ -984,8 +970,7 @@ class Image:
raise ValueError("bad mode for palette image")
if self.mode != "RGB" and self.mode != "L":
raise ValueError(
"only RGB or L mode images can be quantized to a palette"
)
"only RGB or L mode images can be quantized to a palette")
im = self.im.convert("P", 1, palette.im)
return self._makeself(im)
@ -1261,8 +1246,8 @@ class Image:
if warnings:
warnings.warn(
"'offset' is deprecated; use 'ImageChops.offset' instead",
DeprecationWarning, stacklevel=2
)
DeprecationWarning,
stacklevel=2)
from PIL import ImageChops
return ImageChops.offset(self, xoffset, yoffset)
@ -1324,8 +1309,7 @@ class Image:
else:
# FIXME: use self.size here?
raise ValueError(
"cannot determine region size; use 4-item box"
)
"cannot determine region size; use 4-item box")
box = box + (box[0] + size[0], box[1] + size[1])
if isStringType(im):
@ -1582,10 +1566,8 @@ class Image:
if expand:
import math
angle = -angle * math.pi / 180
matrix = [
math.cos(angle), math.sin(angle), 0.0,
-math.sin(angle), math.cos(angle), 0.0
]
matrix = [math.cos(angle), math.sin(angle), 0.0, -math.sin(angle),
math.cos(angle), 0.0]
def transform(x, y, matrix=matrix):
(a, b, c, d, e, f) = matrix
@ -1837,8 +1819,8 @@ class Image:
"""
if self.mode == 'RGBA':
return self.convert('RGBa').transform(
size, method, data, resample, fill).convert('RGBA')
return self.convert('RGBa').transform(size, method, data, resample,
fill).convert('RGBA')
if isinstance(method, ImageTransformHandler):
return method.transform(size, self, resample=resample, fill=fill)
@ -1859,7 +1841,8 @@ class Image:
return im
def __transformer(self, box, image, method, data,
resample=NEAREST, fill=1):
resample=NEAREST,
fill=1):
# FIXME: this should be turned into a lazy operation (?)
@ -1868,8 +1851,7 @@ class Image:
if method == AFFINE:
# change argument order to match implementation
data = (data[2], data[0], data[1],
data[5], data[3], data[4])
data = (data[2], data[0], data[1], data[5], data[3], data[4])
elif method == EXTENT:
# convert extent to an affine transform
x0, y0, x1, y1 = data
@ -1879,8 +1861,7 @@ class Image:
data = (x0 + xs / 2, xs, 0, y0 + ys / 2, 0, ys)
elif method == PERSPECTIVE:
# change argument order to match implementation
data = (data[2], data[0], data[1],
data[5], data[3], data[4],
data = (data[2], data[0], data[1], data[5], data[3], data[4],
data[6], data[7])
elif method == QUAD:
# quadrilateral warp. data specifies the four corners
@ -1893,8 +1874,8 @@ class Image:
As = 1.0 / w
At = 1.0 / h
data = (x0, (ne[0] - x0) * As, (sw[0] - x0) * At,
(se[0]-sw[0]-ne[0]+x0)*As*At,
y0, (ne[1]-y0)*As, (sw[1]-y0)*At,
(se[0] - sw[0] - ne[0] + x0) * As * At, y0,
(ne[1] - y0) * As, (sw[1] - y0) * At,
(se[1] - sw[1] - ne[1] + y0) * As * At)
else:
raise ValueError("unknown transformation method")
@ -1935,12 +1916,11 @@ class Image:
im = self.im.effect_spread(distance)
return self._new(im)
# --------------------------------------------------------------------
# Lazy operations
class _ImageCrop(Image):
class _ImageCrop(Image):
def __init__(self, im, box):
Image.__init__(self)
@ -1971,10 +1951,10 @@ class _ImageCrop(Image):
# FIXME: future versions should optimize crop/paste
# sequences!
# --------------------------------------------------------------------
# Abstract handlers.
class ImagePointHandler:
# used as a mixin by point transforms (for use with im.point)
pass
@ -1984,13 +1964,13 @@ class ImageTransformHandler:
# used as a mixin by geometry transforms (for use with im.transform)
pass
# --------------------------------------------------------------------
# Factories
#
# Debugging
def _wedge():
"Create greyscale wedge (for debugging only)"
@ -2070,8 +2050,7 @@ def fromstring(*args, **kw):
warnings.warn(
'fromstring() is deprecated. Please call frombytes() instead.',
DeprecationWarning,
stacklevel=2
)
stacklevel=2)
return frombytes(*args, **kw)
@ -2121,14 +2100,13 @@ def frombuffer(mode, size, data, decoder_name="raw", *args):
"the frombuffer defaults may change in a future release; "
"for portability, change the call to read:\n"
" frombuffer(mode, size, data, 'raw', mode, 0, 1)",
RuntimeWarning, stacklevel=2
)
RuntimeWarning,
stacklevel=2)
args = mode, 0, -1 # may change to (mode, 0, 1) post-1.1.6
if args[0] in _MAPMODES:
im = new(mode, (1, 1))
im = im._new(
core.map_buffer(data, size, decoder_name, None, 0, args)
)
core.map_buffer(data, size, decoder_name, None, 0, args))
im.readonly = 1
return im
@ -2184,6 +2162,7 @@ def fromarray(obj, mode=None):
return frombuffer(mode, size, obj, "raw", rawmode, 0, 1)
_fromarray_typemap = {
# (shape, typestr) => mode, rawmode
# first two members of shape are set to one
@ -2214,11 +2193,9 @@ def _decompression_bomb_check(size):
pixels = size[0] * size[1]
if pixels > MAX_IMAGE_PIXELS:
warnings.warn(
"Image size (%d pixels) exceeds limit of %d pixels, "
warnings.warn("Image size (%d pixels) exceeds limit of %d pixels, "
"could be decompression bomb DOS attack." %
(pixels, MAX_IMAGE_PIXELS),
DecompressionBombWarning)
(pixels, MAX_IMAGE_PIXELS), DecompressionBombWarning)
def open(fp, mode="r"):
@ -2286,13 +2263,13 @@ def open(fp, mode="r"):
# traceback.print_exc()
pass
raise IOError("cannot identify image file %r"
% (filename if filename else fp))
raise IOError("cannot identify image file %r" % (filename
if filename else fp))
#
# Image processing.
def alpha_composite(im1, im2):
"""
Alpha composite im2 over im1.
@ -2389,10 +2366,10 @@ def merge(mode, bands):
im.putband(bands[i].im, i)
return bands[0]._new(im)
# --------------------------------------------------------------------
# Plugin registry
def register_open(id, factory, accept=None):
"""
Register an image file plugin. This function should not be used
@ -2440,10 +2417,10 @@ def register_extension(id, extension):
"""
EXTENSION[extension.lower()] = id.upper()
# --------------------------------------------------------------------
# Simple display support. User code may override this.
def _show(image, **options):
# override me, as necessary
_showxv(image, **options)
@ -2453,10 +2430,10 @@ def _showxv(image, title=None, **options):
from PIL import ImageShow
ImageShow.show(image, title, **options)
# --------------------------------------------------------------------
# Effects
def effect_mandelbrot(size, extent, quality):
"""
Generate a Mandelbrot set covering the given extent.

View File

@ -139,7 +139,6 @@ for flag in FLAGS.values():
if isinstance(flag, int):
_MAX_FLAG = _MAX_FLAG | flag
# --------------------------------------------------------------------.
# Experimental PIL-level API
# --------------------------------------------------------------------.
@ -147,8 +146,8 @@ for flag in FLAGS.values():
##
# Profile.
class ImageCmsProfile:
class ImageCmsProfile:
def __init__(self, profile):
"""
:param profile: Either a string representing a filename,
@ -193,22 +192,18 @@ class ImageCmsTransform(Image.ImagePointHandler):
# Will return the output profile in the output.info['icc_profile'].
def __init__(self, input, output, input_mode, output_mode,
intent=INTENT_PERCEPTUAL, proof=None,
proof_intent=INTENT_ABSOLUTE_COLORIMETRIC, flags=0):
intent=INTENT_PERCEPTUAL,
proof=None,
proof_intent=INTENT_ABSOLUTE_COLORIMETRIC,
flags=0):
if proof is None:
self.transform = core.buildTransform(
input.profile, output.profile,
self.transform = core.buildTransform(input.profile, output.profile,
input_mode, output_mode,
intent,
flags
)
intent, flags)
else:
self.transform = core.buildProofTransform(
input.profile, output.profile, proof.profile,
input_mode, output_mode,
intent, proof_intent,
flags
)
input.profile, output.profile, proof.profile, input_mode,
output_mode, intent, proof_intent, flags)
# Note: inputMode and outputMode are for pyCMS compatibility only
self.input_mode = self.inputMode = input_mode
self.output_mode = self.outputMode = output_mode
@ -256,21 +251,22 @@ def get_display_profile(handle=None):
profile = get()
return ImageCmsProfile(profile)
# --------------------------------------------------------------------.
# pyCMS compatible layer
# --------------------------------------------------------------------.
class PyCMSError(Exception):
class PyCMSError(Exception):
""" (pyCMS) Exception class.
This is used for all errors in the pyCMS API. """
pass
def profileToProfile(
im, inputProfile, outputProfile, renderingIntent=INTENT_PERCEPTUAL,
outputMode=None, inPlace=0, flags=0):
def profileToProfile(im, inputProfile, outputProfile,
renderingIntent=INTENT_PERCEPTUAL,
outputMode=None,
inPlace=0,
flags=0):
"""
(pyCMS) Applies an ICC transformation to a given image, mapping from
inputProfile to outputProfile.
@ -337,10 +333,9 @@ def profileToProfile(
inputProfile = ImageCmsProfile(inputProfile)
if not isinstance(outputProfile, ImageCmsProfile):
outputProfile = ImageCmsProfile(outputProfile)
transform = ImageCmsTransform(
inputProfile, outputProfile, im.mode, outputMode,
renderingIntent, flags=flags
)
transform = ImageCmsTransform(inputProfile, outputProfile, im.mode,
outputMode, renderingIntent,
flags=flags)
if inPlace:
transform.apply_in_place(im)
imOut = None
@ -374,9 +369,9 @@ def getOpenProfile(profileFilename):
raise PyCMSError(v)
def buildTransform(
inputProfile, outputProfile, inMode, outMode,
renderingIntent=INTENT_PERCEPTUAL, flags=0):
def buildTransform(inputProfile, outputProfile, inMode, outMode,
renderingIntent=INTENT_PERCEPTUAL,
flags=0):
"""
(pyCMS) Builds an ICC transform mapping from the inputProfile to the
outputProfile. Use applyTransform to apply the transform to a given
@ -444,15 +439,15 @@ def buildTransform(
inputProfile = ImageCmsProfile(inputProfile)
if not isinstance(outputProfile, ImageCmsProfile):
outputProfile = ImageCmsProfile(outputProfile)
return ImageCmsTransform(
inputProfile, outputProfile, inMode, outMode,
renderingIntent, flags=flags)
return ImageCmsTransform(inputProfile, outputProfile, inMode, outMode,
renderingIntent,
flags=flags)
except (IOError, TypeError, ValueError) as v:
raise PyCMSError(v)
def buildProofTransform(
inputProfile, outputProfile, proofProfile, inMode, outMode,
def buildProofTransform(inputProfile, outputProfile, proofProfile, inMode,
outMode,
renderingIntent=INTENT_PERCEPTUAL,
proofRenderingIntent=INTENT_ABSOLUTE_COLORIMETRIC,
flags=FLAGS["SOFTPROOFING"]):
@ -544,12 +539,13 @@ def buildProofTransform(
outputProfile = ImageCmsProfile(outputProfile)
if not isinstance(proofProfile, ImageCmsProfile):
proofProfile = ImageCmsProfile(proofProfile)
return ImageCmsTransform(
inputProfile, outputProfile, inMode, outMode, renderingIntent,
proofProfile, proofRenderingIntent, flags)
return ImageCmsTransform(inputProfile, outputProfile, inMode, outMode,
renderingIntent, proofProfile,
proofRenderingIntent, flags)
except (IOError, TypeError, ValueError) as v:
raise PyCMSError(v)
buildTransformFromOpenProfiles = buildTransform
buildProofTransformFromOpenProfiles = buildProofTransform
@ -635,16 +631,15 @@ def createProfile(colorSpace, colorTemp=-1):
if colorSpace not in ["LAB", "XYZ", "sRGB"]:
raise PyCMSError(
"Color space not supported for on-the-fly profile creation (%s)"
% colorSpace)
"Color space not supported for on-the-fly profile creation (%s)" %
colorSpace)
if colorSpace == "LAB":
try:
colorTemp = float(colorTemp)
except:
raise PyCMSError(
"Color temperature must be numeric, \"%s\" not valid"
% colorTemp)
"Color temperature must be numeric, \"%s\" not valid" % colorTemp)
try:
return core.createProfile(colorSpace, colorTemp)
@ -944,10 +939,8 @@ def versions():
"""
import sys
return (
VERSION, core.littlecms_version,
sys.version.split()[0], Image.VERSION
)
return (VERSION, core.littlecms_version, sys.version.split()[0],
Image.VERSION)
# --------------------------------------------------------------------

View File

@ -48,54 +48,31 @@ def getrgb(color):
# check for known string formats
m = re.match("#\w\w\w$", color)
if m:
return (
int(color[1]*2, 16),
int(color[2]*2, 16),
int(color[3]*2, 16)
)
return (int(color[1] * 2, 16), int(color[2] * 2, 16),
int(color[3] * 2, 16))
m = re.match("#\w\w\w\w\w\w$", color)
if m:
return (
int(color[1:3], 16),
int(color[3:5], 16),
int(color[5:7], 16)
)
return (int(color[1:3], 16), int(color[3:5], 16), int(color[5:7], 16))
m = re.match("rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$", color)
if m:
return (
int(m.group(1)),
int(m.group(2)),
int(m.group(3))
)
return (int(m.group(1)), int(m.group(2)), int(m.group(3)))
m = re.match("rgb\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)$", color)
if m:
return (
int((int(m.group(1)) * 255) / 100.0 + 0.5),
return (int((int(m.group(1)) * 255) / 100.0 + 0.5),
int((int(m.group(2)) * 255) / 100.0 + 0.5),
int((int(m.group(3)) * 255) / 100.0 + 0.5)
)
int((int(m.group(3)) * 255) / 100.0 + 0.5))
m = re.match("hsl\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)$", color)
if m:
from colorsys import hls_to_rgb
rgb = hls_to_rgb(
float(m.group(1)) / 360.0,
float(m.group(3)) / 100.0,
float(m.group(2)) / 100.0,
)
return (
int(rgb[0] * 255 + 0.5),
int(rgb[1] * 255 + 0.5),
int(rgb[2] * 255 + 0.5)
)
rgb = hls_to_rgb(float(m.group(1)) / 360.0, float(m.group(3)) / 100.0,
float(m.group(2)) / 100.0, )
return (int(rgb[0] * 255 + 0.5), int(rgb[1] * 255 + 0.5),
int(rgb[2] * 255 + 0.5))
m = re.match("rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$",
color)
if m:
return (
int(m.group(1)),
int(m.group(2)),
int(m.group(3)),
int(m.group(4))
)
return (int(m.group(1)), int(m.group(2)), int(m.group(3)),
int(m.group(4)))
raise ValueError("unknown color specifier: %r" % color)
@ -125,6 +102,7 @@ def getcolor(color, mode):
return color + (alpha, )
return color
colormap = {
# X11 colour table (from "CSS3 module: Color working draft"), with
# gray/grey spelling issues fixed. This is a superset of HTML 4.0

View File

@ -40,13 +40,13 @@ try:
except ImportError:
warnings = None
##
# A simple 2D drawing interface for PIL images.
# <p>
# Application code should use the <b>Draw</b> factory, instead of
# directly.
class ImageDraw:
##
@ -98,8 +98,8 @@ class ImageDraw:
if warnings:
warnings.warn(
"'setink' is deprecated; use keyword arguments instead",
DeprecationWarning, stacklevel=2
)
DeprecationWarning,
stacklevel=2)
if isStringType(ink):
ink = ImageColor.getcolor(ink, self.mode)
if self.palette and not isinstance(ink, numbers.Number):
@ -114,8 +114,8 @@ class ImageDraw:
if warnings:
warnings.warn(
"'setfill' is deprecated; use keyword arguments instead",
DeprecationWarning, stacklevel=2
)
DeprecationWarning,
stacklevel=2)
self.fill = onoff
##
@ -281,7 +281,6 @@ class ImageDraw:
font = self.getfont()
return font.getsize(text)
##
# A simple 2D drawing interface for PIL images.
#
@ -292,6 +291,7 @@ class ImageDraw:
# must be the same as the image mode. If omitted, the mode
# defaults to the mode of the image.
def Draw(im, mode=None):
try:
return im.getdraw(mode)
@ -304,7 +304,6 @@ try:
except:
Outline = None
##
# (Experimental) A more advanced 2D drawing interface for PIL images,
# based on the WCK interface.
@ -313,6 +312,7 @@ except:
# @param hints An optional list of hints.
# @return A (drawing context, drawing resource factory) tuple.
def getdraw(im=None, hints=None):
# FIXME: this needs more work!
# FIXME: come up with a better 'hints' scheme.
@ -328,7 +328,6 @@ def getdraw(im=None, hints=None):
im = handler.Draw(im)
return im, handler
##
# (experimental) Fills a bounded region with a given color.
#
@ -340,6 +339,7 @@ def getdraw(im=None, hints=None):
# the region consists of pixels having the same color as the seed
# pixel.
def floodfill(image, xy, value, border=None):
"Fill bounded region."
# based on an implementation by Eric S. Raymond

View File

@ -38,7 +38,6 @@ class Font:
class Draw:
def __init__(self, image, size=None, color=None):
if not hasattr(image, "im"):
image = Image.new(image, size, color)

View File

@ -22,7 +22,6 @@ from PIL import Image, ImageFilter, ImageStat
class _Enhance:
def enhance(self, factor):
"""
Returns an enhanced image.
@ -45,13 +44,16 @@ class Color(_Enhance):
factor of 0.0 gives a black and white image. A factor of 1.0 gives
the original image.
"""
def __init__(self, image):
self.image = image
self.intermediate_mode = 'L'
if 'A' in image.getbands():
self.intermediate_mode = 'LA'
self.degenerate = image.convert(self.intermediate_mode).convert(image.mode)
self.degenerate = image.convert(self.intermediate_mode).convert(
image.mode)
class Contrast(_Enhance):
"""Adjust image contrast.
@ -60,6 +62,7 @@ class Contrast(_Enhance):
to the contrast control on a TV set. An enhancement factor of 0.0
gives a solid grey image. A factor of 1.0 gives the original image.
"""
def __init__(self, image):
self.image = image
mean = int(ImageStat.Stat(image.convert("L")).mean[0] + 0.5)
@ -76,6 +79,7 @@ class Brightness(_Enhance):
enhancement factor of 0.0 gives a black image. A factor of 1.0 gives the
original image.
"""
def __init__(self, image):
self.image = image
self.degenerate = Image.new(image.mode, image.size, 0)
@ -91,6 +95,7 @@ class Sharpness(_Enhance):
enhancement factor of 0.0 gives a blurred image, a factor of 1.0 gives the
original image, and a factor of 2.0 gives a sharpened image.
"""
def __init__(self, image):
self.image = image
self.degenerate = image.filter(ImageFilter.SMOOTH)

View File

@ -41,11 +41,8 @@ SAFEBLOCK = 1024*1024
LOAD_TRUNCATED_IMAGES = False
ERRORS = {
-1: "image buffer overrun error",
-2: "decoding error",
-3: "unknown error",
-8: "bad configuration",
-9: "out of memory error"
-1: "image buffer overrun error", -2: "decoding error", -3:
"unknown error", -8: "bad configuration", -9: "out of memory error"
}
@ -58,20 +55,20 @@ def raise_ioerror(error):
message = "decoder error %d" % error
raise IOError(message + " when reading image file")
#
# --------------------------------------------------------------------
# Helpers
def _tilesort(t):
# sort on offset
return t[2]
#
# --------------------------------------------------------------------
# ImageFile base class
class ImageFile(Image.Image):
"Base class for image file format handlers."
@ -167,9 +164,8 @@ class ImageFile(Image.Image):
# use built-in mapper
self.map = Image.core.map(self.filename)
self.map.seek(o)
self.im = self.map.readimage(
self.mode, self.size, a[1], a[2]
)
self.im = self.map.readimage(self.mode, self.size,
a[1], a[2])
else:
# use mmap, if possible
import mmap
@ -177,9 +173,8 @@ class ImageFile(Image.Image):
size = os.path.getsize(self.filename)
# FIXME: on Unix, use PROT_READ etc
self.map = mmap.mmap(file.fileno(), size)
self.im = Image.core.map_buffer(
self.map, self.size, d, e, o, a
)
self.im = Image.core.map_buffer(self.map, self.size, d,
e, o, a)
readonly = 1
except (AttributeError, EnvironmentError, ImportError):
self.map = None
@ -291,8 +286,7 @@ class StubImageFile(ImageFile):
def _open(self):
raise NotImplementedError(
"StubImageFile subclass must implement _open"
)
"StubImageFile subclass must implement _open")
def load(self):
loader = self._load()
@ -307,8 +301,7 @@ class StubImageFile(ImageFile):
def _load(self):
"(Hook) Find actual image loader."
raise NotImplementedError(
"StubImageFile subclass must implement _load"
)
"StubImageFile subclass must implement _load")
class Parser:
@ -404,9 +397,8 @@ class Parser:
im.load_prepare()
d, e, o, a = im.tile[0]
im.tile = []
self.decoder = Image._getdecoder(
im.mode, d, a, im.decoderconfig
)
self.decoder = Image._getdecoder(im.mode, d, a,
im.decoderconfig)
self.decoder.setimage(im.im, e)
# calculate decoder offset
@ -446,9 +438,9 @@ class Parser:
fp.close() # explicitly close the virtual file
return self.image
# --------------------------------------------------------------------
def _save(im, fp, tile, bufsize=0):
"""Helper to save image based on tile list

View File

@ -183,93 +183,51 @@ class UnsharpMask(Filter):
class BLUR(BuiltinFilter):
name = "Blur"
filterargs = (5, 5), 16, 0, (
1, 1, 1, 1, 1,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
1, 1, 1, 1, 1
)
filterargs = (5, 5), 16, 0, (1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1,
1, 0, 0, 0, 1, 1, 1, 1, 1, 1)
class CONTOUR(BuiltinFilter):
name = "Contour"
filterargs = (3, 3), 1, 255, (
-1, -1, -1,
-1, 8, -1,
-1, -1, -1
)
filterargs = (3, 3), 1, 255, (-1, -1, -1, -1, 8, -1, -1, -1, -1)
class DETAIL(BuiltinFilter):
name = "Detail"
filterargs = (3, 3), 6, 0, (
0, -1, 0,
-1, 10, -1,
0, -1, 0
)
filterargs = (3, 3), 6, 0, (0, -1, 0, -1, 10, -1, 0, -1, 0)
class EDGE_ENHANCE(BuiltinFilter):
name = "Edge-enhance"
filterargs = (3, 3), 2, 0, (
-1, -1, -1,
-1, 10, -1,
-1, -1, -1
)
filterargs = (3, 3), 2, 0, (-1, -1, -1, -1, 10, -1, -1, -1, -1)
class EDGE_ENHANCE_MORE(BuiltinFilter):
name = "Edge-enhance More"
filterargs = (3, 3), 1, 0, (
-1, -1, -1,
-1, 9, -1,
-1, -1, -1
)
filterargs = (3, 3), 1, 0, (-1, -1, -1, -1, 9, -1, -1, -1, -1)
class EMBOSS(BuiltinFilter):
name = "Emboss"
filterargs = (3, 3), 1, 128, (
-1, 0, 0,
0, 1, 0,
0, 0, 0
)
filterargs = (3, 3), 1, 128, (-1, 0, 0, 0, 1, 0, 0, 0, 0)
class FIND_EDGES(BuiltinFilter):
name = "Find Edges"
filterargs = (3, 3), 1, 0, (
-1, -1, -1,
-1, 8, -1,
-1, -1, -1
)
filterargs = (3, 3), 1, 0, (-1, -1, -1, -1, 8, -1, -1, -1, -1)
class SMOOTH(BuiltinFilter):
name = "Smooth"
filterargs = (3, 3), 13, 0, (
1, 1, 1,
1, 5, 1,
1, 1, 1
)
filterargs = (3, 3), 13, 0, (1, 1, 1, 1, 5, 1, 1, 1, 1)
class SMOOTH_MORE(BuiltinFilter):
name = "Smooth More"
filterargs = (5, 5), 100, 0, (
1, 1, 1, 1, 1,
1, 5, 5, 5, 1,
1, 5, 44, 5, 1,
1, 5, 5, 5, 1,
1, 1, 1, 1, 1
)
filterargs = (5, 5), 100, 0, (1, 1, 1, 1, 1, 1, 5, 5, 5, 1, 1, 5, 44, 5, 1,
1, 5, 5, 5, 1, 1, 1, 1, 1, 1)
class SHARPEN(BuiltinFilter):
name = "Sharpen"
filterargs = (3, 3), 16, 0, (
-2, -2, -2,
-2, 32, -2,
-2, -2, -2
)
filterargs = (3, 3), 16, 0, (-2, -2, -2, -2, 32, -2, -2, -2, -2)

View File

@ -43,6 +43,7 @@ class _imagingft_not_installed:
def __getattr__(self, id):
raise ImportError("The _imagingft C module is not installed")
try:
from PIL import _imagingft as core
except ImportError:
@ -115,11 +116,11 @@ class ImageFont:
self.getsize = self.font.getsize
self.getmask = self.font.getmask
##
# Wrapper for FreeType fonts. Application code should use the
# <b>truetype</b> factory function to create font objects.
class FreeTypeFont:
"FreeType font wrapper (requires _imagingft service)"
@ -127,8 +128,7 @@ class FreeTypeFont:
# FIXME: use service provider instead
if file:
if warnings:
warnings.warn(
'file parameter deprecated, '
warnings.warn('file parameter deprecated, '
'please use font parameter instead.',
DeprecationWarning)
font = file
@ -142,8 +142,8 @@ class FreeTypeFont:
self.font = core.getfont(font, size, index, encoding)
else:
self.font_bytes = font.read()
self.font = core.getfont(
"", size, index, encoding, self.font_bytes)
self.font = core.getfont("", size, index, encoding,
self.font_bytes)
def getname(self):
return self.font.family, self.font.style
@ -177,11 +177,11 @@ class FreeTypeFont:
:return: A FreeTypeFont object.
"""
return FreeTypeFont(font=self.path if font is None else font,
return FreeTypeFont(
font=self.path if font is None else font,
size=self.size if size is None else size,
index=self.index if index is None else index,
encoding=self.encoding if encoding is None else
encoding)
encoding=self.encoding if encoding is None else encoding)
##
# Wrapper that creates a transposed font from any existing font
@ -252,8 +252,7 @@ def truetype(font=None, size=10, index=0, encoding="", filename=None):
if filename:
if warnings:
warnings.warn(
'filename parameter deprecated, '
warnings.warn('filename parameter deprecated, '
'please use font parameter instead.',
DeprecationWarning)
font = filename
@ -277,7 +276,8 @@ def truetype(font=None, size=10, index=0, encoding="", filename=None):
# According to the freedesktop spec, XDG_DATA_DIRS should
# default to /usr/share
lindirs = '/usr/share'
dirs += [os.path.join(lindir, "fonts") for lindir in lindirs.split(":")]
dirs += [os.path.join(lindir, "fonts")
for lindir in lindirs.split(":")]
elif sys.platform == 'darwin':
dirs += ['/Library/Fonts', '/System/Library/Fonts',
os.path.expanduser('~/Library/Fonts')]
@ -290,7 +290,8 @@ def truetype(font=None, size=10, index=0, encoding="", filename=None):
if ext and walkfilename == ttf_filename:
fontpath = os.path.join(walkroot, walkfilename)
return FreeTypeFont(fontpath, size, index, encoding)
elif not ext and os.path.splitext(walkfilename)[0] == ttf_filename:
elif not ext and os.path.splitext(
walkfilename)[0] == ttf_filename:
fontpath = os.path.join(walkroot, walkfilename)
if os.path.splitext(fontpath)[1] == '.ttf':
return FreeTypeFont(fontpath, size, index, encoding)
@ -335,8 +336,7 @@ def load_default():
from io import BytesIO
import base64
f = ImageFont()
f._load_pilfont_data(
# courB08
f._load_pilfont_data( # courB08
BytesIO(base64.decodestring(b'''
UElMZm9udAo7Ozs7OzsxMDsKREFUQQoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

View File

@ -32,11 +32,9 @@ except AttributeError:
def grab(bbox=None):
size, data = grabber()
im = Image.frombytes(
"RGB", size, data,
im = Image.frombytes("RGB", size, data,
# RGB, 32-bit line padding, origo in lower left corner
"raw", "BGR", (size[0]*3 + 3) & -4, -1
)
"raw", "BGR", (size[0] * 3 + 3) & -4, -1)
if bbox:
im = im.crop(bbox)
return im

View File

@ -236,6 +236,7 @@ def imagemath_max(self, other):
def imagemath_convert(self, mode):
return _Operand(self.im.convert(mode))
ops = {}
for k, v in list(globals().items()):
if k[:10] == "imagemath_":

View File

@ -16,12 +16,11 @@
# mode descriptor cache
_modes = {}
##
# Wrapper for mode strings.
class ModeDescriptor:
class ModeDescriptor:
def __init__(self, mode, bands, basemode, basetype):
self.mode = mode
self.bands = bands
@ -31,10 +30,10 @@ class ModeDescriptor:
def __str__(self):
return self.mode
##
# Gets a mode descriptor for the given mode.
def getmode(mode):
if not _modes:
# initialize mode cache

View File

@ -47,6 +47,7 @@ class LutBuilder:
lut = lb.build_lut()
"""
def __init__(self, patterns=None, op_name=None):
if patterns is not None:
self.patterns = patterns
@ -55,16 +56,12 @@ class LutBuilder:
self.lut = None
if op_name is not None:
known_patterns = {
'corner': ['1:(... ... ...)->0',
'4:(00. 01. ...)->1'],
'corner': ['1:(... ... ...)->0', '4:(00. 01. ...)->1'],
'dilation4': ['4:(... .0. .1.)->1'],
'dilation8': ['4:(... .0. .1.)->1',
'4:(... .0. ..1)->1'],
'dilation8': ['4:(... .0. .1.)->1', '4:(... .0. ..1)->1'],
'erosion4': ['4:(... .1. .0.)->0'],
'erosion8': ['4:(... .1. .0.)->0',
'4:(... .1. ..0)->0'],
'edge': ['1:(... ... ...)->0',
'4:(.0. .1. ...)->1',
'erosion8': ['4:(... .1. .0.)->0', '4:(... .1. ..0)->0'],
'edge': ['1:(... ... ...)->0', '4:(.0. .1. ...)->1',
'4:(01. .1. ...)->1']
}
if op_name not in known_patterns:
@ -100,28 +97,24 @@ class LutBuilder:
if '4' in options:
res = patterns[-1][1]
for i in range(4):
patterns.append(
(self._string_permute(patterns[-1][0], [6, 3, 0,
7, 4, 1,
8, 5, 2]), res))
patterns.append((self._string_permute(patterns[-1][0],
[6, 3, 0, 7, 4, 1, 8, 5,
2]), res))
# mirror
if 'M' in options:
n = len(patterns)
for pattern, res in patterns[0:n]:
patterns.append(
(self._string_permute(pattern, [2, 1, 0,
5, 4, 3,
8, 7, 6]), res))
patterns.append((self._string_permute(pattern, [2, 1, 0, 5, 4,
3, 8, 7, 6]),
res))
# negate
if 'N' in options:
n = len(patterns)
for pattern, res in patterns[0:n]:
# Swap 0 and 1
pattern = (pattern
.replace('0', 'Z')
.replace('1', '0')
.replace('Z', '1'))
pattern = (pattern.replace('0', 'Z').replace('1', '0').replace(
'Z', '1'))
res = '%d' % (1 - int(res))
patterns.append((pattern, res))
@ -137,8 +130,8 @@ class LutBuilder:
# Parse and create symmetries of the patterns strings
for p in self.patterns:
m = re.search(
r'(\w*):?\s*\((.+?)\)\s*->\s*(\d)', p.replace('\n', ''))
m = re.search(r'(\w*):?\s*\((.+?)\)\s*->\s*(\d)',
p.replace('\n', ''))
if not m:
raise Exception('Syntax error in pattern "' + p + '"')
options = m.group(1)
@ -179,10 +172,7 @@ class LutBuilder:
class MorphOp:
"""A class for binary morphological operators"""
def __init__(self,
lut=None,
op_name=None,
patterns=None):
def __init__(self, lut=None, op_name=None, patterns=None):
"""Create a binary morphological operator"""
self.lut = lut
if op_name is not None:
@ -199,8 +189,8 @@ class MorphOp:
raise Exception('No operator loaded')
outimage = Image.new(image.mode, image.size, None)
count = _imagingmorph.apply(
bytes(self.lut), image.im.id, outimage.im.id)
count = _imagingmorph.apply(bytes(self.lut), image.im.id,
outimage.im.id)
return count, outimage
def match(self, image):

View File

@ -22,10 +22,10 @@ from PIL._util import isStringType
import operator
from functools import reduce
#
# helpers
def _border(border):
if isinstance(border, tuple):
if len(border) == 2:
@ -174,8 +174,7 @@ def crop(image, border=0):
"""
left, top, right, bottom = _border(border)
return image.crop(
(left, top, image.size[0]-right, image.size[1]-bottom)
)
(left, top, image.size[0] - right, image.size[1] - bottom))
def deform(image, deformer, resample=Image.BILINEAR):
@ -188,9 +187,8 @@ def deform(image, deformer, resample=Image.BILINEAR):
:param resample: What resampling filter to use.
:return: An image.
"""
return image.transform(
image.size, Image.MESH, deformer.getmesh(image), resample
)
return image.transform(image.size, Image.MESH, deformer.getmesh(image),
resample)
def equalize(image, mask=None):
@ -289,17 +287,14 @@ def fit(image, size, method=Image.NEAREST, bleed=0.0, centering=(0.5, 0.5)):
# the 'bleed' around the edges
# number of pixels to trim off on Top and Bottom, Left and Right
bleedPixels = (
int((float(bleed) * float(image.size[0])) + 0.5),
int((float(bleed) * float(image.size[1])) + 0.5)
)
bleedPixels = (int((float(bleed) * float(image.size[0])) + 0.5),
int((float(bleed) * float(image.size[1])) + 0.5))
liveArea = (0, 0, image.size[0], image.size[1])
if bleed > 0.0:
liveArea = (
bleedPixels[0], bleedPixels[1], image.size[0] - bleedPixels[0] - 1,
image.size[1] - bleedPixels[1] - 1
)
liveArea = (bleedPixels[0], bleedPixels[1],
image.size[0] - bleedPixels[0] - 1,
image.size[1] - bleedPixels[1] - 1)
liveSize = (liveArea[2] - liveArea[0], liveArea[3] - liveArea[1])
@ -320,16 +315,17 @@ def fit(image, size, method=Image.NEAREST, bleed=0.0, centering=(0.5, 0.5)):
cropHeight = int((float(liveSize[0]) / aspectRatio) + 0.5)
# make the crop
leftSide = int(liveArea[0] + (float(liveSize[0]-cropWidth) * centering[0]))
leftSide = int(liveArea[0] +
(float(liveSize[0] - cropWidth) * centering[0]))
if leftSide < 0:
leftSide = 0
topSide = int(liveArea[1] + (float(liveSize[1]-cropHeight) * centering[1]))
topSide = int(liveArea[1] +
(float(liveSize[1] - cropHeight) * centering[1]))
if topSide < 0:
topSide = 0
out = image.crop(
(leftSide, topSide, leftSide + cropWidth, topSide + cropHeight)
)
(leftSide, topSide, leftSide + cropWidth, topSide + cropHeight))
# resize the image and return it
return out.resize(size, method)
@ -409,10 +405,10 @@ def solarize(image, threshold=128):
lut.append(255 - i)
return _lut(image, lut)
# --------------------------------------------------------------------
# PIL USM components, from Kevin Cazabon.
def gaussian_blur(im, radius=None):
""" PIL_usm.gblur(im, [radius])"""
@ -423,6 +419,7 @@ def gaussian_blur(im, radius=None):
return im.im.gaussian_blur(radius)
gblur = gaussian_blur
@ -440,6 +437,7 @@ def unsharp_mask(im, radius=None, percent=None, threshold=None):
return im.im.unsharp_mask(radius, percent, threshold)
usm = unsharp_mask

View File

@ -110,10 +110,10 @@ class ImagePalette:
fp.write("\n")
fp.close()
# --------------------------------------------------------------------
# Internal
def raw(rawmode, data):
palette = ImagePalette()
palette.rawmode = rawmode
@ -121,27 +121,21 @@ def raw(rawmode, data):
palette.dirty = 1
return palette
# --------------------------------------------------------------------
# Factories
def _make_linear_lut(black, white):
warnings.warn(
'_make_linear_lut() is deprecated. '
'Please call make_linear_lut() instead.',
DeprecationWarning,
stacklevel=2
)
warnings.warn('_make_linear_lut() is deprecated. '
'Please call make_linear_lut() instead.', DeprecationWarning,
stacklevel=2)
return make_linear_lut(black, white)
def _make_gamma_lut(exp):
warnings.warn(
'_make_gamma_lut() is deprecated. '
'Please call make_gamma_lut() instead.',
DeprecationWarning,
stacklevel=2
)
warnings.warn('_make_gamma_lut() is deprecated. '
'Please call make_gamma_lut() instead.', DeprecationWarning,
stacklevel=2)
return make_gamma_lut(exp)

View File

@ -16,12 +16,10 @@
from PIL import Image
# the Python class below is overridden by the C implementation.
class Path:
def __init__(self, xy):
pass
@ -61,6 +59,5 @@ class Path:
def transform(self, matrix):
pass
# override with C implementation
Path = Image.core.path

View File

@ -35,12 +35,12 @@ else: #PyQt4 is used
##
# (Internal) Turns an RGB color into a Qt compatible color integer.
def rgb(r, g, b, a=255):
# use qRgb to pack the colors, and then turn the resulting long
# into a negative integer with the same bitpattern.
return (qRgba(r, g, b, a) & 0xffffffff)
##
# An PIL image wrapper for Qt. This is a subclass of PyQt4's QImage
# class.
@ -48,8 +48,8 @@ def rgb(r, g, b, a=255):
# @param im A PIL Image object, or a file name (given either as Python
# string or a PyQt string object).
class ImageQt(QImage):
class ImageQt(QImage):
def __init__(self, im):
data = None

View File

@ -37,7 +37,6 @@ def register(viewer, order=1):
elif order < 0:
_viewers.insert(0, viewer)
##
# Displays a given image.
#
@ -46,16 +45,17 @@ def register(viewer, order=1):
# @param **options Additional viewer options.
# @return True if a suitable viewer was found, false otherwise.
def show(image, title=None, **options):
for viewer in _viewers:
if viewer.show(image, title=title, **options):
return 1
return 0
##
# Base class for viewers.
class Viewer:
# main api
@ -147,8 +147,7 @@ else:
class UnixViewer(Viewer):
def show_file(self, file, **options):
command, executable = self.get_command_ex(file, **options)
command = "(%s %s; rm -f %s)&" % (command, quote(file),
quote(file))
command = "(%s %s; rm -f %s)&" % (command, quote(file), quote(file))
os.system(command)
return 1

View File

@ -27,7 +27,6 @@ from functools import reduce
class Stat:
def __init__(self, image_or_list, mask=None):
try:
if mask:
@ -144,4 +143,5 @@ class Stat:
v.append(math.sqrt(self.var[i]))
return v
Global = Stat # compatibility

View File

@ -34,7 +34,6 @@ except ImportError:
from PIL import Image
# --------------------------------------------------------------------
# Check for Tkinter interface hooks
@ -52,10 +51,10 @@ def _pilbitmap_check():
_pilbitmap_ok = 0
return _pilbitmap_ok
# --------------------------------------------------------------------
# PhotoImage
class PhotoImage:
"""
A Tkinter-compatible photo image. This can be used
@ -269,20 +268,21 @@ def getimage(photo):
"""Copies the contents of a PhotoImage to a PIL image memory."""
photo.tk.call("PyImagingPhotoGet", photo)
# --------------------------------------------------------------------
# Helper for the Image.show method.
def _show(image, title):
def _show(image, title):
class UI(tkinter.Label):
def __init__(self, master, im):
if im.mode == "1":
self.image = BitmapImage(im, foreground="white", master=master)
else:
self.image = PhotoImage(im, master=master)
tkinter.Label.__init__(self, master, image=self.image,
bg="black", bd=0)
tkinter.Label.__init__(self, master,
image=self.image,
bg="black",
bd=0)
if not tkinter._default_root:
raise IOError("tkinter not initialized")

View File

@ -28,7 +28,6 @@ class Transform(Image.ImageTransformHandler):
method, data = self.getdata()
return image.transform(size, method, data, **options)
##
# Define an affine image transform.
# <p>
@ -51,7 +50,6 @@ class Transform(Image.ImageTransformHandler):
class AffineTransform(Transform):
method = Image.AFFINE
##
# Define a transform to extract a subregion from an image.
# <p>
@ -71,10 +69,10 @@ class AffineTransform(Transform):
# two points in the input image's coordinate system.
# @see Image#Image.transform
class ExtentTransform(Transform):
method = Image.EXTENT
##
# Define an quad image transform.
# <p>
@ -87,10 +85,10 @@ class ExtentTransform(Transform):
# corner of the source quadrilateral.
# @see Image#Image.transform
class QuadTransform(Transform):
method = Image.QUAD
##
# Define an mesh image transform. A mesh transform consists of one
# or more individual quad transforms.
@ -99,5 +97,6 @@ class QuadTransform(Transform):
# @param data A list of (bbox, quad) tuples.
# @see Image#Image.transform
class MeshTransform(Transform):
method = Image.MESH

View File

@ -27,6 +27,7 @@ class HDC:
:py:meth:`~PIL.ImageWin.Dib.draw` and :py:meth:`~PIL.ImageWin.Dib.expose`
methods.
"""
def __init__(self, dc):
self.dc = dc
@ -40,6 +41,7 @@ class HWND:
:py:meth:`~PIL.ImageWin.Dib.draw` and :py:meth:`~PIL.ImageWin.Dib.expose`
methods, instead of a DC.
"""
def __init__(self, wnd):
self.wnd = wnd
@ -190,28 +192,24 @@ class Dib:
warnings.warn(
'fromstring() is deprecated. Please call frombytes() instead.',
DeprecationWarning,
stacklevel=2
)
stacklevel=2)
return self.frombytes(*args, **kw)
def tostring(self):
warnings.warn(
'tostring() is deprecated. Please call tobytes() instead.',
DeprecationWarning,
stacklevel=2
)
stacklevel=2)
return self.tobytes()
##
# Create a Window with the given title size.
class Window:
class Window:
def __init__(self, title="PIL", width=None, height=None):
self.hwnd = Image.core.createwindow(
title, self.__dispatcher, width or 0, height or 0
)
self.hwnd = Image.core.createwindow(title, self.__dispatcher,
width or 0, height or 0)
def __dispatcher(self, action, *args):
return getattr(self, "ui_handle_" + action)(*args)
@ -234,12 +232,11 @@ class Window:
def mainloop(self):
Image.core.eventloop()
##
# Create an image window which displays the given image.
class ImageWindow(Window):
class ImageWindow(Window):
def __init__(self, image, title="PIL"):
if not isinstance(image, Dib):
image = Dib(image)

View File

@ -14,7 +14,6 @@
# See the README file for information on usage and redistribution.
#
__version__ = "0.2"
import re
@ -26,10 +25,10 @@ from PIL import Image, ImageFile
field = re.compile(br"([a-z]*) ([^ \r\n]*)")
##
# Image plugin for IM Tools images.
class ImtImageFile(ImageFile.ImageFile):
format = "IMT"
@ -55,8 +54,7 @@ class ImtImageFile(ImageFile.ImageFile):
if s == b'\x0C':
# image data begins
self.tile = [("raw", (0, 0)+self.size,
self.fp.tell(),
self.tile = [("raw", (0, 0) + self.size, self.fp.tell(),
(self.mode, 0, 1))]
break
@ -84,7 +82,6 @@ class ImtImageFile(ImageFile.ImageFile):
elif k == "pixel" and v == "n8":
self.mode = "L"
#
# --------------------------------------------------------------------

View File

@ -19,7 +19,6 @@ from __future__ import print_function
__version__ = "0.3"
from PIL import Image, ImageFile, _binary
import os
import tempfile
@ -29,17 +28,14 @@ i16 = _binary.i16be
i32 = _binary.i32be
o8 = _binary.o8
COMPRESSION = {
1: "raw",
5: "jpeg"
}
COMPRESSION = {1: "raw", 5: "jpeg"}
PAD = o8(0) * 4
#
# Helpers
def i(c):
return i32((PAD + c)[-4:])
@ -49,11 +45,11 @@ def dump(c):
print("%02x" % i8(i), end=' ')
print()
##
# Image plugin for IPTC/NAA datastreams. To read IPTC/NAA fields
# from TIFF and JPEG files, use the <b>getiptcinfo</b> function.
class IptcImageFile(ImageFile.ImageFile):
format = "IPTC"
@ -188,7 +184,6 @@ Image.register_open("IPTC", IptcImageFile)
Image.register_extension("IPTC", ".iim")
##
# Get IPTC information from TIFF, JPEG, or IPTC file.
#
@ -196,6 +191,7 @@ Image.register_extension("IPTC", ".iim")
# @return A dictionary containing IPTC information, or None if
# no IPTC information block was found.
def getiptcinfo(im):
from PIL import TiffImagePlugin, JpegImagePlugin
@ -253,6 +249,7 @@ def getiptcinfo(im):
# create an IptcImagePlugin object without initializing it
class FakeImage:
pass
im = FakeImage()
im.__class__ = IptcImageFile

View File

@ -210,10 +210,10 @@ def _accept(prefix):
return (prefix[:4] == b'\xff\x4f\xff\x51' or
prefix[:12] == b'\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a')
# ------------------------------------------------------------
# Save support
def _save(im, fp, filename):
if filename.endswith('.j2k'):
kind = 'j2k'
@ -242,20 +242,10 @@ def _save(im, fp, filename):
except:
fd = -1
im.encoderconfig = (
offset,
tile_offset,
tile_size,
quality_mode,
quality_layers,
num_resolutions,
cblk_size,
precinct_size,
irreversible,
progression,
cinema_mode,
fd
)
im.encoderconfig = (offset, tile_offset, tile_size, quality_mode,
quality_layers, num_resolutions, cblk_size,
precinct_size, irreversible, progression, cinema_mode,
fd)
ImageFile._save(im, fp, [('jpeg2k', (0, 0) + im.size, 0, kind)])

View File

@ -47,10 +47,10 @@ o8 = _binary.o8
i16 = _binary.i16be
i32 = _binary.i32be
#
# Parser
def Skip(self, marker):
n = i16(self.fp.read(2)) - 2
ImageFile._safe_read(self.fp, n)
@ -200,10 +200,10 @@ def DQT(self, marker):
return # FIXME: add code to read 16-bit tables!
# raise SyntaxError, "bad quantization table element size"
#
# JPEG marker table
MARKER = {
0xFFC0: ("SOF0", "Baseline DCT", SOF),
0xFFC1: ("SOF1", "Extended Sequential DCT", SOF),
@ -274,10 +274,10 @@ MARKER = {
def _accept(prefix):
return prefix[0:1] == b"\377"
##
# Image plugin for JPEG and JFIF images.
class JpegImageFile(ImageFile.ImageFile):
format = "JPEG"
@ -350,8 +350,10 @@ class JpegImageFile(ImageFile.ImageFile):
for s in [8, 4, 2, 1]:
if scale >= s:
break
e = e[0], e[1], (e[2]-e[0]+s-1)//s+e[0], (e[3]-e[1]+s-1)//s+e[1]
self.size = ((self.size[0]+s-1)//s, (self.size[1]+s-1)//s)
e = e[0], e[1], (e[2] - e[0] + s -
1) // s + e[0], (e[3] - e[1] + s - 1) // s + e[1]
self.size = ((self.size[0] + s - 1) // s,
(self.size[1] + s - 1) // s)
scale = s
self.tile = [(d, e, o, a)]
@ -513,7 +515,6 @@ def _getmp(self):
# file and so can't test it.
return mp
# --------------------------------------------------------------------
# stuff to save JPEG files
@ -527,16 +528,13 @@ RAWMODE = {
"YCbCr": "YCbCr",
}
zigzag_index = ( 0, 1, 5, 6, 14, 15, 27, 28,
2, 4, 7, 13, 16, 26, 29, 42,
3, 8, 12, 17, 25, 30, 41, 43,
9, 11, 18, 24, 31, 40, 44, 53,
10, 19, 23, 32, 39, 45, 52, 54,
20, 22, 33, 38, 46, 51, 55, 60,
21, 34, 37, 47, 50, 56, 59, 61,
35, 36, 48, 49, 57, 58, 62, 63)
zigzag_index = (0, 1, 5, 6, 14, 15, 27, 28, 2, 4, 7, 13, 16, 26, 29, 42, 3, 8,
12, 17, 25, 30, 41, 43, 9, 11, 18, 24, 31, 40, 44, 53, 10, 19,
23, 32, 39, 45, 52, 54, 20, 22, 33, 38, 46, 51, 55, 60, 21, 34,
37, 47, 50, 56, 59, 61, 35, 36, 48, 49, 57, 58, 62, 63)
samplings = {(1, 1, 1, 1, 1, 1): 0,
samplings = {
(1, 1, 1, 1, 1, 1): 0,
(2, 1, 1, 1, 1, 1): 1,
(2, 2, 1, 1, 1, 1): 2,
}
@ -612,8 +610,8 @@ def _save(im, fp, filename):
return qtables
if isStringType(qtables):
try:
lines = [int(num) for line in qtables.splitlines()
for num in line.split('#', 1)[0].split()]
lines = [int(num) for line in qtables.splitlines() for num in
line.split('#', 1)[0].split()]
except ValueError:
raise ValueError("Invalid quantization table")
else:
@ -667,16 +665,9 @@ def _save(im, fp, filename):
# "progressive" is the official name, but older documentation
# says "progression"
# FIXME: issue a warning if the wrong form is used (post-1.1.7)
"progressive" in info or "progression" in info,
info.get("smooth", 0),
"optimize" in info,
info.get("streamtype", 0),
dpi[0], dpi[1],
subsampling,
qtables,
extra,
info.get("exif", b"")
)
"progressive" in info or "progression" in info, info.get("smooth", 0),
"optimize" in info, info.get("streamtype", 0), dpi[0], dpi[1],
subsampling, qtables, extra, info.get("exif", b""))
# if we optimize, libjpeg needs a buffer big enough to hold the whole image
# in a shot. Guessing on the size, at im.size bytes. (raw pizel size is
@ -724,7 +715,6 @@ def jpeg_factory(fp=None, filename=None):
pass
return im
# -------------------------------------------------------------------q-
# Registry stuff

View File

@ -67,175 +67,117 @@ Libjpeg ref.: http://www.jpegcameras.com/libjpeg/libjpeg-3.html
"""
presets = {
'web_low': {'subsampling': 2, # "4:1:1"
'web_low': {
'subsampling': 2, # "4:1:1"
'quantization': [
[20, 16, 25, 39, 50, 46, 62, 68,
16, 18, 23, 38, 38, 53, 65, 68,
25, 23, 31, 38, 53, 65, 68, 68,
39, 38, 38, 53, 65, 68, 68, 68,
50, 38, 53, 65, 68, 68, 68, 68,
46, 53, 65, 68, 68, 68, 68, 68,
62, 65, 68, 68, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68],
[21, 25, 32, 38, 54, 68, 68, 68,
25, 28, 24, 38, 54, 68, 68, 68,
32, 24, 32, 43, 66, 68, 68, 68,
38, 38, 43, 53, 68, 68, 68, 68,
54, 54, 66, 68, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68]
]},
'web_medium': {'subsampling': 2, # "4:1:1"
[20, 16, 25, 39, 50, 46, 62, 68, 16, 18, 23, 38, 38, 53, 65, 68,
25, 23, 31, 38, 53, 65, 68, 68, 39, 38, 38, 53, 65, 68, 68, 68,
50, 38, 53, 65, 68, 68, 68, 68, 46, 53, 65, 68, 68, 68, 68, 68,
62, 65, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68],
[21, 25, 32, 38, 54, 68, 68, 68, 25, 28, 24, 38, 54, 68, 68, 68,
32, 24, 32, 43, 66, 68, 68, 68, 38, 38, 43, 53, 68, 68, 68, 68,
54, 54, 66, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68]
]
},
'web_medium': {
'subsampling': 2, # "4:1:1"
'quantization': [
[16, 11, 11, 16, 23, 27, 31, 30,
11, 12, 12, 15, 20, 23, 23, 30,
11, 12, 13, 16, 23, 26, 35, 47,
16, 15, 16, 23, 26, 37, 47, 64,
23, 20, 23, 26, 39, 51, 64, 64,
27, 23, 26, 37, 51, 64, 64, 64,
31, 23, 35, 47, 64, 64, 64, 64,
30, 30, 47, 64, 64, 64, 64, 64],
[17, 15, 17, 21, 20, 26, 38, 48,
15, 19, 18, 17, 20, 26, 35, 43,
17, 18, 20, 22, 26, 30, 46, 53,
21, 17, 22, 28, 30, 39, 53, 64,
20, 20, 26, 30, 39, 48, 64, 64,
26, 26, 30, 39, 48, 63, 64, 64,
38, 35, 46, 53, 64, 64, 64, 64,
48, 43, 53, 64, 64, 64, 64, 64]
]},
'web_high': {'subsampling': 0, # "4:4:4"
[16, 11, 11, 16, 23, 27, 31, 30, 11, 12, 12, 15, 20, 23, 23, 30,
11, 12, 13, 16, 23, 26, 35, 47, 16, 15, 16, 23, 26, 37, 47, 64,
23, 20, 23, 26, 39, 51, 64, 64, 27, 23, 26, 37, 51, 64, 64, 64,
31, 23, 35, 47, 64, 64, 64, 64, 30, 30, 47, 64, 64, 64, 64, 64],
[17, 15, 17, 21, 20, 26, 38, 48, 15, 19, 18, 17, 20, 26, 35, 43,
17, 18, 20, 22, 26, 30, 46, 53, 21, 17, 22, 28, 30, 39, 53, 64,
20, 20, 26, 30, 39, 48, 64, 64, 26, 26, 30, 39, 48, 63, 64, 64,
38, 35, 46, 53, 64, 64, 64, 64, 48, 43, 53, 64, 64, 64, 64, 64]
]
},
'web_high': {
'subsampling': 0, # "4:4:4"
'quantization': [
[ 6, 4, 4, 6, 9, 11, 12, 16,
4, 5, 5, 6, 8, 10, 12, 12,
4, 5, 5, 6, 10, 12, 14, 19,
6, 6, 6, 11, 12, 15, 19, 28,
9, 8, 10, 12, 16, 20, 27, 31,
11, 10, 12, 15, 20, 27, 31, 31,
12, 12, 14, 19, 27, 31, 31, 31,
16, 12, 19, 28, 31, 31, 31, 31],
[ 7, 7, 13, 24, 26, 31, 31, 31,
7, 12, 16, 21, 31, 31, 31, 31,
13, 16, 17, 31, 31, 31, 31, 31,
24, 21, 31, 31, 31, 31, 31, 31,
26, 31, 31, 31, 31, 31, 31, 31,
31, 31, 31, 31, 31, 31, 31, 31,
31, 31, 31, 31, 31, 31, 31, 31,
31, 31, 31, 31, 31, 31, 31, 31]
]},
'web_very_high': {'subsampling': 0, # "4:4:4"
[6, 4, 4, 6, 9, 11, 12, 16, 4, 5, 5, 6, 8, 10, 12, 12, 4, 5, 5, 6,
10, 12, 14, 19, 6, 6, 6, 11, 12, 15, 19, 28, 9, 8, 10, 12, 16, 20,
27, 31, 11, 10, 12, 15, 20, 27, 31, 31, 12, 12, 14, 19, 27, 31,
31, 31, 16, 12, 19, 28, 31, 31, 31, 31],
[7, 7, 13, 24, 26, 31, 31, 31, 7, 12, 16, 21, 31, 31, 31, 31, 13,
16, 17, 31, 31, 31, 31, 31, 24, 21, 31, 31, 31, 31, 31, 31, 26,
31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31]
]
},
'web_very_high': {
'subsampling': 0, # "4:4:4"
'quantization': [[2, 2, 2, 2, 3, 4, 5, 6, 2, 2, 2, 2, 3, 4, 5, 6, 2, 2,
2, 2, 4, 5, 7, 9, 2, 2, 2, 4, 5, 7, 9, 12, 3, 3, 4,
5, 8, 10, 12, 12, 4, 4, 5, 7, 10, 12, 12, 12, 5, 5,
7, 9, 12, 12, 12, 12, 6, 6, 9, 12, 12, 12, 12, 12],
[3, 3, 5, 9, 13, 15, 15, 15, 3, 4, 6, 11, 14, 12, 12,
12, 5, 6, 9, 14, 12, 12, 12, 12, 9, 11, 14, 12, 12,
12, 12, 12, 13, 14, 12, 12, 12, 12, 12, 12, 15, 12,
12, 12, 12, 12, 12, 12, 15, 12, 12, 12, 12, 12, 12,
12, 15, 12, 12, 12, 12, 12, 12, 12]]
},
'web_maximum': {
'subsampling': 0, # "4:4:4"
'quantization': [
[ 2, 2, 2, 2, 3, 4, 5, 6,
2, 2, 2, 2, 3, 4, 5, 6,
2, 2, 2, 2, 4, 5, 7, 9,
2, 2, 2, 4, 5, 7, 9, 12,
3, 3, 4, 5, 8, 10, 12, 12,
4, 4, 5, 7, 10, 12, 12, 12,
5, 5, 7, 9, 12, 12, 12, 12,
6, 6, 9, 12, 12, 12, 12, 12],
[ 3, 3, 5, 9, 13, 15, 15, 15,
3, 4, 6, 11, 14, 12, 12, 12,
5, 6, 9, 14, 12, 12, 12, 12,
9, 11, 14, 12, 12, 12, 12, 12,
13, 14, 12, 12, 12, 12, 12, 12,
15, 12, 12, 12, 12, 12, 12, 12,
15, 12, 12, 12, 12, 12, 12, 12,
15, 12, 12, 12, 12, 12, 12, 12]
]},
'web_maximum': {'subsampling': 0, # "4:4:4"
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 2, 2, 3, 1, 1, 1, 1,
2, 2, 3, 3, 1, 1, 1, 2, 2, 3, 3, 3, 1, 1, 2, 2, 3, 3, 3, 3],
[1, 1, 1, 2, 2, 3, 3, 3, 1, 1, 1, 2, 3, 3, 3, 3, 1, 1, 1, 3, 3, 3,
3, 3, 2, 2, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
]
},
'low': {
'subsampling': 2, # "4:1:1"
'quantization': [
[ 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 2,
1, 1, 1, 1, 1, 1, 2, 2,
1, 1, 1, 1, 1, 2, 2, 3,
1, 1, 1, 1, 2, 2, 3, 3,
1, 1, 1, 2, 2, 3, 3, 3,
1, 1, 2, 2, 3, 3, 3, 3],
[ 1, 1, 1, 2, 2, 3, 3, 3,
1, 1, 1, 2, 3, 3, 3, 3,
1, 1, 1, 3, 3, 3, 3, 3,
2, 2, 3, 3, 3, 3, 3, 3,
2, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3]
]},
'low': {'subsampling': 2, # "4:1:1"
[18, 14, 14, 21, 30, 35, 34, 17, 14, 16, 16, 19, 26, 23, 12, 12,
14, 16, 17, 21, 23, 12, 12, 12, 21, 19, 21, 23, 12, 12, 12, 12,
30, 26, 23, 12, 12, 12, 12, 12, 35, 23, 12, 12, 12, 12, 12, 12,
34, 12, 12, 12, 12, 12, 12, 12, 17, 12, 12, 12, 12, 12, 12, 12],
[20, 19, 22, 27, 20, 20, 17, 17, 19, 25, 23, 14, 14, 12, 12, 12,
22, 23, 14, 14, 12, 12, 12, 12, 27, 14, 14, 12, 12, 12, 12, 12,
20, 14, 12, 12, 12, 12, 12, 12, 20, 12, 12, 12, 12, 12, 12, 12,
17, 12, 12, 12, 12, 12, 12, 12, 17, 12, 12, 12, 12, 12, 12, 12]
]
},
'medium': {
'subsampling': 2, # "4:1:1"
'quantization': [
[18, 14, 14, 21, 30, 35, 34, 17,
14, 16, 16, 19, 26, 23, 12, 12,
14, 16, 17, 21, 23, 12, 12, 12,
21, 19, 21, 23, 12, 12, 12, 12,
30, 26, 23, 12, 12, 12, 12, 12,
35, 23, 12, 12, 12, 12, 12, 12,
34, 12, 12, 12, 12, 12, 12, 12,
17, 12, 12, 12, 12, 12, 12, 12],
[20, 19, 22, 27, 20, 20, 17, 17,
19, 25, 23, 14, 14, 12, 12, 12,
22, 23, 14, 14, 12, 12, 12, 12,
27, 14, 14, 12, 12, 12, 12, 12,
20, 14, 12, 12, 12, 12, 12, 12,
20, 12, 12, 12, 12, 12, 12, 12,
17, 12, 12, 12, 12, 12, 12, 12,
17, 12, 12, 12, 12, 12, 12, 12]
]},
'medium': {'subsampling': 2, # "4:1:1"
[12, 8, 8, 12, 17, 21, 24, 17, 8, 9, 9, 11, 15, 19, 12, 12, 8, 9,
10, 12, 19, 12, 12, 12, 12, 11, 12, 21, 12, 12, 12, 12, 17, 15,
19, 12, 12, 12, 12, 12, 21, 19, 12, 12, 12, 12, 12, 12, 24, 12,
12, 12, 12, 12, 12, 12, 17, 12, 12, 12, 12, 12, 12, 12],
[13, 11, 13, 16, 20, 20, 17, 17, 11, 14, 14, 14, 14, 12, 12, 12,
13, 14, 14, 14, 12, 12, 12, 12, 16, 14, 14, 12, 12, 12, 12, 12,
20, 14, 12, 12, 12, 12, 12, 12, 20, 12, 12, 12, 12, 12, 12, 12,
17, 12, 12, 12, 12, 12, 12, 12, 17, 12, 12, 12, 12, 12, 12, 12]
]
},
'high': {
'subsampling': 0, # "4:4:4"
'quantization': [
[12, 8, 8, 12, 17, 21, 24, 17,
8, 9, 9, 11, 15, 19, 12, 12,
8, 9, 10, 12, 19, 12, 12, 12,
12, 11, 12, 21, 12, 12, 12, 12,
17, 15, 19, 12, 12, 12, 12, 12,
21, 19, 12, 12, 12, 12, 12, 12,
24, 12, 12, 12, 12, 12, 12, 12,
17, 12, 12, 12, 12, 12, 12, 12],
[13, 11, 13, 16, 20, 20, 17, 17,
11, 14, 14, 14, 14, 12, 12, 12,
13, 14, 14, 14, 12, 12, 12, 12,
16, 14, 14, 12, 12, 12, 12, 12,
20, 14, 12, 12, 12, 12, 12, 12,
20, 12, 12, 12, 12, 12, 12, 12,
17, 12, 12, 12, 12, 12, 12, 12,
17, 12, 12, 12, 12, 12, 12, 12]
]},
'high': {'subsampling': 0, # "4:4:4"
'quantization': [
[ 6, 4, 4, 6, 9, 11, 12, 16,
4, 5, 5, 6, 8, 10, 12, 12,
4, 5, 5, 6, 10, 12, 12, 12,
6, 6, 6, 11, 12, 12, 12, 12,
9, 8, 10, 12, 12, 12, 12, 12,
11, 10, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12,
16, 12, 12, 12, 12, 12, 12, 12],
[ 7, 7, 13, 24, 20, 20, 17, 17,
7, 12, 16, 14, 14, 12, 12, 12,
13, 16, 14, 14, 12, 12, 12, 12,
24, 14, 14, 12, 12, 12, 12, 12,
20, 14, 12, 12, 12, 12, 12, 12,
20, 12, 12, 12, 12, 12, 12, 12,
17, 12, 12, 12, 12, 12, 12, 12,
17, 12, 12, 12, 12, 12, 12, 12]
]},
'maximum': {'subsampling': 0, # "4:4:4"
'quantization': [
[ 2, 2, 2, 2, 3, 4, 5, 6,
2, 2, 2, 2, 3, 4, 5, 6,
2, 2, 2, 2, 4, 5, 7, 9,
2, 2, 2, 4, 5, 7, 9, 12,
3, 3, 4, 5, 8, 10, 12, 12,
4, 4, 5, 7, 10, 12, 12, 12,
5, 5, 7, 9, 12, 12, 12, 12,
6, 6, 9, 12, 12, 12, 12, 12],
[ 3, 3, 5, 9, 13, 15, 15, 15,
3, 4, 6, 10, 14, 12, 12, 12,
5, 6, 9, 14, 12, 12, 12, 12,
9, 10, 14, 12, 12, 12, 12, 12,
13, 14, 12, 12, 12, 12, 12, 12,
15, 12, 12, 12, 12, 12, 12, 12,
15, 12, 12, 12, 12, 12, 12, 12,
15, 12, 12, 12, 12, 12, 12, 12]
]},
[6, 4, 4, 6, 9, 11, 12, 16, 4, 5, 5, 6, 8, 10, 12, 12, 4, 5, 5, 6,
10, 12, 12, 12, 6, 6, 6, 11, 12, 12, 12, 12, 9, 8, 10, 12, 12, 12,
12, 12, 11, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 16, 12, 12, 12, 12, 12, 12, 12],
[7, 7, 13, 24, 20, 20, 17, 17, 7, 12, 16, 14, 14, 12, 12, 12, 13,
16, 14, 14, 12, 12, 12, 12, 24, 14, 14, 12, 12, 12, 12, 12, 20,
14, 12, 12, 12, 12, 12, 12, 20, 12, 12, 12, 12, 12, 12, 12, 17,
12, 12, 12, 12, 12, 12, 12, 17, 12, 12, 12, 12, 12, 12, 12]
]
},
'maximum': {
'subsampling': 0, # "4:4:4"
'quantization': [[2, 2, 2, 2, 3, 4, 5, 6, 2, 2, 2, 2, 3, 4, 5, 6, 2, 2,
2, 2, 4, 5, 7, 9, 2, 2, 2, 4, 5, 7, 9, 12, 3, 3, 4,
5, 8, 10, 12, 12, 4, 4, 5, 7, 10, 12, 12, 12, 5, 5,
7, 9, 12, 12, 12, 12, 6, 6, 9, 12, 12, 12, 12, 12],
[3, 3, 5, 9, 13, 15, 15, 15, 3, 4, 6, 10, 14, 12, 12,
12, 5, 6, 9, 14, 12, 12, 12, 12, 9, 10, 14, 12, 12,
12, 12, 12, 13, 14, 12, 12, 12, 12, 12, 12, 15, 12,
12, 12, 12, 12, 12, 12, 15, 12, 12, 12, 12, 12, 12,
12, 15, 12, 12, 12, 12, 12, 12, 12]]
},
}

View File

@ -25,10 +25,10 @@ from PIL import Image, ImageFile
def _accept(s):
return s[:8] == b"\x00\x00\x00\x00\x00\x00\x00\x04"
##
# Image plugin for McIdas area images.
class McIdasImageFile(ImageFile.ImageFile):
format = "MCIDAS"

View File

@ -16,14 +16,11 @@
# See the README file for information on usage and redistribution.
#
__version__ = "0.1"
from PIL import Image, TiffImagePlugin
from PIL.OleFileIO import *
#
# --------------------------------------------------------------------
@ -31,10 +28,10 @@ from PIL.OleFileIO import *
def _accept(prefix):
return prefix[:8] == MAGIC
##
# Image plugin for Microsoft's Image Composer file format.
class MicImageFile(TiffImagePlugin.TiffImageFile):
format = "MIC"

View File

@ -18,12 +18,11 @@ __version__ = "0.1"
from PIL import Image, ImageFile
from PIL._binary import i8
#
# Bitstream parser
class BitStream:
class BitStream:
def __init__(self, fp):
self.fp = fp
self.bits = 0
@ -53,11 +52,11 @@ class BitStream:
self.bits = self.bits - bits
return v
##
# Image plugin for MPEG streams. This plugin can identify a stream,
# but it cannot read it.
class MpegImageFile(ImageFile.ImageFile):
format = "MPEG"
@ -73,7 +72,6 @@ class MpegImageFile(ImageFile.ImageFile):
self.mode = "RGB"
self.size = s.read(12), s.read(12)
# --------------------------------------------------------------------
# Registry stuff

View File

@ -31,10 +31,10 @@ def _save(im, fp, filename):
# Note that we can only save the current frame at present
return JpegImagePlugin._save(im, fp, filename)
##
# Image plugin for MPO images.
class MpoImageFile(JpegImagePlugin.JpegImageFile):
format = "MPO"
@ -68,15 +68,13 @@ class MpoImageFile(JpegImagePlugin.JpegImageFile):
else:
self.fp = self.__fp
self.offset = self.__mpoffsets[frame]
self.tile = [
("jpeg", (0, 0) + self.size, self.offset, (self.mode, ""))
]
self.tile = [("jpeg", (0, 0) + self.size, self.offset,
(self.mode, ""))]
self.__frame = frame
def tell(self):
return self.__frame
# -------------------------------------------------------------------q-
# Registry stuff

View File

@ -16,12 +16,10 @@
# See the README file for information on usage and redistribution.
#
__version__ = "0.1"
from PIL import Image, ImageFile, _binary
#
# read MSP files
@ -31,11 +29,11 @@ i16 = _binary.i16le
def _accept(prefix):
return prefix[:4] in [b"DanM", b"LinS"]
##
# Image plugin for Windows MSP images. This plugin supports both
# uncompressed (Windows 1.0).
class MspImageFile(ImageFile.ImageFile):
format = "MSP"
@ -61,7 +59,8 @@ class MspImageFile(ImageFile.ImageFile):
if s[:4] == b"DanM":
self.tile = [("raw", (0, 0) + self.size, 32, ("1", 0, 1))]
else:
self.tile = [("msp", (0, 0)+self.size, 32+2*self.size[1], None)]
self.tile = [("msp",
(0, 0) + self.size, 32 + 2 * self.size[1], None)]
#
# write MSP files (uncompressed only)

View File

@ -23,14 +23,12 @@
## WARNING: THIS IS (STILL) WORK IN PROGRESS.
# Starting with OleFileIO_PL v0.30, only Python 2.6+ and 3.x is supported
# This import enables print() as a function rather than a keyword
# (main requirement to be compatible with Python 3.x)
# The comment on the line below should be printed on Python 2.5 or older:
from __future__ import print_function # This version of OleFileIO_PL requires Python 2.6+ or 3.x.
__author__ = "Philippe Lagadec, Fredrik Lundh (Secret Labs AB)"
__date__ = "2014-02-04"
__version__ = '0.30'
@ -231,7 +229,6 @@ __version__ = '0.30'
#------------------------------------------------------------------------------
import io
import sys
import struct, array, os.path, datetime
@ -259,8 +256,8 @@ elif array.array('I').itemsize == 4:
# on 64 bits platforms, integers in an array are 32 bits:
UINT32 = 'I'
else:
raise ValueError('Need to fix a bug with 32 bit arrays, please contact author...')
raise ValueError(
'Need to fix a bug with 32 bit arrays, please contact author...')
#[PL] These workarounds were inspired from the Path module
# (see http://www.jorendorff.com/articles/python/path/)
@ -283,12 +280,19 @@ KEEP_UNICODE_NAMES = False
#[PL] DEBUG display mode: False by default, use set_debug_mode() or "-d" on
# command line to change it.
DEBUG_MODE = False
def debug_print(msg):
print(msg)
def debug_pass(msg):
pass
debug = debug_pass
def set_debug_mode(debug_mode):
"""
Set debug mode on or off, to control display of debugging messages.
@ -301,18 +305,26 @@ def set_debug_mode(debug_mode):
else:
debug = debug_pass
MAGIC = b'\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1'
#[PL]: added constants for Sector IDs (from AAF specifications)
MAXREGSECT = 0xFFFFFFFA; # maximum SECT
DIFSECT = 0xFFFFFFFC; # (-4) denotes a DIFAT sector in a FAT
FATSECT = 0xFFFFFFFD; # (-3) denotes a FAT sector in a FAT
ENDOFCHAIN = 0xFFFFFFFE; # (-2) end of a virtual stream chain
FREESECT = 0xFFFFFFFF; # (-1) unallocated sector
MAXREGSECT = 0xFFFFFFFA
# maximum SECT
DIFSECT = 0xFFFFFFFC
# (-4) denotes a DIFAT sector in a FAT
FATSECT = 0xFFFFFFFD
# (-3) denotes a FAT sector in a FAT
ENDOFCHAIN = 0xFFFFFFFE
# (-2) end of a virtual stream chain
FREESECT = 0xFFFFFFFF
# (-1) unallocated sector
#[PL]: added constants for Directory Entry IDs (from AAF specifications)
MAXREGSID = 0xFFFFFFFA; # maximum directory entry ID
NOSTREAM = 0xFFFFFFFF; # (-1) unallocated directory entry
MAXREGSID = 0xFFFFFFFA
# maximum directory entry ID
NOSTREAM = 0xFFFFFFFF
# (-1) unallocated directory entry
#[PL] object types in storage (from AAF specifications)
STGTY_EMPTY = 0 # empty directory entry (according to OpenOffice.org doc)
@ -322,20 +334,51 @@ STGTY_LOCKBYTES = 3 # element is an ILockBytes object
STGTY_PROPERTY = 4 # element is an IPropertyStorage object
STGTY_ROOT = 5 # element is a root storage
#
# --------------------------------------------------------------------
# property types
VT_EMPTY=0; VT_NULL=1; VT_I2=2; VT_I4=3; VT_R4=4; VT_R8=5; VT_CY=6;
VT_DATE=7; VT_BSTR=8; VT_DISPATCH=9; VT_ERROR=10; VT_BOOL=11;
VT_VARIANT=12; VT_UNKNOWN=13; VT_DECIMAL=14; VT_I1=16; VT_UI1=17;
VT_UI2=18; VT_UI4=19; VT_I8=20; VT_UI8=21; VT_INT=22; VT_UINT=23;
VT_VOID=24; VT_HRESULT=25; VT_PTR=26; VT_SAFEARRAY=27; VT_CARRAY=28;
VT_USERDEFINED=29; VT_LPSTR=30; VT_LPWSTR=31; VT_FILETIME=64;
VT_BLOB=65; VT_STREAM=66; VT_STORAGE=67; VT_STREAMED_OBJECT=68;
VT_STORED_OBJECT=69; VT_BLOB_OBJECT=70; VT_CF=71; VT_CLSID=72;
VT_VECTOR=0x1000;
VT_EMPTY = 0
VT_NULL = 1
VT_I2 = 2
VT_I4 = 3
VT_R4 = 4
VT_R8 = 5
VT_CY = 6
VT_DATE = 7
VT_BSTR = 8
VT_DISPATCH = 9
VT_ERROR = 10
VT_BOOL = 11
VT_VARIANT = 12
VT_UNKNOWN = 13
VT_DECIMAL = 14
VT_I1 = 16
VT_UI1 = 17
VT_UI2 = 18
VT_UI4 = 19
VT_I8 = 20
VT_UI8 = 21
VT_INT = 22
VT_UINT = 23
VT_VOID = 24
VT_HRESULT = 25
VT_PTR = 26
VT_SAFEARRAY = 27
VT_CARRAY = 28
VT_USERDEFINED = 29
VT_LPSTR = 30
VT_LPWSTR = 31
VT_FILETIME = 64
VT_BLOB = 65
VT_STREAM = 66
VT_STORAGE = 67
VT_STREAMED_OBJECT = 68
VT_STORED_OBJECT = 69
VT_BLOB_OBJECT = 70
VT_CF = 71
VT_CLSID = 72
VT_VECTOR = 0x1000
# map property id to name (for debugging purposes)
@ -364,9 +407,9 @@ for key in list(vars().keys()):
if key.startswith('STGTY_') or key.startswith('DEFECT_'):
__all__.append(key)
#--- FUNCTIONS ----------------------------------------------------------------
def isOleFile(filename):
"""
Test if file is an OLE container (according to its header).
@ -391,9 +434,9 @@ else:
def i8(c):
return c if c.__class__ is int else c[0]
#TODO: replace i16 and i32 with more readable struct.unpack equivalent?
def i16(c, o=0):
"""
Converts a 2-bytes (16 bits) string to an integer.
@ -414,7 +457,8 @@ def i32(c, o = 0):
## return int(ord(c[o])+(ord(c[o+1])<<8)+(ord(c[o+2])<<16)+(ord(c[o+3])<<24))
## # [PL]: added int() because "<<" gives long int since Python 2.4
# copied from Pillow's _binary:
return i8(c[o]) | (i8(c[o+1])<<8) | (i8(c[o+2])<<16) | (i8(c[o+3])<<24)
return i8(c[o]) | (i8(c[o + 1]) << 8) | (i8(c[o + 2]) << 16) | (
i8(c[o + 3]) << 24)
def _clsid(clsid):
@ -432,11 +476,10 @@ def _clsid(clsid):
((i32(clsid, 0), i16(clsid, 4), i16(clsid, 6)) +
tuple(map(i8, clsid[8:16]))))
# UNICODE support:
# (necessary to handle storages/streams names which use Unicode)
def _unicode(s, errors='replace'):
"""
Map unicode string to Latin 1. (Python with Unicode support)
@ -470,10 +513,9 @@ def filetime2datetime(filetime):
#debug('timedelta days=%d' % (filetime//(10*1000000*3600*24)))
return _FILETIME_null_date + datetime.timedelta(microseconds=filetime // 10)
#=== CLASSES ==================================================================
class OleMetadata:
"""
class to parse and store metadata from standard properties of OLE files.
@ -509,20 +551,23 @@ class OleMetadata:
# attribute names for SummaryInformation stream properties:
# (ordered by property id, starting at 1)
SUMMARY_ATTRIBS = ['codepage', 'title', 'subject', 'author', 'keywords', 'comments',
'template', 'last_saved_by', 'revision_number', 'total_edit_time',
'last_printed', 'create_time', 'last_saved_time', 'num_pages',
'num_words', 'num_chars', 'thumbnail', 'creating_application',
'security']
SUMMARY_ATTRIBS = ['codepage', 'title', 'subject', 'author', 'keywords',
'comments', 'template', 'last_saved_by',
'revision_number', 'total_edit_time', 'last_printed',
'create_time', 'last_saved_time', 'num_pages',
'num_words', 'num_chars', 'thumbnail',
'creating_application', 'security']
# attribute names for DocumentSummaryInformation stream properties:
# (ordered by property id, starting at 1)
DOCSUM_ATTRIBS = ['codepage_doc', 'category', 'presentation_target', 'bytes', 'lines', 'paragraphs',
'slides', 'notes', 'hidden_slides', 'mm_clips',
'scale_crop', 'heading_pairs', 'titles_of_parts', 'manager',
'company', 'links_dirty', 'chars_with_spaces', 'unused', 'shared_doc',
'link_base', 'hlinks', 'hlinks_changed', 'version', 'dig_sig',
'content_type', 'content_status', 'language', 'doc_version']
DOCSUM_ATTRIBS = ['codepage_doc', 'category', 'presentation_target',
'bytes', 'lines', 'paragraphs', 'slides', 'notes',
'hidden_slides', 'mm_clips', 'scale_crop',
'heading_pairs', 'titles_of_parts', 'manager', 'company',
'links_dirty', 'chars_with_spaces', 'unused',
'shared_doc', 'link_base', 'hlinks', 'hlinks_changed',
'version', 'dig_sig', 'content_type', 'content_status',
'language', 'doc_version']
def __init__(self):
"""
@ -579,7 +624,6 @@ class OleMetadata:
self.language = None
self.doc_version = None
def parse_properties(self, olefile):
"""
Parse standard properties of an OLE file, from the streams
@ -596,7 +640,8 @@ class OleMetadata:
# (converting timestamps to python datetime, except total_edit_time,
# which is property #10)
props = olefile.getproperties("\x05SummaryInformation",
convert_time=True, no_conversion=[10])
convert_time=True,
no_conversion=[10])
# store them into this object's attributes:
for i in range(len(self.SUMMARY_ATTRIBS)):
# ids for standards properties start at 0x01, until 0x13
@ -625,9 +670,9 @@ class OleMetadata:
value = getattr(self, prop)
print('- %s: %s' % (prop, repr(value)))
#--- _OleStream ---------------------------------------------------------------
class _OleStream(io.BytesIO):
"""
OLE2 Stream
@ -662,7 +707,8 @@ class _OleStream(io.BytesIO):
:returns : a BytesIO instance containing the OLE stream
"""
debug('_OleStream.__init__:')
debug(' sect=%d (%X), size=%d, offset=%d, sectorsize=%d, len(fat)=%d, fp=%s'
debug(
' sect=%d (%X), size=%d, offset=%d, sectorsize=%d, len(fat)=%d, fp=%s'
% (sect, sect, size, offset, sectorsize, len(fat), repr(fp)))
#[PL] To detect malformed documents with FAT loops, we compute the
# expected number of sectors in the stream:
@ -724,9 +770,12 @@ class _OleStream(io.BytesIO):
# complete sector (of 512 or 4K), so we may read less than
# sectorsize.
if len(sector_data) != sectorsize and sect != (len(fat) - 1):
debug('sect=%d / len(fat)=%d, seek=%d / filesize=%d, len read=%d' %
(sect, len(fat), offset+sectorsize*sect, filesize, len(sector_data)))
debug('seek+len(read)=%d' % (offset+sectorsize*sect+len(sector_data)))
debug(
'sect=%d / len(fat)=%d, seek=%d / filesize=%d, len read=%d' %
(sect, len(fat), offset + sectorsize * sect, filesize,
len(sector_data)))
debug('seek+len(read)=%d' %
(offset + sectorsize * sect + len(sector_data)))
raise IOError('incomplete OLE sector')
data.append(sector_data)
# jump to next sector in the FAT:
@ -756,11 +805,10 @@ class _OleStream(io.BytesIO):
io.BytesIO.__init__(self, data)
# Then the _OleStream object can be used as a read-only file object.
#--- _OleDirectoryEntry -------------------------------------------------------
class _OleDirectoryEntry:
class _OleDirectoryEntry:
"""
OLE2 Directory Entry
"""
@ -789,7 +837,6 @@ class _OleDirectoryEntry:
DIRENTRY_SIZE = 128
assert struct.calcsize(STRUCT_DIRENTRY) == DIRENTRY_SIZE
def __init__(self, entry, sid, olefile):
"""
Constructor for an _OleDirectoryEntry object.
@ -813,24 +860,14 @@ class _OleDirectoryEntry:
# directory:
self.used = False
# decode DirEntry
(
name,
namelength,
self.entry_type,
self.color,
self.sid_left,
self.sid_right,
self.sid_child,
clsid,
self.dwUserFlags,
self.createTime,
self.modifyTime,
self.isectStart,
sizeLow,
sizeHigh
) = struct.unpack(_OleDirectoryEntry.STRUCT_DIRENTRY, entry)
if self.entry_type not in [STGTY_ROOT, STGTY_STORAGE, STGTY_STREAM, STGTY_EMPTY]:
olefile._raise_defect(DEFECT_INCORRECT, 'unhandled OLE storage type')
(name, namelength, self.entry_type, self.color, self.sid_left,
self.sid_right, self.sid_child, clsid, self.dwUserFlags,
self.createTime, self.modifyTime, self.isectStart, sizeLow,
sizeHigh) = struct.unpack(_OleDirectoryEntry.STRUCT_DIRENTRY, entry)
if self.entry_type not in [STGTY_ROOT, STGTY_STORAGE, STGTY_STREAM,
STGTY_EMPTY]:
olefile._raise_defect(DEFECT_INCORRECT,
'unhandled OLE storage type')
# only first directory entry can (and should) be root:
if self.entry_type == STGTY_ROOT and sid != 0:
olefile._raise_defect(DEFECT_INCORRECT, 'duplicate OLE root entry')
@ -840,7 +877,8 @@ class _OleDirectoryEntry:
# name should be at most 31 unicode characters + null character,
# so 64 bytes in total (31*2 + 2):
if namelength > 64:
olefile._raise_defect(DEFECT_INCORRECT, 'incorrect DirEntry name length')
olefile._raise_defect(DEFECT_INCORRECT,
'incorrect DirEntry name length')
# if exception not raised, namelength is set to the maximum value:
namelength = 64
# only characters without ending null char are kept:
@ -851,8 +889,8 @@ class _OleDirectoryEntry:
debug('DirEntry SID=%d: %s' % (self.sid, repr(self.name)))
debug(' - type: %d' % self.entry_type)
debug(' - sect: %d' % self.isectStart)
debug(' - SID left: %d, right: %d, child: %d' % (self.sid_left,
self.sid_right, self.sid_child))
debug(' - SID left: %d, right: %d, child: %d' %
(self.sid_left, self.sid_right, self.sid_child))
# sizeHigh is only used for 4K sectors, it should be zero for 512 bytes
# sectors, BUT apparently some implementations set it as 0xFFFFFFFF, 1
@ -861,11 +899,13 @@ class _OleDirectoryEntry:
if sizeHigh != 0 and sizeHigh != 0xFFFFFFFF:
debug('sectorsize=%d, sizeLow=%d, sizeHigh=%d (%X)' %
(olefile.sectorsize, sizeLow, sizeHigh, sizeHigh))
olefile._raise_defect(DEFECT_UNSURE, 'incorrect OLE stream size')
olefile._raise_defect(DEFECT_UNSURE,
'incorrect OLE stream size')
self.size = sizeLow
else:
self.size = sizeLow + (long(sizeHigh) << 32)
debug(' - size: %d (sizeLow=%d, sizeHigh=%d)' % (self.size, sizeLow, sizeHigh))
debug(' - size: %d (sizeLow=%d, sizeHigh=%d)' %
(self.size, sizeLow, sizeHigh))
self.clsid = _clsid(clsid)
# a storage should have a null size, BUT some implementations such as
@ -882,8 +922,6 @@ class _OleDirectoryEntry:
minifat = False
olefile._check_duplicate_stream(self.isectStart, minifat)
def build_storage_tree(self):
"""
Read and build the red-black tree attached to this _OleDirectoryEntry
@ -891,8 +929,8 @@ class _OleDirectoryEntry:
Note that this method builds a tree of all subentries, so it should
only be called for the root object once.
"""
debug('build_storage_tree: SID=%d - %s - sid_child=%d'
% (self.sid, repr(self.name), self.sid_child))
debug('build_storage_tree: SID=%d - %s - sid_child=%d' %
(self.sid, repr(self.name), self.sid_child))
if self.sid_child != NOSTREAM:
# if child SID is not NOSTREAM, then this entry is a storage.
# Let's walk through the tree of children to fill the kids list:
@ -907,7 +945,6 @@ class _OleDirectoryEntry:
# (see rich comparison methods in this class)
self.kids.sort()
def append_kids(self, child_sid):
"""
Walk through red-black tree of children of this directory entry to add
@ -923,11 +960,14 @@ class _OleDirectoryEntry:
return
# check if child SID is in the proper range:
if child_sid < 0 or child_sid >= len(self.olefile.direntries):
self.olefile._raise_defect(DEFECT_FATAL, 'OLE DirEntry index out of range')
self.olefile._raise_defect(DEFECT_FATAL,
'OLE DirEntry index out of range')
# get child direntry:
child = self.olefile._load_direntry(child_sid) #direntries[child_sid]
debug('append_kids: child_sid=%d - %s - sid_left=%d, sid_right=%d, sid_child=%d'
% (child.sid, repr(child.name), child.sid_left, child.sid_right, child.sid_child))
debug(
'append_kids: child_sid=%d - %s - sid_left=%d, sid_right=%d, sid_child=%d'
% (child.sid, repr(child.name), child.sid_left, child.sid_right,
child.sid_child))
# the directory entries are organized as a red-black tree.
# (cf. Wikipedia for details)
# First walk through left side of the tree:
@ -951,7 +991,6 @@ class _OleDirectoryEntry:
# Afterwards build kid's own tree if it's also a storage:
child.build_storage_tree()
def __eq__(self, other):
"Compare entries by name"
return self.name == other.name
@ -971,7 +1010,6 @@ class _OleDirectoryEntry:
#TODO: replace by the same function as MS implementation ?
# (order by name length first, then case-insensitive order)
def dump(self, tab=0):
"Dump this entry, and all its subentries (for debug purposes only)"
TYPES = ["(invalid)", "(storage)", "(stream)", "(lockbytes)",
@ -986,7 +1024,6 @@ class _OleDirectoryEntry:
for kid in self.kids:
kid.dump(tab + 2)
def getmtime(self):
"""
Return modification time of a directory entry.
@ -1000,7 +1037,6 @@ class _OleDirectoryEntry:
return None
return filetime2datetime(self.modifyTime)
def getctime(self):
"""
Return creation time of a directory entry.
@ -1014,9 +1050,9 @@ class _OleDirectoryEntry:
return None
return filetime2datetime(self.createTime)
#--- OleFileIO ----------------------------------------------------------------
class OleFileIO:
"""
OLE container object
@ -1064,7 +1100,6 @@ class OleFileIO:
if filename:
self.open(filename)
def _raise_defect(self, defect_level, message, exception_type=IOError):
"""
This method should be called for any defect found during file parsing.
@ -1086,7 +1121,6 @@ class OleFileIO:
# just record the issue, no exception raised:
self.parsing_issues.append((exception_type, message))
def open(self, filename):
"""
Open an OLE2 file.
@ -1127,7 +1161,8 @@ class OleFileIO:
header = self.fp.read(512)
if len(header) != 512 or header[:8] != MAGIC:
self._raise_defect(DEFECT_FATAL, "not an OLE2 structured storage file")
self._raise_defect(DEFECT_FATAL,
"not an OLE2 structured storage file")
# [PL] header structure according to AAF specifications:
##Header
@ -1168,27 +1203,15 @@ class OleFileIO:
# '<' indicates little-endian byte ordering for Intel (cf. struct module help)
fmt_header = '<8s16sHHHHHHLLLLLLLLLL'
header_size = struct.calcsize(fmt_header)
debug( "fmt_header size = %d, +FAT = %d" % (header_size, header_size + 109*4) )
debug("fmt_header size = %d, +FAT = %d" %
(header_size, header_size + 109 * 4))
header1 = header[:header_size]
(
self.Sig,
self.clsid,
self.MinorVersion,
self.DllVersion,
self.ByteOrder,
self.SectorShift,
self.MiniSectorShift,
self.Reserved, self.Reserved1,
self.csectDir,
self.csectFat,
self.sectDirStart,
self.signature,
self.MiniSectorCutoff,
self.MiniFatStart,
self.csectMiniFat,
self.sectDifStart,
self.csectDif
) = struct.unpack(fmt_header, header1)
(self.Sig, self.clsid, self.MinorVersion, self.DllVersion,
self.ByteOrder, self.SectorShift, self.MiniSectorShift, self.Reserved,
self.Reserved1, self.csectDir, self.csectFat, self.sectDirStart,
self.signature, self.MiniSectorCutoff, self.MiniFatStart,
self.csectMiniFat, self.sectDifStart,
self.csectDif) = struct.unpack(fmt_header, header1)
debug(struct.unpack(fmt_header, header1))
if self.Sig != MAGIC:
@ -1196,41 +1219,51 @@ class OleFileIO:
self._raise_defect(DEFECT_FATAL, "incorrect OLE signature")
if self.clsid != bytearray(16):
# according to AAF specs, CLSID should always be zero
self._raise_defect(DEFECT_INCORRECT, "incorrect CLSID in OLE header")
self._raise_defect(DEFECT_INCORRECT,
"incorrect CLSID in OLE header")
debug("MinorVersion = %d" % self.MinorVersion)
debug("DllVersion = %d" % self.DllVersion)
if self.DllVersion not in [3, 4]:
# version 3: usual format, 512 bytes per sector
# version 4: large format, 4K per sector
self._raise_defect(DEFECT_INCORRECT, "incorrect DllVersion in OLE header")
self._raise_defect(DEFECT_INCORRECT,
"incorrect DllVersion in OLE header")
debug("ByteOrder = %X" % self.ByteOrder)
if self.ByteOrder != 0xFFFE:
# For now only common little-endian documents are handled correctly
self._raise_defect(DEFECT_FATAL, "incorrect ByteOrder in OLE header")
self._raise_defect(DEFECT_FATAL,
"incorrect ByteOrder in OLE header")
# TODO: add big-endian support for documents created on Mac ?
self.SectorSize = 2 ** self.SectorShift
debug("SectorSize = %d" % self.SectorSize)
if self.SectorSize not in [512, 4096]:
self._raise_defect(DEFECT_INCORRECT, "incorrect SectorSize in OLE header")
self._raise_defect(DEFECT_INCORRECT,
"incorrect SectorSize in OLE header")
if (self.DllVersion == 3 and self.SectorSize != 512) \
or (self.DllVersion == 4 and self.SectorSize != 4096):
self._raise_defect(DEFECT_INCORRECT, "SectorSize does not match DllVersion in OLE header")
self._raise_defect(
DEFECT_INCORRECT,
"SectorSize does not match DllVersion in OLE header")
self.MiniSectorSize = 2 ** self.MiniSectorShift
debug("MiniSectorSize = %d" % self.MiniSectorSize)
if self.MiniSectorSize not in [64]:
self._raise_defect(DEFECT_INCORRECT, "incorrect MiniSectorSize in OLE header")
self._raise_defect(DEFECT_INCORRECT,
"incorrect MiniSectorSize in OLE header")
if self.Reserved != 0 or self.Reserved1 != 0:
self._raise_defect(DEFECT_INCORRECT, "incorrect OLE header (non-null reserved bytes)")
self._raise_defect(DEFECT_INCORRECT,
"incorrect OLE header (non-null reserved bytes)")
debug("csectDir = %d" % self.csectDir)
if self.SectorSize == 512 and self.csectDir != 0:
self._raise_defect(DEFECT_INCORRECT, "incorrect csectDir in OLE header")
self._raise_defect(DEFECT_INCORRECT,
"incorrect csectDir in OLE header")
debug("csectFat = %d" % self.csectFat)
debug("sectDirStart = %X" % self.sectDirStart)
debug("signature = %d" % self.signature)
# Signature should be zero, BUT some implementations do not follow this
# rule => only a potential defect:
if self.signature != 0:
self._raise_defect(DEFECT_POTENTIAL, "incorrect OLE header (signature>0)")
self._raise_defect(DEFECT_POTENTIAL,
"incorrect OLE header (signature>0)")
debug("MiniSectorCutoff = %d" % self.MiniSectorCutoff)
debug("MiniFatStart = %X" % self.MiniFatStart)
debug("csectMiniFat = %d" % self.csectMiniFat)
@ -1239,7 +1272,8 @@ class OleFileIO:
# calculate the number of sectors in the file
# (-1 because header doesn't count)
self.nb_sect = ( (filesize + self.SectorSize-1) // self.SectorSize) - 1
self.nb_sect = (
(filesize + self.SectorSize - 1) // self.SectorSize) - 1
debug("Number of sectors in the file: %d" % self.nb_sect)
# file clsid (probably never used, so we don't store it)
@ -1266,14 +1300,12 @@ class OleFileIO:
self.ministream = None
self.minifatsect = self.MiniFatStart #i32(header, 60)
def close(self):
"""
close the OLE file, to release the file object
"""
self.fp.close()
def _check_duplicate_stream(self, first_sect, minifat=False):
"""
Checks if a stream has not been already referenced elsewhere.
@ -1298,7 +1330,6 @@ class OleFileIO:
else:
used_streams.append(first_sect)
def dumpfat(self, fat, firstindex=0):
"Displays a part of FAT in human-readable form for debugging purpose"
# [PL] added only for debug
@ -1335,7 +1366,6 @@ class OleFileIO:
print(nom, end=" ")
print()
def dumpsect(self, sector, firstindex=0):
"Displays a sector in a human-readable form, for debugging purpose."
if not DEBUG_MODE:
@ -1370,7 +1400,6 @@ class OleFileIO:
a.byteswap()
return a
def loadfat_sect(self, sect):
"""
Adds the indexes of the given sector to the FAT
@ -1400,7 +1429,6 @@ class OleFileIO:
self.fat = self.fat + nextfat
return isect
def loadfat(self, header):
"""
Load the FAT table.
@ -1432,10 +1460,12 @@ class OleFileIO:
if self.csectFat <= 109:
# there must be at least 109 blocks in header and the rest in
# DIFAT, so number of sectors must be >109.
self._raise_defect(DEFECT_INCORRECT, 'incorrect DIFAT, not enough sectors')
self._raise_defect(DEFECT_INCORRECT,
'incorrect DIFAT, not enough sectors')
if self.sectDifStart >= self.nb_sect:
# initial DIFAT block index must be valid
self._raise_defect(DEFECT_FATAL, 'incorrect DIFAT, first index out of range')
self._raise_defect(DEFECT_FATAL,
'incorrect DIFAT, first index out of range')
debug("DIFAT analysis...")
# We compute the necessary number of DIFAT sectors :
# (each DIFAT sector = 127 pointers + 1 towards next DIFAT sector)
@ -1466,12 +1496,12 @@ class OleFileIO:
# than the actual number of sectors in the file.
# Keep only the relevant sector indexes:
if len(self.fat) > self.nb_sect:
debug('len(fat)=%d, shrunk to nb_sect=%d' % (len(self.fat), self.nb_sect))
debug('len(fat)=%d, shrunk to nb_sect=%d' %
(len(self.fat), self.nb_sect))
self.fat = self.fat[:self.nb_sect]
debug('\nFAT:')
self.dumpfat(self.fat)
def loadminifat(self):
"""
Load the MiniFAT table.
@ -1487,20 +1517,25 @@ class OleFileIO:
# 2) Actually used size is calculated by dividing the MiniStream size
# (given by root entry size) by the size of mini sectors, *4 for
# 32 bits indexes:
nb_minisectors = (self.root.size + self.MiniSectorSize-1) // self.MiniSectorSize
nb_minisectors = (self.root.size + self.MiniSectorSize -
1) // self.MiniSectorSize
used_size = nb_minisectors * 4
debug('loadminifat(): minifatsect=%d, nb FAT sectors=%d, used_size=%d, stream_size=%d, nb MiniSectors=%d' %
(self.minifatsect, self.csectMiniFat, used_size, stream_size, nb_minisectors))
debug(
'loadminifat(): minifatsect=%d, nb FAT sectors=%d, used_size=%d, stream_size=%d, nb MiniSectors=%d'
% (self.minifatsect, self.csectMiniFat, used_size, stream_size,
nb_minisectors))
if used_size > stream_size:
# This is not really a problem, but may indicate a wrong implementation:
self._raise_defect(DEFECT_INCORRECT, 'OLE MiniStream is larger than MiniFAT')
self._raise_defect(DEFECT_INCORRECT,
'OLE MiniStream is larger than MiniFAT')
# In any case, first read stream_size:
s = self._open(self.minifatsect, stream_size, force_FAT=True).read()
#[PL] Old code replaced by an array:
#self.minifat = [i32(s, i) for i in range(0, len(s), 4)]
self.minifat = self.sect2array(s)
# Then shrink the array to used size, to avoid indexes out of MiniStream:
debug('MiniFAT shrunk from %d to %d sectors' % (len(self.minifat), nb_minisectors))
debug('MiniFAT shrunk from %d to %d sectors' %
(len(self.minifat), nb_minisectors))
self.minifat = self.minifat[:nb_minisectors]
debug('loadminifat(): len=%d' % len(self.minifat))
debug('\nMiniFAT:')
@ -1531,7 +1566,6 @@ class OleFileIO:
self._raise_defect(DEFECT_FATAL, 'incomplete OLE sector')
return sector
def loaddirectory(self, sect):
"""
Load the directory.
@ -1567,7 +1601,6 @@ class OleFileIO:
# read and build all storage trees, starting from the root:
self.root.build_storage_tree()
def _load_direntry(self, sid):
"""
Load a directory entry from the directory.
@ -1592,14 +1625,12 @@ class OleFileIO:
self.direntries[sid] = _OleDirectoryEntry(entry, sid, self)
return self.direntries[sid]
def dumpdirectory(self):
"""
Dump directory (for debugging only)
"""
self.root.dump()
def _open(self, start, size=0x7FFFFFFF, force_FAT=False):
"""
Open a stream, either in FAT or MiniFAT according to its size.
@ -1624,15 +1655,15 @@ class OleFileIO:
debug('Opening MiniStream: sect=%d, size=%d' %
(self.root.isectStart, size_ministream))
self.ministream = self._open(self.root.isectStart,
size_ministream, force_FAT=True)
size_ministream,
force_FAT=True)
return _OleStream(self.ministream, start, size, 0,
self.minisectorsize, self.minifat,
self.ministream.size)
else:
# standard stream
return _OleStream(self.fp, start, size, 512,
self.sectorsize, self.fat, self._filesize)
return _OleStream(self.fp, start, size, 512, self.sectorsize,
self.fat, self._filesize)
def _list(self, files, prefix, node, streams=True, storages=False):
"""
@ -1659,7 +1690,6 @@ class OleFileIO:
# add it to the list
files.append(prefix[1:] + [entry.name])
def listdir(self, streams=True, storages=False):
"""
Return a list of streams stored in this file
@ -1672,7 +1702,6 @@ class OleFileIO:
self._list(files, [], self.root, streams, storages)
return files
def _find(self, filename):
"""
Returns directory entry of given filename. (openstream helper)
@ -1703,7 +1732,6 @@ class OleFileIO:
node = kid
return node.sid
def openstream(self, filename):
"""
Open a stream as a read-only file object (BytesIO).
@ -1724,7 +1752,6 @@ class OleFileIO:
raise IOError("this file is not a stream")
return self._open(entry.isectStart, entry.size)
def get_type(self, filename):
"""
Test if given filename exists as a stream or a storage in the OLE
@ -1744,7 +1771,6 @@ class OleFileIO:
except:
return False
def getmtime(self, filename):
"""
Return modification time of a stream/storage.
@ -1760,7 +1786,6 @@ class OleFileIO:
entry = self.direntries[sid]
return entry.getmtime()
def getctime(self, filename):
"""
Return creation time of a stream/storage.
@ -1776,7 +1801,6 @@ class OleFileIO:
entry = self.direntries[sid]
return entry.getctime()
def exists(self, filename):
"""
Test if given filename exists as a stream or a storage in the OLE
@ -1791,7 +1815,6 @@ class OleFileIO:
except:
return False
def get_size(self, filename):
"""
Return size of a stream in the OLE container, in bytes.
@ -1808,7 +1831,6 @@ class OleFileIO:
raise TypeError('object is not an OLE stream')
return entry.size
def get_rootentry_name(self):
"""
Return root entry name. Should usually be 'Root Entry' or 'R' in most
@ -1816,7 +1838,6 @@ class OleFileIO:
"""
return self.root.name
def getproperties(self, filename, convert_time=False, no_conversion=None):
"""
Return properties described in substream.
@ -1909,17 +1930,22 @@ class OleFileIO:
count = i32(s, offset + 4)
value = _unicode(s[offset + 8:offset + 8 + count * 2])
elif type == VT_FILETIME:
value = long(i32(s, offset+4)) + (long(i32(s, offset+8))<<32)
value = long(i32(s, offset + 4)) + (long(i32(s, offset +
8)) << 32)
# FILETIME is a 64-bit int: "number of 100ns periods
# since Jan 1,1601".
if convert_time and id not in no_conversion:
debug('Converting property #%d to python datetime, value=%d=%fs'
debug(
'Converting property #%d to python datetime, value=%d=%fs'
% (id, value, float(value) / 10000000))
# convert FILETIME to Python datetime.datetime
# inspired from http://code.activestate.com/recipes/511425-filetime-to-datetime/
_FILETIME_null_date = datetime.datetime(1601, 1, 1, 0, 0, 0)
debug('timedelta days=%d' % (value//(10*1000000*3600*24)))
value = _FILETIME_null_date + datetime.timedelta(microseconds=value//10)
_FILETIME_null_date = datetime.datetime(1601, 1, 1, 0,
0, 0)
debug('timedelta days=%d' %
(value // (10 * 1000000 * 3600 * 24)))
value = _FILETIME_null_date + datetime.timedelta(
microseconds=value // 10)
else:
# legacy code kept for backward compatibility: returns a
# number of seconds since Jan 1,1601
@ -1939,7 +1965,9 @@ class OleFileIO:
value = bool(i16(s, offset + 4))
else:
value = None # everything else yields "None"
debug ('property id=%d: type=%d not implemented in parser yet' % (id, type))
debug(
'property id=%d: type=%d not implemented in parser yet' %
(id, type))
# missing: VT_EMPTY, VT_NULL, VT_R4, VT_R8, VT_CY, VT_DATE,
# VT_DECIMAL, VT_I1, VT_I8, VT_UI8,
@ -2027,8 +2055,9 @@ Options:
v = v[:50]
if isinstance(v, bytes):
# quick and dirty binary check:
for c in (1,2,3,4,5,6,7,11,12,14,15,16,17,18,19,20,
21,22,23,24,25,26,27,28,29,30,31):
for c in (1, 2, 3, 4, 5, 6, 7, 11, 12, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
29, 30, 31):
if c in bytearray(v):
v = '(binary data)'
break
@ -2058,8 +2087,8 @@ Options:
print('Modification/Creation times of all directory entries:')
for entry in ole.direntries:
if entry is not None:
print('- %s: mtime=%s ctime=%s' % (entry.name,
entry.getmtime(), entry.getctime()))
print('- %s: mtime=%s ctime=%s' %
(entry.name, entry.getmtime(), entry.getctime()))
print()
# parse and display metadata:
@ -2071,7 +2100,8 @@ Options:
print('Root entry name: "%s"' % root)
if ole.exists('worddocument'):
print("This is a Word document.")
print("type of stream 'WordDocument':", ole.get_type('worddocument'))
print("type of stream 'WordDocument':",
ole.get_type('worddocument'))
print("size :", ole.get_size('worddocument'))
if ole.exists('macros/vba'):
print("This document may contain VBA macros.")

View File

@ -19,10 +19,10 @@ from __future__ import print_function
from PIL import EpsImagePlugin
##
# Simple Postscript graphics interface.
class PSDraw:
"""
Sets up printing to the given file. If **file** is omitted,
@ -57,9 +57,7 @@ class PSDraw:
def end_document(self):
"""Ends printing. (Write Postscript DSC footer.)"""
self._fp_write("%%EndDocument\n"
"restore showpage\n"
"%%End\n")
self._fp_write("%%EndDocument\n" "restore showpage\n" "%%End\n")
if hasattr(self.fp, "flush"):
self.fp.flush()

View File

@ -15,10 +15,10 @@
from PIL._binary import o8
##
# File handler for Teragon-style palette files.
class PaletteFile:
rawmode = "RGB"

View File

@ -29,53 +29,47 @@ _Palm8BitColormapValues = (
(102, 153, 255), (102, 102, 255), (102, 51, 255), (102, 0, 255),
(102, 255, 204), (102, 204, 204), (102, 153, 204), (102, 102, 204),
(102, 51, 204), (102, 0, 204), (102, 255, 153), (102, 204, 153),
(102, 153, 153), (102, 102, 153), (102, 51, 153), (102, 0, 153),
( 51, 255, 255), ( 51, 204, 255), ( 51, 153, 255), ( 51, 102, 255),
( 51, 51, 255), ( 51, 0, 255), ( 51, 255, 204), ( 51, 204, 204),
( 51, 153, 204), ( 51, 102, 204), ( 51, 51, 204), ( 51, 0, 204),
( 51, 255, 153), ( 51, 204, 153), ( 51, 153, 153), ( 51, 102, 153),
( 51, 51, 153), ( 51, 0, 153), ( 0, 255, 255), ( 0, 204, 255),
( 0, 153, 255), ( 0, 102, 255), ( 0, 51, 255), ( 0, 0, 255),
( 0, 255, 204), ( 0, 204, 204), ( 0, 153, 204), ( 0, 102, 204),
( 0, 51, 204), ( 0, 0, 204), ( 0, 255, 153), ( 0, 204, 153),
( 0, 153, 153), ( 0, 102, 153), ( 0, 51, 153), ( 0, 0, 153),
(255, 255, 102), (255, 204, 102), (255, 153, 102), (255, 102, 102),
(255, 51, 102), (255, 0, 102), (255, 255, 51), (255, 204, 51),
(255, 153, 51), (255, 102, 51), (255, 51, 51), (255, 0, 51),
(255, 255, 0), (255, 204, 0), (255, 153, 0), (255, 102, 0),
(255, 51, 0), (255, 0, 0), (204, 255, 102), (204, 204, 102),
(204, 153, 102), (204, 102, 102), (204, 51, 102), (204, 0, 102),
(204, 255, 51), (204, 204, 51), (204, 153, 51), (204, 102, 51),
(204, 51, 51), (204, 0, 51), (204, 255, 0), (204, 204, 0),
(204, 153, 0), (204, 102, 0), (204, 51, 0), (204, 0, 0),
(153, 255, 102), (153, 204, 102), (153, 153, 102), (153, 102, 102),
(153, 51, 102), (153, 0, 102), (153, 255, 51), (153, 204, 51),
(153, 153, 51), (153, 102, 51), (153, 51, 51), (153, 0, 51),
(153, 255, 0), (153, 204, 0), (153, 153, 0), (153, 102, 0),
(153, 51, 0), (153, 0, 0), (102, 255, 102), (102, 204, 102),
(102, 153, 102), (102, 102, 102), (102, 51, 102), (102, 0, 102),
(102, 255, 51), (102, 204, 51), (102, 153, 51), (102, 102, 51),
(102, 51, 51), (102, 0, 51), (102, 255, 0), (102, 204, 0),
(102, 153, 0), (102, 102, 0), (102, 51, 0), (102, 0, 0),
( 51, 255, 102), ( 51, 204, 102), ( 51, 153, 102), ( 51, 102, 102),
( 51, 51, 102), ( 51, 0, 102), ( 51, 255, 51), ( 51, 204, 51),
( 51, 153, 51), ( 51, 102, 51), ( 51, 51, 51), ( 51, 0, 51),
( 51, 255, 0), ( 51, 204, 0), ( 51, 153, 0), ( 51, 102, 0),
( 51, 51, 0), ( 51, 0, 0), ( 0, 255, 102), ( 0, 204, 102),
( 0, 153, 102), ( 0, 102, 102), ( 0, 51, 102), ( 0, 0, 102),
( 0, 255, 51), ( 0, 204, 51), ( 0, 153, 51), ( 0, 102, 51),
( 0, 51, 51), ( 0, 0, 51), ( 0, 255, 0), ( 0, 204, 0),
( 0, 153, 0), ( 0, 102, 0), ( 0, 51, 0), ( 17, 17, 17),
( 34, 34, 34), ( 68, 68, 68), ( 85, 85, 85), (119, 119, 119),
(136, 136, 136), (170, 170, 170), (187, 187, 187), (221, 221, 221),
(238, 238, 238), (192, 192, 192), (128, 0, 0), (128, 0, 128),
( 0, 128, 0), ( 0, 128, 128), ( 0, 0, 0), ( 0, 0, 0),
( 0, 0, 0), ( 0, 0, 0), ( 0, 0, 0), ( 0, 0, 0),
( 0, 0, 0), ( 0, 0, 0), ( 0, 0, 0), ( 0, 0, 0),
( 0, 0, 0), ( 0, 0, 0), ( 0, 0, 0), ( 0, 0, 0),
( 0, 0, 0), ( 0, 0, 0), ( 0, 0, 0), ( 0, 0, 0),
( 0, 0, 0), ( 0, 0, 0), ( 0, 0, 0), ( 0, 0, 0),
( 0, 0, 0), ( 0, 0, 0), ( 0, 0, 0), ( 0, 0, 0))
(102, 153, 153), (102, 102, 153), (102, 51, 153), (102, 0, 153), (
51, 255, 255), (51, 204, 255), (51, 153, 255), (51, 102, 255),
(51, 51, 255), (51, 0, 255), (51, 255, 204), (51, 204, 204), (51, 153, 204
), (51, 102, 204), (51, 51, 204), (51, 0, 204), (51, 255, 153), (
51, 204, 153), (51, 153, 153), (51, 102, 153), (51, 51, 153),
(51, 0, 153), (0, 255, 255), (0, 204, 255), (0, 153, 255), (0, 102, 255), (
0, 51, 255), (0, 0, 255), (0, 255, 204), (0, 204, 204), (0, 153, 204),
(0, 102, 204), (0, 51, 204), (0, 0, 204), (0, 255, 153), (0, 204, 153), (
0, 153, 153), (0, 102, 153), (0, 51, 153), (0, 0, 153), (255, 255, 102
), (255, 204, 102), (255, 153, 102), (255, 102, 102), (255, 51, 102), (
255, 0, 102), (255, 255, 51), (255, 204, 51), (255, 153, 51),
(255, 102, 51), (255, 51, 51), (255, 0, 51), (255, 255, 0), (255, 204, 0),
(255, 153, 0), (255, 102, 0), (255, 51, 0), (255, 0, 0), (204, 255, 102), (
204, 204, 102), (204, 153, 102), (204, 102, 102), (204, 51, 102), (
204, 0, 102), (204, 255, 51), (204, 204, 51), (204, 153, 51),
(204, 102, 51), (204, 51, 51), (204, 0, 51), (204, 255, 0), (204, 204, 0),
(204, 153, 0), (204, 102, 0), (204, 51, 0), (204, 0, 0), (153, 255, 102), (
153, 204, 102), (153, 153, 102), (153, 102, 102), (153, 51, 102), (
153, 0, 102), (153, 255, 51), (153, 204, 51), (153, 153, 51), (
153, 102, 51), (153, 51, 51), (153, 0, 51), (153, 255, 0
), (153, 204, 0), (153, 153, 0), (153, 102, 0), (153, 51, 0), (
153, 0, 0), (102, 255, 102), (102, 204, 102), (102, 153, 102), (
102, 102, 102), (102, 51, 102), (102, 0, 102), (102, 255, 51), (
102, 204, 51), (102, 153, 51), (102, 102, 51), (102, 51, 51
), (102, 0, 51), (102, 255, 0), (102, 204, 0), (102, 153, 0), (
102, 102, 0), (102, 51, 0), (102, 0, 0), (51, 255, 102), (51, 204, 102
), (51, 153, 102), (51, 102, 102), (51, 51, 102
), (51, 0, 102), (51, 255, 51), (51, 204, 51), (51, 153, 51), (
51, 102, 51), (51, 51, 51), (51, 0, 51), (51, 255, 0), (51, 204, 0), (
51, 153, 0), (51, 102, 0), (51, 51, 0), (51, 0, 0), (0, 255, 102),
(0, 204, 102), (0, 153, 102), (0, 102, 102), (0, 51, 102), (0, 0, 102), (
0, 255, 51), (0, 204, 51), (0, 153, 51), (0, 102, 51), (0, 51, 51
), (0, 0, 51), (0, 255, 0), (0, 204, 0), (0, 153, 0), (0, 102, 0), (
0, 51, 0), (17, 17, 17), (34, 34, 34), (68, 68, 68), (85, 85, 85), (
119, 119, 119), (136, 136, 136), (170, 170, 170), (187, 187, 187),
(221, 221, 221), (238, 238, 238), (192, 192, 192), (128, 0, 0), (
128, 0, 128), (0, 128, 0), (0, 128, 128), (0, 0, 0), (0, 0, 0), (0, 0, 0
), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (
0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (
0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (
0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0))
# so build a prototype image to be used for palette resampling
@ -90,6 +84,7 @@ def build_prototype_image():
image.putpalette(palettedata)
return image
Palm8BitColormapImage = build_prototype_image()
# OK, we now have in Palm8BitColormapImage,
@ -103,22 +98,18 @@ _FLAGS = {
"has-transparent": 0x2000,
}
_COMPRESSION_TYPES = {
"none": 0xFF,
"rle": 0x01,
"scanline": 0x00,
}
_COMPRESSION_TYPES = {"none": 0xFF, "rle": 0x01, "scanline": 0x00, }
o8 = _binary.o8
o16b = _binary.o16be
#
# --------------------------------------------------------------------
##
# (Internal) Image save plugin for the Palm format.
def _save(im, fp, filename, check=0):
if im.mode == "P":
@ -130,16 +121,16 @@ def _save(im, fp, filename, check=0):
bpp = 8
version = 1
elif (im.mode == "L" and
"bpp" in im.encoderinfo and
im.encoderinfo["bpp"] in (1, 2, 4)):
elif (
im.mode == "L" and "bpp" in im.encoderinfo and im.encoderinfo["bpp"] in
(1, 2, 4)):
# this is 8-bit grayscale, so we shift it to get the high-order bits,
# and invert it because
# Palm does greyscale from white (0) to black (1)
bpp = im.encoderinfo["bpp"]
im = im.point(
lambda x, shift=8-bpp, maxval=(1 << bpp)-1: maxval - (x >> shift))
im = im.point(lambda x, shift=8 - bpp, maxval=(1 << bpp) - 1: maxval -
(x >> shift))
# we ignore the palette here
im.mode = "P"
rawmode = "P;" + str(bpp)
@ -213,23 +204,18 @@ def _save(im, fp, filename, check=0):
for i in range(256):
fp.write(o8(i))
if colormapmode == 'RGB':
fp.write(
o8(colormap[3 * i]) +
o8(colormap[3 * i + 1]) +
fp.write(o8(colormap[3 * i]) + o8(colormap[3 * i + 1]) +
o8(colormap[3 * i + 2]))
elif colormapmode == 'RGBA':
fp.write(
o8(colormap[4 * i]) +
o8(colormap[4 * i + 1]) +
fp.write(o8(colormap[4 * i]) + o8(colormap[4 * i + 1]) +
o8(colormap[4 * i + 2]))
# now convert data to raw form
ImageFile._save(
im, fp, [("raw", (0, 0)+im.size, 0, (rawmode, rowbytes, 1))])
ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0,
(rawmode, rowbytes, 1))])
fp.flush()
#
# --------------------------------------------------------------------

View File

@ -14,20 +14,18 @@
# See the README file for information on usage and redistribution.
#
__version__ = "0.1"
from PIL import Image, ImageFile, _binary
i8 = _binary.i8
##
# Image plugin for PhotoCD images. This plugin only reads the 768x512
# image from the file; higher resolutions are encoded in a proprietary
# encoding.
class PcdImageFile(ImageFile.ImageFile):
format = "PCD"

View File

@ -35,12 +35,10 @@ PCF_SWIDTHS = (1 << 6)
PCF_GLYPH_NAMES = (1 << 7)
PCF_BDF_ACCELERATORS = (1 << 8)
BYTES_PER_ROW = [
lambda bits: ((bits+7) >> 3),
BYTES_PER_ROW = [lambda bits: ((bits + 7) >> 3),
lambda bits: ((bits + 15) >> 3) & ~1,
lambda bits: ((bits + 31) >> 3) & ~3,
lambda bits: ((bits+63) >> 3) & ~7,
]
lambda bits: ((bits + 63) >> 3) & ~7, ]
i8 = _binary.i8
l16 = _binary.i16le
@ -52,10 +50,10 @@ b32 = _binary.i32be
def sz(s, o):
return s[o:s.index(b"\0", o)]
##
# Font file plugin for the X11 PCF format.
class PcfFontFile(FontFile.FontFile):
name = "name"
@ -158,10 +156,7 @@ class PcfFontFile(FontFile.FontFile):
descent = i8(fp.read(1)) - 128
xsize = right - left
ysize = ascent + descent
append(
(xsize, ysize, left, right, width,
ascent, descent, 0)
)
append((xsize, ysize, left, right, width, ascent, descent, 0))
else:
@ -175,10 +170,8 @@ class PcfFontFile(FontFile.FontFile):
attributes = i16(fp.read(2))
xsize = right - left
ysize = ascent + descent
append(
(xsize, ysize, left, right, width,
ascent, descent, attributes)
)
append((xsize, ysize, left, right, width, ascent, descent,
attributes))
return metrics
@ -222,8 +215,7 @@ class PcfFontFile(FontFile.FontFile):
x, y, l, r, w, a, d, f = metrics[i]
b, e = offsets[i], offsets[i + 1]
bitmaps.append(
Image.frombytes("1", (x, y), data[b:e], "raw", mode, pad(x))
)
Image.frombytes("1", (x, y), data[b:e], "raw", mode, pad(x)))
return bitmaps

View File

@ -37,10 +37,10 @@ o8 = _binary.o8
def _accept(prefix):
return i8(prefix[0]) == 10 and i8(prefix[1]) in [0, 2, 3, 5]
##
# Image plugin for Paintbrush images.
class PcxImageFile(ImageFile.ImageFile):
format = "PCX"
@ -143,8 +143,8 @@ def _save(im, fp, filename, check=0):
# gets overwritten.
if Image.DEBUG:
print ("PcxImagePlugin._save: xwidth: %d, bits: %d, stride: %d" % (
im.size[0], bits, stride))
print("PcxImagePlugin._save: xwidth: %d, bits: %d, stride: %d" %
(im.size[0], bits, stride))
# under windows, we could determine the current screen size with
# "Image.core.display_mode()[1]", but I think that's overkill...
@ -154,13 +154,10 @@ def _save(im, fp, filename, check=0):
dpi = 100, 100
# PCX header
fp.write(
o8(10) + o8(version) + o8(1) + o8(bits) + o16(0) +
o16(0) + o16(im.size[0]-1) + o16(im.size[1]-1) + o16(dpi[0]) +
o16(dpi[1]) + b"\0"*24 + b"\xFF"*24 + b"\0" + o8(planes) +
o16(stride) + o16(1) + o16(screen[0]) + o16(screen[1]) +
b"\0"*54
)
fp.write(o8(10) + o8(version) + o8(1) + o8(bits) + o16(0) + o16(0) + o16(
im.size[0] - 1) + o16(im.size[1] - 1) + o16(dpi[0]) + o16(dpi[1]) +
b"\0" * 24 + b"\xFF" * 24 + b"\0" + o8(planes) + o16(stride) +
o16(1) + o16(screen[0]) + o16(screen[1]) + b"\0" * 54)
assert fp.tell() == 128

View File

@ -26,7 +26,6 @@ from PIL import Image, ImageFile
from PIL._binary import i8
import io
#
# --------------------------------------------------------------------
@ -37,6 +36,7 @@ import io
# 4. page
# 5. page contents
def _obj(fp, obj, **dict):
fp.write("%d 0 obj\n" % obj)
if dict:
@ -50,10 +50,10 @@ def _obj(fp, obj, **dict):
def _endobj(fp):
fp.write("endobj\n")
##
# (Internal) Image save plugin for the PDF format.
def _save(im, fp, filename):
resolution = im.encoderinfo.get("resolution", 72.0)
@ -126,21 +126,14 @@ def _save(im, fp, filename):
# catalogue
xref[1] = fp.tell()
_obj(
fp, 1,
Type="/Catalog",
Pages="2 0 R")
_obj(fp, 1, Type="/Catalog", Pages="2 0 R")
_endobj(fp)
#
# pages
xref[2] = fp.tell()
_obj(
fp, 2,
Type="/Pages",
Count=1,
Kids="[4 0 R]")
_obj(fp, 2, Type="/Pages", Count=1, Kids="[4 0 R]")
_endobj(fp)
#
@ -166,8 +159,7 @@ def _save(im, fp, filename):
raise ValueError("unsupported PDF filter (%s)" % filter)
xref[3] = fp.tell()
_obj(
fp, 3,
_obj(fp, 3,
Type="/XObject",
Subtype="/Image",
Width=width, # * 72.0 / resolution,
@ -189,14 +181,11 @@ def _save(im, fp, filename):
xref[4] = fp.tell()
_obj(fp, 4)
fp.write(
"<<\n/Type /Page\n/Parent 2 0 R\n"
fp.write("<<\n/Type /Page\n/Parent 2 0 R\n"
"/Resources <<\n/ProcSet [ /PDF %s ]\n"
"/XObject << /image 3 0 R >>\n>>\n"
"/MediaBox [ 0 0 %d %d ]\n/Contents 5 0 R\n>>\n" % (
procset,
int(width * 72.0 / resolution),
int(height * 72.0 / resolution)))
"/MediaBox [ 0 0 %d %d ]\n/Contents 5 0 R\n>>\n" % (procset, int(
width * 72.0 / resolution), int(height * 72.0 / resolution)))
_endobj(fp)
#
@ -204,10 +193,8 @@ def _save(im, fp, filename):
op = TextWriter(io.BytesIO())
op.write(
"q %d 0 0 %d 0 0 cm /image Do Q\n" % (
int(width * 72.0 / resolution),
int(height * 72.0 / resolution)))
op.write("q %d 0 0 %d 0 0 cm /image Do Q\n" %
(int(width * 72.0 / resolution), int(height * 72.0 / resolution)))
xref[5] = fp.tell()
_obj(fp, 5, Length=len(op.fp.getvalue()))

View File

@ -29,10 +29,10 @@ from PIL import Image, ImageFile, _binary
i16 = _binary.i16le
i32 = _binary.i32le
##
# Image plugin for PIXAR raster images.
class PixarImageFile(ImageFile.ImageFile):
format = "PIXAR"

View File

@ -46,10 +46,8 @@ i32 = _binary.i32be
is_cid = re.compile(b"\w\w\w\w").match
_MAGIC = b"\211PNG\r\n\032\n"
_MODES = {
# supported bits/color combinations, and corresponding modes/rawmodes
(1, 0): ("1", "1"),
@ -69,7 +67,6 @@ _MODES = {
(16, 6): ("RGBA", "RGBA;16B"),
}
_simple_palette = re.compile(b'^\xff+\x00\xff*$')
# Maximum decompressed size for a iTXt or zTXt chunk.
@ -78,6 +75,7 @@ MAX_TEXT_CHUNK = ImageFile.SAFEBLOCK
# Set the maximum total text chunk size.
MAX_TEXT_MEMORY = 64 * MAX_TEXT_CHUNK
def _safe_zlib_decompress(s):
dobj = zlib.decompressobj()
plaintext = dobj.decompress(s, MAX_TEXT_CHUNK)
@ -85,12 +83,11 @@ def _safe_zlib_decompress(s):
raise ValueError("Decompressed Data Too Large")
return plaintext
# --------------------------------------------------------------------
# Support classes. Suitable for PNG and related formats like MNG etc.
class ChunkStream:
class ChunkStream:
def __init__(self, fp):
self.fp = fp
@ -168,6 +165,7 @@ class iTXt(str):
keeping their extra information
"""
@staticmethod
def __new__(cls, text, lang, tkey):
"""
@ -225,8 +223,8 @@ class PngInfo:
self.add(b"iTXt", key + b"\0\x01\0" + lang + b"\0" + tkey + b"\0" +
zlib.compress(value))
else:
self.add(b"iTXt", key + b"\0\0\0" + lang + b"\0" + tkey + b"\0" +
value)
self.add(b"iTXt",
key + b"\0\0\0" + lang + b"\0" + tkey + b"\0" + value)
def add_text(self, key, value, zip=0):
"""Appends a text chunk.
@ -255,12 +253,11 @@ class PngInfo:
else:
self.add(b"tEXt", key + b"\0" + value)
# --------------------------------------------------------------------
# PNG image stream (IHDR/IEND)
class PngStream(ChunkStream):
class PngStream(ChunkStream):
def __init__(self, fp):
ChunkStream.__init__(self, fp)
@ -278,7 +275,8 @@ class PngStream(ChunkStream):
def check_text_memory(self, chunklen):
self.text_memory += chunklen
if self.text_memory > MAX_TEXT_MEMORY:
raise ValueError("Too much memory used in text chunks: %s>MAX_TEXT_MEMORY" %
raise ValueError(
"Too much memory used in text chunks: %s>MAX_TEXT_MEMORY" %
self.text_memory)
def chunk_iCCP(self, pos, length):
@ -296,8 +294,8 @@ class PngStream(ChunkStream):
print("Compression method", i8(s[i]))
comp_method = i8(s[i])
if comp_method != 0:
raise SyntaxError("Unknown compression method %s in iCCP chunk" %
comp_method)
raise SyntaxError(
"Unknown compression method %s in iCCP chunk" % comp_method)
try:
icc_profile = _safe_zlib_decompress(s[i + 2:])
except zlib.error:
@ -411,8 +409,8 @@ class PngStream(ChunkStream):
else:
comp_method = 0
if comp_method != 0:
raise SyntaxError("Unknown compression method %s in zTXt chunk" %
comp_method)
raise SyntaxError(
"Unknown compression method %s in zTXt chunk" % comp_method)
try:
v = _safe_zlib_decompress(v[1:])
except zlib.error:
@ -465,17 +463,17 @@ class PngStream(ChunkStream):
return s
# --------------------------------------------------------------------
# PNG reader
def _accept(prefix):
return prefix[:8] == _MAGIC
##
# Image plugin for PNG images.
class PngImageFile(ImageFile.ImageFile):
format = "PNG"
@ -582,7 +580,6 @@ class PngImageFile(ImageFile.ImageFile):
self.png.close()
self.png = None
# --------------------------------------------------------------------
# PNG writer
@ -668,8 +665,7 @@ def _save(im, fp, filename, chunk=putchunk, check=0):
im.encoderconfig = ("optimize" in im.encoderinfo,
im.encoderinfo.get("compress_level", -1),
im.encoderinfo.get("compress_type", -1),
dictionary)
im.encoderinfo.get("compress_type", -1), dictionary)
# get the corresponding PNG mode
try:
@ -685,8 +681,7 @@ def _save(im, fp, filename, chunk=putchunk, check=0):
fp.write(_MAGIC)
chunk(fp, b"IHDR",
o32(im.size[0]), o32(im.size[1]), # 0: size
chunk(fp, b"IHDR", o32(im.size[0]), o32(im.size[1]), # 0: size
mode, # 8: depth/type
b'\0', # 10: compression
b'\0', # 11: filter category
@ -731,10 +726,8 @@ def _save(im, fp, filename, chunk=putchunk, check=0):
dpi = im.encoderinfo.get("dpi")
if dpi:
chunk(fp, b"pHYs",
o32(int(dpi[0] / 0.0254 + 0.5)),
o32(int(dpi[1] / 0.0254 + 0.5)),
b'\x01')
chunk(fp, b"pHYs", o32(int(dpi[0] / 0.0254 + 0.5)),
o32(int(dpi[1] / 0.0254 + 0.5)), b'\x01')
info = im.encoderinfo.get("pnginfo")
if info:
@ -753,8 +746,8 @@ def _save(im, fp, filename, chunk=putchunk, check=0):
data = name + b"\0\0" + zlib.compress(im.info["icc_profile"])
chunk(fp, b"iCCP", data)
ImageFile._save(im, _idat(fp, chunk),
[("zip", (0, 0)+im.size, 0, rawmode)])
ImageFile._save(im, _idat(fp, chunk), [("zip",
(0, 0) + im.size, 0, rawmode)])
chunk(fp, b"IEND", b"")
@ -763,10 +756,10 @@ def _save(im, fp, filename, chunk=putchunk, check=0):
except:
pass
# --------------------------------------------------------------------
# PNG chunk converter
def getchunks(im, **params):
"""Return a list of PNG chunks representing this image."""
@ -795,7 +788,6 @@ def getchunks(im, **params):
return fp.data
# --------------------------------------------------------------------
# Registry

View File

@ -14,7 +14,6 @@
# See the README file for information on usage and redistribution.
#
__version__ = "0.2"
import string
@ -37,25 +36,19 @@ b_whitespace = b_whitespace.encode('ascii', 'ignore')
MODES = {
# standard
b"P4": "1",
b"P5": "L",
b"P6": "RGB",
# extensions
b"P0CMYK": "CMYK",
# PIL extensions (for test purposes only)
b"PyP": "P",
b"PyRGBA": "RGBA",
b"PyCMYK": "CMYK"
b"P4": "1", b"P5": "L", b"P6": "RGB", # extensions
b"P0CMYK": "CMYK", # PIL extensions (for test purposes only)
b"PyP": "P", b"PyRGBA": "RGBA", b"PyCMYK": "CMYK"
}
def _accept(prefix):
return prefix[0:1] == b"P" and prefix[1] in b"0456y"
##
# Image plugin for PBM, PGM, and PPM images.
class PpmImageFile(ImageFile.ImageFile):
format = "PPM"
@ -116,9 +109,7 @@ class PpmImageFile(ImageFile.ImageFile):
rawmode = 'I;32B'
self.size = xsize, ysize
self.tile = [("raw",
(0, 0, xsize, ysize),
self.fp.tell(),
self.tile = [("raw", (0, 0, xsize, ysize), self.fp.tell(),
(rawmode, 0, 1))]
# ALTERNATIVE: load via builtin debug function
@ -126,10 +117,10 @@ class PpmImageFile(ImageFile.ImageFile):
# self.mode = self.im.mode
# self.size = self.im.size
#
# --------------------------------------------------------------------
def _save(im, fp, filename):
if im.mode == "1":
rawmode, head = "1;I", b"P4"
@ -164,6 +155,7 @@ def _save(im, fp, filename):
#
# --------------------------------------------------------------------
Image.register_open("PPM", PpmImageFile, _accept)
Image.register_save("PPM", _save)

View File

@ -40,17 +40,17 @@ i8 = _binary.i8
i16 = _binary.i16be
i32 = _binary.i32be
# --------------------------------------------------------------------.
# read PSD images
def _accept(prefix):
return prefix[:4] == b"8BPS"
##
# Image plugin for Photoshop images.
class PsdImageFile(ImageFile.ImageFile):
format = "PSD"
@ -282,9 +282,7 @@ def _maketile(file, mode, bbox, channels):
layer = mode[channel]
if mode == "CMYK":
layer += ";I"
tile.append(
("packbits", bbox, offset, layer)
)
tile.append(("packbits", bbox, offset, layer))
for y in range(ysize):
offset = offset + i16(bytecount[i:i + 2])
i += 2

View File

@ -40,7 +40,6 @@ ffi.cdef(defs)
class PyAccess(object):
def __init__(self, img, readonly=False):
vals = dict(img.im.unsafe_ptrs)
self.readonly = readonly
@ -97,6 +96,7 @@ class PyAccess(object):
class _PyAccess32_2(PyAccess):
""" PA, LA, stored in first and last bytes of a 32 bit word """
def _post_init(self, *args, **kwargs):
self.pixels = ffi.cast("struct Pixel_RGBA **", self.image32)
@ -131,6 +131,7 @@ class _PyAccess32_3(PyAccess):
class _PyAccess32_4(PyAccess):
""" RGBA etc, all 4 bytes of a 32 bit word """
def _post_init(self, *args, **kwargs):
self.pixels = ffi.cast("struct Pixel_RGBA **", self.image32)
@ -149,6 +150,7 @@ class _PyAccess32_4(PyAccess):
class _PyAccess8(PyAccess):
""" 1, L, P, 8 bit images stored as uint8 """
def _post_init(self, *args, **kwargs):
self.pixels = self.image8
@ -166,6 +168,7 @@ class _PyAccess8(PyAccess):
class _PyAccessI16_N(PyAccess):
""" I;16 access, native bitendian without conversion """
def _post_init(self, *args, **kwargs):
self.pixels = ffi.cast('unsigned short **', self.image)
@ -183,6 +186,7 @@ class _PyAccessI16_N(PyAccess):
class _PyAccessI16_L(PyAccess):
""" I;16L access, with conversion """
def _post_init(self, *args, **kwargs):
self.pixels = ffi.cast('struct Pixel_I16 **', self.image)
@ -203,6 +207,7 @@ class _PyAccessI16_L(PyAccess):
class _PyAccessI16_B(PyAccess):
""" I;16B access, with conversion """
def _post_init(self, *args, **kwargs):
self.pixels = ffi.cast('struct Pixel_I16 **', self.image)
@ -223,6 +228,7 @@ class _PyAccessI16_B(PyAccess):
class _PyAccessI32_N(PyAccess):
""" Signed Int32 access, native endian """
def _post_init(self, *args, **kwargs):
self.pixels = self.image32
@ -235,6 +241,7 @@ class _PyAccessI32_N(PyAccess):
class _PyAccessI32_Swap(PyAccess):
""" I;32L/B access, with byteswapping conversion """
def _post_init(self, *args, **kwargs):
self.pixels = self.image32
@ -254,6 +261,7 @@ class _PyAccessI32_Swap(PyAccess):
class _PyAccessF(PyAccess):
""" 32 bit float access """
def _post_init(self, *args, **kwargs):
self.pixels = ffi.cast('float **', self.image32)
@ -269,7 +277,8 @@ class _PyAccessF(PyAccess):
self.pixels[y][x] = color[0]
mode_map = {'1': _PyAccess8,
mode_map = {
'1': _PyAccess8,
'L': _PyAccess8,
'P': _PyAccess8,
'LA': _PyAccess32_2,

View File

@ -17,10 +17,8 @@
# See the README file for information on usage and redistribution.
#
__version__ = "0.2"
from PIL import Image, ImageFile, _binary
i8 = _binary.i8
@ -31,10 +29,10 @@ i32 = _binary.i32be
def _accept(prefix):
return i16(prefix) == 474
##
# Image plugin for SGI images.
class SgiImageFile(ImageFile.ImageFile):
format = "SGI"
@ -72,8 +70,8 @@ class SgiImageFile(ImageFile.ImageFile):
pagesize = self.size[0] * self.size[1] * layout[0]
self.tile = []
for layer in self.mode:
self.tile.append(
("raw", (0, 0)+self.size, offset, (layer, 0, -1)))
self.tile.append(("raw", (0, 0) + self.size, offset,
(layer, 0, -1)))
offset = offset + pagesize
elif compression == 1:
raise ValueError("SGI RLE encoding not supported")

View File

@ -51,14 +51,15 @@ def isInt(f):
except:
return 0
iforms = [1, 3, -11, -12, -21, -22]
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,
# otherwise returns 0
def isSpiderHeader(t):
h = (99, ) + t # add 1 value so can use spider header index start=1
# header values 1,2,5,12,13,22,23 should be integers
@ -149,9 +150,7 @@ class SpiderImageFile(ImageFile.ImageFile):
self.rawmode = "F;32F"
self.mode = "F"
self.tile = [
("raw", (0, 0) + self.size, offset,
(self.rawmode, 0, 1))]
self.tile = [("raw", (0, 0) + self.size, offset, (self.rawmode, 0, 1))]
self.__fp = self.fp # FIXME: hack
# 1st image index is zero (although SPIDER imgnumber starts at 1)
@ -185,10 +184,10 @@ class SpiderImageFile(ImageFile.ImageFile):
from PIL import ImageTk
return ImageTk.PhotoImage(self.convert2byte(), palette=256)
# --------------------------------------------------------------------
# Image series
# given a list of filenames, return a list of images
def loadImageSeries(filelist=None):
" create a list of Image.images for use in montage "
@ -210,10 +209,10 @@ def loadImageSeries(filelist=None):
imglist.append(im)
return imglist
# --------------------------------------------------------------------
# For saving images in Spider format
def makeSpiderHeader(im):
nsam, nrow = im.size
lenbyt = nsam * 4 # There are labrec records in the header
@ -306,7 +305,6 @@ if __name__ == "__main__":
if outfile != "":
# perform some image operation
im = im.transpose(Image.FLIP_LEFT_RIGHT)
print(
"saving a flipped version of %s as %s " %
print("saving a flipped version of %s as %s " %
(os.path.basename(filename), outfile))
im.save(outfile, "SPIDER")

View File

@ -16,10 +16,8 @@
# See the README file for information on usage and redistribution.
#
__version__ = "0.3"
from PIL import Image, ImageFile, ImagePalette, _binary
i16 = _binary.i16be
@ -29,10 +27,10 @@ i32 = _binary.i32be
def _accept(prefix):
return i32(prefix) == 0x59a66a95
##
# Image plugin for Sun raster files.
class SunImageFile(ImageFile.ImageFile):
format = "SUN"
@ -71,7 +69,8 @@ class SunImageFile(ImageFile.ImageFile):
stride = (((self.size[0] * depth + 7) // 8) + 3) & (~3)
if compression == 1:
self.tile = [("raw", (0, 0)+self.size, offset, (rawmode, stride))]
self.tile = [("raw", (0, 0) + self.size, offset,
(rawmode, stride))]
elif compression == 2:
self.tile = [("sun_rle", (0, 0) + self.size, offset, rawmode)]

View File

@ -16,11 +16,11 @@
from PIL import ContainerIO
##
# A file object that provides read access to a given member of a TAR
# file.
class TarIO(ContainerIO.ContainerIO):
##

View File

@ -16,12 +16,10 @@
# See the README file for information on usage and redistribution.
#
__version__ = "0.3"
from PIL import Image, ImageFile, ImagePalette, _binary
#
# --------------------------------------------------------------------
# Read RGA file
@ -30,7 +28,6 @@ i8 = _binary.i8
i16 = _binary.i16le
i32 = _binary.i32le
MODES = {
# map imagetype/depth to rawmode
(1, 8): "P",
@ -41,10 +38,10 @@ MODES = {
(2, 32): "BGRA",
}
##
# Image plugin for Targa files.
class TgaImageFile(ImageFile.ImageFile):
format = "TGA"
@ -121,11 +118,11 @@ class TgaImageFile(ImageFile.ImageFile):
rawmode = MODES[(imagetype & 7, depth)]
if imagetype & 8:
# compressed
self.tile = [("tga_rle", (0, 0)+self.size,
self.fp.tell(), (rawmode, orientation, depth))]
self.tile = [("tga_rle", (0, 0) + self.size, self.fp.tell(),
(rawmode, orientation, depth))]
else:
self.tile = [("raw", (0, 0)+self.size,
self.fp.tell(), (rawmode, 0, orientation))]
self.tile = [("raw", (0, 0) + self.size, self.fp.tell(),
(rawmode, 0, orientation))]
except KeyError:
pass # cannot decode
@ -170,24 +167,15 @@ def _save(im, fp, filename, check=0):
if orientation > 0:
flags = flags | 0x20
fp.write(b"\000" +
o8(colormaptype) +
o8(imagetype) +
o16(colormapfirst) +
o16(colormaplength) +
o8(colormapentry) +
o16(0) +
o16(0) +
o16(im.size[0]) +
o16(im.size[1]) +
o8(bits) +
o8(flags))
fp.write(b"\000" + o8(colormaptype) + o8(imagetype) + o16(colormapfirst) +
o16(colormaplength) + o8(colormapentry) + o16(0) + o16(0) +
o16(im.size[0]) + o16(im.size[1]) + o8(bits) + o8(flags))
if colormaptype:
fp.write(im.im.getpalette("RGB", "BGR"))
ImageFile._save(
im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, orientation))])
ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0,
(rawmode, 0, orientation))])
#
# --------------------------------------------------------------------

View File

@ -180,7 +180,6 @@ OPEN_INFO = {
(II, 5, 1, 1, (8, 8, 8, 8), ()): ("CMYK", "CMYK"),
(II, 6, 1, 1, (8, 8, 8), ()): ("YCbCr", "YCbCr"),
(II, 8, 1, 1, (8, 8, 8), ()): ("LAB", "LAB"),
(MM, 0, 1, 1, (1, ), ()): ("1", "1;I"),
(MM, 0, 1, 2, (1, ), ()): ("1", "1;IR"),
(MM, 0, 1, 1, (8, ), ()): ("L", "L;I"),
@ -212,7 +211,6 @@ OPEN_INFO = {
(MM, 5, 1, 1, (8, 8, 8, 8), ()): ("CMYK", "CMYK"),
(MM, 6, 1, 1, (8, 8, 8), ()): ("YCbCr", "YCbCr"),
(MM, 8, 1, 1, (8, 8, 8), ()): ("LAB", "LAB"),
}
PREFIXES = [b"MM\000\052", b"II\052\000", b"II\xBC\000"]
@ -221,10 +219,10 @@ PREFIXES = [b"MM\000\052", b"II\052\000", b"II\xBC\000"]
def _accept(prefix):
return prefix[:4] in PREFIXES
##
# Wrapper for TIFF IFDs.
class ImageFileDirectory(collections.MutableMapping):
""" This class represents a TIFF tag directory. To speed things
up, we don't decode tags unless they're asked for.
@ -338,6 +336,7 @@ class ImageFileDirectory(collections.MutableMapping):
return tag in self.tags or tag in self.tagdata
if bytes is str:
def has_key(self, tag):
return tag in self
@ -366,12 +365,14 @@ class ImageFileDirectory(collections.MutableMapping):
def load_byte(self, data):
return data
load_dispatch[1] = (1, load_byte)
def load_string(self, data):
if data[-1:] == b'\0':
data = data[:-1]
return data.decode('latin-1', 'replace')
load_dispatch[2] = (1, load_string)
def load_short(self, data):
@ -379,6 +380,7 @@ class ImageFileDirectory(collections.MutableMapping):
for i in range(0, len(data), 2):
l.append(self.i16(data, i))
return tuple(l)
load_dispatch[3] = (2, load_short)
def load_long(self, data):
@ -386,6 +388,7 @@ class ImageFileDirectory(collections.MutableMapping):
for i in range(0, len(data), 4):
l.append(self.i32(data, i))
return tuple(l)
load_dispatch[4] = (4, load_long)
def load_rational(self, data):
@ -393,6 +396,7 @@ class ImageFileDirectory(collections.MutableMapping):
for i in range(0, len(data), 8):
l.append((self.i32(data, i), self.i32(data, i + 4)))
return tuple(l)
load_dispatch[5] = (8, load_rational)
def load_float(self, data):
@ -400,6 +404,7 @@ class ImageFileDirectory(collections.MutableMapping):
if self.prefix != native_prefix:
a.byteswap()
return tuple(a)
load_dispatch[11] = (4, load_float)
def load_double(self, data):
@ -407,11 +412,13 @@ class ImageFileDirectory(collections.MutableMapping):
if self.prefix != native_prefix:
a.byteswap()
return tuple(a)
load_dispatch[12] = (8, load_double)
def load_undefined(self, data):
# Untyped data
return data
load_dispatch[7] = (1, load_undefined)
def load(self, fp):
@ -567,7 +574,8 @@ class ImageFileDirectory(collections.MutableMapping):
if len(data) == 4:
append((tag, typ, len(value), data, b""))
elif len(data) < 4:
append((tag, typ, len(value), data + (4-len(data))*b"\0", b""))
append((tag, typ, len(value), data +
(4 - len(data)) * b"\0", b""))
else:
count = len(value)
if typ == 5:
@ -602,10 +610,10 @@ class ImageFileDirectory(collections.MutableMapping):
return offset
##
# Image plugin for TIFF files.
class TiffImageFile(ImageFile.ImageFile):
format = "TIFF"
@ -661,7 +669,8 @@ class TiffImageFile(ImageFile.ImageFile):
if not self.__next:
raise EOFError("no more images in TIFF file")
if Image.DEBUG:
print("Seeking to frame %s, on frame %s, __next %s, location: %s" %
print(
"Seeking to frame %s, on frame %s, __next %s, location: %s" %
(frame, self.__frame, self.__next, self.fp.tell()))
# reset python3 buffered io handle in case fp
# was passed to libtiff, invalidating the buffer
@ -809,11 +818,9 @@ class TiffImageFile(ImageFile.ImageFile):
format = getscalar(SAMPLEFORMAT, 1)
# mode: check photometric interpretation and bits per pixel
key = (
self.tag.prefix, photo, format, fillorder,
self.tag.get(BITSPERSAMPLE, (1,)),
self.tag.get(EXTRASAMPLES, ())
)
key = (self.tag.prefix, photo, format, fillorder,
self.tag.get(BITSPERSAMPLE,
(1, )), self.tag.get(EXTRASAMPLES, ()))
if Image.DEBUG:
print("format key:", key)
try:
@ -855,14 +862,11 @@ class TiffImageFile(ImageFile.ImageFile):
offsets = self.tag[STRIPOFFSETS]
h = getscalar(ROWSPERSTRIP, ysize)
w = self.size[0]
if READ_LIBTIFF or self._compression in ["tiff_ccitt", "group3",
"group4", "tiff_jpeg",
"tiff_adobe_deflate",
"tiff_thunderscan",
"tiff_deflate",
"tiff_sgilog",
"tiff_sgilog24",
"tiff_raw_16"]:
if READ_LIBTIFF or self._compression in [
"tiff_ccitt", "group3", "group4", "tiff_jpeg",
"tiff_adobe_deflate", "tiff_thunderscan", "tiff_deflate",
"tiff_sgilog", "tiff_sgilog24", "tiff_raw_16"
]:
# if Image.DEBUG:
# print "Activating g4 compression for whole file"
@ -899,11 +903,9 @@ class TiffImageFile(ImageFile.ImageFile):
# bits, so stripes of the image are reversed. See
# https://github.com/python-pillow/Pillow/issues/279
if fillorder == 2:
key = (
self.tag.prefix, photo, format, 1,
self.tag.get(BITSPERSAMPLE, (1,)),
self.tag.get(EXTRASAMPLES, ())
)
key = (self.tag.prefix, photo, format, 1,
self.tag.get(BITSPERSAMPLE,
(1, )), self.tag.get(EXTRASAMPLES, ()))
if Image.DEBUG:
print("format key:", key)
# this should always work, since all the
@ -920,17 +922,13 @@ class TiffImageFile(ImageFile.ImageFile):
# Offset in the tile tuple is 0, we go from 0,0 to
# w,h, and we only do this once -- eds
a = (rawmode, self._compression, fp)
self.tile.append(
(self._compression,
(0, 0, w, ysize),
0, a))
self.tile.append((self._compression, (0, 0, w, ysize), 0, a))
a = None
else:
for i in range(len(offsets)):
a = self._decoder(rawmode, l, i)
self.tile.append(
(self._compression,
self.tile.append((self._compression,
(0, min(y, ysize), w, min(y + h, ysize)),
offsets[i], a))
if Image.DEBUG:
@ -950,10 +948,8 @@ class TiffImageFile(ImageFile.ImageFile):
a = self._decoder(rawmode, l)
# FIXME: this doesn't work if the image size
# is not a multiple of the tile size...
self.tile.append(
(self._compression,
(x, y, x+w, y+h),
o, a))
self.tile.append((self._compression, (x, y, x + w, y + h), o,
a))
x = x + w
if x >= self.size[0]:
x, y = 0, y + h
@ -996,7 +992,6 @@ SAVE_INFO = {
"CMYK": ("CMYK", II, 5, 1, (8, 8, 8, 8), None),
"YCbCr": ("YCbCr", II, 6, 1, (8, 8, 8), None),
"LAB": ("LAB", II, 8, 1, (8, 8, 8), None),
"I;32BS": ("I;32BS", MM, 1, 2, (32, ), None),
"I;16B": ("I;16B", MM, 1, 1, (16, ), None),
"I;16BS": ("I;16BS", MM, 1, 2, (16, ), None),
@ -1073,13 +1068,15 @@ def _save(im, fp, filename):
(X_RESOLUTION, "resolution", _cvt_res),
(Y_RESOLUTION, "resolution", _cvt_res),
(X_RESOLUTION, "x_resolution", _cvt_res),
(Y_RESOLUTION, "y_resolution", _cvt_res),
(RESOLUTION_UNIT, "resolution_unit",
lambda x: {"inch": 2, "cm": 3, "centimeter": 3}.get(x, 1)),
(SOFTWARE, "software", lambda x: x),
(DATE_TIME, "date_time", lambda x: x),
(ARTIST, "artist", lambda x: x),
(COPYRIGHT, "copyright", lambda x: x)]:
(Y_RESOLUTION, "y_resolution", _cvt_res), (
RESOLUTION_UNIT, "resolution_unit",
lambda x: {"inch": 2,
"cm": 3,
"centimeter": 3}.get(x, 1)
), (SOFTWARE, "software", lambda x: x),
(DATE_TIME, "date_time", lambda x: x), (ARTIST, "artist", lambda x: x),
(COPYRIGHT, "copyright", lambda x: x)
]:
name_with_spaces = name.replace("_", " ")
if "_" in name and name_with_spaces in im.encoderinfo:
warnings.warn("%r is deprecated; use %r instead" %
@ -1152,8 +1149,7 @@ def _save(im, fp, filename):
# following tiffcp.c->cpTag->TIFF_RATIONAL
atts[k] = float(v[0][0]) / float(v[0][1])
continue
if (type(v) == tuple and
(len(v) > 2 or
if (type(v) == tuple and (len(v) > 2 or
(len(v) == 2 and v[1] == 0))):
# List of ints?
# Avoid divide by zero in next if-clause
@ -1203,9 +1199,8 @@ def _save(im, fp, filename):
else:
offset = ifd.save(fp)
ImageFile._save(im, fp, [
("raw", (0, 0)+im.size, offset, (rawmode, stride, 1))
])
ImageFile._save(im, fp, [("raw", (0, 0) + im.size, offset,
(rawmode, stride, 1))])
# -- helper for multi-page save --
if "_debug_multipage" in im.encoderinfo:

View File

@ -21,13 +21,11 @@
# Map tag numbers (or tag number, tag value tuples) to tag names.
TAGS = {
254: "NewSubfileType",
255: "SubfileType",
256: "ImageWidth",
257: "ImageLength",
258: "BitsPerSample",
259: "Compression",
(259, 1): "Uncompressed",
(259, 2): "CCITT 1d",
@ -36,7 +34,6 @@ TAGS = {
(259, 5): "LZW",
(259, 6): "JPEG",
(259, 32773): "PackBits",
262: "PhotometricInterpretation",
(262, 0): "WhiteIsZero",
(262, 1): "BlackIsZero",
@ -48,13 +45,11 @@ TAGS = {
(262, 8): "CieLAB",
(262, 32803): "CFA", # TIFF/EP, Adobe DNG
(262, 32892): "LinearRaw", # Adobe DNG
263: "Thresholding",
264: "CellWidth",
265: "CellHeight",
266: "FillOrder",
269: "DocumentName",
270: "ImageDescription",
271: "Make",
272: "Model",
@ -63,7 +58,6 @@ TAGS = {
277: "SamplesPerPixel",
278: "RowsPerStrip",
279: "StripByteCounts",
280: "MinSampleValue",
281: "MaxSampleValue",
282: "XResolution",
@ -71,37 +65,31 @@ TAGS = {
284: "PlanarConfiguration",
(284, 1): "Contigous",
(284, 2): "Separate",
285: "PageName",
286: "XPosition",
287: "YPosition",
288: "FreeOffsets",
289: "FreeByteCounts",
290: "GrayResponseUnit",
291: "GrayResponseCurve",
292: "T4Options",
293: "T6Options",
296: "ResolutionUnit",
297: "PageNumber",
301: "TransferFunction",
305: "Software",
306: "DateTime",
315: "Artist",
316: "HostComputer",
317: "Predictor",
318: "WhitePoint",
319: "PrimaryChromaticies",
320: "ColorMap",
321: "HalftoneHints",
322: "TileWidth",
323: "TileLength",
324: "TileOffsets",
325: "TileByteCounts",
332: "InkSet",
333: "InkNames",
334: "NumberOfInks",
@ -109,14 +97,10 @@ TAGS = {
337: "TargetPrinter",
338: "ExtraSamples",
339: "SampleFormat",
340: "SMinSampleValue",
341: "SMaxSampleValue",
342: "TransferRange",
347: "JPEGTables",
# obsolete JPEG tags
347: "JPEGTables", # obsolete JPEG tags
512: "JPEGProc",
513: "JPEGInterchangeFormat",
514: "JPEGInterchangeFormatLength",
@ -126,28 +110,16 @@ TAGS = {
519: "JPEGQTables",
520: "JPEGDCTables",
521: "JPEGACTables",
529: "YCbCrCoefficients",
530: "YCbCrSubSampling",
531: "YCbCrPositioning",
532: "ReferenceBlackWhite",
# XMP
532: "ReferenceBlackWhite", # XMP
700: "XMP",
33432: "Copyright",
# various extensions (should check specs for "official" names)
33432: "Copyright", # various extensions (should check specs for "official" names)
33723: "IptcNaaInfo",
34377: "PhotoshopInfo",
# Exif IFD
34665: "ExifIFD",
# ICC Profile
34675: "ICCProfile",
# Additional Exif Info
34377: "PhotoshopInfo", # Exif IFD
34665: "ExifIFD", # ICC Profile
34675: "ICCProfile", # Additional Exif Info
33434: "ExposureTime",
33437: "FNumber",
34850: "ExposureProgram",
@ -218,9 +190,7 @@ TAGS = {
42035: "LensMake",
42036: "LensModel",
42037: "LensSerialNumber",
42240: "Gamma",
# MP Info
42240: "Gamma", # MP Info
45056: "MPFVersion",
45057: "NumberOfImages",
45058: "MPEntry",
@ -239,9 +209,7 @@ TAGS = {
45578: "AxisDistance_Z",
45579: "YawAngle",
45580: "PitchAngle",
45581: "RollAngle",
# Adobe DNG
45581: "RollAngle", # Adobe DNG
50706: "DNGVersion",
50707: "DNGBackwardVersion",
50708: "UniqueCameraModel",
@ -279,9 +247,7 @@ TAGS = {
50738: "AntiAliasStrength",
50740: "DNGPrivateData",
50741: "MakerNoteSafety",
50780: "BestQualityScale",
# ImageJ
50780: "BestQualityScale", # ImageJ
50838: "ImageJMetaDataByteCounts", # private tag registered with Adobe
50839: "ImageJMetaData", # private tag registered with Adobe
}
@ -290,7 +256,6 @@ TAGS = {
# Map type numbers to type names.
TYPES = {
1: "byte",
2: "ascii",
3: "short",
@ -303,5 +268,4 @@ TYPES = {
10: "signed rational",
11: "float",
12: "double",
}

View File

@ -31,7 +31,6 @@ except ImportError:
i32 = _binary.i32le
##
# Load texture from a Quake2 WAL texture file.
# <p>
@ -41,6 +40,7 @@ i32 = _binary.i32le
# @param filename WAL file name, or an opened file handle.
# @return An image instance.
def open(filename):
# FIXME: modify to return a WalImageFile instance instead of
# plain Image object ?
@ -73,8 +73,7 @@ def open(filename):
return im
quake2palette = (
# default palette taken from piffo 0.93 by Hans Häggström
quake2palette = ( # default palette taken from piffo 0.93 by Hans Häggström
b"\x01\x01\x01\x0b\x0b\x0b\x12\x12\x12\x17\x17\x17\x1b\x1b\x1b\x1e"
b"\x1e\x1e\x22\x22\x22\x26\x26\x26\x29\x29\x29\x2c\x2c\x2c\x2f\x2f"
b"\x2f\x32\x32\x32\x35\x35\x35\x37\x37\x37\x3a\x3a\x3a\x3c\x3c\x3c"
@ -122,8 +121,7 @@ quake2palette = (
b"\x01\x27\x07\x01\x23\x01\x01\x1d\x01\x01\x17\x01\x01\x10\x01\x01"
b"\x3d\x01\x01\x19\x19\x3f\x3f\x01\x01\x01\x01\x3f\x16\x16\x13\x10"
b"\x10\x0f\x0d\x0d\x0b\x3c\x2e\x2a\x36\x27\x20\x30\x21\x18\x29\x1b"
b"\x10\x3c\x39\x37\x37\x32\x2f\x31\x2c\x28\x2b\x26\x21\x30\x22\x20"
)
b"\x10\x3c\x39\x37\x37\x32\x2f\x31\x2c\x28\x2b\x26\x21\x30\x22\x20")
if __name__ == "__main__":
im = open("../hacks/sample.wal")

View File

@ -3,11 +3,7 @@ from PIL import ImageFile
from io import BytesIO
from PIL import _webp
_VALID_WEBP_MODES = {
"RGB": True,
"RGBA": True,
}
_VALID_WEBP_MODES = {"RGB": True, "RGBA": True, }
_VP8_MODES_BY_IDENTIFIER = {
b"VP8 ": "RGB",
@ -57,16 +53,8 @@ def _save(im, fp, filename):
icc_profile = im.encoderinfo.get("icc_profile", "")
exif = im.encoderinfo.get("exif", "")
data = _webp.WebPEncode(
im.tobytes(),
im.size[0],
im.size[1],
lossless,
float(quality),
im.mode,
icc_profile,
exif
)
data = _webp.WebPEncode(im.tobytes(), im.size[0], im.size[1], lossless,
float(quality), im.mode, icc_profile, exif)
if data is None:
raise IOError("cannot write file as WEBP (encoder returned None)")

View File

@ -24,21 +24,21 @@ _handler = None
if str != bytes:
long = int
##
# Install application-specific WMF image handler.
#
# @param handler Handler object.
def register_handler(handler):
global _handler
_handler = handler
if hasattr(Image.core, "drawwmf"):
# install default handler (windows only)
class WmfHandler:
def open(self, im):
im.mode = "RGB"
self.bbox = im.info["wmf_bbox"]
@ -47,9 +47,8 @@ if hasattr(Image.core, "drawwmf"):
im.fp.seek(0) # rewind
return Image.frombytes(
"RGB", im.size,
Image.core.drawwmf(im.fp.read(), im.size, self.bbox),
"raw", "BGR", (im.size[0]*3 + 3) & -4, -1
)
Image.core.drawwmf(im.fp.read(), im.size, self.bbox), "raw",
"BGR", (im.size[0] * 3 + 3) & -4, -1)
register_handler(WmfHandler())
@ -64,23 +63,22 @@ def short(c, o=0):
v -= 65536
return v
dword = _binary.i32le
dword = _binary.i32le
#
# --------------------------------------------------------------------
# Read WMF file
def _accept(prefix):
return (
prefix[:6] == b"\xd7\xcd\xc6\x9a\x00\x00" or
prefix[:4] == b"\x01\x00\x00\x00"
)
def _accept(prefix):
return (prefix[:6] == b"\xd7\xcd\xc6\x9a\x00\x00" or
prefix[:4] == b"\x01\x00\x00\x00")
##
# Image plugin for Windows metafiles.
class WmfStubImageFile(ImageFile.StubImageFile):
format = "WMF"

View File

@ -28,12 +28,13 @@ PALETTE = b""
for r in range(8):
for g in range(8):
for b in range(4):
PALETTE = PALETTE + (o8((r*255)//7)+o8((g*255)//7)+o8((b*255)//3))
PALETTE = PALETTE + (o8((r * 255) // 7) + o8((g * 255) // 7) + o8(
(b * 255) // 3))
##
# Image plugin for XV thumbnail images.
class XVThumbImageFile(ImageFile.ImageFile):
format = "XVThumb"
@ -65,10 +66,8 @@ class XVThumbImageFile(ImageFile.ImageFile):
self.palette = ImagePalette.raw("RGB", PALETTE)
self.tile = [
("raw", (0, 0)+self.size,
self.fp.tell(), (self.mode, 0, 1)
)]
self.tile = [("raw", (0, 0) + self.size, self.fp.tell(),
(self.mode, 0, 1))]
# --------------------------------------------------------------------

View File

@ -32,17 +32,16 @@ xbm_head = re.compile(
b"#define[ \t]+[^_]*_x_hot[ \t]+(?P<xhot>[0-9]+)[\r\n]+"
b"#define[ \t]+[^_]*_y_hot[ \t]+(?P<yhot>[0-9]+)[\r\n]+"
b")?"
b"[\\000-\\377]*_bits\\[\\]"
)
b"[\\000-\\377]*_bits\\[\\]")
def _accept(prefix):
return prefix.lstrip()[:7] == b"#define"
##
# Image plugin for X11 bitmaps.
class XbmImageFile(ImageFile.ImageFile):
format = "XBM"
@ -58,9 +57,8 @@ class XbmImageFile(ImageFile.ImageFile):
ysize = int(m.group("height"))
if m.group("hotspot"):
self.info["hotspot"] = (
int(m.group("xhot")), int(m.group("yhot"))
)
self.info["hotspot"] = (int(m.group("xhot")),
int(m.group("yhot")))
self.mode = "1"
self.size = xsize, ysize

View File

@ -14,10 +14,8 @@
# See the README file for information on usage and redistribution.
#
__version__ = "0.2"
import re
from PIL import Image, ImageFile, ImagePalette
from PIL._binary import i8, o8
@ -29,10 +27,10 @@ xpm_head = re.compile(b"\"([0-9]*) ([0-9]*) ([0-9]*) ([0-9]*)")
def _accept(prefix):
return prefix[:9] == b"/* XPM */"
##
# Image plugin for X11 pixel maps.
class XpmImageFile(ImageFile.ImageFile):
format = "XPM"
@ -87,9 +85,8 @@ class XpmImageFile(ImageFile.ImageFile):
elif rgb[0:1] == b"#":
# FIXME: handle colour names (see ImagePalette.py)
rgb = int(rgb[1:], 16)
palette[c] = (o8((rgb >> 16) & 255) +
o8((rgb >> 8) & 255) +
o8(rgb & 255))
palette[c] = (o8((rgb >> 16) & 255) + o8(
(rgb >> 8) & 255) + o8(rgb & 255))
else:
# unknown colour
raise ValueError("cannot read this XPM file")

View File

@ -14,45 +14,17 @@
VERSION = '1.1.7' # PIL version
PILLOW_VERSION = '2.8.0' # Pillow
_plugins = ['BmpImagePlugin',
'BufrStubImagePlugin',
'CurImagePlugin',
'DcxImagePlugin',
'EpsImagePlugin',
'FitsStubImagePlugin',
'FliImagePlugin',
'FpxImagePlugin',
'GbrImagePlugin',
'GifImagePlugin',
'GribStubImagePlugin',
'Hdf5StubImagePlugin',
'IcnsImagePlugin',
'IcoImagePlugin',
'ImImagePlugin',
'ImtImagePlugin',
'IptcImagePlugin',
'JpegImagePlugin',
'Jpeg2KImagePlugin',
'McIdasImagePlugin',
'MicImagePlugin',
'MpegImagePlugin',
'MpoImagePlugin',
'MspImagePlugin',
'PalmImagePlugin',
'PcdImagePlugin',
'PcxImagePlugin',
'PdfImagePlugin',
'PixarImagePlugin',
'PngImagePlugin',
'PpmImagePlugin',
'PsdImagePlugin',
'SgiImagePlugin',
'SpiderImagePlugin',
'SunImagePlugin',
'TgaImagePlugin',
'TiffImagePlugin',
'WebPImagePlugin',
'WmfImagePlugin',
'XbmImagePlugin',
'XpmImagePlugin',
'XVThumbImagePlugin']
_plugins = ['BmpImagePlugin', 'BufrStubImagePlugin', 'CurImagePlugin',
'DcxImagePlugin', 'EpsImagePlugin', 'FitsStubImagePlugin',
'FliImagePlugin', 'FpxImagePlugin', 'GbrImagePlugin',
'GifImagePlugin', 'GribStubImagePlugin', 'Hdf5StubImagePlugin',
'IcnsImagePlugin', 'IcoImagePlugin', 'ImImagePlugin',
'ImtImagePlugin', 'IptcImagePlugin', 'JpegImagePlugin',
'Jpeg2KImagePlugin', 'McIdasImagePlugin', 'MicImagePlugin',
'MpegImagePlugin', 'MpoImagePlugin', 'MspImagePlugin',
'PalmImagePlugin', 'PcdImagePlugin', 'PcxImagePlugin',
'PdfImagePlugin', 'PixarImagePlugin', 'PngImagePlugin',
'PpmImagePlugin', 'PsdImagePlugin', 'SgiImagePlugin',
'SpiderImagePlugin', 'SunImagePlugin', 'TgaImagePlugin',
'TiffImagePlugin', 'WebPImagePlugin', 'WmfImagePlugin',
'XbmImagePlugin', 'XpmImagePlugin', 'XVThumbImagePlugin']

View File

@ -14,12 +14,14 @@
from struct import unpack, pack
if bytes is str:
def i8(c):
return ord(c)
def o8(i):
return chr(i & 255)
else:
def i8(c):
return c if c.__class__ is int else c[0]

View File

@ -1,12 +1,14 @@
import os
if bytes is str:
def isStringType(t):
return isinstance(t, basestring)
def isPath(f):
return isinstance(f, basestring)
else:
def isStringType(t):
return isinstance(t, str)