This commit is contained in:
Alex Clark 2015-04-05 08:40:07 +00:00
commit d162881e59
82 changed files with 1649 additions and 2009 deletions

View File

@ -20,7 +20,6 @@
from PIL import Image from PIL import Image
from PIL import FontFile from PIL import FontFile
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# parse X Bitmap Distribution Format (BDF) # parse X Bitmap Distribution Format (BDF)
# -------------------------------------------------------------------- # --------------------------------------------------------------------
@ -34,11 +33,7 @@ bdf_slant = {
"OT": "Other" "OT": "Other"
} }
bdf_spacing = { bdf_spacing = {"P": "Proportional", "M": "Monospaced", "C": "Cell"}
"P": "Proportional",
"M": "Monospaced",
"C": "Cell"
}
def bdf_char(f): def bdf_char(f):
@ -58,7 +53,7 @@ def bdf_char(f):
if not s or s[:6] == b"BITMAP": if not s or s[:6] == b"BITMAP":
break break
i = s.find(b" ") i = s.find(b" ")
props[s[:i].decode('ascii')] = s[i+1:-1].decode('ascii') props[s[:i].decode('ascii')] = s[i + 1:-1].decode('ascii')
# load bitmap # load bitmap
bitmap = [] bitmap = []
@ -72,7 +67,7 @@ def bdf_char(f):
[x, y, l, d] = [int(p) for p in props["BBX"].split()] [x, y, l, d] = [int(p) for p in props["BBX"].split()]
[dx, dy] = [int(p) for p in props["DWIDTH"].split()] [dx, dy] = [int(p) for p in props["DWIDTH"].split()]
bbox = (dx, dy), (l, -d-y, x+l, -d), (0, 0, x, y) bbox = (dx, dy), (l, -d - y, x + l, -d), (0, 0, x, y)
try: try:
im = Image.frombytes("1", (x, y), bitmap, "hex", "1") im = Image.frombytes("1", (x, y), bitmap, "hex", "1")
@ -82,12 +77,11 @@ def bdf_char(f):
return id, int(props["ENCODING"]), bbox, im return id, int(props["ENCODING"]), bbox, im
## ##
# Font file plugin for the X11 BDF format. # Font file plugin for the X11 BDF format.
class BdfFontFile(FontFile.FontFile):
class BdfFontFile(FontFile.FontFile):
def __init__(self, fp): def __init__(self, fp):
FontFile.FontFile.__init__(self) FontFile.FontFile.__init__(self)
@ -104,10 +98,10 @@ class BdfFontFile(FontFile.FontFile):
if not s or s[:13] == b"ENDPROPERTIES": if not s or s[:13] == b"ENDPROPERTIES":
break break
i = s.find(b" ") i = s.find(b" ")
props[s[:i].decode('ascii')] = s[i+1:-1].decode('ascii') props[s[:i].decode('ascii')] = s[i + 1:-1].decode('ascii')
if s[:i] in [b"COMMENT", b"COPYRIGHT"]: if s[:i] in [b"COMMENT", b"COPYRIGHT"]:
if s.find(b"LogicalFontDescription") < 0: if s.find(b"LogicalFontDescription") < 0:
comments.append(s[i+1:-1].decode('ascii')) comments.append(s[i + 1:-1].decode('ascii'))
font = props["FONT"].split("-") font = props["FONT"].split("-")

View File

@ -23,14 +23,11 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
__version__ = "0.7" __version__ = "0.7"
from PIL import Image, ImageFile, ImagePalette, _binary from PIL import Image, ImageFile, ImagePalette, _binary
import math import math
i8 = _binary.i8 i8 = _binary.i8
i16 = _binary.i16le i16 = _binary.i16le
i32 = _binary.i32le i32 = _binary.i32le
@ -67,7 +64,14 @@ class BmpImageFile(ImageFile.ImageFile):
format_description = "Windows Bitmap" format_description = "Windows Bitmap"
format = "BMP" format = "BMP"
# --------------------------------------------------- BMP Compression values # --------------------------------------------------- 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 RAW, RLE8, RLE4, BITFIELDS, JPEG, PNG = 0, 1, 2, 3, 4, 5
def _bitmap(self, header=0, offset=0): def _bitmap(self, header=0, offset=0):
@ -76,10 +80,14 @@ class BmpImageFile(ImageFile.ImageFile):
if header: if header:
seek(header) seek(header)
file_info = dict() 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 file_info['direction'] = -1
# --------------------- If requested, read header at a specific position # --------------------- 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 # --------------------------------------------------- IBM OS/2 Bitmap v1
# ------ This format has different offsets because of width/height types # ------ This format has different offsets because of width/height types
if file_info['header_size'] == 12: if file_info['header_size'] == 12:
@ -90,59 +98,87 @@ class BmpImageFile(ImageFile.ImageFile):
file_info['compression'] = self.RAW file_info['compression'] = self.RAW
file_info['palette_padding'] = 3 file_info['palette_padding'] = 3
# ---------------------------------------------- Windows Bitmap v2 to v5 # ---------------------------------------------- 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 if file_info['header_size'] >= 40: # v3 and OS/2
file_info['y_flip'] = i8(header_data[7]) == 0xff file_info['y_flip'] = i8(header_data[7]) == 0xff
file_info['direction'] = 1 if file_info['y_flip'] else -1 file_info['direction'] = 1 if file_info['y_flip'] else -1
file_info['width'] = i32(header_data[0:4]) 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['planes'] = i16(header_data[8:10])
file_info['bits'] = i16(header_data[10:12]) file_info['bits'] = i16(header_data[10:12])
file_info['compression'] = i32(header_data[12:16]) file_info['compression'] = i32(header_data[12:16])
file_info['data_size'] = i32(header_data[16:20]) # byte size of pixel data file_info['data_size'] = i32(header_data[16:20]
file_info['pixels_per_meter'] = (i32(header_data[20:24]), i32(header_data[24:28])) ) # 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['colors'] = i32(header_data[28:32])
file_info['palette_padding'] = 4 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 file_info['compression'] == self.BITFIELDS:
if len(header_data) >= 52: if len(header_data) >= 52:
for idx, mask in enumerate(['r_mask', 'g_mask', 'b_mask', 'a_mask']): for idx, mask in enumerate(['r_mask', 'g_mask',
file_info[mask] = i32(header_data[36+idx*4:40+idx*4]) 'b_mask', 'a_mask']):
file_info[mask] = i32(
header_data[36 + idx * 4:40 + idx * 4])
else: else:
for mask in ['r_mask', 'g_mask', 'b_mask', 'a_mask']: for mask in ['r_mask', 'g_mask', 'b_mask', 'a_mask']:
file_info[mask] = i32(read(4)) file_info[mask] = i32(read(4))
file_info['rgb_mask'] = (file_info['r_mask'], file_info['g_mask'], file_info['b_mask']) file_info['rgb_mask'] = (file_info['r_mask'],
file_info['rgba_mask'] = (file_info['r_mask'], file_info['g_mask'], file_info['b_mask'], file_info['a_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: 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 # ------------------ Special case : header is reported 40, which
# ---------------------- is shorter than real size for bpp >= 16 # ---------------------- is shorter than real size for bpp >= 16
self.size = file_info['width'], file_info['height'] self.size = file_info['width'], file_info['height']
# -------- If color count was not found in the header, compute from bits # -------- 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 # -------------------------------- Check abnormal values for DOS attacks
if file_info['width'] * file_info['height'] > 2**31: if file_info['width'] * file_info['height'] > 2 ** 31:
raise IOError("Unsupported BMP Size: (%dx%d)" % self.size) raise IOError("Unsupported BMP Size: (%dx%d)" % self.size)
# ----------------------- Check bit depth for unusual unsupported values # ----------------------- Check bit depth for unusual unsupported values
self.mode, raw_mode = BIT2MODE.get(file_info['bits'], (None, None)) self.mode, raw_mode = BIT2MODE.get(file_info['bits'], (None, None))
if self.mode is 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) # ----------------- Process BMP with Bitfields compression (not palette)
if file_info['compression'] == self.BITFIELDS: if file_info['compression'] == self.BITFIELDS:
SUPPORTED = { 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)], 24: [(0xff0000, 0xff00, 0xff)],
16: [(0xf800, 0x7e0, 0x1f), (0x7c00, 0x3e0, 0x1f)]} 16: [(0xf800, 0x7e0, 0x1f), (0x7c00, 0x3e0, 0x1f)]
}
MASK_MODES = { 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", (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'] in SUPPORTED:
if file_info['bits'] == 32 and file_info['rgba_mask'] in SUPPORTED[file_info['bits']]: if file_info['bits'] == 32 and file_info[
raw_mode = MASK_MODES[(file_info['bits'], file_info['rgba_mask'])] 'rgba_mask'
self.mode = "RGBA" if raw_mode in ("BGRA",) else self.mode ] in SUPPORTED[file_info['bits']]:
elif file_info['bits'] in (24, 16) and file_info['rgb_mask'] in SUPPORTED[file_info['bits']]: raw_mode = MASK_MODES[(file_info['bits'],
raw_mode = MASK_MODES[(file_info['bits'], file_info['rgb_mask'])] 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'])]
else: else:
raise IOError("Unsupported BMP bitfields layout") raise IOError("Unsupported BMP bitfields layout")
else: else:
@ -151,20 +187,23 @@ class BmpImageFile(ImageFile.ImageFile):
if file_info['bits'] == 32 and header == 22: # 32-bit .cur offset if file_info['bits'] == 32 and header == 22: # 32-bit .cur offset
raw_mode, self.mode = "BGRA", "RGBA" raw_mode, self.mode = "BGRA", "RGBA"
else: 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 # ---------------- Once the header is processed, process the palette/LUT
if self.mode == "P": # Paletted for 1, 4 and 8 bit images if self.mode == "P": # Paletted for 1, 4 and 8 bit images
# ----------------------------------------------------- 1-bit images # ----------------------------------------------------- 1-bit images
if not (0 < file_info['colors'] <= 65536): 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: else:
padding = file_info['palette_padding'] padding = file_info['palette_padding']
palette = read(padding * file_info['colors']) palette = read(padding * file_info['colors'])
greyscale = True 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 # ------------------ Check if greyscale and ignore palette if so
for ind, val in enumerate(indices): for ind, val in enumerate(indices):
rgb = palette[ind*padding:ind*padding + 3] rgb = palette[ind * padding:ind * padding + 3]
if rgb != o8(val) * 3: if rgb != o8(val) * 3:
greyscale = False greyscale = False
# -------- If all colors are grey, white or black, ditch palette # -------- If all colors are grey, white or black, ditch palette
@ -173,13 +212,16 @@ class BmpImageFile(ImageFile.ImageFile):
raw_mode = self.mode raw_mode = self.mode
else: else:
self.mode = "P" 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 # ----------------------------- Finally set the tile data for the plugin
self.info['compression'] = file_info['compression'] self.info['compression'] = file_info['compression']
self.tile = [('raw', (0, 0, file_info['width'], file_info['height']), offset or self.fp.tell(), self.tile = [('raw', (0, 0, file_info['width'], file_info['height']),
(raw_mode, ((file_info['width'] * file_info['bits'] + 31) >> 3) & (~3), file_info['direction']) offset or self.fp.tell(),
)] (raw_mode,
((file_info['width'] * file_info['bits'] + 31) >> 3) &
(~3), file_info['direction']))]
def _open(self): def _open(self):
""" Open file, check magic number and read header """ """ Open file, check magic number and read header """
@ -234,14 +276,14 @@ def _save(im, fp, filename, check=0):
# 1 meter == 39.3701 inches # 1 meter == 39.3701 inches
ppm = tuple(map(lambda x: int(x * 39.3701), dpi)) ppm = tuple(map(lambda x: int(x * 39.3701), dpi))
stride = ((im.size[0]*bits+7)//8+3) & (~3) stride = ((im.size[0] * bits + 7) // 8 + 3) & (~3)
header = 40 # or 64 for OS/2 version 2 header = 40 # or 64 for OS/2 version 2
offset = 14 + header + colors * 4 offset = 14 + header + colors * 4
image = stride * im.size[1] image = stride * im.size[1]
# bitmap header # bitmap header
fp.write(b"BM" + # file type (magic) fp.write(b"BM" + # file type (magic)
o32(offset+image) + # file size o32(offset + image) + # file size
o32(0) + # reserved o32(0) + # reserved
o32(offset)) # image data offset o32(offset)) # image data offset
@ -268,7 +310,7 @@ def _save(im, fp, filename, check=0):
elif im.mode == "P": elif im.mode == "P":
fp.write(im.im.getpalette("RGB", "BGRX")) fp.write(im.im.getpalette("RGB", "BGRX"))
ImageFile._save(im, fp, [("raw", (0, 0)+im.size, 0, ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0,
(rawmode, stride, -1))]) (rawmode, stride, -1))])
# #

View File

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

View File

@ -16,12 +16,10 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
__version__ = "0.1" __version__ = "0.1"
from PIL import Image, BmpImagePlugin, _binary from PIL import Image, BmpImagePlugin, _binary
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
@ -33,10 +31,10 @@ i32 = _binary.i32le
def _accept(prefix): def _accept(prefix):
return prefix[:4] == b"\0\0\2\0" return prefix[:4] == b"\0\0\2\0"
## ##
# Image plugin for Windows Cursor files. # Image plugin for Windows Cursor files.
class CurImageFile(BmpImagePlugin.BmpImageFile): class CurImageFile(BmpImagePlugin.BmpImageFile):
format = "CUR" format = "CUR"
@ -72,13 +70,12 @@ class CurImageFile(BmpImagePlugin.BmpImageFile):
self._bitmap(i32(m[12:]) + offset) self._bitmap(i32(m[12:]) + offset)
# patch up the bitmap height # patch up the bitmap height
self.size = self.size[0], self.size[1]//2 self.size = self.size[0], self.size[1] // 2
d, e, o, a = self.tile[0] d, e, o, a = self.tile[0]
self.tile[0] = d, (0, 0)+self.size, o, a self.tile[0] = d, (0, 0) + self.size, o, a
return return
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------

View File

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

View File

@ -81,8 +81,8 @@ def Ghostscript(tile, size, fp, scale=1):
# orig_bbox = bbox # orig_bbox = bbox
size = (size[0] * scale, size[1] * scale) size = (size[0] * scale, size[1] * scale)
# resolution is dependent on bbox and size # resolution is dependent on bbox and size
res = (float((72.0 * size[0]) / (bbox[2]-bbox[0])), res = (float((72.0 * size[0]) / (bbox[2] - bbox[0])),
float((72.0 * size[1]) / (bbox[3]-bbox[1]))) float((72.0 * size[1]) / (bbox[3] - bbox[1])))
# print("Ghostscript", scale, size, orig_size, bbox, orig_bbox, res) # print("Ghostscript", scale, size, orig_size, bbox, orig_bbox, res)
import os import os
@ -112,15 +112,14 @@ def Ghostscript(tile, size, fp, scale=1):
fp.seek(0) fp.seek(0)
lengthfile = fsize lengthfile = fsize
while lengthfile > 0: while lengthfile > 0:
s = fp.read(min(lengthfile, 100*1024)) s = fp.read(min(lengthfile, 100 * 1024))
if not s: if not s:
break break
lengthfile -= len(s) lengthfile -= len(s)
f.write(s) f.write(s)
# Build ghostscript command # Build ghostscript command
command = ["gs", command = ["gs", "-q", # quiet mode
"-q", # quiet mode
"-g%dx%d" % size, # set output geometry (pixels) "-g%dx%d" % size, # set output geometry (pixels)
"-r%fx%f" % res, # set input DPI (dots per inch) "-r%fx%f" % res, # set input DPI (dots per inch)
"-dNOPAUSE -dSAFER", # don't pause between pages, "-dNOPAUSE -dSAFER", # don't pause between pages,
@ -139,7 +138,8 @@ def Ghostscript(tile, size, fp, scale=1):
# push data through ghostscript # push data through ghostscript
try: try:
gs = subprocess.Popen(command, stdin=subprocess.PIPE, gs = subprocess.Popen(command,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE) stdout=subprocess.PIPE)
gs.stdin.close() gs.stdin.close()
status = gs.wait() status = gs.wait()
@ -161,6 +161,7 @@ class PSFile:
""" """
Wrapper for bytesio object that treats either CR or LF as end of line. Wrapper for bytesio object that treats either CR or LF as end of line.
""" """
def __init__(self, fp): def __init__(self, fp):
self.fp = fp self.fp = fp
self.char = None self.char = None
@ -343,10 +344,10 @@ class EpsImageFile(ImageFile.ImageFile):
# use our custom load method by defining this method. # use our custom load method by defining this method.
pass pass
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
def _save(im, fp, filename, eps=1): def _save(im, fp, filename, eps=1):
"""EPS Writer for the Python Imaging Library.""" """EPS Writer for the Python Imaging Library."""
@ -405,7 +406,7 @@ def _save(im, fp, filename, eps=1):
fp.write(operator[2] + "\n") fp.write(operator[2] + "\n")
fp.flush() fp.flush()
ImageFile._save(im, base_fp, [("eps", (0, 0)+im.size, 0, None)]) ImageFile._save(im, base_fp, [("eps", (0, 0) + im.size, 0, None)])
fp.write("\n%%%%EndBinary\n") fp.write("\n%%%%EndBinary\n")
fp.write("grestore end\n") fp.write("grestore end\n")

View File

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

View File

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

View File

@ -15,7 +15,6 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
__version__ = "0.2" __version__ = "0.2"
from PIL import Image, ImageFile, ImagePalette, _binary from PIL import Image, ImageFile, ImagePalette, _binary
@ -25,18 +24,18 @@ i16 = _binary.i16le
i32 = _binary.i32le i32 = _binary.i32le
o8 = _binary.o8 o8 = _binary.o8
# #
# decoder # decoder
def _accept(prefix): def _accept(prefix):
return i16(prefix[4:6]) in [0xAF11, 0xAF12] return i16(prefix[4:6]) in [0xAF11, 0xAF12]
## ##
# Image plugin for the FLI/FLC animation format. Use the <b>seek</b> # Image plugin for the FLI/FLC animation format. Use the <b>seek</b>
# method to load individual frames. # method to load individual frames.
class FliImageFile(ImageFile.ImageFile): class FliImageFile(ImageFile.ImageFile):
format = "FLI" format = "FLI"
@ -47,8 +46,8 @@ class FliImageFile(ImageFile.ImageFile):
# HEAD # HEAD
s = self.fp.read(128) s = self.fp.read(128)
magic = i16(s[4:6]) magic = i16(s[4:6])
if not (magic in [0xAF11, 0xAF12] and if not (magic in [0xAF11, 0xAF12] and i16(s[14:16]) in [0, 3] and
i16(s[14:16]) in [0, 3] and # flags # flags
s[20:22] == b"\x00\x00"): # reserved s[20:22] == b"\x00\x00"): # reserved
raise SyntaxError("not an FLI/FLC file") raise SyntaxError("not an FLI/FLC file")
@ -82,7 +81,7 @@ class FliImageFile(ImageFile.ImageFile):
elif i16(s[4:6]) == 4: elif i16(s[4:6]) == 4:
self._palette(palette, 0) self._palette(palette, 0)
palette = [o8(r)+o8(g)+o8(b) for (r, g, b) in palette] palette = [o8(r) + o8(g) + o8(b) for (r, g, b) in palette]
self.palette = ImagePalette.raw("RGB", b"".join(palette)) self.palette = ImagePalette.raw("RGB", b"".join(palette))
# set things up to decode first frame # set things up to decode first frame
@ -104,8 +103,8 @@ class FliImageFile(ImageFile.ImageFile):
s = self.fp.read(n * 3) s = self.fp.read(n * 3)
for n in range(0, len(s), 3): for n in range(0, len(s), 3):
r = i8(s[n]) << shift r = i8(s[n]) << shift
g = i8(s[n+1]) << shift g = i8(s[n + 1]) << shift
b = i8(s[n+2]) << shift b = i8(s[n + 2]) << shift
palette[i] = (r, g, b) palette[i] = (r, g, b)
i += 1 i += 1
@ -126,7 +125,7 @@ class FliImageFile(ImageFile.ImageFile):
framesize = i32(s) framesize = i32(s)
self.decodermaxblock = framesize self.decodermaxblock = framesize
self.tile = [("fli", (0, 0)+self.size, self.__offset, None)] self.tile = [("fli", (0, 0) + self.size, self.__offset, None)]
self.__offset = self.__offset + framesize self.__offset = self.__offset + framesize

View File

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

View File

@ -15,20 +15,17 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
__version__ = "0.1" __version__ = "0.1"
from PIL import Image, ImageFile from PIL import Image, ImageFile
from PIL.OleFileIO import i8, i32, MAGIC, OleFileIO from PIL.OleFileIO import i8, i32, MAGIC, OleFileIO
# we map from colour field tuples to (mode, rawmode) descriptors # we map from colour field tuples to (mode, rawmode) descriptors
MODES = { MODES = {
# opacity # opacity
(0x00007ffe): ("A", "L"), (0x00007ffe): ("A", "L"),
# monochrome # monochrome
(0x00010000,): ("L", "L"), (0x00010000, ): ("L", "L"),
(0x00018000, 0x00017ffe): ("RGBA", "LA"), (0x00018000, 0x00017ffe): ("RGBA", "LA"),
# photo YCC # photo YCC
(0x00020000, 0x00020001, 0x00020002): ("RGB", "YCC;P"), (0x00020000, 0x00020001, 0x00020002): ("RGB", "YCC;P"),
@ -38,17 +35,17 @@ MODES = {
(0x00038000, 0x00038001, 0x00038002, 0x00037ffe): ("RGBA", "RGBA"), (0x00038000, 0x00038001, 0x00038002, 0x00037ffe): ("RGBA", "RGBA"),
} }
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
def _accept(prefix): def _accept(prefix):
return prefix[:8] == MAGIC return prefix[:8] == MAGIC
## ##
# Image plugin for the FlashPix images. # Image plugin for the FlashPix images.
class FpxImageFile(ImageFile.ImageFile): class FpxImageFile(ImageFile.ImageFile):
format = "FPX" format = "FPX"
@ -73,10 +70,8 @@ class FpxImageFile(ImageFile.ImageFile):
# #
# get the Image Contents Property Set # get the Image Contents Property Set
prop = self.ole.getproperties([ prop = self.ole.getproperties(["Data Object Store %06d" % index,
"Data Object Store %06d" % index, "\005Image Contents"])
"\005Image Contents"
])
# size (highest resolution) # size (highest resolution)
@ -102,7 +97,7 @@ class FpxImageFile(ImageFile.ImageFile):
colors = [] colors = []
for i in range(i32(s, 4)): for i in range(i32(s, 4)):
# note: for now, we ignore the "uncalibrated" flag # note: for now, we ignore the "uncalibrated" flag
colors.append(i32(s, 8+i*4) & 0x7fffffff) colors.append(i32(s, 8 + i * 4) & 0x7fffffff)
self.mode, self.rawmode = MODES[tuple(colors)] self.mode, self.rawmode = MODES[tuple(colors)]
@ -121,11 +116,8 @@ class FpxImageFile(ImageFile.ImageFile):
# #
# setup tile descriptors for a given subimage # setup tile descriptors for a given subimage
stream = [ stream = ["Data Object Store %06d" % index,
"Data Object Store %06d" % index, "Resolution %04d" % subimage, "Subimage 0000 Header"]
"Resolution %04d" % subimage,
"Subimage 0000 Header"
]
fp = self.ole.openstream(stream) fp = self.ole.openstream(stream)
@ -158,16 +150,16 @@ class FpxImageFile(ImageFile.ImageFile):
for i in range(0, len(s), length): for i in range(0, len(s), length):
compression = i32(s, i+8) compression = i32(s, i + 8)
if compression == 0: if compression == 0:
self.tile.append(("raw", (x, y, x+xtile, y+ytile), self.tile.append(("raw", (x, y, x + xtile, y + ytile),
i32(s, i) + 28, (self.rawmode))) i32(s, i) + 28, (self.rawmode)))
elif compression == 1: elif compression == 1:
# FIXME: the fill decoder is not implemented # FIXME: the fill decoder is not implemented
self.tile.append(("fill", (x, y, x+xtile, y+ytile), self.tile.append(("fill", (x, y, x + xtile, y + ytile),
i32(s, i) + 28, (self.rawmode, s[12:16]))) i32(s, i) + 28, (self.rawmode, s[12:16])))
elif compression == 2: elif compression == 2:
@ -190,7 +182,7 @@ class FpxImageFile(ImageFile.ImageFile):
# The image is stored as defined by rawmode # The image is stored as defined by rawmode
jpegmode = rawmode jpegmode = rawmode
self.tile.append(("jpeg", (x, y, x+xtile, y+ytile), self.tile.append(("jpeg", (x, y, x + xtile, y + ytile),
i32(s, i) + 28, (rawmode, jpegmode))) i32(s, i) + 28, (rawmode, jpegmode)))
# FIXME: jpeg tables are tile dependent; the prefix # FIXME: jpeg tables are tile dependent; the prefix
@ -214,8 +206,8 @@ class FpxImageFile(ImageFile.ImageFile):
def load(self): def load(self):
if not self.fp: if not self.fp:
self.fp = self.ole.openstream(self.stream[:2] + self.fp = self.ole.openstream(
["Subimage 0000 Data"]) self.stream[:2] + ["Subimage 0000 Data"])
ImageFile.ImageFile.load(self) ImageFile.ImageFile.load(self)

View File

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

View File

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

View File

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

View File

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

View File

@ -17,17 +17,17 @@
import re import re
from PIL._binary import o8 from PIL._binary import o8
## ##
# File handler for GIMP's palette format. # File handler for GIMP's palette format.
class GimpPaletteFile: class GimpPaletteFile:
rawmode = "RGB" rawmode = "RGB"
def __init__(self, fp): def __init__(self, fp):
self.palette = [o8(i)*3 for i in range(256)] self.palette = [o8(i) * 3 for i in range(256)]
if fp.readline()[:12] != b"GIMP Palette": if fp.readline()[:12] != b"GIMP Palette":
raise SyntaxError("not a GIMP palette file") raise SyntaxError("not a GIMP palette file")

View File

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

View File

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

View File

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

View File

@ -21,7 +21,6 @@
# * http://en.wikipedia.org/wiki/ICO_(file_format) # * http://en.wikipedia.org/wiki/ICO_(file_format)
# * http://msdn.microsoft.com/en-us/library/ms997538.aspx # * http://msdn.microsoft.com/en-us/library/ms997538.aspx
__version__ = "0.1" __version__ = "0.1"
import struct import struct
@ -46,11 +45,12 @@ def _save(im, fp, filename):
[(16, 16), (24, 24), (32, 32), (48, 48), [(16, 16), (24, 24), (32, 32), (48, 48),
(64, 64), (128, 128), (255, 255)]) (64, 64), (128, 128), (255, 255)])
width, height = im.size width, height = im.size
filter(lambda x: False if (x[0] > width or x[1] > height or filter(lambda x: False
x[0] > 255 or x[1] > 255) else True, sizes) 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]) sizes = sorted(sizes, key=lambda x: x[0])
fp.write(struct.pack("H", len(sizes))) # idCount(2) fp.write(struct.pack("H", len(sizes))) # idCount(2)
offset = fp.tell() + len(sizes)*16 offset = fp.tell() + len(sizes) * 16
for size in sizes: for size in sizes:
width, height = size width, height = size
fp.write(struct.pack("B", width)) # bWidth(1) fp.write(struct.pack("B", width)) # bWidth(1)
@ -119,14 +119,15 @@ class IcoFile:
# See Wikipedia notes about color depth. # See Wikipedia notes about color depth.
# We need this just to differ images with equal sizes # 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 (icon_header['nb_color'] != 0 and
ceil(log(icon_header['nb_color'], ceil(log(icon_header['nb_color'], 2))) or 256)
2))) or 256)
icon_header['dim'] = (icon_header['width'], icon_header['height']) icon_header['dim'] = (icon_header['width'], icon_header['height'])
icon_header['square'] = (icon_header['width'] * icon_header['square'] = (
icon_header['height']) icon_header['width'] * icon_header['height']
)
self.entry.append(icon_header) self.entry.append(icon_header)
@ -224,7 +225,7 @@ class IcoFile:
im.size, # (w, h) im.size, # (w, h)
maskData, # source chars maskData, # source chars
'raw', # raw decoder 'raw', # raw decoder
('1;I', int(w/8), -1) # 1bpp inverted, padded, reversed ('1;I', int(w / 8), -1) # 1bpp inverted, padded, reversed
) )
# now we have two images, im is XOR image and mask is AND image # now we have two images, im is XOR image and mask is AND image
@ -235,10 +236,10 @@ class IcoFile:
return im return im
## ##
# Image plugin for Windows Icon files. # Image plugin for Windows Icon files.
class IcoImageFile(ImageFile.ImageFile): class IcoImageFile(ImageFile.ImageFile):
""" """
PIL read-only image support for Microsoft Windows .ico files. 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. # See the README file for information on usage and redistribution.
# #
__version__ = "0.7" __version__ = "0.7"
import re import re
from PIL import Image, ImageFile, ImagePalette from PIL import Image, ImageFile, ImagePalette
from PIL._binary import i8 from PIL._binary import i8
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Standard tags # Standard tags
@ -46,8 +44,17 @@ SCALE = "Scale (x,y)"
SIZE = "Image size (x*y)" SIZE = "Image size (x*y)"
MODE = "Image type" MODE = "Image type"
TAGS = {COMMENT: 0, DATE: 0, EQUIPMENT: 0, FRAMES: 0, LUT: 0, NAME: 0, TAGS = {
SCALE: 0, SIZE: 0, MODE: 0} COMMENT: 0,
DATE: 0,
EQUIPMENT: 0,
FRAMES: 0,
LUT: 0,
NAME: 0,
SCALE: 0,
SIZE: 0,
MODE: 0
}
OPEN = { OPEN = {
# ifunc93/p3cfunc formats # ifunc93/p3cfunc formats
@ -88,7 +95,6 @@ for i in ["32S"]:
for i in range(2, 33): for i in range(2, 33):
OPEN["L*%s image" % i] = ("F", "F;%s" % i) OPEN["L*%s image" % i] = ("F", "F;%s" % i)
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Read IM directory # Read IM directory
@ -101,10 +107,10 @@ def number(s):
except ValueError: except ValueError:
return float(s) return float(s)
## ##
# Image plugin for the IFUNC IM file format. # Image plugin for the IFUNC IM file format.
class ImImageFile(ImageFile.ImageFile): class ImImageFile(ImageFile.ImageFile):
format = "IM" format = "IM"
@ -188,8 +194,8 @@ class ImImageFile(ImageFile.ImageFile):
else: else:
raise SyntaxError("Syntax error in IM header: " + raise SyntaxError(
s.decode('ascii', 'replace')) "Syntax error in IM header: " + s.decode('ascii', 'replace'))
if not n: if not n:
raise SyntaxError("Not an IM file") raise SyntaxError("Not an IM file")
@ -210,7 +216,7 @@ class ImImageFile(ImageFile.ImageFile):
greyscale = 1 # greyscale palette greyscale = 1 # greyscale palette
linear = 1 # linear greyscale palette linear = 1 # linear greyscale palette
for i in range(256): for i in range(256):
if palette[i] == palette[i+256] == palette[i+512]: if palette[i] == palette[i + 256] == palette[i + 512]:
if i8(palette[i]) != i: if i8(palette[i]) != i:
linear = 0 linear = 0
else: else:
@ -242,7 +248,7 @@ class ImImageFile(ImageFile.ImageFile):
# use bit decoder (if necessary) # use bit decoder (if necessary)
bits = int(self.rawmode[2:]) bits = int(self.rawmode[2:])
if bits not in [8, 16, 32]: if bits not in [8, 16, 32]:
self.tile = [("bit", (0, 0)+self.size, offs, self.tile = [("bit", (0, 0) + self.size, offs,
(bits, 8, 3, 0, -1))] (bits, 8, 3, 0, -1))]
return return
except ValueError: except ValueError:
@ -252,12 +258,14 @@ class ImImageFile(ImageFile.ImageFile):
# Old LabEye/3PC files. Would be very surprised if anyone # Old LabEye/3PC files. Would be very surprised if anyone
# ever stumbled upon such a file ;-) # ever stumbled upon such a file ;-)
size = self.size[0] * self.size[1] size = self.size[0] * self.size[1]
self.tile = [("raw", (0, 0)+self.size, offs, ("G", 0, -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 + size,
("raw", (0, 0)+self.size, offs+2*size, ("B", 0, -1))] ("R", 0, -1)), ("raw",
(0, 0) + self.size, offs + 2 * size,
("B", 0, -1))]
else: else:
# LabEye/IFUNC files # LabEye/IFUNC files
self.tile = [("raw", (0, 0)+self.size, offs, self.tile = [("raw", (0, 0) + self.size, offs,
(self.rawmode, 0, -1))] (self.rawmode, 0, -1))]
def seek(self, frame): def seek(self, frame):
@ -280,7 +288,7 @@ class ImImageFile(ImageFile.ImageFile):
self.fp = self.__fp self.fp = self.__fp
self.tile = [("raw", (0, 0)+self.size, offs, (self.rawmode, 0, -1))] self.tile = [("raw", (0, 0) + self.size, offs, (self.rawmode, 0, -1))]
def tell(self): def tell(self):
@ -292,21 +300,12 @@ class ImImageFile(ImageFile.ImageFile):
SAVE = { SAVE = {
# mode: (im type, raw mode) # mode: (im type, raw mode)
"1": ("0 1", "1"), "1": ("0 1", "1"), "L": ("Greyscale", "L"), "LA": ("LA", "LA;L"), "P": (
"L": ("Greyscale", "L"), "Greyscale", "P"), "PA": ("LA", "PA;L"), "I": ("L 32S", "I;32S"
"LA": ("LA", "LA;L"), ), "I;16": ("L 16", "I;16"), "I;16L": ("L 16L", "I;16L"), "I;16B": (
"P": ("Greyscale", "P"), "L 16B", "I;16B"), "F": ("L 32F", "F;32F"), "RGB": ("RGB", "RGB;L"
"PA": ("LA", "PA;L"), ), "RGBA": ("RGBA", "RGBA;L"), "RGBX": ("RGBX", "RGBX;L"), "CMYK": (
"I": ("L 32S", "I;32S"), "CMYK", "CMYK;L"), "YCbCr": ("YCC", "YCbCr;L")
"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")
} }
@ -332,10 +331,10 @@ def _save(im, fp, filename, check=0):
fp.write(("File size (no of images): %d\r\n" % frames).encode('ascii')) fp.write(("File size (no of images): %d\r\n" % frames).encode('ascii'))
if im.mode == "P": if im.mode == "P":
fp.write(b"Lut: 1\r\n") fp.write(b"Lut: 1\r\n")
fp.write(b"\000" * (511-fp.tell()) + b"\032") fp.write(b"\000" * (511 - fp.tell()) + b"\032")
if im.mode == "P": if im.mode == "P":
fp.write(im.im.getpalette("RGB", "RGB;L")) # 768 bytes fp.write(im.im.getpalette("RGB", "RGB;L")) # 768 bytes
ImageFile._save(im, fp, [("raw", (0, 0)+im.size, 0, (rawmode, 0, -1))]) ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, -1))])
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------

