mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-08-09 23:04:45 +03:00
Just for fun, yapf-formatting of PIL/*.py
And amazingly all tests pass! https://github.com/google/yapf
This commit is contained in:
parent
d754598f14
commit
3bb6b14313
|
@ -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("-")
|
||||||
|
|
||||||
|
|
|
@ -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),
|
||||||
24: [(0xff0000, 0xff00, 0xff)],
|
(0xff0000, 0xff00, 0xff, 0xff000000),
|
||||||
16: [(0xf800, 0x7e0, 0x1f), (0x7c00, 0x3e0, 0x1f)]}
|
(0x0, 0x0, 0x0, 0x0)],
|
||||||
|
24: [(0xff0000, 0xff00, 0xff)],
|
||||||
|
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",
|
||||||
(24, (0xff0000, 0xff00, 0xff)): "BGR",
|
(32, (0xff0000, 0xff00, 0xff, 0xff000000)): "BGRA",
|
||||||
(16, (0xf800, 0x7e0, 0x1f)): "BGR;16", (16, (0x7c00, 0x3e0, 0x1f)): "BGR;15"}
|
(32, (0x0, 0x0, 0x0, 0x0)): "BGRA",
|
||||||
|
(24, (0xff0000, 0xff00, 0xff)): "BGR",
|
||||||
|
(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,30 +276,30 @@ 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
|
||||||
|
|
||||||
# bitmap info header
|
# bitmap info header
|
||||||
fp.write(o32(header) + # info header size
|
fp.write(o32(header) + # info header size
|
||||||
o32(im.size[0]) + # width
|
o32(im.size[0]) + # width
|
||||||
o32(im.size[1]) + # height
|
o32(im.size[1]) + # height
|
||||||
o16(1) + # planes
|
o16(1) + # planes
|
||||||
o16(bits) + # depth
|
o16(bits) + # depth
|
||||||
o32(0) + # compression (0=uncompressed)
|
o32(0) + # compression (0=uncompressed)
|
||||||
o32(image) + # size of bitmap
|
o32(image) + # size of bitmap
|
||||||
o32(ppm[0]) + o32(ppm[1]) + # resolution
|
o32(ppm[0]) + o32(ppm[1]) + # resolution
|
||||||
o32(colors) + # colors used
|
o32(colors) + # colors used
|
||||||
o32(colors)) # colors important
|
o32(colors)) # colors important
|
||||||
|
|
||||||
fp.write(b"\0" * (header - 40)) # padding (for OS/2 format)
|
fp.write(b"\0" * (header - 40)) # padding (for OS/2 format)
|
||||||
|
|
||||||
if im.mode == "1":
|
if im.mode == "1":
|
||||||
for i in (0, 255):
|
for i in (0, 255):
|
||||||
|
@ -268,8 +310,8 @@ 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))])
|
||||||
|
|
||||||
#
|
#
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
@ -68,17 +66,16 @@ class CurImageFile(BmpImagePlugin.BmpImageFile):
|
||||||
# print "bytes", i32(s[8:])
|
# print "bytes", i32(s[8:])
|
||||||
# print "offset", i32(s[12:])
|
# print "offset", i32(s[12:])
|
||||||
|
|
||||||
# load as bitmap
|
# load as bitmap
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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,25 +112,24 @@ 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,
|
# safe mode
|
||||||
# safe mode
|
"-sDEVICE=ppmraw", # ppm driver
|
||||||
"-sDEVICE=ppmraw", # ppm driver
|
|
||||||
"-sOutputFile=%s" % outfile, # output file
|
"-sOutputFile=%s" % outfile, # output file
|
||||||
"-c", "%d %d translate" % (-bbox[0], -bbox[1]),
|
"-c", "%d %d translate" % (-bbox[0], -bbox[1]),
|
||||||
# adjust for image origin
|
# adjust for image origin
|
||||||
"-f", infile, # input file
|
"-f", infile, # input file
|
||||||
]
|
]
|
||||||
|
|
||||||
if gs_windows_binary is not None:
|
if gs_windows_binary is not None:
|
||||||
if not gs_windows_binary:
|
if not gs_windows_binary:
|
||||||
|
@ -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")
|
||||||
|
|
|
@ -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",
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,17 +150,17 @@ 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,8 +182,8 @@ 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
|
||||||
# data must be placed in the tile descriptor itself!
|
# data must be placed in the tile descriptor itself!
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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":
|
||||||
|
|
|
@ -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,10 +188,8 @@ 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),
|
(bits, interlace))]
|
||||||
self.__offset,
|
|
||||||
(bits, interlace))]
|
|
||||||
break
|
break
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
@ -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,24 +319,21 @@ 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
|
o8(transparency) + # transparency index
|
||||||
o8(transparency) + # transparency index
|
|
||||||
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]) + o8(flags) + # flags
|
||||||
o16(im.size[1]) +
|
o8(8)) # bits
|
||||||
o8(flags) + # flags
|
|
||||||
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,11 +404,10 @@ 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
|
]
|
||||||
]
|
|
||||||
|
|
||||||
if im.mode == "P":
|
if im.mode == "P":
|
||||||
if palette and isinstance(palette, bytes):
|
if palette and isinstance(palette, bytes):
|
||||||
|
@ -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
|
o8(8)) # bits
|
||||||
o16(im.size[1]) +
|
|
||||||
o8(0) + # flags
|
|
||||||
o8(8)) # bits
|
|
||||||
|
|
||||||
ImageFile._save(im, fp, [("gif", (0, 0)+im.size, 0, RAWMODE[im.mode])])
|
ImageFile._save(im, fp, [("gif",
|
||||||
|
(0, 0) + im.size, 0, RAWMODE[im.mode])])
|
||||||
|
|
||||||
fp.write(b"\0") # end of image data
|
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)
|
||||||
|
|
|
@ -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":
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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'it32', read_32t),
|
||||||
(b'ic14', read_png_or_jpeg2000),
|
(b't8mk', read_mk), ],
|
||||||
],
|
(64, 64, 1): [(b'icp6', read_png_or_jpeg2000), ],
|
||||||
(256, 256, 1): [
|
(32, 32, 2): [(b'ic12', read_png_or_jpeg2000), ],
|
||||||
(b'ic08', read_png_or_jpeg2000),
|
(48, 48, 1): [(b'ih32', read_32),
|
||||||
],
|
(b'h8mk', read_mk), ],
|
||||||
(128, 128, 2): [
|
(32, 32, 1): [(b'icp5', read_png_or_jpeg2000),
|
||||||
(b'ic13', read_png_or_jpeg2000),
|
(b'il32', read_32),
|
||||||
],
|
(b'l8mk', read_mk), ],
|
||||||
(128, 128, 1): [
|
(16, 16, 2): [(b'ic11', read_png_or_jpeg2000), ],
|
||||||
(b'ic07', read_png_or_jpeg2000),
|
(16, 16, 1): [(b'icp4', read_png_or_jpeg2000),
|
||||||
(b'it32', read_32t),
|
(b'is32', read_32),
|
||||||
(b't8mk', read_mk),
|
(b's8mk', read_mk), ],
|
||||||
],
|
|
||||||
(64, 64, 1): [
|
|
||||||
(b'icp6', read_png_or_jpeg2000),
|
|
||||||
],
|
|
||||||
(32, 32, 2): [
|
|
||||||
(b'ic12', read_png_or_jpeg2000),
|
|
||||||
],
|
|
||||||
(48, 48, 1): [
|
|
||||||
(b'ih32', read_32),
|
|
||||||
(b'h8mk', read_mk),
|
|
||||||
],
|
|
||||||
(32, 32, 1): [
|
|
||||||
(b'icp5', read_png_or_jpeg2000),
|
|
||||||
(b'il32', read_32),
|
|
||||||
(b'l8mk', read_mk),
|
|
||||||
],
|
|
||||||
(16, 16, 2): [
|
|
||||||
(b'ic11', read_png_or_jpeg2000),
|
|
||||||
],
|
|
||||||
(16, 16, 1): [
|
|
||||||
(b'icp4', read_png_or_jpeg2000),
|
|
||||||
(b'is32', read_32),
|
|
||||||
(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')
|
||||||
|
|
||||||
|
|
|
@ -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['nb_color'] != 0 and
|
icon_header['bpp'] or
|
||||||
ceil(log(icon_header['nb_color'],
|
(icon_header['nb_color'] != 0 and
|
||||||
2))) or 256)
|
ceil(log(icon_header['nb_color'], 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)
|
||||||
|
|
||||||
|
@ -195,11 +196,11 @@ class IcoFile:
|
||||||
|
|
||||||
# convert to an 8bpp grayscale image
|
# convert to an 8bpp grayscale image
|
||||||
mask = Image.frombuffer(
|
mask = Image.frombuffer(
|
||||||
'L', # 8bpp
|
'L', # 8bpp
|
||||||
im.size, # (w, h)
|
im.size, # (w, h)
|
||||||
alpha_bytes, # source chars
|
alpha_bytes, # source chars
|
||||||
'raw', # raw decoder
|
'raw', # raw decoder
|
||||||
('L', 0, -1) # 8bpp inverted, unpadded, reversed
|
('L', 0, -1) # 8bpp inverted, unpadded, reversed
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# get AND image from end of bitmap
|
# get AND image from end of bitmap
|
||||||
|
@ -220,25 +221,25 @@ class IcoFile:
|
||||||
|
|
||||||
# convert raw data to image
|
# convert raw data to image
|
||||||
mask = Image.frombuffer(
|
mask = Image.frombuffer(
|
||||||
'1', # 1 bpp
|
'1', # 1 bpp
|
||||||
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
|
||||||
|
|
||||||
# apply mask image as alpha channel
|
# apply mask image as alpha channel
|
||||||
im = im.convert('RGBA')
|
im = im.convert('RGBA')
|
||||||
im.putalpha(mask)
|
im.putalpha(mask)
|
||||||
|
|
||||||
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.
|
||||||
|
|
|
@ -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,8 +248,8 @@ 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:
|
||||||
pass
|
pass
|
||||||
|
@ -252,13 +258,15 @@ 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))])
|
||||||
|
|
||||||
#
|
#
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
215
PIL/Image.py
215
PIL/Image.py
|
@ -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
|
||||||
|
@ -195,7 +189,6 @@ if hasattr(core, 'DEFAULT_STRATEGY'):
|
||||||
RLE = core.RLE
|
RLE = core.RLE
|
||||||
FIXED = core.FIXED
|
FIXED = core.FIXED
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
# Registries
|
# Registries
|
||||||
|
|
||||||
|
@ -211,25 +204,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':
|
||||||
|
@ -272,7 +262,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())
|
||||||
|
@ -386,7 +376,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:
|
||||||
|
@ -397,17 +387,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
|
||||||
|
@ -424,7 +414,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
|
||||||
|
@ -434,10 +424,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)
|
||||||
|
|
||||||
|
@ -467,16 +457,16 @@ def _getscaleoffset(expr):
|
||||||
try:
|
try:
|
||||||
((a, b, c), d, e) = data # full syntax
|
((a, b, c), d, e) = data # full syntax
|
||||||
if (a is stub and b == "__mul__" and isinstance(c, numbers.Number) and
|
if (a is stub and b == "__mul__" and isinstance(c, numbers.Number) and
|
||||||
d == "__add__" and isinstance(e, numbers.Number)):
|
d == "__add__" and isinstance(e, numbers.Number)):
|
||||||
return c, e
|
return c, e
|
||||||
except TypeError:
|
except TypeError:
|
||||||
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
|
||||||
|
@ -545,7 +535,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
|
||||||
|
@ -562,7 +552,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)
|
||||||
|
@ -594,10 +584,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
|
||||||
|
@ -621,12 +609,8 @@ 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.tobytes()]
|
||||||
self.mode,
|
|
||||||
self.size,
|
|
||||||
self.getpalette(),
|
|
||||||
self.tobytes()]
|
|
||||||
|
|
||||||
def __setstate__(self, state):
|
def __setstate__(self, state):
|
||||||
Image.__init__(self)
|
Image.__init__(self)
|
||||||
|
@ -685,8 +669,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"):
|
||||||
|
@ -704,11 +687,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):
|
||||||
"""
|
"""
|
||||||
|
@ -791,8 +774,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
|
||||||
|
@ -893,11 +880,10 @@ class Image:
|
||||||
if isinstance(t, bytes):
|
if isinstance(t, bytes):
|
||||||
self.im.putpalettealphas(t)
|
self.im.putpalettealphas(t)
|
||||||
elif isinstance(t, int):
|
elif isinstance(t, int):
|
||||||
self.im.putpalettealpha(t,0)
|
self.im.putpalettealpha(t, 0)
|
||||||
else:
|
else:
|
||||||
raise ValueError("Transparency for P mode should" +
|
raise ValueError(
|
||||||
" be bytes or int")
|
"Transparency for P mode should" + " be bytes or int")
|
||||||
|
|
||||||
|
|
||||||
if mode == "P" and palette == ADAPTIVE:
|
if mode == "P" and palette == ADAPTIVE:
|
||||||
im = self.im.quantize(colors)
|
im = self.im.quantize(colors)
|
||||||
|
@ -907,16 +893,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 +922,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 +970,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 +1246,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 +1309,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
|
||||||
|
@ -1546,7 +1530,7 @@ class Image:
|
||||||
|
|
||||||
self.load()
|
self.load()
|
||||||
|
|
||||||
size=tuple(size)
|
size = tuple(size)
|
||||||
if self.size == size:
|
if self.size == size:
|
||||||
return self._new(self.im)
|
return self._new(self.im)
|
||||||
|
|
||||||
|
@ -1582,14 +1566,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 +1819,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 +1836,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 +1873,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 +1916,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 +1932,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 +1951,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 +1964,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 +2050,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 +2100,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 +2162,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 +2179,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 +2193,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), DecompressionBombWarning)
|
||||||
(pixels, MAX_IMAGE_PIXELS),
|
|
||||||
DecompressionBombWarning)
|
|
||||||
|
|
||||||
|
|
||||||
def open(fp, mode="r"):
|
def open(fp, mode="r"):
|
||||||
|
@ -2286,13 +2263,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 +2366,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 +2417,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 +2430,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.
|
||||||
|
|
|
@ -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, flags)
|
||||||
intent,
|
|
||||||
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,18 +439,18 @@ 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"]):
|
||||||
"""
|
"""
|
||||||
(pyCMS) Builds an ICC transform mapping from the inputProfile to the
|
(pyCMS) Builds an ICC transform mapping from the inputProfile to the
|
||||||
outputProfile, but tries to simulate the result that would be
|
outputProfile, but tries to simulate the result that would be
|
||||||
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
||||||
)
|
|
||||||
|
|
|
@ -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,10 +128,9 @@ 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
|
||||||
|
|
||||||
self.path = font
|
self.path = font
|
||||||
|
@ -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(
|
||||||
size=self.size if size is None else size,
|
font=self.path if font is None else font,
|
||||||
index=self.index if index is None else index,
|
size=self.size if size is None else size,
|
||||||
encoding=self.encoding if encoding is None else
|
index=self.index if index is None else index,
|
||||||
encoding)
|
encoding=self.encoding if encoding is None else encoding)
|
||||||
|
|
||||||
##
|
##
|
||||||
# Wrapper that creates a transposed font from any existing font
|
# Wrapper that creates a transposed font from any existing font
|
||||||
|
@ -252,10 +252,9 @@ 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
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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_":
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,11 +27,11 @@ 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")
|
||||||
|
|
||||||
def getdata(self):
|
def getdata(self):
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -29,18 +29,18 @@ if 'PyQt4.QtGui' not in sys.modules:
|
||||||
except:
|
except:
|
||||||
from PySide.QtGui import QImage, qRgba
|
from PySide.QtGui import QImage, qRgba
|
||||||
|
|
||||||
else: #PyQt4 is used
|
else: #PyQt4 is used
|
||||||
from PyQt4.QtGui import QImage, qRgba
|
from PyQt4.QtGui import QImage, qRgba
|
||||||
|
|
||||||
##
|
##
|
||||||
# (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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,9 +54,8 @@ 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"
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -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:])
|
||||||
|
|
||||||
|
@ -110,19 +106,19 @@ class IptcImageFile(ImageFile.ImageFile):
|
||||||
|
|
||||||
# print tag, self.info[tag]
|
# print tag, self.info[tag]
|
||||||
|
|
||||||
# mode
|
# mode
|
||||||
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))
|
||||||
|
@ -136,7 +132,7 @@ class IptcImageFile(ImageFile.ImageFile):
|
||||||
# tile
|
# tile
|
||||||
if tag == (8, 10):
|
if tag == (8, 10):
|
||||||
self.tile = [("iptc", (compression, offset),
|
self.tile = [("iptc", (compression, offset),
|
||||||
(0, 0, self.size[0], self.size[1]))]
|
(0, 0, self.size[0], self.size[1]))]
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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])
|
||||||
|
@ -116,7 +116,7 @@ def _parse_jp2_header(fp):
|
||||||
meth, prec, approx = struct.unpack('>BBB', content[:3])
|
meth, prec, approx = struct.unpack('>BBB', content[:3])
|
||||||
if meth == 1:
|
if meth == 1:
|
||||||
cs = struct.unpack('>I', content[3:7])[0]
|
cs = struct.unpack('>I', content[3:7])[0]
|
||||||
if cs == 16: # sRGB
|
if cs == 16: # sRGB
|
||||||
if nc == 1 and (bpc & 0x7f) > 8:
|
if nc == 1 and (bpc & 0x7f) > 8:
|
||||||
mode = 'I;16'
|
mode = 'I;16'
|
||||||
elif nc == 1:
|
elif nc == 1:
|
||||||
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
@ -323,7 +323,7 @@ class JpegImageFile(ImageFile.ImageFile):
|
||||||
if self.mode == "CMYK":
|
if self.mode == "CMYK":
|
||||||
rawmode = "CMYK;I" # assume adobe conventions
|
rawmode = "CMYK;I" # assume adobe conventions
|
||||||
self.tile = [("jpeg", (0, 0) + self.size, 0,
|
self.tile = [("jpeg", (0, 0) + self.size, 0,
|
||||||
(rawmode, ""))]
|
(rawmode, ""))]
|
||||||
# self.__offset = self.fp.tell()
|
# self.__offset = self.fp.tell()
|
||||||
break
|
break
|
||||||
s = self.fp.read(1)
|
s = self.fp.read(1)
|
||||||
|
@ -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 = {
|
||||||
(2, 1, 1, 1, 1, 1): 1,
|
(1, 1, 1, 1, 1, 1): 0,
|
||||||
(2, 2, 1, 1, 1, 1): 2,
|
(2, 1, 1, 1, 1, 1): 1,
|
||||||
}
|
(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
|
||||||
|
@ -684,7 +675,7 @@ def _save(im, fp, filename):
|
||||||
# https://github.com/jdriscoll/django-imagekit/issues/50
|
# https://github.com/jdriscoll/django-imagekit/issues/50
|
||||||
bufsize = 0
|
bufsize = 0
|
||||||
if "optimize" in info or "progressive" in info or "progression" in info:
|
if "optimize" in info or "progressive" in info or "progression" in info:
|
||||||
# keep sets quality to 0, but the actual value may be high.
|
# keep sets quality to 0, but the actual value may be high.
|
||||||
if quality >= 95 or quality == 0:
|
if quality >= 95 or quality == 0:
|
||||||
bufsize = 2 * im.size[0] * im.size[1]
|
bufsize = 2 * im.size[0] * im.size[1]
|
||||||
else:
|
else:
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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': {
|
||||||
'quantization': [
|
'subsampling': 2, # "4:1:1"
|
||||||
[20, 16, 25, 39, 50, 46, 62, 68,
|
'quantization': [
|
||||||
16, 18, 23, 38, 38, 53, 65, 68,
|
[20, 16, 25, 39, 50, 46, 62, 68, 16, 18, 23, 38, 38, 53, 65, 68,
|
||||||
25, 23, 31, 38, 53, 65, 68, 68,
|
25, 23, 31, 38, 53, 65, 68, 68, 39, 38, 38, 53, 65, 68, 68, 68,
|
||||||
39, 38, 38, 53, 65, 68, 68, 68,
|
50, 38, 53, 65, 68, 68, 68, 68, 46, 53, 65, 68, 68, 68, 68, 68,
|
||||||
50, 38, 53, 65, 68, 68, 68, 68,
|
62, 65, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68],
|
||||||
46, 53, 65, 68, 68, 68, 68, 68,
|
[21, 25, 32, 38, 54, 68, 68, 68, 25, 28, 24, 38, 54, 68, 68, 68,
|
||||||
62, 65, 68, 68, 68, 68, 68, 68,
|
32, 24, 32, 43, 66, 68, 68, 68, 38, 38, 43, 53, 68, 68, 68, 68,
|
||||||
68, 68, 68, 68, 68, 68, 68, 68],
|
54, 54, 66, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
|
||||||
[21, 25, 32, 38, 54, 68, 68, 68,
|
68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68]
|
||||||
25, 28, 24, 38, 54, 68, 68, 68,
|
]
|
||||||
32, 24, 32, 43, 66, 68, 68, 68,
|
},
|
||||||
38, 38, 43, 53, 68, 68, 68, 68,
|
'web_medium': {
|
||||||
54, 54, 66, 68, 68, 68, 68, 68,
|
'subsampling': 2, # "4:1:1"
|
||||||
68, 68, 68, 68, 68, 68, 68, 68,
|
'quantization': [
|
||||||
68, 68, 68, 68, 68, 68, 68, 68,
|
[16, 11, 11, 16, 23, 27, 31, 30, 11, 12, 12, 15, 20, 23, 23, 30,
|
||||||
68, 68, 68, 68, 68, 68, 68, 68]
|
11, 12, 13, 16, 23, 26, 35, 47, 16, 15, 16, 23, 26, 37, 47, 64,
|
||||||
]},
|
23, 20, 23, 26, 39, 51, 64, 64, 27, 23, 26, 37, 51, 64, 64, 64,
|
||||||
'web_medium': {'subsampling': 2, # "4:1:1"
|
31, 23, 35, 47, 64, 64, 64, 64, 30, 30, 47, 64, 64, 64, 64, 64],
|
||||||
'quantization': [
|
[17, 15, 17, 21, 20, 26, 38, 48, 15, 19, 18, 17, 20, 26, 35, 43,
|
||||||
[16, 11, 11, 16, 23, 27, 31, 30,
|
17, 18, 20, 22, 26, 30, 46, 53, 21, 17, 22, 28, 30, 39, 53, 64,
|
||||||
11, 12, 12, 15, 20, 23, 23, 30,
|
20, 20, 26, 30, 39, 48, 64, 64, 26, 26, 30, 39, 48, 63, 64, 64,
|
||||||
11, 12, 13, 16, 23, 26, 35, 47,
|
38, 35, 46, 53, 64, 64, 64, 64, 48, 43, 53, 64, 64, 64, 64, 64]
|
||||||
16, 15, 16, 23, 26, 37, 47, 64,
|
]
|
||||||
23, 20, 23, 26, 39, 51, 64, 64,
|
},
|
||||||
27, 23, 26, 37, 51, 64, 64, 64,
|
'web_high': {
|
||||||
31, 23, 35, 47, 64, 64, 64, 64,
|
'subsampling': 0, # "4:4:4"
|
||||||
30, 30, 47, 64, 64, 64, 64, 64],
|
'quantization': [
|
||||||
[17, 15, 17, 21, 20, 26, 38, 48,
|
[6, 4, 4, 6, 9, 11, 12, 16, 4, 5, 5, 6, 8, 10, 12, 12, 4, 5, 5, 6,
|
||||||
15, 19, 18, 17, 20, 26, 35, 43,
|
10, 12, 14, 19, 6, 6, 6, 11, 12, 15, 19, 28, 9, 8, 10, 12, 16, 20,
|
||||||
17, 18, 20, 22, 26, 30, 46, 53,
|
27, 31, 11, 10, 12, 15, 20, 27, 31, 31, 12, 12, 14, 19, 27, 31,
|
||||||
21, 17, 22, 28, 30, 39, 53, 64,
|
31, 31, 16, 12, 19, 28, 31, 31, 31, 31],
|
||||||
20, 20, 26, 30, 39, 48, 64, 64,
|
[7, 7, 13, 24, 26, 31, 31, 31, 7, 12, 16, 21, 31, 31, 31, 31, 13,
|
||||||
26, 26, 30, 39, 48, 63, 64, 64,
|
16, 17, 31, 31, 31, 31, 31, 24, 21, 31, 31, 31, 31, 31, 31, 26,
|
||||||
38, 35, 46, 53, 64, 64, 64, 64,
|
31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
|
||||||
48, 43, 53, 64, 64, 64, 64, 64]
|
31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31]
|
||||||
]},
|
]
|
||||||
'web_high': {'subsampling': 0, # "4:4:4"
|
},
|
||||||
'quantization': [
|
'web_very_high': {
|
||||||
[ 6, 4, 4, 6, 9, 11, 12, 16,
|
'subsampling': 0, # "4:4:4"
|
||||||
4, 5, 5, 6, 8, 10, 12, 12,
|
'quantization': [[2, 2, 2, 2, 3, 4, 5, 6, 2, 2, 2, 2, 3, 4, 5, 6, 2, 2,
|
||||||
4, 5, 5, 6, 10, 12, 14, 19,
|
2, 2, 4, 5, 7, 9, 2, 2, 2, 4, 5, 7, 9, 12, 3, 3, 4,
|
||||||
6, 6, 6, 11, 12, 15, 19, 28,
|
5, 8, 10, 12, 12, 4, 4, 5, 7, 10, 12, 12, 12, 5, 5,
|
||||||
9, 8, 10, 12, 16, 20, 27, 31,
|
7, 9, 12, 12, 12, 12, 6, 6, 9, 12, 12, 12, 12, 12],
|
||||||
11, 10, 12, 15, 20, 27, 31, 31,
|
[3, 3, 5, 9, 13, 15, 15, 15, 3, 4, 6, 11, 14, 12, 12,
|
||||||
12, 12, 14, 19, 27, 31, 31, 31,
|
12, 5, 6, 9, 14, 12, 12, 12, 12, 9, 11, 14, 12, 12,
|
||||||
16, 12, 19, 28, 31, 31, 31, 31],
|
12, 12, 12, 13, 14, 12, 12, 12, 12, 12, 12, 15, 12,
|
||||||
[ 7, 7, 13, 24, 26, 31, 31, 31,
|
12, 12, 12, 12, 12, 12, 15, 12, 12, 12, 12, 12, 12,
|
||||||
7, 12, 16, 21, 31, 31, 31, 31,
|
12, 15, 12, 12, 12, 12, 12, 12, 12]]
|
||||||
13, 16, 17, 31, 31, 31, 31, 31,
|
},
|
||||||
24, 21, 31, 31, 31, 31, 31, 31,
|
'web_maximum': {
|
||||||
26, 31, 31, 31, 31, 31, 31, 31,
|
'subsampling': 0, # "4:4:4"
|
||||||
31, 31, 31, 31, 31, 31, 31, 31,
|
'quantization': [
|
||||||
31, 31, 31, 31, 31, 31, 31, 31,
|
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
31, 31, 31, 31, 31, 31, 31, 31]
|
1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 2, 2, 3, 1, 1, 1, 1,
|
||||||
]},
|
2, 2, 3, 3, 1, 1, 1, 2, 2, 3, 3, 3, 1, 1, 2, 2, 3, 3, 3, 3],
|
||||||
'web_very_high': {'subsampling': 0, # "4:4:4"
|
[1, 1, 1, 2, 2, 3, 3, 3, 1, 1, 1, 2, 3, 3, 3, 3, 1, 1, 1, 3, 3, 3,
|
||||||
'quantization': [
|
3, 3, 2, 2, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
[ 2, 2, 2, 2, 3, 4, 5, 6,
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
|
||||||
2, 2, 2, 2, 3, 4, 5, 6,
|
]
|
||||||
2, 2, 2, 2, 4, 5, 7, 9,
|
},
|
||||||
2, 2, 2, 4, 5, 7, 9, 12,
|
'low': {
|
||||||
3, 3, 4, 5, 8, 10, 12, 12,
|
'subsampling': 2, # "4:1:1"
|
||||||
4, 4, 5, 7, 10, 12, 12, 12,
|
'quantization': [
|
||||||
5, 5, 7, 9, 12, 12, 12, 12,
|
[18, 14, 14, 21, 30, 35, 34, 17, 14, 16, 16, 19, 26, 23, 12, 12,
|
||||||
6, 6, 9, 12, 12, 12, 12, 12],
|
14, 16, 17, 21, 23, 12, 12, 12, 21, 19, 21, 23, 12, 12, 12, 12,
|
||||||
[ 3, 3, 5, 9, 13, 15, 15, 15,
|
30, 26, 23, 12, 12, 12, 12, 12, 35, 23, 12, 12, 12, 12, 12, 12,
|
||||||
3, 4, 6, 11, 14, 12, 12, 12,
|
34, 12, 12, 12, 12, 12, 12, 12, 17, 12, 12, 12, 12, 12, 12, 12],
|
||||||
5, 6, 9, 14, 12, 12, 12, 12,
|
[20, 19, 22, 27, 20, 20, 17, 17, 19, 25, 23, 14, 14, 12, 12, 12,
|
||||||
9, 11, 14, 12, 12, 12, 12, 12,
|
22, 23, 14, 14, 12, 12, 12, 12, 27, 14, 14, 12, 12, 12, 12, 12,
|
||||||
13, 14, 12, 12, 12, 12, 12, 12,
|
20, 14, 12, 12, 12, 12, 12, 12, 20, 12, 12, 12, 12, 12, 12, 12,
|
||||||
15, 12, 12, 12, 12, 12, 12, 12,
|
17, 12, 12, 12, 12, 12, 12, 12, 17, 12, 12, 12, 12, 12, 12, 12]
|
||||||
15, 12, 12, 12, 12, 12, 12, 12,
|
]
|
||||||
15, 12, 12, 12, 12, 12, 12, 12]
|
},
|
||||||
]},
|
'medium': {
|
||||||
'web_maximum': {'subsampling': 0, # "4:4:4"
|
'subsampling': 2, # "4:1:1"
|
||||||
'quantization': [
|
'quantization': [
|
||||||
[ 1, 1, 1, 1, 1, 1, 1, 1,
|
[12, 8, 8, 12, 17, 21, 24, 17, 8, 9, 9, 11, 15, 19, 12, 12, 8, 9,
|
||||||
1, 1, 1, 1, 1, 1, 1, 1,
|
10, 12, 19, 12, 12, 12, 12, 11, 12, 21, 12, 12, 12, 12, 17, 15,
|
||||||
1, 1, 1, 1, 1, 1, 1, 2,
|
19, 12, 12, 12, 12, 12, 21, 19, 12, 12, 12, 12, 12, 12, 24, 12,
|
||||||
1, 1, 1, 1, 1, 1, 2, 2,
|
12, 12, 12, 12, 12, 12, 17, 12, 12, 12, 12, 12, 12, 12],
|
||||||
1, 1, 1, 1, 1, 2, 2, 3,
|
[13, 11, 13, 16, 20, 20, 17, 17, 11, 14, 14, 14, 14, 12, 12, 12,
|
||||||
1, 1, 1, 1, 2, 2, 3, 3,
|
13, 14, 14, 14, 12, 12, 12, 12, 16, 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,
|
'high': {
|
||||||
2, 2, 3, 3, 3, 3, 3, 3,
|
'subsampling': 0, # "4:4:4"
|
||||||
2, 3, 3, 3, 3, 3, 3, 3,
|
'quantization': [
|
||||||
3, 3, 3, 3, 3, 3, 3, 3,
|
[6, 4, 4, 6, 9, 11, 12, 16, 4, 5, 5, 6, 8, 10, 12, 12, 4, 5, 5, 6,
|
||||||
3, 3, 3, 3, 3, 3, 3, 3,
|
10, 12, 12, 12, 6, 6, 6, 11, 12, 12, 12, 12, 9, 8, 10, 12, 12, 12,
|
||||||
3, 3, 3, 3, 3, 3, 3, 3]
|
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],
|
||||||
'low': {'subsampling': 2, # "4:1:1"
|
[7, 7, 13, 24, 20, 20, 17, 17, 7, 12, 16, 14, 14, 12, 12, 12, 13,
|
||||||
'quantization': [
|
16, 14, 14, 12, 12, 12, 12, 24, 14, 14, 12, 12, 12, 12, 12, 20,
|
||||||
[18, 14, 14, 21, 30, 35, 34, 17,
|
14, 12, 12, 12, 12, 12, 12, 20, 12, 12, 12, 12, 12, 12, 12, 17,
|
||||||
14, 16, 16, 19, 26, 23, 12, 12,
|
12, 12, 12, 12, 12, 12, 12, 17, 12, 12, 12, 12, 12, 12, 12]
|
||||||
14, 16, 17, 21, 23, 12, 12, 12,
|
]
|
||||||
21, 19, 21, 23, 12, 12, 12, 12,
|
},
|
||||||
30, 26, 23, 12, 12, 12, 12, 12,
|
'maximum': {
|
||||||
35, 23, 12, 12, 12, 12, 12, 12,
|
'subsampling': 0, # "4:4:4"
|
||||||
34, 12, 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,
|
||||||
17, 12, 12, 12, 12, 12, 12, 12],
|
2, 2, 4, 5, 7, 9, 2, 2, 2, 4, 5, 7, 9, 12, 3, 3, 4,
|
||||||
[20, 19, 22, 27, 20, 20, 17, 17,
|
5, 8, 10, 12, 12, 4, 4, 5, 7, 10, 12, 12, 12, 5, 5,
|
||||||
19, 25, 23, 14, 14, 12, 12, 12,
|
7, 9, 12, 12, 12, 12, 6, 6, 9, 12, 12, 12, 12, 12],
|
||||||
22, 23, 14, 14, 12, 12, 12, 12,
|
[3, 3, 5, 9, 13, 15, 15, 15, 3, 4, 6, 10, 14, 12, 12,
|
||||||
27, 14, 14, 12, 12, 12, 12, 12,
|
12, 5, 6, 9, 14, 12, 12, 12, 12, 9, 10, 14, 12, 12,
|
||||||
20, 14, 12, 12, 12, 12, 12, 12,
|
12, 12, 12, 13, 14, 12, 12, 12, 12, 12, 12, 15, 12,
|
||||||
20, 12, 12, 12, 12, 12, 12, 12,
|
12, 12, 12, 12, 12, 12, 15, 12, 12, 12, 12, 12, 12,
|
||||||
17, 12, 12, 12, 12, 12, 12, 12,
|
12, 15, 12, 12, 12, 12, 12, 12, 12]]
|
||||||
17, 12, 12, 12, 12, 12, 12, 12]
|
},
|
||||||
]},
|
|
||||||
'medium': {'subsampling': 2, # "4:1:1"
|
|
||||||
'quantization': [
|
|
||||||
[12, 8, 8, 12, 17, 21, 24, 17,
|
|
||||||
8, 9, 9, 11, 15, 19, 12, 12,
|
|
||||||
8, 9, 10, 12, 19, 12, 12, 12,
|
|
||||||
12, 11, 12, 21, 12, 12, 12, 12,
|
|
||||||
17, 15, 19, 12, 12, 12, 12, 12,
|
|
||||||
21, 19, 12, 12, 12, 12, 12, 12,
|
|
||||||
24, 12, 12, 12, 12, 12, 12, 12,
|
|
||||||
17, 12, 12, 12, 12, 12, 12, 12],
|
|
||||||
[13, 11, 13, 16, 20, 20, 17, 17,
|
|
||||||
11, 14, 14, 14, 14, 12, 12, 12,
|
|
||||||
13, 14, 14, 14, 12, 12, 12, 12,
|
|
||||||
16, 14, 14, 12, 12, 12, 12, 12,
|
|
||||||
20, 14, 12, 12, 12, 12, 12, 12,
|
|
||||||
20, 12, 12, 12, 12, 12, 12, 12,
|
|
||||||
17, 12, 12, 12, 12, 12, 12, 12,
|
|
||||||
17, 12, 12, 12, 12, 12, 12, 12]
|
|
||||||
]},
|
|
||||||
'high': {'subsampling': 0, # "4:4:4"
|
|
||||||
'quantization': [
|
|
||||||
[ 6, 4, 4, 6, 9, 11, 12, 16,
|
|
||||||
4, 5, 5, 6, 8, 10, 12, 12,
|
|
||||||
4, 5, 5, 6, 10, 12, 12, 12,
|
|
||||||
6, 6, 6, 11, 12, 12, 12, 12,
|
|
||||||
9, 8, 10, 12, 12, 12, 12, 12,
|
|
||||||
11, 10, 12, 12, 12, 12, 12, 12,
|
|
||||||
12, 12, 12, 12, 12, 12, 12, 12,
|
|
||||||
16, 12, 12, 12, 12, 12, 12, 12],
|
|
||||||
[ 7, 7, 13, 24, 20, 20, 17, 17,
|
|
||||||
7, 12, 16, 14, 14, 12, 12, 12,
|
|
||||||
13, 16, 14, 14, 12, 12, 12, 12,
|
|
||||||
24, 14, 14, 12, 12, 12, 12, 12,
|
|
||||||
20, 14, 12, 12, 12, 12, 12, 12,
|
|
||||||
20, 12, 12, 12, 12, 12, 12, 12,
|
|
||||||
17, 12, 12, 12, 12, 12, 12, 12,
|
|
||||||
17, 12, 12, 12, 12, 12, 12, 12]
|
|
||||||
]},
|
|
||||||
'maximum': {'subsampling': 0, # "4:4:4"
|
|
||||||
'quantization': [
|
|
||||||
[ 2, 2, 2, 2, 3, 4, 5, 6,
|
|
||||||
2, 2, 2, 2, 3, 4, 5, 6,
|
|
||||||
2, 2, 2, 2, 4, 5, 7, 9,
|
|
||||||
2, 2, 2, 4, 5, 7, 9, 12,
|
|
||||||
3, 3, 4, 5, 8, 10, 12, 12,
|
|
||||||
4, 4, 5, 7, 10, 12, 12, 12,
|
|
||||||
5, 5, 7, 9, 12, 12, 12, 12,
|
|
||||||
6, 6, 9, 12, 12, 12, 12, 12],
|
|
||||||
[ 3, 3, 5, 9, 13, 15, 15, 15,
|
|
||||||
3, 4, 6, 10, 14, 12, 12, 12,
|
|
||||||
5, 6, 9, 14, 12, 12, 12, 12,
|
|
||||||
9, 10, 14, 12, 12, 12, 12, 12,
|
|
||||||
13, 14, 12, 12, 12, 12, 12, 12,
|
|
||||||
15, 12, 12, 12, 12, 12, 12, 12,
|
|
||||||
15, 12, 12, 12, 12, 12, 12, 12,
|
|
||||||
15, 12, 12, 12, 12, 12, 12, 12]
|
|
||||||
]},
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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))]
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
680
PIL/OleFileIO.py
680
PIL/OleFileIO.py
File diff suppressed because it is too large
Load Diff
|
@ -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):
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -13,74 +13,68 @@ from PIL import Image, ImageFile, _binary
|
||||||
|
|
||||||
_Palm8BitColormapValues = (
|
_Palm8BitColormapValues = (
|
||||||
(255, 255, 255), (255, 204, 255), (255, 153, 255), (255, 102, 255),
|
(255, 255, 255), (255, 204, 255), (255, 153, 255), (255, 102, 255),
|
||||||
(255, 51, 255), (255, 0, 255), (255, 255, 204), (255, 204, 204),
|
(255, 51, 255), (255, 0, 255), (255, 255, 204), (255, 204, 204),
|
||||||
(255, 153, 204), (255, 102, 204), (255, 51, 204), (255, 0, 204),
|
(255, 153, 204), (255, 102, 204), (255, 51, 204), (255, 0, 204),
|
||||||
(255, 255, 153), (255, 204, 153), (255, 153, 153), (255, 102, 153),
|
(255, 255, 153), (255, 204, 153), (255, 153, 153), (255, 102, 153),
|
||||||
(255, 51, 153), (255, 0, 153), (204, 255, 255), (204, 204, 255),
|
(255, 51, 153), (255, 0, 153), (204, 255, 255), (204, 204, 255),
|
||||||
(204, 153, 255), (204, 102, 255), (204, 51, 255), (204, 0, 255),
|
(204, 153, 255), (204, 102, 255), (204, 51, 255), (204, 0, 255),
|
||||||
(204, 255, 204), (204, 204, 204), (204, 153, 204), (204, 102, 204),
|
(204, 255, 204), (204, 204, 204), (204, 153, 204), (204, 102, 204),
|
||||||
(204, 51, 204), (204, 0, 204), (204, 255, 153), (204, 204, 153),
|
(204, 51, 204), (204, 0, 204), (204, 255, 153), (204, 204, 153),
|
||||||
(204, 153, 153), (204, 102, 153), (204, 51, 153), (204, 0, 153),
|
(204, 153, 153), (204, 102, 153), (204, 51, 153), (204, 0, 153),
|
||||||
(153, 255, 255), (153, 204, 255), (153, 153, 255), (153, 102, 255),
|
(153, 255, 255), (153, 204, 255), (153, 153, 255), (153, 102, 255),
|
||||||
(153, 51, 255), (153, 0, 255), (153, 255, 204), (153, 204, 204),
|
(153, 51, 255), (153, 0, 255), (153, 255, 204), (153, 204, 204),
|
||||||
(153, 153, 204), (153, 102, 204), (153, 51, 204), (153, 0, 204),
|
(153, 153, 204), (153, 102, 204), (153, 51, 204), (153, 0, 204),
|
||||||
(153, 255, 153), (153, 204, 153), (153, 153, 153), (153, 102, 153),
|
(153, 255, 153), (153, 204, 153), (153, 153, 153), (153, 102, 153),
|
||||||
(153, 51, 153), (153, 0, 153), (102, 255, 255), (102, 204, 255),
|
(153, 51, 153), (153, 0, 153), (102, 255, 255), (102, 204, 255),
|
||||||
(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,
|
||||||
|
@ -99,26 +94,22 @@ Palm8BitColormapImage = build_prototype_image()
|
||||||
|
|
||||||
_FLAGS = {
|
_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"]
|
||||||
|
|
||||||
|
@ -204,7 +195,7 @@ def _save(im, fp, filename, check=0):
|
||||||
fp.write(o16b(offset))
|
fp.write(o16b(offset))
|
||||||
fp.write(o8(transparent_index))
|
fp.write(o8(transparent_index))
|
||||||
fp.write(o8(compression_type))
|
fp.write(o8(compression_type))
|
||||||
fp.write(o16b(0)) # reserved by Palm
|
fp.write(o16b(0)) # reserved by Palm
|
||||||
|
|
||||||
# now write colormap if necessary
|
# now write colormap if necessary
|
||||||
|
|
||||||
|
@ -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 + 2]))
|
||||||
o8(colormap[3 * i + 1]) +
|
|
||||||
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 + 2]))
|
||||||
o8(colormap[4 * i + 1]) +
|
|
||||||
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()
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
@ -205,7 +198,7 @@ class PcfFontFile(FontFile.FontFile):
|
||||||
bitmapSizes.append(i32(fp.read(4)))
|
bitmapSizes.append(i32(fp.read(4)))
|
||||||
|
|
||||||
byteorder = format & 4 # non-zero => MSB
|
byteorder = format & 4 # non-zero => MSB
|
||||||
bitorder = format & 8 # non-zero => MSB
|
bitorder = format & 8 # non-zero => MSB
|
||||||
padindex = format & 3
|
padindex = format & 3
|
||||||
|
|
||||||
bitmapsize = bitmapSizes[padindex]
|
bitmapsize = bitmapSizes[padindex]
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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,8 +66,8 @@ 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
|
||||||
|
|
|
@ -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,28 +148,27 @@ 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,
|
Height=height, # * 72.0 / resolution,
|
||||||
Height=height, # * 72.0 / resolution,
|
Length=len(op.getvalue()),
|
||||||
Length=len(op.getvalue()),
|
Filter=filter,
|
||||||
Filter=filter,
|
BitsPerComponent=bits,
|
||||||
BitsPerComponent=bits,
|
DecodeParams=params,
|
||||||
DecodeParams=params,
|
ColorSpace=colorspace)
|
||||||
ColorSpace=colorspace)
|
|
||||||
|
|
||||||
fp.write("stream\n")
|
fp.write("stream\n")
|
||||||
fp.fp.write(op.getvalue())
|
fp.fp.write(op.getvalue())
|
||||||
|
@ -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" % (procset, int(
|
||||||
"/MediaBox [ 0 0 %d %d ]\n/Contents 5 0 R\n>>\n" % (
|
width * 72.0 / resolution), int(height * 72.0 / resolution)))
|
||||||
procset,
|
|
||||||
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()))
|
||||||
|
|
|
@ -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))]
|
||||||
|
|
||||||
#
|
#
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
|
@ -46,30 +46,27 @@ 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"),
|
||||||
(2, 0): ("L", "L;2"),
|
(2, 0): ("L", "L;2"),
|
||||||
(4, 0): ("L", "L;4"),
|
(4, 0): ("L", "L;4"),
|
||||||
(8, 0): ("L", "L"),
|
(8, 0): ("L", "L"),
|
||||||
(16, 0): ("I", "I;16B"),
|
(16, 0): ("I", "I;16B"),
|
||||||
(8, 2): ("RGB", "RGB"),
|
(8, 2): ("RGB", "RGB"),
|
||||||
(16, 2): ("RGB", "RGB;16B"),
|
(16, 2): ("RGB", "RGB;16B"),
|
||||||
(1, 3): ("P", "P;1"),
|
(1, 3): ("P", "P;1"),
|
||||||
(2, 3): ("P", "P;2"),
|
(2, 3): ("P", "P;2"),
|
||||||
(4, 3): ("P", "P;4"),
|
(4, 3): ("P", "P;4"),
|
||||||
(8, 3): ("P", "P"),
|
(8, 3): ("P", "P"),
|
||||||
(8, 4): ("LA", "LA"),
|
(8, 4): ("LA", "LA"),
|
||||||
(16, 4): ("RGBA", "LA;16B"), # LA;16B->LA not yet available
|
(16, 4): ("RGBA", "LA;16B"), # LA;16B->LA not yet available
|
||||||
(8, 6): ("RGBA", "RGBA"),
|
(8, 6): ("RGBA", "RGBA"),
|
||||||
(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,8 +275,9 @@ 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(
|
||||||
self.text_memory)
|
"Too much memory used in text chunks: %s>MAX_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
|
||||||
|
|
||||||
|
@ -592,19 +589,19 @@ o32 = _binary.o32be
|
||||||
|
|
||||||
_OUTMODES = {
|
_OUTMODES = {
|
||||||
# supported PIL modes, and corresponding rawmodes/bits/color combinations
|
# supported PIL modes, and corresponding rawmodes/bits/color combinations
|
||||||
"1": ("1", b'\x01\x00'),
|
"1": ("1", b'\x01\x00'),
|
||||||
"L;1": ("L;1", b'\x01\x00'),
|
"L;1": ("L;1", b'\x01\x00'),
|
||||||
"L;2": ("L;2", b'\x02\x00'),
|
"L;2": ("L;2", b'\x02\x00'),
|
||||||
"L;4": ("L;4", b'\x04\x00'),
|
"L;4": ("L;4", b'\x04\x00'),
|
||||||
"L": ("L", b'\x08\x00'),
|
"L": ("L", b'\x08\x00'),
|
||||||
"LA": ("LA", b'\x08\x04'),
|
"LA": ("LA", b'\x08\x04'),
|
||||||
"I": ("I;16B", b'\x10\x00'),
|
"I": ("I;16B", b'\x10\x00'),
|
||||||
"P;1": ("P;1", b'\x01\x03'),
|
"P;1": ("P;1", b'\x01\x03'),
|
||||||
"P;2": ("P;2", b'\x02\x03'),
|
"P;2": ("P;2", b'\x02\x03'),
|
||||||
"P;4": ("P;4", b'\x04\x03'),
|
"P;4": ("P;4", b'\x04\x03'),
|
||||||
"P": ("P", b'\x08\x03'),
|
"P": ("P", b'\x08\x03'),
|
||||||
"RGB": ("RGB", b'\x08\x02'),
|
"RGB": ("RGB", b'\x08\x02'),
|
||||||
"RGBA": ("RGBA", b'\x08\x06'),
|
"RGBA": ("RGBA", b'\x08\x06'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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,12 +681,11 @@ 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
|
b'\0') # 12: interlace flag
|
||||||
b'\0') # 12: interlace flag
|
|
||||||
|
|
||||||
if im.mode == "P":
|
if im.mode == "P":
|
||||||
palette_byte_number = (2 ** bits) * 3
|
palette_byte_number = (2 ** bits) * 3
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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,19 +109,17 @@ 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),
|
(rawmode, 0, 1))]
|
||||||
self.fp.tell(),
|
|
||||||
(rawmode, 0, 1))]
|
|
||||||
|
|
||||||
# ALTERNATIVE: load via builtin debug function
|
# ALTERNATIVE: load via builtin debug function
|
||||||
# self.im = Image.core.open_ppm(self.filename)
|
# self.im = Image.core.open_ppm(self.filename)
|
||||||
# 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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,22 +277,23 @@ class _PyAccessF(PyAccess):
|
||||||
self.pixels[y][x] = color[0]
|
self.pixels[y][x] = color[0]
|
||||||
|
|
||||||
|
|
||||||
mode_map = {'1': _PyAccess8,
|
mode_map = {
|
||||||
'L': _PyAccess8,
|
'1': _PyAccess8,
|
||||||
'P': _PyAccess8,
|
'L': _PyAccess8,
|
||||||
'LA': _PyAccess32_2,
|
'P': _PyAccess8,
|
||||||
'PA': _PyAccess32_2,
|
'LA': _PyAccess32_2,
|
||||||
'RGB': _PyAccess32_3,
|
'PA': _PyAccess32_2,
|
||||||
'LAB': _PyAccess32_3,
|
'RGB': _PyAccess32_3,
|
||||||
'HSV': _PyAccess32_3,
|
'LAB': _PyAccess32_3,
|
||||||
'YCbCr': _PyAccess32_3,
|
'HSV': _PyAccess32_3,
|
||||||
'RGBA': _PyAccess32_4,
|
'YCbCr': _PyAccess32_3,
|
||||||
'RGBa': _PyAccess32_4,
|
'RGBA': _PyAccess32_4,
|
||||||
'RGBX': _PyAccess32_4,
|
'RGBa': _PyAccess32_4,
|
||||||
'CMYK': _PyAccess32_4,
|
'RGBX': _PyAccess32_4,
|
||||||
'F': _PyAccessF,
|
'CMYK': _PyAccess32_4,
|
||||||
'I': _PyAccessI32_N,
|
'F': _PyAccessF,
|
||||||
}
|
'I': _PyAccessI32_N,
|
||||||
|
}
|
||||||
|
|
||||||
if sys.byteorder == 'little':
|
if sys.byteorder == 'little':
|
||||||
mode_map['I;16'] = _PyAccessI16_N
|
mode_map['I;16'] = _PyAccessI16_N
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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]):
|
||||||
|
@ -70,9 +71,9 @@ def isSpiderHeader(t):
|
||||||
if iform not in iforms:
|
if iform not in iforms:
|
||||||
return 0
|
return 0
|
||||||
# check other header values
|
# check other header values
|
||||||
labrec = int(h[13]) # no. records in file header
|
labrec = int(h[13]) # no. records in file header
|
||||||
labbyt = int(h[22]) # total no. of bytes in header
|
labbyt = int(h[22]) # total no. of bytes in header
|
||||||
lenbyt = int(h[23]) # record length in bytes
|
lenbyt = int(h[23]) # record length in bytes
|
||||||
# print "labrec = %d, labbyt = %d, lenbyt = %d" % (labrec,labbyt,lenbyt)
|
# print "labrec = %d, labbyt = %d, lenbyt = %d" % (labrec,labbyt,lenbyt)
|
||||||
if labbyt != (labrec * lenbyt):
|
if labbyt != (labrec * lenbyt):
|
||||||
return 0
|
return 0
|
||||||
|
@ -82,7 +83,7 @@ def isSpiderHeader(t):
|
||||||
|
|
||||||
def isSpiderImage(filename):
|
def isSpiderImage(filename):
|
||||||
fp = open(filename, 'rb')
|
fp = open(filename, 'rb')
|
||||||
f = fp.read(92) # read 23 * 4 bytes
|
f = fp.read(92) # read 23 * 4 bytes
|
||||||
fp.close()
|
fp.close()
|
||||||
t = struct.unpack('>23f', f) # try big-endian first
|
t = struct.unpack('>23f', f) # try big-endian first
|
||||||
hdrlen = isSpiderHeader(t)
|
hdrlen = isSpiderHeader(t)
|
||||||
|
@ -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
|
||||||
|
@ -230,10 +229,10 @@ def makeSpiderHeader(im):
|
||||||
return []
|
return []
|
||||||
|
|
||||||
# NB these are Fortran indices
|
# NB these are Fortran indices
|
||||||
hdr[1] = 1.0 # nslice (=1 for an image)
|
hdr[1] = 1.0 # nslice (=1 for an image)
|
||||||
hdr[2] = float(nrow) # number of rows per slice
|
hdr[2] = float(nrow) # number of rows per slice
|
||||||
hdr[5] = 1.0 # iform for 2D image
|
hdr[5] = 1.0 # iform for 2D image
|
||||||
hdr[12] = float(nsam) # number of pixels per line
|
hdr[12] = float(nsam) # number of pixels per line
|
||||||
hdr[13] = float(labrec) # number of records in file header
|
hdr[13] = float(labrec) # number of records in file header
|
||||||
hdr[22] = float(labbyt) # total number of bytes in header
|
hdr[22] = float(labbyt) # total number of bytes in header
|
||||||
hdr[23] = float(lenbyt) # record length in bytes
|
hdr[23] = float(lenbyt) # record length in bytes
|
||||||
|
@ -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")
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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):
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
|
@ -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,21 +28,20 @@ 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",
|
||||||
(3, 1): "1",
|
(3, 1): "1",
|
||||||
(3, 8): "L",
|
(3, 8): "L",
|
||||||
(2, 16): "BGR;5",
|
(2, 16): "BGR;5",
|
||||||
(2, 24): "BGR",
|
(2, 24): "BGR",
|
||||||
(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))])
|
||||||
|
|
||||||
#
|
#
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
|
@ -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,11 +574,12 @@ 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:
|
||||||
count = count // 2 # adjust for rational data field
|
count = count // 2 # adjust for rational data field
|
||||||
|
|
||||||
append((tag, typ, count, o32(offset), data))
|
append((tag, typ, count, o32(offset), data))
|
||||||
offset += len(data)
|
offset += len(data)
|
||||||
|
@ -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,8 +669,9 @@ 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(
|
||||||
(frame, self.__frame, self.__next, self.fp.tell()))
|
"Seeking to frame %s, on frame %s, __next %s, location: %s" %
|
||||||
|
(frame, self.__frame, self.__next, self.fp.tell()))
|
||||||
# reset python3 buffered io handle in case fp
|
# reset python3 buffered io handle in case fp
|
||||||
# was passed to libtiff, invalidating the buffer
|
# was passed to libtiff, invalidating the buffer
|
||||||
self.fp.tell()
|
self.fp.tell()
|
||||||
|
@ -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)
|
||||||
|
@ -1025,7 +1020,7 @@ def _save(im, fp, filename):
|
||||||
ifd = ImageFileDirectory(prefix)
|
ifd = ImageFileDirectory(prefix)
|
||||||
|
|
||||||
compression = im.encoderinfo.get('compression', im.info.get('compression',
|
compression = im.encoderinfo.get('compression', im.info.get('compression',
|
||||||
'raw'))
|
'raw'))
|
||||||
|
|
||||||
libtiff = WRITE_LIBTIFF or compression != 'raw'
|
libtiff = WRITE_LIBTIFF or compression != 'raw'
|
||||||
|
|
||||||
|
@ -1069,17 +1064,19 @@ def _save(im, fp, filename):
|
||||||
ifd[ICCPROFILE] = im.info["icc_profile"]
|
ifd[ICCPROFILE] = im.info["icc_profile"]
|
||||||
|
|
||||||
for key, name, cvt in [
|
for key, name, cvt in [
|
||||||
(IMAGEDESCRIPTION, "description", lambda x: x),
|
(IMAGEDESCRIPTION, "description", lambda x: x),
|
||||||
(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,17 +1141,16 @@ 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
|
||||||
if type(v[0]) in (int, float):
|
if type(v[0]) in (int, float):
|
||||||
|
@ -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:
|
||||||
|
|
|
@ -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",
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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)")
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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)
|
|
||||||
)]
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -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")
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -14,45 +14,17 @@
|
||||||
VERSION = '1.1.7' # PIL version
|
VERSION = '1.1.7' # PIL version
|
||||||
PILLOW_VERSION = '2.8.0' # Pillow
|
PILLOW_VERSION = '2.8.0' # 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']
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user