# Application code should use the Draw factory, instead of # directly. + class ImageDraw: ## @@ -98,8 +98,8 @@ def setink(self, ink): if warnings: warnings.warn( "'setink' is deprecated; use keyword arguments instead", - DeprecationWarning, stacklevel=2 - ) + DeprecationWarning, + stacklevel=2) if isStringType(ink): ink = ImageColor.getcolor(ink, self.mode) if self.palette and not isinstance(ink, numbers.Number): @@ -114,8 +114,8 @@ def setfill(self, onoff): if warnings: warnings.warn( "'setfill' is deprecated; use keyword arguments instead", - DeprecationWarning, stacklevel=2 - ) + DeprecationWarning, + stacklevel=2) self.fill = onoff ## @@ -281,7 +281,6 @@ def textsize(self, text, font=None): font = self.getfont() return font.getsize(text) - ## # A simple 2D drawing interface for PIL images. # @@ -292,6 +291,7 @@ def textsize(self, text, font=None): # must be the same as the image mode. If omitted, the mode # defaults to the mode of the image. + def Draw(im, mode=None): try: return im.getdraw(mode) @@ -304,7 +304,6 @@ def Draw(im, mode=None): except: Outline = None - ## # (Experimental) A more advanced 2D drawing interface for PIL images, # based on the WCK interface. @@ -313,6 +312,7 @@ def Draw(im, mode=None): # @param hints An optional list of hints. # @return A (drawing context, drawing resource factory) tuple. + def getdraw(im=None, hints=None): # FIXME: this needs more work! # FIXME: come up with a better 'hints' scheme. @@ -328,7 +328,6 @@ def getdraw(im=None, hints=None): im = handler.Draw(im) return im, handler - ## # (experimental) Fills a bounded region with a given color. # @@ -340,6 +339,7 @@ def getdraw(im=None, hints=None): # the region consists of pixels having the same color as the seed # pixel. + def floodfill(image, xy, value, border=None): "Fill bounded region." # based on an implementation by Eric S. Raymond @@ -357,7 +357,7 @@ def floodfill(image, xy, value, border=None): while edge: newedge = [] 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: p = pixel[s, t] except IndexError: @@ -371,7 +371,7 @@ def floodfill(image, xy, value, border=None): while edge: newedge = [] 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: p = pixel[s, t] except IndexError: diff --git a/PIL/ImageDraw2.py b/PIL/ImageDraw2.py index c967a200f4b..0c2928067b3 100644 --- a/PIL/ImageDraw2.py +++ b/PIL/ImageDraw2.py @@ -38,7 +38,6 @@ def __init__(self, color, file, size=12): class Draw: - def __init__(self, image, size=None, color=None): if not hasattr(image, "im"): image = Image.new(image, size, color) diff --git a/PIL/ImageEnhance.py b/PIL/ImageEnhance.py index a196d5b09ae..5b0e2ddc434 100644 --- a/PIL/ImageEnhance.py +++ b/PIL/ImageEnhance.py @@ -22,7 +22,6 @@ class _Enhance: - def enhance(self, factor): """ Returns an enhanced image. @@ -45,13 +44,16 @@ class Color(_Enhance): factor of 0.0 gives a black and white image. A factor of 1.0 gives the original image. """ + def __init__(self, image): self.image = image self.intermediate_mode = 'L' if 'A' in image.getbands(): self.intermediate_mode = 'LA' - self.degenerate = image.convert(self.intermediate_mode).convert(image.mode) + self.degenerate = image.convert(self.intermediate_mode).convert( + image.mode) + class Contrast(_Enhance): """Adjust image contrast. @@ -60,6 +62,7 @@ class Contrast(_Enhance): to the contrast control on a TV set. An enhancement factor of 0.0 gives a solid grey image. A factor of 1.0 gives the original image. """ + def __init__(self, image): self.image = image mean = int(ImageStat.Stat(image.convert("L")).mean[0] + 0.5) @@ -76,6 +79,7 @@ class Brightness(_Enhance): enhancement factor of 0.0 gives a black image. A factor of 1.0 gives the original image. """ + def __init__(self, image): self.image = image self.degenerate = Image.new(image.mode, image.size, 0) @@ -91,6 +95,7 @@ class Sharpness(_Enhance): enhancement factor of 0.0 gives a blurred image, a factor of 1.0 gives the original image, and a factor of 2.0 gives a sharpened image. """ + def __init__(self, image): self.image = image self.degenerate = image.filter(ImageFilter.SMOOTH) diff --git a/PIL/ImageFile.py b/PIL/ImageFile.py index 79faff79712..85383faec27 100644 --- a/PIL/ImageFile.py +++ b/PIL/ImageFile.py @@ -36,16 +36,13 @@ MAXBLOCK = 65536 -SAFEBLOCK = 1024*1024 +SAFEBLOCK = 1024 * 1024 LOAD_TRUNCATED_IMAGES = False ERRORS = { - -1: "image buffer overrun error", - -2: "decoding error", - -3: "unknown error", - -8: "bad configuration", - -9: "out of memory error" + -1: "image buffer overrun error", -2: "decoding error", -3: + "unknown error", -8: "bad configuration", -9: "out of memory error" } @@ -58,20 +55,20 @@ def raise_ioerror(error): message = "decoder error %d" % error raise IOError(message + " when reading image file") - # # -------------------------------------------------------------------- # Helpers + def _tilesort(t): # sort on offset return t[2] - # # -------------------------------------------------------------------- # ImageFile base class + class ImageFile(Image.Image): "Base class for image file format handlers." @@ -167,9 +164,8 @@ def load(self): # use built-in mapper self.map = Image.core.map(self.filename) self.map.seek(o) - self.im = self.map.readimage( - self.mode, self.size, a[1], a[2] - ) + self.im = self.map.readimage(self.mode, self.size, + a[1], a[2]) else: # use mmap, if possible import mmap @@ -177,9 +173,8 @@ def load(self): size = os.path.getsize(self.filename) # FIXME: on Unix, use PROT_READ etc self.map = mmap.mmap(file.fileno(), size) - self.im = Image.core.map_buffer( - self.map, self.size, d, e, o, a - ) + self.im = Image.core.map_buffer(self.map, self.size, d, + e, o, a) readonly = 1 except (AttributeError, EnvironmentError, ImportError): self.map = None @@ -291,8 +286,7 @@ class StubImageFile(ImageFile): def _open(self): raise NotImplementedError( - "StubImageFile subclass must implement _open" - ) + "StubImageFile subclass must implement _open") def load(self): loader = self._load() @@ -307,8 +301,7 @@ def load(self): def _load(self): "(Hook) Find actual image loader." raise NotImplementedError( - "StubImageFile subclass must implement _load" - ) + "StubImageFile subclass must implement _load") class Parser: @@ -404,9 +397,8 @@ def feed(self, data): im.load_prepare() d, e, o, a = im.tile[0] im.tile = [] - self.decoder = Image._getdecoder( - im.mode, d, a, im.decoderconfig - ) + self.decoder = Image._getdecoder(im.mode, d, a, + im.decoderconfig) self.decoder.setimage(im.im, e) # calculate decoder offset @@ -446,9 +438,9 @@ def close(self): fp.close() # explicitly close the virtual file return self.image - # -------------------------------------------------------------------- + def _save(im, fp, tile, bufsize=0): """Helper to save image based on tile list diff --git a/PIL/ImageFilter.py b/PIL/ImageFilter.py index b46845807c0..2a4b3de755f 100644 --- a/PIL/ImageFilter.py +++ b/PIL/ImageFilter.py @@ -43,7 +43,7 @@ class Kernel(Filter): def __init__(self, size, kernel, scale=None, offset=0): if scale is None: # 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): raise ValueError("not enough coefficients in kernel") self.filterargs = size, scale, offset, kernel @@ -78,7 +78,7 @@ def __init__(self, size, rank): def filter(self, image): if image.mode == "P": 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) @@ -93,7 +93,7 @@ class MedianFilter(RankFilter): def __init__(self, size=3): self.size = size - self.rank = size*size//2 + self.rank = size * size // 2 class MinFilter(RankFilter): @@ -121,7 +121,7 @@ class MaxFilter(RankFilter): def __init__(self, size=3): self.size = size - self.rank = size*size-1 + self.rank = size * size - 1 class ModeFilter(Filter): @@ -183,93 +183,51 @@ def filter(self, image): class BLUR(BuiltinFilter): name = "Blur" - filterargs = (5, 5), 16, 0, ( - 1, 1, 1, 1, 1, - 1, 0, 0, 0, 1, - 1, 0, 0, 0, 1, - 1, 0, 0, 0, 1, - 1, 1, 1, 1, 1 - ) + filterargs = (5, 5), 16, 0, (1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, + 1, 0, 0, 0, 1, 1, 1, 1, 1, 1) class CONTOUR(BuiltinFilter): name = "Contour" - filterargs = (3, 3), 1, 255, ( - -1, -1, -1, - -1, 8, -1, - -1, -1, -1 - ) + filterargs = (3, 3), 1, 255, (-1, -1, -1, -1, 8, -1, -1, -1, -1) class DETAIL(BuiltinFilter): name = "Detail" - filterargs = (3, 3), 6, 0, ( - 0, -1, 0, - -1, 10, -1, - 0, -1, 0 - ) + filterargs = (3, 3), 6, 0, (0, -1, 0, -1, 10, -1, 0, -1, 0) class EDGE_ENHANCE(BuiltinFilter): name = "Edge-enhance" - filterargs = (3, 3), 2, 0, ( - -1, -1, -1, - -1, 10, -1, - -1, -1, -1 - ) + filterargs = (3, 3), 2, 0, (-1, -1, -1, -1, 10, -1, -1, -1, -1) class EDGE_ENHANCE_MORE(BuiltinFilter): name = "Edge-enhance More" - filterargs = (3, 3), 1, 0, ( - -1, -1, -1, - -1, 9, -1, - -1, -1, -1 - ) + filterargs = (3, 3), 1, 0, (-1, -1, -1, -1, 9, -1, -1, -1, -1) class EMBOSS(BuiltinFilter): name = "Emboss" - filterargs = (3, 3), 1, 128, ( - -1, 0, 0, - 0, 1, 0, - 0, 0, 0 - ) + filterargs = (3, 3), 1, 128, (-1, 0, 0, 0, 1, 0, 0, 0, 0) class FIND_EDGES(BuiltinFilter): name = "Find Edges" - filterargs = (3, 3), 1, 0, ( - -1, -1, -1, - -1, 8, -1, - -1, -1, -1 - ) + filterargs = (3, 3), 1, 0, (-1, -1, -1, -1, 8, -1, -1, -1, -1) class SMOOTH(BuiltinFilter): name = "Smooth" - filterargs = (3, 3), 13, 0, ( - 1, 1, 1, - 1, 5, 1, - 1, 1, 1 - ) + filterargs = (3, 3), 13, 0, (1, 1, 1, 1, 5, 1, 1, 1, 1) class SMOOTH_MORE(BuiltinFilter): name = "Smooth More" - filterargs = (5, 5), 100, 0, ( - 1, 1, 1, 1, 1, - 1, 5, 5, 5, 1, - 1, 5, 44, 5, 1, - 1, 5, 5, 5, 1, - 1, 1, 1, 1, 1 - ) + filterargs = (5, 5), 100, 0, (1, 1, 1, 1, 1, 1, 5, 5, 5, 1, 1, 5, 44, 5, 1, + 1, 5, 5, 5, 1, 1, 1, 1, 1, 1) class SHARPEN(BuiltinFilter): name = "Sharpen" - filterargs = (3, 3), 16, 0, ( - -2, -2, -2, - -2, 32, -2, - -2, -2, -2 - ) + filterargs = (3, 3), 16, 0, (-2, -2, -2, -2, 32, -2, -2, -2, -2) diff --git a/PIL/ImageFont.py b/PIL/ImageFont.py index 1e5a27f7b25..a9d3c43cf1b 100644 --- a/PIL/ImageFont.py +++ b/PIL/ImageFont.py @@ -43,6 +43,7 @@ class _imagingft_not_installed: def __getattr__(self, id): raise ImportError("The _imagingft C module is not installed") + try: from PIL import _imagingft as core except ImportError: @@ -101,7 +102,7 @@ def _load_pilfont_data(self, file, image): self.info.append(s) # read PILfont metrics - data = file.read(256*20) + data = file.read(256 * 20) # check image if image.mode not in ("1", "L"): @@ -115,11 +116,11 @@ def _load_pilfont_data(self, file, image): self.getsize = self.font.getsize self.getmask = self.font.getmask - ## # Wrapper for FreeType fonts. Application code should use the # truetype factory function to create font objects. + class FreeTypeFont: "FreeType font wrapper (requires _imagingft service)" @@ -127,10 +128,9 @@ def __init__(self, font=None, size=10, index=0, encoding="", file=None): # FIXME: use service provider instead if file: if warnings: - warnings.warn( - 'file parameter deprecated, ' - 'please use font parameter instead.', - DeprecationWarning) + warnings.warn('file parameter deprecated, ' + 'please use font parameter instead.', + DeprecationWarning) font = file self.path = font @@ -142,8 +142,8 @@ def __init__(self, font=None, size=10, index=0, encoding="", file=None): self.font = core.getfont(font, size, index, encoding) else: self.font_bytes = font.read() - self.font = core.getfont( - "", size, index, encoding, self.font_bytes) + self.font = core.getfont("", size, index, encoding, + self.font_bytes) def getname(self): return self.font.family, self.font.style @@ -177,11 +177,11 @@ def font_variant(self, font=None, size=None, index=None, encoding=None): :return: A FreeTypeFont object. """ - return FreeTypeFont(font=self.path if font is None else font, - size=self.size if size is None else size, - index=self.index if index is None else index, - encoding=self.encoding if encoding is None else - encoding) + return FreeTypeFont( + font=self.path if font is None else font, + size=self.size if size is None else size, + index=self.index if index is None else index, + encoding=self.encoding if encoding is None else encoding) ## # 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 warnings: - warnings.warn( - 'filename parameter deprecated, ' - 'please use font parameter instead.', - DeprecationWarning) + warnings.warn('filename parameter deprecated, ' + 'please use font parameter instead.', + DeprecationWarning) font = filename 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 # default to /usr/share lindirs = '/usr/share' - dirs += [os.path.join(lindir, "fonts") for lindir in lindirs.split(":")] + dirs += [os.path.join(lindir, "fonts") + for lindir in lindirs.split(":")] elif sys.platform == 'darwin': dirs += ['/Library/Fonts', '/System/Library/Fonts', os.path.expanduser('~/Library/Fonts')] @@ -290,7 +290,8 @@ def truetype(font=None, size=10, index=0, encoding="", filename=None): if ext and walkfilename == ttf_filename: fontpath = os.path.join(walkroot, walkfilename) return FreeTypeFont(fontpath, size, index, encoding) - elif not ext and os.path.splitext(walkfilename)[0] == ttf_filename: + elif not ext and os.path.splitext( + walkfilename)[0] == ttf_filename: fontpath = os.path.join(walkroot, walkfilename) if os.path.splitext(fontpath)[1] == '.ttf': return FreeTypeFont(fontpath, size, index, encoding) @@ -335,8 +336,7 @@ def load_default(): from io import BytesIO import base64 f = ImageFont() - f._load_pilfont_data( - # courB08 + f._load_pilfont_data( # courB08 BytesIO(base64.decodestring(b''' UElMZm9udAo7Ozs7OzsxMDsKREFUQQoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA diff --git a/PIL/ImageGrab.py b/PIL/ImageGrab.py index ef013533426..7bd77a701a5 100644 --- a/PIL/ImageGrab.py +++ b/PIL/ImageGrab.py @@ -32,11 +32,9 @@ def grab(bbox=None): size, data = grabber() - im = Image.frombytes( - "RGB", size, data, - # RGB, 32-bit line padding, origo in lower left corner - "raw", "BGR", (size[0]*3 + 3) & -4, -1 - ) + im = Image.frombytes("RGB", size, data, + # RGB, 32-bit line padding, origo in lower left corner + "raw", "BGR", (size[0] * 3 + 3) & -4, -1) if bbox: im = im.crop(bbox) return im diff --git a/PIL/ImageMath.py b/PIL/ImageMath.py index 4dcc5125cf1..4b4c892774b 100644 --- a/PIL/ImageMath.py +++ b/PIL/ImageMath.py @@ -61,7 +61,7 @@ def apply(self, op, im1, im2=None, mode=None): out = Image.new(mode or im1.mode, im1.size, None) im1.load() try: - op = getattr(_imagingmath, op+"_"+im1.mode) + op = getattr(_imagingmath, op + "_" + im1.mode) except AttributeError: raise TypeError("bad operand type for '%s'" % op) _imagingmath.unop(op, out.im.id, im1.im.id) @@ -90,7 +90,7 @@ def apply(self, op, im1, im2=None, mode=None): im1.load() im2.load() try: - op = getattr(_imagingmath, op+"_"+im1.mode) + op = getattr(_imagingmath, op + "_" + im1.mode) except AttributeError: raise TypeError("bad operand type for '%s'" % op) _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): return _Operand(self.im.convert(mode)) + ops = {} for k, v in list(globals().items()): if k[:10] == "imagemath_": diff --git a/PIL/ImageMode.py b/PIL/ImageMode.py index 29506910898..c37894a1ce7 100644 --- a/PIL/ImageMode.py +++ b/PIL/ImageMode.py @@ -16,12 +16,11 @@ # mode descriptor cache _modes = {} - ## # Wrapper for mode strings. -class ModeDescriptor: +class ModeDescriptor: def __init__(self, mode, bands, basemode, basetype): self.mode = mode self.bands = bands @@ -31,10 +30,10 @@ def __init__(self, mode, bands, basemode, basetype): def __str__(self): return self.mode - ## # Gets a mode descriptor for the given mode. + def getmode(mode): if not _modes: # initialize mode cache diff --git a/PIL/ImageMorph.py b/PIL/ImageMorph.py index 996eacb7d69..bc0da5a74dc 100644 --- a/PIL/ImageMorph.py +++ b/PIL/ImageMorph.py @@ -47,6 +47,7 @@ class LutBuilder: lut = lb.build_lut() """ + def __init__(self, patterns=None, op_name=None): if patterns is not None: self.patterns = patterns @@ -55,20 +56,16 @@ def __init__(self, patterns=None, op_name=None): self.lut = None if op_name is not None: known_patterns = { - 'corner': ['1:(... ... ...)->0', - '4:(00. 01. ...)->1'], + 'corner': ['1:(... ... ...)->0', '4:(00. 01. ...)->1'], 'dilation4': ['4:(... .0. .1.)->1'], - 'dilation8': ['4:(... .0. .1.)->1', - '4:(... .0. ..1)->1'], + 'dilation8': ['4:(... .0. .1.)->1', '4:(... .0. ..1)->1'], 'erosion4': ['4:(... .1. .0.)->0'], - 'erosion8': ['4:(... .1. .0.)->0', - '4:(... .1. ..0)->0'], - 'edge': ['1:(... ... ...)->0', - '4:(.0. .1. ...)->1', + 'erosion8': ['4:(... .1. .0.)->0', '4:(... .1. ..0)->0'], + 'edge': ['1:(... ... ...)->0', '4:(.0. .1. ...)->1', '4:(01. .1. ...)->1'] } if op_name not in known_patterns: - raise Exception('Unknown pattern '+op_name+'!') + raise Exception('Unknown pattern ' + op_name + '!') self.patterns = known_patterns[op_name] @@ -87,7 +84,7 @@ def _string_permute(self, pattern, permutation): """string_permute takes a pattern and a permutation and returns the string permuted according to the permutation list. """ - assert(len(permutation) == 9) + assert (len(permutation) == 9) return ''.join([pattern[p] for p in permutation]) def _pattern_permute(self, basic_pattern, options, basic_result): @@ -100,29 +97,25 @@ def _pattern_permute(self, basic_pattern, options, basic_result): if '4' in options: res = patterns[-1][1] for i in range(4): - patterns.append( - (self._string_permute(patterns[-1][0], [6, 3, 0, - 7, 4, 1, - 8, 5, 2]), res)) + patterns.append((self._string_permute(patterns[-1][0], + [6, 3, 0, 7, 4, 1, 8, 5, + 2]), res)) # mirror if 'M' in options: n = len(patterns) for pattern, res in patterns[0:n]: - patterns.append( - (self._string_permute(pattern, [2, 1, 0, - 5, 4, 3, - 8, 7, 6]), res)) + patterns.append((self._string_permute(pattern, [2, 1, 0, 5, 4, + 3, 8, 7, 6]), + res)) # negate if 'N' in options: n = len(patterns) for pattern, res in patterns[0:n]: # Swap 0 and 1 - pattern = (pattern - .replace('0', 'Z') - .replace('1', '0') - .replace('Z', '1')) - res = '%d' % (1-int(res)) + pattern = (pattern.replace('0', 'Z').replace('1', '0').replace( + 'Z', '1')) + res = '%d' % (1 - int(res)) patterns.append((pattern, res)) return patterns @@ -137,10 +130,10 @@ def build_lut(self): # Parse and create symmetries of the patterns strings for p in self.patterns: - m = re.search( - r'(\w*):?\s*\((.+?)\)\s*->\s*(\d)', p.replace('\n', '')) + m = re.search(r'(\w*):?\s*\((.+?)\)\s*->\s*(\d)', + p.replace('\n', '')) if not m: - raise Exception('Syntax error in pattern "'+p+'"') + raise Exception('Syntax error in pattern "' + p + '"') options = m.group(1) pattern = m.group(2) result = int(m.group(3)) @@ -155,7 +148,7 @@ def build_lut(self): # print p,r # print '--' - # compile the patterns into regular expressions for speed +# compile the patterns into regular expressions for speed for i in range(len(patterns)): p = patterns[i][0].replace('.', 'X').replace('X', '[01]') p = re.compile(p) @@ -167,7 +160,7 @@ def build_lut(self): for i in range(LUT_SIZE): # Build the bit pattern bitpattern = bin(i)[2:] - bitpattern = ('0'*(9-len(bitpattern)) + bitpattern)[::-1] + bitpattern = ('0' * (9 - len(bitpattern)) + bitpattern)[::-1] for p, r in patterns: if p.match(bitpattern): @@ -179,10 +172,7 @@ def build_lut(self): class MorphOp: """A class for binary morphological operators""" - def __init__(self, - lut=None, - op_name=None, - patterns=None): + def __init__(self, lut=None, op_name=None, patterns=None): """Create a binary morphological operator""" self.lut = lut if op_name is not None: @@ -199,8 +189,8 @@ def apply(self, image): raise Exception('No operator loaded') outimage = Image.new(image.mode, image.size, None) - count = _imagingmorph.apply( - bytes(self.lut), image.im.id, outimage.im.id) + count = _imagingmorph.apply(bytes(self.lut), image.im.id, + outimage.im.id) return count, outimage def match(self, image): diff --git a/PIL/ImageOps.py b/PIL/ImageOps.py index a1706875d18..b3b7a56f4c9 100644 --- a/PIL/ImageOps.py +++ b/PIL/ImageOps.py @@ -22,10 +22,10 @@ import operator from functools import reduce - # # helpers + def _border(border): if isinstance(border, tuple): if len(border) == 2: @@ -75,7 +75,7 @@ def autocontrast(image, cutoff=0, ignore=None): histogram = image.histogram() lut = [] for layer in range(0, len(histogram), 256): - h = histogram[layer:layer+256] + h = histogram[layer:layer + 256] if ignore is not None: # get rid of outliers try: @@ -154,9 +154,9 @@ def colorize(image, black, white): green = [] blue = [] for i in range(256): - red.append(black[0]+i*(white[0]-black[0])//255) - green.append(black[1]+i*(white[1]-black[1])//255) - blue.append(black[2]+i*(white[2]-black[2])//255) + red.append(black[0] + i * (white[0] - black[0]) // 255) + green.append(black[1] + i * (white[1] - black[1]) // 255) + blue.append(black[2] + i * (white[2] - black[2]) // 255) image = image.convert("RGB") return _lut(image, red + green + blue) @@ -174,8 +174,7 @@ def crop(image, border=0): """ left, top, right, bottom = _border(border) return image.crop( - (left, top, image.size[0]-right, image.size[1]-bottom) - ) + (left, top, image.size[0] - right, image.size[1] - bottom)) def deform(image, deformer, resample=Image.BILINEAR): @@ -188,9 +187,8 @@ def deform(image, deformer, resample=Image.BILINEAR): :param resample: What resampling filter to use. :return: An image. """ - return image.transform( - image.size, Image.MESH, deformer.getmesh(image), resample - ) + return image.transform(image.size, Image.MESH, deformer.getmesh(image), + resample) def equalize(image, mask=None): @@ -209,7 +207,7 @@ def equalize(image, mask=None): h = image.histogram(mask) lut = [] 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: lut.extend(list(range(256))) else: @@ -220,7 +218,7 @@ def equalize(image, mask=None): n = step // 2 for i in range(256): lut.append(n // step) - n = n + h[i+b] + n = n + h[i + b] 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 # number of pixels to trim off on Top and Bottom, Left and Right - bleedPixels = ( - int((float(bleed) * float(image.size[0])) + 0.5), - int((float(bleed) * float(image.size[1])) + 0.5) - ) + bleedPixels = (int((float(bleed) * float(image.size[0])) + 0.5), + int((float(bleed) * float(image.size[1])) + 0.5)) liveArea = (0, 0, image.size[0], image.size[1]) if bleed > 0.0: - liveArea = ( - bleedPixels[0], bleedPixels[1], image.size[0] - bleedPixels[0] - 1, - image.size[1] - bleedPixels[1] - 1 - ) + liveArea = (bleedPixels[0], bleedPixels[1], + image.size[0] - bleedPixels[0] - 1, + image.size[1] - bleedPixels[1] - 1) liveSize = (liveArea[2] - liveArea[0], liveArea[3] - liveArea[1]) # 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 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: # liveArea is taller than what's needed, crop the top and bottom cropWidth = liveSize[0] - cropHeight = int((float(liveSize[0])/aspectRatio) + 0.5) + cropHeight = int((float(liveSize[0]) / aspectRatio) + 0.5) # make the crop - leftSide = int(liveArea[0] + (float(liveSize[0]-cropWidth) * centering[0])) + leftSide = int(liveArea[0] + + (float(liveSize[0] - cropWidth) * centering[0])) if leftSide < 0: leftSide = 0 - topSide = int(liveArea[1] + (float(liveSize[1]-cropHeight) * centering[1])) + topSide = int(liveArea[1] + + (float(liveSize[1] - cropHeight) * centering[1])) if topSide < 0: topSide = 0 out = image.crop( - (leftSide, topSide, leftSide + cropWidth, topSide + cropHeight) - ) + (leftSide, topSide, leftSide + cropWidth, topSide + cropHeight)) # resize the image and return it return out.resize(size, method) @@ -364,7 +360,7 @@ def invert(image): """ lut = [] for i in range(256): - lut.append(255-i) + lut.append(255 - i) return _lut(image, lut) @@ -387,7 +383,7 @@ def posterize(image, bits): :return: An image. """ lut = [] - mask = ~(2**(8-bits)-1) + mask = ~(2 ** (8 - bits) - 1) for i in range(256): lut.append(i & mask) return _lut(image, lut) @@ -406,13 +402,13 @@ def solarize(image, threshold=128): if i < threshold: lut.append(i) else: - lut.append(255-i) + lut.append(255 - i) return _lut(image, lut) - # -------------------------------------------------------------------- # PIL USM components, from Kevin Cazabon. + def gaussian_blur(im, radius=None): """ PIL_usm.gblur(im, [radius])""" @@ -423,6 +419,7 @@ def gaussian_blur(im, radius=None): return im.im.gaussian_blur(radius) + gblur = gaussian_blur @@ -440,6 +437,7 @@ def unsharp_mask(im, radius=None, percent=None, threshold=None): return im.im.unsharp_mask(radius, percent, threshold) + usm = unsharp_mask diff --git a/PIL/ImagePalette.py b/PIL/ImagePalette.py index 62f8814f156..24f49b738ce 100644 --- a/PIL/ImagePalette.py +++ b/PIL/ImagePalette.py @@ -27,11 +27,11 @@ class ImagePalette: def __init__(self, mode="RGB", palette=None, size=0): self.mode = mode 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.dirty = None - if ((size == 0 and len(self.mode)*256 != len(self.palette)) or - (size != 0 and size != len(self.palette))): + if ((size == 0 and len(self.mode) * 256 != len(self.palette)) or + (size != 0 and size != len(self.palette))): raise ValueError("wrong palette size") def getdata(self): @@ -82,8 +82,8 @@ def getcolor(self, color): raise ValueError("cannot allocate more than 256 colors") self.colors[color] = index self.palette[index] = color[0] - self.palette[index+256] = color[1] - self.palette[index+512] = color[2] + self.palette[index + 256] = color[1] + self.palette[index + 512] = color[2] self.dirty = 1 return index else: @@ -102,7 +102,7 @@ def save(self, fp): fp.write("# Mode: %s\n" % self.mode) for i in range(256): 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: fp.write(" %d" % self.palette[j]) except IndexError: @@ -110,10 +110,10 @@ def save(self, fp): fp.write("\n") fp.close() - # -------------------------------------------------------------------- # Internal + def raw(rawmode, data): palette = ImagePalette() palette.rawmode = rawmode @@ -121,27 +121,21 @@ def raw(rawmode, data): palette.dirty = 1 return palette - # -------------------------------------------------------------------- # Factories + def _make_linear_lut(black, white): - warnings.warn( - '_make_linear_lut() is deprecated. ' - 'Please call make_linear_lut() instead.', - DeprecationWarning, - stacklevel=2 - ) + warnings.warn('_make_linear_lut() is deprecated. ' + 'Please call make_linear_lut() instead.', DeprecationWarning, + stacklevel=2) return make_linear_lut(black, white) def _make_gamma_lut(exp): - warnings.warn( - '_make_gamma_lut() is deprecated. ' - 'Please call make_gamma_lut() instead.', - DeprecationWarning, - stacklevel=2 - ) + warnings.warn('_make_gamma_lut() is deprecated. ' + 'Please call make_gamma_lut() instead.', DeprecationWarning, + stacklevel=2) return make_gamma_lut(exp) @@ -149,7 +143,7 @@ def make_linear_lut(black, white): lut = [] if black == 0: for i in range(256): - lut.append(white*i//255) + lut.append(white * i // 255) else: raise NotImplementedError # FIXME return lut @@ -171,7 +165,7 @@ def negative(mode="RGB"): def random(mode="RGB"): from random import randint palette = [] - for i in range(256*len(mode)): + for i in range(256 * len(mode)): palette.append(randint(0, 255)) return ImagePalette(mode, palette) diff --git a/PIL/ImagePath.py b/PIL/ImagePath.py index 656d5ce617b..ba9b74c2bb2 100644 --- a/PIL/ImagePath.py +++ b/PIL/ImagePath.py @@ -16,12 +16,10 @@ from PIL import Image - # the Python class below is overridden by the C implementation. class Path: - def __init__(self, xy): pass @@ -61,6 +59,5 @@ def tolist(self, flat=0): def transform(self, matrix): pass - # override with C implementation Path = Image.core.path diff --git a/PIL/ImageQt.py b/PIL/ImageQt.py index 22ee2ea8f79..379d7493b80 100644 --- a/PIL/ImageQt.py +++ b/PIL/ImageQt.py @@ -29,18 +29,18 @@ except: from PySide.QtGui import QImage, qRgba -else: #PyQt4 is used +else: #PyQt4 is used from PyQt4.QtGui import QImage, qRgba ## # (Internal) Turns an RGB color into a Qt compatible color integer. + def rgb(r, g, b, a=255): # use qRgb to pack the colors, and then turn the resulting long # into a negative integer with the same bitpattern. return (qRgba(r, g, b, a) & 0xffffffff) - ## # An PIL image wrapper for Qt. This is a subclass of PyQt4's QImage # class. @@ -48,8 +48,8 @@ def rgb(r, g, b, a=255): # @param im A PIL Image object, or a file name (given either as Python # string or a PyQt string object). -class ImageQt(QImage): +class ImageQt(QImage): def __init__(self, im): data = None @@ -74,7 +74,7 @@ def __init__(self, im): colortable = [] palette = im.getpalette() 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": data = im.tobytes("raw", "BGRX") format = QImage.Format_RGB32 diff --git a/PIL/ImageShow.py b/PIL/ImageShow.py index 9527dbf971b..373b565b8e1 100644 --- a/PIL/ImageShow.py +++ b/PIL/ImageShow.py @@ -37,7 +37,6 @@ def register(viewer, order=1): elif order < 0: _viewers.insert(0, viewer) - ## # Displays a given image. # @@ -46,16 +45,17 @@ def register(viewer, order=1): # @param **options Additional viewer options. # @return True if a suitable viewer was found, false otherwise. + def show(image, title=None, **options): for viewer in _viewers: if viewer.show(image, title=title, **options): return 1 return 0 - ## # Base class for viewers. + class Viewer: # main api @@ -147,8 +147,7 @@ def which(executable): class UnixViewer(Viewer): def show_file(self, file, **options): command, executable = self.get_command_ex(file, **options) - command = "(%s %s; rm -f %s)&" % (command, quote(file), - quote(file)) + command = "(%s %s; rm -f %s)&" % (command, quote(file), quote(file)) os.system(command) return 1 diff --git a/PIL/ImageStat.py b/PIL/ImageStat.py index 7e023c673c8..297cc38fdf3 100644 --- a/PIL/ImageStat.py +++ b/PIL/ImageStat.py @@ -27,7 +27,6 @@ class Stat: - def __init__(self, image_or_list, mask=None): try: if mask: @@ -71,7 +70,7 @@ def _getcount(self): v = [] 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 def _getsum(self): @@ -110,10 +109,10 @@ def _getmedian(self): v = [] for i in self.bands: s = 0 - l = self.count[i]//2 + l = self.count[i] // 2 b = i * 256 for j in range(256): - s = s + self.h[b+j] + s = s + self.h[b + j] if s > l: break v.append(j) @@ -133,7 +132,7 @@ def _getvar(self): v = [] for i in self.bands: 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 def _getstddev(self): @@ -144,4 +143,5 @@ def _getstddev(self): v.append(math.sqrt(self.var[i])) return v + Global = Stat # compatibility diff --git a/PIL/ImageTk.py b/PIL/ImageTk.py index 5fb5ecff392..0b310046a10 100644 --- a/PIL/ImageTk.py +++ b/PIL/ImageTk.py @@ -34,7 +34,6 @@ from PIL import Image - # -------------------------------------------------------------------- # Check for Tkinter interface hooks @@ -52,10 +51,10 @@ def _pilbitmap_check(): _pilbitmap_ok = 0 return _pilbitmap_ok - # -------------------------------------------------------------------- # PhotoImage + class PhotoImage: """ A Tkinter-compatible photo image. This can be used @@ -269,20 +268,21 @@ def getimage(photo): """Copies the contents of a PhotoImage to a PIL image memory.""" photo.tk.call("PyImagingPhotoGet", photo) - # -------------------------------------------------------------------- # Helper for the Image.show method. -def _show(image, title): +def _show(image, title): class UI(tkinter.Label): def __init__(self, master, im): if im.mode == "1": self.image = BitmapImage(im, foreground="white", master=master) else: self.image = PhotoImage(im, master=master) - tkinter.Label.__init__(self, master, image=self.image, - bg="black", bd=0) + tkinter.Label.__init__(self, master, + image=self.image, + bg="black", + bd=0) if not tkinter._default_root: raise IOError("tkinter not initialized") diff --git a/PIL/ImageTransform.py b/PIL/ImageTransform.py index 81f90502caa..a1acf60b7f9 100644 --- a/PIL/ImageTransform.py +++ b/PIL/ImageTransform.py @@ -28,7 +28,6 @@ def transform(self, size, image, **options): method, data = self.getdata() return image.transform(size, method, data, **options) - ## # Define an affine image transform. #
@@ -51,7 +50,6 @@ def transform(self, size, image, **options): class AffineTransform(Transform): method = Image.AFFINE - ## # Define a transform to extract a subregion from an image. #
@@ -71,10 +69,10 @@ class AffineTransform(Transform): # two points in the input image's coordinate system. # @see Image#Image.transform + class ExtentTransform(Transform): method = Image.EXTENT - ## # Define an quad image transform. #
@@ -87,10 +85,10 @@ class ExtentTransform(Transform): # corner of the source quadrilateral. # @see Image#Image.transform + class QuadTransform(Transform): method = Image.QUAD - ## # Define an mesh image transform. A mesh transform consists of one # or more individual quad transforms. @@ -99,5 +97,6 @@ class QuadTransform(Transform): # @param data A list of (bbox, quad) tuples. # @see Image#Image.transform + class MeshTransform(Transform): method = Image.MESH diff --git a/PIL/ImageWin.py b/PIL/ImageWin.py index 300d118c932..875c46e9141 100644 --- a/PIL/ImageWin.py +++ b/PIL/ImageWin.py @@ -27,6 +27,7 @@ class HDC: :py:meth:`~PIL.ImageWin.Dib.draw` and :py:meth:`~PIL.ImageWin.Dib.expose` methods. """ + def __init__(self, dc): self.dc = dc @@ -40,6 +41,7 @@ class HWND: :py:meth:`~PIL.ImageWin.Dib.draw` and :py:meth:`~PIL.ImageWin.Dib.expose` methods, instead of a DC. """ + def __init__(self, wnd): self.wnd = wnd @@ -190,28 +192,24 @@ def fromstring(self, *args, **kw): warnings.warn( 'fromstring() is deprecated. Please call frombytes() instead.', DeprecationWarning, - stacklevel=2 - ) + stacklevel=2) return self.frombytes(*args, **kw) def tostring(self): warnings.warn( 'tostring() is deprecated. Please call tobytes() instead.', DeprecationWarning, - stacklevel=2 - ) + stacklevel=2) return self.tobytes() - ## # Create a Window with the given title size. -class Window: +class Window: def __init__(self, title="PIL", width=None, height=None): - self.hwnd = Image.core.createwindow( - title, self.__dispatcher, width or 0, height or 0 - ) + self.hwnd = Image.core.createwindow(title, self.__dispatcher, + width or 0, height or 0) def __dispatcher(self, action, *args): return getattr(self, "ui_handle_" + action)(*args) @@ -234,12 +232,11 @@ def ui_handle_resize(self, width, height): def mainloop(self): Image.core.eventloop() - ## # Create an image window which displays the given image. -class ImageWindow(Window): +class ImageWindow(Window): def __init__(self, image, title="PIL"): if not isinstance(image, Dib): image = Dib(image) diff --git a/PIL/ImtImagePlugin.py b/PIL/ImtImagePlugin.py index f512eb801ec..203cdb3234a 100644 --- a/PIL/ImtImagePlugin.py +++ b/PIL/ImtImagePlugin.py @@ -14,7 +14,6 @@ # See the README file for information on usage and redistribution. # - __version__ = "0.2" import re @@ -26,10 +25,10 @@ field = re.compile(br"([a-z]*) ([^ \r\n]*)") - ## # Image plugin for IM Tools images. + class ImtImageFile(ImageFile.ImageFile): format = "IMT" @@ -55,9 +54,8 @@ def _open(self): if s == b'\x0C': # image data begins - self.tile = [("raw", (0, 0)+self.size, - self.fp.tell(), - (self.mode, 0, 1))] + self.tile = [("raw", (0, 0) + self.size, self.fp.tell(), + (self.mode, 0, 1))] break @@ -84,7 +82,6 @@ def _open(self): elif k == "pixel" and v == "n8": self.mode = "L" - # # -------------------------------------------------------------------- diff --git a/PIL/IptcImagePlugin.py b/PIL/IptcImagePlugin.py index dc860759182..d214a5fe735 100644 --- a/PIL/IptcImagePlugin.py +++ b/PIL/IptcImagePlugin.py @@ -19,7 +19,6 @@ __version__ = "0.3" - from PIL import Image, ImageFile, _binary import os import tempfile @@ -29,17 +28,14 @@ i32 = _binary.i32be o8 = _binary.o8 -COMPRESSION = { - 1: "raw", - 5: "jpeg" -} +COMPRESSION = {1: "raw", 5: "jpeg"} PAD = o8(0) * 4 - # # Helpers + def i(c): return i32((PAD + c)[-4:]) @@ -49,11 +45,11 @@ def dump(c): print("%02x" % i8(i), end=' ') print() - ## # Image plugin for IPTC/NAA datastreams. To read IPTC/NAA fields # from TIFF and JPEG files, use the getiptcinfo function. + class IptcImageFile(ImageFile.ImageFile): format = "IPTC" @@ -82,7 +78,7 @@ def field(self): elif size == 128: size = 0 elif size > 128: - size = i(self.fp.read(size-128)) + size = i(self.fp.read(size - 128)) else: size = i16(s[3:]) @@ -110,19 +106,19 @@ def _open(self): # print tag, self.info[tag] - # mode + # mode layers = i8(self.info[(3, 60)][0]) component = i8(self.info[(3, 60)][1]) if (3, 65) in self.info: - id = i8(self.info[(3, 65)][0])-1 + id = i8(self.info[(3, 65)][0]) - 1 else: id = 0 if layers == 1 and not component: self.mode = "L" elif layers == 3 and component: - self.mode = "RGB"[id] + self.mode = "RGB" [id] elif layers == 4 and component: - self.mode = "CMYK"[id] + self.mode = "CMYK" [id] # size self.size = self.getint((3, 20)), self.getint((3, 30)) @@ -136,7 +132,7 @@ def _open(self): # tile if tag == (8, 10): self.tile = [("iptc", (compression, offset), - (0, 0, self.size[0], self.size[1]))] + (0, 0, self.size[0], self.size[1]))] def load(self): @@ -188,7 +184,6 @@ def load(self): Image.register_extension("IPTC", ".iim") - ## # Get IPTC information from TIFF, JPEG, or IPTC file. # @@ -196,6 +191,7 @@ def load(self): # @return A dictionary containing IPTC information, or None if # no IPTC information block was found. + def getiptcinfo(im): from PIL import TiffImagePlugin, JpegImagePlugin @@ -215,14 +211,14 @@ def getiptcinfo(im): app = app[14:] # parse the image resource block offset = 0 - while app[offset:offset+4] == b"8BIM": + while app[offset:offset + 4] == b"8BIM": offset += 4 # resource code code = JpegImagePlugin.i16(app, offset) offset += 2 # resource name (usually empty) 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 if offset & 1: offset += 1 @@ -231,7 +227,7 @@ def getiptcinfo(im): offset += 4 if code == 0x0404: # 0x0404 contains IPTC/NAA data - data = app[offset:offset+size] + data = app[offset:offset + size] break offset = offset + size if offset & 1: @@ -253,6 +249,7 @@ def getiptcinfo(im): # create an IptcImagePlugin object without initializing it class FakeImage: pass + im = FakeImage() im.__class__ = IptcImageFile diff --git a/PIL/Jpeg2KImagePlugin.py b/PIL/Jpeg2KImagePlugin.py index ed3e1530a6d..a083a12acbd 100644 --- a/PIL/Jpeg2KImagePlugin.py +++ b/PIL/Jpeg2KImagePlugin.py @@ -30,9 +30,9 @@ def _parse_codestream(fp): lsiz, rsiz, xsiz, ysiz, xosiz, yosiz, xtsiz, ytsiz, \ xtosiz, ytosiz, csiz \ = struct.unpack('>HHIIIIIIIIH', siz[:38]) - ssiz = [None]*csiz - xrsiz = [None]*csiz - yrsiz = [None]*csiz + ssiz = [None] * csiz + xrsiz = [None] * csiz + yrsiz = [None] * csiz for i in range(csiz): ssiz[i], xrsiz[i], yrsiz[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]) if meth == 1: cs = struct.unpack('>I', content[3:7])[0] - if cs == 16: # sRGB + if cs == 16: # sRGB if nc == 1 and (bpc & 0x7f) > 8: mode = 'I;16' elif nc == 1: @@ -210,10 +210,10 @@ def _accept(prefix): return (prefix[:4] == b'\xff\x4f\xff\x51' or prefix[:12] == b'\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a') - # ------------------------------------------------------------ # Save support + def _save(im, fp, filename): if filename.endswith('.j2k'): kind = 'j2k' @@ -242,22 +242,12 @@ def _save(im, fp, filename): except: fd = -1 - im.encoderconfig = ( - offset, - tile_offset, - tile_size, - quality_mode, - quality_layers, - num_resolutions, - cblk_size, - precinct_size, - irreversible, - progression, - cinema_mode, - fd - ) - - ImageFile._save(im, fp, [('jpeg2k', (0, 0)+im.size, 0, kind)]) + im.encoderconfig = (offset, tile_offset, tile_size, quality_mode, + quality_layers, num_resolutions, cblk_size, + precinct_size, irreversible, progression, cinema_mode, + fd) + + ImageFile._save(im, fp, [('jpeg2k', (0, 0) + im.size, 0, kind)]) # ------------------------------------------------------------ # Registry stuff diff --git a/PIL/JpegImagePlugin.py b/PIL/JpegImagePlugin.py index 8c20f586329..0e4a060a368 100644 --- a/PIL/JpegImagePlugin.py +++ b/PIL/JpegImagePlugin.py @@ -47,12 +47,12 @@ i16 = _binary.i16be i32 = _binary.i32be - # # Parser + def Skip(self, marker): - n = i16(self.fp.read(2))-2 + n = i16(self.fp.read(2)) - 2 ImageFile._safe_read(self.fp, n) @@ -61,7 +61,7 @@ def APP(self, marker): # Application marker. Store these in the APP dictionary. # 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) app = "APP%d" % (marker & 15) @@ -123,7 +123,7 @@ def APP(self, marker): def COM(self, marker): # # 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) self.app["COM"] = s # compatibility @@ -138,7 +138,7 @@ def SOF(self, marker): # mode. Note that this could be made a bit brighter, by # 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) self.size = i16(s[3:]), i16(s[1:]) @@ -173,9 +173,9 @@ def SOF(self, marker): self.icclist = None for i in range(6, len(s), 3): - t = s[i:i+3] + t = s[i:i + 3] # 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): @@ -187,22 +187,22 @@ def DQT(self, marker): # FIXME: The quantization tables can be used to estimate the # compression quality. - n = i16(self.fp.read(2))-2 + n = i16(self.fp.read(2)) - 2 s = ImageFile._safe_read(self.fp, n) while len(s): if len(s) < 65: raise SyntaxError("bad quantization table marker") v = i8(s[0]) - if v//16 == 0: + if v // 16 == 0: self.quantization[v & 15] = array.array("b", s[1:65]) s = s[65:] else: return # FIXME: add code to read 16-bit tables! # raise SyntaxError, "bad quantization table element size" + # + # JPEG marker table -# -# JPEG marker table MARKER = { 0xFFC0: ("SOF0", "Baseline DCT", SOF), @@ -274,10 +274,10 @@ def DQT(self, marker): def _accept(prefix): return prefix[0:1] == b"\377" - ## # Image plugin for JPEG and JFIF images. + class JpegImageFile(ImageFile.ImageFile): format = "JPEG" @@ -323,7 +323,7 @@ def _open(self): if self.mode == "CMYK": rawmode = "CMYK;I" # assume adobe conventions self.tile = [("jpeg", (0, 0) + self.size, 0, - (rawmode, ""))] + (rawmode, ""))] # self.__offset = self.fp.tell() break s = self.fp.read(1) @@ -350,8 +350,10 @@ def draft(self, mode, size): for s in [8, 4, 2, 1]: if scale >= s: break - e = e[0], e[1], (e[2]-e[0]+s-1)//s+e[0], (e[3]-e[1]+s-1)//s+e[1] - self.size = ((self.size[0]+s-1)//s, (self.size[1]+s-1)//s) + e = e[0], e[1], (e[2] - e[0] + s - + 1) // s + e[0], (e[3] - e[1] + s - 1) // s + e[1] + self.size = ((self.size[0] + s - 1) // s, + (self.size[1] + s - 1) // s) scale = s self.tile = [(d, e, o, a)] @@ -513,7 +515,6 @@ def _getmp(self): # file and so can't test it. return mp - # -------------------------------------------------------------------- # stuff to save JPEG files @@ -527,19 +528,16 @@ def _getmp(self): "YCbCr": "YCbCr", } -zigzag_index = ( 0, 1, 5, 6, 14, 15, 27, 28, - 2, 4, 7, 13, 16, 26, 29, 42, - 3, 8, 12, 17, 25, 30, 41, 43, - 9, 11, 18, 24, 31, 40, 44, 53, - 10, 19, 23, 32, 39, 45, 52, 54, - 20, 22, 33, 38, 46, 51, 55, 60, - 21, 34, 37, 47, 50, 56, 59, 61, - 35, 36, 48, 49, 57, 58, 62, 63) +zigzag_index = (0, 1, 5, 6, 14, 15, 27, 28, 2, 4, 7, 13, 16, 26, 29, 42, 3, 8, + 12, 17, 25, 30, 41, 43, 9, 11, 18, 24, 31, 40, 44, 53, 10, 19, + 23, 32, 39, 45, 52, 54, 20, 22, 33, 38, 46, 51, 55, 60, 21, 34, + 37, 47, 50, 56, 59, 61, 35, 36, 48, 49, 57, 58, 62, 63) -samplings = {(1, 1, 1, 1, 1, 1): 0, - (2, 1, 1, 1, 1, 1): 1, - (2, 2, 1, 1, 1, 1): 2, - } +samplings = { + (1, 1, 1, 1, 1, 1): 0, + (2, 1, 1, 1, 1, 1): 1, + (2, 2, 1, 1, 1, 1): 2, +} def convert_dict_qtables(qtables): @@ -612,12 +610,12 @@ def validate_qtables(qtables): return qtables if isStringType(qtables): try: - lines = [int(num) for line in qtables.splitlines() - for num in line.split('#', 1)[0].split()] + lines = [int(num) for line in qtables.splitlines() for num in + line.split('#', 1)[0].split()] except ValueError: raise ValueError("Invalid quantization table") else: - 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, dict): qtables = convert_dict_qtables(qtables) @@ -667,16 +665,9 @@ def validate_qtables(qtables): # "progressive" is the official name, but older documentation # says "progression" # FIXME: issue a warning if the wrong form is used (post-1.1.7) - "progressive" in info or "progression" in info, - info.get("smooth", 0), - "optimize" in info, - info.get("streamtype", 0), - dpi[0], dpi[1], - subsampling, - qtables, - extra, - info.get("exif", b"") - ) + "progressive" in info or "progression" in info, info.get("smooth", 0), + "optimize" in info, info.get("streamtype", 0), dpi[0], dpi[1], + subsampling, qtables, extra, info.get("exif", b"")) # if we optimize, libjpeg needs a buffer big enough to hold the whole image # in a shot. Guessing on the size, at im.size bytes. (raw pizel size is @@ -684,7 +675,7 @@ def validate_qtables(qtables): # https://github.com/jdriscoll/django-imagekit/issues/50 bufsize = 0 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: bufsize = 2 * im.size[0] * im.size[1] else: @@ -694,7 +685,7 @@ def validate_qtables(qtables): # Ensure that our buffer is big enough 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): @@ -724,7 +715,6 @@ def jpeg_factory(fp=None, filename=None): pass return im - # -------------------------------------------------------------------q- # Registry stuff diff --git a/PIL/JpegPresets.py b/PIL/JpegPresets.py index 6ca46d0cd6b..4e3faa31980 100644 --- a/PIL/JpegPresets.py +++ b/PIL/JpegPresets.py @@ -67,175 +67,117 @@ """ presets = { - 'web_low': {'subsampling': 2, # "4:1:1" - 'quantization': [ - [20, 16, 25, 39, 50, 46, 62, 68, - 16, 18, 23, 38, 38, 53, 65, 68, - 25, 23, 31, 38, 53, 65, 68, 68, - 39, 38, 38, 53, 65, 68, 68, 68, - 50, 38, 53, 65, 68, 68, 68, 68, - 46, 53, 65, 68, 68, 68, 68, 68, - 62, 65, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68], - [21, 25, 32, 38, 54, 68, 68, 68, - 25, 28, 24, 38, 54, 68, 68, 68, - 32, 24, 32, 43, 66, 68, 68, 68, - 38, 38, 43, 53, 68, 68, 68, 68, - 54, 54, 66, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68] - ]}, - 'web_medium': {'subsampling': 2, # "4:1:1" - 'quantization': [ - [16, 11, 11, 16, 23, 27, 31, 30, - 11, 12, 12, 15, 20, 23, 23, 30, - 11, 12, 13, 16, 23, 26, 35, 47, - 16, 15, 16, 23, 26, 37, 47, 64, - 23, 20, 23, 26, 39, 51, 64, 64, - 27, 23, 26, 37, 51, 64, 64, 64, - 31, 23, 35, 47, 64, 64, 64, 64, - 30, 30, 47, 64, 64, 64, 64, 64], - [17, 15, 17, 21, 20, 26, 38, 48, - 15, 19, 18, 17, 20, 26, 35, 43, - 17, 18, 20, 22, 26, 30, 46, 53, - 21, 17, 22, 28, 30, 39, 53, 64, - 20, 20, 26, 30, 39, 48, 64, 64, - 26, 26, 30, 39, 48, 63, 64, 64, - 38, 35, 46, 53, 64, 64, 64, 64, - 48, 43, 53, 64, 64, 64, 64, 64] - ]}, - 'web_high': {'subsampling': 0, # "4:4:4" - 'quantization': [ - [ 6, 4, 4, 6, 9, 11, 12, 16, - 4, 5, 5, 6, 8, 10, 12, 12, - 4, 5, 5, 6, 10, 12, 14, 19, - 6, 6, 6, 11, 12, 15, 19, 28, - 9, 8, 10, 12, 16, 20, 27, 31, - 11, 10, 12, 15, 20, 27, 31, 31, - 12, 12, 14, 19, 27, 31, 31, 31, - 16, 12, 19, 28, 31, 31, 31, 31], - [ 7, 7, 13, 24, 26, 31, 31, 31, - 7, 12, 16, 21, 31, 31, 31, 31, - 13, 16, 17, 31, 31, 31, 31, 31, - 24, 21, 31, 31, 31, 31, 31, 31, - 26, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31] - ]}, - 'web_very_high': {'subsampling': 0, # "4:4:4" - 'quantization': [ - [ 2, 2, 2, 2, 3, 4, 5, 6, - 2, 2, 2, 2, 3, 4, 5, 6, - 2, 2, 2, 2, 4, 5, 7, 9, - 2, 2, 2, 4, 5, 7, 9, 12, - 3, 3, 4, 5, 8, 10, 12, 12, - 4, 4, 5, 7, 10, 12, 12, 12, - 5, 5, 7, 9, 12, 12, 12, 12, - 6, 6, 9, 12, 12, 12, 12, 12], - [ 3, 3, 5, 9, 13, 15, 15, 15, - 3, 4, 6, 11, 14, 12, 12, 12, - 5, 6, 9, 14, 12, 12, 12, 12, - 9, 11, 14, 12, 12, 12, 12, 12, - 13, 14, 12, 12, 12, 12, 12, 12, - 15, 12, 12, 12, 12, 12, 12, 12, - 15, 12, 12, 12, 12, 12, 12, 12, - 15, 12, 12, 12, 12, 12, 12, 12] - ]}, - 'web_maximum': {'subsampling': 0, # "4:4:4" - 'quantization': [ - [ 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 2, - 1, 1, 1, 1, 1, 1, 2, 2, - 1, 1, 1, 1, 1, 2, 2, 3, - 1, 1, 1, 1, 2, 2, 3, 3, - 1, 1, 1, 2, 2, 3, 3, 3, - 1, 1, 2, 2, 3, 3, 3, 3], - [ 1, 1, 1, 2, 2, 3, 3, 3, - 1, 1, 1, 2, 3, 3, 3, 3, - 1, 1, 1, 3, 3, 3, 3, 3, - 2, 2, 3, 3, 3, 3, 3, 3, - 2, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3] - ]}, - 'low': {'subsampling': 2, # "4:1:1" - 'quantization': [ - [18, 14, 14, 21, 30, 35, 34, 17, - 14, 16, 16, 19, 26, 23, 12, 12, - 14, 16, 17, 21, 23, 12, 12, 12, - 21, 19, 21, 23, 12, 12, 12, 12, - 30, 26, 23, 12, 12, 12, 12, 12, - 35, 23, 12, 12, 12, 12, 12, 12, - 34, 12, 12, 12, 12, 12, 12, 12, - 17, 12, 12, 12, 12, 12, 12, 12], - [20, 19, 22, 27, 20, 20, 17, 17, - 19, 25, 23, 14, 14, 12, 12, 12, - 22, 23, 14, 14, 12, 12, 12, 12, - 27, 14, 14, 12, 12, 12, 12, 12, - 20, 14, 12, 12, 12, 12, 12, 12, - 20, 12, 12, 12, 12, 12, 12, 12, - 17, 12, 12, 12, 12, 12, 12, 12, - 17, 12, 12, 12, 12, 12, 12, 12] - ]}, - 'medium': {'subsampling': 2, # "4:1:1" - 'quantization': [ - [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] - ]}, + 'web_low': { + 'subsampling': 2, # "4:1:1" + 'quantization': [ + [20, 16, 25, 39, 50, 46, 62, 68, 16, 18, 23, 38, 38, 53, 65, 68, + 25, 23, 31, 38, 53, 65, 68, 68, 39, 38, 38, 53, 65, 68, 68, 68, + 50, 38, 53, 65, 68, 68, 68, 68, 46, 53, 65, 68, 68, 68, 68, 68, + 62, 65, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68], + [21, 25, 32, 38, 54, 68, 68, 68, 25, 28, 24, 38, 54, 68, 68, 68, + 32, 24, 32, 43, 66, 68, 68, 68, 38, 38, 43, 53, 68, 68, 68, 68, + 54, 54, 66, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68] + ] + }, + 'web_medium': { + 'subsampling': 2, # "4:1:1" + 'quantization': [ + [16, 11, 11, 16, 23, 27, 31, 30, 11, 12, 12, 15, 20, 23, 23, 30, + 11, 12, 13, 16, 23, 26, 35, 47, 16, 15, 16, 23, 26, 37, 47, 64, + 23, 20, 23, 26, 39, 51, 64, 64, 27, 23, 26, 37, 51, 64, 64, 64, + 31, 23, 35, 47, 64, 64, 64, 64, 30, 30, 47, 64, 64, 64, 64, 64], + [17, 15, 17, 21, 20, 26, 38, 48, 15, 19, 18, 17, 20, 26, 35, 43, + 17, 18, 20, 22, 26, 30, 46, 53, 21, 17, 22, 28, 30, 39, 53, 64, + 20, 20, 26, 30, 39, 48, 64, 64, 26, 26, 30, 39, 48, 63, 64, 64, + 38, 35, 46, 53, 64, 64, 64, 64, 48, 43, 53, 64, 64, 64, 64, 64] + ] + }, + 'web_high': { + 'subsampling': 0, # "4:4:4" + 'quantization': [ + [6, 4, 4, 6, 9, 11, 12, 16, 4, 5, 5, 6, 8, 10, 12, 12, 4, 5, 5, 6, + 10, 12, 14, 19, 6, 6, 6, 11, 12, 15, 19, 28, 9, 8, 10, 12, 16, 20, + 27, 31, 11, 10, 12, 15, 20, 27, 31, 31, 12, 12, 14, 19, 27, 31, + 31, 31, 16, 12, 19, 28, 31, 31, 31, 31], + [7, 7, 13, 24, 26, 31, 31, 31, 7, 12, 16, 21, 31, 31, 31, 31, 13, + 16, 17, 31, 31, 31, 31, 31, 24, 21, 31, 31, 31, 31, 31, 31, 26, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31] + ] + }, + 'web_very_high': { + 'subsampling': 0, # "4:4:4" + 'quantization': [[2, 2, 2, 2, 3, 4, 5, 6, 2, 2, 2, 2, 3, 4, 5, 6, 2, 2, + 2, 2, 4, 5, 7, 9, 2, 2, 2, 4, 5, 7, 9, 12, 3, 3, 4, + 5, 8, 10, 12, 12, 4, 4, 5, 7, 10, 12, 12, 12, 5, 5, + 7, 9, 12, 12, 12, 12, 6, 6, 9, 12, 12, 12, 12, 12], + [3, 3, 5, 9, 13, 15, 15, 15, 3, 4, 6, 11, 14, 12, 12, + 12, 5, 6, 9, 14, 12, 12, 12, 12, 9, 11, 14, 12, 12, + 12, 12, 12, 13, 14, 12, 12, 12, 12, 12, 12, 15, 12, + 12, 12, 12, 12, 12, 12, 15, 12, 12, 12, 12, 12, 12, + 12, 15, 12, 12, 12, 12, 12, 12, 12]] + }, + 'web_maximum': { + 'subsampling': 0, # "4:4:4" + 'quantization': [ + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 2, 2, 3, 1, 1, 1, 1, + 2, 2, 3, 3, 1, 1, 1, 2, 2, 3, 3, 3, 1, 1, 2, 2, 3, 3, 3, 3], + [1, 1, 1, 2, 2, 3, 3, 3, 1, 1, 1, 2, 3, 3, 3, 3, 1, 1, 1, 3, 3, 3, + 3, 3, 2, 2, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3] + ] + }, + 'low': { + 'subsampling': 2, # "4:1:1" + 'quantization': [ + [18, 14, 14, 21, 30, 35, 34, 17, 14, 16, 16, 19, 26, 23, 12, 12, + 14, 16, 17, 21, 23, 12, 12, 12, 21, 19, 21, 23, 12, 12, 12, 12, + 30, 26, 23, 12, 12, 12, 12, 12, 35, 23, 12, 12, 12, 12, 12, 12, + 34, 12, 12, 12, 12, 12, 12, 12, 17, 12, 12, 12, 12, 12, 12, 12], + [20, 19, 22, 27, 20, 20, 17, 17, 19, 25, 23, 14, 14, 12, 12, 12, + 22, 23, 14, 14, 12, 12, 12, 12, 27, 14, 14, 12, 12, 12, 12, 12, + 20, 14, 12, 12, 12, 12, 12, 12, 20, 12, 12, 12, 12, 12, 12, 12, + 17, 12, 12, 12, 12, 12, 12, 12, 17, 12, 12, 12, 12, 12, 12, 12] + ] + }, + 'medium': { + 'subsampling': 2, # "4:1:1" + 'quantization': [ + [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]] + }, } diff --git a/PIL/McIdasImagePlugin.py b/PIL/McIdasImagePlugin.py index c3f255fd2c6..ebef6784498 100644 --- a/PIL/McIdasImagePlugin.py +++ b/PIL/McIdasImagePlugin.py @@ -25,10 +25,10 @@ def _accept(s): return s[:8] == b"\x00\x00\x00\x00\x00\x00\x00\x04" - ## # Image plugin for McIdas area images. + class McIdasImageFile(ImageFile.ImageFile): format = "MCIDAS" @@ -62,7 +62,7 @@ def _open(self): self.size = w[10], w[9] 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))] diff --git a/PIL/MicImagePlugin.py b/PIL/MicImagePlugin.py index cdfaf3eda6f..38eab0fb1c7 100644 --- a/PIL/MicImagePlugin.py +++ b/PIL/MicImagePlugin.py @@ -16,14 +16,11 @@ # See the README file for information on usage and redistribution. # - __version__ = "0.1" - from PIL import Image, TiffImagePlugin from PIL.OleFileIO import * - # # -------------------------------------------------------------------- @@ -31,10 +28,10 @@ def _accept(prefix): return prefix[:8] == MAGIC - ## # Image plugin for Microsoft's Image Composer file format. + class MicImageFile(TiffImagePlugin.TiffImageFile): format = "MIC" diff --git a/PIL/MpegImagePlugin.py b/PIL/MpegImagePlugin.py index 9aca58f16fb..e865913543b 100644 --- a/PIL/MpegImagePlugin.py +++ b/PIL/MpegImagePlugin.py @@ -18,12 +18,11 @@ from PIL import Image, ImageFile from PIL._binary import i8 - # # Bitstream parser -class BitStream: +class BitStream: def __init__(self, fp): self.fp = fp self.bits = 0 @@ -53,11 +52,11 @@ def read(self, bits): self.bits = self.bits - bits return v - ## # Image plugin for MPEG streams. This plugin can identify a stream, # but it cannot read it. + class MpegImageFile(ImageFile.ImageFile): format = "MPEG" @@ -73,7 +72,6 @@ def _open(self): self.mode = "RGB" self.size = s.read(12), s.read(12) - # -------------------------------------------------------------------- # Registry stuff diff --git a/PIL/MpoImagePlugin.py b/PIL/MpoImagePlugin.py index c345fd32776..afa6908635d 100644 --- a/PIL/MpoImagePlugin.py +++ b/PIL/MpoImagePlugin.py @@ -31,10 +31,10 @@ def _save(im, fp, filename): # Note that we can only save the current frame at present return JpegImagePlugin._save(im, fp, filename) - ## # Image plugin for MPO images. + class MpoImageFile(JpegImagePlugin.JpegImageFile): format = "MPO" @@ -68,15 +68,13 @@ def seek(self, frame): else: self.fp = self.__fp self.offset = self.__mpoffsets[frame] - self.tile = [ - ("jpeg", (0, 0) + self.size, self.offset, (self.mode, "")) - ] + self.tile = [("jpeg", (0, 0) + self.size, self.offset, + (self.mode, ""))] self.__frame = frame def tell(self): return self.__frame - # -------------------------------------------------------------------q- # Registry stuff diff --git a/PIL/MspImagePlugin.py b/PIL/MspImagePlugin.py index 4753be7cd74..ecc54138a2c 100644 --- a/PIL/MspImagePlugin.py +++ b/PIL/MspImagePlugin.py @@ -16,12 +16,10 @@ # See the README file for information on usage and redistribution. # - __version__ = "0.1" from PIL import Image, ImageFile, _binary - # # read MSP files @@ -31,11 +29,11 @@ def _accept(prefix): return prefix[:4] in [b"DanM", b"LinS"] - ## # Image plugin for Windows MSP images. This plugin supports both # uncompressed (Windows 1.0). + class MspImageFile(ImageFile.ImageFile): format = "MSP" @@ -51,7 +49,7 @@ def _open(self): # Header checksum sum = 0 for i in range(0, 32, 2): - sum = sum ^ i16(s[i:i+2]) + sum = sum ^ i16(s[i:i + 2]) if sum != 0: raise SyntaxError("bad MSP checksum") @@ -59,9 +57,10 @@ def _open(self): self.size = i16(s[4:]), i16(s[6:]) 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: - 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) @@ -93,7 +92,7 @@ def _save(im, fp, filename): fp.write(o16(h)) # 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 diff --git a/PIL/OleFileIO.py b/PIL/OleFileIO.py index a08ae0ee3fa..a1772276e4e 100755 --- a/PIL/OleFileIO.py +++ b/PIL/OleFileIO.py @@ -23,16 +23,14 @@ ## WARNING: THIS IS (STILL) WORK IN PROGRESS. - # Starting with OleFileIO_PL v0.30, only Python 2.6+ and 3.x is supported # This import enables print() as a function rather than a keyword # (main requirement to be compatible with Python 3.x) # The comment on the line below should be printed on Python 2.5 or older: -from __future__ import print_function # This version of OleFileIO_PL requires Python 2.6+ or 3.x. - +from __future__ import print_function # This version of OleFileIO_PL requires Python 2.6+ or 3.x. -__author__ = "Philippe Lagadec, Fredrik Lundh (Secret Labs AB)" -__date__ = "2014-02-04" +__author__ = "Philippe Lagadec, Fredrik Lundh (Secret Labs AB)" +__date__ = "2014-02-04" __version__ = '0.30' #--- LICENSE ------------------------------------------------------------------ @@ -231,7 +229,6 @@ #------------------------------------------------------------------------------ - import io import sys import struct, array, os.path, datetime @@ -259,8 +256,8 @@ # on 64 bits platforms, integers in an array are 32 bits: UINT32 = 'I' else: - raise ValueError('Need to fix a bug with 32 bit arrays, please contact author...') - + raise ValueError( + 'Need to fix a bug with 32 bit arrays, please contact author...') #[PL] These workarounds were inspired from the Path module # (see http://www.jorendorff.com/articles/python/path/) @@ -283,12 +280,19 @@ #[PL] DEBUG display mode: False by default, use set_debug_mode() or "-d" on # command line to change it. DEBUG_MODE = False + + def debug_print(msg): print(msg) + + def debug_pass(msg): pass + + debug = debug_pass + def set_debug_mode(debug_mode): """ Set debug mode on or off, to control display of debugging messages. @@ -301,41 +305,80 @@ def set_debug_mode(debug_mode): else: debug = debug_pass + MAGIC = b'\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1' #[PL]: added constants for Sector IDs (from AAF specifications) -MAXREGSECT = 0xFFFFFFFA; # maximum SECT -DIFSECT = 0xFFFFFFFC; # (-4) denotes a DIFAT sector in a FAT -FATSECT = 0xFFFFFFFD; # (-3) denotes a FAT sector in a FAT -ENDOFCHAIN = 0xFFFFFFFE; # (-2) end of a virtual stream chain -FREESECT = 0xFFFFFFFF; # (-1) unallocated sector +MAXREGSECT = 0xFFFFFFFA +# maximum SECT +DIFSECT = 0xFFFFFFFC +# (-4) denotes a DIFAT sector in a FAT +FATSECT = 0xFFFFFFFD +# (-3) denotes a FAT sector in a FAT +ENDOFCHAIN = 0xFFFFFFFE +# (-2) end of a virtual stream chain +FREESECT = 0xFFFFFFFF +# (-1) unallocated sector #[PL]: added constants for Directory Entry IDs (from AAF specifications) -MAXREGSID = 0xFFFFFFFA; # maximum directory entry ID -NOSTREAM = 0xFFFFFFFF; # (-1) unallocated directory entry +MAXREGSID = 0xFFFFFFFA +# maximum directory entry ID +NOSTREAM = 0xFFFFFFFF +# (-1) unallocated directory entry #[PL] object types in storage (from AAF specifications) -STGTY_EMPTY = 0 # empty directory entry (according to OpenOffice.org doc) -STGTY_STORAGE = 1 # element is a storage object -STGTY_STREAM = 2 # element is a stream object -STGTY_LOCKBYTES = 3 # element is an ILockBytes object -STGTY_PROPERTY = 4 # element is an IPropertyStorage object -STGTY_ROOT = 5 # element is a root storage - +STGTY_EMPTY = 0 # empty directory entry (according to OpenOffice.org doc) +STGTY_STORAGE = 1 # element is a storage object +STGTY_STREAM = 2 # element is a stream object +STGTY_LOCKBYTES = 3 # element is an ILockBytes object +STGTY_PROPERTY = 4 # element is an IPropertyStorage object +STGTY_ROOT = 5 # element is a root storage # # -------------------------------------------------------------------- # property types -VT_EMPTY=0; VT_NULL=1; VT_I2=2; VT_I4=3; VT_R4=4; VT_R8=5; VT_CY=6; -VT_DATE=7; VT_BSTR=8; VT_DISPATCH=9; VT_ERROR=10; VT_BOOL=11; -VT_VARIANT=12; VT_UNKNOWN=13; VT_DECIMAL=14; VT_I1=16; VT_UI1=17; -VT_UI2=18; VT_UI4=19; VT_I8=20; VT_UI8=21; VT_INT=22; VT_UINT=23; -VT_VOID=24; VT_HRESULT=25; VT_PTR=26; VT_SAFEARRAY=27; VT_CARRAY=28; -VT_USERDEFINED=29; VT_LPSTR=30; VT_LPWSTR=31; VT_FILETIME=64; -VT_BLOB=65; VT_STREAM=66; VT_STORAGE=67; VT_STREAMED_OBJECT=68; -VT_STORED_OBJECT=69; VT_BLOB_OBJECT=70; VT_CF=71; VT_CLSID=72; -VT_VECTOR=0x1000; +VT_EMPTY = 0 +VT_NULL = 1 +VT_I2 = 2 +VT_I4 = 3 +VT_R4 = 4 +VT_R8 = 5 +VT_CY = 6 +VT_DATE = 7 +VT_BSTR = 8 +VT_DISPATCH = 9 +VT_ERROR = 10 +VT_BOOL = 11 +VT_VARIANT = 12 +VT_UNKNOWN = 13 +VT_DECIMAL = 14 +VT_I1 = 16 +VT_UI1 = 17 +VT_UI2 = 18 +VT_UI4 = 19 +VT_I8 = 20 +VT_UI8 = 21 +VT_INT = 22 +VT_UINT = 23 +VT_VOID = 24 +VT_HRESULT = 25 +VT_PTR = 26 +VT_SAFEARRAY = 27 +VT_CARRAY = 28 +VT_USERDEFINED = 29 +VT_LPSTR = 30 +VT_LPWSTR = 31 +VT_FILETIME = 64 +VT_BLOB = 65 +VT_STREAM = 66 +VT_STORAGE = 67 +VT_STREAMED_OBJECT = 68 +VT_STORED_OBJECT = 69 +VT_BLOB_OBJECT = 70 +VT_CF = 71 +VT_CLSID = 72 +VT_VECTOR = 0x1000 # map property id to name (for debugging purposes) @@ -352,22 +395,22 @@ def set_debug_mode(debug_mode): #TODO: check Excel, PPT, ... #[PL]: Defect levels to classify parsing errors - see OleFileIO._raise_defect() -DEFECT_UNSURE = 10 # a case which looks weird, but not sure it's a defect -DEFECT_POTENTIAL = 20 # a potential defect -DEFECT_INCORRECT = 30 # an error according to specifications, but parsing - # can go on -DEFECT_FATAL = 40 # an error which cannot be ignored, parsing is - # impossible +DEFECT_UNSURE = 10 # a case which looks weird, but not sure it's a defect +DEFECT_POTENTIAL = 20 # a potential defect +DEFECT_INCORRECT = 30 # an error according to specifications, but parsing +# can go on +DEFECT_FATAL = 40 # an error which cannot be ignored, parsing is +# impossible #[PL] add useful constants to __all__: for key in list(vars().keys()): if key.startswith('STGTY_') or key.startswith('DEFECT_'): __all__.append(key) - #--- FUNCTIONS ---------------------------------------------------------------- -def isOleFile (filename): + +def isOleFile(filename): """ Test if file is an OLE container (according to its header). @@ -391,30 +434,31 @@ def i8(c): def i8(c): return c if c.__class__ is int else c[0] - #TODO: replace i16 and i32 with more readable struct.unpack equivalent? -def i16(c, o = 0): + +def i16(c, o=0): """ Converts a 2-bytes (16 bits) string to an integer. :param c: string containing bytes to convert :param o: offset of bytes to convert in string """ - return i8(c[o]) | (i8(c[o+1])<<8) + return i8(c[o]) | (i8(c[o + 1]) << 8) -def i32(c, o = 0): +def i32(c, o=0): """ Converts a 4-bytes (32 bits) string to an integer. :param c: string containing bytes to convert :param o: offset of bytes to convert in string """ -## return int(ord(c[o])+(ord(c[o+1])<<8)+(ord(c[o+2])<<16)+(ord(c[o+3])<<24)) -## # [PL]: added int() because "<<" gives long int since Python 2.4 + ## return int(ord(c[o])+(ord(c[o+1])<<8)+(ord(c[o+2])<<16)+(ord(c[o+3])<<24)) + ## # [PL]: added int() because "<<" gives long int since Python 2.4 # copied from Pillow's _binary: - return i8(c[o]) | (i8(c[o+1])<<8) | (i8(c[o+2])<<16) | (i8(c[o+3])<<24) + return i8(c[o]) | (i8(c[o + 1]) << 8) | (i8(c[o + 2]) << 16) | ( + i8(c[o + 3]) << 24) def _clsid(clsid): @@ -430,13 +474,12 @@ def _clsid(clsid): return "" return (("%08X-%04X-%04X-%02X%02X-" + "%02X" * 6) % ((i32(clsid, 0), i16(clsid, 4), i16(clsid, 6)) + - tuple(map(i8, clsid[8:16])))) - - + tuple(map(i8, clsid[8:16])))) # UNICODE support: # (necessary to handle storages/streams names which use Unicode) + def _unicode(s, errors='replace'): """ Map unicode string to Latin 1. (Python with Unicode support) @@ -461,19 +504,18 @@ def _unicode(s, errors='replace'): def filetime2datetime(filetime): - """ + """ convert FILETIME (64 bits int) to Python datetime.datetime """ - # TODO: manage exception when microseconds is too large - # inspired from http://code.activestate.com/recipes/511425-filetime-to-datetime/ - _FILETIME_null_date = datetime.datetime(1601, 1, 1, 0, 0, 0) - #debug('timedelta days=%d' % (filetime//(10*1000000*3600*24))) - return _FILETIME_null_date + datetime.timedelta(microseconds=filetime//10) - - + # TODO: manage exception when microseconds is too large + # inspired from http://code.activestate.com/recipes/511425-filetime-to-datetime/ + _FILETIME_null_date = datetime.datetime(1601, 1, 1, 0, 0, 0) + #debug('timedelta days=%d' % (filetime//(10*1000000*3600*24))) + return _FILETIME_null_date + datetime.timedelta(microseconds=filetime // 10) #=== CLASSES ================================================================== + class OleMetadata: """ class to parse and store metadata from standard properties of OLE files. @@ -509,20 +551,23 @@ class to parse and store metadata from standard properties of OLE files. # attribute names for SummaryInformation stream properties: # (ordered by property id, starting at 1) - SUMMARY_ATTRIBS = ['codepage', 'title', 'subject', 'author', 'keywords', 'comments', - 'template', 'last_saved_by', 'revision_number', 'total_edit_time', - 'last_printed', 'create_time', 'last_saved_time', 'num_pages', - 'num_words', 'num_chars', 'thumbnail', 'creating_application', - 'security'] + SUMMARY_ATTRIBS = ['codepage', 'title', 'subject', 'author', 'keywords', + 'comments', 'template', 'last_saved_by', + 'revision_number', 'total_edit_time', 'last_printed', + 'create_time', 'last_saved_time', 'num_pages', + 'num_words', 'num_chars', 'thumbnail', + 'creating_application', 'security'] # attribute names for DocumentSummaryInformation stream properties: # (ordered by property id, starting at 1) - DOCSUM_ATTRIBS = ['codepage_doc', 'category', 'presentation_target', 'bytes', 'lines', 'paragraphs', - 'slides', 'notes', 'hidden_slides', 'mm_clips', - 'scale_crop', 'heading_pairs', 'titles_of_parts', 'manager', - 'company', 'links_dirty', 'chars_with_spaces', 'unused', 'shared_doc', - 'link_base', 'hlinks', 'hlinks_changed', 'version', 'dig_sig', - 'content_type', 'content_status', 'language', 'doc_version'] + DOCSUM_ATTRIBS = ['codepage_doc', 'category', 'presentation_target', + 'bytes', 'lines', 'paragraphs', 'slides', 'notes', + 'hidden_slides', 'mm_clips', 'scale_crop', + 'heading_pairs', 'titles_of_parts', 'manager', 'company', + 'links_dirty', 'chars_with_spaces', 'unused', + 'shared_doc', 'link_base', 'hlinks', 'hlinks_changed', + 'version', 'dig_sig', 'content_type', 'content_status', + 'language', 'doc_version'] def __init__(self): """ @@ -579,7 +624,6 @@ def __init__(self): self.language = None self.doc_version = None - def parse_properties(self, olefile): """ Parse standard properties of an OLE file, from the streams @@ -596,20 +640,21 @@ def parse_properties(self, olefile): # (converting timestamps to python datetime, except total_edit_time, # which is property #10) props = olefile.getproperties("\x05SummaryInformation", - convert_time=True, no_conversion=[10]) + convert_time=True, + no_conversion=[10]) # store them into this object's attributes: for i in range(len(self.SUMMARY_ATTRIBS)): # ids for standards properties start at 0x01, until 0x13 - value = props.get(i+1, None) + value = props.get(i + 1, None) setattr(self, self.SUMMARY_ATTRIBS[i], value) if olefile.exists("\x05DocumentSummaryInformation"): # get properties from the stream: props = olefile.getproperties("\x05DocumentSummaryInformation", - convert_time=True) + convert_time=True) # store them into this object's attributes: for i in range(len(self.DOCSUM_ATTRIBS)): # ids for standards properties start at 0x01, until 0x13 - value = props.get(i+1, None) + value = props.get(i + 1, None) setattr(self, self.DOCSUM_ATTRIBS[i], value) def dump(self): @@ -625,9 +670,9 @@ def dump(self): value = getattr(self, prop) print('- %s: %s' % (prop, repr(value))) - #--- _OleStream --------------------------------------------------------------- + class _OleStream(io.BytesIO): """ OLE2 Stream @@ -662,20 +707,21 @@ def __init__(self, fp, sect, size, offset, sectorsize, fat, filesize): :returns : a BytesIO instance containing the OLE stream """ debug('_OleStream.__init__:') - debug(' sect=%d (%X), size=%d, offset=%d, sectorsize=%d, len(fat)=%d, fp=%s' - %(sect,sect,size,offset,sectorsize,len(fat), repr(fp))) + debug( + ' sect=%d (%X), size=%d, offset=%d, sectorsize=%d, len(fat)=%d, fp=%s' + % (sect, sect, size, offset, sectorsize, len(fat), repr(fp))) #[PL] To detect malformed documents with FAT loops, we compute the # expected number of sectors in the stream: unknown_size = False - if size==0x7FFFFFFF: + if size == 0x7FFFFFFF: # this is the case when called from OleFileIO._open(), and stream # size is not known in advance (for example when reading the # Directory stream). Then we can only guess maximum size: - size = len(fat)*sectorsize + size = len(fat) * sectorsize # and we keep a record that size was unknown: unknown_size = True debug(' stream with UNKNOWN SIZE') - nb_sectors = (size + (sectorsize-1)) // sectorsize + nb_sectors = (size + (sectorsize - 1)) // sectorsize debug('nb_sectors = %d' % nb_sectors) # This number should (at least) be less than the total number of # sectors in the given FAT: @@ -701,14 +747,14 @@ def __init__(self, fp, sect, size, offset, sectorsize, fat, filesize): debug('sect=ENDOFCHAIN before expected size') raise IOError('incomplete OLE stream') # sector index should be within FAT: - if sect<0 or sect>=len(fat): + if sect < 0 or sect >= len(fat): debug('sect=%d (%X) / len(fat)=%d' % (sect, sect, len(fat))) - debug('i=%d / nb_sectors=%d' %(i, nb_sectors)) -## tmp_data = b"".join(data) -## f = open('test_debug.bin', 'wb') -## f.write(tmp_data) -## f.close() -## debug('data read so far: %d bytes' % len(tmp_data)) + debug('i=%d / nb_sectors=%d' % (i, nb_sectors)) + ## tmp_data = b"".join(data) + ## f = open('test_debug.bin', 'wb') + ## f.write(tmp_data) + ## f.close() + ## debug('data read so far: %d bytes' % len(tmp_data)) raise IOError('incorrect OLE FAT, sector index out of range') #TODO: merge this code with OleFileIO.getsect() ? #TODO: check if this works with 4K sectors: @@ -716,17 +762,20 @@ def __init__(self, fp, sect, size, offset, sectorsize, fat, filesize): fp.seek(offset + sectorsize * sect) except: debug('sect=%d, seek=%d, filesize=%d' % - (sect, offset+sectorsize*sect, filesize)) + (sect, offset + sectorsize * sect, filesize)) raise IOError('OLE sector index out of range') sector_data = fp.read(sectorsize) # [PL] check if there was enough data: # Note: if sector is the last of the file, sometimes it is not a # complete sector (of 512 or 4K), so we may read less than # sectorsize. - if len(sector_data)!=sectorsize and sect!=(len(fat)-1): - debug('sect=%d / len(fat)=%d, seek=%d / filesize=%d, len read=%d' % - (sect, len(fat), offset+sectorsize*sect, filesize, len(sector_data))) - debug('seek+len(read)=%d' % (offset+sectorsize*sect+len(sector_data))) + if len(sector_data) != sectorsize and sect != (len(fat) - 1): + debug( + 'sect=%d / len(fat)=%d, seek=%d / filesize=%d, len read=%d' % + (sect, len(fat), offset + sectorsize * sect, filesize, + len(sector_data))) + debug('seek+len(read)=%d' % + (offset + sectorsize * sect + len(sector_data))) raise IOError('incomplete OLE sector') data.append(sector_data) # jump to next sector in the FAT: @@ -756,11 +805,10 @@ def __init__(self, fp, sect, size, offset, sectorsize, fat, filesize): io.BytesIO.__init__(self, data) # Then the _OleStream object can be used as a read-only file object. + #--- _OleDirectoryEntry ------------------------------------------------------- -#--- _OleDirectoryEntry ------------------------------------------------------- class _OleDirectoryEntry: - """ OLE2 Directory Entry """ @@ -789,7 +837,6 @@ class _OleDirectoryEntry: DIRENTRY_SIZE = 128 assert struct.calcsize(STRUCT_DIRENTRY) == DIRENTRY_SIZE - def __init__(self, entry, sid, olefile): """ Constructor for an _OleDirectoryEntry object. @@ -813,24 +860,14 @@ def __init__(self, entry, sid, olefile): # directory: self.used = False # decode DirEntry - ( - name, - namelength, - self.entry_type, - self.color, - self.sid_left, - self.sid_right, - self.sid_child, - clsid, - self.dwUserFlags, - self.createTime, - self.modifyTime, - self.isectStart, - sizeLow, - sizeHigh - ) = struct.unpack(_OleDirectoryEntry.STRUCT_DIRENTRY, entry) - if self.entry_type not in [STGTY_ROOT, STGTY_STORAGE, STGTY_STREAM, STGTY_EMPTY]: - olefile._raise_defect(DEFECT_INCORRECT, 'unhandled OLE storage type') + (name, namelength, self.entry_type, self.color, self.sid_left, + self.sid_right, self.sid_child, clsid, self.dwUserFlags, + self.createTime, self.modifyTime, self.isectStart, sizeLow, + sizeHigh) = struct.unpack(_OleDirectoryEntry.STRUCT_DIRENTRY, entry) + if self.entry_type not in [STGTY_ROOT, STGTY_STORAGE, STGTY_STREAM, + STGTY_EMPTY]: + olefile._raise_defect(DEFECT_INCORRECT, + 'unhandled OLE storage type') # only first directory entry can (and should) be root: if self.entry_type == STGTY_ROOT and sid != 0: olefile._raise_defect(DEFECT_INCORRECT, 'duplicate OLE root entry') @@ -839,20 +876,21 @@ def __init__(self, entry, sid, olefile): #debug (struct.unpack(fmt_entry, entry[:len_entry])) # name should be at most 31 unicode characters + null character, # so 64 bytes in total (31*2 + 2): - if namelength>64: - olefile._raise_defect(DEFECT_INCORRECT, 'incorrect DirEntry name length') + if namelength > 64: + olefile._raise_defect(DEFECT_INCORRECT, + 'incorrect DirEntry name length') # if exception not raised, namelength is set to the maximum value: namelength = 64 # only characters without ending null char are kept: - name = name[:(namelength-2)] + name = name[:(namelength - 2)] # name is converted from unicode to Latin-1: self.name = _unicode(name) debug('DirEntry SID=%d: %s' % (self.sid, repr(self.name))) debug(' - type: %d' % self.entry_type) debug(' - sect: %d' % self.isectStart) - debug(' - SID left: %d, right: %d, child: %d' % (self.sid_left, - self.sid_right, self.sid_child)) + debug(' - SID left: %d, right: %d, child: %d' % + (self.sid_left, self.sid_right, self.sid_child)) # sizeHigh is only used for 4K sectors, it should be zero for 512 bytes # sectors, BUT apparently some implementations set it as 0xFFFFFFFF, 1 @@ -860,12 +898,14 @@ def __init__(self, entry, sid, olefile): if olefile.sectorsize == 512: if sizeHigh != 0 and sizeHigh != 0xFFFFFFFF: debug('sectorsize=%d, sizeLow=%d, sizeHigh=%d (%X)' % - (olefile.sectorsize, sizeLow, sizeHigh, sizeHigh)) - olefile._raise_defect(DEFECT_UNSURE, 'incorrect OLE stream size') + (olefile.sectorsize, sizeLow, sizeHigh, sizeHigh)) + olefile._raise_defect(DEFECT_UNSURE, + 'incorrect OLE stream size') self.size = sizeLow else: - self.size = sizeLow + (long(sizeHigh)<<32) - debug(' - size: %d (sizeLow=%d, sizeHigh=%d)' % (self.size, sizeLow, sizeHigh)) + self.size = sizeLow + (long(sizeHigh) << 32) + debug(' - size: %d (sizeLow=%d, sizeHigh=%d)' % + (self.size, sizeLow, sizeHigh)) self.clsid = _clsid(clsid) # a storage should have a null size, BUT some implementations such as @@ -873,17 +913,15 @@ def __init__(self, entry, sid, olefile): if self.entry_type == STGTY_STORAGE and self.size != 0: olefile._raise_defect(DEFECT_POTENTIAL, 'OLE storage with size>0') # check if stream is not already referenced elsewhere: - if self.entry_type in (STGTY_ROOT, STGTY_STREAM) and self.size>0: + if self.entry_type in (STGTY_ROOT, STGTY_STREAM) and self.size > 0: if self.size < olefile.minisectorcutoff \ - and self.entry_type==STGTY_STREAM: # only streams can be in MiniFAT + and self.entry_type == STGTY_STREAM: # only streams can be in MiniFAT # ministream object minifat = True else: minifat = False olefile._check_duplicate_stream(self.isectStart, minifat) - - def build_storage_tree(self): """ Read and build the red-black tree attached to this _OleDirectoryEntry @@ -891,8 +929,8 @@ def build_storage_tree(self): Note that this method builds a tree of all subentries, so it should only be called for the root object once. """ - debug('build_storage_tree: SID=%d - %s - sid_child=%d' - % (self.sid, repr(self.name), self.sid_child)) + debug('build_storage_tree: SID=%d - %s - sid_child=%d' % + (self.sid, repr(self.name), self.sid_child)) if self.sid_child != NOSTREAM: # if child SID is not NOSTREAM, then this entry is a storage. # Let's walk through the tree of children to fill the kids list: @@ -907,7 +945,6 @@ def build_storage_tree(self): # (see rich comparison methods in this class) self.kids.sort() - def append_kids(self, child_sid): """ Walk through red-black tree of children of this directory entry to add @@ -922,12 +959,15 @@ def append_kids(self, child_sid): if child_sid == NOSTREAM: return # check if child SID is in the proper range: - if child_sid<0 or child_sid>=len(self.olefile.direntries): - self.olefile._raise_defect(DEFECT_FATAL, 'OLE DirEntry index out of range') + if child_sid < 0 or child_sid >= len(self.olefile.direntries): + self.olefile._raise_defect(DEFECT_FATAL, + 'OLE DirEntry index out of range') # get child direntry: - child = self.olefile._load_direntry(child_sid) #direntries[child_sid] - debug('append_kids: child_sid=%d - %s - sid_left=%d, sid_right=%d, sid_child=%d' - % (child.sid, repr(child.name), child.sid_left, child.sid_right, child.sid_child)) + child = self.olefile._load_direntry(child_sid) #direntries[child_sid] + debug( + 'append_kids: child_sid=%d - %s - sid_left=%d, sid_right=%d, sid_child=%d' + % (child.sid, repr(child.name), child.sid_left, child.sid_right, + child.sid_child)) # the directory entries are organized as a red-black tree. # (cf. Wikipedia for details) # First walk through left side of the tree: @@ -936,7 +976,7 @@ def append_kids(self, child_sid): name_lower = child.name.lower() if name_lower in self.kids_dict: self.olefile._raise_defect(DEFECT_INCORRECT, - "Duplicate filename in OLE storage") + "Duplicate filename in OLE storage") # Then the child_sid _OleDirectoryEntry object is appended to the # kids list and dictionary: self.kids.append(child) @@ -944,14 +984,13 @@ def append_kids(self, child_sid): # Check if kid was not already referenced in a storage: if child.used: self.olefile._raise_defect(DEFECT_INCORRECT, - 'OLE Entry referenced more than once') + 'OLE Entry referenced more than once') child.used = True # Finally walk through right side of the tree: self.append_kids(child.sid_right) # Afterwards build kid's own tree if it's also a storage: child.build_storage_tree() - def __eq__(self, other): "Compare entries by name" return self.name == other.name @@ -971,22 +1010,20 @@ def __le__(self, other): #TODO: replace by the same function as MS implementation ? # (order by name length first, then case-insensitive order) - - def dump(self, tab = 0): + def dump(self, tab=0): "Dump this entry, and all its subentries (for debug purposes only)" TYPES = ["(invalid)", "(storage)", "(stream)", "(lockbytes)", "(property)", "(root)"] - print(" "*tab + repr(self.name), TYPES[self.entry_type], end=' ') + print(" " * tab + repr(self.name), TYPES[self.entry_type], end=' ') if self.entry_type in (STGTY_STREAM, STGTY_ROOT): print(self.size, "bytes", end=' ') print() if self.entry_type in (STGTY_STORAGE, STGTY_ROOT) and self.clsid: - print(" "*tab + "{%s}" % self.clsid) + print(" " * tab + "{%s}" % self.clsid) for kid in self.kids: kid.dump(tab + 2) - def getmtime(self): """ Return modification time of a directory entry. @@ -1000,7 +1037,6 @@ def getmtime(self): return None return filetime2datetime(self.modifyTime) - def getctime(self): """ Return creation time of a directory entry. @@ -1014,9 +1050,9 @@ def getctime(self): return None return filetime2datetime(self.createTime) - #--- OleFileIO ---------------------------------------------------------------- + class OleFileIO: """ OLE container object @@ -1047,7 +1083,7 @@ class OleFileIO: TIFF files). """ - def __init__(self, filename = None, raise_defects=DEFECT_FATAL): + def __init__(self, filename=None, raise_defects=DEFECT_FATAL): """ Constructor for OleFileIO class. @@ -1064,7 +1100,6 @@ def __init__(self, filename = None, raise_defects=DEFECT_FATAL): if filename: self.open(filename) - def _raise_defect(self, defect_level, message, exception_type=IOError): """ This method should be called for any defect found during file parsing. @@ -1086,7 +1121,6 @@ def _raise_defect(self, defect_level, message, exception_type=IOError): # just record the issue, no exception raised: self.parsing_issues.append((exception_type, message)) - def open(self, filename): """ Open an OLE2 file. @@ -1127,7 +1161,8 @@ def open(self, filename): header = self.fp.read(512) if len(header) != 512 or header[:8] != MAGIC: - self._raise_defect(DEFECT_FATAL, "not an OLE2 structured storage file") + self._raise_defect(DEFECT_FATAL, + "not an OLE2 structured storage file") # [PL] header structure according to AAF specifications: ##Header @@ -1168,85 +1203,84 @@ def open(self, filename): # '<' indicates little-endian byte ordering for Intel (cf. struct module help) fmt_header = '<8s16sHHHHHHLLLLLLLLLL' header_size = struct.calcsize(fmt_header) - debug( "fmt_header size = %d, +FAT = %d" % (header_size, header_size + 109*4) ) + debug("fmt_header size = %d, +FAT = %d" % + (header_size, header_size + 109 * 4)) header1 = header[:header_size] - ( - self.Sig, - self.clsid, - self.MinorVersion, - self.DllVersion, - self.ByteOrder, - self.SectorShift, - self.MiniSectorShift, - self.Reserved, self.Reserved1, - self.csectDir, - self.csectFat, - self.sectDirStart, - self.signature, - self.MiniSectorCutoff, - self.MiniFatStart, - self.csectMiniFat, - self.sectDifStart, - self.csectDif - ) = struct.unpack(fmt_header, header1) - debug( struct.unpack(fmt_header, header1)) + (self.Sig, self.clsid, self.MinorVersion, self.DllVersion, + self.ByteOrder, self.SectorShift, self.MiniSectorShift, self.Reserved, + self.Reserved1, self.csectDir, self.csectFat, self.sectDirStart, + self.signature, self.MiniSectorCutoff, self.MiniFatStart, + self.csectMiniFat, self.sectDifStart, + self.csectDif) = struct.unpack(fmt_header, header1) + debug(struct.unpack(fmt_header, header1)) if self.Sig != MAGIC: # OLE signature should always be present self._raise_defect(DEFECT_FATAL, "incorrect OLE signature") if self.clsid != bytearray(16): # according to AAF specs, CLSID should always be zero - self._raise_defect(DEFECT_INCORRECT, "incorrect CLSID in OLE header") - debug( "MinorVersion = %d" % self.MinorVersion ) - debug( "DllVersion = %d" % self.DllVersion ) + self._raise_defect(DEFECT_INCORRECT, + "incorrect CLSID in OLE header") + debug("MinorVersion = %d" % self.MinorVersion) + debug("DllVersion = %d" % self.DllVersion) if self.DllVersion not in [3, 4]: # version 3: usual format, 512 bytes per sector # version 4: large format, 4K per sector - self._raise_defect(DEFECT_INCORRECT, "incorrect DllVersion in OLE header") - debug( "ByteOrder = %X" % self.ByteOrder ) + self._raise_defect(DEFECT_INCORRECT, + "incorrect DllVersion in OLE header") + debug("ByteOrder = %X" % self.ByteOrder) if self.ByteOrder != 0xFFFE: # For now only common little-endian documents are handled correctly - self._raise_defect(DEFECT_FATAL, "incorrect ByteOrder in OLE header") + self._raise_defect(DEFECT_FATAL, + "incorrect ByteOrder in OLE header") # TODO: add big-endian support for documents created on Mac ? - self.SectorSize = 2**self.SectorShift - debug( "SectorSize = %d" % self.SectorSize ) + self.SectorSize = 2 ** self.SectorShift + debug("SectorSize = %d" % self.SectorSize) if self.SectorSize not in [512, 4096]: - self._raise_defect(DEFECT_INCORRECT, "incorrect SectorSize in OLE header") - if (self.DllVersion==3 and self.SectorSize!=512) \ - or (self.DllVersion==4 and self.SectorSize!=4096): - self._raise_defect(DEFECT_INCORRECT, "SectorSize does not match DllVersion in OLE header") - self.MiniSectorSize = 2**self.MiniSectorShift - debug( "MiniSectorSize = %d" % self.MiniSectorSize ) + self._raise_defect(DEFECT_INCORRECT, + "incorrect SectorSize in OLE header") + if (self.DllVersion == 3 and self.SectorSize != 512) \ + or (self.DllVersion == 4 and self.SectorSize != 4096): + self._raise_defect( + DEFECT_INCORRECT, + "SectorSize does not match DllVersion in OLE header") + self.MiniSectorSize = 2 ** self.MiniSectorShift + debug("MiniSectorSize = %d" % self.MiniSectorSize) if self.MiniSectorSize not in [64]: - self._raise_defect(DEFECT_INCORRECT, "incorrect MiniSectorSize in OLE header") + self._raise_defect(DEFECT_INCORRECT, + "incorrect MiniSectorSize in OLE header") if self.Reserved != 0 or self.Reserved1 != 0: - self._raise_defect(DEFECT_INCORRECT, "incorrect OLE header (non-null reserved bytes)") - debug( "csectDir = %d" % self.csectDir ) - if self.SectorSize==512 and self.csectDir!=0: - self._raise_defect(DEFECT_INCORRECT, "incorrect csectDir in OLE header") - debug( "csectFat = %d" % self.csectFat ) - debug( "sectDirStart = %X" % self.sectDirStart ) - debug( "signature = %d" % self.signature ) + self._raise_defect(DEFECT_INCORRECT, + "incorrect OLE header (non-null reserved bytes)") + debug("csectDir = %d" % self.csectDir) + if self.SectorSize == 512 and self.csectDir != 0: + self._raise_defect(DEFECT_INCORRECT, + "incorrect csectDir in OLE header") + debug("csectFat = %d" % self.csectFat) + debug("sectDirStart = %X" % self.sectDirStart) + debug("signature = %d" % self.signature) # Signature should be zero, BUT some implementations do not follow this # rule => only a potential defect: if self.signature != 0: - self._raise_defect(DEFECT_POTENTIAL, "incorrect OLE header (signature>0)") - debug( "MiniSectorCutoff = %d" % self.MiniSectorCutoff ) - debug( "MiniFatStart = %X" % self.MiniFatStart ) - debug( "csectMiniFat = %d" % self.csectMiniFat ) - debug( "sectDifStart = %X" % self.sectDifStart ) - debug( "csectDif = %d" % self.csectDif ) + self._raise_defect(DEFECT_POTENTIAL, + "incorrect OLE header (signature>0)") + debug("MiniSectorCutoff = %d" % self.MiniSectorCutoff) + debug("MiniFatStart = %X" % self.MiniFatStart) + debug("csectMiniFat = %d" % self.csectMiniFat) + debug("sectDifStart = %X" % self.sectDifStart) + debug("csectDif = %d" % self.csectDif) # calculate the number of sectors in the file # (-1 because header doesn't count) - self.nb_sect = ( (filesize + self.SectorSize-1) // self.SectorSize) - 1 - debug( "Number of sectors in the file: %d" % self.nb_sect ) + self.nb_sect = ( + (filesize + self.SectorSize - 1) // self.SectorSize) - 1 + debug("Number of sectors in the file: %d" % self.nb_sect) # file clsid (probably never used, so we don't store it) #clsid = _clsid(header[8:24]) - self.sectorsize = self.SectorSize #1 << i16(header, 30) + self.sectorsize = self.SectorSize #1 << i16(header, 30) self.minisectorsize = self.MiniSectorSize #1 << i16(header, 32) - self.minisectorcutoff = self.MiniSectorCutoff # i32(header, 56) + self.minisectorcutoff = self.MiniSectorCutoff # i32(header, 56) # check known streams for duplicate references (these are always in FAT, # never in MiniFAT): @@ -1262,10 +1296,9 @@ def open(self, filename): self.loadfat(header) # Load direcory. This sets both the direntries list (ordered by sid) # and the root (ordered by hierarchy) members. - self.loaddirectory(self.sectDirStart)#i32(header, 48)) + self.loaddirectory(self.sectDirStart) #i32(header, 48)) self.ministream = None - self.minifatsect = self.MiniFatStart #i32(header, 60) - + self.minifatsect = self.MiniFatStart #i32(header, 60) def close(self): """ @@ -1273,7 +1306,6 @@ def close(self): """ self.fp.close() - def _check_duplicate_stream(self, first_sect, minifat=False): """ Checks if a stream has not been already referenced elsewhere. @@ -1288,7 +1320,7 @@ def _check_duplicate_stream(self, first_sect, minifat=False): else: debug('_check_duplicate_stream: sect=%d in FAT' % first_sect) # some values can be safely ignored (not a real stream): - if first_sect in (DIFSECT,FATSECT,ENDOFCHAIN,FREESECT): + if first_sect in (DIFSECT, FATSECT, ENDOFCHAIN, FREESECT): return used_streams = self._used_streams_fat #TODO: would it be more efficient using a dict or hash values, instead @@ -1298,61 +1330,59 @@ def _check_duplicate_stream(self, first_sect, minifat=False): else: used_streams.append(first_sect) - def dumpfat(self, fat, firstindex=0): "Displays a part of FAT in human-readable form for debugging purpose" # [PL] added only for debug if not DEBUG_MODE: return # dictionary to convert special FAT values in human-readable strings - VPL=8 # valeurs par ligne (8+1 * 8+1 = 81) + VPL = 8 # valeurs par ligne (8+1 * 8+1 = 81) fatnames = { - FREESECT: "..free..", + FREESECT: "..free..", ENDOFCHAIN: "[ END. ]", - FATSECT: "FATSECT ", - DIFSECT: "DIFSECT " - } + FATSECT: "FATSECT ", + DIFSECT: "DIFSECT " + } nbsect = len(fat) - nlines = (nbsect+VPL-1)//VPL + nlines = (nbsect + VPL - 1) // VPL print("index", end=" ") for i in range(VPL): print("%8X" % i, end=" ") print() for l in range(nlines): - index = l*VPL - print("%8X:" % (firstindex+index), end=" ") - for i in range(index, index+VPL): - if i>=nbsect: + index = l * VPL + print("%8X:" % (firstindex + index), end=" ") + for i in range(index, index + VPL): + if i >= nbsect: break sect = fat[i] if sect in fatnames: nom = fatnames[sect] else: - if sect == i+1: + if sect == i + 1: nom = " --->" else: nom = "%8X" % sect print(nom, end=" ") print() - def dumpsect(self, sector, firstindex=0): "Displays a sector in a human-readable form, for debugging purpose." if not DEBUG_MODE: return - VPL=8 # number of values per line (8+1 * 8+1 = 81) + VPL = 8 # number of values per line (8+1 * 8+1 = 81) tab = array.array(UINT32, sector) nbsect = len(tab) - nlines = (nbsect+VPL-1)//VPL + nlines = (nbsect + VPL - 1) // VPL print("index", end=" ") for i in range(VPL): print("%8X" % i, end=" ") print() for l in range(nlines): - index = l*VPL - print("%8X:" % (firstindex+index), end=" ") - for i in range(index, index+VPL): - if i>=nbsect: + index = l * VPL + print("%8X:" % (firstindex + index), end=" ") + for i in range(index, index + VPL): + if i >= nbsect: break sect = tab[i] nom = "%8X" % sect @@ -1370,7 +1400,6 @@ def sect2array(self, sect): a.byteswap() return a - def loadfat_sect(self, sect): """ Adds the indexes of the given sector to the FAT @@ -1400,7 +1429,6 @@ def loadfat_sect(self, sect): self.fat = self.fat + nextfat return isect - def loadfat(self, header): """ Load the FAT table. @@ -1410,7 +1438,7 @@ def loadfat(self, header): # described by DIF blocks sect = header[76:512] - debug( "len(sect)=%d, so %d integers" % (len(sect), len(sect)//4) ) + debug("len(sect)=%d, so %d integers" % (len(sect), len(sect) // 4)) #fat = [] # [PL] FAT is an array of 32 bits unsigned ints, it's more effective # to use an array than a list in Python. @@ -1418,34 +1446,36 @@ def loadfat(self, header): self.fat = array.array(UINT32) self.loadfat_sect(sect) #self.dumpfat(self.fat) -## for i in range(0, len(sect), 4): -## ix = i32(sect, i) -## #[PL] if ix == -2 or ix == -1: # ix == 0xFFFFFFFE or ix == 0xFFFFFFFF: -## if ix == 0xFFFFFFFE or ix == 0xFFFFFFFF: -## break -## s = self.getsect(ix) -## #fat = fat + [i32(s, i) for i in range(0, len(s), 4)] -## fat = fat + array.array(UINT32, s) + ## for i in range(0, len(sect), 4): + ## ix = i32(sect, i) + ## #[PL] if ix == -2 or ix == -1: # ix == 0xFFFFFFFE or ix == 0xFFFFFFFF: + ## if ix == 0xFFFFFFFE or ix == 0xFFFFFFFF: + ## break + ## s = self.getsect(ix) + ## #fat = fat + [i32(s, i) for i in range(0, len(s), 4)] + ## fat = fat + array.array(UINT32, s) if self.csectDif != 0: # [PL] There's a DIFAT because file is larger than 6.8MB # some checks just in case: if self.csectFat <= 109: # there must be at least 109 blocks in header and the rest in # DIFAT, so number of sectors must be >109. - self._raise_defect(DEFECT_INCORRECT, 'incorrect DIFAT, not enough sectors') + self._raise_defect(DEFECT_INCORRECT, + 'incorrect DIFAT, not enough sectors') if self.sectDifStart >= self.nb_sect: # initial DIFAT block index must be valid - self._raise_defect(DEFECT_FATAL, 'incorrect DIFAT, first index out of range') - debug( "DIFAT analysis..." ) + self._raise_defect(DEFECT_FATAL, + 'incorrect DIFAT, first index out of range') + debug("DIFAT analysis...") # We compute the necessary number of DIFAT sectors : # (each DIFAT sector = 127 pointers + 1 towards next DIFAT sector) - nb_difat = (self.csectFat-109 + 126)//127 - debug( "nb_difat = %d" % nb_difat ) + nb_difat = (self.csectFat - 109 + 126) // 127 + debug("nb_difat = %d" % nb_difat) if self.csectDif != nb_difat: raise IOError('incorrect DIFAT') isect_difat = self.sectDifStart for i in iterrange(nb_difat): - debug( "DIFAT block %d, sector %X" % (i, isect_difat) ) + debug("DIFAT block %d, sector %X" % (i, isect_difat)) #TODO: check if corresponding FAT SID = DIFSECT sector_difat = self.getsect(isect_difat) difat = self.sect2array(sector_difat) @@ -1453,7 +1483,7 @@ def loadfat(self, header): self.loadfat_sect(difat[:127]) # last DIFAT pointer is next DIFAT sector: isect_difat = difat[127] - debug( "next DIFAT sector: %X" % isect_difat ) + debug("next DIFAT sector: %X" % isect_difat) # checks: if isect_difat not in [ENDOFCHAIN, FREESECT]: # last DIFAT pointer value must be ENDOFCHAIN or FREESECT @@ -1462,16 +1492,16 @@ def loadfat(self, header): ## # FAT should contain csectFat blocks ## print("FAT length: %d instead of %d" % (len(self.fat), self.csectFat)) ## raise IOError('incorrect DIFAT') - # since FAT is read from fixed-size sectors, it may contain more values - # than the actual number of sectors in the file. - # Keep only the relevant sector indexes: +# since FAT is read from fixed-size sectors, it may contain more values +# than the actual number of sectors in the file. +# Keep only the relevant sector indexes: if len(self.fat) > self.nb_sect: - debug('len(fat)=%d, shrunk to nb_sect=%d' % (len(self.fat), self.nb_sect)) + debug('len(fat)=%d, shrunk to nb_sect=%d' % + (len(self.fat), self.nb_sect)) self.fat = self.fat[:self.nb_sect] debug('\nFAT:') self.dumpfat(self.fat) - def loadminifat(self): """ Load the MiniFAT table. @@ -1487,20 +1517,25 @@ def loadminifat(self): # 2) Actually used size is calculated by dividing the MiniStream size # (given by root entry size) by the size of mini sectors, *4 for # 32 bits indexes: - nb_minisectors = (self.root.size + self.MiniSectorSize-1) // self.MiniSectorSize + nb_minisectors = (self.root.size + self.MiniSectorSize - + 1) // self.MiniSectorSize used_size = nb_minisectors * 4 - debug('loadminifat(): minifatsect=%d, nb FAT sectors=%d, used_size=%d, stream_size=%d, nb MiniSectors=%d' % - (self.minifatsect, self.csectMiniFat, used_size, stream_size, nb_minisectors)) + debug( + 'loadminifat(): minifatsect=%d, nb FAT sectors=%d, used_size=%d, stream_size=%d, nb MiniSectors=%d' + % (self.minifatsect, self.csectMiniFat, used_size, stream_size, + nb_minisectors)) if used_size > stream_size: # This is not really a problem, but may indicate a wrong implementation: - self._raise_defect(DEFECT_INCORRECT, 'OLE MiniStream is larger than MiniFAT') + self._raise_defect(DEFECT_INCORRECT, + 'OLE MiniStream is larger than MiniFAT') # In any case, first read stream_size: s = self._open(self.minifatsect, stream_size, force_FAT=True).read() #[PL] Old code replaced by an array: #self.minifat = [i32(s, i) for i in range(0, len(s), 4)] self.minifat = self.sect2array(s) # Then shrink the array to used size, to avoid indexes out of MiniStream: - debug('MiniFAT shrunk from %d to %d sectors' % (len(self.minifat), nb_minisectors)) + debug('MiniFAT shrunk from %d to %d sectors' % + (len(self.minifat), nb_minisectors)) self.minifat = self.minifat[:nb_minisectors] debug('loadminifat(): len=%d' % len(self.minifat)) debug('\nMiniFAT:') @@ -1519,19 +1554,18 @@ def getsect(self, sect): #[PL]: added safety checks: #print("getsect(%X)" % sect) try: - self.fp.seek(self.sectorsize * (sect+1)) + self.fp.seek(self.sectorsize * (sect + 1)) except: debug('getsect(): sect=%X, seek=%d, filesize=%d' % - (sect, self.sectorsize*(sect+1), self._filesize)) + (sect, self.sectorsize * (sect + 1), self._filesize)) self._raise_defect(DEFECT_FATAL, 'OLE sector index out of range') sector = self.fp.read(self.sectorsize) if len(sector) != self.sectorsize: debug('getsect(): sect=%X, read=%d, sectorsize=%d' % - (sect, len(sector), self.sectorsize)) + (sect, len(sector), self.sectorsize)) self._raise_defect(DEFECT_FATAL, 'incomplete OLE sector') return sector - def loaddirectory(self, sect): """ Load the directory. @@ -1549,17 +1583,17 @@ def loaddirectory(self, sect): # number of directory entries can be calculated: max_entries = self.directory_fp.size // 128 debug('loaddirectory: size=%d, max_entries=%d' % - (self.directory_fp.size, max_entries)) + (self.directory_fp.size, max_entries)) # Create list of directory entries #self.direntries = [] # We start with a list of "None" object self.direntries = [None] * max_entries -## for sid in iterrange(max_entries): -## entry = fp.read(128) -## if not entry: -## break -## self.direntries.append(_OleDirectoryEntry(entry, sid, self)) + ## for sid in iterrange(max_entries): + ## entry = fp.read(128) + ## if not entry: + ## break + ## self.direntries.append(_OleDirectoryEntry(entry, sid, self)) # load root entry: self._load_direntry(0) # Root entry is the first entry: @@ -1567,8 +1601,7 @@ def loaddirectory(self, sect): # read and build all storage trees, starting from the root: self.root.build_storage_tree() - - def _load_direntry (self, sid): + def _load_direntry(self, sid): """ Load a directory entry from the directory. This method should only be called once for each storage/stream when @@ -1579,12 +1612,12 @@ def _load_direntry (self, sid): :exception IOError: if the entry has always been referenced. """ # check if SID is OK: - if sid<0 or sid>=len(self.direntries): + if sid < 0 or sid >= len(self.direntries): self._raise_defect(DEFECT_FATAL, "OLE directory index out of range") # check if entry was already referenced: if self.direntries[sid] is not None: self._raise_defect(DEFECT_INCORRECT, - "double reference for OLE stream/storage") + "double reference for OLE stream/storage") # if exception not raised, return the object return self.direntries[sid] self.directory_fp.seek(sid * 128) @@ -1592,15 +1625,13 @@ def _load_direntry (self, sid): self.direntries[sid] = _OleDirectoryEntry(entry, sid, self) return self.direntries[sid] - def dumpdirectory(self): """ Dump directory (for debugging only) """ self.root.dump() - - def _open(self, start, size = 0x7FFFFFFF, force_FAT=False): + def _open(self, start, size=0x7FFFFFFF, force_FAT=False): """ Open a stream, either in FAT or MiniFAT according to its size. (openstream helper) @@ -1611,7 +1642,7 @@ def _open(self, start, size = 0x7FFFFFFF, force_FAT=False): according to size. If True, it will always be opened in FAT. """ debug('OleFileIO.open(): sect=%d, size=%d, force_FAT=%s' % - (start, size, str(force_FAT))) + (start, size, str(force_FAT))) # stream size is compared to the MiniSectorCutoff threshold: if size < self.minisectorcutoff and not force_FAT: # ministream object @@ -1622,17 +1653,17 @@ def _open(self, start, size = 0x7FFFFFFF, force_FAT=False): # root directory entry: size_ministream = self.root.size debug('Opening MiniStream: sect=%d, size=%d' % - (self.root.isectStart, size_ministream)) + (self.root.isectStart, size_ministream)) self.ministream = self._open(self.root.isectStart, - size_ministream, force_FAT=True) + size_ministream, + force_FAT=True) return _OleStream(self.ministream, start, size, 0, self.minisectorsize, self.minifat, self.ministream.size) else: # standard stream - return _OleStream(self.fp, start, size, 512, - self.sectorsize, self.fat, self._filesize) - + return _OleStream(self.fp, start, size, 512, self.sectorsize, + self.fat, self._filesize) def _list(self, files, prefix, node, streams=True, storages=False): """ @@ -1659,7 +1690,6 @@ def _list(self, files, prefix, node, streams=True, storages=False): # add it to the list files.append(prefix[1:] + [entry.name]) - def listdir(self, streams=True, storages=False): """ Return a list of streams stored in this file @@ -1672,7 +1702,6 @@ def listdir(self, streams=True, storages=False): self._list(files, [], self.root, streams, storages) return files - def _find(self, filename): """ Returns directory entry of given filename. (openstream helper) @@ -1703,7 +1732,6 @@ def _find(self, filename): node = kid return node.sid - def openstream(self, filename): """ Open a stream as a read-only file object (BytesIO). @@ -1724,7 +1752,6 @@ def openstream(self, filename): raise IOError("this file is not a stream") return self._open(entry.isectStart, entry.size) - def get_type(self, filename): """ Test if given filename exists as a stream or a storage in the OLE @@ -1744,7 +1771,6 @@ def get_type(self, filename): except: return False - def getmtime(self, filename): """ Return modification time of a stream/storage. @@ -1760,7 +1786,6 @@ def getmtime(self, filename): entry = self.direntries[sid] return entry.getmtime() - def getctime(self, filename): """ Return creation time of a stream/storage. @@ -1776,7 +1801,6 @@ def getctime(self, filename): entry = self.direntries[sid] return entry.getctime() - def exists(self, filename): """ Test if given filename exists as a stream or a storage in the OLE @@ -1791,7 +1815,6 @@ def exists(self, filename): except: return False - def get_size(self, filename): """ Return size of a stream in the OLE container, in bytes. @@ -1808,7 +1831,6 @@ def get_size(self, filename): raise TypeError('object is not an OLE stream') return entry.size - def get_rootentry_name(self): """ Return root entry name. Should usually be 'Root Entry' or 'R' in most @@ -1816,7 +1838,6 @@ def get_rootentry_name(self): """ return self.root.name - def getproperties(self, filename, convert_time=False, no_conversion=None): """ Return properties described in substream. @@ -1850,7 +1871,7 @@ def getproperties(self, filename, convert_time=False, no_conversion=None): fp.seek(i32(s, 16)) # get section - s = b"****" + fp.read(i32(fp.read(4))-4) + s = b"****" + fp.read(i32(fp.read(4)) - 4) # number of properties: num_props = i32(s, 4) except BaseException as exc: @@ -1864,82 +1885,89 @@ def getproperties(self, filename, convert_time=False, no_conversion=None): for i in range(num_props): try: - id = 0 # just in case of an exception - id = i32(s, 8+i*8) - offset = i32(s, 12+i*8) + id = 0 # just in case of an exception + id = i32(s, 8 + i * 8) + offset = i32(s, 12 + i * 8) type = i32(s, offset) - debug ('property id=%d: type=%d offset=%X' % (id, type, offset)) + debug('property id=%d: type=%d offset=%X' % (id, type, offset)) # test for common types first (should perhaps use # a dictionary instead?) - if type == VT_I2: # 16-bit signed integer - value = i16(s, offset+4) + if type == VT_I2: # 16-bit signed integer + value = i16(s, offset + 4) if value >= 32768: value = value - 65536 - elif type == VT_UI2: # 2-byte unsigned integer - value = i16(s, offset+4) + elif type == VT_UI2: # 2-byte unsigned integer + value = i16(s, offset + 4) elif type in (VT_I4, VT_INT, VT_ERROR): # VT_I4: 32-bit signed integer # VT_ERROR: HRESULT, similar to 32-bit signed integer, # see http://msdn.microsoft.com/en-us/library/cc230330.aspx - value = i32(s, offset+4) - elif type in (VT_UI4, VT_UINT): # 4-byte unsigned integer - value = i32(s, offset+4) # FIXME + value = i32(s, offset + 4) + elif type in (VT_UI4, VT_UINT): # 4-byte unsigned integer + value = i32(s, offset + 4) # FIXME elif type in (VT_BSTR, VT_LPSTR): # CodePageString, see http://msdn.microsoft.com/en-us/library/dd942354.aspx # size is a 32 bits integer, including the null terminator, and # possibly trailing or embedded null chars #TODO: if codepage is unicode, the string should be converted as such - count = i32(s, offset+4) - value = s[offset+8:offset+8+count-1] + count = i32(s, offset + 4) + value = s[offset + 8:offset + 8 + count - 1] # remove all null chars: value = value.replace(b'\x00', b'') elif type == VT_BLOB: # binary large object (BLOB) # see http://msdn.microsoft.com/en-us/library/dd942282.aspx - count = i32(s, offset+4) - value = s[offset+8:offset+8+count] + count = i32(s, offset + 4) + value = s[offset + 8:offset + 8 + count] elif type == VT_LPWSTR: # UnicodeString # see http://msdn.microsoft.com/en-us/library/dd942313.aspx # "the string should NOT contain embedded or additional trailing # null characters." - count = i32(s, offset+4) - value = _unicode(s[offset+8:offset+8+count*2]) + count = i32(s, offset + 4) + value = _unicode(s[offset + 8:offset + 8 + count * 2]) elif type == VT_FILETIME: - value = long(i32(s, offset+4)) + (long(i32(s, offset+8))<<32) + value = long(i32(s, offset + 4)) + (long(i32(s, offset + + 8)) << 32) # FILETIME is a 64-bit int: "number of 100ns periods # since Jan 1,1601". if convert_time and id not in no_conversion: - debug('Converting property #%d to python datetime, value=%d=%fs' - %(id, value, float(value)/10000000)) + debug( + 'Converting property #%d to python datetime, value=%d=%fs' + % (id, value, float(value) / 10000000)) # convert FILETIME to Python datetime.datetime # inspired from http://code.activestate.com/recipes/511425-filetime-to-datetime/ - _FILETIME_null_date = datetime.datetime(1601, 1, 1, 0, 0, 0) - debug('timedelta days=%d' % (value//(10*1000000*3600*24))) - value = _FILETIME_null_date + datetime.timedelta(microseconds=value//10) + _FILETIME_null_date = datetime.datetime(1601, 1, 1, 0, + 0, 0) + debug('timedelta days=%d' % + (value // (10 * 1000000 * 3600 * 24))) + value = _FILETIME_null_date + datetime.timedelta( + microseconds=value // 10) else: # legacy code kept for backward compatibility: returns a # number of seconds since Jan 1,1601 - value = value // 10000000 # seconds - elif type == VT_UI1: # 1-byte unsigned integer - value = i8(s[offset+4]) + value = value // 10000000 # seconds + elif type == VT_UI1: # 1-byte unsigned integer + value = i8(s[offset + 4]) elif type == VT_CLSID: - value = _clsid(s[offset+4:offset+20]) + value = _clsid(s[offset + 4:offset + 20]) elif type == VT_CF: # PropertyIdentifier or ClipboardData?? # see http://msdn.microsoft.com/en-us/library/dd941945.aspx - count = i32(s, offset+4) - value = s[offset+8:offset+8+count] + count = i32(s, offset + 4) + value = s[offset + 8:offset + 8 + count] elif type == VT_BOOL: # VARIANT_BOOL, 16 bits bool, 0x0000=Fals, 0xFFFF=True # see http://msdn.microsoft.com/en-us/library/cc237864.aspx - value = bool(i16(s, offset+4)) + value = bool(i16(s, offset + 4)) else: - value = None # everything else yields "None" - debug ('property id=%d: type=%d not implemented in parser yet' % (id, type)) + value = None # everything else yields "None" + debug( + 'property id=%d: type=%d not implemented in parser yet' % + (id, type)) # missing: VT_EMPTY, VT_NULL, VT_R4, VT_R8, VT_CY, VT_DATE, # VT_DECIMAL, VT_I1, VT_I8, VT_UI8, @@ -2010,7 +2038,7 @@ def get_metadata(self): check_streams = True continue - ole = OleFileIO(filename)#, raise_defects=DEFECT_INCORRECT) + ole = OleFileIO(filename) #, raise_defects=DEFECT_INCORRECT) print("-" * 68) print(filename) print("-" * 68) @@ -2027,8 +2055,9 @@ def get_metadata(self): v = v[:50] if isinstance(v, bytes): # quick and dirty binary check: - for c in (1,2,3,4,5,6,7,11,12,14,15,16,17,18,19,20, - 21,22,23,24,25,26,27,28,29,30,31): + for c in (1, 2, 3, 4, 5, 6, 7, 11, 12, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31): if c in bytearray(v): v = '(binary data)' break @@ -2039,7 +2068,7 @@ def get_metadata(self): print('\nChecking streams...') for streamname in ole.listdir(): # print name using repr() to convert binary chars to \xNN: - print('-', repr('/'.join(streamname)),'-', end=' ') + print('-', repr('/'.join(streamname)), '-', end=' ') st_type = ole.get_type(streamname) if st_type == STGTY_STREAM: print('size %d' % ole.get_size(streamname)) @@ -2058,8 +2087,8 @@ def get_metadata(self): print('Modification/Creation times of all directory entries:') for entry in ole.direntries: if entry is not None: - print('- %s: mtime=%s ctime=%s' % (entry.name, - entry.getmtime(), entry.getctime())) + print('- %s: mtime=%s ctime=%s' % + (entry.name, entry.getmtime(), entry.getctime())) print() # parse and display metadata: @@ -2071,7 +2100,8 @@ def get_metadata(self): print('Root entry name: "%s"' % root) if ole.exists('worddocument'): print("This is a Word document.") - print("type of stream 'WordDocument':", ole.get_type('worddocument')) + print("type of stream 'WordDocument':", + ole.get_type('worddocument')) print("size :", ole.get_size('worddocument')) if ole.exists('macros/vba'): print("This document may contain VBA macros.") diff --git a/PIL/PSDraw.py b/PIL/PSDraw.py index 6187e40adb6..ba68b176488 100644 --- a/PIL/PSDraw.py +++ b/PIL/PSDraw.py @@ -19,10 +19,10 @@ from PIL import EpsImagePlugin - ## # Simple Postscript graphics interface. + class PSDraw: """ Sets up printing to the given file. If **file** is omitted, @@ -57,9 +57,7 @@ def begin_document(self, id=None): def end_document(self): """Ends printing. (Write Postscript DSC footer.)""" - self._fp_write("%%EndDocument\n" - "restore showpage\n" - "%%End\n") + self._fp_write("%%EndDocument\n" "restore showpage\n" "%%End\n") if hasattr(self.fp, "flush"): self.fp.flush() @@ -109,7 +107,7 @@ def text(self, xy, text): """ text = "\\(".join(text.split("(")) text = "\\)".join(text.split(")")) - xy = xy + (text,) + xy = xy + (text, ) self._fp_write("%d %d M (%s) S\n" % xy) def image(self, box, im, dpi=None): diff --git a/PIL/PaletteFile.py b/PIL/PaletteFile.py index 37ba4cbff89..2bbdb62afc9 100644 --- a/PIL/PaletteFile.py +++ b/PIL/PaletteFile.py @@ -15,10 +15,10 @@ from PIL._binary import o8 - ## # File handler for Teragon-style palette files. + class PaletteFile: rawmode = "RGB" diff --git a/PIL/PalmImagePlugin.py b/PIL/PalmImagePlugin.py index bba1de8bbf3..c3fde0a544d 100644 --- a/PIL/PalmImagePlugin.py +++ b/PIL/PalmImagePlugin.py @@ -13,74 +13,68 @@ _Palm8BitColormapValues = ( (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, 153, 204), (255, 102, 204), (255, 51, 204), (255, 0, 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, 255, 153), (255, 204, 153), (255, 153, 153), (255, 102, 153), - (255, 51, 153), (255, 0, 153), (204, 255, 255), (204, 204, 255), - (204, 153, 255), (204, 102, 255), (204, 51, 255), (204, 0, 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, 255, 204), (204, 204, 204), (204, 153, 204), (204, 102, 204), - (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, 51, 204), (204, 0, 204), (204, 255, 153), (204, 204, 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, 51, 255), (153, 0, 255), (153, 255, 204), (153, 204, 204), - (153, 153, 204), (153, 102, 204), (153, 51, 204), (153, 0, 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, 255, 153), (153, 204, 153), (153, 153, 153), (153, 102, 153), - (153, 51, 153), (153, 0, 153), (102, 255, 255), (102, 204, 255), - (102, 153, 255), (102, 102, 255), (102, 51, 255), (102, 0, 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, 255, 204), (102, 204, 204), (102, 153, 204), (102, 102, 204), - (102, 51, 204), (102, 0, 204), (102, 255, 153), (102, 204, 153), - (102, 153, 153), (102, 102, 153), (102, 51, 153), (102, 0, 153), - ( 51, 255, 255), ( 51, 204, 255), ( 51, 153, 255), ( 51, 102, 255), - ( 51, 51, 255), ( 51, 0, 255), ( 51, 255, 204), ( 51, 204, 204), - ( 51, 153, 204), ( 51, 102, 204), ( 51, 51, 204), ( 51, 0, 204), - ( 51, 255, 153), ( 51, 204, 153), ( 51, 153, 153), ( 51, 102, 153), - ( 51, 51, 153), ( 51, 0, 153), ( 0, 255, 255), ( 0, 204, 255), - ( 0, 153, 255), ( 0, 102, 255), ( 0, 51, 255), ( 0, 0, 255), - ( 0, 255, 204), ( 0, 204, 204), ( 0, 153, 204), ( 0, 102, 204), - ( 0, 51, 204), ( 0, 0, 204), ( 0, 255, 153), ( 0, 204, 153), - ( 0, 153, 153), ( 0, 102, 153), ( 0, 51, 153), ( 0, 0, 153), - (255, 255, 102), (255, 204, 102), (255, 153, 102), (255, 102, 102), - (255, 51, 102), (255, 0, 102), (255, 255, 51), (255, 204, 51), - (255, 153, 51), (255, 102, 51), (255, 51, 51), (255, 0, 51), - (255, 255, 0), (255, 204, 0), (255, 153, 0), (255, 102, 0), - (255, 51, 0), (255, 0, 0), (204, 255, 102), (204, 204, 102), - (204, 153, 102), (204, 102, 102), (204, 51, 102), (204, 0, 102), - (204, 255, 51), (204, 204, 51), (204, 153, 51), (204, 102, 51), - (204, 51, 51), (204, 0, 51), (204, 255, 0), (204, 204, 0), - (204, 153, 0), (204, 102, 0), (204, 51, 0), (204, 0, 0), - (153, 255, 102), (153, 204, 102), (153, 153, 102), (153, 102, 102), - (153, 51, 102), (153, 0, 102), (153, 255, 51), (153, 204, 51), - (153, 153, 51), (153, 102, 51), (153, 51, 51), (153, 0, 51), - (153, 255, 0), (153, 204, 0), (153, 153, 0), (153, 102, 0), - (153, 51, 0), (153, 0, 0), (102, 255, 102), (102, 204, 102), - (102, 153, 102), (102, 102, 102), (102, 51, 102), (102, 0, 102), - (102, 255, 51), (102, 204, 51), (102, 153, 51), (102, 102, 51), - (102, 51, 51), (102, 0, 51), (102, 255, 0), (102, 204, 0), - (102, 153, 0), (102, 102, 0), (102, 51, 0), (102, 0, 0), - ( 51, 255, 102), ( 51, 204, 102), ( 51, 153, 102), ( 51, 102, 102), - ( 51, 51, 102), ( 51, 0, 102), ( 51, 255, 51), ( 51, 204, 51), - ( 51, 153, 51), ( 51, 102, 51), ( 51, 51, 51), ( 51, 0, 51), - ( 51, 255, 0), ( 51, 204, 0), ( 51, 153, 0), ( 51, 102, 0), - ( 51, 51, 0), ( 51, 0, 0), ( 0, 255, 102), ( 0, 204, 102), - ( 0, 153, 102), ( 0, 102, 102), ( 0, 51, 102), ( 0, 0, 102), - ( 0, 255, 51), ( 0, 204, 51), ( 0, 153, 51), ( 0, 102, 51), - ( 0, 51, 51), ( 0, 0, 51), ( 0, 255, 0), ( 0, 204, 0), - ( 0, 153, 0), ( 0, 102, 0), ( 0, 51, 0), ( 17, 17, 17), - ( 34, 34, 34), ( 68, 68, 68), ( 85, 85, 85), (119, 119, 119), - (136, 136, 136), (170, 170, 170), (187, 187, 187), (221, 221, 221), - (238, 238, 238), (192, 192, 192), (128, 0, 0), (128, 0, 128), - ( 0, 128, 0), ( 0, 128, 128), ( 0, 0, 0), ( 0, 0, 0), - ( 0, 0, 0), ( 0, 0, 0), ( 0, 0, 0), ( 0, 0, 0), - ( 0, 0, 0), ( 0, 0, 0), ( 0, 0, 0), ( 0, 0, 0), - ( 0, 0, 0), ( 0, 0, 0), ( 0, 0, 0), ( 0, 0, 0), - ( 0, 0, 0), ( 0, 0, 0), ( 0, 0, 0), ( 0, 0, 0), - ( 0, 0, 0), ( 0, 0, 0), ( 0, 0, 0), ( 0, 0, 0), - ( 0, 0, 0), ( 0, 0, 0), ( 0, 0, 0), ( 0, 0, 0)) + (102, 51, 204), (102, 0, 204), (102, 255, 153), (102, 204, 153), + (102, 153, 153), (102, 102, 153), (102, 51, 153), (102, 0, 153), ( + 51, 255, 255), (51, 204, 255), (51, 153, 255), (51, 102, 255), + (51, 51, 255), (51, 0, 255), (51, 255, 204), (51, 204, 204), (51, 153, 204 + ), (51, 102, 204), (51, 51, 204), (51, 0, 204), (51, 255, 153), ( + 51, 204, 153), (51, 153, 153), (51, 102, 153), (51, 51, 153), + (51, 0, 153), (0, 255, 255), (0, 204, 255), (0, 153, 255), (0, 102, 255), ( + 0, 51, 255), (0, 0, 255), (0, 255, 204), (0, 204, 204), (0, 153, 204), + (0, 102, 204), (0, 51, 204), (0, 0, 204), (0, 255, 153), (0, 204, 153), ( + 0, 153, 153), (0, 102, 153), (0, 51, 153), (0, 0, 153), (255, 255, 102 + ), (255, 204, 102), (255, 153, 102), (255, 102, 102), (255, 51, 102), ( + 255, 0, 102), (255, 255, 51), (255, 204, 51), (255, 153, 51), + (255, 102, 51), (255, 51, 51), (255, 0, 51), (255, 255, 0), (255, 204, 0), + (255, 153, 0), (255, 102, 0), (255, 51, 0), (255, 0, 0), (204, 255, 102), ( + 204, 204, 102), (204, 153, 102), (204, 102, 102), (204, 51, 102), ( + 204, 0, 102), (204, 255, 51), (204, 204, 51), (204, 153, 51), + (204, 102, 51), (204, 51, 51), (204, 0, 51), (204, 255, 0), (204, 204, 0), + (204, 153, 0), (204, 102, 0), (204, 51, 0), (204, 0, 0), (153, 255, 102), ( + 153, 204, 102), (153, 153, 102), (153, 102, 102), (153, 51, 102), ( + 153, 0, 102), (153, 255, 51), (153, 204, 51), (153, 153, 51), ( + 153, 102, 51), (153, 51, 51), (153, 0, 51), (153, 255, 0 + ), (153, 204, 0), (153, 153, 0), (153, 102, 0), (153, 51, 0), ( + 153, 0, 0), (102, 255, 102), (102, 204, 102), (102, 153, 102), ( + 102, 102, 102), (102, 51, 102), (102, 0, 102), (102, 255, 51), ( + 102, 204, 51), (102, 153, 51), (102, 102, 51), (102, 51, 51 + ), (102, 0, 51), (102, 255, 0), (102, 204, 0), (102, 153, 0), ( + 102, 102, 0), (102, 51, 0), (102, 0, 0), (51, 255, 102), (51, 204, 102 + ), (51, 153, 102), (51, 102, 102), (51, 51, 102 + ), (51, 0, 102), (51, 255, 51), (51, 204, 51), (51, 153, 51), ( + 51, 102, 51), (51, 51, 51), (51, 0, 51), (51, 255, 0), (51, 204, 0), ( + 51, 153, 0), (51, 102, 0), (51, 51, 0), (51, 0, 0), (0, 255, 102), + (0, 204, 102), (0, 153, 102), (0, 102, 102), (0, 51, 102), (0, 0, 102), ( + 0, 255, 51), (0, 204, 51), (0, 153, 51), (0, 102, 51), (0, 51, 51 + ), (0, 0, 51), (0, 255, 0), (0, 204, 0), (0, 153, 0), (0, 102, 0), ( + 0, 51, 0), (17, 17, 17), (34, 34, 34), (68, 68, 68), (85, 85, 85), ( + 119, 119, 119), (136, 136, 136), (170, 170, 170), (187, 187, 187), + (221, 221, 221), (238, 238, 238), (192, 192, 192), (128, 0, 0), ( + 128, 0, 128), (0, 128, 0), (0, 128, 128), (0, 0, 0), (0, 0, 0), (0, 0, 0 + ), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), ( + 0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), ( + 0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), ( + 0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0)) # so build a prototype image to be used for palette resampling def build_prototype_image(): - image = Image.new("L", (1, len(_Palm8BitColormapValues),)) + image = Image.new("L", (1, len(_Palm8BitColormapValues), )) image.putdata(list(range(len(_Palm8BitColormapValues)))) palettedata = () for i in range(len(_Palm8BitColormapValues)): @@ -90,6 +84,7 @@ def build_prototype_image(): image.putpalette(palettedata) return image + Palm8BitColormapImage = build_prototype_image() # OK, we now have in Palm8BitColormapImage, @@ -99,26 +94,22 @@ def build_prototype_image(): _FLAGS = { "custom-colormap": 0x4000, - "is-compressed": 0x8000, + "is-compressed": 0x8000, "has-transparent": 0x2000, - } +} -_COMPRESSION_TYPES = { - "none": 0xFF, - "rle": 0x01, - "scanline": 0x00, - } +_COMPRESSION_TYPES = {"none": 0xFF, "rle": 0x01, "scanline": 0x00, } o8 = _binary.o8 o16b = _binary.o16be - # # -------------------------------------------------------------------- ## # (Internal) Image save plugin for the Palm format. + def _save(im, fp, filename, check=0): if im.mode == "P": @@ -130,16 +121,16 @@ def _save(im, fp, filename, check=0): bpp = 8 version = 1 - elif (im.mode == "L" and - "bpp" in im.encoderinfo and - im.encoderinfo["bpp"] in (1, 2, 4)): + elif ( + im.mode == "L" and "bpp" in im.encoderinfo and im.encoderinfo["bpp"] in + (1, 2, 4)): # this is 8-bit grayscale, so we shift it to get the high-order bits, # and invert it because # Palm does greyscale from white (0) to black (1) bpp = im.encoderinfo["bpp"] - im = im.point( - lambda x, shift=8-bpp, maxval=(1 << bpp)-1: maxval - (x >> shift)) + im = im.point(lambda x, shift=8 - bpp, maxval=(1 << bpp) - 1: maxval - + (x >> shift)) # we ignore the palette here im.mode = "P" rawmode = "P;" + str(bpp) @@ -151,7 +142,7 @@ def _save(im, fp, filename, check=0): # only the lower bpp bits are significant. # We invert them to match the Palm. 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 im.mode = "P" rawmode = "P;" + str(bpp) @@ -180,7 +171,7 @@ def _save(im, fp, filename, check=0): cols = im.size[0] 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 compression_type = _COMPRESSION_TYPES["none"] @@ -204,7 +195,7 @@ def _save(im, fp, filename, check=0): fp.write(o16b(offset)) fp.write(o8(transparent_index)) fp.write(o8(compression_type)) - fp.write(o16b(0)) # reserved by Palm + fp.write(o16b(0)) # reserved by Palm # now write colormap if necessary @@ -213,23 +204,18 @@ def _save(im, fp, filename, check=0): for i in range(256): fp.write(o8(i)) if colormapmode == 'RGB': - fp.write( - o8(colormap[3 * i]) + - o8(colormap[3 * i + 1]) + - o8(colormap[3 * i + 2])) + fp.write(o8(colormap[3 * i]) + o8(colormap[3 * i + 1]) + + o8(colormap[3 * i + 2])) elif colormapmode == 'RGBA': - fp.write( - o8(colormap[4 * i]) + - o8(colormap[4 * i + 1]) + - o8(colormap[4 * i + 2])) + fp.write(o8(colormap[4 * i]) + o8(colormap[4 * i + 1]) + + o8(colormap[4 * i + 2])) # now convert data to raw form - ImageFile._save( - im, fp, [("raw", (0, 0)+im.size, 0, (rawmode, rowbytes, 1))]) + ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, + (rawmode, rowbytes, 1))]) fp.flush() - # # -------------------------------------------------------------------- diff --git a/PIL/PcdImagePlugin.py b/PIL/PcdImagePlugin.py index 5ce7aa48cc6..811b8a5999f 100644 --- a/PIL/PcdImagePlugin.py +++ b/PIL/PcdImagePlugin.py @@ -14,20 +14,18 @@ # See the README file for information on usage and redistribution. # - __version__ = "0.1" - from PIL import Image, ImageFile, _binary i8 = _binary.i8 - ## # Image plugin for PhotoCD images. This plugin only reads the 768x512 # image from the file; higher resolutions are encoded in a proprietary # encoding. + class PcdImageFile(ImageFile.ImageFile): format = "PCD" @@ -50,7 +48,7 @@ def _open(self): self.mode = "RGB" 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): @@ -61,7 +59,7 @@ def draft(self, mode, size): if size: 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: break # e = e[0], e[1], (e[2]-e[0]+s-1)/s+e[0], (e[3]-e[1]+s-1)/s+e[1] diff --git a/PIL/PcfFontFile.py b/PIL/PcfFontFile.py index c19a1c53246..25a6db13879 100644 --- a/PIL/PcfFontFile.py +++ b/PIL/PcfFontFile.py @@ -35,12 +35,10 @@ PCF_GLYPH_NAMES = (1 << 7) PCF_BDF_ACCELERATORS = (1 << 8) -BYTES_PER_ROW = [ - lambda bits: ((bits+7) >> 3), - lambda bits: ((bits+15) >> 3) & ~1, - lambda bits: ((bits+31) >> 3) & ~3, - lambda bits: ((bits+63) >> 3) & ~7, -] +BYTES_PER_ROW = [lambda bits: ((bits + 7) >> 3), + lambda bits: ((bits + 15) >> 3) & ~1, + lambda bits: ((bits + 31) >> 3) & ~3, + lambda bits: ((bits + 63) >> 3) & ~7, ] i8 = _binary.i8 l16 = _binary.i16le @@ -52,10 +50,10 @@ def sz(s, o): return s[o:s.index(b"\0", o)] - ## # Font file plugin for the X11 PCF format. + class PcfFontFile(FontFile.FontFile): name = "name" @@ -89,7 +87,7 @@ def __init__(self, fp): ix = encoding[ch] if ix is not None: 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 def _getformat(self, tag): @@ -158,10 +156,7 @@ def _load_metrics(self): descent = i8(fp.read(1)) - 128 xsize = right - left ysize = ascent + descent - append( - (xsize, ysize, left, right, width, - ascent, descent, 0) - ) + append((xsize, ysize, left, right, width, ascent, descent, 0)) else: @@ -175,10 +170,8 @@ def _load_metrics(self): attributes = i16(fp.read(2)) xsize = right - left ysize = ascent + descent - append( - (xsize, ysize, left, right, width, - ascent, descent, attributes) - ) + append((xsize, ysize, left, right, width, ascent, descent, + attributes)) return metrics @@ -205,7 +198,7 @@ def _load_bitmaps(self, metrics): bitmapSizes.append(i32(fp.read(4))) byteorder = format & 4 # non-zero => MSB - bitorder = format & 8 # non-zero => MSB + bitorder = format & 8 # non-zero => MSB padindex = format & 3 bitmapsize = bitmapSizes[padindex] @@ -220,10 +213,9 @@ def _load_bitmaps(self, metrics): for i in range(nbitmaps): 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( - 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 @@ -245,7 +237,7 @@ def _load_encoding(self): encodingOffset = i16(fp.read(2)) if encodingOffset != 0xFFFF: try: - encoding[i+firstCol] = encodingOffset + encoding[i + firstCol] = encodingOffset except IndexError: break # only load ISO-8859-1 glyphs diff --git a/PIL/PcxImagePlugin.py b/PIL/PcxImagePlugin.py index 0765f099e4b..a245e7b4f90 100644 --- a/PIL/PcxImagePlugin.py +++ b/PIL/PcxImagePlugin.py @@ -37,10 +37,10 @@ def _accept(prefix): return i8(prefix[0]) == 10 and i8(prefix[1]) in [0, 2, 3, 5] - ## # Image plugin for Paintbrush images. + class PcxImageFile(ImageFile.ImageFile): format = "PCX" @@ -54,11 +54,11 @@ def _open(self): raise SyntaxError("not a PCX file") # 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]: raise SyntaxError("bad PCX image size") if Image.DEBUG: - print ("BBox: %s %s %s %s" % bbox) + print("BBox: %s %s %s %s" % bbox) # format version = i8(s[1]) @@ -66,8 +66,8 @@ def _open(self): planes = i8(s[65]) stride = i16(s, 66) if Image.DEBUG: - print ("PCX version %s, bits %s, planes %s, stride %s" % - (version, bits, planes, stride)) + print("PCX version %s, bits %s, planes %s, stride %s" % + (version, bits, planes, stride)) self.info["dpi"] = i16(s, 12), i16(s, 14) @@ -87,7 +87,7 @@ def _open(self): if len(s) == 769 and i8(s[0]) == 12: # check if the palette is linear greyscale 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" break if mode == "P": @@ -102,11 +102,11 @@ def _open(self): raise IOError("unknown PCX 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 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))] @@ -143,8 +143,8 @@ def _save(im, fp, filename, check=0): # gets overwritten. if Image.DEBUG: - print ("PcxImagePlugin._save: xwidth: %d, bits: %d, stride: %d" % ( - im.size[0], bits, stride)) + print("PcxImagePlugin._save: xwidth: %d, bits: %d, stride: %d" % + (im.size[0], bits, stride)) # under windows, we could determine the current screen size with # "Image.core.display_mode()[1]", but I think that's overkill... @@ -154,18 +154,15 @@ def _save(im, fp, filename, check=0): dpi = 100, 100 # PCX header - fp.write( - o8(10) + o8(version) + o8(1) + o8(bits) + o16(0) + - o16(0) + o16(im.size[0]-1) + o16(im.size[1]-1) + o16(dpi[0]) + - o16(dpi[1]) + b"\0"*24 + b"\xFF"*24 + b"\0" + o8(planes) + - o16(stride) + o16(1) + o16(screen[0]) + o16(screen[1]) + - b"\0"*54 - ) + fp.write(o8(10) + o8(version) + o8(1) + o8(bits) + o16(0) + o16(0) + o16( + im.size[0] - 1) + o16(im.size[1] - 1) + o16(dpi[0]) + o16(dpi[1]) + + b"\0" * 24 + b"\xFF" * 24 + b"\0" + o8(planes) + o16(stride) + + o16(1) + o16(screen[0]) + o16(screen[1]) + b"\0" * 54) assert fp.tell() == 128 - ImageFile._save(im, fp, [("pcx", (0, 0)+im.size, 0, - (rawmode, bits*planes))]) + ImageFile._save(im, fp, [("pcx", (0, 0) + im.size, 0, + (rawmode, bits * planes))]) if im.mode == "P": # colour palette @@ -175,7 +172,7 @@ def _save(im, fp, filename, check=0): # greyscale palette fp.write(o8(12)) for i in range(256): - fp.write(o8(i)*3) + fp.write(o8(i) * 3) # -------------------------------------------------------------------- # registry diff --git a/PIL/PdfImagePlugin.py b/PIL/PdfImagePlugin.py index 5113f099e58..267be6ee98d 100644 --- a/PIL/PdfImagePlugin.py +++ b/PIL/PdfImagePlugin.py @@ -26,7 +26,6 @@ from PIL._binary import i8 import io - # # -------------------------------------------------------------------- @@ -37,6 +36,7 @@ # 4. page # 5. page contents + def _obj(fp, obj, **dict): fp.write("%d 0 obj\n" % obj) if dict: @@ -50,10 +50,10 @@ def _obj(fp, obj, **dict): def _endobj(fp): fp.write("endobj\n") - ## # (Internal) Image save plugin for the PDF format. + def _save(im, fp, filename): resolution = im.encoderinfo.get("resolution", 72.0) @@ -61,7 +61,7 @@ def _save(im, fp, filename): # make sure image data is available im.load() - xref = [0]*(5+1) # placeholders + xref = [0] * (5 + 1) # placeholders class TextWriter: def __init__(self, fp): @@ -105,9 +105,9 @@ def write(self, value): colorspace = "[ /Indexed /DeviceRGB 255 <" palette = im.im.getpalette("RGB") for i in range(256): - r = i8(palette[i*3]) - g = i8(palette[i*3+1]) - b = i8(palette[i*3+2]) + r = i8(palette[i * 3]) + g = i8(palette[i * 3 + 1]) + b = i8(palette[i * 3 + 2]) colorspace += "%02x%02x%02x " % (r, g, b) colorspace += "> ]" procset = "/ImageI" # indexed color @@ -126,21 +126,14 @@ def write(self, value): # catalogue xref[1] = fp.tell() - _obj( - fp, 1, - Type="/Catalog", - Pages="2 0 R") + _obj(fp, 1, Type="/Catalog", Pages="2 0 R") _endobj(fp) # # pages xref[2] = fp.tell() - _obj( - fp, 2, - Type="/Pages", - Count=1, - Kids="[4 0 R]") + _obj(fp, 2, Type="/Pages", Count=1, Kids="[4 0 R]") _endobj(fp) # @@ -155,28 +148,27 @@ def write(self, value): data = im.tobytes("raw", "1") im = Image.new("L", (len(data), 1), None) 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": Image.SAVE["JPEG"](im, op, filename) 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": - 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: raise ValueError("unsupported PDF filter (%s)" % filter) xref[3] = fp.tell() - _obj( - fp, 3, - Type="/XObject", - Subtype="/Image", - Width=width, # * 72.0 / resolution, - Height=height, # * 72.0 / resolution, - Length=len(op.getvalue()), - Filter=filter, - BitsPerComponent=bits, - DecodeParams=params, - ColorSpace=colorspace) + _obj(fp, 3, + Type="/XObject", + Subtype="/Image", + Width=width, # * 72.0 / resolution, + Height=height, # * 72.0 / resolution, + Length=len(op.getvalue()), + Filter=filter, + BitsPerComponent=bits, + DecodeParams=params, + ColorSpace=colorspace) fp.write("stream\n") fp.fp.write(op.getvalue()) @@ -189,14 +181,11 @@ def write(self, value): xref[4] = fp.tell() _obj(fp, 4) - fp.write( - "<<\n/Type /Page\n/Parent 2 0 R\n" - "/Resources <<\n/ProcSet [ /PDF %s ]\n" - "/XObject << /image 3 0 R >>\n>>\n" - "/MediaBox [ 0 0 %d %d ]\n/Contents 5 0 R\n>>\n" % ( - procset, - int(width * 72.0 / resolution), - int(height * 72.0 / resolution))) + fp.write("<<\n/Type /Page\n/Parent 2 0 R\n" + "/Resources <<\n/ProcSet [ /PDF %s ]\n" + "/XObject << /image 3 0 R >>\n>>\n" + "/MediaBox [ 0 0 %d %d ]\n/Contents 5 0 R\n>>\n" % (procset, int( + width * 72.0 / resolution), int(height * 72.0 / resolution))) _endobj(fp) # @@ -204,10 +193,8 @@ def write(self, value): op = TextWriter(io.BytesIO()) - op.write( - "q %d 0 0 %d 0 0 cm /image Do Q\n" % ( - int(width * 72.0 / resolution), - int(height * 72.0 / resolution))) + op.write("q %d 0 0 %d 0 0 cm /image Do Q\n" % + (int(width * 72.0 / resolution), int(height * 72.0 / resolution))) xref[5] = fp.tell() _obj(fp, 5, Length=len(op.fp.getvalue())) diff --git a/PIL/PixarImagePlugin.py b/PIL/PixarImagePlugin.py index ebf4c8c61e6..2068dcdd924 100644 --- a/PIL/PixarImagePlugin.py +++ b/PIL/PixarImagePlugin.py @@ -29,10 +29,10 @@ i16 = _binary.i16le i32 = _binary.i32le - ## # Image plugin for PIXAR raster images. + class PixarImageFile(ImageFile.ImageFile): format = "PIXAR" @@ -58,7 +58,7 @@ def _open(self): # FIXME: to be continued... # 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))] # # -------------------------------------------------------------------- diff --git a/PIL/PngImagePlugin.py b/PIL/PngImagePlugin.py index d8593f90d92..53c25a34c04 100644 --- a/PIL/PngImagePlugin.py +++ b/PIL/PngImagePlugin.py @@ -46,30 +46,27 @@ is_cid = re.compile(b"\w\w\w\w").match - _MAGIC = b"\211PNG\r\n\032\n" - _MODES = { # supported bits/color combinations, and corresponding modes/rawmodes - (1, 0): ("1", "1"), - (2, 0): ("L", "L;2"), - (4, 0): ("L", "L;4"), - (8, 0): ("L", "L"), + (1, 0): ("1", "1"), + (2, 0): ("L", "L;2"), + (4, 0): ("L", "L;4"), + (8, 0): ("L", "L"), (16, 0): ("I", "I;16B"), - (8, 2): ("RGB", "RGB"), + (8, 2): ("RGB", "RGB"), (16, 2): ("RGB", "RGB;16B"), - (1, 3): ("P", "P;1"), - (2, 3): ("P", "P;2"), - (4, 3): ("P", "P;4"), - (8, 3): ("P", "P"), - (8, 4): ("LA", "LA"), + (1, 3): ("P", "P;1"), + (2, 3): ("P", "P;2"), + (4, 3): ("P", "P;4"), + (8, 3): ("P", "P"), + (8, 4): ("LA", "LA"), (16, 4): ("RGBA", "LA;16B"), # LA;16B->LA not yet available - (8, 6): ("RGBA", "RGBA"), + (8, 6): ("RGBA", "RGBA"), (16, 6): ("RGBA", "RGBA;16B"), } - _simple_palette = re.compile(b'^\xff+\x00\xff*$') # Maximum decompressed size for a iTXt or zTXt chunk. @@ -78,6 +75,7 @@ # Set the maximum total text chunk size. MAX_TEXT_MEMORY = 64 * MAX_TEXT_CHUNK + def _safe_zlib_decompress(s): dobj = zlib.decompressobj() plaintext = dobj.decompress(s, MAX_TEXT_CHUNK) @@ -85,12 +83,11 @@ def _safe_zlib_decompress(s): raise ValueError("Decompressed Data Too Large") return plaintext - # -------------------------------------------------------------------- # Support classes. Suitable for PNG and related formats like MNG etc. -class ChunkStream: +class ChunkStream: def __init__(self, fp): self.fp = fp @@ -168,6 +165,7 @@ class iTXt(str): keeping their extra information """ + @staticmethod def __new__(cls, text, lang, tkey): """ @@ -225,8 +223,8 @@ def add_itxt(self, key, value, lang="", tkey="", zip=False): self.add(b"iTXt", key + b"\0\x01\0" + lang + b"\0" + tkey + b"\0" + zlib.compress(value)) else: - self.add(b"iTXt", key + b"\0\0\0" + lang + b"\0" + tkey + b"\0" + - value) + self.add(b"iTXt", + key + b"\0\0\0" + lang + b"\0" + tkey + b"\0" + value) def add_text(self, key, value, zip=0): """Appends a text chunk. @@ -255,12 +253,11 @@ def add_text(self, key, value, zip=0): else: self.add(b"tEXt", key + b"\0" + value) - # -------------------------------------------------------------------- # PNG image stream (IHDR/IEND) -class PngStream(ChunkStream): +class PngStream(ChunkStream): def __init__(self, fp): ChunkStream.__init__(self, fp) @@ -278,8 +275,9 @@ def __init__(self, fp): def check_text_memory(self, chunklen): self.text_memory += chunklen if self.text_memory > MAX_TEXT_MEMORY: - raise ValueError("Too much memory used in text chunks: %s>MAX_TEXT_MEMORY" % - self.text_memory) + raise ValueError( + "Too much memory used in text chunks: %s>MAX_TEXT_MEMORY" % + self.text_memory) def chunk_iCCP(self, pos, length): @@ -296,10 +294,10 @@ def chunk_iCCP(self, pos, length): print("Compression method", i8(s[i])) comp_method = i8(s[i]) if comp_method != 0: - raise SyntaxError("Unknown compression method %s in iCCP chunk" % - comp_method) + raise SyntaxError( + "Unknown compression method %s in iCCP chunk" % comp_method) try: - icc_profile = _safe_zlib_decompress(s[i+2:]) + icc_profile = _safe_zlib_decompress(s[i + 2:]) except zlib.error: icc_profile = None # FIXME self.im_info["icc_profile"] = icc_profile @@ -323,7 +321,7 @@ def chunk_IHDR(self, pos, length): def chunk_IDAT(self, pos, length): # 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 raise EOFError @@ -411,8 +409,8 @@ def chunk_zTXt(self, pos, length): else: comp_method = 0 if comp_method != 0: - raise SyntaxError("Unknown compression method %s in zTXt chunk" % - comp_method) + raise SyntaxError( + "Unknown compression method %s in zTXt chunk" % comp_method) try: v = _safe_zlib_decompress(v[1:]) except zlib.error: @@ -465,17 +463,17 @@ def chunk_iTXt(self, pos, length): return s - # -------------------------------------------------------------------- # PNG reader + def _accept(prefix): return prefix[:8] == _MAGIC - ## # Image plugin for PNG images. + class PngImageFile(ImageFile.ImageFile): format = "PNG" @@ -546,7 +544,7 @@ def load_prepare(self): "internal: prepare to read PNG file" if self.info.get("interlace"): - self.decoderconfig = self.decoderconfig + (1,) + self.decoderconfig = self.decoderconfig + (1, ) ImageFile.ImageFile.load_prepare(self) @@ -582,7 +580,6 @@ def load_end(self): self.png.close() self.png = None - # -------------------------------------------------------------------- # PNG writer @@ -592,19 +589,19 @@ def load_end(self): _OUTMODES = { # supported PIL modes, and corresponding rawmodes/bits/color combinations - "1": ("1", b'\x01\x00'), - "L;1": ("L;1", b'\x01\x00'), - "L;2": ("L;2", b'\x02\x00'), - "L;4": ("L;4", b'\x04\x00'), - "L": ("L", b'\x08\x00'), - "LA": ("LA", b'\x08\x04'), - "I": ("I;16B", b'\x10\x00'), - "P;1": ("P;1", b'\x01\x03'), - "P;2": ("P;2", b'\x02\x03'), - "P;4": ("P;4", b'\x04\x03'), - "P": ("P", b'\x08\x03'), - "RGB": ("RGB", b'\x08\x02'), - "RGBA": ("RGBA", b'\x08\x06'), + "1": ("1", b'\x01\x00'), + "L;1": ("L;1", b'\x01\x00'), + "L;2": ("L;2", b'\x02\x00'), + "L;4": ("L;4", b'\x04\x00'), + "L": ("L", b'\x08\x00'), + "LA": ("LA", b'\x08\x04'), + "I": ("I;16B", b'\x10\x00'), + "P;1": ("P;1", b'\x01\x03'), + "P;2": ("P;2", b'\x02\x03'), + "P;4": ("P;4", b'\x04\x03'), + "P": ("P", b'\x08\x03'), + "RGB": ("RGB", b'\x08\x02'), + "RGBA": ("RGBA", b'\x08\x06'), } @@ -645,7 +642,7 @@ def _save(im, fp, filename, chunk=putchunk, check=0): else: # check palette contents 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: colors = 256 @@ -668,8 +665,7 @@ def _save(im, fp, filename, chunk=putchunk, check=0): im.encoderconfig = ("optimize" in im.encoderinfo, im.encoderinfo.get("compress_level", -1), - im.encoderinfo.get("compress_type", -1), - dictionary) + im.encoderinfo.get("compress_type", -1), dictionary) # get the corresponding PNG mode try: @@ -685,12 +681,11 @@ def _save(im, fp, filename, chunk=putchunk, check=0): fp.write(_MAGIC) - chunk(fp, b"IHDR", - o32(im.size[0]), o32(im.size[1]), # 0: size - mode, # 8: depth/type - b'\0', # 10: compression - b'\0', # 11: filter category - b'\0') # 12: interlace flag + chunk(fp, b"IHDR", o32(im.size[0]), o32(im.size[1]), # 0: size + mode, # 8: depth/type + b'\0', # 10: compression + b'\0', # 11: filter category + b'\0') # 12: interlace flag if im.mode == "P": 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 im.mode == "P": # limit to actual palette size - alpha_bytes = 2**bits + alpha_bytes = 2 ** bits if isinstance(transparency, bytes): chunk(fp, b"tRNS", transparency[:alpha_bytes]) else: @@ -726,15 +721,13 @@ def _save(im, fp, filename, chunk=putchunk, check=0): else: if im.mode == "P" and im.im.getpalettemode() == "RGBA": alpha = im.im.getpalette("RGBA", "A") - alpha_bytes = 2**bits + alpha_bytes = 2 ** bits chunk(fp, b"tRNS", alpha[:alpha_bytes]) dpi = im.encoderinfo.get("dpi") if dpi: - chunk(fp, b"pHYs", - o32(int(dpi[0] / 0.0254 + 0.5)), - o32(int(dpi[1] / 0.0254 + 0.5)), - b'\x01') + chunk(fp, b"pHYs", o32(int(dpi[0] / 0.0254 + 0.5)), + o32(int(dpi[1] / 0.0254 + 0.5)), b'\x01') info = im.encoderinfo.get("pnginfo") if info: @@ -753,8 +746,8 @@ def _save(im, fp, filename, chunk=putchunk, check=0): data = name + b"\0\0" + zlib.compress(im.info["icc_profile"]) chunk(fp, b"iCCP", data) - ImageFile._save(im, _idat(fp, chunk), - [("zip", (0, 0)+im.size, 0, rawmode)]) + ImageFile._save(im, _idat(fp, chunk), [("zip", + (0, 0) + im.size, 0, rawmode)]) chunk(fp, b"IEND", b"") @@ -763,10 +756,10 @@ def _save(im, fp, filename, chunk=putchunk, check=0): except: pass - # -------------------------------------------------------------------- # PNG chunk converter + def getchunks(im, **params): """Return a list of PNG chunks representing this image.""" @@ -795,7 +788,6 @@ def append(fp, cid, *data): return fp.data - # -------------------------------------------------------------------- # Registry diff --git a/PIL/PpmImagePlugin.py b/PIL/PpmImagePlugin.py index 954832451b7..08f70766056 100644 --- a/PIL/PpmImagePlugin.py +++ b/PIL/PpmImagePlugin.py @@ -14,7 +14,6 @@ # See the README file for information on usage and redistribution. # - __version__ = "0.2" import string @@ -37,25 +36,19 @@ MODES = { # standard - b"P4": "1", - b"P5": "L", - b"P6": "RGB", - # extensions - b"P0CMYK": "CMYK", - # PIL extensions (for test purposes only) - b"PyP": "P", - b"PyRGBA": "RGBA", - b"PyCMYK": "CMYK" + b"P4": "1", b"P5": "L", b"P6": "RGB", # extensions + b"P0CMYK": "CMYK", # PIL extensions (for test purposes only) + b"PyP": "P", b"PyRGBA": "RGBA", b"PyCMYK": "CMYK" } def _accept(prefix): return prefix[0:1] == b"P" and prefix[1] in b"0456y" - ## # Image plugin for PBM, PGM, and PPM images. + class PpmImageFile(ImageFile.ImageFile): format = "PPM" @@ -108,7 +101,7 @@ def _open(self): if s > 255: if not mode == 'L': raise ValueError("Too many colors for band: %s" % s) - if s < 2**16: + if s < 2 ** 16: self.mode = 'I' rawmode = 'I;16B' else: @@ -116,19 +109,17 @@ def _open(self): rawmode = 'I;32B' self.size = xsize, ysize - self.tile = [("raw", - (0, 0, xsize, ysize), - self.fp.tell(), - (rawmode, 0, 1))] + self.tile = [("raw", (0, 0, xsize, ysize), self.fp.tell(), + (rawmode, 0, 1))] # ALTERNATIVE: load via builtin debug function # self.im = Image.core.open_ppm(self.filename) # self.mode = self.im.mode # self.size = self.im.size + # + # -------------------------------------------------------------------- -# -# -------------------------------------------------------------------- def _save(im, fp, filename): if im.mode == "1": @@ -136,7 +127,7 @@ def _save(im, fp, filename): elif im.mode == "L": rawmode, head = "L", b"P5" elif im.mode == "I": - if im.getextrema()[1] < 2**16: + if im.getextrema()[1] < 2 ** 16: rawmode, head = "I;16B", b"P5" else: rawmode, head = "I;32B", b"P5" @@ -156,13 +147,14 @@ def _save(im, fp, filename): fp.write(b"65535\n") elif rawmode == "I;32B": 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 # im._dump(filename) -# -# -------------------------------------------------------------------- + # + # -------------------------------------------------------------------- + Image.register_open("PPM", PpmImageFile, _accept) Image.register_save("PPM", _save) diff --git a/PIL/PsdImagePlugin.py b/PIL/PsdImagePlugin.py index 02c94a8603f..72fc87be5d6 100644 --- a/PIL/PsdImagePlugin.py +++ b/PIL/PsdImagePlugin.py @@ -40,17 +40,17 @@ i16 = _binary.i16be i32 = _binary.i32be - # --------------------------------------------------------------------. # read PSD images + def _accept(prefix): return prefix[:4] == b"8BPS" - ## # Image plugin for Photoshop images. + class PsdImageFile(ImageFile.ImageFile): format = "PSD" @@ -139,7 +139,7 @@ def seek(self, layer): try: if layer <= 0: raise IndexError - name, mode, bbox, tile = self.layers[layer-1] + name, mode, bbox, tile = self.layers[layer - 1] self.mode = mode self.tile = tile self.frame = layer @@ -187,7 +187,7 @@ def _layerinfo(file): if type == 65535: m = "A" else: - m = "RGBA"[type] + m = "RGBA" [type] mode.append(m) size = i32(read(4)) @@ -269,7 +269,7 @@ def _maketile(file, mode, bbox, channels): if mode == "CMYK": layer += ";I" tile.append(("raw", bbox, offset, layer)) - offset = offset + xsize*ysize + offset = offset + xsize * ysize elif compression == 1: # @@ -282,11 +282,9 @@ def _maketile(file, mode, bbox, channels): layer = mode[channel] if mode == "CMYK": layer += ";I" - tile.append( - ("packbits", bbox, offset, layer) - ) + tile.append(("packbits", bbox, offset, layer)) for y in range(ysize): - offset = offset + i16(bytecount[i:i+2]) + offset = offset + i16(bytecount[i:i + 2]) i += 2 file.seek(offset) diff --git a/PIL/PyAccess.py b/PIL/PyAccess.py index a3f1c390968..f75d2fc236b 100644 --- a/PIL/PyAccess.py +++ b/PIL/PyAccess.py @@ -40,7 +40,6 @@ class PyAccess(object): - def __init__(self, img, readonly=False): vals = dict(img.im.unsafe_ptrs) self.readonly = readonly @@ -51,7 +50,7 @@ def __init__(self, img, readonly=False): self.ysize = vals['ysize'] if DEBUG: - print (vals) + print(vals) self._post_init() def _post_init(self): @@ -97,6 +96,7 @@ def check_xy(self, xy): class _PyAccess32_2(PyAccess): """ PA, LA, stored in first and last bytes of a 32 bit word """ + def _post_init(self, *args, **kwargs): self.pixels = ffi.cast("struct Pixel_RGBA **", self.image32) @@ -131,6 +131,7 @@ def set_pixel(self, x, y, color): class _PyAccess32_4(PyAccess): """ RGBA etc, all 4 bytes of a 32 bit word """ + def _post_init(self, *args, **kwargs): self.pixels = ffi.cast("struct Pixel_RGBA **", self.image32) @@ -149,6 +150,7 @@ def set_pixel(self, x, y, color): class _PyAccess8(PyAccess): """ 1, L, P, 8 bit images stored as uint8 """ + def _post_init(self, *args, **kwargs): self.pixels = self.image8 @@ -166,6 +168,7 @@ def set_pixel(self, x, y, color): class _PyAccessI16_N(PyAccess): """ I;16 access, native bitendian without conversion """ + def _post_init(self, *args, **kwargs): self.pixels = ffi.cast('unsigned short **', self.image) @@ -183,6 +186,7 @@ def set_pixel(self, x, y, color): class _PyAccessI16_L(PyAccess): """ I;16L access, with conversion """ + def _post_init(self, *args, **kwargs): self.pixels = ffi.cast('struct Pixel_I16 **', self.image) @@ -203,6 +207,7 @@ def set_pixel(self, x, y, color): class _PyAccessI16_B(PyAccess): """ I;16B access, with conversion """ + def _post_init(self, *args, **kwargs): self.pixels = ffi.cast('struct Pixel_I16 **', self.image) @@ -223,6 +228,7 @@ def set_pixel(self, x, y, color): class _PyAccessI32_N(PyAccess): """ Signed Int32 access, native endian """ + def _post_init(self, *args, **kwargs): self.pixels = self.image32 @@ -235,6 +241,7 @@ def set_pixel(self, x, y, color): class _PyAccessI32_Swap(PyAccess): """ I;32L/B access, with byteswapping conversion """ + def _post_init(self, *args, **kwargs): self.pixels = self.image32 @@ -254,6 +261,7 @@ def set_pixel(self, x, y, color): class _PyAccessF(PyAccess): """ 32 bit float access """ + def _post_init(self, *args, **kwargs): self.pixels = ffi.cast('float **', self.image32) @@ -269,22 +277,23 @@ def set_pixel(self, x, y, color): self.pixels[y][x] = color[0] -mode_map = {'1': _PyAccess8, - 'L': _PyAccess8, - 'P': _PyAccess8, - 'LA': _PyAccess32_2, - 'PA': _PyAccess32_2, - 'RGB': _PyAccess32_3, - 'LAB': _PyAccess32_3, - 'HSV': _PyAccess32_3, - 'YCbCr': _PyAccess32_3, - 'RGBA': _PyAccess32_4, - 'RGBa': _PyAccess32_4, - 'RGBX': _PyAccess32_4, - 'CMYK': _PyAccess32_4, - 'F': _PyAccessF, - 'I': _PyAccessI32_N, - } +mode_map = { + '1': _PyAccess8, + 'L': _PyAccess8, + 'P': _PyAccess8, + 'LA': _PyAccess32_2, + 'PA': _PyAccess32_2, + 'RGB': _PyAccess32_3, + 'LAB': _PyAccess32_3, + 'HSV': _PyAccess32_3, + 'YCbCr': _PyAccess32_3, + 'RGBA': _PyAccess32_4, + 'RGBa': _PyAccess32_4, + 'RGBX': _PyAccess32_4, + 'CMYK': _PyAccess32_4, + 'F': _PyAccessF, + 'I': _PyAccessI32_N, +} if sys.byteorder == 'little': mode_map['I;16'] = _PyAccessI16_N diff --git a/PIL/SgiImagePlugin.py b/PIL/SgiImagePlugin.py index 2b8fcd8e474..25c9174e199 100644 --- a/PIL/SgiImagePlugin.py +++ b/PIL/SgiImagePlugin.py @@ -17,10 +17,8 @@ # See the README file for information on usage and redistribution. # - __version__ = "0.2" - from PIL import Image, ImageFile, _binary i8 = _binary.i8 @@ -31,10 +29,10 @@ def _accept(prefix): return i16(prefix) == 474 - ## # Image plugin for SGI images. + class SgiImageFile(ImageFile.ImageFile): format = "SGI" @@ -69,11 +67,11 @@ def _open(self): # decoder info if compression == 0: offset = 512 - pagesize = self.size[0]*self.size[1]*layout[0] + pagesize = self.size[0] * self.size[1] * layout[0] self.tile = [] for layer in self.mode: - self.tile.append( - ("raw", (0, 0)+self.size, offset, (layer, 0, -1))) + self.tile.append(("raw", (0, 0) + self.size, offset, + (layer, 0, -1))) offset = offset + pagesize elif compression == 1: raise ValueError("SGI RLE encoding not supported") diff --git a/PIL/SpiderImagePlugin.py b/PIL/SpiderImagePlugin.py index 306b348bc40..dbd6d3e513b 100644 --- a/PIL/SpiderImagePlugin.py +++ b/PIL/SpiderImagePlugin.py @@ -44,23 +44,24 @@ def isInt(f): try: i = int(f) - if f-i == 0: + if f - i == 0: return 1 else: return 0 except: return 0 -iforms = [1, 3, -11, -12, -21, -22] +iforms = [1, 3, -11, -12, -21, -22] # There is no magic number to identify Spider files, so just check a # series of header locations to see if they have reasonable values. # Returns no.of bytes in the header, if it is a valid Spider header, # otherwise returns 0 + def isSpiderHeader(t): - h = (99,) + t # add 1 value so can use spider header index start=1 + 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 for i in [1, 2, 5, 12, 13, 22, 23]: if not isInt(h[i]): @@ -70,9 +71,9 @@ def isSpiderHeader(t): if iform not in iforms: return 0 # check other header values - labrec = int(h[13]) # no. records in file header - labbyt = int(h[22]) # total no. of bytes in header - lenbyt = int(h[23]) # record length in bytes + labrec = int(h[13]) # no. records in file header + labbyt = int(h[22]) # total no. of bytes in header + lenbyt = int(h[23]) # record length in bytes # print "labrec = %d, labbyt = %d, lenbyt = %d" % (labrec,labbyt,lenbyt) if labbyt != (labrec * lenbyt): return 0 @@ -82,7 +83,7 @@ def isSpiderHeader(t): def isSpiderImage(filename): fp = open(filename, 'rb') - f = fp.read(92) # read 23 * 4 bytes + f = fp.read(92) # read 23 * 4 bytes fp.close() t = struct.unpack('>23f', f) # try big-endian first hdrlen = isSpiderHeader(t) @@ -115,7 +116,7 @@ def _open(self): except struct.error: 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]) if iform != 1: raise SyntaxError("not a Spider 2D image") @@ -149,9 +150,7 @@ def _open(self): self.rawmode = "F;32F" self.mode = "F" - self.tile = [ - ("raw", (0, 0) + self.size, offset, - (self.rawmode, 0, 1))] + self.tile = [("raw", (0, 0) + self.size, offset, (self.rawmode, 0, 1))] self.__fp = self.fp # FIXME: hack # 1st image index is zero (although SPIDER imgnumber starts at 1) @@ -176,7 +175,7 @@ def convert2byte(self, depth=255): (min, max) = self.getextrema() m = 1 if max != min: - m = depth / (max-min) + m = depth / (max - min) b = -m * min return self.point(lambda i, m=m, b=b: i * m + b).convert("L") @@ -185,10 +184,10 @@ def tkPhotoImage(self): from PIL import ImageTk return ImageTk.PhotoImage(self.convert2byte(), palette=256) - # -------------------------------------------------------------------- # Image series + # given a list of filenames, return a list of images def loadImageSeries(filelist=None): " create a list of Image.images for use in montage " @@ -210,10 +209,10 @@ def loadImageSeries(filelist=None): imglist.append(im) return imglist - # -------------------------------------------------------------------- # For saving images in Spider format + def makeSpiderHeader(im): nsam, nrow = im.size lenbyt = nsam * 4 # There are labrec records in the header @@ -230,10 +229,10 @@ def makeSpiderHeader(im): return [] # NB these are Fortran indices - hdr[1] = 1.0 # nslice (=1 for an image) - hdr[2] = float(nrow) # number of rows per slice - hdr[5] = 1.0 # iform for 2D image - hdr[12] = float(nsam) # number of pixels per line + hdr[1] = 1.0 # nslice (=1 for an image) + hdr[2] = float(nrow) # number of rows per slice + hdr[5] = 1.0 # iform for 2D image + hdr[12] = float(nsam) # number of pixels per line hdr[13] = float(labrec) # number of records in file header hdr[22] = float(labbyt) # total number of bytes in header hdr[23] = float(lenbyt) # record length in bytes @@ -264,7 +263,7 @@ def _save(im, fp, filename): fp.writelines(hdr) 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() @@ -306,7 +305,6 @@ def _save_spider(im, fp, filename): if outfile != "": # perform some image operation im = im.transpose(Image.FLIP_LEFT_RIGHT) - print( - "saving a flipped version of %s as %s " % - (os.path.basename(filename), outfile)) + print("saving a flipped version of %s as %s " % + (os.path.basename(filename), outfile)) im.save(outfile, "SPIDER") diff --git a/PIL/SunImagePlugin.py b/PIL/SunImagePlugin.py index e0a7aa6ee35..fdd56ba1427 100644 --- a/PIL/SunImagePlugin.py +++ b/PIL/SunImagePlugin.py @@ -16,10 +16,8 @@ # See the README file for information on usage and redistribution. # - __version__ = "0.3" - from PIL import Image, ImageFile, ImagePalette, _binary i16 = _binary.i16be @@ -29,10 +27,10 @@ def _accept(prefix): return i32(prefix) == 0x59a66a95 - ## # Image plugin for Sun raster files. + class SunImageFile(ImageFile.ImageFile): format = "SUN" @@ -71,9 +69,10 @@ def _open(self): stride = (((self.size[0] * depth + 7) // 8) + 3) & (~3) if compression == 1: - self.tile = [("raw", (0, 0)+self.size, offset, (rawmode, stride))] + self.tile = [("raw", (0, 0) + self.size, offset, + (rawmode, stride))] elif compression == 2: - self.tile = [("sun_rle", (0, 0)+self.size, offset, rawmode)] + self.tile = [("sun_rle", (0, 0) + self.size, offset, rawmode)] # # registry diff --git a/PIL/TarIO.py b/PIL/TarIO.py index 4e5115b268f..d70de0897de 100644 --- a/PIL/TarIO.py +++ b/PIL/TarIO.py @@ -16,11 +16,11 @@ from PIL import ContainerIO - ## # A file object that provides read access to a given member of a TAR # file. + class TarIO(ContainerIO.ContainerIO): ## diff --git a/PIL/TgaImagePlugin.py b/PIL/TgaImagePlugin.py index 46eafe8d029..38e33f97c54 100644 --- a/PIL/TgaImagePlugin.py +++ b/PIL/TgaImagePlugin.py @@ -16,12 +16,10 @@ # See the README file for information on usage and redistribution. # - __version__ = "0.3" from PIL import Image, ImageFile, ImagePalette, _binary - # # -------------------------------------------------------------------- # Read RGA file @@ -30,21 +28,20 @@ i16 = _binary.i16le i32 = _binary.i32le - MODES = { # map imagetype/depth to rawmode - (1, 8): "P", - (3, 1): "1", - (3, 8): "L", + (1, 8): "P", + (3, 1): "1", + (3, 8): "L", (2, 16): "BGR;5", (2, 24): "BGR", (2, 32): "BGRA", } - ## # Image plugin for Targa files. + class TgaImageFile(ImageFile.ImageFile): format = "TGA" @@ -108,24 +105,24 @@ def _open(self): start, size, mapdepth = i16(s[3:]), i16(s[5:]), i16(s[7:]) if mapdepth == 16: 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: 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: 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 try: rawmode = MODES[(imagetype & 7, depth)] if imagetype & 8: # compressed - self.tile = [("tga_rle", (0, 0)+self.size, - self.fp.tell(), (rawmode, orientation, depth))] + self.tile = [("tga_rle", (0, 0) + self.size, self.fp.tell(), + (rawmode, orientation, depth))] else: - self.tile = [("raw", (0, 0)+self.size, - self.fp.tell(), (rawmode, 0, orientation))] + self.tile = [("raw", (0, 0) + self.size, self.fp.tell(), + (rawmode, 0, orientation))] except KeyError: pass # cannot decode @@ -170,24 +167,15 @@ def _save(im, fp, filename, check=0): if orientation > 0: flags = flags | 0x20 - fp.write(b"\000" + - o8(colormaptype) + - o8(imagetype) + - o16(colormapfirst) + - o16(colormaplength) + - o8(colormapentry) + - o16(0) + - o16(0) + - o16(im.size[0]) + - o16(im.size[1]) + - o8(bits) + - o8(flags)) + fp.write(b"\000" + o8(colormaptype) + o8(imagetype) + o16(colormapfirst) + + o16(colormaplength) + o8(colormapentry) + o16(0) + o16(0) + + o16(im.size[0]) + o16(im.size[1]) + o8(bits) + o8(flags)) if colormaptype: fp.write(im.im.getpalette("RGB", "BGR")) - ImageFile._save( - im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, orientation))]) + ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, + (rawmode, 0, orientation))]) # # -------------------------------------------------------------------- diff --git a/PIL/TiffImagePlugin.py b/PIL/TiffImagePlugin.py index a533c27eae6..25d983ffc08 100644 --- a/PIL/TiffImagePlugin.py +++ b/PIL/TiffImagePlugin.py @@ -144,75 +144,73 @@ OPEN_INFO = { # (ByteOrder, PhotoInterpretation, SampleFormat, FillOrder, BitsPerSample, # ExtraSamples) => mode, rawmode - (II, 0, 1, 1, (1,), ()): ("1", "1;I"), - (II, 0, 1, 2, (1,), ()): ("1", "1;IR"), - (II, 0, 1, 1, (8,), ()): ("L", "L;I"), - (II, 0, 1, 2, (8,), ()): ("L", "L;IR"), - (II, 0, 3, 1, (32,), ()): ("F", "F;32F"), - (II, 1, 1, 1, (1,), ()): ("1", "1"), - (II, 1, 1, 1, (4,), ()): ("L", "L;4"), - (II, 1, 1, 2, (1,), ()): ("1", "1;R"), - (II, 1, 1, 1, (8,), ()): ("L", "L"), - (II, 1, 1, 1, (8, 8), (2,)): ("LA", "LA"), - (II, 1, 1, 2, (8,), ()): ("L", "L;R"), - (II, 1, 1, 1, (12,), ()): ("I;16", "I;12"), - (II, 1, 1, 1, (16,), ()): ("I;16", "I;16"), - (II, 1, 2, 1, (16,), ()): ("I;16S", "I;16S"), - (II, 1, 1, 1, (32,), ()): ("I", "I;32N"), - (II, 1, 2, 1, (32,), ()): ("I", "I;32S"), - (II, 1, 3, 1, (32,), ()): ("F", "F;32F"), + (II, 0, 1, 1, (1, ), ()): ("1", "1;I"), + (II, 0, 1, 2, (1, ), ()): ("1", "1;IR"), + (II, 0, 1, 1, (8, ), ()): ("L", "L;I"), + (II, 0, 1, 2, (8, ), ()): ("L", "L;IR"), + (II, 0, 3, 1, (32, ), ()): ("F", "F;32F"), + (II, 1, 1, 1, (1, ), ()): ("1", "1"), + (II, 1, 1, 1, (4, ), ()): ("L", "L;4"), + (II, 1, 1, 2, (1, ), ()): ("1", "1;R"), + (II, 1, 1, 1, (8, ), ()): ("L", "L"), + (II, 1, 1, 1, (8, 8), (2, )): ("LA", "LA"), + (II, 1, 1, 2, (8, ), ()): ("L", "L;R"), + (II, 1, 1, 1, (12, ), ()): ("I;16", "I;12"), + (II, 1, 1, 1, (16, ), ()): ("I;16", "I;16"), + (II, 1, 2, 1, (16, ), ()): ("I;16S", "I;16S"), + (II, 1, 1, 1, (32, ), ()): ("I", "I;32N"), + (II, 1, 2, 1, (32, ), ()): ("I", "I;32S"), + (II, 1, 3, 1, (32, ), ()): ("F", "F;32F"), (II, 2, 1, 1, (8, 8, 8), ()): ("RGB", "RGB"), (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), (0,)): ("RGBX", "RGBX"), - (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), (999,)): ("RGBA", "RGBA"), # Corel Draw 10 - (II, 3, 1, 1, (1,), ()): ("P", "P;1"), - (II, 3, 1, 2, (1,), ()): ("P", "P;1R"), - (II, 3, 1, 1, (2,), ()): ("P", "P;2"), - (II, 3, 1, 2, (2,), ()): ("P", "P;2R"), - (II, 3, 1, 1, (4,), ()): ("P", "P;4"), - (II, 3, 1, 2, (4,), ()): ("P", "P;4R"), - (II, 3, 1, 1, (8,), ()): ("P", "P"), - (II, 3, 1, 1, (8, 8), (2,)): ("PA", "PA"), - (II, 3, 1, 2, (8,), ()): ("P", "P;R"), + (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), (2, )): ("RGBA", "RGBA"), + (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, 2, (1, ), ()): ("P", "P;1R"), + (II, 3, 1, 1, (2, ), ()): ("P", "P;2"), + (II, 3, 1, 2, (2, ), ()): ("P", "P;2R"), + (II, 3, 1, 1, (4, ), ()): ("P", "P;4"), + (II, 3, 1, 2, (4, ), ()): ("P", "P;4R"), + (II, 3, 1, 1, (8, ), ()): ("P", "P"), + (II, 3, 1, 1, (8, 8), (2, )): ("PA", "PA"), + (II, 3, 1, 2, (8, ), ()): ("P", "P;R"), (II, 5, 1, 1, (8, 8, 8, 8), ()): ("CMYK", "CMYK"), (II, 6, 1, 1, (8, 8, 8), ()): ("YCbCr", "YCbCr"), (II, 8, 1, 1, (8, 8, 8), ()): ("LAB", "LAB"), - - (MM, 0, 1, 1, (1,), ()): ("1", "1;I"), - (MM, 0, 1, 2, (1,), ()): ("1", "1;IR"), - (MM, 0, 1, 1, (8,), ()): ("L", "L;I"), - (MM, 0, 1, 2, (8,), ()): ("L", "L;IR"), - (MM, 1, 1, 1, (1,), ()): ("1", "1"), - (MM, 1, 1, 2, (1,), ()): ("1", "1;R"), - (MM, 1, 1, 1, (8,), ()): ("L", "L"), - (MM, 1, 1, 1, (8, 8), (2,)): ("LA", "LA"), - (MM, 1, 1, 2, (8,), ()): ("L", "L;R"), - (MM, 1, 1, 1, (16,), ()): ("I;16B", "I;16B"), - (MM, 1, 2, 1, (16,), ()): ("I;16BS", "I;16BS"), - (MM, 1, 2, 1, (32,), ()): ("I;32BS", "I;32BS"), - (MM, 1, 3, 1, (32,), ()): ("F", "F;32BF"), + (MM, 0, 1, 1, (1, ), ()): ("1", "1;I"), + (MM, 0, 1, 2, (1, ), ()): ("1", "1;IR"), + (MM, 0, 1, 1, (8, ), ()): ("L", "L;I"), + (MM, 0, 1, 2, (8, ), ()): ("L", "L;IR"), + (MM, 1, 1, 1, (1, ), ()): ("1", "1"), + (MM, 1, 1, 2, (1, ), ()): ("1", "1;R"), + (MM, 1, 1, 1, (8, ), ()): ("L", "L"), + (MM, 1, 1, 1, (8, 8), (2, )): ("LA", "LA"), + (MM, 1, 1, 2, (8, ), ()): ("L", "L;R"), + (MM, 1, 1, 1, (16, ), ()): ("I;16B", "I;16B"), + (MM, 1, 2, 1, (16, ), ()): ("I;16BS", "I;16BS"), + (MM, 1, 2, 1, (32, ), ()): ("I;32BS", "I;32BS"), + (MM, 1, 3, 1, (32, ), ()): ("F", "F;32BF"), (MM, 2, 1, 1, (8, 8, 8), ()): ("RGB", "RGB"), (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), (1,)): ("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, 3, 1, 1, (1,), ()): ("P", "P;1"), - (MM, 3, 1, 2, (1,), ()): ("P", "P;1R"), - (MM, 3, 1, 1, (2,), ()): ("P", "P;2"), - (MM, 3, 1, 2, (2,), ()): ("P", "P;2R"), - (MM, 3, 1, 1, (4,), ()): ("P", "P;4"), - (MM, 3, 1, 2, (4,), ()): ("P", "P;4R"), - (MM, 3, 1, 1, (8,), ()): ("P", "P"), - (MM, 3, 1, 1, (8, 8), (2,)): ("PA", "PA"), - (MM, 3, 1, 2, (8,), ()): ("P", "P;R"), + (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), (2, )): ("RGBA", "RGBA"), + (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, 2, (1, ), ()): ("P", "P;1R"), + (MM, 3, 1, 1, (2, ), ()): ("P", "P;2"), + (MM, 3, 1, 2, (2, ), ()): ("P", "P;2R"), + (MM, 3, 1, 1, (4, ), ()): ("P", "P;4"), + (MM, 3, 1, 2, (4, ), ()): ("P", "P;4R"), + (MM, 3, 1, 1, (8, ), ()): ("P", "P"), + (MM, 3, 1, 1, (8, 8), (2, )): ("PA", "PA"), + (MM, 3, 1, 2, (8, ), ()): ("P", "P;R"), (MM, 5, 1, 1, (8, 8, 8, 8), ()): ("CMYK", "CMYK"), (MM, 6, 1, 1, (8, 8, 8), ()): ("YCbCr", "YCbCr"), (MM, 8, 1, 1, (8, 8, 8), ()): ("LAB", "LAB"), - } PREFIXES = [b"MM\000\052", b"II\052\000", b"II\xBC\000"] @@ -221,10 +219,10 @@ def _accept(prefix): return prefix[:4] in PREFIXES - ## # Wrapper for TIFF IFDs. + class ImageFileDirectory(collections.MutableMapping): """ This class represents a TIFF tag directory. To speed things up, we don't decode tags unless they're asked for. @@ -338,6 +336,7 @@ def __contains__(self, tag): return tag in self.tags or tag in self.tagdata if bytes is str: + def has_key(self, tag): return tag in self @@ -346,7 +345,7 @@ def __setitem__(self, tag, value): # tags are not tuples for byte, string, and undefined data. # see load_* if not isinstance(value, tuple): - value = (value,) + value = (value, ) self.tags[tag] = value def __delitem__(self, tag): @@ -366,12 +365,14 @@ def items(self): def load_byte(self, data): return data + load_dispatch[1] = (1, load_byte) def load_string(self, data): if data[-1:] == b'\0': data = data[:-1] return data.decode('latin-1', 'replace') + load_dispatch[2] = (1, load_string) def load_short(self, data): @@ -379,6 +380,7 @@ def load_short(self, data): for i in range(0, len(data), 2): l.append(self.i16(data, i)) return tuple(l) + load_dispatch[3] = (2, load_short) def load_long(self, data): @@ -386,13 +388,15 @@ def load_long(self, data): for i in range(0, len(data), 4): l.append(self.i32(data, i)) return tuple(l) + load_dispatch[4] = (4, load_long) def load_rational(self, data): l = [] 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) + load_dispatch[5] = (8, load_rational) def load_float(self, data): @@ -400,6 +404,7 @@ def load_float(self, data): if self.prefix != native_prefix: a.byteswap() return tuple(a) + load_dispatch[11] = (4, load_float) def load_double(self, data): @@ -407,11 +412,13 @@ def load_double(self, data): if self.prefix != native_prefix: a.byteswap() return tuple(a) + load_dispatch[12] = (8, load_double) def load_undefined(self, data): # Untyped data return data + load_dispatch[7] = (1, load_undefined) def load(self, fp): @@ -458,7 +465,7 @@ def load(self, fp): data = ImageFile._safe_read(fp, size) fp.seek(here) else: - data = ifd[8:8+size] + data = ifd[8:8 + size] if len(data) != size: warnings.warn("Possibly corrupt EXIF data. " @@ -506,7 +513,7 @@ def save(self, fp): typ = self.tagtype[tag] 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: # byte data @@ -567,11 +574,12 @@ def save(self, fp): if len(data) == 4: append((tag, typ, len(value), data, b"")) elif len(data) < 4: - append((tag, typ, len(value), data + (4-len(data))*b"\0", b"")) + append((tag, typ, len(value), data + + (4 - len(data)) * b"\0", b"")) else: count = len(value) if typ == 5: - count = count // 2 # adjust for rational data field + count = count // 2 # adjust for rational data field append((tag, typ, count, o32(offset), data)) offset += len(data) @@ -602,10 +610,10 @@ def save(self, fp): return offset - ## # Image plugin for TIFF files. + class TiffImageFile(ImageFile.ImageFile): format = "TIFF" @@ -629,9 +637,9 @@ def _open(self): self.__fp = self.fp if Image.DEBUG: - print ("*** TiffImageFile._open ***") - print ("- __first:", self.__first) - print ("- ifh: ", ifh) + print("*** TiffImageFile._open ***") + print("- __first:", self.__first) + print("- ifh: ", ifh) # and load the first frame self._seek(0) @@ -661,8 +669,9 @@ def _seek(self, frame): if not self.__next: raise EOFError("no more images in TIFF file") if Image.DEBUG: - print("Seeking to frame %s, on frame %s, __next %s, location: %s" % - (frame, self.__frame, self.__next, self.fp.tell())) + print( + "Seeking to frame %s, on frame %s, __next %s, location: %s" % + (frame, self.__frame, self.__next, self.fp.tell())) # reset python3 buffered io handle in case fp # was passed to libtiff, invalidating the buffer self.fp.tell() @@ -697,7 +706,7 @@ def _decoder(self, rawmode, layer, tile=None): args = rawmode if 317 in self.tag: # Section 14: Differencing Predictor - self.decoderconfig = (self.tag[PREDICTOR][0],) + self.decoderconfig = (self.tag[PREDICTOR][0], ) if ICCPROFILE in self.tag: self.info['icc_profile'] = self.tag[ICCPROFILE] @@ -723,7 +732,7 @@ def _load_libtiff(self): # (self._compression, (extents tuple), # 0, (rawmode, self._compression, fp)) 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, self.decoderconfig) try: @@ -742,19 +751,19 @@ def _load_libtiff(self): # that returns an IOError if there's no underlying fp. Easier to # dea. with here by reordering. 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()) elif hasattr(self.fp, "fileno"): # we've got a actual file on disk, pass in the fp. 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) # 4 bytes, otherwise the trace might error out n, err = decoder.decode(b"fpfp") else: # we have something else. 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. n, err = decoder.decode(self.fp.read()) @@ -809,11 +818,9 @@ def _setup(self): format = getscalar(SAMPLEFORMAT, 1) # mode: check photometric interpretation and bits per pixel - key = ( - self.tag.prefix, photo, format, fillorder, - self.tag.get(BITSPERSAMPLE, (1,)), - self.tag.get(EXTRASAMPLES, ()) - ) + key = (self.tag.prefix, photo, format, fillorder, + self.tag.get(BITSPERSAMPLE, + (1, )), self.tag.get(EXTRASAMPLES, ())) if Image.DEBUG: print("format key:", key) try: @@ -855,14 +862,11 @@ def _setup(self): offsets = self.tag[STRIPOFFSETS] h = getscalar(ROWSPERSTRIP, ysize) w = self.size[0] - if READ_LIBTIFF or self._compression in ["tiff_ccitt", "group3", - "group4", "tiff_jpeg", - "tiff_adobe_deflate", - "tiff_thunderscan", - "tiff_deflate", - "tiff_sgilog", - "tiff_sgilog24", - "tiff_raw_16"]: + if READ_LIBTIFF or self._compression in [ + "tiff_ccitt", "group3", "group4", "tiff_jpeg", + "tiff_adobe_deflate", "tiff_thunderscan", "tiff_deflate", + "tiff_sgilog", "tiff_sgilog24", "tiff_raw_16" + ]: # if Image.DEBUG: # print "Activating g4 compression for whole file" @@ -899,11 +903,9 @@ def _setup(self): # bits, so stripes of the image are reversed. See # https://github.com/python-pillow/Pillow/issues/279 if fillorder == 2: - key = ( - self.tag.prefix, photo, format, 1, - self.tag.get(BITSPERSAMPLE, (1,)), - self.tag.get(EXTRASAMPLES, ()) - ) + key = (self.tag.prefix, photo, format, 1, + self.tag.get(BITSPERSAMPLE, + (1, )), self.tag.get(EXTRASAMPLES, ())) if Image.DEBUG: print("format key:", key) # this should always work, since all the @@ -920,21 +922,17 @@ def _setup(self): # Offset in the tile tuple is 0, we go from 0,0 to # w,h, and we only do this once -- eds a = (rawmode, self._compression, fp) - self.tile.append( - (self._compression, - (0, 0, w, ysize), - 0, a)) + self.tile.append((self._compression, (0, 0, w, ysize), 0, a)) a = None else: for i in range(len(offsets)): a = self._decoder(rawmode, l, i) - self.tile.append( - (self._compression, - (0, min(y, ysize), w, min(y+h, ysize)), - offsets[i], a)) + self.tile.append((self._compression, + (0, min(y, ysize), w, min(y + h, ysize)), + offsets[i], a)) if Image.DEBUG: - print ("tiles: ", self.tile) + print("tiles: ", self.tile) y = y + h if y >= self.size[1]: x = y = 0 @@ -950,10 +948,8 @@ def _setup(self): a = self._decoder(rawmode, l) # FIXME: this doesn't work if the image size # is not a multiple of the tile size... - self.tile.append( - (self._compression, - (x, y, x+w, y+h), - o, a)) + self.tile.append((self._compression, (x, y, x + w, y + h), o, + a)) x = x + w if x >= self.size[0]: x, y = 0, y + h @@ -981,33 +977,32 @@ def _setup(self): SAVE_INFO = { # mode => rawmode, byteorder, photometrics, # sampleformat, bitspersample, extra - "1": ("1", II, 1, 1, (1,), None), - "L": ("L", II, 1, 1, (8,), None), + "1": ("1", II, 1, 1, (1, ), None), + "L": ("L", II, 1, 1, (8, ), None), "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), - "I": ("I;32S", II, 1, 2, (32,), None), - "I;16": ("I;16", II, 1, 1, (16,), None), - "I;16S": ("I;16S", II, 1, 2, (16,), None), - "F": ("F;32F", II, 1, 3, (32,), None), + "I": ("I;32S", II, 1, 2, (32, ), None), + "I;16": ("I;16", II, 1, 1, (16, ), None), + "I;16S": ("I;16S", II, 1, 2, (16, ), None), + "F": ("F;32F", II, 1, 3, (32, ), None), "RGB": ("RGB", II, 2, 1, (8, 8, 8), None), "RGBX": ("RGBX", II, 2, 1, (8, 8, 8, 8), 0), "RGBA": ("RGBA", II, 2, 1, (8, 8, 8, 8), 2), "CMYK": ("CMYK", II, 5, 1, (8, 8, 8, 8), None), "YCbCr": ("YCbCr", II, 6, 1, (8, 8, 8), None), "LAB": ("LAB", II, 8, 1, (8, 8, 8), None), - - "I;32BS": ("I;32BS", MM, 1, 2, (32,), None), - "I;16B": ("I;16B", MM, 1, 1, (16,), None), - "I;16BS": ("I;16BS", MM, 1, 2, (16,), None), - "F;32BF": ("F;32BF", MM, 1, 3, (32,), None), + "I;32BS": ("I;32BS", MM, 1, 2, (32, ), None), + "I;16B": ("I;16B", MM, 1, 1, (16, ), None), + "I;16BS": ("I;16BS", MM, 1, 2, (16, ), None), + "F;32BF": ("F;32BF", MM, 1, 3, (32, ), None), } def _cvt_res(value): # convert value to TIFF rational number -- (numerator, denominator) if isinstance(value, collections.Sequence): - assert(len(value) % 2 == 0) + assert (len(value) % 2 == 0) return value if isinstance(value, int): return (value, 1) @@ -1025,7 +1020,7 @@ def _save(im, fp, filename): ifd = ImageFileDirectory(prefix) compression = im.encoderinfo.get('compression', im.info.get('compression', - 'raw')) + 'raw')) libtiff = WRITE_LIBTIFF or compression != 'raw' @@ -1069,17 +1064,19 @@ def _save(im, fp, filename): ifd[ICCPROFILE] = im.info["icc_profile"] for key, name, cvt in [ - (IMAGEDESCRIPTION, "description", lambda x: x), - (X_RESOLUTION, "resolution", _cvt_res), - (Y_RESOLUTION, "resolution", _cvt_res), - (X_RESOLUTION, "x_resolution", _cvt_res), - (Y_RESOLUTION, "y_resolution", _cvt_res), - (RESOLUTION_UNIT, "resolution_unit", - lambda x: {"inch": 2, "cm": 3, "centimeter": 3}.get(x, 1)), - (SOFTWARE, "software", lambda x: x), - (DATE_TIME, "date_time", lambda x: x), - (ARTIST, "artist", lambda x: x), - (COPYRIGHT, "copyright", lambda x: x)]: + (IMAGEDESCRIPTION, "description", lambda x: x), + (X_RESOLUTION, "resolution", _cvt_res), + (Y_RESOLUTION, "resolution", _cvt_res), + (X_RESOLUTION, "x_resolution", _cvt_res), + (Y_RESOLUTION, "y_resolution", _cvt_res), ( + RESOLUTION_UNIT, "resolution_unit", + lambda x: {"inch": 2, + "cm": 3, + "centimeter": 3}.get(x, 1) + ), (SOFTWARE, "software", lambda x: x), + (DATE_TIME, "date_time", lambda x: x), (ARTIST, "artist", lambda x: x), + (COPYRIGHT, "copyright", lambda x: x) + ]: name_with_spaces = name.replace("_", " ") if "_" in name and name_with_spaces in im.encoderinfo: 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[Y_RESOLUTION] = _cvt_res(dpi[1]) - if bits != (1,): + if bits != (1, ): ifd[BITSPERSAMPLE] = bits if len(bits) != 1: ifd[SAMPLESPERPIXEL] = len(bits) @@ -1110,7 +1107,7 @@ def _save(im, fp, filename): ifd[COLORMAP] = tuple(i8(v) * 256 for v in lut) # 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[STRIPBYTECOUNTS] = stride * im.size[1] ifd[STRIPOFFSETS] = 0 # this is adjusted by IFD writer @@ -1119,8 +1116,8 @@ def _save(im, fp, filename): if libtiff: if Image.DEBUG: - print ("Saving using libtiff encoder") - print (ifd.items()) + print("Saving using libtiff encoder") + print(ifd.items()) _fp = 0 if hasattr(fp, "fileno"): try: @@ -1144,17 +1141,16 @@ def _save(im, fp, filename): # A tuple of more than one rational tuples # flatten to floats, # 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 if type(v[0]) == tuple and len(v) == 1: # A tuple of one rational tuples # flatten to floats, # 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 - if (type(v) == tuple and - (len(v) > 2 or - (len(v) == 2 and v[1] == 0))): + if (type(v) == tuple and (len(v) > 2 or + (len(v) == 2 and v[1] == 0))): # List of ints? # Avoid divide by zero in next if-clause if type(v[0]) in (int, float): @@ -1164,7 +1160,7 @@ def _save(im, fp, filename): # one rational tuple # flatten to float, # following tiffcp.c->cpTag->TIFF_RATIONAL - atts[k] = float(v[0])/float(v[1]) + atts[k] = float(v[0]) / float(v[1]) continue if type(v) == tuple and len(v) == 1: v = v[0] @@ -1177,7 +1173,7 @@ def _save(im, fp, filename): atts[k] = v if Image.DEBUG: - print (atts) + print(atts) # libtiff always expects the bytes in native order. # 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) # print (im.mode, compression, 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: # undone, change to self.decodermaxblock: - l, s, d = e.encode(16*1024) + l, s, d = e.encode(16 * 1024) if not _fp: fp.write(d) if s: @@ -1203,9 +1199,8 @@ def _save(im, fp, filename): else: offset = ifd.save(fp) - ImageFile._save(im, fp, [ - ("raw", (0, 0)+im.size, offset, (rawmode, stride, 1)) - ]) + ImageFile._save(im, fp, [("raw", (0, 0) + im.size, offset, + (rawmode, stride, 1))]) # -- helper for multi-page save -- if "_debug_multipage" in im.encoderinfo: diff --git a/PIL/TiffTags.py b/PIL/TiffTags.py index d15aa7ebe2f..f76c03909a5 100644 --- a/PIL/TiffTags.py +++ b/PIL/TiffTags.py @@ -21,13 +21,11 @@ # Map tag numbers (or tag number, tag value tuples) to tag names. TAGS = { - 254: "NewSubfileType", 255: "SubfileType", 256: "ImageWidth", 257: "ImageLength", 258: "BitsPerSample", - 259: "Compression", (259, 1): "Uncompressed", (259, 2): "CCITT 1d", @@ -36,7 +34,6 @@ (259, 5): "LZW", (259, 6): "JPEG", (259, 32773): "PackBits", - 262: "PhotometricInterpretation", (262, 0): "WhiteIsZero", (262, 1): "BlackIsZero", @@ -48,13 +45,11 @@ (262, 8): "CieLAB", (262, 32803): "CFA", # TIFF/EP, Adobe DNG (262, 32892): "LinearRaw", # Adobe DNG - 263: "Thresholding", 264: "CellWidth", 265: "CellHeight", 266: "FillOrder", 269: "DocumentName", - 270: "ImageDescription", 271: "Make", 272: "Model", @@ -63,7 +58,6 @@ 277: "SamplesPerPixel", 278: "RowsPerStrip", 279: "StripByteCounts", - 280: "MinSampleValue", 281: "MaxSampleValue", 282: "XResolution", @@ -71,37 +65,31 @@ 284: "PlanarConfiguration", (284, 1): "Contigous", (284, 2): "Separate", - 285: "PageName", 286: "XPosition", 287: "YPosition", 288: "FreeOffsets", 289: "FreeByteCounts", - 290: "GrayResponseUnit", 291: "GrayResponseCurve", 292: "T4Options", 293: "T6Options", 296: "ResolutionUnit", 297: "PageNumber", - 301: "TransferFunction", 305: "Software", 306: "DateTime", - 315: "Artist", 316: "HostComputer", 317: "Predictor", 318: "WhitePoint", 319: "PrimaryChromaticies", - 320: "ColorMap", 321: "HalftoneHints", 322: "TileWidth", 323: "TileLength", 324: "TileOffsets", 325: "TileByteCounts", - 332: "InkSet", 333: "InkNames", 334: "NumberOfInks", @@ -109,14 +97,10 @@ 337: "TargetPrinter", 338: "ExtraSamples", 339: "SampleFormat", - 340: "SMinSampleValue", 341: "SMaxSampleValue", 342: "TransferRange", - - 347: "JPEGTables", - - # obsolete JPEG tags + 347: "JPEGTables", # obsolete JPEG tags 512: "JPEGProc", 513: "JPEGInterchangeFormat", 514: "JPEGInterchangeFormatLength", @@ -126,28 +110,16 @@ 519: "JPEGQTables", 520: "JPEGDCTables", 521: "JPEGACTables", - 529: "YCbCrCoefficients", 530: "YCbCrSubSampling", 531: "YCbCrPositioning", - 532: "ReferenceBlackWhite", - - # XMP + 532: "ReferenceBlackWhite", # XMP 700: "XMP", - - 33432: "Copyright", - - # various extensions (should check specs for "official" names) + 33432: "Copyright", # various extensions (should check specs for "official" names) 33723: "IptcNaaInfo", - 34377: "PhotoshopInfo", - - # Exif IFD - 34665: "ExifIFD", - - # ICC Profile - 34675: "ICCProfile", - - # Additional Exif Info + 34377: "PhotoshopInfo", # Exif IFD + 34665: "ExifIFD", # ICC Profile + 34675: "ICCProfile", # Additional Exif Info 33434: "ExposureTime", 33437: "FNumber", 34850: "ExposureProgram", @@ -218,9 +190,7 @@ 42035: "LensMake", 42036: "LensModel", 42037: "LensSerialNumber", - 42240: "Gamma", - - # MP Info + 42240: "Gamma", # MP Info 45056: "MPFVersion", 45057: "NumberOfImages", 45058: "MPEntry", @@ -239,9 +209,7 @@ 45578: "AxisDistance_Z", 45579: "YawAngle", 45580: "PitchAngle", - 45581: "RollAngle", - - # Adobe DNG + 45581: "RollAngle", # Adobe DNG 50706: "DNGVersion", 50707: "DNGBackwardVersion", 50708: "UniqueCameraModel", @@ -279,9 +247,7 @@ 50738: "AntiAliasStrength", 50740: "DNGPrivateData", 50741: "MakerNoteSafety", - 50780: "BestQualityScale", - - # ImageJ + 50780: "BestQualityScale", # ImageJ 50838: "ImageJMetaDataByteCounts", # private tag registered with Adobe 50839: "ImageJMetaData", # private tag registered with Adobe } @@ -290,7 +256,6 @@ # Map type numbers to type names. TYPES = { - 1: "byte", 2: "ascii", 3: "short", @@ -303,5 +268,4 @@ 10: "signed rational", 11: "float", 12: "double", - } diff --git a/PIL/WalImageFile.py b/PIL/WalImageFile.py index fc2bb30a766..2bd90edb45c 100644 --- a/PIL/WalImageFile.py +++ b/PIL/WalImageFile.py @@ -31,7 +31,6 @@ i32 = _binary.i32le - ## # Load texture from a Quake2 WAL texture file. #
@@ -41,6 +40,7 @@
# @param filename WAL file name, or an opened file handle.
# @return An image instance.
+
def open(filename):
# FIXME: modify to return a WalImageFile instance instead of
# plain Image object ?
@@ -51,7 +51,7 @@ def open(filename):
fp = builtins.open(filename, "rb")
# read header fields
- header = fp.read(32+24+32+12)
+ header = fp.read(32 + 24 + 32 + 12)
size = i32(header, 32), i32(header, 36)
offset = i32(header, 40)
@@ -66,15 +66,14 @@ def open(filename):
# strings are null-terminated
im.info["name"] = header[:32].split(b"\0", 1)[0]
- next_name = header[56:56+32].split(b"\0", 1)[0]
+ next_name = header[56:56 + 32].split(b"\0", 1)[0]
if next_name:
im.info["next_name"] = next_name
return im
-quake2palette = (
- # default palette taken from piffo 0.93 by Hans Häggström
+quake2palette = ( # default palette taken from piffo 0.93 by Hans Häggström
b"\x01\x01\x01\x0b\x0b\x0b\x12\x12\x12\x17\x17\x17\x1b\x1b\x1b\x1e"
b"\x1e\x1e\x22\x22\x22\x26\x26\x26\x29\x29\x29\x2c\x2c\x2c\x2f\x2f"
b"\x2f\x32\x32\x32\x35\x35\x35\x37\x37\x37\x3a\x3a\x3a\x3c\x3c\x3c"
@@ -122,8 +121,7 @@ def open(filename):
b"\x01\x27\x07\x01\x23\x01\x01\x1d\x01\x01\x17\x01\x01\x10\x01\x01"
b"\x3d\x01\x01\x19\x19\x3f\x3f\x01\x01\x01\x01\x3f\x16\x16\x13\x10"
b"\x10\x0f\x0d\x0d\x0b\x3c\x2e\x2a\x36\x27\x20\x30\x21\x18\x29\x1b"
- b"\x10\x3c\x39\x37\x37\x32\x2f\x31\x2c\x28\x2b\x26\x21\x30\x22\x20"
-)
+ b"\x10\x3c\x39\x37\x37\x32\x2f\x31\x2c\x28\x2b\x26\x21\x30\x22\x20")
if __name__ == "__main__":
im = open("../hacks/sample.wal")
diff --git a/PIL/WebPImagePlugin.py b/PIL/WebPImagePlugin.py
index 78a7a53195e..5691b22462c 100644
--- a/PIL/WebPImagePlugin.py
+++ b/PIL/WebPImagePlugin.py
@@ -3,17 +3,13 @@
from io import BytesIO
from PIL import _webp
-
-_VALID_WEBP_MODES = {
- "RGB": True,
- "RGBA": True,
- }
+_VALID_WEBP_MODES = {"RGB": True, "RGBA": True, }
_VP8_MODES_BY_IDENTIFIER = {
b"VP8 ": "RGB",
b"VP8X": "RGBA",
b"VP8L": "RGBA", # lossless
- }
+}
def _accept(prefix):
@@ -57,16 +53,8 @@ def _save(im, fp, filename):
icc_profile = im.encoderinfo.get("icc_profile", "")
exif = im.encoderinfo.get("exif", "")
- data = _webp.WebPEncode(
- im.tobytes(),
- im.size[0],
- im.size[1],
- lossless,
- float(quality),
- im.mode,
- icc_profile,
- exif
- )
+ data = _webp.WebPEncode(im.tobytes(), im.size[0], im.size[1], lossless,
+ float(quality), im.mode, icc_profile, exif)
if data is None:
raise IOError("cannot write file as WEBP (encoder returned None)")
diff --git a/PIL/WmfImagePlugin.py b/PIL/WmfImagePlugin.py
index 6146c15604e..06aaf603e7e 100644
--- a/PIL/WmfImagePlugin.py
+++ b/PIL/WmfImagePlugin.py
@@ -24,21 +24,21 @@
if str != bytes:
long = int
-
##
# Install application-specific WMF image handler.
#
# @param handler Handler object.
+
def register_handler(handler):
global _handler
_handler = handler
+
if hasattr(Image.core, "drawwmf"):
# install default handler (windows only)
class WmfHandler:
-
def open(self, im):
im.mode = "RGB"
self.bbox = im.info["wmf_bbox"]
@@ -47,9 +47,8 @@ def load(self, im):
im.fp.seek(0) # rewind
return Image.frombytes(
"RGB", im.size,
- Image.core.drawwmf(im.fp.read(), im.size, self.bbox),
- "raw", "BGR", (im.size[0]*3 + 3) & -4, -1
- )
+ Image.core.drawwmf(im.fp.read(), im.size, self.bbox), "raw",
+ "BGR", (im.size[0] * 3 + 3) & -4, -1)
register_handler(WmfHandler())
@@ -64,23 +63,22 @@ def short(c, o=0):
v -= 65536
return v
-dword = _binary.i32le
+dword = _binary.i32le
#
# --------------------------------------------------------------------
# Read WMF file
-def _accept(prefix):
- return (
- prefix[:6] == b"\xd7\xcd\xc6\x9a\x00\x00" or
- prefix[:4] == b"\x01\x00\x00\x00"
- )
+def _accept(prefix):
+ return (prefix[:6] == b"\xd7\xcd\xc6\x9a\x00\x00" or
+ prefix[:4] == b"\x01\x00\x00\x00")
##
# Image plugin for Windows metafiles.
+
class WmfStubImageFile(ImageFile.StubImageFile):
format = "WMF"
diff --git a/PIL/XVThumbImagePlugin.py b/PIL/XVThumbImagePlugin.py
index 5cf1386fd88..ec19493a328 100644
--- a/PIL/XVThumbImagePlugin.py
+++ b/PIL/XVThumbImagePlugin.py
@@ -28,12 +28,13 @@
for r in range(8):
for g in range(8):
for b in range(4):
- PALETTE = PALETTE + (o8((r*255)//7)+o8((g*255)//7)+o8((b*255)//3))
-
+ PALETTE = PALETTE + (o8((r * 255) // 7) + o8((g * 255) // 7) + o8(
+ (b * 255) // 3))
##
# Image plugin for XV thumbnail images.
+
class XVThumbImageFile(ImageFile.ImageFile):
format = "XVThumb"
@@ -65,10 +66,8 @@ def _open(self):
self.palette = ImagePalette.raw("RGB", PALETTE)
- self.tile = [
- ("raw", (0, 0)+self.size,
- self.fp.tell(), (self.mode, 0, 1)
- )]
+ self.tile = [("raw", (0, 0) + self.size, self.fp.tell(),
+ (self.mode, 0, 1))]
# --------------------------------------------------------------------
diff --git a/PIL/XbmImagePlugin.py b/PIL/XbmImagePlugin.py
index 604ba15a886..1792ff14cd4 100644
--- a/PIL/XbmImagePlugin.py
+++ b/PIL/XbmImagePlugin.py
@@ -32,17 +32,16 @@
b"#define[ \t]+[^_]*_x_hot[ \t]+(?P