View File

@ -40,7 +40,6 @@ class _imaging_not_installed:
def __getattr__(self, id): def __getattr__(self, id):
raise ImportError("The _imaging C module is not installed") raise ImportError("The _imaging C module is not installed")
# Limit to around a quarter gigabyte for a 24 bit (3 bpp) image # Limit to around a quarter gigabyte for a 24 bit (3 bpp) image
MAX_IMAGE_PIXELS = int(1024 * 1024 * 1024 / 4 / 3) MAX_IMAGE_PIXELS = int(1024 * 1024 * 1024 / 4 / 3)
@ -72,25 +71,20 @@ except ImportError as v:
# The _imaging C module is present, but not compiled for # The _imaging C module is present, but not compiled for
# the right version (windows only). Print a warning, if # the right version (windows only). Print a warning, if
# possible. # possible.
warnings.warn( warnings.warn("The _imaging extension was built for another version "
"The _imaging extension was built for another version " "of Python.", RuntimeWarning)
"of Python.",
RuntimeWarning
)
elif str(v).startswith("The _imaging extension"): elif str(v).startswith("The _imaging extension"):
warnings.warn(str(v), RuntimeWarning) warnings.warn(str(v), RuntimeWarning)
elif "Symbol not found: _PyUnicodeUCS2_FromString" in str(v): elif "Symbol not found: _PyUnicodeUCS2_FromString" in str(v):
warnings.warn( warnings.warn(
"The _imaging extension was built for Python with UCS2 support; " "The _imaging extension was built for Python with UCS2 support; "
"recompile PIL or build Python --without-wide-unicode. ", "recompile PIL or build Python --without-wide-unicode. ",
RuntimeWarning RuntimeWarning)
)
elif "Symbol not found: _PyUnicodeUCS4_FromString" in str(v): elif "Symbol not found: _PyUnicodeUCS4_FromString" in str(v):
warnings.warn( warnings.warn(
"The _imaging extension was built for Python with UCS4 support; " "The _imaging extension was built for Python with UCS4 support; "
"recompile PIL or build Python --with-wide-unicode. ", "recompile PIL or build Python --with-wide-unicode. ",
RuntimeWarning RuntimeWarning)
)
# Fail here anyway. Don't let people run with a mostly broken Pillow. # Fail here anyway. Don't let people run with a mostly broken Pillow.
# see docs/porting-pil-to-pillow.rst # see docs/porting-pil-to-pillow.rst
raise raise
@ -196,7 +190,6 @@ if hasattr(core, 'DEFAULT_STRATEGY'):
RLE = core.RLE RLE = core.RLE
FIXED = core.FIXED FIXED = core.FIXED
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Registries # Registries
@ -212,25 +205,22 @@ EXTENSION = {}
_MODEINFO = { _MODEINFO = {
# NOTE: this table will be removed in future versions. use # NOTE: this table will be removed in future versions. use
# getmode* functions or ImageMode descriptors instead. # getmode* functions or ImageMode descriptors instead.
# official modes # official modes
"1": ("L", "L", ("1",)), "1": ("L", "L", ("1", )), "L": ("L", "L", ("L", )), "I": ("L", "I", ("I", )
"L": ("L", "L", ("L",)), ), "F": ("L", "F",
"I": ("L", "I", ("I",)), ("F", )), "P": ("RGB", "L",
"F": ("L", "F", ("F",)), ("P", )), "RGB": ("RGB", "L", ("R", "G", "B")
"P": ("RGB", "L", ("P",)), ), "RGBX": ("RGB", "L",
"RGB": ("RGB", "L", ("R", "G", "B")), ("R", "G", "B", "X")), "RGBA": ("RGB", "L",
"RGBX": ("RGB", "L", ("R", "G", "B", "X")), ("R", "G", "B", "A")
"RGBA": ("RGB", "L", ("R", "G", "B", "A")), ), "CMYK": ("RGB", "L",
"CMYK": ("RGB", "L", ("C", "M", "Y", "K")), ("C", "M", "Y", "K")), "YCbCr": ("RGB", "L",
"YCbCr": ("RGB", "L", ("Y", "Cb", "Cr")), ("Y", "Cb", "Cr")
"LAB": ("RGB", "L", ("L", "A", "B")), ), "LAB": ("RGB", "L", ("L", "A", "B")), "HSV": ("RGB", "L",
"HSV": ("RGB", "L", ("H", "S", "V")), ("H", "S", "V")),
# Experimental modes include I;16, I;16L, I;16B, RGBa, BGR;15, and # 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 # BGR;24. Use these modes only if you know exactly what you're
# doing... # doing...
} }
if sys.byteorder == 'little': if sys.byteorder == 'little':
@ -273,7 +263,7 @@ def _conv_type_shape(im):
if extra is None: if extra is None:
return shape, typ return shape, typ
else: else:
return shape+(extra,), typ return shape + (extra, ), typ
MODES = sorted(_MODEINFO.keys()) MODES = sorted(_MODEINFO.keys())
@ -387,7 +377,7 @@ def init():
for plugin in _plugins: for plugin in _plugins:
try: try:
if DEBUG: if DEBUG:
print ("Importing %s" % plugin) print("Importing %s" % plugin)
__import__("PIL.%s" % plugin, globals(), locals(), []) __import__("PIL.%s" % plugin, globals(), locals(), [])
except ImportError: except ImportError:
if DEBUG: if DEBUG:
@ -398,17 +388,17 @@ def init():
_initialized = 2 _initialized = 2
return 1 return 1
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Codec factories (used by tobytes/frombytes and ImageFile.load) # Codec factories (used by tobytes/frombytes and ImageFile.load)
def _getdecoder(mode, decoder_name, args, extra=()): def _getdecoder(mode, decoder_name, args, extra=()):
# tweak arguments # tweak arguments
if args is None: if args is None:
args = () args = ()
elif not isinstance(args, tuple): elif not isinstance(args, tuple):
args = (args,) args = (args, )
try: try:
# get decoder # get decoder
@ -425,7 +415,7 @@ def _getencoder(mode, encoder_name, args, extra=()):
if args is None: if args is None:
args = () args = ()
elif not isinstance(args, tuple): elif not isinstance(args, tuple):
args = (args,) args = (args, )
try: try:
# get encoder # get encoder
@ -435,10 +425,10 @@ def _getencoder(mode, encoder_name, args, extra=()):
except AttributeError: except AttributeError:
raise IOError("encoder %s not available" % encoder_name) raise IOError("encoder %s not available" % encoder_name)
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Simple expression analyzer # Simple expression analyzer
def coerce_e(value): def coerce_e(value):
return value if isinstance(value, _E) else _E(value) return value if isinstance(value, _E) else _E(value)
@ -474,10 +464,10 @@ def _getscaleoffset(expr):
pass pass
raise ValueError("illegal expression") raise ValueError("illegal expression")
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Implementation wrapper # Implementation wrapper
class Image: class Image:
""" """
This class represents an image object. To create This class represents an image object. To create
@ -546,7 +536,7 @@ class Image:
self.fp.close() self.fp.close()
except Exception as msg: except Exception as msg:
if DEBUG: if DEBUG:
print ("Error closing: %s" % msg) print("Error closing: %s" % msg)
# Instead of simply setting to None, we're setting up a # Instead of simply setting to None, we're setting up a
# deferred error that will better explain that the core image # deferred error that will better explain that the core image
@ -563,7 +553,7 @@ class Image:
import tempfile import tempfile
suffix = '' suffix = ''
if format: if format:
suffix = '.'+format suffix = '.' + format
if not file: if not file:
f, file = tempfile.mkstemp(suffix) f, file = tempfile.mkstemp(suffix)
os.close(f) os.close(f)
@ -595,10 +585,8 @@ class Image:
def __repr__(self): def __repr__(self):
return "<%s.%s image mode=%s size=%dx%d at 0x%X>" % ( return "<%s.%s image mode=%s size=%dx%d at 0x%X>" % (
self.__class__.__module__, self.__class__.__name__, self.__class__.__module__, self.__class__.__name__, self.mode,
self.mode, self.size[0], self.size[1], self.size[0], self.size[1], id(self))
id(self)
)
def _repr_png_(self): def _repr_png_(self):
""" iPython display hook support """ iPython display hook support
@ -622,11 +610,7 @@ class Image:
raise AttributeError(name) raise AttributeError(name)
def __getstate__(self): def __getstate__(self):
return [ return [self.info, self.mode, self.size, self.getpalette(),
self.info,
self.mode,
self.size,
self.getpalette(),
self.tobytes()] self.tobytes()]
def __setstate__(self, state): def __setstate__(self, state):
@ -686,8 +670,7 @@ class Image:
warnings.warn( warnings.warn(
'tostring() is deprecated. Please call tobytes() instead.', 'tostring() is deprecated. Please call tobytes() instead.',
DeprecationWarning, DeprecationWarning,
stacklevel=2, stacklevel=2, )
)
return self.tobytes(*args, **kw) return self.tobytes(*args, **kw)
def tobitmap(self, name="image"): def tobitmap(self, name="image"):
@ -705,11 +688,11 @@ class Image:
if self.mode != "1": if self.mode != "1":
raise ValueError("not a bitmap") raise ValueError("not a bitmap")
data = self.tobytes("xbm") data = self.tobytes("xbm")
return b"".join([ return b"".join(
("#define %s_width %d\n" % (name, self.size[0])).encode('ascii'), [("#define %s_width %d\n" % (name, self.size[0])).encode('ascii'),
("#define %s_height %d\n" % (name, self.size[1])).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): def frombytes(self, data, decoder_name="raw", *args):
""" """
@ -792,8 +775,12 @@ class Image:
""" """
pass pass
def convert(self, mode=None, matrix=None, dither=None, def convert(self,
palette=WEB, colors=256): mode=None,
matrix=None,
dither=None,
palette=WEB,
colors=256):
""" """
Returns a converted copy of this image. For the "P" mode, this Returns a converted copy of this image. For the "P" mode, this
method translates pixels through the palette. If mode is method translates pixels through the palette. If mode is
@ -907,16 +894,16 @@ class Image:
if delete_trns: if delete_trns:
# This could possibly happen if we requantize to fewer colors. # This could possibly happen if we requantize to fewer colors.
# The transparency would be totally off in that case. # The transparency would be totally off in that case.
del(new.info['transparency']) del (new.info['transparency'])
if trns is not None: if trns is not None:
try: try:
new.info['transparency'] = new.palette.getcolor(trns) new.info['transparency'] = new.palette.getcolor(trns)
except: except:
# if we can't make a transparent color, don't leave the old # if we can't make a transparent color, don't leave the old
# transparency hanging around to mess us up. # transparency hanging around to mess us up.
del(new.info['transparency']) del (new.info['transparency'])
warnings.warn("Couldn't allocate palette entry " + warnings.warn(
"for transparency") "Couldn't allocate palette entry " + "for transparency")
return new return new
# colorspace conversion # colorspace conversion
@ -936,15 +923,15 @@ class Image:
new_im = self._new(im) new_im = self._new(im)
if delete_trns: if delete_trns:
# crash fail if we leave a bytes transparency in an rgb/l mode. # crash fail if we leave a bytes transparency in an rgb/l mode.
del(new_im.info['transparency']) del (new_im.info['transparency'])
if trns is not None: if trns is not None:
if new_im.mode == 'P': if new_im.mode == 'P':
try: try:
new_im.info['transparency'] = new_im.palette.getcolor(trns) new_im.info['transparency'] = new_im.palette.getcolor(trns)
except: except:
del(new_im.info['transparency']) del (new_im.info['transparency'])
warnings.warn("Couldn't allocate palette entry " + warnings.warn(
"for transparency") "Couldn't allocate palette entry " + "for transparency")
else: else:
new_im.info['transparency'] = trns new_im.info['transparency'] = trns
return new_im return new_im
@ -984,8 +971,7 @@ class Image:
raise ValueError("bad mode for palette image") raise ValueError("bad mode for palette image")
if self.mode != "RGB" and self.mode != "L": if self.mode != "RGB" and self.mode != "L":
raise ValueError( 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) im = self.im.convert("P", 1, palette.im)
return self._makeself(im) return self._makeself(im)
@ -1261,8 +1247,8 @@ class Image:
if warnings: if warnings:
warnings.warn( warnings.warn(
"'offset' is deprecated; use 'ImageChops.offset' instead", "'offset' is deprecated; use 'ImageChops.offset' instead",
DeprecationWarning, stacklevel=2 DeprecationWarning,
) stacklevel=2)
from PIL import ImageChops from PIL import ImageChops
return ImageChops.offset(self, xoffset, yoffset) return ImageChops.offset(self, xoffset, yoffset)
@ -1324,9 +1310,8 @@ class Image:
else: else:
# FIXME: use self.size here? # FIXME: use self.size here?
raise ValueError( 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])
box = box + (box[0]+size[0], box[1]+size[1])
if isStringType(im): if isStringType(im):
from PIL import ImageColor from PIL import ImageColor
@ -1582,14 +1567,12 @@ class Image:
if expand: if expand:
import math import math
angle = -angle * math.pi / 180 angle = -angle * math.pi / 180
matrix = [ matrix = [math.cos(angle), math.sin(angle), 0.0, -math.sin(angle),
math.cos(angle), math.sin(angle), 0.0, math.cos(angle), 0.0]
-math.sin(angle), math.cos(angle), 0.0
]
def transform(x, y, matrix=matrix): def transform(x, y, matrix=matrix):
(a, b, c, d, e, f) = matrix (a, b, c, d, e, f) = matrix
return a*x + b*y + c, d*x + e*y + f return a * x + b * y + c, d * x + e * y + f
# calculate output size # calculate output size
w, h = self.size w, h = self.size
@ -1837,8 +1820,8 @@ class Image:
""" """
if self.mode == 'RGBA': if self.mode == 'RGBA':
return self.convert('RGBa').transform( return self.convert('RGBa').transform(size, method, data, resample,
size, method, data, resample, fill).convert('RGBA') fill).convert('RGBA')
if isinstance(method, ImageTransformHandler): if isinstance(method, ImageTransformHandler):
return method.transform(size, self, resample=resample, fill=fill) return method.transform(size, self, resample=resample, fill=fill)
@ -1854,33 +1837,32 @@ class Image:
for box, quad in data: for box, quad in data:
im.__transformer(box, self, QUAD, quad, resample, fill) im.__transformer(box, self, QUAD, quad, resample, fill)
else: else:
im.__transformer((0, 0)+size, self, method, data, resample, fill) im.__transformer((0, 0) + size, self, method, data, resample, fill)
return im return im
def __transformer(self, box, image, method, data, def __transformer(self, box, image, method, data,
resample=NEAREST, fill=1): resample=NEAREST,
fill=1):
# FIXME: this should be turned into a lazy operation (?) # FIXME: this should be turned into a lazy operation (?)
w = box[2]-box[0] w = box[2] - box[0]
h = box[3]-box[1] h = box[3] - box[1]
if method == AFFINE: if method == AFFINE:
# change argument order to match implementation # change argument order to match implementation
data = (data[2], data[0], data[1], data = (data[2], data[0], data[1], data[5], data[3], data[4])
data[5], data[3], data[4])
elif method == EXTENT: elif method == EXTENT:
# convert extent to an affine transform # convert extent to an affine transform
x0, y0, x1, y1 = data x0, y0, x1, y1 = data
xs = float(x1 - x0) / w xs = float(x1 - x0) / w
ys = float(y1 - y0) / h ys = float(y1 - y0) / h
method = AFFINE method = AFFINE
data = (x0 + xs/2, xs, 0, y0 + ys/2, 0, ys) data = (x0 + xs / 2, xs, 0, y0 + ys / 2, 0, ys)
elif method == PERSPECTIVE: elif method == PERSPECTIVE:
# change argument order to match implementation # change argument order to match implementation
data = (data[2], data[0], data[1], data = (data[2], data[0], data[1], data[5], data[3], data[4],
data[5], data[3], data[4],
data[6], data[7]) data[6], data[7])
elif method == QUAD: elif method == QUAD:
# quadrilateral warp. data specifies the four corners # quadrilateral warp. data specifies the four corners
@ -1892,10 +1874,10 @@ class Image:
x0, y0 = nw x0, y0 = nw
As = 1.0 / w As = 1.0 / w
At = 1.0 / h At = 1.0 / h
data = (x0, (ne[0]-x0)*As, (sw[0]-x0)*At, data = (x0, (ne[0] - x0) * As, (sw[0] - x0) * At,
(se[0]-sw[0]-ne[0]+x0)*As*At, (se[0] - sw[0] - ne[0] + x0) * As * At, y0,
y0, (ne[1]-y0)*As, (sw[1]-y0)*At, (ne[1] - y0) * As, (sw[1] - y0) * At,
(se[1]-sw[1]-ne[1]+y0)*As*At) (se[1] - sw[1] - ne[1] + y0) * As * At)
else: else:
raise ValueError("unknown transformation method") raise ValueError("unknown transformation method")
@ -1935,12 +1917,11 @@ class Image:
im = self.im.effect_spread(distance) im = self.im.effect_spread(distance)
return self._new(im) return self._new(im)
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Lazy operations # Lazy operations
class _ImageCrop(Image):
class _ImageCrop(Image):
def __init__(self, im, box): def __init__(self, im, box):
Image.__init__(self) Image.__init__(self)
@ -1952,7 +1933,7 @@ class _ImageCrop(Image):
y1 = y0 y1 = y0
self.mode = im.mode self.mode = im.mode
self.size = x1-x0, y1-y0 self.size = x1 - x0, y1 - y0
self.__crop = x0, y0, x1, y1 self.__crop = x0, y0, x1, y1
@ -1971,9 +1952,9 @@ class _ImageCrop(Image):
# FIXME: future versions should optimize crop/paste # FIXME: future versions should optimize crop/paste
# sequences! # sequences!
# --------------------------------------------------------------------
# Abstract handlers.
# --------------------------------------------------------------------
# Abstract handlers.
class ImagePointHandler: class ImagePointHandler:
# used as a mixin by point transforms (for use with im.point) # used as a mixin by point transforms (for use with im.point)
@ -1984,13 +1965,13 @@ class ImageTransformHandler:
# used as a mixin by geometry transforms (for use with im.transform) # used as a mixin by geometry transforms (for use with im.transform)
pass pass
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Factories # Factories
# #
# Debugging # Debugging
def _wedge(): def _wedge():
"Create greyscale wedge (for debugging only)" "Create greyscale wedge (for debugging only)"
@ -2070,8 +2051,7 @@ def fromstring(*args, **kw):
warnings.warn( warnings.warn(
'fromstring() is deprecated. Please call frombytes() instead.', 'fromstring() is deprecated. Please call frombytes() instead.',
DeprecationWarning, DeprecationWarning,
stacklevel=2 stacklevel=2)
)
return frombytes(*args, **kw) return frombytes(*args, **kw)
@ -2121,14 +2101,13 @@ def frombuffer(mode, size, data, decoder_name="raw", *args):
"the frombuffer defaults may change in a future release; " "the frombuffer defaults may change in a future release; "
"for portability, change the call to read:\n" "for portability, change the call to read:\n"
" frombuffer(mode, size, data, 'raw', mode, 0, 1)", " 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 args = mode, 0, -1 # may change to (mode, 0, 1) post-1.1.6
if args[0] in _MAPMODES: if args[0] in _MAPMODES:
im = new(mode, (1, 1)) im = new(mode, (1, 1))
im = im._new( 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 im.readonly = 1
return im return im
@ -2184,6 +2163,7 @@ def fromarray(obj, mode=None):
return frombuffer(mode, size, obj, "raw", rawmode, 0, 1) return frombuffer(mode, size, obj, "raw", rawmode, 0, 1)
_fromarray_typemap = { _fromarray_typemap = {
# (shape, typestr) => mode, rawmode # (shape, typestr) => mode, rawmode
# first two members of shape are set to one # first two members of shape are set to one
@ -2200,7 +2180,7 @@ _fromarray_typemap = {
((1, 1), ">f8"): ("F", "F;64BF"), ((1, 1), ">f8"): ("F", "F;64BF"),
((1, 1, 3), "|u1"): ("RGB", "RGB"), ((1, 1, 3), "|u1"): ("RGB", "RGB"),
((1, 1, 4), "|u1"): ("RGBA", "RGBA"), ((1, 1, 4), "|u1"): ("RGBA", "RGBA"),
} }
# shortcuts # shortcuts
_fromarray_typemap[((1, 1), _ENDIAN + "i4")] = ("I", "I") _fromarray_typemap[((1, 1), _ENDIAN + "i4")] = ("I", "I")
@ -2214,11 +2194,9 @@ def _decompression_bomb_check(size):
pixels = size[0] * size[1] pixels = size[0] * size[1]
if pixels > MAX_IMAGE_PIXELS: if pixels > MAX_IMAGE_PIXELS:
warnings.warn( warnings.warn("Image size (%d pixels) exceeds limit of %d pixels, "
"Image size (%d pixels) exceeds limit of %d pixels, "
"could be decompression bomb DOS attack." % "could be decompression bomb DOS attack." %
(pixels, MAX_IMAGE_PIXELS), (pixels, MAX_IMAGE_PIXELS), DecompressionBombWarning)
DecompressionBombWarning)
def open(fp, mode="r"): def open(fp, mode="r"):
@ -2286,13 +2264,13 @@ def open(fp, mode="r"):
# traceback.print_exc() # traceback.print_exc()
pass pass
raise IOError("cannot identify image file %r" raise IOError("cannot identify image file %r" % (filename
% (filename if filename else fp)) if filename else fp))
# #
# Image processing. # Image processing.
def alpha_composite(im1, im2): def alpha_composite(im1, im2):
""" """
Alpha composite im2 over im1. Alpha composite im2 over im1.
@ -2389,10 +2367,10 @@ def merge(mode, bands):
im.putband(bands[i].im, i) im.putband(bands[i].im, i)
return bands[0]._new(im) return bands[0]._new(im)
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Plugin registry # Plugin registry
def register_open(id, factory, accept=None): def register_open(id, factory, accept=None):
""" """
Register an image file plugin. This function should not be used Register an image file plugin. This function should not be used
@ -2440,10 +2418,10 @@ def register_extension(id, extension):
""" """
EXTENSION[extension.lower()] = id.upper() EXTENSION[extension.lower()] = id.upper()
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Simple display support. User code may override this. # Simple display support. User code may override this.
def _show(image, **options): def _show(image, **options):
# override me, as necessary # override me, as necessary
_showxv(image, **options) _showxv(image, **options)
@ -2453,10 +2431,10 @@ def _showxv(image, title=None, **options):
from PIL import ImageShow from PIL import ImageShow
ImageShow.show(image, title, **options) ImageShow.show(image, title, **options)
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Effects # Effects
def effect_mandelbrot(size, extent, quality): def effect_mandelbrot(size, extent, quality):
""" """
Generate a Mandelbrot set covering the given extent. Generate a Mandelbrot set covering the given extent.

View File

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

View File

@ -48,54 +48,31 @@ def getrgb(color):
# check for known string formats # check for known string formats
m = re.match("#\w\w\w$", color) m = re.match("#\w\w\w$", color)
if m: if m:
return ( return (int(color[1] * 2, 16), int(color[2] * 2, 16),
int(color[1]*2, 16), int(color[3] * 2, 16))
int(color[2]*2, 16),
int(color[3]*2, 16)
)
m = re.match("#\w\w\w\w\w\w$", color) m = re.match("#\w\w\w\w\w\w$", color)
if m: if m:
return ( return (int(color[1:3], 16), int(color[3:5], 16), int(color[5:7], 16))
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) m = re.match("rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$", color)
if m: if m:
return ( return (int(m.group(1)), int(m.group(2)), int(m.group(3)))
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) m = re.match("rgb\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)$", color)
if m: if m:
return ( return (int((int(m.group(1)) * 255) / 100.0 + 0.5),
int((int(m.group(1)) * 255) / 100.0 + 0.5),
int((int(m.group(2)) * 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) m = re.match("hsl\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)$", color)
if m: if m:
from colorsys import hls_to_rgb from colorsys import hls_to_rgb
rgb = hls_to_rgb( rgb = hls_to_rgb(float(m.group(1)) / 360.0, float(m.group(3)) / 100.0,
float(m.group(1)) / 360.0, float(m.group(2)) / 100.0, )
float(m.group(3)) / 100.0, return (int(rgb[0] * 255 + 0.5), int(rgb[1] * 255 + 0.5),
float(m.group(2)) / 100.0, int(rgb[2] * 255 + 0.5))
)
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*\)$", m = re.match("rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$",
color) color)
if m: if m:
return ( return (int(m.group(1)), int(m.group(2)), int(m.group(3)),
int(m.group(1)), int(m.group(4)))
int(m.group(2)),
int(m.group(3)),
int(m.group(4))
)
raise ValueError("unknown color specifier: %r" % color) raise ValueError("unknown color specifier: %r" % color)
@ -117,14 +94,15 @@ def getcolor(color, mode):
if Image.getmodebase(mode) == "L": if Image.getmodebase(mode) == "L":
r, g, b = color r, g, b = color
color = (r*299 + g*587 + b*114)//1000 color = (r * 299 + g * 587 + b * 114) // 1000
if mode[-1] == 'A': if mode[-1] == 'A':
return (color, alpha) return (color, alpha)
else: else:
if mode[-1] == 'A': if mode[-1] == 'A':
return color + (alpha,) return color + (alpha, )
return color return color
colormap = { colormap = {
# X11 colour table (from "CSS3 module: Color working draft"), with # X11 colour table (from "CSS3 module: Color working draft"), with
# gray/grey spelling issues fixed. This is a superset of HTML 4.0 # gray/grey spelling issues fixed. This is a superset of HTML 4.0

View File

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

View File

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

View File

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

View File

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

View File

@ -43,7 +43,7 @@ class Kernel(Filter):
def __init__(self, size, kernel, scale=None, offset=0): def __init__(self, size, kernel, scale=None, offset=0):
if scale is None: if scale is None:
# default scale is sum of kernel # default scale is sum of kernel
scale = reduce(lambda a, b: a+b, kernel) scale = reduce(lambda a, b: a + b, kernel)
if size[0] * size[1] != len(kernel): if size[0] * size[1] != len(kernel):
raise ValueError("not enough coefficients in kernel") raise ValueError("not enough coefficients in kernel")
self.filterargs = size, scale, offset, kernel self.filterargs = size, scale, offset, kernel
@ -78,7 +78,7 @@ class RankFilter(Filter):
def filter(self, image): def filter(self, image):
if image.mode == "P": if image.mode == "P":
raise ValueError("cannot filter palette images") raise ValueError("cannot filter palette images")
image = image.expand(self.size//2, self.size//2) image = image.expand(self.size // 2, self.size // 2)
return image.rankfilter(self.size, self.rank) return image.rankfilter(self.size, self.rank)
@ -93,7 +93,7 @@ class MedianFilter(RankFilter):
def __init__(self, size=3): def __init__(self, size=3):
self.size = size self.size = size
self.rank = size*size//2 self.rank = size * size // 2
class MinFilter(RankFilter): class MinFilter(RankFilter):
@ -121,7 +121,7 @@ class MaxFilter(RankFilter):
def __init__(self, size=3): def __init__(self, size=3):
self.size = size self.size = size
self.rank = size*size-1 self.rank = size * size - 1
class ModeFilter(Filter): class ModeFilter(Filter):
@ -183,93 +183,51 @@ class UnsharpMask(Filter):
class BLUR(BuiltinFilter): class BLUR(BuiltinFilter):
name = "Blur" name = "Blur"
filterargs = (5, 5), 16, 0, ( filterargs = (5, 5), 16, 0, (1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 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): class CONTOUR(BuiltinFilter):
name = "Contour" name = "Contour"
filterargs = (3, 3), 1, 255, ( filterargs = (3, 3), 1, 255, (-1, -1, -1, -1, 8, -1, -1, -1, -1)
-1, -1, -1,
-1, 8, -1,
-1, -1, -1
)
class DETAIL(BuiltinFilter): class DETAIL(BuiltinFilter):
name = "Detail" name = "Detail"
filterargs = (3, 3), 6, 0, ( filterargs = (3, 3), 6, 0, (0, -1, 0, -1, 10, -1, 0, -1, 0)
0, -1, 0,
-1, 10, -1,
0, -1, 0
)
class EDGE_ENHANCE(BuiltinFilter): class EDGE_ENHANCE(BuiltinFilter):
name = "Edge-enhance" name = "Edge-enhance"
filterargs = (3, 3), 2, 0, ( filterargs = (3, 3), 2, 0, (-1, -1, -1, -1, 10, -1, -1, -1, -1)
-1, -1, -1,
-1, 10, -1,
-1, -1, -1
)
class EDGE_ENHANCE_MORE(BuiltinFilter): class EDGE_ENHANCE_MORE(BuiltinFilter):
name = "Edge-enhance More" name = "Edge-enhance More"
filterargs = (3, 3), 1, 0, ( filterargs = (3, 3), 1, 0, (-1, -1, -1, -1, 9, -1, -1, -1, -1)
-1, -1, -1,
-1, 9, -1,
-1, -1, -1
)
class EMBOSS(BuiltinFilter): class EMBOSS(BuiltinFilter):
name = "Emboss" name = "Emboss"
filterargs = (3, 3), 1, 128, ( filterargs = (3, 3), 1, 128, (-1, 0, 0, 0, 1, 0, 0, 0, 0)
-1, 0, 0,
0, 1, 0,
0, 0, 0
)
class FIND_EDGES(BuiltinFilter): class FIND_EDGES(BuiltinFilter):
name = "Find Edges" name = "Find Edges"
filterargs = (3, 3), 1, 0, ( filterargs = (3, 3), 1, 0, (-1, -1, -1, -1, 8, -1, -1, -1, -1)
-1, -1, -1,
-1, 8, -1,
-1, -1, -1
)
class SMOOTH(BuiltinFilter): class SMOOTH(BuiltinFilter):
name = "Smooth" name = "Smooth"
filterargs = (3, 3), 13, 0, ( filterargs = (3, 3), 13, 0, (1, 1, 1, 1, 5, 1, 1, 1, 1)
1, 1, 1,
1, 5, 1,
1, 1, 1
)
class SMOOTH_MORE(BuiltinFilter): class SMOOTH_MORE(BuiltinFilter):
name = "Smooth More" name = "Smooth More"
filterargs = (5, 5), 100, 0, ( filterargs = (5, 5), 100, 0, (1, 1, 1, 1, 1, 1, 5, 5, 5, 1, 1, 5, 44, 5, 1,
1, 1, 1, 1, 1, 1, 5, 5, 5, 1, 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): class SHARPEN(BuiltinFilter):
name = "Sharpen" name = "Sharpen"
filterargs = (3, 3), 16, 0, ( filterargs = (3, 3), 16, 0, (-2, -2, -2, -2, 32, -2, -2, -2, -2)
-2, -2, -2,
-2, 32, -2,
-2, -2, -2
)

View File

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

View File

@ -32,11 +32,9 @@ except AttributeError:
def grab(bbox=None): def grab(bbox=None):
size, data = grabber() size, data = grabber()
im = Image.frombytes( im = Image.frombytes("RGB", size, data,
"RGB", size, data,
# RGB, 32-bit line padding, origo in lower left corner # 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: if bbox:
im = im.crop(bbox) im = im.crop(bbox)
return im return im

View File

@ -61,7 +61,7 @@ class _Operand:
out = Image.new(mode or im1.mode, im1.size, None) out = Image.new(mode or im1.mode, im1.size, None)
im1.load() im1.load()
try: try:
op = getattr(_imagingmath, op+"_"+im1.mode) op = getattr(_imagingmath, op + "_" + im1.mode)
except AttributeError: except AttributeError:
raise TypeError("bad operand type for '%s'" % op) raise TypeError("bad operand type for '%s'" % op)
_imagingmath.unop(op, out.im.id, im1.im.id) _imagingmath.unop(op, out.im.id, im1.im.id)
@ -90,7 +90,7 @@ class _Operand:
im1.load() im1.load()
im2.load() im2.load()
try: try:
op = getattr(_imagingmath, op+"_"+im1.mode) op = getattr(_imagingmath, op + "_" + im1.mode)
except AttributeError: except AttributeError:
raise TypeError("bad operand type for '%s'" % op) raise TypeError("bad operand type for '%s'" % op)
_imagingmath.binop(op, out.im.id, im1.im.id, im2.im.id) _imagingmath.binop(op, out.im.id, im1.im.id, im2.im.id)
@ -236,6 +236,7 @@ def imagemath_max(self, other):
def imagemath_convert(self, mode): def imagemath_convert(self, mode):
return _Operand(self.im.convert(mode)) return _Operand(self.im.convert(mode))
ops = {} ops = {}
for k, v in list(globals().items()): for k, v in list(globals().items()):
if k[:10] == "imagemath_": if k[:10] == "imagemath_":

View File

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

View File

@ -47,6 +47,7 @@ class LutBuilder:
lut = lb.build_lut() lut = lb.build_lut()
""" """
def __init__(self, patterns=None, op_name=None): def __init__(self, patterns=None, op_name=None):
if patterns is not None: if patterns is not None:
self.patterns = patterns self.patterns = patterns
@ -55,20 +56,16 @@ class LutBuilder:
self.lut = None self.lut = None
if op_name is not None: if op_name is not None:
known_patterns = { known_patterns = {
'corner': ['1:(... ... ...)->0', 'corner': ['1:(... ... ...)->0', '4:(00. 01. ...)->1'],
'4:(00. 01. ...)->1'],
'dilation4': ['4:(... .0. .1.)->1'], 'dilation4': ['4:(... .0. .1.)->1'],
'dilation8': ['4:(... .0. .1.)->1', 'dilation8': ['4:(... .0. .1.)->1', '4:(... .0. ..1)->1'],
'4:(... .0. ..1)->1'],
'erosion4': ['4:(... .1. .0.)->0'], 'erosion4': ['4:(... .1. .0.)->0'],
'erosion8': ['4:(... .1. .0.)->0', 'erosion8': ['4:(... .1. .0.)->0', '4:(... .1. ..0)->0'],
'4:(... .1. ..0)->0'], 'edge': ['1:(... ... ...)->0', '4:(.0. .1. ...)->1',
'edge': ['1:(... ... ...)->0',
'4:(.0. .1. ...)->1',
'4:(01. .1. ...)->1'] '4:(01. .1. ...)->1']
} }
if op_name not in known_patterns: if op_name not in known_patterns:
raise Exception('Unknown pattern '+op_name+'!') raise Exception('Unknown pattern ' + op_name + '!')
self.patterns = known_patterns[op_name] self.patterns = known_patterns[op_name]
@ -87,7 +84,7 @@ class LutBuilder:
"""string_permute takes a pattern and a permutation and returns the """string_permute takes a pattern and a permutation and returns the
string permuted according to the permutation list. string permuted according to the permutation list.
""" """
assert(len(permutation) == 9) assert (len(permutation) == 9)
return ''.join([pattern[p] for p in permutation]) return ''.join([pattern[p] for p in permutation])
def _pattern_permute(self, basic_pattern, options, basic_result): def _pattern_permute(self, basic_pattern, options, basic_result):
@ -100,29 +97,25 @@ class LutBuilder:
if '4' in options: if '4' in options:
res = patterns[-1][1] res = patterns[-1][1]
for i in range(4): for i in range(4):
patterns.append( patterns.append((self._string_permute(patterns[-1][0],
(self._string_permute(patterns[-1][0], [6, 3, 0, [6, 3, 0, 7, 4, 1, 8, 5,
7, 4, 1, 2]), res))
8, 5, 2]), res))
# mirror # mirror
if 'M' in options: if 'M' in options:
n = len(patterns) n = len(patterns)
for pattern, res in patterns[0:n]: for pattern, res in patterns[0:n]:
patterns.append( patterns.append((self._string_permute(pattern, [2, 1, 0, 5, 4,
(self._string_permute(pattern, [2, 1, 0, 3, 8, 7, 6]),
5, 4, 3, res))
8, 7, 6]), res))
# negate # negate
if 'N' in options: if 'N' in options:
n = len(patterns) n = len(patterns)
for pattern, res in patterns[0:n]: for pattern, res in patterns[0:n]:
# Swap 0 and 1 # Swap 0 and 1
pattern = (pattern pattern = (pattern.replace('0', 'Z').replace('1', '0').replace(
.replace('0', 'Z') 'Z', '1'))
.replace('1', '0') res = '%d' % (1 - int(res))
.replace('Z', '1'))
res = '%d' % (1-int(res))
patterns.append((pattern, res)) patterns.append((pattern, res))
return patterns return patterns
@ -137,10 +130,10 @@ class LutBuilder:
# Parse and create symmetries of the patterns strings # Parse and create symmetries of the patterns strings
for p in self.patterns: for p in self.patterns:
m = re.search( m = re.search(r'(\w*):?\s*\((.+?)\)\s*->\s*(\d)',
r'(\w*):?\s*\((.+?)\)\s*->\s*(\d)', p.replace('\n', '')) p.replace('\n', ''))
if not m: if not m:
raise Exception('Syntax error in pattern "'+p+'"') raise Exception('Syntax error in pattern "' + p + '"')
options = m.group(1) options = m.group(1)
pattern = m.group(2) pattern = m.group(2)
result = int(m.group(3)) result = int(m.group(3))
@ -155,7 +148,7 @@ class LutBuilder:
# print p,r # print p,r
# print '--' # print '--'
# compile the patterns into regular expressions for speed # compile the patterns into regular expressions for speed
for i in range(len(patterns)): for i in range(len(patterns)):
p = patterns[i][0].replace('.', 'X').replace('X', '[01]') p = patterns[i][0].replace('.', 'X').replace('X', '[01]')
p = re.compile(p) p = re.compile(p)
@ -167,7 +160,7 @@ class LutBuilder:
for i in range(LUT_SIZE): for i in range(LUT_SIZE):
# Build the bit pattern # Build the bit pattern
bitpattern = bin(i)[2:] bitpattern = bin(i)[2:]
bitpattern = ('0'*(9-len(bitpattern)) + bitpattern)[::-1] bitpattern = ('0' * (9 - len(bitpattern)) + bitpattern)[::-1]
for p, r in patterns: for p, r in patterns:
if p.match(bitpattern): if p.match(bitpattern):
@ -179,10 +172,7 @@ class LutBuilder:
class MorphOp: class MorphOp:
"""A class for binary morphological operators""" """A class for binary morphological operators"""
def __init__(self, def __init__(self, lut=None, op_name=None, patterns=None):
lut=None,
op_name=None,
patterns=None):
"""Create a binary morphological operator""" """Create a binary morphological operator"""
self.lut = lut self.lut = lut
if op_name is not None: if op_name is not None:
@ -199,8 +189,8 @@ class MorphOp:
raise Exception('No operator loaded') raise Exception('No operator loaded')
outimage = Image.new(image.mode, image.size, None) outimage = Image.new(image.mode, image.size, None)
count = _imagingmorph.apply( count = _imagingmorph.apply(bytes(self.lut), image.im.id,
bytes(self.lut), image.im.id, outimage.im.id) outimage.im.id)
return count, outimage return count, outimage
def match(self, image): def match(self, image):

View File

@ -22,10 +22,10 @@ from PIL._util import isStringType
import operator import operator
from functools import reduce from functools import reduce
# #
# helpers # helpers
def _border(border): def _border(border):
if isinstance(border, tuple): if isinstance(border, tuple):
if len(border) == 2: if len(border) == 2:
@ -75,7 +75,7 @@ def autocontrast(image, cutoff=0, ignore=None):
histogram = image.histogram() histogram = image.histogram()
lut = [] lut = []
for layer in range(0, len(histogram), 256): for layer in range(0, len(histogram), 256):
h = histogram[layer:layer+256] h = histogram[layer:layer + 256]
if ignore is not None: if ignore is not None:
# get rid of outliers # get rid of outliers
try: try:
@ -154,9 +154,9 @@ def colorize(image, black, white):
green = [] green = []
blue = [] blue = []
for i in range(256): for i in range(256):
red.append(black[0]+i*(white[0]-black[0])//255) red.append(black[0] + i * (white[0] - black[0]) // 255)
green.append(black[1]+i*(white[1]-black[1])//255) green.append(black[1] + i * (white[1] - black[1]) // 255)
blue.append(black[2]+i*(white[2]-black[2])//255) blue.append(black[2] + i * (white[2] - black[2]) // 255)
image = image.convert("RGB") image = image.convert("RGB")
return _lut(image, red + green + blue) return _lut(image, red + green + blue)
@ -174,8 +174,7 @@ def crop(image, border=0):
""" """
left, top, right, bottom = _border(border) left, top, right, bottom = _border(border)
return image.crop( 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): 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. :param resample: What resampling filter to use.
:return: An image. :return: An image.
""" """
return image.transform( return image.transform(image.size, Image.MESH, deformer.getmesh(image),
image.size, Image.MESH, deformer.getmesh(image), resample resample)
)
def equalize(image, mask=None): def equalize(image, mask=None):
@ -209,7 +207,7 @@ def equalize(image, mask=None):
h = image.histogram(mask) h = image.histogram(mask)
lut = [] lut = []
for b in range(0, len(h), 256): for b in range(0, len(h), 256):
histo = [_f for _f in h[b:b+256] if _f] histo = [_f for _f in h[b:b + 256] if _f]
if len(histo) <= 1: if len(histo) <= 1:
lut.extend(list(range(256))) lut.extend(list(range(256)))
else: else:
@ -220,7 +218,7 @@ def equalize(image, mask=None):
n = step // 2 n = step // 2
for i in range(256): for i in range(256):
lut.append(n // step) lut.append(n // step)
n = n + h[i+b] n = n + h[i + b]
return _lut(image, lut) return _lut(image, lut)
@ -289,22 +287,19 @@ def fit(image, size, method=Image.NEAREST, bleed=0.0, centering=(0.5, 0.5)):
# the 'bleed' around the edges # the 'bleed' around the edges
# number of pixels to trim off on Top and Bottom, Left and Right # number of pixels to trim off on Top and Bottom, Left and Right
bleedPixels = ( bleedPixels = (int((float(bleed) * float(image.size[0])) + 0.5),
int((float(bleed) * float(image.size[0])) + 0.5), int((float(bleed) * float(image.size[1])) + 0.5))
int((float(bleed) * float(image.size[1])) + 0.5)
)
liveArea = (0, 0, image.size[0], image.size[1]) liveArea = (0, 0, image.size[0], image.size[1])
if bleed > 0.0: if bleed > 0.0:
liveArea = ( liveArea = (bleedPixels[0], bleedPixels[1],
bleedPixels[0], bleedPixels[1], image.size[0] - bleedPixels[0] - 1, image.size[0] - bleedPixels[0] - 1,
image.size[1] - bleedPixels[1] - 1 image.size[1] - bleedPixels[1] - 1)
)
liveSize = (liveArea[2] - liveArea[0], liveArea[3] - liveArea[1]) liveSize = (liveArea[2] - liveArea[0], liveArea[3] - liveArea[1])
# calculate the aspect ratio of the liveArea # calculate the aspect ratio of the liveArea
liveAreaAspectRatio = float(liveSize[0])/float(liveSize[1]) liveAreaAspectRatio = float(liveSize[0]) / float(liveSize[1])
# calculate the aspect ratio of the output image # calculate the aspect ratio of the output image
aspectRatio = float(size[0]) / float(size[1]) aspectRatio = float(size[0]) / float(size[1])
@ -317,19 +312,20 @@ def fit(image, size, method=Image.NEAREST, bleed=0.0, centering=(0.5, 0.5)):
else: else:
# liveArea is taller than what's needed, crop the top and bottom # liveArea is taller than what's needed, crop the top and bottom
cropWidth = liveSize[0] cropWidth = liveSize[0]
cropHeight = int((float(liveSize[0])/aspectRatio) + 0.5) cropHeight = int((float(liveSize[0]) / aspectRatio) + 0.5)
# make the crop # 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: if leftSide < 0:
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: if topSide < 0:
topSide = 0 topSide = 0
out = image.crop( out = image.crop(
(leftSide, topSide, leftSide + cropWidth, topSide + cropHeight) (leftSide, topSide, leftSide + cropWidth, topSide + cropHeight))
)
# resize the image and return it # resize the image and return it
return out.resize(size, method) return out.resize(size, method)
@ -364,7 +360,7 @@ def invert(image):
""" """
lut = [] lut = []
for i in range(256): for i in range(256):
lut.append(255-i) lut.append(255 - i)
return _lut(image, lut) return _lut(image, lut)
@ -387,7 +383,7 @@ def posterize(image, bits):
:return: An image. :return: An image.
""" """
lut = [] lut = []
mask = ~(2**(8-bits)-1) mask = ~(2 ** (8 - bits) - 1)
for i in range(256): for i in range(256):
lut.append(i & mask) lut.append(i & mask)
return _lut(image, lut) return _lut(image, lut)
@ -406,13 +402,13 @@ def solarize(image, threshold=128):
if i < threshold: if i < threshold:
lut.append(i) lut.append(i)
else: else:
lut.append(255-i) lut.append(255 - i)
return _lut(image, lut) return _lut(image, lut)
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# PIL USM components, from Kevin Cazabon. # PIL USM components, from Kevin Cazabon.
def gaussian_blur(im, radius=None): def gaussian_blur(im, radius=None):
""" PIL_usm.gblur(im, [radius])""" """ PIL_usm.gblur(im, [radius])"""
@ -423,6 +419,7 @@ def gaussian_blur(im, radius=None):
return im.im.gaussian_blur(radius) return im.im.gaussian_blur(radius)
gblur = gaussian_blur 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) return im.im.unsharp_mask(radius, percent, threshold)
usm = unsharp_mask usm = unsharp_mask

View File

@ -27,10 +27,10 @@ class ImagePalette:
def __init__(self, mode="RGB", palette=None, size=0): def __init__(self, mode="RGB", palette=None, size=0):
self.mode = mode self.mode = mode
self.rawmode = None # if set, palette contains raw data self.rawmode = None # if set, palette contains raw data
self.palette = palette or list(range(256))*len(self.mode) self.palette = palette or list(range(256)) * len(self.mode)
self.colors = {} self.colors = {}
self.dirty = None self.dirty = None
if ((size == 0 and len(self.mode)*256 != len(self.palette)) or if ((size == 0 and len(self.mode) * 256 != len(self.palette)) or
(size != 0 and size != len(self.palette))): (size != 0 and size != len(self.palette))):
raise ValueError("wrong palette size") raise ValueError("wrong palette size")
@ -82,8 +82,8 @@ class ImagePalette:
raise ValueError("cannot allocate more than 256 colors") raise ValueError("cannot allocate more than 256 colors")
self.colors[color] = index self.colors[color] = index
self.palette[index] = color[0] self.palette[index] = color[0]
self.palette[index+256] = color[1] self.palette[index + 256] = color[1]
self.palette[index+512] = color[2] self.palette[index + 512] = color[2]
self.dirty = 1 self.dirty = 1
return index return index
else: else:
@ -102,7 +102,7 @@ class ImagePalette:
fp.write("# Mode: %s\n" % self.mode) fp.write("# Mode: %s\n" % self.mode)
for i in range(256): for i in range(256):
fp.write("%d" % i) fp.write("%d" % i)
for j in range(i*len(self.mode), (i+1)*len(self.mode)): for j in range(i * len(self.mode), (i + 1) * len(self.mode)):
try: try:
fp.write(" %d" % self.palette[j]) fp.write(" %d" % self.palette[j])
except IndexError: except IndexError:
@ -110,10 +110,10 @@ class ImagePalette:
fp.write("\n") fp.write("\n")
fp.close() fp.close()
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Internal # Internal
def raw(rawmode, data): def raw(rawmode, data):
palette = ImagePalette() palette = ImagePalette()
palette.rawmode = rawmode palette.rawmode = rawmode
@ -121,27 +121,21 @@ def raw(rawmode, data):
palette.dirty = 1 palette.dirty = 1
return palette return palette
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Factories # Factories
def _make_linear_lut(black, white): def _make_linear_lut(black, white):
warnings.warn( warnings.warn('_make_linear_lut() is deprecated. '
'_make_linear_lut() is deprecated. ' 'Please call make_linear_lut() instead.', DeprecationWarning,
'Please call make_linear_lut() instead.', stacklevel=2)
DeprecationWarning,
stacklevel=2
)
return make_linear_lut(black, white) return make_linear_lut(black, white)
def _make_gamma_lut(exp): def _make_gamma_lut(exp):
warnings.warn( warnings.warn('_make_gamma_lut() is deprecated. '
'_make_gamma_lut() is deprecated. ' 'Please call make_gamma_lut() instead.', DeprecationWarning,
'Please call make_gamma_lut() instead.', stacklevel=2)
DeprecationWarning,
stacklevel=2
)
return make_gamma_lut(exp) return make_gamma_lut(exp)
@ -149,7 +143,7 @@ def make_linear_lut(black, white):
lut = [] lut = []
if black == 0: if black == 0:
for i in range(256): for i in range(256):
lut.append(white*i//255) lut.append(white * i // 255)
else: else:
raise NotImplementedError # FIXME raise NotImplementedError # FIXME
return lut return lut
@ -171,7 +165,7 @@ def negative(mode="RGB"):
def random(mode="RGB"): def random(mode="RGB"):
from random import randint from random import randint
palette = [] palette = []
for i in range(256*len(mode)): for i in range(256 * len(mode)):
palette.append(randint(0, 255)) palette.append(randint(0, 255))
return ImagePalette(mode, palette) return ImagePalette(mode, palette)

View File

@ -16,12 +16,10 @@
from PIL import Image from PIL import Image
# the Python class below is overridden by the C implementation. # the Python class below is overridden by the C implementation.
class Path: class Path:
def __init__(self, xy): def __init__(self, xy):
pass pass
@ -61,6 +59,5 @@ class Path:
def transform(self, matrix): def transform(self, matrix):
pass pass
# override with C implementation # override with C implementation
Path = Image.core.path 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. # (Internal) Turns an RGB color into a Qt compatible color integer.
def rgb(r, g, b, a=255): def rgb(r, g, b, a=255):
# use qRgb to pack the colors, and then turn the resulting long # use qRgb to pack the colors, and then turn the resulting long
# into a negative integer with the same bitpattern. # into a negative integer with the same bitpattern.
return (qRgba(r, g, b, a) & 0xffffffff) return (qRgba(r, g, b, a) & 0xffffffff)
## ##
# An PIL image wrapper for Qt. This is a subclass of PyQt4's QImage # An PIL image wrapper for Qt. This is a subclass of PyQt4's QImage
# class. # 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 # @param im A PIL Image object, or a file name (given either as Python
# string or a PyQt string object). # string or a PyQt string object).
class ImageQt(QImage):
class ImageQt(QImage):
def __init__(self, im): def __init__(self, im):
data = None data = None
@ -74,7 +74,7 @@ class ImageQt(QImage):
colortable = [] colortable = []
palette = im.getpalette() palette = im.getpalette()
for i in range(0, len(palette), 3): for i in range(0, len(palette), 3):
colortable.append(rgb(*palette[i:i+3])) colortable.append(rgb(*palette[i:i + 3]))
elif im.mode == "RGB": elif im.mode == "RGB":
data = im.tobytes("raw", "BGRX") data = im.tobytes("raw", "BGRX")
format = QImage.Format_RGB32 format = QImage.Format_RGB32

View File

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

View File

@ -27,7 +27,6 @@ from functools import reduce
class Stat: class Stat:
def __init__(self, image_or_list, mask=None): def __init__(self, image_or_list, mask=None):
try: try:
if mask: if mask:
@ -71,7 +70,7 @@ class Stat:
v = [] v = []
for i in range(0, len(self.h), 256): for i in range(0, len(self.h), 256):
v.append(reduce(operator.add, self.h[i:i+256])) v.append(reduce(operator.add, self.h[i:i + 256]))
return v return v
def _getsum(self): def _getsum(self):
@ -110,10 +109,10 @@ class Stat:
v = [] v = []
for i in self.bands: for i in self.bands:
s = 0 s = 0
l = self.count[i]//2 l = self.count[i] // 2
b = i * 256 b = i * 256
for j in range(256): for j in range(256):
s = s + self.h[b+j] s = s + self.h[b + j]
if s > l: if s > l:
break break
v.append(j) v.append(j)
@ -133,7 +132,7 @@ class Stat:
v = [] v = []
for i in self.bands: for i in self.bands:
n = self.count[i] n = self.count[i]
v.append((self.sum2[i]-(self.sum[i]**2.0)/n)/n) v.append((self.sum2[i] - (self.sum[i] ** 2.0) / n) / n)
return v return v
def _getstddev(self): def _getstddev(self):
@ -144,4 +143,5 @@ class Stat:
v.append(math.sqrt(self.var[i])) v.append(math.sqrt(self.var[i]))
return v return v
Global = Stat # compatibility Global = Stat # compatibility

View File

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

View File

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

View File

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

View File

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

View File

@ -19,7 +19,6 @@ from __future__ import print_function
__version__ = "0.3" __version__ = "0.3"
from PIL import Image, ImageFile, _binary from PIL import Image, ImageFile, _binary
import os import os
import tempfile import tempfile
@ -29,17 +28,14 @@ i16 = _binary.i16be
i32 = _binary.i32be i32 = _binary.i32be
o8 = _binary.o8 o8 = _binary.o8
COMPRESSION = { COMPRESSION = {1: "raw", 5: "jpeg"}
1: "raw",
5: "jpeg"
}
PAD = o8(0) * 4 PAD = o8(0) * 4
# #
# Helpers # Helpers
def i(c): def i(c):
return i32((PAD + c)[-4:]) return i32((PAD + c)[-4:])
@ -49,11 +45,11 @@ def dump(c):
print("%02x" % i8(i), end=' ') print("%02x" % i8(i), end=' ')
print() print()
## ##
# Image plugin for IPTC/NAA datastreams. To read IPTC/NAA fields # Image plugin for IPTC/NAA datastreams. To read IPTC/NAA fields
# from TIFF and JPEG files, use the <b>getiptcinfo</b> function. # from TIFF and JPEG files, use the <b>getiptcinfo</b> function.
class IptcImageFile(ImageFile.ImageFile): class IptcImageFile(ImageFile.ImageFile):
format = "IPTC" format = "IPTC"
@ -82,7 +78,7 @@ class IptcImageFile(ImageFile.ImageFile):
elif size == 128: elif size == 128:
size = 0 size = 0
elif size > 128: elif size > 128:
size = i(self.fp.read(size-128)) size = i(self.fp.read(size - 128))
else: else:
size = i16(s[3:]) size = i16(s[3:])
@ -114,15 +110,15 @@ class IptcImageFile(ImageFile.ImageFile):
layers = i8(self.info[(3, 60)][0]) layers = i8(self.info[(3, 60)][0])
component = i8(self.info[(3, 60)][1]) component = i8(self.info[(3, 60)][1])
if (3, 65) in self.info: if (3, 65) in self.info:
id = i8(self.info[(3, 65)][0])-1 id = i8(self.info[(3, 65)][0]) - 1
else: else:
id = 0 id = 0
if layers == 1 and not component: if layers == 1 and not component:
self.mode = "L" self.mode = "L"
elif layers == 3 and component: elif layers == 3 and component:
self.mode = "RGB"[id] self.mode = "RGB" [id]
elif layers == 4 and component: elif layers == 4 and component:
self.mode = "CMYK"[id] self.mode = "CMYK" [id]
# size # size
self.size = self.getint((3, 20)), self.getint((3, 30)) self.size = self.getint((3, 20)), self.getint((3, 30))
@ -188,7 +184,6 @@ Image.register_open("IPTC", IptcImageFile)
Image.register_extension("IPTC", ".iim") Image.register_extension("IPTC", ".iim")
## ##
# Get IPTC information from TIFF, JPEG, or IPTC file. # 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 # @return A dictionary containing IPTC information, or None if
# no IPTC information block was found. # no IPTC information block was found.
def getiptcinfo(im): def getiptcinfo(im):
from PIL import TiffImagePlugin, JpegImagePlugin from PIL import TiffImagePlugin, JpegImagePlugin
@ -215,14 +211,14 @@ def getiptcinfo(im):
app = app[14:] app = app[14:]
# parse the image resource block # parse the image resource block
offset = 0 offset = 0
while app[offset:offset+4] == b"8BIM": while app[offset:offset + 4] == b"8BIM":
offset += 4 offset += 4
# resource code # resource code
code = JpegImagePlugin.i16(app, offset) code = JpegImagePlugin.i16(app, offset)
offset += 2 offset += 2
# resource name (usually empty) # resource name (usually empty)
name_len = i8(app[offset]) name_len = i8(app[offset])
name = app[offset+1:offset+1+name_len] name = app[offset + 1:offset + 1 + name_len]
offset = 1 + offset + name_len offset = 1 + offset + name_len
if offset & 1: if offset & 1:
offset += 1 offset += 1
@ -231,7 +227,7 @@ def getiptcinfo(im):
offset += 4 offset += 4
if code == 0x0404: if code == 0x0404:
# 0x0404 contains IPTC/NAA data # 0x0404 contains IPTC/NAA data
data = app[offset:offset+size] data = app[offset:offset + size]
break break
offset = offset + size offset = offset + size
if offset & 1: if offset & 1:
@ -253,6 +249,7 @@ def getiptcinfo(im):
# create an IptcImagePlugin object without initializing it # create an IptcImagePlugin object without initializing it
class FakeImage: class FakeImage:
pass pass
im = FakeImage() im = FakeImage()
im.__class__ = IptcImageFile im.__class__ = IptcImageFile

View File

@ -30,9 +30,9 @@ def _parse_codestream(fp):
lsiz, rsiz, xsiz, ysiz, xosiz, yosiz, xtsiz, ytsiz, \ lsiz, rsiz, xsiz, ysiz, xosiz, yosiz, xtsiz, ytsiz, \
xtosiz, ytosiz, csiz \ xtosiz, ytosiz, csiz \
= struct.unpack('>HHIIIIIIIIH', siz[:38]) = struct.unpack('>HHIIIIIIIIH', siz[:38])
ssiz = [None]*csiz ssiz = [None] * csiz
xrsiz = [None]*csiz xrsiz = [None] * csiz
yrsiz = [None]*csiz yrsiz = [None] * csiz
for i in range(csiz): for i in range(csiz):
ssiz[i], xrsiz[i], yrsiz[i] \ ssiz[i], xrsiz[i], yrsiz[i] \
= struct.unpack('>BBB', siz[36 + 3 * i:39 + 3 * i]) = struct.unpack('>BBB', siz[36 + 3 * i:39 + 3 * i])
@ -210,10 +210,10 @@ def _accept(prefix):
return (prefix[:4] == b'\xff\x4f\xff\x51' or return (prefix[:4] == b'\xff\x4f\xff\x51' or
prefix[:12] == b'\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a') prefix[:12] == b'\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a')
# ------------------------------------------------------------ # ------------------------------------------------------------
# Save support # Save support
def _save(im, fp, filename): def _save(im, fp, filename):
if filename.endswith('.j2k'): if filename.endswith('.j2k'):
kind = 'j2k' kind = 'j2k'
@ -242,22 +242,12 @@ def _save(im, fp, filename):
except: except:
fd = -1 fd = -1
im.encoderconfig = ( im.encoderconfig = (offset, tile_offset, tile_size, quality_mode,
offset, quality_layers, num_resolutions, cblk_size,
tile_offset, precinct_size, irreversible, progression, cinema_mode,
tile_size, fd)
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)]) ImageFile._save(im, fp, [('jpeg2k', (0, 0) + im.size, 0, kind)])
# ------------------------------------------------------------ # ------------------------------------------------------------
# Registry stuff # Registry stuff

View File

@ -47,12 +47,12 @@ o8 = _binary.o8
i16 = _binary.i16be i16 = _binary.i16be
i32 = _binary.i32be i32 = _binary.i32be
# #
# Parser # Parser
def Skip(self, marker): def Skip(self, marker):
n = i16(self.fp.read(2))-2 n = i16(self.fp.read(2)) - 2
ImageFile._safe_read(self.fp, n) ImageFile._safe_read(self.fp, n)
@ -61,7 +61,7 @@ def APP(self, marker):
# Application marker. Store these in the APP dictionary. # Application marker. Store these in the APP dictionary.
# Also look for well-known application markers. # Also look for well-known application markers.
n = i16(self.fp.read(2))-2 n = i16(self.fp.read(2)) - 2
s = ImageFile._safe_read(self.fp, n) s = ImageFile._safe_read(self.fp, n)
app = "APP%d" % (marker & 15) app = "APP%d" % (marker & 15)
@ -123,7 +123,7 @@ def APP(self, marker):
def COM(self, marker): def COM(self, marker):
# #
# Comment marker. Store these in the APP dictionary. # Comment marker. Store these in the APP dictionary.
n = i16(self.fp.read(2))-2 n = i16(self.fp.read(2)) - 2
s = ImageFile._safe_read(self.fp, n) s = ImageFile._safe_read(self.fp, n)
self.app["COM"] = s # compatibility self.app["COM"] = s # compatibility
@ -138,7 +138,7 @@ def SOF(self, marker):
# mode. Note that this could be made a bit brighter, by # mode. Note that this could be made a bit brighter, by
# looking for JFIF and Adobe APP markers. # looking for JFIF and Adobe APP markers.
n = i16(self.fp.read(2))-2 n = i16(self.fp.read(2)) - 2
s = ImageFile._safe_read(self.fp, n) s = ImageFile._safe_read(self.fp, n)
self.size = i16(s[3:]), i16(s[1:]) self.size = i16(s[3:]), i16(s[1:])
@ -173,9 +173,9 @@ def SOF(self, marker):
self.icclist = None self.icclist = None
for i in range(6, len(s), 3): for i in range(6, len(s), 3):
t = s[i:i+3] t = s[i:i + 3]
# 4-tuples: id, vsamp, hsamp, qtable # 4-tuples: id, vsamp, hsamp, qtable
self.layer.append((t[0], i8(t[1])//16, i8(t[1]) & 15, i8(t[2]))) self.layer.append((t[0], i8(t[1]) // 16, i8(t[1]) & 15, i8(t[2])))
def DQT(self, marker): def DQT(self, marker):
@ -187,22 +187,22 @@ def DQT(self, marker):
# FIXME: The quantization tables can be used to estimate the # FIXME: The quantization tables can be used to estimate the
# compression quality. # compression quality.
n = i16(self.fp.read(2))-2 n = i16(self.fp.read(2)) - 2
s = ImageFile._safe_read(self.fp, n) s = ImageFile._safe_read(self.fp, n)
while len(s): while len(s):
if len(s) < 65: if len(s) < 65:
raise SyntaxError("bad quantization table marker") raise SyntaxError("bad quantization table marker")
v = i8(s[0]) v = i8(s[0])
if v//16 == 0: if v // 16 == 0:
self.quantization[v & 15] = array.array("b", s[1:65]) self.quantization[v & 15] = array.array("b", s[1:65])
s = s[65:] s = s[65:]
else: else:
return # FIXME: add code to read 16-bit tables! return # FIXME: add code to read 16-bit tables!
# raise SyntaxError, "bad quantization table element size" # raise SyntaxError, "bad quantization table element size"
#
# JPEG marker table
#
# JPEG marker table
MARKER = { MARKER = {
0xFFC0: ("SOF0", "Baseline DCT", SOF), 0xFFC0: ("SOF0", "Baseline DCT", SOF),
@ -274,10 +274,10 @@ MARKER = {
def _accept(prefix): def _accept(prefix):
return prefix[0:1] == b"\377" return prefix[0:1] == b"\377"
## ##
# Image plugin for JPEG and JFIF images. # Image plugin for JPEG and JFIF images.
class JpegImageFile(ImageFile.ImageFile): class JpegImageFile(ImageFile.ImageFile):
format = "JPEG" format = "JPEG"
@ -350,8 +350,10 @@ class JpegImageFile(ImageFile.ImageFile):
for s in [8, 4, 2, 1]: for s in [8, 4, 2, 1]:
if scale >= s: if scale >= s:
break break
e = e[0], e[1], (e[2]-e[0]+s-1)//s+e[0], (e[3]-e[1]+s-1)//s+e[1] e = e[0], e[1], (e[2] - e[0] + s -
self.size = ((self.size[0]+s-1)//s, (self.size[1]+s-1)//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 scale = s
self.tile = [(d, e, o, a)] self.tile = [(d, e, o, a)]
@ -513,7 +515,6 @@ def _getmp(self):
# file and so can't test it. # file and so can't test it.
return mp return mp
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# stuff to save JPEG files # stuff to save JPEG files
@ -527,19 +528,16 @@ RAWMODE = {
"YCbCr": "YCbCr", "YCbCr": "YCbCr",
} }
zigzag_index = ( 0, 1, 5, 6, 14, 15, 27, 28, zigzag_index = (0, 1, 5, 6, 14, 15, 27, 28, 2, 4, 7, 13, 16, 26, 29, 42, 3, 8,
2, 4, 7, 13, 16, 26, 29, 42, 12, 17, 25, 30, 41, 43, 9, 11, 18, 24, 31, 40, 44, 53, 10, 19,
3, 8, 12, 17, 25, 30, 41, 43, 23, 32, 39, 45, 52, 54, 20, 22, 33, 38, 46, 51, 55, 60, 21, 34,
9, 11, 18, 24, 31, 40, 44, 53, 37, 47, 50, 56, 59, 61, 35, 36, 48, 49, 57, 58, 62, 63)
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, 1, 1, 1, 1, 1): 1,
(2, 2, 1, 1, 1, 1): 2, (2, 2, 1, 1, 1, 1): 2,
} }
def convert_dict_qtables(qtables): def convert_dict_qtables(qtables):
@ -612,12 +610,12 @@ def _save(im, fp, filename):
return qtables return qtables
if isStringType(qtables): if isStringType(qtables):
try: try:
lines = [int(num) for line in qtables.splitlines() lines = [int(num) for line in qtables.splitlines() for num in
for num in line.split('#', 1)[0].split()] line.split('#', 1)[0].split()]
except ValueError: except ValueError:
raise ValueError("Invalid quantization table") raise ValueError("Invalid quantization table")
else: else:
qtables = [lines[s:s+64] for s in range(0, len(lines), 64)] qtables = [lines[s:s + 64] for s in range(0, len(lines), 64)]
if isinstance(qtables, (tuple, list, dict)): if isinstance(qtables, (tuple, list, dict)):
if isinstance(qtables, dict): if isinstance(qtables, dict):
qtables = convert_dict_qtables(qtables) qtables = convert_dict_qtables(qtables)
@ -667,16 +665,9 @@ def _save(im, fp, filename):
# "progressive" is the official name, but older documentation # "progressive" is the official name, but older documentation
# says "progression" # says "progression"
# FIXME: issue a warning if the wrong form is used (post-1.1.7) # FIXME: issue a warning if the wrong form is used (post-1.1.7)
"progressive" in info or "progression" in info, "progressive" in info or "progression" in info, info.get("smooth", 0),
info.get("smooth", 0), "optimize" in info, info.get("streamtype", 0), dpi[0], dpi[1],
"optimize" in info, subsampling, qtables, extra, info.get("exif", b""))
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 # 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 # in a shot. Guessing on the size, at im.size bytes. (raw pizel size is
@ -694,7 +685,7 @@ def _save(im, fp, filename):
# Ensure that our buffer is big enough # Ensure that our buffer is big enough
bufsize = max(ImageFile.MAXBLOCK, bufsize, len(info.get("exif", b"")) + 5) bufsize = max(ImageFile.MAXBLOCK, bufsize, len(info.get("exif", b"")) + 5)
ImageFile._save(im, fp, [("jpeg", (0, 0)+im.size, 0, rawmode)], bufsize) ImageFile._save(im, fp, [("jpeg", (0, 0) + im.size, 0, rawmode)], bufsize)
def _save_cjpeg(im, fp, filename): def _save_cjpeg(im, fp, filename):
@ -724,7 +715,6 @@ def jpeg_factory(fp=None, filename=None):
pass pass
return im return im
# -------------------------------------------------------------------q- # -------------------------------------------------------------------q-
# Registry stuff # Registry stuff

View File

@ -67,175 +67,117 @@ Libjpeg ref.: http://www.jpegcameras.com/libjpeg/libjpeg-3.html
""" """
presets = { presets = {
'web_low': {'subsampling': 2, # "4:1:1" 'web_low': {
'subsampling': 2, # "4:1:1"
'quantization': [ 'quantization': [
[20, 16, 25, 39, 50, 46, 62, 68, [20, 16, 25, 39, 50, 46, 62, 68, 16, 18, 23, 38, 38, 53, 65, 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,
25, 23, 31, 38, 53, 65, 68, 68, 50, 38, 53, 65, 68, 68, 68, 68, 46, 53, 65, 68, 68, 68, 68, 68,
39, 38, 38, 53, 65, 68, 68, 68, 62, 65, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68],
50, 38, 53, 65, 68, 68, 68, 68, [21, 25, 32, 38, 54, 68, 68, 68, 25, 28, 24, 38, 54, 68, 68, 68,
46, 53, 65, 68, 68, 68, 68, 68, 32, 24, 32, 43, 66, 68, 68, 68, 38, 38, 43, 53, 68, 68, 68, 68,
62, 65, 68, 68, 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, 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, 'web_medium': {
38, 38, 43, 53, 68, 68, 68, 68, 'subsampling': 2, # "4:1:1"
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': [ 'quantization': [
[16, 11, 11, 16, 23, 27, 31, 30, [16, 11, 11, 16, 23, 27, 31, 30, 11, 12, 12, 15, 20, 23, 23, 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,
11, 12, 13, 16, 23, 26, 35, 47, 23, 20, 23, 26, 39, 51, 64, 64, 27, 23, 26, 37, 51, 64, 64, 64,
16, 15, 16, 23, 26, 37, 47, 64, 31, 23, 35, 47, 64, 64, 64, 64, 30, 30, 47, 64, 64, 64, 64, 64],
23, 20, 23, 26, 39, 51, 64, 64, [17, 15, 17, 21, 20, 26, 38, 48, 15, 19, 18, 17, 20, 26, 35, 43,
27, 23, 26, 37, 51, 64, 64, 64, 17, 18, 20, 22, 26, 30, 46, 53, 21, 17, 22, 28, 30, 39, 53, 64,
31, 23, 35, 47, 64, 64, 64, 64, 20, 20, 26, 30, 39, 48, 64, 64, 26, 26, 30, 39, 48, 63, 64, 64,
30, 30, 47, 64, 64, 64, 64, 64], 38, 35, 46, 53, 64, 64, 64, 64, 48, 43, 53, 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, 'web_high': {
21, 17, 22, 28, 30, 39, 53, 64, 'subsampling': 0, # "4:4:4"
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': [ 'quantization': [
[ 6, 4, 4, 6, 9, 11, 12, 16, [6, 4, 4, 6, 9, 11, 12, 16, 4, 5, 5, 6, 8, 10, 12, 12, 4, 5, 5, 6,
4, 5, 5, 6, 8, 10, 12, 12, 10, 12, 14, 19, 6, 6, 6, 11, 12, 15, 19, 28, 9, 8, 10, 12, 16, 20,
4, 5, 5, 6, 10, 12, 14, 19, 27, 31, 11, 10, 12, 15, 20, 27, 31, 31, 12, 12, 14, 19, 27, 31,
6, 6, 6, 11, 12, 15, 19, 28, 31, 31, 16, 12, 19, 28, 31, 31, 31, 31],
9, 8, 10, 12, 16, 20, 27, 31, [7, 7, 13, 24, 26, 31, 31, 31, 7, 12, 16, 21, 31, 31, 31, 31, 13,
11, 10, 12, 15, 20, 27, 31, 31, 16, 17, 31, 31, 31, 31, 31, 24, 21, 31, 31, 31, 31, 31, 31, 26,
12, 12, 14, 19, 27, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
16, 12, 19, 28, 31, 31, 31, 31], 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 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, 'web_very_high': {
24, 21, 31, 31, 31, 31, 31, 31, 'subsampling': 0, # "4:4:4"
26, 31, 31, 31, 31, 31, 31, 31, 'quantization': [[2, 2, 2, 2, 3, 4, 5, 6, 2, 2, 2, 2, 3, 4, 5, 6, 2, 2,
31, 31, 31, 31, 31, 31, 31, 31, 2, 2, 4, 5, 7, 9, 2, 2, 2, 4, 5, 7, 9, 12, 3, 3, 4,
31, 31, 31, 31, 31, 31, 31, 31, 5, 8, 10, 12, 12, 4, 4, 5, 7, 10, 12, 12, 12, 5, 5,
31, 31, 31, 31, 31, 31, 31, 31] 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,
'web_very_high': {'subsampling': 0, # "4:4:4" 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': [ 'quantization': [
[ 2, 2, 2, 2, 3, 4, 5, 6, [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 3, 4, 5, 6, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 2, 2, 3, 1, 1, 1, 1,
2, 2, 2, 2, 4, 5, 7, 9, 2, 2, 3, 3, 1, 1, 1, 2, 2, 3, 3, 3, 1, 1, 2, 2, 3, 3, 3, 3],
2, 2, 2, 4, 5, 7, 9, 12, [1, 1, 1, 2, 2, 3, 3, 3, 1, 1, 1, 2, 3, 3, 3, 3, 1, 1, 1, 3, 3, 3,
3, 3, 4, 5, 8, 10, 12, 12, 3, 3, 2, 2, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 5, 7, 10, 12, 12, 12, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
5, 5, 7, 9, 12, 12, 12, 12, ]
6, 6, 9, 12, 12, 12, 12, 12], },
[ 3, 3, 5, 9, 13, 15, 15, 15, 'low': {
3, 4, 6, 11, 14, 12, 12, 12, 'subsampling': 2, # "4:1:1"
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': [ 'quantization': [
[ 1, 1, 1, 1, 1, 1, 1, 1, [18, 14, 14, 21, 30, 35, 34, 17, 14, 16, 16, 19, 26, 23, 12, 12,
1, 1, 1, 1, 1, 1, 1, 1, 14, 16, 17, 21, 23, 12, 12, 12, 21, 19, 21, 23, 12, 12, 12, 12,
1, 1, 1, 1, 1, 1, 1, 2, 30, 26, 23, 12, 12, 12, 12, 12, 35, 23, 12, 12, 12, 12, 12, 12,
1, 1, 1, 1, 1, 1, 2, 2, 34, 12, 12, 12, 12, 12, 12, 12, 17, 12, 12, 12, 12, 12, 12, 12],
1, 1, 1, 1, 1, 2, 2, 3, [20, 19, 22, 27, 20, 20, 17, 17, 19, 25, 23, 14, 14, 12, 12, 12,
1, 1, 1, 1, 2, 2, 3, 3, 22, 23, 14, 14, 12, 12, 12, 12, 27, 14, 14, 12, 12, 12, 12, 12,
1, 1, 1, 2, 2, 3, 3, 3, 20, 14, 12, 12, 12, 12, 12, 12, 20, 12, 12, 12, 12, 12, 12, 12,
1, 1, 2, 2, 3, 3, 3, 3], 17, 12, 12, 12, 12, 12, 12, 12, 17, 12, 12, 12, 12, 12, 12, 12]
[ 1, 1, 1, 2, 2, 3, 3, 3, ]
1, 1, 1, 2, 3, 3, 3, 3, },
1, 1, 1, 3, 3, 3, 3, 3, 'medium': {
2, 2, 3, 3, 3, 3, 3, 3, 'subsampling': 2, # "4:1:1"
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': [ 'quantization': [
[18, 14, 14, 21, 30, 35, 34, 17, [12, 8, 8, 12, 17, 21, 24, 17, 8, 9, 9, 11, 15, 19, 12, 12, 8, 9,
14, 16, 16, 19, 26, 23, 12, 12, 10, 12, 19, 12, 12, 12, 12, 11, 12, 21, 12, 12, 12, 12, 17, 15,
14, 16, 17, 21, 23, 12, 12, 12, 19, 12, 12, 12, 12, 12, 21, 19, 12, 12, 12, 12, 12, 12, 24, 12,
21, 19, 21, 23, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 17, 12, 12, 12, 12, 12, 12, 12],
30, 26, 23, 12, 12, 12, 12, 12, [13, 11, 13, 16, 20, 20, 17, 17, 11, 14, 14, 14, 14, 12, 12, 12,
35, 23, 12, 12, 12, 12, 12, 12, 13, 14, 14, 14, 12, 12, 12, 12, 16, 14, 14, 12, 12, 12, 12, 12,
34, 12, 12, 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, 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, 'high': {
27, 14, 14, 12, 12, 12, 12, 12, 'subsampling': 0, # "4:4:4"
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': [ 'quantization': [
[12, 8, 8, 12, 17, 21, 24, 17, [6, 4, 4, 6, 9, 11, 12, 16, 4, 5, 5, 6, 8, 10, 12, 12, 4, 5, 5, 6,
8, 9, 9, 11, 15, 19, 12, 12, 10, 12, 12, 12, 6, 6, 6, 11, 12, 12, 12, 12, 9, 8, 10, 12, 12, 12,
8, 9, 10, 12, 19, 12, 12, 12, 12, 12, 11, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 11, 12, 21, 12, 12, 12, 12, 12, 12, 16, 12, 12, 12, 12, 12, 12, 12],
17, 15, 19, 12, 12, 12, 12, 12, [7, 7, 13, 24, 20, 20, 17, 17, 7, 12, 16, 14, 14, 12, 12, 12, 13,
21, 19, 12, 12, 12, 12, 12, 12, 16, 14, 14, 12, 12, 12, 12, 24, 14, 14, 12, 12, 12, 12, 12, 20,
24, 12, 12, 12, 12, 12, 12, 12, 14, 12, 12, 12, 12, 12, 12, 20, 12, 12, 12, 12, 12, 12, 12, 17,
17, 12, 12, 12, 12, 12, 12, 12], 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, 'maximum': {
16, 14, 14, 12, 12, 12, 12, 12, 'subsampling': 0, # "4:4:4"
20, 14, 12, 12, 12, 12, 12, 12, 'quantization': [[2, 2, 2, 2, 3, 4, 5, 6, 2, 2, 2, 2, 3, 4, 5, 6, 2, 2,
20, 12, 12, 12, 12, 12, 12, 12, 2, 2, 4, 5, 7, 9, 2, 2, 2, 4, 5, 7, 9, 12, 3, 3, 4,
17, 12, 12, 12, 12, 12, 12, 12, 5, 8, 10, 12, 12, 4, 4, 5, 7, 10, 12, 12, 12, 5, 5,
17, 12, 12, 12, 12, 12, 12, 12] 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,
'high': {'subsampling': 0, # "4:4:4" 12, 5, 6, 9, 14, 12, 12, 12, 12, 9, 10, 14, 12, 12,
'quantization': [ 12, 12, 12, 13, 14, 12, 12, 12, 12, 12, 12, 15, 12,
[ 6, 4, 4, 6, 9, 11, 12, 16, 12, 12, 12, 12, 12, 12, 15, 12, 12, 12, 12, 12, 12,
4, 5, 5, 6, 8, 10, 12, 12, 12, 15, 12, 12, 12, 12, 12, 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): def _accept(s):
return s[:8] == b"\x00\x00\x00\x00\x00\x00\x00\x04" return s[:8] == b"\x00\x00\x00\x00\x00\x00\x00\x04"
## ##
# Image plugin for McIdas area images. # Image plugin for McIdas area images.
class McIdasImageFile(ImageFile.ImageFile): class McIdasImageFile(ImageFile.ImageFile):
format = "MCIDAS" format = "MCIDAS"
@ -62,7 +62,7 @@ class McIdasImageFile(ImageFile.ImageFile):
self.size = w[10], w[9] self.size = w[10], w[9]
offset = w[34] + w[15] offset = w[34] + w[15]
stride = w[15] + w[10]*w[11]*w[14] stride = w[15] + w[10] * w[11] * w[14]
self.tile = [("raw", (0, 0) + self.size, offset, (rawmode, stride, 1))] self.tile = [("raw", (0, 0) + self.size, offset, (rawmode, stride, 1))]

View File

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

View File

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

View File

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

View File

@ -16,12 +16,10 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
__version__ = "0.1" __version__ = "0.1"
from PIL import Image, ImageFile, _binary from PIL import Image, ImageFile, _binary
# #
# read MSP files # read MSP files
@ -31,11 +29,11 @@ i16 = _binary.i16le
def _accept(prefix): def _accept(prefix):
return prefix[:4] in [b"DanM", b"LinS"] return prefix[:4] in [b"DanM", b"LinS"]
## ##
# Image plugin for Windows MSP images. This plugin supports both # Image plugin for Windows MSP images. This plugin supports both
# uncompressed (Windows 1.0). # uncompressed (Windows 1.0).
class MspImageFile(ImageFile.ImageFile): class MspImageFile(ImageFile.ImageFile):
format = "MSP" format = "MSP"
@ -51,7 +49,7 @@ class MspImageFile(ImageFile.ImageFile):
# Header checksum # Header checksum
sum = 0 sum = 0
for i in range(0, 32, 2): for i in range(0, 32, 2):
sum = sum ^ i16(s[i:i+2]) sum = sum ^ i16(s[i:i + 2])
if sum != 0: if sum != 0:
raise SyntaxError("bad MSP checksum") raise SyntaxError("bad MSP checksum")
@ -59,9 +57,10 @@ class MspImageFile(ImageFile.ImageFile):
self.size = i16(s[4:]), i16(s[6:]) self.size = i16(s[4:]), i16(s[6:])
if s[:4] == b"DanM": if s[:4] == b"DanM":
self.tile = [("raw", (0, 0)+self.size, 32, ("1", 0, 1))] self.tile = [("raw", (0, 0) + self.size, 32, ("1", 0, 1))]
else: 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) # write MSP files (uncompressed only)
@ -93,7 +92,7 @@ def _save(im, fp, filename):
fp.write(o16(h)) fp.write(o16(h))
# image body # image body
ImageFile._save(im, fp, [("raw", (0, 0)+im.size, 32, ("1", 0, 1))]) ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 32, ("1", 0, 1))])
# #
# registry # registry

File diff suppressed because it is too large Load Diff

View File

@ -19,10 +19,10 @@ from __future__ import print_function
from PIL import EpsImagePlugin from PIL import EpsImagePlugin
## ##
# Simple Postscript graphics interface. # Simple Postscript graphics interface.
class PSDraw: class PSDraw:
""" """
Sets up printing to the given file. If **file** is omitted, Sets up printing to the given file. If **file** is omitted,
@ -57,9 +57,7 @@ class PSDraw:
def end_document(self): def end_document(self):
"""Ends printing. (Write Postscript DSC footer.)""" """Ends printing. (Write Postscript DSC footer.)"""
self._fp_write("%%EndDocument\n" self._fp_write("%%EndDocument\n" "restore showpage\n" "%%End\n")
"restore showpage\n"
"%%End\n")
if hasattr(self.fp, "flush"): if hasattr(self.fp, "flush"):
self.fp.flush() self.fp.flush()
@ -109,7 +107,7 @@ class PSDraw:
""" """
text = "\\(".join(text.split("(")) text = "\\(".join(text.split("("))
text = "\\)".join(text.split(")")) text = "\\)".join(text.split(")"))
xy = xy + (text,) xy = xy + (text, )
self._fp_write("%d %d M (%s) S\n" % xy) self._fp_write("%d %d M (%s) S\n" % xy)
def image(self, box, im, dpi=None): def image(self, box, im, dpi=None):

View File

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

View File

@ -29,58 +29,52 @@ _Palm8BitColormapValues = (
(102, 153, 255), (102, 102, 255), (102, 51, 255), (102, 0, 255), (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, 255, 204), (102, 204, 204), (102, 153, 204), (102, 102, 204),
(102, 51, 204), (102, 0, 204), (102, 255, 153), (102, 204, 153), (102, 51, 204), (102, 0, 204), (102, 255, 153), (102, 204, 153),
(102, 153, 153), (102, 102, 153), (102, 51, 153), (102, 0, 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, 255, 255), (51, 204, 255), (51, 153, 255), (51, 102, 255),
( 51, 51, 255), ( 51, 0, 255), ( 51, 255, 204), ( 51, 204, 204), (51, 51, 255), (51, 0, 255), (51, 255, 204), (51, 204, 204), (51, 153, 204
( 51, 153, 204), ( 51, 102, 204), ( 51, 51, 204), ( 51, 0, 204), ), (51, 102, 204), (51, 51, 204), (51, 0, 204), (51, 255, 153), (
( 51, 255, 153), ( 51, 204, 153), ( 51, 153, 153), ( 51, 102, 153), 51, 204, 153), (51, 153, 153), (51, 102, 153), (51, 51, 153),
( 51, 51, 153), ( 51, 0, 153), ( 0, 255, 255), ( 0, 204, 255), (51, 0, 153), (0, 255, 255), (0, 204, 255), (0, 153, 255), (0, 102, 255), (
( 0, 153, 255), ( 0, 102, 255), ( 0, 51, 255), ( 0, 0, 255), 0, 51, 255), (0, 0, 255), (0, 255, 204), (0, 204, 204), (0, 153, 204),
( 0, 255, 204), ( 0, 204, 204), ( 0, 153, 204), ( 0, 102, 204), (0, 102, 204), (0, 51, 204), (0, 0, 204), (0, 255, 153), (0, 204, 153), (
( 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
( 0, 153, 153), ( 0, 102, 153), ( 0, 51, 153), ( 0, 0, 153), ), (255, 204, 102), (255, 153, 102), (255, 102, 102), (255, 51, 102), (
(255, 255, 102), (255, 204, 102), (255, 153, 102), (255, 102, 102), 255, 0, 102), (255, 255, 51), (255, 204, 51), (255, 153, 51),
(255, 51, 102), (255, 0, 102), (255, 255, 51), (255, 204, 51), (255, 102, 51), (255, 51, 51), (255, 0, 51), (255, 255, 0), (255, 204, 0),
(255, 153, 51), (255, 102, 51), (255, 51, 51), (255, 0, 51), (255, 153, 0), (255, 102, 0), (255, 51, 0), (255, 0, 0), (204, 255, 102), (
(255, 255, 0), (255, 204, 0), (255, 153, 0), (255, 102, 0), 204, 204, 102), (204, 153, 102), (204, 102, 102), (204, 51, 102), (
(255, 51, 0), (255, 0, 0), (204, 255, 102), (204, 204, 102), 204, 0, 102), (204, 255, 51), (204, 204, 51), (204, 153, 51),
(204, 153, 102), (204, 102, 102), (204, 51, 102), (204, 0, 102), (204, 102, 51), (204, 51, 51), (204, 0, 51), (204, 255, 0), (204, 204, 0),
(204, 255, 51), (204, 204, 51), (204, 153, 51), (204, 102, 51), (204, 153, 0), (204, 102, 0), (204, 51, 0), (204, 0, 0), (153, 255, 102), (
(204, 51, 51), (204, 0, 51), (204, 255, 0), (204, 204, 0), 153, 204, 102), (153, 153, 102), (153, 102, 102), (153, 51, 102), (
(204, 153, 0), (204, 102, 0), (204, 51, 0), (204, 0, 0), 153, 0, 102), (153, 255, 51), (153, 204, 51), (153, 153, 51), (
(153, 255, 102), (153, 204, 102), (153, 153, 102), (153, 102, 102), 153, 102, 51), (153, 51, 51), (153, 0, 51), (153, 255, 0
(153, 51, 102), (153, 0, 102), (153, 255, 51), (153, 204, 51), ), (153, 204, 0), (153, 153, 0), (153, 102, 0), (153, 51, 0), (
(153, 153, 51), (153, 102, 51), (153, 51, 51), (153, 0, 51), 153, 0, 0), (102, 255, 102), (102, 204, 102), (102, 153, 102), (
(153, 255, 0), (153, 204, 0), (153, 153, 0), (153, 102, 0), 102, 102, 102), (102, 51, 102), (102, 0, 102), (102, 255, 51), (
(153, 51, 0), (153, 0, 0), (102, 255, 102), (102, 204, 102), 102, 204, 51), (102, 153, 51), (102, 102, 51), (102, 51, 51
(102, 153, 102), (102, 102, 102), (102, 51, 102), (102, 0, 102), ), (102, 0, 51), (102, 255, 0), (102, 204, 0), (102, 153, 0), (
(102, 255, 51), (102, 204, 51), (102, 153, 51), (102, 102, 51), 102, 102, 0), (102, 51, 0), (102, 0, 0), (51, 255, 102), (51, 204, 102
(102, 51, 51), (102, 0, 51), (102, 255, 0), (102, 204, 0), ), (51, 153, 102), (51, 102, 102), (51, 51, 102
(102, 153, 0), (102, 102, 0), (102, 51, 0), (102, 0, 0), ), (51, 0, 102), (51, 255, 51), (51, 204, 51), (51, 153, 51), (
( 51, 255, 102), ( 51, 204, 102), ( 51, 153, 102), ( 51, 102, 102), 51, 102, 51), (51, 51, 51), (51, 0, 51), (51, 255, 0), (51, 204, 0), (
( 51, 51, 102), ( 51, 0, 102), ( 51, 255, 51), ( 51, 204, 51), 51, 153, 0), (51, 102, 0), (51, 51, 0), (51, 0, 0), (0, 255, 102),
( 51, 153, 51), ( 51, 102, 51), ( 51, 51, 51), ( 51, 0, 51), (0, 204, 102), (0, 153, 102), (0, 102, 102), (0, 51, 102), (0, 0, 102), (
( 51, 255, 0), ( 51, 204, 0), ( 51, 153, 0), ( 51, 102, 0), 0, 255, 51), (0, 204, 51), (0, 153, 51), (0, 102, 51), (0, 51, 51
( 51, 51, 0), ( 51, 0, 0), ( 0, 255, 102), ( 0, 204, 102), ), (0, 0, 51), (0, 255, 0), (0, 204, 0), (0, 153, 0), (0, 102, 0), (
( 0, 153, 102), ( 0, 102, 102), ( 0, 51, 102), ( 0, 0, 102), 0, 51, 0), (17, 17, 17), (34, 34, 34), (68, 68, 68), (85, 85, 85), (
( 0, 255, 51), ( 0, 204, 51), ( 0, 153, 51), ( 0, 102, 51), 119, 119, 119), (136, 136, 136), (170, 170, 170), (187, 187, 187),
( 0, 51, 51), ( 0, 0, 51), ( 0, 255, 0), ( 0, 204, 0), (221, 221, 221), (238, 238, 238), (192, 192, 192), (128, 0, 0), (
( 0, 153, 0), ( 0, 102, 0), ( 0, 51, 0), ( 17, 17, 17), 128, 0, 128), (0, 128, 0), (0, 128, 128), (0, 0, 0), (0, 0, 0), (0, 0, 0
( 34, 34, 34), ( 68, 68, 68), ( 85, 85, 85), (119, 119, 119), ), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (
(136, 136, 136), (170, 170, 170), (187, 187, 187), (221, 221, 221), 0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (
(238, 238, 238), (192, 192, 192), (128, 0, 0), (128, 0, 128), 0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (
( 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), ( 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 # so build a prototype image to be used for palette resampling
def build_prototype_image(): def build_prototype_image():
image = Image.new("L", (1, len(_Palm8BitColormapValues),)) image = Image.new("L", (1, len(_Palm8BitColormapValues), ))
image.putdata(list(range(len(_Palm8BitColormapValues)))) image.putdata(list(range(len(_Palm8BitColormapValues))))
palettedata = () palettedata = ()
for i in range(len(_Palm8BitColormapValues)): for i in range(len(_Palm8BitColormapValues)):
@ -90,6 +84,7 @@ def build_prototype_image():
image.putpalette(palettedata) image.putpalette(palettedata)
return image return image
Palm8BitColormapImage = build_prototype_image() Palm8BitColormapImage = build_prototype_image()
# OK, we now have in Palm8BitColormapImage, # OK, we now have in Palm8BitColormapImage,
@ -101,24 +96,20 @@ _FLAGS = {
"custom-colormap": 0x4000, "custom-colormap": 0x4000,
"is-compressed": 0x8000, "is-compressed": 0x8000,
"has-transparent": 0x2000, "has-transparent": 0x2000,
} }
_COMPRESSION_TYPES = { _COMPRESSION_TYPES = {"none": 0xFF, "rle": 0x01, "scanline": 0x00, }
"none": 0xFF,
"rle": 0x01,
"scanline": 0x00,
}
o8 = _binary.o8 o8 = _binary.o8
o16b = _binary.o16be o16b = _binary.o16be
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
## ##
# (Internal) Image save plugin for the Palm format. # (Internal) Image save plugin for the Palm format.
def _save(im, fp, filename, check=0): def _save(im, fp, filename, check=0):
if im.mode == "P": if im.mode == "P":
@ -130,16 +121,16 @@ def _save(im, fp, filename, check=0):
bpp = 8 bpp = 8
version = 1 version = 1
elif (im.mode == "L" and elif (
"bpp" in im.encoderinfo and im.mode == "L" and "bpp" in im.encoderinfo and im.encoderinfo["bpp"] in
im.encoderinfo["bpp"] in (1, 2, 4)): (1, 2, 4)):
# this is 8-bit grayscale, so we shift it to get the high-order bits, # this is 8-bit grayscale, so we shift it to get the high-order bits,
# and invert it because # and invert it because
# Palm does greyscale from white (0) to black (1) # Palm does greyscale from white (0) to black (1)
bpp = im.encoderinfo["bpp"] bpp = im.encoderinfo["bpp"]
im = im.point( im = im.point(lambda x, shift=8 - bpp, maxval=(1 << bpp) - 1: maxval -
lambda x, shift=8-bpp, maxval=(1 << bpp)-1: maxval - (x >> shift)) (x >> shift))
# we ignore the palette here # we ignore the palette here
im.mode = "P" im.mode = "P"
rawmode = "P;" + str(bpp) rawmode = "P;" + str(bpp)
@ -151,7 +142,7 @@ def _save(im, fp, filename, check=0):
# only the lower bpp bits are significant. # only the lower bpp bits are significant.
# We invert them to match the Palm. # We invert them to match the Palm.
bpp = im.info["bpp"] bpp = im.info["bpp"]
im = im.point(lambda x, maxval=(1 << bpp)-1: maxval - (x & maxval)) im = im.point(lambda x, maxval=(1 << bpp) - 1: maxval - (x & maxval))
# we ignore the palette here # we ignore the palette here
im.mode = "P" im.mode = "P"
rawmode = "P;" + str(bpp) rawmode = "P;" + str(bpp)
@ -180,7 +171,7 @@ def _save(im, fp, filename, check=0):
cols = im.size[0] cols = im.size[0]
rows = im.size[1] rows = im.size[1]
rowbytes = int((cols + (16//bpp - 1)) / (16 // bpp)) * 2 rowbytes = int((cols + (16 // bpp - 1)) / (16 // bpp)) * 2
transparent_index = 0 transparent_index = 0
compression_type = _COMPRESSION_TYPES["none"] compression_type = _COMPRESSION_TYPES["none"]
@ -213,23 +204,18 @@ def _save(im, fp, filename, check=0):
for i in range(256): for i in range(256):
fp.write(o8(i)) fp.write(o8(i))
if colormapmode == 'RGB': if colormapmode == 'RGB':
fp.write( fp.write(o8(colormap[3 * i]) + o8(colormap[3 * i + 1]) +
o8(colormap[3 * i]) +
o8(colormap[3 * i + 1]) +
o8(colormap[3 * i + 2])) o8(colormap[3 * i + 2]))
elif colormapmode == 'RGBA': elif colormapmode == 'RGBA':
fp.write( fp.write(o8(colormap[4 * i]) + o8(colormap[4 * i + 1]) +
o8(colormap[4 * i]) +
o8(colormap[4 * i + 1]) +
o8(colormap[4 * i + 2])) o8(colormap[4 * i + 2]))
# now convert data to raw form # now convert data to raw form
ImageFile._save( ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0,
im, fp, [("raw", (0, 0)+im.size, 0, (rawmode, rowbytes, 1))]) (rawmode, rowbytes, 1))])
fp.flush() fp.flush()
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------

View File

@ -14,20 +14,18 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
__version__ = "0.1" __version__ = "0.1"
from PIL import Image, ImageFile, _binary from PIL import Image, ImageFile, _binary
i8 = _binary.i8 i8 = _binary.i8
## ##
# Image plugin for PhotoCD images. This plugin only reads the 768x512 # Image plugin for PhotoCD images. This plugin only reads the 768x512
# image from the file; higher resolutions are encoded in a proprietary # image from the file; higher resolutions are encoded in a proprietary
# encoding. # encoding.
class PcdImageFile(ImageFile.ImageFile): class PcdImageFile(ImageFile.ImageFile):
format = "PCD" format = "PCD"
@ -50,7 +48,7 @@ class PcdImageFile(ImageFile.ImageFile):
self.mode = "RGB" self.mode = "RGB"
self.size = 768, 512 # FIXME: not correct for rotated images! self.size = 768, 512 # FIXME: not correct for rotated images!
self.tile = [("pcd", (0, 0)+self.size, 96*2048, None)] self.tile = [("pcd", (0, 0) + self.size, 96 * 2048, None)]
def draft(self, mode, size): def draft(self, mode, size):
@ -61,7 +59,7 @@ class PcdImageFile(ImageFile.ImageFile):
if size: if size:
scale = max(self.size[0] / size[0], self.size[1] / size[1]) scale = max(self.size[0] / size[0], self.size[1] / size[1])
for s, o in [(4, 0*2048), (2, 0*2048), (1, 96*2048)]: for s, o in [(4, 0 * 2048), (2, 0 * 2048), (1, 96 * 2048)]:
if scale >= s: if scale >= s:
break break
# e = e[0], e[1], (e[2]-e[0]+s-1)/s+e[0], (e[3]-e[1]+s-1)/s+e[1] # e = e[0], e[1], (e[2]-e[0]+s-1)/s+e[0], (e[3]-e[1]+s-1)/s+e[1]

View File

@ -35,12 +35,10 @@ PCF_SWIDTHS = (1 << 6)
PCF_GLYPH_NAMES = (1 << 7) PCF_GLYPH_NAMES = (1 << 7)
PCF_BDF_ACCELERATORS = (1 << 8) PCF_BDF_ACCELERATORS = (1 << 8)
BYTES_PER_ROW = [ BYTES_PER_ROW = [lambda bits: ((bits + 7) >> 3),
lambda bits: ((bits+7) >> 3), lambda bits: ((bits + 15) >> 3) & ~1,
lambda bits: ((bits+15) >> 3) & ~1, lambda bits: ((bits + 31) >> 3) & ~3,
lambda bits: ((bits+31) >> 3) & ~3, lambda bits: ((bits + 63) >> 3) & ~7, ]
lambda bits: ((bits+63) >> 3) & ~7,
]
i8 = _binary.i8 i8 = _binary.i8
l16 = _binary.i16le l16 = _binary.i16le
@ -52,10 +50,10 @@ b32 = _binary.i32be
def sz(s, o): def sz(s, o):
return s[o:s.index(b"\0", o)] return s[o:s.index(b"\0", o)]
## ##
# Font file plugin for the X11 PCF format. # Font file plugin for the X11 PCF format.
class PcfFontFile(FontFile.FontFile): class PcfFontFile(FontFile.FontFile):
name = "name" name = "name"
@ -89,7 +87,7 @@ class PcfFontFile(FontFile.FontFile):
ix = encoding[ch] ix = encoding[ch]
if ix is not None: if ix is not None:
x, y, l, r, w, a, d, f = metrics[ix] x, y, l, r, w, a, d, f = metrics[ix]
glyph = (w, 0), (l, d-y, x+l, d), (0, 0, x, y), bitmaps[ix] glyph = (w, 0), (l, d - y, x + l, d), (0, 0, x, y), bitmaps[ix]
self.glyph[ch] = glyph self.glyph[ch] = glyph
def _getformat(self, tag): def _getformat(self, tag):
@ -158,10 +156,7 @@ class PcfFontFile(FontFile.FontFile):
descent = i8(fp.read(1)) - 128 descent = i8(fp.read(1)) - 128
xsize = right - left xsize = right - left
ysize = ascent + descent ysize = ascent + descent
append( append((xsize, ysize, left, right, width, ascent, descent, 0))
(xsize, ysize, left, right, width,
ascent, descent, 0)
)
else: else:
@ -175,10 +170,8 @@ class PcfFontFile(FontFile.FontFile):
attributes = i16(fp.read(2)) attributes = i16(fp.read(2))
xsize = right - left xsize = right - left
ysize = ascent + descent ysize = ascent + descent
append( append((xsize, ysize, left, right, width, ascent, descent,
(xsize, ysize, left, right, width, attributes))
ascent, descent, attributes)
)
return metrics return metrics
@ -220,10 +213,9 @@ class PcfFontFile(FontFile.FontFile):
for i in range(nbitmaps): for i in range(nbitmaps):
x, y, l, r, w, a, d, f = metrics[i] x, y, l, r, w, a, d, f = metrics[i]
b, e = offsets[i], offsets[i+1] b, e = offsets[i], offsets[i + 1]
bitmaps.append( 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 return bitmaps
@ -245,7 +237,7 @@ class PcfFontFile(FontFile.FontFile):
encodingOffset = i16(fp.read(2)) encodingOffset = i16(fp.read(2))
if encodingOffset != 0xFFFF: if encodingOffset != 0xFFFF:
try: try:
encoding[i+firstCol] = encodingOffset encoding[i + firstCol] = encodingOffset
except IndexError: except IndexError:
break # only load ISO-8859-1 glyphs break # only load ISO-8859-1 glyphs

View File

@ -37,10 +37,10 @@ o8 = _binary.o8
def _accept(prefix): def _accept(prefix):
return i8(prefix[0]) == 10 and i8(prefix[1]) in [0, 2, 3, 5] return i8(prefix[0]) == 10 and i8(prefix[1]) in [0, 2, 3, 5]
## ##
# Image plugin for Paintbrush images. # Image plugin for Paintbrush images.
class PcxImageFile(ImageFile.ImageFile): class PcxImageFile(ImageFile.ImageFile):
format = "PCX" format = "PCX"
@ -54,11 +54,11 @@ class PcxImageFile(ImageFile.ImageFile):
raise SyntaxError("not a PCX file") raise SyntaxError("not a PCX file")
# image # image
bbox = i16(s, 4), i16(s, 6), i16(s, 8)+1, i16(s, 10)+1 bbox = i16(s, 4), i16(s, 6), i16(s, 8) + 1, i16(s, 10) + 1
if bbox[2] <= bbox[0] or bbox[3] <= bbox[1]: if bbox[2] <= bbox[0] or bbox[3] <= bbox[1]:
raise SyntaxError("bad PCX image size") raise SyntaxError("bad PCX image size")
if Image.DEBUG: if Image.DEBUG:
print ("BBox: %s %s %s %s" % bbox) print("BBox: %s %s %s %s" % bbox)
# format # format
version = i8(s[1]) version = i8(s[1])
@ -66,7 +66,7 @@ class PcxImageFile(ImageFile.ImageFile):
planes = i8(s[65]) planes = i8(s[65])
stride = i16(s, 66) stride = i16(s, 66)
if Image.DEBUG: if Image.DEBUG:
print ("PCX version %s, bits %s, planes %s, stride %s" % print("PCX version %s, bits %s, planes %s, stride %s" %
(version, bits, planes, stride)) (version, bits, planes, stride))
self.info["dpi"] = i16(s, 12), i16(s, 14) self.info["dpi"] = i16(s, 12), i16(s, 14)
@ -87,7 +87,7 @@ class PcxImageFile(ImageFile.ImageFile):
if len(s) == 769 and i8(s[0]) == 12: if len(s) == 769 and i8(s[0]) == 12:
# check if the palette is linear greyscale # check if the palette is linear greyscale
for i in range(256): for i in range(256):
if s[i*3+1:i*3+4] != o8(i)*3: if s[i * 3 + 1:i * 3 + 4] != o8(i) * 3:
mode = rawmode = "P" mode = rawmode = "P"
break break
if mode == "P": if mode == "P":
@ -102,11 +102,11 @@ class PcxImageFile(ImageFile.ImageFile):
raise IOError("unknown PCX mode") raise IOError("unknown PCX mode")
self.mode = mode self.mode = mode
self.size = bbox[2]-bbox[0], bbox[3]-bbox[1] self.size = bbox[2] - bbox[0], bbox[3] - bbox[1]
bbox = (0, 0) + self.size bbox = (0, 0) + self.size
if Image.DEBUG: if Image.DEBUG:
print ("size: %sx%s" % self.size) print("size: %sx%s" % self.size)
self.tile = [("pcx", bbox, self.fp.tell(), (rawmode, planes * stride))] self.tile = [("pcx", bbox, self.fp.tell(), (rawmode, planes * stride))]
@ -143,8 +143,8 @@ def _save(im, fp, filename, check=0):
# gets overwritten. # gets overwritten.
if Image.DEBUG: if Image.DEBUG:
print ("PcxImagePlugin._save: xwidth: %d, bits: %d, stride: %d" % ( print("PcxImagePlugin._save: xwidth: %d, bits: %d, stride: %d" %
im.size[0], bits, stride)) (im.size[0], bits, stride))
# under windows, we could determine the current screen size with # under windows, we could determine the current screen size with
# "Image.core.display_mode()[1]", but I think that's overkill... # "Image.core.display_mode()[1]", but I think that's overkill...
@ -154,18 +154,15 @@ def _save(im, fp, filename, check=0):
dpi = 100, 100 dpi = 100, 100
# PCX header # PCX header
fp.write( fp.write(o8(10) + o8(version) + o8(1) + o8(bits) + o16(0) + o16(0) + o16(
o8(10) + o8(version) + o8(1) + o8(bits) + o16(0) + im.size[0] - 1) + o16(im.size[1] - 1) + o16(dpi[0]) + o16(dpi[1]) +
o16(0) + o16(im.size[0]-1) + o16(im.size[1]-1) + o16(dpi[0]) + b"\0" * 24 + b"\xFF" * 24 + b"\0" + o8(planes) + o16(stride) +
o16(dpi[1]) + b"\0"*24 + b"\xFF"*24 + b"\0" + o8(planes) + o16(1) + o16(screen[0]) + o16(screen[1]) + b"\0" * 54)
o16(stride) + o16(1) + o16(screen[0]) + o16(screen[1]) +
b"\0"*54
)
assert fp.tell() == 128 assert fp.tell() == 128
ImageFile._save(im, fp, [("pcx", (0, 0)+im.size, 0, ImageFile._save(im, fp, [("pcx", (0, 0) + im.size, 0,
(rawmode, bits*planes))]) (rawmode, bits * planes))])
if im.mode == "P": if im.mode == "P":
# colour palette # colour palette
@ -175,7 +172,7 @@ def _save(im, fp, filename, check=0):
# greyscale palette # greyscale palette
fp.write(o8(12)) fp.write(o8(12))
for i in range(256): for i in range(256):
fp.write(o8(i)*3) fp.write(o8(i) * 3)
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# registry # registry

View File

@ -26,7 +26,6 @@ from PIL import Image, ImageFile
from PIL._binary import i8 from PIL._binary import i8
import io import io
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
@ -37,6 +36,7 @@ import io
# 4. page # 4. page
# 5. page contents # 5. page contents
def _obj(fp, obj, **dict): def _obj(fp, obj, **dict):
fp.write("%d 0 obj\n" % obj) fp.write("%d 0 obj\n" % obj)
if dict: if dict:
@ -50,10 +50,10 @@ def _obj(fp, obj, **dict):
def _endobj(fp): def _endobj(fp):
fp.write("endobj\n") fp.write("endobj\n")
## ##
# (Internal) Image save plugin for the PDF format. # (Internal) Image save plugin for the PDF format.
def _save(im, fp, filename): def _save(im, fp, filename):
resolution = im.encoderinfo.get("resolution", 72.0) resolution = im.encoderinfo.get("resolution", 72.0)
@ -61,7 +61,7 @@ def _save(im, fp, filename):
# make sure image data is available # make sure image data is available
im.load() im.load()
xref = [0]*(5+1) # placeholders xref = [0] * (5 + 1) # placeholders
class TextWriter: class TextWriter:
def __init__(self, fp): def __init__(self, fp):
@ -105,9 +105,9 @@ def _save(im, fp, filename):
colorspace = "[ /Indexed /DeviceRGB 255 <" colorspace = "[ /Indexed /DeviceRGB 255 <"
palette = im.im.getpalette("RGB") palette = im.im.getpalette("RGB")
for i in range(256): for i in range(256):
r = i8(palette[i*3]) r = i8(palette[i * 3])
g = i8(palette[i*3+1]) g = i8(palette[i * 3 + 1])
b = i8(palette[i*3+2]) b = i8(palette[i * 3 + 2])
colorspace += "%02x%02x%02x " % (r, g, b) colorspace += "%02x%02x%02x " % (r, g, b)
colorspace += "> ]" colorspace += "> ]"
procset = "/ImageI" # indexed color procset = "/ImageI" # indexed color
@ -126,21 +126,14 @@ def _save(im, fp, filename):
# catalogue # catalogue
xref[1] = fp.tell() xref[1] = fp.tell()
_obj( _obj(fp, 1, Type="/Catalog", Pages="2 0 R")
fp, 1,
Type="/Catalog",
Pages="2 0 R")
_endobj(fp) _endobj(fp)
# #
# pages # pages
xref[2] = fp.tell() xref[2] = fp.tell()
_obj( _obj(fp, 2, Type="/Pages", Count=1, Kids="[4 0 R]")
fp, 2,
Type="/Pages",
Count=1,
Kids="[4 0 R]")
_endobj(fp) _endobj(fp)
# #
@ -155,19 +148,18 @@ def _save(im, fp, filename):
data = im.tobytes("raw", "1") data = im.tobytes("raw", "1")
im = Image.new("L", (len(data), 1), None) im = Image.new("L", (len(data), 1), None)
im.putdata(data) im.putdata(data)
ImageFile._save(im, op, [("hex", (0, 0)+im.size, 0, im.mode)]) ImageFile._save(im, op, [("hex", (0, 0) + im.size, 0, im.mode)])
elif filter == "/DCTDecode": elif filter == "/DCTDecode":
Image.SAVE["JPEG"](im, op, filename) Image.SAVE["JPEG"](im, op, filename)
elif filter == "/FlateDecode": elif filter == "/FlateDecode":
ImageFile._save(im, op, [("zip", (0, 0)+im.size, 0, im.mode)]) ImageFile._save(im, op, [("zip", (0, 0) + im.size, 0, im.mode)])
elif filter == "/RunLengthDecode": elif filter == "/RunLengthDecode":
ImageFile._save(im, op, [("packbits", (0, 0)+im.size, 0, im.mode)]) ImageFile._save(im, op, [("packbits", (0, 0) + im.size, 0, im.mode)])
else: else:
raise ValueError("unsupported PDF filter (%s)" % filter) raise ValueError("unsupported PDF filter (%s)" % filter)
xref[3] = fp.tell() xref[3] = fp.tell()
_obj( _obj(fp, 3,
fp, 3,
Type="/XObject", Type="/XObject",
Subtype="/Image", Subtype="/Image",
Width=width, # * 72.0 / resolution, Width=width, # * 72.0 / resolution,
@ -189,14 +181,11 @@ def _save(im, fp, filename):
xref[4] = fp.tell() xref[4] = fp.tell()
_obj(fp, 4) _obj(fp, 4)
fp.write( fp.write("<<\n/Type /Page\n/Parent 2 0 R\n"
"<<\n/Type /Page\n/Parent 2 0 R\n"
"/Resources <<\n/ProcSet [ /PDF %s ]\n" "/Resources <<\n/ProcSet [ /PDF %s ]\n"
"/XObject << /image 3 0 R >>\n>>\n" "/XObject << /image 3 0 R >>\n>>\n"
"/MediaBox [ 0 0 %d %d ]\n/Contents 5 0 R\n>>\n" % ( "/MediaBox [ 0 0 %d %d ]\n/Contents 5 0 R\n>>\n" % (procset, int(
procset, width * 72.0 / resolution), int(height * 72.0 / resolution)))
int(width * 72.0 / resolution),
int(height * 72.0 / resolution)))
_endobj(fp) _endobj(fp)
# #
@ -204,10 +193,8 @@ def _save(im, fp, filename):
op = TextWriter(io.BytesIO()) op = TextWriter(io.BytesIO())
op.write( op.write("q %d 0 0 %d 0 0 cm /image Do Q\n" %
"q %d 0 0 %d 0 0 cm /image Do Q\n" % ( (int(width * 72.0 / resolution), int(height * 72.0 / resolution)))
int(width * 72.0 / resolution),
int(height * 72.0 / resolution)))
xref[5] = fp.tell() xref[5] = fp.tell()
_obj(fp, 5, Length=len(op.fp.getvalue())) _obj(fp, 5, Length=len(op.fp.getvalue()))

View File

@ -29,10 +29,10 @@ from PIL import Image, ImageFile, _binary
i16 = _binary.i16le i16 = _binary.i16le
i32 = _binary.i32le i32 = _binary.i32le
## ##
# Image plugin for PIXAR raster images. # Image plugin for PIXAR raster images.
class PixarImageFile(ImageFile.ImageFile): class PixarImageFile(ImageFile.ImageFile):
format = "PIXAR" format = "PIXAR"
@ -58,7 +58,7 @@ class PixarImageFile(ImageFile.ImageFile):
# FIXME: to be continued... # FIXME: to be continued...
# create tile descriptor (assuming "dumped") # create tile descriptor (assuming "dumped")
self.tile = [("raw", (0, 0)+self.size, 1024, (self.mode, 0, 1))] self.tile = [("raw", (0, 0) + self.size, 1024, (self.mode, 0, 1))]
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------

View File

@ -46,10 +46,8 @@ i32 = _binary.i32be
is_cid = re.compile(b"\w\w\w\w").match is_cid = re.compile(b"\w\w\w\w").match
_MAGIC = b"\211PNG\r\n\032\n" _MAGIC = b"\211PNG\r\n\032\n"
_MODES = { _MODES = {
# supported bits/color combinations, and corresponding modes/rawmodes # supported bits/color combinations, and corresponding modes/rawmodes
(1, 0): ("1", "1"), (1, 0): ("1", "1"),
@ -69,7 +67,6 @@ _MODES = {
(16, 6): ("RGBA", "RGBA;16B"), (16, 6): ("RGBA", "RGBA;16B"),
} }
_simple_palette = re.compile(b'^\xff+\x00\xff*$') _simple_palette = re.compile(b'^\xff+\x00\xff*$')
# Maximum decompressed size for a iTXt or zTXt chunk. # 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. # Set the maximum total text chunk size.
MAX_TEXT_MEMORY = 64 * MAX_TEXT_CHUNK MAX_TEXT_MEMORY = 64 * MAX_TEXT_CHUNK
def _safe_zlib_decompress(s): def _safe_zlib_decompress(s):
dobj = zlib.decompressobj() dobj = zlib.decompressobj()
plaintext = dobj.decompress(s, MAX_TEXT_CHUNK) plaintext = dobj.decompress(s, MAX_TEXT_CHUNK)
@ -85,12 +83,11 @@ def _safe_zlib_decompress(s):
raise ValueError("Decompressed Data Too Large") raise ValueError("Decompressed Data Too Large")
return plaintext return plaintext
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Support classes. Suitable for PNG and related formats like MNG etc. # Support classes. Suitable for PNG and related formats like MNG etc.
class ChunkStream:
class ChunkStream:
def __init__(self, fp): def __init__(self, fp):
self.fp = fp self.fp = fp
@ -168,6 +165,7 @@ class iTXt(str):
keeping their extra information keeping their extra information
""" """
@staticmethod @staticmethod
def __new__(cls, text, lang, tkey): 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" + self.add(b"iTXt", key + b"\0\x01\0" + lang + b"\0" + tkey + b"\0" +
zlib.compress(value)) zlib.compress(value))
else: else:
self.add(b"iTXt", key + b"\0\0\0" + lang + b"\0" + tkey + b"\0" + self.add(b"iTXt",
value) key + b"\0\0\0" + lang + b"\0" + tkey + b"\0" + value)
def add_text(self, key, value, zip=0): def add_text(self, key, value, zip=0):
"""Appends a text chunk. """Appends a text chunk.
@ -255,12 +253,11 @@ class PngInfo:
else: else:
self.add(b"tEXt", key + b"\0" + value) self.add(b"tEXt", key + b"\0" + value)
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# PNG image stream (IHDR/IEND) # PNG image stream (IHDR/IEND)
class PngStream(ChunkStream):
class PngStream(ChunkStream):
def __init__(self, fp): def __init__(self, fp):
ChunkStream.__init__(self, fp) ChunkStream.__init__(self, fp)
@ -278,7 +275,8 @@ class PngStream(ChunkStream):
def check_text_memory(self, chunklen): def check_text_memory(self, chunklen):
self.text_memory += chunklen self.text_memory += chunklen
if self.text_memory > MAX_TEXT_MEMORY: 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) self.text_memory)
def chunk_iCCP(self, pos, length): def chunk_iCCP(self, pos, length):
@ -296,10 +294,10 @@ class PngStream(ChunkStream):
print("Compression method", i8(s[i])) print("Compression method", i8(s[i]))
comp_method = i8(s[i]) comp_method = i8(s[i])
if comp_method != 0: if comp_method != 0:
raise SyntaxError("Unknown compression method %s in iCCP chunk" % raise SyntaxError(
comp_method) "Unknown compression method %s in iCCP chunk" % comp_method)
try: try:
icc_profile = _safe_zlib_decompress(s[i+2:]) icc_profile = _safe_zlib_decompress(s[i + 2:])
except zlib.error: except zlib.error:
icc_profile = None # FIXME icc_profile = None # FIXME
self.im_info["icc_profile"] = icc_profile self.im_info["icc_profile"] = icc_profile
@ -323,7 +321,7 @@ class PngStream(ChunkStream):
def chunk_IDAT(self, pos, length): def chunk_IDAT(self, pos, length):
# image data # image data
self.im_tile = [("zip", (0, 0)+self.im_size, pos, self.im_rawmode)] self.im_tile = [("zip", (0, 0) + self.im_size, pos, self.im_rawmode)]
self.im_idat = length self.im_idat = length
raise EOFError raise EOFError
@ -411,8 +409,8 @@ class PngStream(ChunkStream):
else: else:
comp_method = 0 comp_method = 0
if comp_method != 0: if comp_method != 0:
raise SyntaxError("Unknown compression method %s in zTXt chunk" % raise SyntaxError(
comp_method) "Unknown compression method %s in zTXt chunk" % comp_method)
try: try:
v = _safe_zlib_decompress(v[1:]) v = _safe_zlib_decompress(v[1:])
except zlib.error: except zlib.error:
@ -465,17 +463,17 @@ class PngStream(ChunkStream):
return s return s
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# PNG reader # PNG reader
def _accept(prefix): def _accept(prefix):
return prefix[:8] == _MAGIC return prefix[:8] == _MAGIC
## ##
# Image plugin for PNG images. # Image plugin for PNG images.
class PngImageFile(ImageFile.ImageFile): class PngImageFile(ImageFile.ImageFile):
format = "PNG" format = "PNG"
@ -546,7 +544,7 @@ class PngImageFile(ImageFile.ImageFile):
"internal: prepare to read PNG file" "internal: prepare to read PNG file"
if self.info.get("interlace"): if self.info.get("interlace"):
self.decoderconfig = self.decoderconfig + (1,) self.decoderconfig = self.decoderconfig + (1, )
ImageFile.ImageFile.load_prepare(self) ImageFile.ImageFile.load_prepare(self)
@ -582,7 +580,6 @@ class PngImageFile(ImageFile.ImageFile):
self.png.close() self.png.close()
self.png = None self.png = None
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# PNG writer # PNG writer
@ -645,7 +642,7 @@ def _save(im, fp, filename, chunk=putchunk, check=0):
else: else:
# check palette contents # check palette contents
if im.palette: if im.palette:
colors = max(min(len(im.palette.getdata()[1])//3, 256), 2) colors = max(min(len(im.palette.getdata()[1]) // 3, 256), 2)
else: else:
colors = 256 colors = 256
@ -668,8 +665,7 @@ def _save(im, fp, filename, chunk=putchunk, check=0):
im.encoderconfig = ("optimize" in im.encoderinfo, im.encoderconfig = ("optimize" in im.encoderinfo,
im.encoderinfo.get("compress_level", -1), im.encoderinfo.get("compress_level", -1),
im.encoderinfo.get("compress_type", -1), im.encoderinfo.get("compress_type", -1), dictionary)
dictionary)
# get the corresponding PNG mode # get the corresponding PNG mode
try: try:
@ -685,8 +681,7 @@ def _save(im, fp, filename, chunk=putchunk, check=0):
fp.write(_MAGIC) fp.write(_MAGIC)
chunk(fp, b"IHDR", chunk(fp, b"IHDR", o32(im.size[0]), o32(im.size[1]), # 0: size
o32(im.size[0]), o32(im.size[1]), # 0: size
mode, # 8: depth/type mode, # 8: depth/type
b'\0', # 10: compression b'\0', # 10: compression
b'\0', # 11: filter category b'\0', # 11: filter category
@ -705,7 +700,7 @@ def _save(im, fp, filename, chunk=putchunk, check=0):
if transparency or transparency == 0: if transparency or transparency == 0:
if im.mode == "P": if im.mode == "P":
# limit to actual palette size # limit to actual palette size
alpha_bytes = 2**bits alpha_bytes = 2 ** bits
if isinstance(transparency, bytes): if isinstance(transparency, bytes):
chunk(fp, b"tRNS", transparency[:alpha_bytes]) chunk(fp, b"tRNS", transparency[:alpha_bytes])
else: else:
@ -726,15 +721,13 @@ def _save(im, fp, filename, chunk=putchunk, check=0):
else: else:
if im.mode == "P" and im.im.getpalettemode() == "RGBA": if im.mode == "P" and im.im.getpalettemode() == "RGBA":
alpha = im.im.getpalette("RGBA", "A") alpha = im.im.getpalette("RGBA", "A")
alpha_bytes = 2**bits alpha_bytes = 2 ** bits
chunk(fp, b"tRNS", alpha[:alpha_bytes]) chunk(fp, b"tRNS", alpha[:alpha_bytes])
dpi = im.encoderinfo.get("dpi") dpi = im.encoderinfo.get("dpi")
if dpi: if dpi:
chunk(fp, b"pHYs", chunk(fp, b"pHYs", o32(int(dpi[0] / 0.0254 + 0.5)),
o32(int(dpi[0] / 0.0254 + 0.5)), o32(int(dpi[1] / 0.0254 + 0.5)), b'\x01')
o32(int(dpi[1] / 0.0254 + 0.5)),
b'\x01')
info = im.encoderinfo.get("pnginfo") info = im.encoderinfo.get("pnginfo")
if info: 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"]) data = name + b"\0\0" + zlib.compress(im.info["icc_profile"])
chunk(fp, b"iCCP", data) chunk(fp, b"iCCP", data)
ImageFile._save(im, _idat(fp, chunk), ImageFile._save(im, _idat(fp, chunk), [("zip",
[("zip", (0, 0)+im.size, 0, rawmode)]) (0, 0) + im.size, 0, rawmode)])
chunk(fp, b"IEND", b"") chunk(fp, b"IEND", b"")
@ -763,10 +756,10 @@ def _save(im, fp, filename, chunk=putchunk, check=0):
except: except:
pass pass
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# PNG chunk converter # PNG chunk converter
def getchunks(im, **params): def getchunks(im, **params):
"""Return a list of PNG chunks representing this image.""" """Return a list of PNG chunks representing this image."""
@ -795,7 +788,6 @@ def getchunks(im, **params):
return fp.data return fp.data
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Registry # Registry

View File

@ -14,7 +14,6 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
__version__ = "0.2" __version__ = "0.2"
import string import string
@ -37,25 +36,19 @@ b_whitespace = b_whitespace.encode('ascii', 'ignore')
MODES = { MODES = {
# standard # standard
b"P4": "1", b"P4": "1", b"P5": "L", b"P6": "RGB", # extensions
b"P5": "L", b"P0CMYK": "CMYK", # PIL extensions (for test purposes only)
b"P6": "RGB", b"PyP": "P", b"PyRGBA": "RGBA", b"PyCMYK": "CMYK"
# extensions
b"P0CMYK": "CMYK",
# PIL extensions (for test purposes only)
b"PyP": "P",
b"PyRGBA": "RGBA",
b"PyCMYK": "CMYK"
} }
def _accept(prefix): def _accept(prefix):
return prefix[0:1] == b"P" and prefix[1] in b"0456y" return prefix[0:1] == b"P" and prefix[1] in b"0456y"
## ##
# Image plugin for PBM, PGM, and PPM images. # Image plugin for PBM, PGM, and PPM images.
class PpmImageFile(ImageFile.ImageFile): class PpmImageFile(ImageFile.ImageFile):
format = "PPM" format = "PPM"
@ -108,7 +101,7 @@ class PpmImageFile(ImageFile.ImageFile):
if s > 255: if s > 255:
if not mode == 'L': if not mode == 'L':
raise ValueError("Too many colors for band: %s" % s) raise ValueError("Too many colors for band: %s" % s)
if s < 2**16: if s < 2 ** 16:
self.mode = 'I' self.mode = 'I'
rawmode = 'I;16B' rawmode = 'I;16B'
else: else:
@ -116,9 +109,7 @@ class PpmImageFile(ImageFile.ImageFile):
rawmode = 'I;32B' rawmode = 'I;32B'
self.size = xsize, ysize self.size = xsize, ysize
self.tile = [("raw", self.tile = [("raw", (0, 0, xsize, ysize), self.fp.tell(),
(0, 0, xsize, ysize),
self.fp.tell(),
(rawmode, 0, 1))] (rawmode, 0, 1))]
# ALTERNATIVE: load via builtin debug function # ALTERNATIVE: load via builtin debug function
@ -126,9 +117,9 @@ class PpmImageFile(ImageFile.ImageFile):
# self.mode = self.im.mode # self.mode = self.im.mode
# self.size = self.im.size # self.size = self.im.size
#
# --------------------------------------------------------------------
#
# --------------------------------------------------------------------
def _save(im, fp, filename): def _save(im, fp, filename):
if im.mode == "1": if im.mode == "1":
@ -136,7 +127,7 @@ def _save(im, fp, filename):
elif im.mode == "L": elif im.mode == "L":
rawmode, head = "L", b"P5" rawmode, head = "L", b"P5"
elif im.mode == "I": elif im.mode == "I":
if im.getextrema()[1] < 2**16: if im.getextrema()[1] < 2 ** 16:
rawmode, head = "I;16B", b"P5" rawmode, head = "I;16B", b"P5"
else: else:
rawmode, head = "I;32B", b"P5" rawmode, head = "I;32B", b"P5"
@ -156,13 +147,14 @@ def _save(im, fp, filename):
fp.write(b"65535\n") fp.write(b"65535\n")
elif rawmode == "I;32B": elif rawmode == "I;32B":
fp.write(b"2147483648\n") fp.write(b"2147483648\n")
ImageFile._save(im, fp, [("raw", (0, 0)+im.size, 0, (rawmode, 0, 1))]) ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, 1))])
# ALTERNATIVE: save via builtin debug function # ALTERNATIVE: save via builtin debug function
# im._dump(filename) # im._dump(filename)
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
Image.register_open("PPM", PpmImageFile, _accept) Image.register_open("PPM", PpmImageFile, _accept)
Image.register_save("PPM", _save) Image.register_save("PPM", _save)

View File

@ -40,17 +40,17 @@ i8 = _binary.i8
i16 = _binary.i16be i16 = _binary.i16be
i32 = _binary.i32be i32 = _binary.i32be
# --------------------------------------------------------------------. # --------------------------------------------------------------------.
# read PSD images # read PSD images
def _accept(prefix): def _accept(prefix):
return prefix[:4] == b"8BPS" return prefix[:4] == b"8BPS"
## ##
# Image plugin for Photoshop images. # Image plugin for Photoshop images.
class PsdImageFile(ImageFile.ImageFile): class PsdImageFile(ImageFile.ImageFile):
format = "PSD" format = "PSD"
@ -139,7 +139,7 @@ class PsdImageFile(ImageFile.ImageFile):
try: try:
if layer <= 0: if layer <= 0:
raise IndexError raise IndexError
name, mode, bbox, tile = self.layers[layer-1] name, mode, bbox, tile = self.layers[layer - 1]
self.mode = mode self.mode = mode
self.tile = tile self.tile = tile
self.frame = layer self.frame = layer
@ -187,7 +187,7 @@ def _layerinfo(file):
if type == 65535: if type == 65535:
m = "A" m = "A"
else: else:
m = "RGBA"[type] m = "RGBA" [type]
mode.append(m) mode.append(m)
size = i32(read(4)) size = i32(read(4))
@ -269,7 +269,7 @@ def _maketile(file, mode, bbox, channels):
if mode == "CMYK": if mode == "CMYK":
layer += ";I" layer += ";I"
tile.append(("raw", bbox, offset, layer)) tile.append(("raw", bbox, offset, layer))
offset = offset + xsize*ysize offset = offset + xsize * ysize
elif compression == 1: elif compression == 1:
# #
@ -282,11 +282,9 @@ def _maketile(file, mode, bbox, channels):
layer = mode[channel] layer = mode[channel]
if mode == "CMYK": if mode == "CMYK":
layer += ";I" layer += ";I"
tile.append( tile.append(("packbits", bbox, offset, layer))
("packbits", bbox, offset, layer)
)
for y in range(ysize): for y in range(ysize):
offset = offset + i16(bytecount[i:i+2]) offset = offset + i16(bytecount[i:i + 2])
i += 2 i += 2
file.seek(offset) file.seek(offset)

View File

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

View File

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

View File

@ -44,23 +44,24 @@ import sys
def isInt(f): def isInt(f):
try: try:
i = int(f) i = int(f)
if f-i == 0: if f - i == 0:
return 1 return 1
else: else:
return 0 return 0
except: except:
return 0 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 # There is no magic number to identify Spider files, so just check a
# series of header locations to see if they have reasonable values. # series of header locations to see if they have reasonable values.
# Returns no.of bytes in the header, if it is a valid Spider header, # Returns no.of bytes in the header, if it is a valid Spider header,
# otherwise returns 0 # otherwise returns 0
def isSpiderHeader(t): def isSpiderHeader(t):
h = (99,) + t # add 1 value so can use spider header index start=1 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 # header values 1,2,5,12,13,22,23 should be integers
for i in [1, 2, 5, 12, 13, 22, 23]: for i in [1, 2, 5, 12, 13, 22, 23]:
if not isInt(h[i]): if not isInt(h[i]):
@ -115,7 +116,7 @@ class SpiderImageFile(ImageFile.ImageFile):
except struct.error: except struct.error:
raise SyntaxError("not a valid Spider file") raise SyntaxError("not a valid Spider file")
h = (99,) + t # add 1 value : spider header index starts at 1 h = (99, ) + t # add 1 value : spider header index starts at 1
iform = int(h[5]) iform = int(h[5])
if iform != 1: if iform != 1:
raise SyntaxError("not a Spider 2D image") raise SyntaxError("not a Spider 2D image")
@ -149,9 +150,7 @@ class SpiderImageFile(ImageFile.ImageFile):
self.rawmode = "F;32F" self.rawmode = "F;32F"
self.mode = "F" self.mode = "F"
self.tile = [ self.tile = [("raw", (0, 0) + self.size, offset, (self.rawmode, 0, 1))]
("raw", (0, 0) + self.size, offset,
(self.rawmode, 0, 1))]
self.__fp = self.fp # FIXME: hack self.__fp = self.fp # FIXME: hack
# 1st image index is zero (although SPIDER imgnumber starts at 1) # 1st image index is zero (although SPIDER imgnumber starts at 1)
@ -176,7 +175,7 @@ class SpiderImageFile(ImageFile.ImageFile):
(min, max) = self.getextrema() (min, max) = self.getextrema()
m = 1 m = 1
if max != min: if max != min:
m = depth / (max-min) m = depth / (max - min)
b = -m * min b = -m * min
return self.point(lambda i, m=m, b=b: i * m + b).convert("L") return self.point(lambda i, m=m, b=b: i * m + b).convert("L")
@ -185,10 +184,10 @@ class SpiderImageFile(ImageFile.ImageFile):
from PIL import ImageTk from PIL import ImageTk
return ImageTk.PhotoImage(self.convert2byte(), palette=256) return ImageTk.PhotoImage(self.convert2byte(), palette=256)
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Image series # Image series
# given a list of filenames, return a list of images # given a list of filenames, return a list of images
def loadImageSeries(filelist=None): def loadImageSeries(filelist=None):
" create a list of Image.images for use in montage " " create a list of Image.images for use in montage "
@ -210,10 +209,10 @@ def loadImageSeries(filelist=None):
imglist.append(im) imglist.append(im)
return imglist return imglist
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# For saving images in Spider format # For saving images in Spider format
def makeSpiderHeader(im): def makeSpiderHeader(im):
nsam, nrow = im.size nsam, nrow = im.size
lenbyt = nsam * 4 # There are labrec records in the header lenbyt = nsam * 4 # There are labrec records in the header
@ -264,7 +263,7 @@ def _save(im, fp, filename):
fp.writelines(hdr) fp.writelines(hdr)
rawmode = "F;32NF" # 32-bit native floating point rawmode = "F;32NF" # 32-bit native floating point
ImageFile._save(im, fp, [("raw", (0, 0)+im.size, 0, (rawmode, 0, 1))]) ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, 1))])
fp.close() fp.close()
@ -306,7 +305,6 @@ if __name__ == "__main__":
if outfile != "": if outfile != "":
# perform some image operation # perform some image operation
im = im.transpose(Image.FLIP_LEFT_RIGHT) im = im.transpose(Image.FLIP_LEFT_RIGHT)
print( print("saving a flipped version of %s as %s " %
"saving a flipped version of %s as %s " %
(os.path.basename(filename), outfile)) (os.path.basename(filename), outfile))
im.save(outfile, "SPIDER") im.save(outfile, "SPIDER")

View File

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

View File

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

View File

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

View File

@ -144,75 +144,73 @@ COMPRESSION_INFO_REV = dict([(v, k) for (k, v) in COMPRESSION_INFO.items()])
OPEN_INFO = { OPEN_INFO = {
# (ByteOrder, PhotoInterpretation, SampleFormat, FillOrder, BitsPerSample, # (ByteOrder, PhotoInterpretation, SampleFormat, FillOrder, BitsPerSample,
# ExtraSamples) => mode, rawmode # ExtraSamples) => mode, rawmode
(II, 0, 1, 1, (1,), ()): ("1", "1;I"), (II, 0, 1, 1, (1, ), ()): ("1", "1;I"),
(II, 0, 1, 2, (1,), ()): ("1", "1;IR"), (II, 0, 1, 2, (1, ), ()): ("1", "1;IR"),
(II, 0, 1, 1, (8,), ()): ("L", "L;I"), (II, 0, 1, 1, (8, ), ()): ("L", "L;I"),
(II, 0, 1, 2, (8,), ()): ("L", "L;IR"), (II, 0, 1, 2, (8, ), ()): ("L", "L;IR"),
(II, 0, 3, 1, (32,), ()): ("F", "F;32F"), (II, 0, 3, 1, (32, ), ()): ("F", "F;32F"),
(II, 1, 1, 1, (1,), ()): ("1", "1"), (II, 1, 1, 1, (1, ), ()): ("1", "1"),
(II, 1, 1, 1, (4,), ()): ("L", "L;4"), (II, 1, 1, 1, (4, ), ()): ("L", "L;4"),
(II, 1, 1, 2, (1,), ()): ("1", "1;R"), (II, 1, 1, 2, (1, ), ()): ("1", "1;R"),
(II, 1, 1, 1, (8,), ()): ("L", "L"), (II, 1, 1, 1, (8, ), ()): ("L", "L"),
(II, 1, 1, 1, (8, 8), (2,)): ("LA", "LA"), (II, 1, 1, 1, (8, 8), (2, )): ("LA", "LA"),
(II, 1, 1, 2, (8,), ()): ("L", "L;R"), (II, 1, 1, 2, (8, ), ()): ("L", "L;R"),
(II, 1, 1, 1, (12,), ()): ("I;16", "I;12"), (II, 1, 1, 1, (12, ), ()): ("I;16", "I;12"),
(II, 1, 1, 1, (16,), ()): ("I;16", "I;16"), (II, 1, 1, 1, (16, ), ()): ("I;16", "I;16"),
(II, 1, 2, 1, (16,), ()): ("I;16S", "I;16S"), (II, 1, 2, 1, (16, ), ()): ("I;16S", "I;16S"),
(II, 1, 1, 1, (32,), ()): ("I", "I;32N"), (II, 1, 1, 1, (32, ), ()): ("I", "I;32N"),
(II, 1, 2, 1, (32,), ()): ("I", "I;32S"), (II, 1, 2, 1, (32, ), ()): ("I", "I;32S"),
(II, 1, 3, 1, (32,), ()): ("F", "F;32F"), (II, 1, 3, 1, (32, ), ()): ("F", "F;32F"),
(II, 2, 1, 1, (8, 8, 8), ()): ("RGB", "RGB"), (II, 2, 1, 1, (8, 8, 8), ()): ("RGB", "RGB"),
(II, 2, 1, 2, (8, 8, 8), ()): ("RGB", "RGB;R"), (II, 2, 1, 2, (8, 8, 8), ()): ("RGB", "RGB;R"),
(II, 2, 1, 1, (8, 8, 8, 8), ()): ("RGBA", "RGBA"), # missing ExtraSamples (II, 2, 1, 1, (8, 8, 8, 8), ()): ("RGBA", "RGBA"), # missing ExtraSamples
(II, 2, 1, 1, (8, 8, 8, 8), (0,)): ("RGBX", "RGBX"), (II, 2, 1, 1, (8, 8, 8, 8), (0, )): ("RGBX", "RGBX"),
(II, 2, 1, 1, (8, 8, 8, 8), (1,)): ("RGBA", "RGBa"), (II, 2, 1, 1, (8, 8, 8, 8), (1, )): ("RGBA", "RGBa"),
(II, 2, 1, 1, (8, 8, 8, 8), (2,)): ("RGBA", "RGBA"), (II, 2, 1, 1, (8, 8, 8, 8), (2, )): ("RGBA", "RGBA"),
(II, 2, 1, 1, (8, 8, 8, 8), (999,)): ("RGBA", "RGBA"), # Corel Draw 10 (II, 2, 1, 1, (8, 8, 8, 8), (999, )): ("RGBA", "RGBA"), # Corel Draw 10
(II, 3, 1, 1, (1,), ()): ("P", "P;1"), (II, 3, 1, 1, (1, ), ()): ("P", "P;1"),
(II, 3, 1, 2, (1,), ()): ("P", "P;1R"), (II, 3, 1, 2, (1, ), ()): ("P", "P;1R"),
(II, 3, 1, 1, (2,), ()): ("P", "P;2"), (II, 3, 1, 1, (2, ), ()): ("P", "P;2"),
(II, 3, 1, 2, (2,), ()): ("P", "P;2R"), (II, 3, 1, 2, (2, ), ()): ("P", "P;2R"),
(II, 3, 1, 1, (4,), ()): ("P", "P;4"), (II, 3, 1, 1, (4, ), ()): ("P", "P;4"),
(II, 3, 1, 2, (4,), ()): ("P", "P;4R"), (II, 3, 1, 2, (4, ), ()): ("P", "P;4R"),
(II, 3, 1, 1, (8,), ()): ("P", "P"), (II, 3, 1, 1, (8, ), ()): ("P", "P"),
(II, 3, 1, 1, (8, 8), (2,)): ("PA", "PA"), (II, 3, 1, 1, (8, 8), (2, )): ("PA", "PA"),
(II, 3, 1, 2, (8,), ()): ("P", "P;R"), (II, 3, 1, 2, (8, ), ()): ("P", "P;R"),
(II, 5, 1, 1, (8, 8, 8, 8), ()): ("CMYK", "CMYK"), (II, 5, 1, 1, (8, 8, 8, 8), ()): ("CMYK", "CMYK"),
(II, 6, 1, 1, (8, 8, 8), ()): ("YCbCr", "YCbCr"), (II, 6, 1, 1, (8, 8, 8), ()): ("YCbCr", "YCbCr"),
(II, 8, 1, 1, (8, 8, 8), ()): ("LAB", "LAB"), (II, 8, 1, 1, (8, 8, 8), ()): ("LAB", "LAB"),
(MM, 0, 1, 1, (1, ), ()): ("1", "1;I"),
(MM, 0, 1, 1, (1,), ()): ("1", "1;I"), (MM, 0, 1, 2, (1, ), ()): ("1", "1;IR"),
(MM, 0, 1, 2, (1,), ()): ("1", "1;IR"), (MM, 0, 1, 1, (8, ), ()): ("L", "L;I"),
(MM, 0, 1, 1, (8,), ()): ("L", "L;I"), (MM, 0, 1, 2, (8, ), ()): ("L", "L;IR"),
(MM, 0, 1, 2, (8,), ()): ("L", "L;IR"), (MM, 1, 1, 1, (1, ), ()): ("1", "1"),
(MM, 1, 1, 1, (1,), ()): ("1", "1"), (MM, 1, 1, 2, (1, ), ()): ("1", "1;R"),
(MM, 1, 1, 2, (1,), ()): ("1", "1;R"), (MM, 1, 1, 1, (8, ), ()): ("L", "L"),
(MM, 1, 1, 1, (8,), ()): ("L", "L"), (MM, 1, 1, 1, (8, 8), (2, )): ("LA", "LA"),
(MM, 1, 1, 1, (8, 8), (2,)): ("LA", "LA"), (MM, 1, 1, 2, (8, ), ()): ("L", "L;R"),
(MM, 1, 1, 2, (8,), ()): ("L", "L;R"), (MM, 1, 1, 1, (16, ), ()): ("I;16B", "I;16B"),
(MM, 1, 1, 1, (16,), ()): ("I;16B", "I;16B"), (MM, 1, 2, 1, (16, ), ()): ("I;16BS", "I;16BS"),
(MM, 1, 2, 1, (16,), ()): ("I;16BS", "I;16BS"), (MM, 1, 2, 1, (32, ), ()): ("I;32BS", "I;32BS"),
(MM, 1, 2, 1, (32,), ()): ("I;32BS", "I;32BS"), (MM, 1, 3, 1, (32, ), ()): ("F", "F;32BF"),
(MM, 1, 3, 1, (32,), ()): ("F", "F;32BF"),
(MM, 2, 1, 1, (8, 8, 8), ()): ("RGB", "RGB"), (MM, 2, 1, 1, (8, 8, 8), ()): ("RGB", "RGB"),
(MM, 2, 1, 2, (8, 8, 8), ()): ("RGB", "RGB;R"), (MM, 2, 1, 2, (8, 8, 8), ()): ("RGB", "RGB;R"),
(MM, 2, 1, 1, (8, 8, 8, 8), (0,)): ("RGBX", "RGBX"), (MM, 2, 1, 1, (8, 8, 8, 8), (0, )): ("RGBX", "RGBX"),
(MM, 2, 1, 1, (8, 8, 8, 8), (1,)): ("RGBA", "RGBa"), (MM, 2, 1, 1, (8, 8, 8, 8), (1, )): ("RGBA", "RGBa"),
(MM, 2, 1, 1, (8, 8, 8, 8), (2,)): ("RGBA", "RGBA"), (MM, 2, 1, 1, (8, 8, 8, 8), (2, )): ("RGBA", "RGBA"),
(MM, 2, 1, 1, (8, 8, 8, 8), (999,)): ("RGBA", "RGBA"), # Corel Draw 10 (MM, 2, 1, 1, (8, 8, 8, 8), (999, )): ("RGBA", "RGBA"), # Corel Draw 10
(MM, 3, 1, 1, (1,), ()): ("P", "P;1"), (MM, 3, 1, 1, (1, ), ()): ("P", "P;1"),
(MM, 3, 1, 2, (1,), ()): ("P", "P;1R"), (MM, 3, 1, 2, (1, ), ()): ("P", "P;1R"),
(MM, 3, 1, 1, (2,), ()): ("P", "P;2"), (MM, 3, 1, 1, (2, ), ()): ("P", "P;2"),
(MM, 3, 1, 2, (2,), ()): ("P", "P;2R"), (MM, 3, 1, 2, (2, ), ()): ("P", "P;2R"),
(MM, 3, 1, 1, (4,), ()): ("P", "P;4"), (MM, 3, 1, 1, (4, ), ()): ("P", "P;4"),
(MM, 3, 1, 2, (4,), ()): ("P", "P;4R"), (MM, 3, 1, 2, (4, ), ()): ("P", "P;4R"),
(MM, 3, 1, 1, (8,), ()): ("P", "P"), (MM, 3, 1, 1, (8, ), ()): ("P", "P"),
(MM, 3, 1, 1, (8, 8), (2,)): ("PA", "PA"), (MM, 3, 1, 1, (8, 8), (2, )): ("PA", "PA"),
(MM, 3, 1, 2, (8,), ()): ("P", "P;R"), (MM, 3, 1, 2, (8, ), ()): ("P", "P;R"),
(MM, 5, 1, 1, (8, 8, 8, 8), ()): ("CMYK", "CMYK"), (MM, 5, 1, 1, (8, 8, 8, 8), ()): ("CMYK", "CMYK"),
(MM, 6, 1, 1, (8, 8, 8), ()): ("YCbCr", "YCbCr"), (MM, 6, 1, 1, (8, 8, 8), ()): ("YCbCr", "YCbCr"),
(MM, 8, 1, 1, (8, 8, 8), ()): ("LAB", "LAB"), (MM, 8, 1, 1, (8, 8, 8), ()): ("LAB", "LAB"),
} }
PREFIXES = [b"MM\000\052", b"II\052\000", b"II\xBC\000"] 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): def _accept(prefix):
return prefix[:4] in PREFIXES return prefix[:4] in PREFIXES
## ##
# Wrapper for TIFF IFDs. # Wrapper for TIFF IFDs.
class ImageFileDirectory(collections.MutableMapping): class ImageFileDirectory(collections.MutableMapping):
""" This class represents a TIFF tag directory. To speed things """ This class represents a TIFF tag directory. To speed things
up, we don't decode tags unless they're asked for. 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 return tag in self.tags or tag in self.tagdata
if bytes is str: if bytes is str:
def has_key(self, tag): def has_key(self, tag):
return tag in self return tag in self
@ -346,7 +345,7 @@ class ImageFileDirectory(collections.MutableMapping):
# tags are not tuples for byte, string, and undefined data. # tags are not tuples for byte, string, and undefined data.
# see load_* # see load_*
if not isinstance(value, tuple): if not isinstance(value, tuple):
value = (value,) value = (value, )
self.tags[tag] = value self.tags[tag] = value
def __delitem__(self, tag): def __delitem__(self, tag):
@ -366,12 +365,14 @@ class ImageFileDirectory(collections.MutableMapping):
def load_byte(self, data): def load_byte(self, data):
return data return data
load_dispatch[1] = (1, load_byte) load_dispatch[1] = (1, load_byte)
def load_string(self, data): def load_string(self, data):
if data[-1:] == b'\0': if data[-1:] == b'\0':
data = data[:-1] data = data[:-1]
return data.decode('latin-1', 'replace') return data.decode('latin-1', 'replace')
load_dispatch[2] = (1, load_string) load_dispatch[2] = (1, load_string)
def load_short(self, data): def load_short(self, data):
@ -379,6 +380,7 @@ class ImageFileDirectory(collections.MutableMapping):
for i in range(0, len(data), 2): for i in range(0, len(data), 2):
l.append(self.i16(data, i)) l.append(self.i16(data, i))
return tuple(l) return tuple(l)
load_dispatch[3] = (2, load_short) load_dispatch[3] = (2, load_short)
def load_long(self, data): def load_long(self, data):
@ -386,13 +388,15 @@ class ImageFileDirectory(collections.MutableMapping):
for i in range(0, len(data), 4): for i in range(0, len(data), 4):
l.append(self.i32(data, i)) l.append(self.i32(data, i))
return tuple(l) return tuple(l)
load_dispatch[4] = (4, load_long) load_dispatch[4] = (4, load_long)
def load_rational(self, data): def load_rational(self, data):
l = [] l = []
for i in range(0, len(data), 8): for i in range(0, len(data), 8):
l.append((self.i32(data, i), self.i32(data, i+4))) l.append((self.i32(data, i), self.i32(data, i + 4)))
return tuple(l) return tuple(l)
load_dispatch[5] = (8, load_rational) load_dispatch[5] = (8, load_rational)
def load_float(self, data): def load_float(self, data):
@ -400,6 +404,7 @@ class ImageFileDirectory(collections.MutableMapping):
if self.prefix != native_prefix: if self.prefix != native_prefix:
a.byteswap() a.byteswap()
return tuple(a) return tuple(a)
load_dispatch[11] = (4, load_float) load_dispatch[11] = (4, load_float)
def load_double(self, data): def load_double(self, data):
@ -407,11 +412,13 @@ class ImageFileDirectory(collections.MutableMapping):
if self.prefix != native_prefix: if self.prefix != native_prefix:
a.byteswap() a.byteswap()
return tuple(a) return tuple(a)
load_dispatch[12] = (8, load_double) load_dispatch[12] = (8, load_double)
def load_undefined(self, data): def load_undefined(self, data):
# Untyped data # Untyped data
return data return data
load_dispatch[7] = (1, load_undefined) load_dispatch[7] = (1, load_undefined)
def load(self, fp): def load(self, fp):
@ -458,7 +465,7 @@ class ImageFileDirectory(collections.MutableMapping):
data = ImageFile._safe_read(fp, size) data = ImageFile._safe_read(fp, size)
fp.seek(here) fp.seek(here)
else: else:
data = ifd[8:8+size] data = ifd[8:8 + size]
if len(data) != size: if len(data) != size:
warnings.warn("Possibly corrupt EXIF data. " warnings.warn("Possibly corrupt EXIF data. "
@ -506,7 +513,7 @@ class ImageFileDirectory(collections.MutableMapping):
typ = self.tagtype[tag] typ = self.tagtype[tag]
if Image.DEBUG: if Image.DEBUG:
print ("Tag %s, Type: %s, Value: %s" % (tag, typ, value)) print("Tag %s, Type: %s, Value: %s" % (tag, typ, value))
if typ == 1: if typ == 1:
# byte data # byte data
@ -567,7 +574,8 @@ class ImageFileDirectory(collections.MutableMapping):
if len(data) == 4: if len(data) == 4:
append((tag, typ, len(value), data, b"")) append((tag, typ, len(value), data, b""))
elif len(data) < 4: 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: else:
count = len(value) count = len(value)
if typ == 5: if typ == 5:
@ -602,10 +610,10 @@ class ImageFileDirectory(collections.MutableMapping):
return offset return offset
## ##
# Image plugin for TIFF files. # Image plugin for TIFF files.
class TiffImageFile(ImageFile.ImageFile): class TiffImageFile(ImageFile.ImageFile):
format = "TIFF" format = "TIFF"
@ -629,9 +637,9 @@ class TiffImageFile(ImageFile.ImageFile):
self.__fp = self.fp self.__fp = self.fp
if Image.DEBUG: if Image.DEBUG:
print ("*** TiffImageFile._open ***") print("*** TiffImageFile._open ***")
print ("- __first:", self.__first) print("- __first:", self.__first)
print ("- ifh: ", ifh) print("- ifh: ", ifh)
# and load the first frame # and load the first frame
self._seek(0) self._seek(0)
@ -661,7 +669,8 @@ class TiffImageFile(ImageFile.ImageFile):
if not self.__next: if not self.__next:
raise EOFError("no more images in TIFF file") raise EOFError("no more images in TIFF file")
if Image.DEBUG: 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())) (frame, self.__frame, self.__next, self.fp.tell()))
# reset python3 buffered io handle in case fp # reset python3 buffered io handle in case fp
# was passed to libtiff, invalidating the buffer # was passed to libtiff, invalidating the buffer
@ -697,7 +706,7 @@ class TiffImageFile(ImageFile.ImageFile):
args = rawmode args = rawmode
if 317 in self.tag: if 317 in self.tag:
# Section 14: Differencing Predictor # Section 14: Differencing Predictor
self.decoderconfig = (self.tag[PREDICTOR][0],) self.decoderconfig = (self.tag[PREDICTOR][0], )
if ICCPROFILE in self.tag: if ICCPROFILE in self.tag:
self.info['icc_profile'] = self.tag[ICCPROFILE] self.info['icc_profile'] = self.tag[ICCPROFILE]
@ -723,7 +732,7 @@ class TiffImageFile(ImageFile.ImageFile):
# (self._compression, (extents tuple), # (self._compression, (extents tuple),
# 0, (rawmode, self._compression, fp)) # 0, (rawmode, self._compression, fp))
ignored, extents, ignored_2, args = self.tile[0] ignored, extents, ignored_2, args = self.tile[0]
args = args + (self.ifd.offset,) args = args + (self.ifd.offset, )
decoder = Image._getdecoder(self.mode, 'libtiff', args, decoder = Image._getdecoder(self.mode, 'libtiff', args,
self.decoderconfig) self.decoderconfig)
try: try:
@ -742,19 +751,19 @@ class TiffImageFile(ImageFile.ImageFile):
# that returns an IOError if there's no underlying fp. Easier to # that returns an IOError if there's no underlying fp. Easier to
# dea. with here by reordering. # dea. with here by reordering.
if Image.DEBUG: if Image.DEBUG:
print ("have getvalue. just sending in a string from getvalue") print("have getvalue. just sending in a string from getvalue")
n, err = decoder.decode(self.fp.getvalue()) n, err = decoder.decode(self.fp.getvalue())
elif hasattr(self.fp, "fileno"): elif hasattr(self.fp, "fileno"):
# we've got a actual file on disk, pass in the fp. # we've got a actual file on disk, pass in the fp.
if Image.DEBUG: if Image.DEBUG:
print ("have fileno, calling fileno version of the decoder.") print("have fileno, calling fileno version of the decoder.")
self.fp.seek(0) self.fp.seek(0)
# 4 bytes, otherwise the trace might error out # 4 bytes, otherwise the trace might error out
n, err = decoder.decode(b"fpfp") n, err = decoder.decode(b"fpfp")
else: else:
# we have something else. # we have something else.
if Image.DEBUG: if Image.DEBUG:
print ("don't have fileno or getvalue. just reading") print("don't have fileno or getvalue. just reading")
# UNDONE -- so much for that buffer size thing. # UNDONE -- so much for that buffer size thing.
n, err = decoder.decode(self.fp.read()) n, err = decoder.decode(self.fp.read())
@ -809,11 +818,9 @@ class TiffImageFile(ImageFile.ImageFile):
format = getscalar(SAMPLEFORMAT, 1) format = getscalar(SAMPLEFORMAT, 1)
# mode: check photometric interpretation and bits per pixel # mode: check photometric interpretation and bits per pixel
key = ( key = (self.tag.prefix, photo, format, fillorder,
self.tag.prefix, photo, format, fillorder, self.tag.get(BITSPERSAMPLE,
self.tag.get(BITSPERSAMPLE, (1,)), (1, )), self.tag.get(EXTRASAMPLES, ()))
self.tag.get(EXTRASAMPLES, ())
)
if Image.DEBUG: if Image.DEBUG:
print("format key:", key) print("format key:", key)
try: try:
@ -855,14 +862,11 @@ class TiffImageFile(ImageFile.ImageFile):
offsets = self.tag[STRIPOFFSETS] offsets = self.tag[STRIPOFFSETS]
h = getscalar(ROWSPERSTRIP, ysize) h = getscalar(ROWSPERSTRIP, ysize)
w = self.size[0] w = self.size[0]
if READ_LIBTIFF or self._compression in ["tiff_ccitt", "group3", if READ_LIBTIFF or self._compression in [
"group4", "tiff_jpeg", "tiff_ccitt", "group3", "group4", "tiff_jpeg",
"tiff_adobe_deflate", "tiff_adobe_deflate", "tiff_thunderscan", "tiff_deflate",
"tiff_thunderscan", "tiff_sgilog", "tiff_sgilog24", "tiff_raw_16"
"tiff_deflate", ]:
"tiff_sgilog",
"tiff_sgilog24",
"tiff_raw_16"]:
# if Image.DEBUG: # if Image.DEBUG:
# print "Activating g4 compression for whole file" # print "Activating g4 compression for whole file"
@ -899,11 +903,9 @@ class TiffImageFile(ImageFile.ImageFile):
# bits, so stripes of the image are reversed. See # bits, so stripes of the image are reversed. See
# https://github.com/python-pillow/Pillow/issues/279 # https://github.com/python-pillow/Pillow/issues/279
if fillorder == 2: if fillorder == 2:
key = ( key = (self.tag.prefix, photo, format, 1,
self.tag.prefix, photo, format, 1, self.tag.get(BITSPERSAMPLE,
self.tag.get(BITSPERSAMPLE, (1,)), (1, )), self.tag.get(EXTRASAMPLES, ()))
self.tag.get(EXTRASAMPLES, ())
)
if Image.DEBUG: if Image.DEBUG:
print("format key:", key) print("format key:", key)
# this should always work, since all the # this should always work, since all the
@ -920,21 +922,17 @@ class TiffImageFile(ImageFile.ImageFile):
# Offset in the tile tuple is 0, we go from 0,0 to # Offset in the tile tuple is 0, we go from 0,0 to
# w,h, and we only do this once -- eds # w,h, and we only do this once -- eds
a = (rawmode, self._compression, fp) a = (rawmode, self._compression, fp)
self.tile.append( self.tile.append((self._compression, (0, 0, w, ysize), 0, a))
(self._compression,
(0, 0, w, ysize),
0, a))
a = None a = None
else: else:
for i in range(len(offsets)): for i in range(len(offsets)):
a = self._decoder(rawmode, l, i) a = self._decoder(rawmode, l, i)
self.tile.append( self.tile.append((self._compression,
(self._compression, (0, min(y, ysize), w, min(y + h, ysize)),
(0, min(y, ysize), w, min(y+h, ysize)),
offsets[i], a)) offsets[i], a))
if Image.DEBUG: if Image.DEBUG:
print ("tiles: ", self.tile) print("tiles: ", self.tile)
y = y + h y = y + h
if y >= self.size[1]: if y >= self.size[1]:
x = y = 0 x = y = 0
@ -950,10 +948,8 @@ class TiffImageFile(ImageFile.ImageFile):
a = self._decoder(rawmode, l) a = self._decoder(rawmode, l)
# FIXME: this doesn't work if the image size # FIXME: this doesn't work if the image size
# is not a multiple of the tile size... # is not a multiple of the tile size...
self.tile.append( self.tile.append((self._compression, (x, y, x + w, y + h), o,
(self._compression, a))
(x, y, x+w, y+h),
o, a))
x = x + w x = x + w
if x >= self.size[0]: if x >= self.size[0]:
x, y = 0, y + h x, y = 0, y + h
@ -981,33 +977,32 @@ class TiffImageFile(ImageFile.ImageFile):
SAVE_INFO = { SAVE_INFO = {
# mode => rawmode, byteorder, photometrics, # mode => rawmode, byteorder, photometrics,
# sampleformat, bitspersample, extra # sampleformat, bitspersample, extra
"1": ("1", II, 1, 1, (1,), None), "1": ("1", II, 1, 1, (1, ), None),
"L": ("L", II, 1, 1, (8,), None), "L": ("L", II, 1, 1, (8, ), None),
"LA": ("LA", II, 1, 1, (8, 8), 2), "LA": ("LA", II, 1, 1, (8, 8), 2),
"P": ("P", II, 3, 1, (8,), None), "P": ("P", II, 3, 1, (8, ), None),
"PA": ("PA", II, 3, 1, (8, 8), 2), "PA": ("PA", II, 3, 1, (8, 8), 2),
"I": ("I;32S", II, 1, 2, (32,), None), "I": ("I;32S", II, 1, 2, (32, ), None),
"I;16": ("I;16", II, 1, 1, (16,), None), "I;16": ("I;16", II, 1, 1, (16, ), None),
"I;16S": ("I;16S", II, 1, 2, (16,), None), "I;16S": ("I;16S", II, 1, 2, (16, ), None),
"F": ("F;32F", II, 1, 3, (32,), None), "F": ("F;32F", II, 1, 3, (32, ), None),
"RGB": ("RGB", II, 2, 1, (8, 8, 8), None), "RGB": ("RGB", II, 2, 1, (8, 8, 8), None),
"RGBX": ("RGBX", II, 2, 1, (8, 8, 8, 8), 0), "RGBX": ("RGBX", II, 2, 1, (8, 8, 8, 8), 0),
"RGBA": ("RGBA", II, 2, 1, (8, 8, 8, 8), 2), "RGBA": ("RGBA", II, 2, 1, (8, 8, 8, 8), 2),
"CMYK": ("CMYK", II, 5, 1, (8, 8, 8, 8), None), "CMYK": ("CMYK", II, 5, 1, (8, 8, 8, 8), None),
"YCbCr": ("YCbCr", II, 6, 1, (8, 8, 8), None), "YCbCr": ("YCbCr", II, 6, 1, (8, 8, 8), None),
"LAB": ("LAB", II, 8, 1, (8, 8, 8), None), "LAB": ("LAB", II, 8, 1, (8, 8, 8), None),
"I;32BS": ("I;32BS", MM, 1, 2, (32, ), None),
"I;32BS": ("I;32BS", MM, 1, 2, (32,), None), "I;16B": ("I;16B", MM, 1, 1, (16, ), None),
"I;16B": ("I;16B", MM, 1, 1, (16,), None), "I;16BS": ("I;16BS", MM, 1, 2, (16, ), None),
"I;16BS": ("I;16BS", MM, 1, 2, (16,), None), "F;32BF": ("F;32BF", MM, 1, 3, (32, ), None),
"F;32BF": ("F;32BF", MM, 1, 3, (32,), None),
} }
def _cvt_res(value): def _cvt_res(value):
# convert value to TIFF rational number -- (numerator, denominator) # convert value to TIFF rational number -- (numerator, denominator)
if isinstance(value, collections.Sequence): if isinstance(value, collections.Sequence):
assert(len(value) % 2 == 0) assert (len(value) % 2 == 0)
return value return value
if isinstance(value, int): if isinstance(value, int):
return (value, 1) return (value, 1)
@ -1073,13 +1068,15 @@ def _save(im, fp, filename):
(X_RESOLUTION, "resolution", _cvt_res), (X_RESOLUTION, "resolution", _cvt_res),
(Y_RESOLUTION, "resolution", _cvt_res), (Y_RESOLUTION, "resolution", _cvt_res),
(X_RESOLUTION, "x_resolution", _cvt_res), (X_RESOLUTION, "x_resolution", _cvt_res),
(Y_RESOLUTION, "y_resolution", _cvt_res), (Y_RESOLUTION, "y_resolution", _cvt_res), (
(RESOLUTION_UNIT, "resolution_unit", RESOLUTION_UNIT, "resolution_unit",
lambda x: {"inch": 2, "cm": 3, "centimeter": 3}.get(x, 1)), lambda x: {"inch": 2,
(SOFTWARE, "software", lambda x: x), "cm": 3,
(DATE_TIME, "date_time", lambda x: x), "centimeter": 3}.get(x, 1)
(ARTIST, "artist", lambda x: x), ), (SOFTWARE, "software", lambda x: x),
(COPYRIGHT, "copyright", 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("_", " ") name_with_spaces = name.replace("_", " ")
if "_" in name and name_with_spaces in im.encoderinfo: if "_" in name and name_with_spaces in im.encoderinfo:
warnings.warn("%r is deprecated; use %r instead" % warnings.warn("%r is deprecated; use %r instead" %
@ -1094,7 +1091,7 @@ def _save(im, fp, filename):
ifd[X_RESOLUTION] = _cvt_res(dpi[0]) ifd[X_RESOLUTION] = _cvt_res(dpi[0])
ifd[Y_RESOLUTION] = _cvt_res(dpi[1]) ifd[Y_RESOLUTION] = _cvt_res(dpi[1])
if bits != (1,): if bits != (1, ):
ifd[BITSPERSAMPLE] = bits ifd[BITSPERSAMPLE] = bits
if len(bits) != 1: if len(bits) != 1:
ifd[SAMPLESPERPIXEL] = len(bits) ifd[SAMPLESPERPIXEL] = len(bits)
@ -1110,7 +1107,7 @@ def _save(im, fp, filename):
ifd[COLORMAP] = tuple(i8(v) * 256 for v in lut) ifd[COLORMAP] = tuple(i8(v) * 256 for v in lut)
# data orientation # data orientation
stride = len(bits) * ((im.size[0]*bits[0]+7)//8) stride = len(bits) * ((im.size[0] * bits[0] + 7) // 8)
ifd[ROWSPERSTRIP] = im.size[1] ifd[ROWSPERSTRIP] = im.size[1]
ifd[STRIPBYTECOUNTS] = stride * im.size[1] ifd[STRIPBYTECOUNTS] = stride * im.size[1]
ifd[STRIPOFFSETS] = 0 # this is adjusted by IFD writer ifd[STRIPOFFSETS] = 0 # this is adjusted by IFD writer
@ -1119,8 +1116,8 @@ def _save(im, fp, filename):
if libtiff: if libtiff:
if Image.DEBUG: if Image.DEBUG:
print ("Saving using libtiff encoder") print("Saving using libtiff encoder")
print (ifd.items()) print(ifd.items())
_fp = 0 _fp = 0
if hasattr(fp, "fileno"): if hasattr(fp, "fileno"):
try: try:
@ -1144,16 +1141,15 @@ def _save(im, fp, filename):
# A tuple of more than one rational tuples # A tuple of more than one rational tuples
# flatten to floats, # flatten to floats,
# following tiffcp.c->cpTag->TIFF_RATIONAL # following tiffcp.c->cpTag->TIFF_RATIONAL
atts[k] = [float(elt[0])/float(elt[1]) for elt in v] atts[k] = [float(elt[0]) / float(elt[1]) for elt in v]
continue continue
if type(v[0]) == tuple and len(v) == 1: if type(v[0]) == tuple and len(v) == 1:
# A tuple of one rational tuples # A tuple of one rational tuples
# flatten to floats, # flatten to floats,
# following tiffcp.c->cpTag->TIFF_RATIONAL # following tiffcp.c->cpTag->TIFF_RATIONAL
atts[k] = float(v[0][0])/float(v[0][1]) atts[k] = float(v[0][0]) / float(v[0][1])
continue continue
if (type(v) == tuple and if (type(v) == tuple and (len(v) > 2 or
(len(v) > 2 or
(len(v) == 2 and v[1] == 0))): (len(v) == 2 and v[1] == 0))):
# List of ints? # List of ints?
# Avoid divide by zero in next if-clause # Avoid divide by zero in next if-clause
@ -1164,7 +1160,7 @@ def _save(im, fp, filename):
# one rational tuple # one rational tuple
# flatten to float, # flatten to float,
# following tiffcp.c->cpTag->TIFF_RATIONAL # following tiffcp.c->cpTag->TIFF_RATIONAL
atts[k] = float(v[0])/float(v[1]) atts[k] = float(v[0]) / float(v[1])
continue continue
if type(v) == tuple and len(v) == 1: if type(v) == tuple and len(v) == 1:
v = v[0] v = v[0]
@ -1177,7 +1173,7 @@ def _save(im, fp, filename):
atts[k] = v atts[k] = v
if Image.DEBUG: if Image.DEBUG:
print (atts) print(atts)
# libtiff always expects the bytes in native order. # libtiff always expects the bytes in native order.
# we're storing image byte order. So, if the rawmode # we're storing image byte order. So, if the rawmode
@ -1189,10 +1185,10 @@ def _save(im, fp, filename):
a = (rawmode, compression, _fp, filename, atts) a = (rawmode, compression, _fp, filename, atts)
# print (im.mode, compression, a, im.encoderconfig) # print (im.mode, compression, a, im.encoderconfig)
e = Image._getencoder(im.mode, 'libtiff', a, im.encoderconfig) e = Image._getencoder(im.mode, 'libtiff', a, im.encoderconfig)
e.setimage(im.im, (0, 0)+im.size) e.setimage(im.im, (0, 0) + im.size)
while True: while True:
# undone, change to self.decodermaxblock: # undone, change to self.decodermaxblock:
l, s, d = e.encode(16*1024) l, s, d = e.encode(16 * 1024)
if not _fp: if not _fp:
fp.write(d) fp.write(d)
if s: if s:
@ -1203,9 +1199,8 @@ def _save(im, fp, filename):
else: else:
offset = ifd.save(fp) offset = ifd.save(fp)
ImageFile._save(im, fp, [ ImageFile._save(im, fp, [("raw", (0, 0) + im.size, offset,
("raw", (0, 0)+im.size, offset, (rawmode, stride, 1)) (rawmode, stride, 1))])
])
# -- helper for multi-page save -- # -- helper for multi-page save --
if "_debug_multipage" in im.encoderinfo: if "_debug_multipage" in im.encoderinfo:

View File

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

View File

@ -31,7 +31,6 @@ except ImportError:
i32 = _binary.i32le i32 = _binary.i32le
## ##
# Load texture from a Quake2 WAL texture file. # Load texture from a Quake2 WAL texture file.
# <p> # <p>
@ -41,6 +40,7 @@ i32 = _binary.i32le
# @param filename WAL file name, or an opened file handle. # @param filename WAL file name, or an opened file handle.
# @return An image instance. # @return An image instance.
def open(filename): def open(filename):
# FIXME: modify to return a WalImageFile instance instead of # FIXME: modify to return a WalImageFile instance instead of
# plain Image object ? # plain Image object ?
@ -51,7 +51,7 @@ def open(filename):
fp = builtins.open(filename, "rb") fp = builtins.open(filename, "rb")
# read header fields # read header fields
header = fp.read(32+24+32+12) header = fp.read(32 + 24 + 32 + 12)
size = i32(header, 32), i32(header, 36) size = i32(header, 32), i32(header, 36)
offset = i32(header, 40) offset = i32(header, 40)
@ -66,15 +66,14 @@ def open(filename):
# strings are null-terminated # strings are null-terminated
im.info["name"] = header[:32].split(b"\0", 1)[0] im.info["name"] = header[:32].split(b"\0", 1)[0]
next_name = header[56:56+32].split(b"\0", 1)[0] next_name = header[56:56 + 32].split(b"\0", 1)[0]
if next_name: if next_name:
im.info["next_name"] = next_name im.info["next_name"] = next_name
return im return im
quake2palette = ( quake2palette = ( # default palette taken from piffo 0.93 by Hans Häggström
# 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"\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"\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" 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"\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"\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\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__": if __name__ == "__main__":
im = open("../hacks/sample.wal") im = open("../hacks/sample.wal")

View File

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

View File

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

View File

@ -28,12 +28,13 @@ PALETTE = b""
for r in range(8): for r in range(8):
for g in range(8): for g in range(8):
for b in range(4): 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. # Image plugin for XV thumbnail images.
class XVThumbImageFile(ImageFile.ImageFile): class XVThumbImageFile(ImageFile.ImageFile):
format = "XVThumb" format = "XVThumb"
@ -65,10 +66,8 @@ class XVThumbImageFile(ImageFile.ImageFile):
self.palette = ImagePalette.raw("RGB", PALETTE) self.palette = ImagePalette.raw("RGB", PALETTE)
self.tile = [ self.tile = [("raw", (0, 0) + self.size, self.fp.tell(),
("raw", (0, 0)+self.size, (self.mode, 0, 1))]
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]+[^_]*_x_hot[ \t]+(?P<xhot>[0-9]+)[\r\n]+"
b"#define[ \t]+[^_]*_y_hot[ \t]+(?P<yhot>[0-9]+)[\r\n]+" b"#define[ \t]+[^_]*_y_hot[ \t]+(?P<yhot>[0-9]+)[\r\n]+"
b")?" b")?"
b"[\\000-\\377]*_bits\\[\\]" b"[\\000-\\377]*_bits\\[\\]")
)
def _accept(prefix): def _accept(prefix):
return prefix.lstrip()[:7] == b"#define" return prefix.lstrip()[:7] == b"#define"
## ##
# Image plugin for X11 bitmaps. # Image plugin for X11 bitmaps.
class XbmImageFile(ImageFile.ImageFile): class XbmImageFile(ImageFile.ImageFile):
format = "XBM" format = "XBM"
@ -58,14 +57,13 @@ class XbmImageFile(ImageFile.ImageFile):
ysize = int(m.group("height")) ysize = int(m.group("height"))
if m.group("hotspot"): if m.group("hotspot"):
self.info["hotspot"] = ( self.info["hotspot"] = (int(m.group("xhot")),
int(m.group("xhot")), int(m.group("yhot")) int(m.group("yhot")))
)
self.mode = "1" self.mode = "1"
self.size = xsize, ysize self.size = xsize, ysize
self.tile = [("xbm", (0, 0)+self.size, m.end(), None)] self.tile = [("xbm", (0, 0) + self.size, m.end(), None)]
def _save(im, fp, filename): def _save(im, fp, filename):
@ -83,7 +81,7 @@ def _save(im, fp, filename):
fp.write(b"static char im_bits[] = {\n") fp.write(b"static char im_bits[] = {\n")
ImageFile._save(im, fp, [("xbm", (0, 0)+im.size, 0, None)]) ImageFile._save(im, fp, [("xbm", (0, 0) + im.size, 0, None)])
fp.write(b"};\n") fp.write(b"};\n")

View File

@ -14,10 +14,8 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
__version__ = "0.2" __version__ = "0.2"
import re import re
from PIL import Image, ImageFile, ImagePalette from PIL import Image, ImageFile, ImagePalette
from PIL._binary import i8, o8 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): def _accept(prefix):
return prefix[:9] == b"/* XPM */" return prefix[:9] == b"/* XPM */"
## ##
# Image plugin for X11 pixel maps. # Image plugin for X11 pixel maps.
class XpmImageFile(ImageFile.ImageFile): class XpmImageFile(ImageFile.ImageFile):
format = "XPM" format = "XPM"
@ -81,15 +79,14 @@ class XpmImageFile(ImageFile.ImageFile):
if s[i] == b"c": if s[i] == b"c":
# process colour key # process colour key
rgb = s[i+1] rgb = s[i + 1]
if rgb == b"None": if rgb == b"None":
self.info["transparency"] = c self.info["transparency"] = c
elif rgb[0:1] == b"#": elif rgb[0:1] == b"#":
# FIXME: handle colour names (see ImagePalette.py) # FIXME: handle colour names (see ImagePalette.py)
rgb = int(rgb[1:], 16) rgb = int(rgb[1:], 16)
palette[c] = (o8((rgb >> 16) & 255) + palette[c] = (o8((rgb >> 16) & 255) + o8(
o8((rgb >> 8) & 255) + (rgb >> 8) & 255) + o8(rgb & 255))
o8(rgb & 255))
else: else:
# unknown colour # unknown colour
raise ValueError("cannot read this XPM file") raise ValueError("cannot read this XPM file")
@ -103,7 +100,7 @@ class XpmImageFile(ImageFile.ImageFile):
self.mode = "P" self.mode = "P"
self.palette = ImagePalette.raw("RGB", b"".join(palette)) self.palette = ImagePalette.raw("RGB", b"".join(palette))
self.tile = [("raw", (0, 0)+self.size, self.fp.tell(), ("P", 0, 1))] self.tile = [("raw", (0, 0) + self.size, self.fp.tell(), ("P", 0, 1))]
def load_read(self, bytes): def load_read(self, bytes):
@ -115,7 +112,7 @@ class XpmImageFile(ImageFile.ImageFile):
s = [None] * ysize s = [None] * ysize
for i in range(ysize): for i in range(ysize):
s[i] = self.fp.readline()[1:xsize+1].ljust(xsize) s[i] = self.fp.readline()[1:xsize + 1].ljust(xsize)
self.fp = None self.fp = None

View File

@ -14,45 +14,17 @@
VERSION = '1.1.7' # PIL version VERSION = '1.1.7' # PIL version
PILLOW_VERSION = '2.9.0.dev0' # Pillow PILLOW_VERSION = '2.9.0.dev0' # Pillow
_plugins = ['BmpImagePlugin', _plugins = ['BmpImagePlugin', 'BufrStubImagePlugin', 'CurImagePlugin',
'BufrStubImagePlugin', 'DcxImagePlugin', 'EpsImagePlugin', 'FitsStubImagePlugin',
'CurImagePlugin', 'FliImagePlugin', 'FpxImagePlugin', 'GbrImagePlugin',
'DcxImagePlugin', 'GifImagePlugin', 'GribStubImagePlugin', 'Hdf5StubImagePlugin',
'EpsImagePlugin', 'IcnsImagePlugin', 'IcoImagePlugin', 'ImImagePlugin',
'FitsStubImagePlugin', 'ImtImagePlugin', 'IptcImagePlugin', 'JpegImagePlugin',
'FliImagePlugin', 'Jpeg2KImagePlugin', 'McIdasImagePlugin', 'MicImagePlugin',
'FpxImagePlugin', 'MpegImagePlugin', 'MpoImagePlugin', 'MspImagePlugin',
'GbrImagePlugin', 'PalmImagePlugin', 'PcdImagePlugin', 'PcxImagePlugin',
'GifImagePlugin', 'PdfImagePlugin', 'PixarImagePlugin', 'PngImagePlugin',
'GribStubImagePlugin', 'PpmImagePlugin', 'PsdImagePlugin', 'SgiImagePlugin',
'Hdf5StubImagePlugin', 'SpiderImagePlugin', 'SunImagePlugin', 'TgaImagePlugin',
'IcnsImagePlugin', 'TiffImagePlugin', 'WebPImagePlugin', 'WmfImagePlugin',
'IcoImagePlugin', 'XbmImagePlugin', 'XpmImagePlugin', 'XVThumbImagePlugin']
'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,17 +14,19 @@
from struct import unpack, pack from struct import unpack, pack
if bytes is str: if bytes is str:
def i8(c): def i8(c):
return ord(c) return ord(c)
def o8(i): def o8(i):
return chr(i & 255) return chr(i & 255)
else: else:
def i8(c): def i8(c):
return c if c.__class__ is int else c[0] return c if c.__class__ is int else c[0]
def o8(i): def o8(i):
return bytes((i & 255,)) return bytes((i & 255, ))
# Input, le = little endian, be = big endian # Input, le = little endian, be = big endian
@ -36,7 +38,7 @@ def i16le(c, o=0):
c: string containing bytes to convert c: string containing bytes to convert
o: offset of bytes to convert in string o: offset of bytes to convert in string
""" """
return unpack("<H", c[o:o+2])[0] return unpack("<H", c[o:o + 2])[0]
def i32le(c, o=0): def i32le(c, o=0):
@ -46,15 +48,15 @@ def i32le(c, o=0):
c: string containing bytes to convert c: string containing bytes to convert
o: offset of bytes to convert in string o: offset of bytes to convert in string
""" """
return unpack("<I", c[o:o+4])[0] return unpack("<I", c[o:o + 4])[0]
def i16be(c, o=0): def i16be(c, o=0):
return unpack(">H", c[o:o+2])[0] return unpack(">H", c[o:o + 2])[0]
def i32be(c, o=0): def i32be(c, o=0):
return unpack(">I", c[o:o+4])[0] return unpack(">I", c[o:o + 4])[0]
# Output, le = little endian, be = big endian # Output, le = little endian, be = big endian

View File

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