diff --git a/PIL/BdfFontFile.py b/PIL/BdfFontFile.py index 0c1614e0f8f..ade14ec401a 100644 --- a/PIL/BdfFontFile.py +++ b/PIL/BdfFontFile.py @@ -20,7 +20,6 @@ from PIL import Image from PIL import FontFile - # -------------------------------------------------------------------- # parse X Bitmap Distribution Format (BDF) # -------------------------------------------------------------------- @@ -34,11 +33,7 @@ "OT": "Other" } -bdf_spacing = { - "P": "Proportional", - "M": "Monospaced", - "C": "Cell" -} +bdf_spacing = {"P": "Proportional", "M": "Monospaced", "C": "Cell"} def bdf_char(f): @@ -58,7 +53,7 @@ def bdf_char(f): if not s or s[:6] == b"BITMAP": break i = s.find(b" ") - props[s[:i].decode('ascii')] = s[i+1:-1].decode('ascii') + props[s[:i].decode('ascii')] = s[i + 1:-1].decode('ascii') # load bitmap bitmap = [] @@ -72,7 +67,7 @@ def bdf_char(f): [x, y, l, d] = [int(p) for p in props["BBX"].split()] [dx, dy] = [int(p) for p in props["DWIDTH"].split()] - bbox = (dx, dy), (l, -d-y, x+l, -d), (0, 0, x, y) + bbox = (dx, dy), (l, -d - y, x + l, -d), (0, 0, x, y) try: im = Image.frombytes("1", (x, y), bitmap, "hex", "1") @@ -82,12 +77,11 @@ def bdf_char(f): return id, int(props["ENCODING"]), bbox, im - ## # Font file plugin for the X11 BDF format. -class BdfFontFile(FontFile.FontFile): +class BdfFontFile(FontFile.FontFile): def __init__(self, fp): FontFile.FontFile.__init__(self) @@ -104,10 +98,10 @@ def __init__(self, fp): if not s or s[:13] == b"ENDPROPERTIES": break i = s.find(b" ") - props[s[:i].decode('ascii')] = s[i+1:-1].decode('ascii') + props[s[:i].decode('ascii')] = s[i + 1:-1].decode('ascii') if s[:i] in [b"COMMENT", b"COPYRIGHT"]: if s.find(b"LogicalFontDescription") < 0: - comments.append(s[i+1:-1].decode('ascii')) + comments.append(s[i + 1:-1].decode('ascii')) font = props["FONT"].split("-") diff --git a/PIL/BmpImagePlugin.py b/PIL/BmpImagePlugin.py index 30ca10971bc..3e1b7e633b2 100644 --- a/PIL/BmpImagePlugin.py +++ b/PIL/BmpImagePlugin.py @@ -23,14 +23,11 @@ # See the README file for information on usage and redistribution. # - __version__ = "0.7" - from PIL import Image, ImageFile, ImagePalette, _binary import math - i8 = _binary.i8 i16 = _binary.i16le i32 = _binary.i32le @@ -67,7 +64,14 @@ class BmpImageFile(ImageFile.ImageFile): format_description = "Windows Bitmap" format = "BMP" # --------------------------------------------------- BMP Compression values - COMPRESSIONS = {'RAW': 0, 'RLE8': 1, 'RLE4': 2, 'BITFIELDS': 3, 'JPEG': 4, 'PNG': 5} + COMPRESSIONS = { + 'RAW': 0, + 'RLE8': 1, + 'RLE4': 2, + 'BITFIELDS': 3, + 'JPEG': 4, + 'PNG': 5 + } RAW, RLE8, RLE4, BITFIELDS, JPEG, PNG = 0, 1, 2, 3, 4, 5 def _bitmap(self, header=0, offset=0): @@ -76,10 +80,14 @@ def _bitmap(self, header=0, offset=0): if header: seek(header) file_info = dict() - file_info['header_size'] = i32(read(4)) # read bmp header size @offset 14 (this is part of the header size) + file_info['header_size'] = i32( + read(4) + ) # read bmp header size @offset 14 (this is part of the header size) file_info['direction'] = -1 # --------------------- If requested, read header at a specific position - header_data = ImageFile._safe_read(self.fp, file_info['header_size'] - 4) # read the rest of the bmp header, without its size + header_data = ImageFile._safe_read( + self.fp, file_info['header_size'] - 4 + ) # read the rest of the bmp header, without its size # --------------------------------------------------- IBM OS/2 Bitmap v1 # ------ This format has different offsets because of width/height types if file_info['header_size'] == 12: @@ -90,59 +98,87 @@ def _bitmap(self, header=0, offset=0): file_info['compression'] = self.RAW file_info['palette_padding'] = 3 # ---------------------------------------------- Windows Bitmap v2 to v5 - elif file_info['header_size'] in (40, 64, 108, 124): # v3, OS/2 v2, v4, v5 + elif file_info['header_size'] in (40, 64, 108, + 124): # v3, OS/2 v2, v4, v5 if file_info['header_size'] >= 40: # v3 and OS/2 file_info['y_flip'] = i8(header_data[7]) == 0xff file_info['direction'] = 1 if file_info['y_flip'] else -1 file_info['width'] = i32(header_data[0:4]) - file_info['height'] = i32(header_data[4:8]) if not file_info['y_flip'] else 2**32 - i32(header_data[4:8]) + file_info['height'] = i32(header_data[4:8]) if not file_info[ + 'y_flip' + ] else 2 ** 32 - i32(header_data[4:8]) file_info['planes'] = i16(header_data[8:10]) file_info['bits'] = i16(header_data[10:12]) file_info['compression'] = i32(header_data[12:16]) - file_info['data_size'] = i32(header_data[16:20]) # byte size of pixel data - file_info['pixels_per_meter'] = (i32(header_data[20:24]), i32(header_data[24:28])) + file_info['data_size'] = i32(header_data[16:20] + ) # byte size of pixel data + file_info['pixels_per_meter'] = (i32(header_data[20:24]), + i32(header_data[24:28])) file_info['colors'] = i32(header_data[28:32]) file_info['palette_padding'] = 4 - self.info["dpi"] = tuple(map(lambda x: math.ceil(x / 39.3701), file_info['pixels_per_meter'])) + self.info["dpi"] = tuple(map(lambda x: math.ceil(x / 39.3701), + file_info['pixels_per_meter'])) if file_info['compression'] == self.BITFIELDS: if len(header_data) >= 52: - for idx, mask in enumerate(['r_mask', 'g_mask', 'b_mask', 'a_mask']): - file_info[mask] = i32(header_data[36+idx*4:40+idx*4]) + for idx, mask in enumerate(['r_mask', 'g_mask', + 'b_mask', 'a_mask']): + file_info[mask] = i32( + header_data[36 + idx * 4:40 + idx * 4]) else: for mask in ['r_mask', 'g_mask', 'b_mask', 'a_mask']: file_info[mask] = i32(read(4)) - file_info['rgb_mask'] = (file_info['r_mask'], file_info['g_mask'], file_info['b_mask']) - file_info['rgba_mask'] = (file_info['r_mask'], file_info['g_mask'], file_info['b_mask'], file_info['a_mask']) + file_info['rgb_mask'] = (file_info['r_mask'], + file_info['g_mask'], + file_info['b_mask']) + file_info['rgba_mask'] = ( + file_info['r_mask'], file_info['g_mask'], + file_info['b_mask'], file_info['a_mask']) else: - raise IOError("Unsupported BMP header type (%d)" % file_info['header_size']) + raise IOError( + "Unsupported BMP header type (%d)" % file_info['header_size']) # ------------------ Special case : header is reported 40, which # ---------------------- is shorter than real size for bpp >= 16 self.size = file_info['width'], file_info['height'] # -------- If color count was not found in the header, compute from bits - file_info['colors'] = file_info['colors'] if file_info.get('colors', 0) else (1 << file_info['bits']) + file_info['colors'] = file_info['colors'] if file_info.get( + 'colors', 0) else (1 << file_info['bits']) # -------------------------------- Check abnormal values for DOS attacks - if file_info['width'] * file_info['height'] > 2**31: + if file_info['width'] * file_info['height'] > 2 ** 31: raise IOError("Unsupported BMP Size: (%dx%d)" % self.size) # ----------------------- Check bit depth for unusual unsupported values self.mode, raw_mode = BIT2MODE.get(file_info['bits'], (None, None)) if self.mode is None: - raise IOError("Unsupported BMP pixel depth (%d)" % file_info['bits']) + raise IOError( + "Unsupported BMP pixel depth (%d)" % file_info['bits']) # ----------------- Process BMP with Bitfields compression (not palette) if file_info['compression'] == self.BITFIELDS: SUPPORTED = { - 32: [(0xff0000, 0xff00, 0xff, 0x0), (0xff0000, 0xff00, 0xff, 0xff000000), (0x0, 0x0, 0x0, 0x0)], - 24: [(0xff0000, 0xff00, 0xff)], - 16: [(0xf800, 0x7e0, 0x1f), (0x7c00, 0x3e0, 0x1f)]} + 32: [(0xff0000, 0xff00, 0xff, 0x0), + (0xff0000, 0xff00, 0xff, 0xff000000), + (0x0, 0x0, 0x0, 0x0)], + 24: [(0xff0000, 0xff00, 0xff)], + 16: [(0xf800, 0x7e0, 0x1f), (0x7c00, 0x3e0, 0x1f)] + } MASK_MODES = { - (32, (0xff0000, 0xff00, 0xff, 0x0)): "BGRX", (32, (0xff0000, 0xff00, 0xff, 0xff000000)): "BGRA", (32, (0x0, 0x0, 0x0, 0x0)): "BGRA", - (24, (0xff0000, 0xff00, 0xff)): "BGR", - (16, (0xf800, 0x7e0, 0x1f)): "BGR;16", (16, (0x7c00, 0x3e0, 0x1f)): "BGR;15"} + (32, (0xff0000, 0xff00, 0xff, 0x0)): "BGRX", + (32, (0xff0000, 0xff00, 0xff, 0xff000000)): "BGRA", + (32, (0x0, 0x0, 0x0, 0x0)): "BGRA", + (24, (0xff0000, 0xff00, 0xff)): "BGR", + (16, (0xf800, 0x7e0, 0x1f)): "BGR;16", + (16, (0x7c00, 0x3e0, 0x1f)): "BGR;15" + } if file_info['bits'] in SUPPORTED: - if file_info['bits'] == 32 and file_info['rgba_mask'] in SUPPORTED[file_info['bits']]: - raw_mode = MASK_MODES[(file_info['bits'], file_info['rgba_mask'])] - self.mode = "RGBA" if raw_mode in ("BGRA",) else self.mode - elif file_info['bits'] in (24, 16) and file_info['rgb_mask'] in SUPPORTED[file_info['bits']]: - raw_mode = MASK_MODES[(file_info['bits'], file_info['rgb_mask'])] + if file_info['bits'] == 32 and file_info[ + 'rgba_mask' + ] in SUPPORTED[file_info['bits']]: + raw_mode = MASK_MODES[(file_info['bits'], + file_info['rgba_mask'])] + self.mode = "RGBA" if raw_mode in ("BGRA", ) else self.mode + elif file_info['bits'] in ( + 24, 16 + ) and file_info['rgb_mask'] in SUPPORTED[file_info['bits']]: + raw_mode = MASK_MODES[(file_info['bits'], + file_info['rgb_mask'])] else: raise IOError("Unsupported BMP bitfields layout") else: @@ -151,20 +187,23 @@ def _bitmap(self, header=0, offset=0): if file_info['bits'] == 32 and header == 22: # 32-bit .cur offset raw_mode, self.mode = "BGRA", "RGBA" else: - raise IOError("Unsupported BMP compression (%d)" % file_info['compression']) + raise IOError( + "Unsupported BMP compression (%d)" % file_info['compression']) # ---------------- Once the header is processed, process the palette/LUT if self.mode == "P": # Paletted for 1, 4 and 8 bit images # ----------------------------------------------------- 1-bit images if not (0 < file_info['colors'] <= 65536): - raise IOError("Unsupported BMP Palette size (%d)" % file_info['colors']) + raise IOError( + "Unsupported BMP Palette size (%d)" % file_info['colors']) else: padding = file_info['palette_padding'] palette = read(padding * file_info['colors']) greyscale = True - indices = (0, 255) if file_info['colors'] == 2 else list(range(file_info['colors'])) + indices = (0, 255) if file_info['colors'] == 2 else list( + range(file_info['colors'])) # ------------------ Check if greyscale and ignore palette if so for ind, val in enumerate(indices): - rgb = palette[ind*padding:ind*padding + 3] + rgb = palette[ind * padding:ind * padding + 3] if rgb != o8(val) * 3: greyscale = False # -------- If all colors are grey, white or black, ditch palette @@ -173,13 +212,16 @@ def _bitmap(self, header=0, offset=0): raw_mode = self.mode else: self.mode = "P" - self.palette = ImagePalette.raw("BGRX" if padding == 4 else "BGR", palette) + self.palette = ImagePalette.raw("BGRX" if padding == 4 else + "BGR", palette) # ----------------------------- Finally set the tile data for the plugin self.info['compression'] = file_info['compression'] - self.tile = [('raw', (0, 0, file_info['width'], file_info['height']), offset or self.fp.tell(), - (raw_mode, ((file_info['width'] * file_info['bits'] + 31) >> 3) & (~3), file_info['direction']) - )] + self.tile = [('raw', (0, 0, file_info['width'], file_info['height']), + offset or self.fp.tell(), + (raw_mode, + ((file_info['width'] * file_info['bits'] + 31) >> 3) & + (~3), file_info['direction']))] def _open(self): """ Open file, check magic number and read header """ @@ -234,30 +276,30 @@ def _save(im, fp, filename, check=0): # 1 meter == 39.3701 inches ppm = tuple(map(lambda x: int(x * 39.3701), dpi)) - stride = ((im.size[0]*bits+7)//8+3) & (~3) + stride = ((im.size[0] * bits + 7) // 8 + 3) & (~3) header = 40 # or 64 for OS/2 version 2 offset = 14 + header + colors * 4 image = stride * im.size[1] # bitmap header - fp.write(b"BM" + # file type (magic) - o32(offset+image) + # file size - o32(0) + # reserved - o32(offset)) # image data offset + fp.write(b"BM" + # file type (magic) + o32(offset + image) + # file size + o32(0) + # reserved + o32(offset)) # image data offset # bitmap info header - fp.write(o32(header) + # info header size - o32(im.size[0]) + # width - o32(im.size[1]) + # height - o16(1) + # planes - o16(bits) + # depth - o32(0) + # compression (0=uncompressed) - o32(image) + # size of bitmap + fp.write(o32(header) + # info header size + o32(im.size[0]) + # width + o32(im.size[1]) + # height + o16(1) + # planes + o16(bits) + # depth + o32(0) + # compression (0=uncompressed) + o32(image) + # size of bitmap o32(ppm[0]) + o32(ppm[1]) + # resolution - o32(colors) + # colors used - o32(colors)) # colors important + o32(colors) + # colors used + o32(colors)) # colors important - fp.write(b"\0" * (header - 40)) # padding (for OS/2 format) + fp.write(b"\0" * (header - 40)) # padding (for OS/2 format) if im.mode == "1": for i in (0, 255): @@ -268,8 +310,8 @@ def _save(im, fp, filename, check=0): elif im.mode == "P": fp.write(im.im.getpalette("RGB", "BGRX")) - ImageFile._save(im, fp, [("raw", (0, 0)+im.size, 0, - (rawmode, stride, -1))]) + ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, + (rawmode, stride, -1))]) # # -------------------------------------------------------------------- diff --git a/PIL/BufrStubImagePlugin.py b/PIL/BufrStubImagePlugin.py index 45ee54776c1..6aca8ee7f60 100644 --- a/PIL/BufrStubImagePlugin.py +++ b/PIL/BufrStubImagePlugin.py @@ -13,20 +13,20 @@ _handler = None - ## # Install application-specific BUFR image handler. # # @param handler Handler object. + def register_handler(handler): global _handler _handler = handler - # -------------------------------------------------------------------- # Image adapter + def _accept(prefix): return prefix[:4] == b"BUFR" or prefix[:4] == b"ZCZC" @@ -62,7 +62,6 @@ def _save(im, fp, filename): raise IOError("BUFR save handler not installed") _handler.save(im, fp, filename) - # -------------------------------------------------------------------- # Registry diff --git a/PIL/CurImagePlugin.py b/PIL/CurImagePlugin.py index 0178957ee30..55b745c70e5 100644 --- a/PIL/CurImagePlugin.py +++ b/PIL/CurImagePlugin.py @@ -16,12 +16,10 @@ # See the README file for information on usage and redistribution. # - __version__ = "0.1" from PIL import Image, BmpImagePlugin, _binary - # # -------------------------------------------------------------------- @@ -33,10 +31,10 @@ def _accept(prefix): return prefix[:4] == b"\0\0\2\0" - ## # Image plugin for Windows Cursor files. + class CurImageFile(BmpImagePlugin.BmpImageFile): format = "CUR" @@ -68,17 +66,16 @@ def _open(self): # print "bytes", i32(s[8:]) # print "offset", i32(s[12:]) - # load as bitmap + # load as bitmap self._bitmap(i32(m[12:]) + offset) # patch up the bitmap height - self.size = self.size[0], self.size[1]//2 + self.size = self.size[0], self.size[1] // 2 d, e, o, a = self.tile[0] - self.tile[0] = d, (0, 0)+self.size, o, a + self.tile[0] = d, (0, 0) + self.size, o, a return - # # -------------------------------------------------------------------- diff --git a/PIL/DcxImagePlugin.py b/PIL/DcxImagePlugin.py index 0940b3935ec..711d09f54f4 100644 --- a/PIL/DcxImagePlugin.py +++ b/PIL/DcxImagePlugin.py @@ -35,10 +35,10 @@ def _accept(prefix): return i32(prefix) == MAGIC - ## # Image plugin for the Intel DCX format. + class DcxImageFile(PcxImageFile): format = "DCX" diff --git a/PIL/EpsImagePlugin.py b/PIL/EpsImagePlugin.py index 83024b63f15..4ee055fcbed 100644 --- a/PIL/EpsImagePlugin.py +++ b/PIL/EpsImagePlugin.py @@ -81,8 +81,8 @@ def Ghostscript(tile, size, fp, scale=1): # orig_bbox = bbox size = (size[0] * scale, size[1] * scale) # resolution is dependent on bbox and size - res = (float((72.0 * size[0]) / (bbox[2]-bbox[0])), - float((72.0 * size[1]) / (bbox[3]-bbox[1]))) + res = (float((72.0 * size[0]) / (bbox[2] - bbox[0])), + float((72.0 * size[1]) / (bbox[3] - bbox[1]))) # print("Ghostscript", scale, size, orig_size, bbox, orig_bbox, res) import os @@ -112,25 +112,24 @@ def Ghostscript(tile, size, fp, scale=1): fp.seek(0) lengthfile = fsize while lengthfile > 0: - s = fp.read(min(lengthfile, 100*1024)) + s = fp.read(min(lengthfile, 100 * 1024)) if not s: break lengthfile -= len(s) f.write(s) # Build ghostscript command - command = ["gs", - "-q", # quiet mode - "-g%dx%d" % size, # set output geometry (pixels) - "-r%fx%f" % res, # set input DPI (dots per inch) - "-dNOPAUSE -dSAFER", # don't pause between pages, - # safe mode - "-sDEVICE=ppmraw", # ppm driver + command = ["gs", "-q", # quiet mode + "-g%dx%d" % size, # set output geometry (pixels) + "-r%fx%f" % res, # set input DPI (dots per inch) + "-dNOPAUSE -dSAFER", # don't pause between pages, + # safe mode + "-sDEVICE=ppmraw", # ppm driver "-sOutputFile=%s" % outfile, # output file "-c", "%d %d translate" % (-bbox[0], -bbox[1]), - # adjust for image origin - "-f", infile, # input file - ] + # adjust for image origin + "-f", infile, # input file + ] if gs_windows_binary is not None: if not gs_windows_binary: @@ -139,7 +138,8 @@ def Ghostscript(tile, size, fp, scale=1): # push data through ghostscript try: - gs = subprocess.Popen(command, stdin=subprocess.PIPE, + gs = subprocess.Popen(command, + stdin=subprocess.PIPE, stdout=subprocess.PIPE) gs.stdin.close() status = gs.wait() @@ -161,6 +161,7 @@ class PSFile: """ Wrapper for bytesio object that treats either CR or LF as end of line. """ + def __init__(self, fp): self.fp = fp self.char = None @@ -343,10 +344,10 @@ def load_seek(self, *args, **kwargs): # use our custom load method by defining this method. pass - # # -------------------------------------------------------------------- + def _save(im, fp, filename, eps=1): """EPS Writer for the Python Imaging Library.""" @@ -405,7 +406,7 @@ def close(self): fp.write(operator[2] + "\n") fp.flush() - ImageFile._save(im, base_fp, [("eps", (0, 0)+im.size, 0, None)]) + ImageFile._save(im, base_fp, [("eps", (0, 0) + im.size, 0, None)]) fp.write("\n%%%%EndBinary\n") fp.write("grestore end\n") diff --git a/PIL/ExifTags.py b/PIL/ExifTags.py index 52e145f6210..57cfd51d64d 100644 --- a/PIL/ExifTags.py +++ b/PIL/ExifTags.py @@ -18,7 +18,6 @@ # Maps EXIF tags to tag names. TAGS = { - # possibly incomplete 0x00fe: "NewSubfileType", 0x00ff: "SubfileType", @@ -151,7 +150,6 @@ 0xa434: "LensModel", 0xa435: "LensSerialNumber", 0xa500: "Gamma", - } ## diff --git a/PIL/FitsStubImagePlugin.py b/PIL/FitsStubImagePlugin.py index 0b851ae592e..c3bdc86f44d 100644 --- a/PIL/FitsStubImagePlugin.py +++ b/PIL/FitsStubImagePlugin.py @@ -18,6 +18,7 @@ # # @param handler Handler object. + def register_handler(handler): global _handler _handler = handler @@ -25,9 +26,11 @@ def register_handler(handler): # -------------------------------------------------------------------- # Image adapter + def _accept(prefix): return prefix[:6] == b"SIMPLE" + class FITSStubImageFile(ImageFile.StubImageFile): format = "FITS" @@ -62,7 +65,6 @@ def _save(im, fp, filename): raise IOError("FITS save handler not installed") _handler.save(im, fp, filename) - # -------------------------------------------------------------------- # Registry diff --git a/PIL/FliImagePlugin.py b/PIL/FliImagePlugin.py index 4ecaccdc419..5e73f1586d0 100644 --- a/PIL/FliImagePlugin.py +++ b/PIL/FliImagePlugin.py @@ -15,7 +15,6 @@ # See the README file for information on usage and redistribution. # - __version__ = "0.2" from PIL import Image, ImageFile, ImagePalette, _binary @@ -25,18 +24,18 @@ i32 = _binary.i32le o8 = _binary.o8 - # # decoder + def _accept(prefix): return i16(prefix[4:6]) in [0xAF11, 0xAF12] - ## # Image plugin for the FLI/FLC animation format. Use the seek # method to load individual frames. + class FliImageFile(ImageFile.ImageFile): format = "FLI" @@ -47,8 +46,8 @@ def _open(self): # HEAD s = self.fp.read(128) magic = i16(s[4:6]) - if not (magic in [0xAF11, 0xAF12] and - i16(s[14:16]) in [0, 3] and # flags + if not (magic in [0xAF11, 0xAF12] and i16(s[14:16]) in [0, 3] and + # flags s[20:22] == b"\x00\x00"): # reserved raise SyntaxError("not an FLI/FLC file") @@ -82,7 +81,7 @@ def _open(self): elif i16(s[4:6]) == 4: self._palette(palette, 0) - palette = [o8(r)+o8(g)+o8(b) for (r, g, b) in palette] + palette = [o8(r) + o8(g) + o8(b) for (r, g, b) in palette] self.palette = ImagePalette.raw("RGB", b"".join(palette)) # set things up to decode first frame @@ -104,8 +103,8 @@ def _palette(self, palette, shift): s = self.fp.read(n * 3) for n in range(0, len(s), 3): r = i8(s[n]) << shift - g = i8(s[n+1]) << shift - b = i8(s[n+2]) << shift + g = i8(s[n + 1]) << shift + b = i8(s[n + 2]) << shift palette[i] = (r, g, b) i += 1 @@ -126,7 +125,7 @@ def seek(self, frame): framesize = i32(s) self.decodermaxblock = framesize - self.tile = [("fli", (0, 0)+self.size, self.__offset, None)] + self.tile = [("fli", (0, 0) + self.size, self.__offset, None)] self.__offset = self.__offset + framesize diff --git a/PIL/FontFile.py b/PIL/FontFile.py index 26ddff0acde..b8bbce3a426 100644 --- a/PIL/FontFile.py +++ b/PIL/FontFile.py @@ -32,10 +32,10 @@ def puti16(fp, values): v += 65536 fp.write(_binary.o16be(v)) - ## # Base class for raster font file handlers. + class FontFile: bitmap = None diff --git a/PIL/FpxImagePlugin.py b/PIL/FpxImagePlugin.py index ed0c20c4e79..1d2ee2ddb65 100644 --- a/PIL/FpxImagePlugin.py +++ b/PIL/FpxImagePlugin.py @@ -15,20 +15,17 @@ # See the README file for information on usage and redistribution. # - __version__ = "0.1" - from PIL import Image, ImageFile from PIL.OleFileIO import i8, i32, MAGIC, OleFileIO - # we map from colour field tuples to (mode, rawmode) descriptors MODES = { # opacity (0x00007ffe): ("A", "L"), # monochrome - (0x00010000,): ("L", "L"), + (0x00010000, ): ("L", "L"), (0x00018000, 0x00017ffe): ("RGBA", "LA"), # photo YCC (0x00020000, 0x00020001, 0x00020002): ("RGB", "YCC;P"), @@ -38,17 +35,17 @@ (0x00038000, 0x00038001, 0x00038002, 0x00037ffe): ("RGBA", "RGBA"), } - # # -------------------------------------------------------------------- + def _accept(prefix): return prefix[:8] == MAGIC - ## # Image plugin for the FlashPix images. + class FpxImageFile(ImageFile.ImageFile): format = "FPX" @@ -73,10 +70,8 @@ def _open_index(self, index=1): # # get the Image Contents Property Set - prop = self.ole.getproperties([ - "Data Object Store %06d" % index, - "\005Image Contents" - ]) + prop = self.ole.getproperties(["Data Object Store %06d" % index, + "\005Image Contents"]) # size (highest resolution) @@ -102,7 +97,7 @@ def _open_index(self, index=1): colors = [] for i in range(i32(s, 4)): # note: for now, we ignore the "uncalibrated" flag - colors.append(i32(s, 8+i*4) & 0x7fffffff) + colors.append(i32(s, 8 + i * 4) & 0x7fffffff) self.mode, self.rawmode = MODES[tuple(colors)] @@ -121,11 +116,8 @@ def _open_subimage(self, index=1, subimage=0): # # setup tile descriptors for a given subimage - stream = [ - "Data Object Store %06d" % index, - "Resolution %04d" % subimage, - "Subimage 0000 Header" - ] + stream = ["Data Object Store %06d" % index, + "Resolution %04d" % subimage, "Subimage 0000 Header"] fp = self.ole.openstream(stream) @@ -158,17 +150,17 @@ def _open_subimage(self, index=1, subimage=0): for i in range(0, len(s), length): - compression = i32(s, i+8) + compression = i32(s, i + 8) if compression == 0: - self.tile.append(("raw", (x, y, x+xtile, y+ytile), - i32(s, i) + 28, (self.rawmode))) + self.tile.append(("raw", (x, y, x + xtile, y + ytile), + i32(s, i) + 28, (self.rawmode))) elif compression == 1: # FIXME: the fill decoder is not implemented - self.tile.append(("fill", (x, y, x+xtile, y+ytile), - i32(s, i) + 28, (self.rawmode, s[12:16]))) + self.tile.append(("fill", (x, y, x + xtile, y + ytile), + i32(s, i) + 28, (self.rawmode, s[12:16]))) elif compression == 2: @@ -190,8 +182,8 @@ def _open_subimage(self, index=1, subimage=0): # The image is stored as defined by rawmode jpegmode = rawmode - self.tile.append(("jpeg", (x, y, x+xtile, y+ytile), - i32(s, i) + 28, (rawmode, jpegmode))) + self.tile.append(("jpeg", (x, y, x + xtile, y + ytile), + i32(s, i) + 28, (rawmode, jpegmode))) # FIXME: jpeg tables are tile dependent; the prefix # data must be placed in the tile descriptor itself! @@ -214,8 +206,8 @@ def _open_subimage(self, index=1, subimage=0): def load(self): if not self.fp: - self.fp = self.ole.openstream(self.stream[:2] + - ["Subimage 0000 Data"]) + self.fp = self.ole.openstream( + self.stream[:2] + ["Subimage 0000 Data"]) ImageFile.ImageFile.load(self) diff --git a/PIL/GbrImagePlugin.py b/PIL/GbrImagePlugin.py index 0e686326cb6..a33d1a0bd5f 100644 --- a/PIL/GbrImagePlugin.py +++ b/PIL/GbrImagePlugin.py @@ -21,10 +21,10 @@ def _accept(prefix): return i32(prefix) >= 20 and i32(prefix[4:8]) == 1 - ## # Image plugin for the GIMP brush format. + class GbrImageFile(ImageFile.ImageFile): format = "GBR" diff --git a/PIL/GdImageFile.py b/PIL/GdImageFile.py index 080153a9f1c..d707573fe8a 100644 --- a/PIL/GdImageFile.py +++ b/PIL/GdImageFile.py @@ -13,7 +13,6 @@ # See the README file for information on usage and redistribution. # - # NOTE: This format cannot be automatically recognized, so the # class is not registered for use with Image.open(). To open a # gd file, use the GdImageFile.open() function instead. @@ -22,7 +21,6 @@ # implementation is provided for convenience and demonstrational # purposes only. - __version__ = "0.1" from PIL import ImageFile, ImagePalette, _binary @@ -36,13 +34,13 @@ i16 = _binary.i16be - ## # Image plugin for the GD uncompressed format. Note that this format # is not supported by the standard Image.open function. To use # this plugin, you have to import the GdImageFile module and # use the GdImageFile.open function. + class GdImageFile(ImageFile.ImageFile): format = "GD" @@ -63,8 +61,7 @@ def _open(self): self.palette = ImagePalette.raw("RGB", s[7:]) - self.tile = [("raw", (0, 0)+self.size, 775, ("L", 0, -1))] - + self.tile = [("raw", (0, 0) + self.size, 775, ("L", 0, -1))] ## # Load texture from a GD image file. @@ -75,6 +72,7 @@ def _open(self): # @return An image instance. # @exception IOError If the image could not be read. + def open(fp, mode="r"): if mode != "r": diff --git a/PIL/GifImagePlugin.py b/PIL/GifImagePlugin.py index 8db42e8e8cf..bb42c0c61e2 100644 --- a/PIL/GifImagePlugin.py +++ b/PIL/GifImagePlugin.py @@ -28,7 +28,6 @@ __version__ = "0.9" - # -------------------------------------------------------------------- # Helpers @@ -37,18 +36,18 @@ o8 = _binary.o8 o16 = _binary.o16le - # -------------------------------------------------------------------- # Identify/read GIF files + def _accept(prefix): return prefix[:6] in [b"GIF87a", b"GIF89a"] - ## # Image plugin for GIF images. This plugin supports both GIF87 and # GIF89 images. + class GifImageFile(ImageFile.ImageFile): format = "GIF" @@ -80,7 +79,7 @@ def _open(self): # check if palette contains colour indices p = self.fp.read(3 << bits) for i in range(0, len(p), 3): - if not (i//3 == i8(p[i]) == i8(p[i+1]) == i8(p[i+2])): + if not (i // 3 == i8(p[i]) == i8(p[i + 1]) == i8(p[i + 2])): p = ImagePalette.raw("RGB", p) self.global_palette = self.palette = p break @@ -189,10 +188,8 @@ def seek(self, frame): # image data bits = i8(self.fp.read(1)) self.__offset = self.fp.tell() - self.tile = [("gif", - (x0, y0, x1, y1), - self.__offset, - (bits, interlace))] + self.tile = [("gif", (x0, y0, x1, y1), self.__offset, + (bits, interlace))] break else: @@ -251,11 +248,7 @@ def load_end(self): except ImportError: _imaging_gif = None -RAWMODE = { - "1": "L", - "L": "L", - "P": "P", -} +RAWMODE = {"1": "L", "L": "L", "P": "P", } def _save(im, fp, filename): @@ -326,24 +319,21 @@ def _save(im, fp, filename): # transparency extension block if transparent_color_exists: - fp.write(b"!" + - o8(249) + # extension intro - o8(4) + # length - o8(1) + # transparency info present - o16(0) + # duration - o8(transparency) + # transparency index + fp.write(b"!" + o8(249) + # extension intro + o8(4) + # length + o8(1) + # transparency info present + o16(0) + # duration + o8(transparency) + # transparency index o8(0)) # local image header - fp.write(b"," + - o16(0) + o16(0) + # bounding box - o16(im.size[0]) + # size - o16(im.size[1]) + - o8(flags) + # flags - o8(8)) # bits + fp.write(b"," + o16(0) + o16(0) + # bounding box + o16(im.size[0]) + # size + o16(im.size[1]) + o8(flags) + # flags + o8(8)) # bits im_out.encoderconfig = (8, interlace) - ImageFile._save(im_out, fp, [("gif", (0, 0)+im.size, 0, + ImageFile._save(im_out, fp, [("gif", (0, 0) + im.size, 0, RAWMODE[im_out.mode])]) fp.write(b"\0") # end of image data @@ -382,7 +372,9 @@ def _save_netpbm(im, fp, filename): stderr = tempfile.TemporaryFile() quant_proc = Popen(quant_cmd, stdout=PIPE, stderr=stderr) stderr = tempfile.TemporaryFile() - togif_proc = Popen(togif_cmd, stdin=quant_proc.stdout, stdout=f, + togif_proc = Popen(togif_cmd, + stdin=quant_proc.stdout, + stdout=f, stderr=stderr) # Allow ppmquant to receive SIGPIPE if ppmtogif exits @@ -401,10 +393,10 @@ def _save_netpbm(im, fp, filename): except: pass - # -------------------------------------------------------------------- # GIF utilities + def getheader(im, palette=None, info=None): """Return a list of strings representing a GIF header""" @@ -412,11 +404,10 @@ def getheader(im, palette=None, info=None): # Header Block # http://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp - header = [ - b"GIF87a" + # signature + version - o16(im.size[0]) + # canvas width - o16(im.size[1]) # canvas height - ] + header = [b"GIF87a" + # signature + version + o16(im.size[0]) + # canvas width + o16(im.size[1]) # canvas height + ] if im.mode == "P": if palette and isinstance(palette, bytes): @@ -427,7 +418,7 @@ def getheader(im, palette=None, info=None): if palette and isinstance(palette, bytes): source_palette = palette[:768] else: - source_palette = bytearray([i//3 for i in range(768)]) + source_palette = bytearray([i // 3 for i in range(768)]) used_palette_colors = palette_bytes = None @@ -449,7 +440,8 @@ def getheader(im, palette=None, info=None): i = 0 # pick only the used colors from the palette for oldPosition in used_palette_colors: - palette_bytes += source_palette[oldPosition*3:oldPosition*3+3] + palette_bytes += source_palette[oldPosition * 3:oldPosition * 3 + + 3] new_positions[oldPosition] = i i += 1 @@ -471,7 +463,7 @@ def getheader(im, palette=None, info=None): # Logical Screen Descriptor # calculate the palette size for the header import math - color_table_size = int(math.ceil(math.log(len(palette_bytes)//3, 2)))-1 + color_table_size = int(math.ceil(math.log(len(palette_bytes) // 3, 2))) - 1 if color_table_size < 0: color_table_size = 0 # size of global color table + global color table flag @@ -482,7 +474,7 @@ def getheader(im, palette=None, info=None): # add the missing amount of bytes # the palette has to be 2< 0: palette_bytes += o8(0) * 3 * actual_target_size_diff @@ -510,15 +502,13 @@ def write(self, data): im.encoderinfo = params # local image header - fp.write(b"," + - o16(offset[0]) + # offset - o16(offset[1]) + - o16(im.size[0]) + # size - o16(im.size[1]) + - o8(0) + # flags - o8(8)) # bits + fp.write(b"," + o16(offset[0]) + # offset + o16(offset[1]) + o16(im.size[0]) + # size + o16(im.size[1]) + o8(0) + # flags + o8(8)) # bits - ImageFile._save(im, fp, [("gif", (0, 0)+im.size, 0, RAWMODE[im.mode])]) + ImageFile._save(im, fp, [("gif", + (0, 0) + im.size, 0, RAWMODE[im.mode])]) fp.write(b"\0") # end of image data @@ -527,7 +517,6 @@ def write(self, data): return fp.data - # -------------------------------------------------------------------- # Registry @@ -539,5 +528,4 @@ def write(self, data): # # Uncomment the following line if you wish to use NETPBM/PBMPLUS # instead of the built-in "uncompressed" GIF encoder - # Image.register_save(GifImageFile.format, _save_netpbm) diff --git a/PIL/GimpGradientFile.py b/PIL/GimpGradientFile.py index 696f425f197..2fe8945a316 100644 --- a/PIL/GimpGradientFile.py +++ b/PIL/GimpGradientFile.py @@ -55,6 +55,7 @@ def sphere_increasing(middle, pos): def sphere_decreasing(middle, pos): return 1.0 - sqrt(1.0 - linear(middle, pos) ** 2) + SEGMENTS = [linear, curved, sine, sphere_increasing, sphere_decreasing] @@ -71,7 +72,7 @@ def getpalette(self, entries=256): for i in range(entries): - x = i / float(entries-1) + x = i / float(entries - 1) while x1 < x: ix += 1 @@ -95,12 +96,11 @@ def getpalette(self, entries=256): return b"".join(palette), "RGBA" - ## # File handler for GIMP's gradient format. -class GimpGradientFile(GradientFile): +class GimpGradientFile(GradientFile): def __init__(self, fp): if fp.readline()[:13] != b"GIMP Gradient": diff --git a/PIL/GimpPaletteFile.py b/PIL/GimpPaletteFile.py index a066c80ccbd..3892e5792dd 100644 --- a/PIL/GimpPaletteFile.py +++ b/PIL/GimpPaletteFile.py @@ -17,17 +17,17 @@ import re from PIL._binary import o8 - ## # File handler for GIMP's palette format. + class GimpPaletteFile: rawmode = "RGB" def __init__(self, fp): - self.palette = [o8(i)*3 for i in range(256)] + self.palette = [o8(i) * 3 for i in range(256)] if fp.readline()[:12] != b"GIMP Palette": raise SyntaxError("not a GIMP palette file") diff --git a/PIL/GribStubImagePlugin.py b/PIL/GribStubImagePlugin.py index 8ffad810059..626e4eefba5 100644 --- a/PIL/GribStubImagePlugin.py +++ b/PIL/GribStubImagePlugin.py @@ -13,20 +13,20 @@ _handler = None - ## # Install application-specific GRIB image handler. # # @param handler Handler object. + def register_handler(handler): global _handler _handler = handler - # -------------------------------------------------------------------- # Image adapter + def _accept(prefix): return prefix[0:4] == b"GRIB" and prefix[7] == b'\x01' @@ -62,7 +62,6 @@ def _save(im, fp, filename): raise IOError("GRIB save handler not installed") _handler.save(im, fp, filename) - # -------------------------------------------------------------------- # Registry diff --git a/PIL/Hdf5StubImagePlugin.py b/PIL/Hdf5StubImagePlugin.py index f7945be7ee5..df01f2d1e93 100644 --- a/PIL/Hdf5StubImagePlugin.py +++ b/PIL/Hdf5StubImagePlugin.py @@ -13,20 +13,20 @@ _handler = None - ## # Install application-specific HDF5 image handler. # # @param handler Handler object. + def register_handler(handler): global _handler _handler = handler - # -------------------------------------------------------------------- # Image adapter + def _accept(prefix): return prefix[:8] == b"\x89HDF\r\n\x1a\n" @@ -62,7 +62,6 @@ def _save(im, fp, filename): raise IOError("HDF5 save handler not installed") _handler.save(im, fp, filename) - # -------------------------------------------------------------------- # Registry diff --git a/PIL/IcnsImagePlugin.py b/PIL/IcnsImagePlugin.py index e88b84985dd..88e013607c4 100644 --- a/PIL/IcnsImagePlugin.py +++ b/PIL/IcnsImagePlugin.py @@ -79,11 +79,9 @@ def read_32(fobj, start_length, size): break if bytesleft != 0: raise SyntaxError( - "Error reading channel [%r left]" % bytesleft - ) - band = Image.frombuffer( - "L", pixel_size, b"".join(data), "raw", "L", 0, 1 - ) + "Error reading channel [%r left]" % bytesleft) + band = Image.frombuffer("L", pixel_size, b"".join(data), "raw", + "L", 0, 1) im.im.putband(band.im, band_ix) return {"RGB": im} @@ -94,9 +92,8 @@ def read_mk(fobj, start_length, size): fobj.seek(start) pixel_size = (size[0] * size[2], size[1] * size[2]) sizesq = pixel_size[0] * pixel_size[1] - band = Image.frombuffer( - "L", pixel_size, fobj.read(sizesq), "raw", "L", 0, 1 - ) + band = Image.frombuffer("L", pixel_size, fobj.read(sizesq), "raw", "L", 0, + 1) return {"A": band} @@ -129,49 +126,25 @@ def read_png_or_jpeg2000(fobj, start_length, size): class IcnsFile: SIZES = { - (512, 512, 2): [ - (b'ic10', read_png_or_jpeg2000), - ], - (512, 512, 1): [ - (b'ic09', read_png_or_jpeg2000), - ], - (256, 256, 2): [ - (b'ic14', read_png_or_jpeg2000), - ], - (256, 256, 1): [ - (b'ic08', read_png_or_jpeg2000), - ], - (128, 128, 2): [ - (b'ic13', read_png_or_jpeg2000), - ], - (128, 128, 1): [ - (b'ic07', read_png_or_jpeg2000), - (b'it32', read_32t), - (b't8mk', read_mk), - ], - (64, 64, 1): [ - (b'icp6', read_png_or_jpeg2000), - ], - (32, 32, 2): [ - (b'ic12', read_png_or_jpeg2000), - ], - (48, 48, 1): [ - (b'ih32', read_32), - (b'h8mk', read_mk), - ], - (32, 32, 1): [ - (b'icp5', read_png_or_jpeg2000), - (b'il32', read_32), - (b'l8mk', read_mk), - ], - (16, 16, 2): [ - (b'ic11', read_png_or_jpeg2000), - ], - (16, 16, 1): [ - (b'icp4', read_png_or_jpeg2000), - (b'is32', read_32), - (b's8mk', read_mk), - ], + (512, 512, 2): [(b'ic10', read_png_or_jpeg2000), ], + (512, 512, 1): [(b'ic09', read_png_or_jpeg2000), ], + (256, 256, 2): [(b'ic14', read_png_or_jpeg2000), ], + (256, 256, 1): [(b'ic08', read_png_or_jpeg2000), ], + (128, 128, 2): [(b'ic13', read_png_or_jpeg2000), ], + (128, 128, 1): [(b'ic07', read_png_or_jpeg2000), + (b'it32', read_32t), + (b't8mk', read_mk), ], + (64, 64, 1): [(b'icp6', read_png_or_jpeg2000), ], + (32, 32, 2): [(b'ic12', read_png_or_jpeg2000), ], + (48, 48, 1): [(b'ih32', read_32), + (b'h8mk', read_mk), ], + (32, 32, 1): [(b'icp5', read_png_or_jpeg2000), + (b'il32', read_32), + (b'l8mk', read_mk), ], + (16, 16, 2): [(b'ic11', read_png_or_jpeg2000), ], + (16, 16, 1): [(b'icp4', read_png_or_jpeg2000), + (b'is32', read_32), + (b's8mk', read_mk), ], } def __init__(self, fobj): @@ -241,10 +214,10 @@ def getimage(self, size=None): pass return im - ## # Image plugin for Mac OS icons. + class IcnsImageFile(ImageFile.ImageFile): """ PIL read-only image support for Mac OS .icns files. @@ -267,7 +240,7 @@ def _open(self): self.best_size[1] * self.best_size[2]) self.info['sizes'] = self.icns.itersizes() # Just use this to see if it's loaded or not yet. - self.tile = ('',) + self.tile = ('', ) def load(self): if len(self.size) == 3: @@ -293,6 +266,7 @@ def load(self): self.tile = () self.load_end() + Image.register_open("ICNS", IcnsImageFile, lambda x: x[:4] == b'icns') Image.register_extension("ICNS", '.icns') diff --git a/PIL/IcoImagePlugin.py b/PIL/IcoImagePlugin.py index b4817db2719..2ab1dca10f6 100644 --- a/PIL/IcoImagePlugin.py +++ b/PIL/IcoImagePlugin.py @@ -21,7 +21,6 @@ # * http://en.wikipedia.org/wiki/ICO_(file_format) # * http://msdn.microsoft.com/en-us/library/ms997538.aspx - __version__ = "0.1" import struct @@ -46,11 +45,12 @@ def _save(im, fp, filename): [(16, 16), (24, 24), (32, 32), (48, 48), (64, 64), (128, 128), (255, 255)]) width, height = im.size - filter(lambda x: False if (x[0] > width or x[1] > height or - x[0] > 255 or x[1] > 255) else True, sizes) + filter(lambda x: False + if (x[0] > width or x[1] > height or x[0] > 255 or x[1] > 255) else + True, sizes) sizes = sorted(sizes, key=lambda x: x[0]) fp.write(struct.pack("H", len(sizes))) # idCount(2) - offset = fp.tell() + len(sizes)*16 + offset = fp.tell() + len(sizes) * 16 for size in sizes: width, height = size fp.write(struct.pack("B", width)) # bWidth(1) @@ -119,14 +119,15 @@ def __init__(self, buf): # See Wikipedia notes about color depth. # We need this just to differ images with equal sizes - icon_header['color_depth'] = (icon_header['bpp'] or - (icon_header['nb_color'] != 0 and - ceil(log(icon_header['nb_color'], - 2))) or 256) + icon_header['color_depth'] = ( + icon_header['bpp'] or + (icon_header['nb_color'] != 0 and + ceil(log(icon_header['nb_color'], 2))) or 256) icon_header['dim'] = (icon_header['width'], icon_header['height']) - icon_header['square'] = (icon_header['width'] * - icon_header['height']) + icon_header['square'] = ( + icon_header['width'] * icon_header['height'] + ) self.entry.append(icon_header) @@ -195,11 +196,11 @@ def frame(self, idx): # convert to an 8bpp grayscale image mask = Image.frombuffer( - 'L', # 8bpp - im.size, # (w, h) - alpha_bytes, # source chars - 'raw', # raw decoder - ('L', 0, -1) # 8bpp inverted, unpadded, reversed + 'L', # 8bpp + im.size, # (w, h) + alpha_bytes, # source chars + 'raw', # raw decoder + ('L', 0, -1) # 8bpp inverted, unpadded, reversed ) else: # get AND image from end of bitmap @@ -220,25 +221,25 @@ def frame(self, idx): # convert raw data to image mask = Image.frombuffer( - '1', # 1 bpp - im.size, # (w, h) - maskData, # source chars - 'raw', # raw decoder - ('1;I', int(w/8), -1) # 1bpp inverted, padded, reversed + '1', # 1 bpp + im.size, # (w, h) + maskData, # source chars + 'raw', # raw decoder + ('1;I', int(w / 8), -1) # 1bpp inverted, padded, reversed ) # now we have two images, im is XOR image and mask is AND image - # apply mask image as alpha channel + # apply mask image as alpha channel im = im.convert('RGBA') im.putalpha(mask) return im - ## # Image plugin for Windows Icon files. + class IcoImageFile(ImageFile.ImageFile): """ PIL read-only image support for Microsoft Windows .ico files. diff --git a/PIL/ImImagePlugin.py b/PIL/ImImagePlugin.py index 4266f831512..994a22ba4a6 100644 --- a/PIL/ImImagePlugin.py +++ b/PIL/ImImagePlugin.py @@ -25,14 +25,12 @@ # See the README file for information on usage and redistribution. # - __version__ = "0.7" import re from PIL import Image, ImageFile, ImagePalette from PIL._binary import i8 - # -------------------------------------------------------------------- # Standard tags @@ -46,8 +44,17 @@ SIZE = "Image size (x*y)" MODE = "Image type" -TAGS = {COMMENT: 0, DATE: 0, EQUIPMENT: 0, FRAMES: 0, LUT: 0, NAME: 0, - SCALE: 0, SIZE: 0, MODE: 0} +TAGS = { + COMMENT: 0, + DATE: 0, + EQUIPMENT: 0, + FRAMES: 0, + LUT: 0, + NAME: 0, + SCALE: 0, + SIZE: 0, + MODE: 0 +} OPEN = { # ifunc93/p3cfunc formats @@ -88,7 +95,6 @@ for i in range(2, 33): OPEN["L*%s image" % i] = ("F", "F;%s" % i) - # -------------------------------------------------------------------- # Read IM directory @@ -101,10 +107,10 @@ def number(s): except ValueError: return float(s) - ## # Image plugin for the IFUNC IM file format. + class ImImageFile(ImageFile.ImageFile): format = "IM" @@ -188,8 +194,8 @@ def _open(self): else: - raise SyntaxError("Syntax error in IM header: " + - s.decode('ascii', 'replace')) + raise SyntaxError( + "Syntax error in IM header: " + s.decode('ascii', 'replace')) if not n: raise SyntaxError("Not an IM file") @@ -210,7 +216,7 @@ def _open(self): greyscale = 1 # greyscale palette linear = 1 # linear greyscale palette for i in range(256): - if palette[i] == palette[i+256] == palette[i+512]: + if palette[i] == palette[i + 256] == palette[i + 512]: if i8(palette[i]) != i: linear = 0 else: @@ -242,8 +248,8 @@ def _open(self): # use bit decoder (if necessary) bits = int(self.rawmode[2:]) if bits not in [8, 16, 32]: - self.tile = [("bit", (0, 0)+self.size, offs, - (bits, 8, 3, 0, -1))] + self.tile = [("bit", (0, 0) + self.size, offs, + (bits, 8, 3, 0, -1))] return except ValueError: pass @@ -252,13 +258,15 @@ def _open(self): # Old LabEye/3PC files. Would be very surprised if anyone # ever stumbled upon such a file ;-) size = self.size[0] * self.size[1] - self.tile = [("raw", (0, 0)+self.size, offs, ("G", 0, -1)), - ("raw", (0, 0)+self.size, offs+size, ("R", 0, -1)), - ("raw", (0, 0)+self.size, offs+2*size, ("B", 0, -1))] + self.tile = [("raw", (0, 0) + self.size, offs, ("G", 0, -1)), + ("raw", (0, 0) + self.size, offs + size, + ("R", 0, -1)), ("raw", + (0, 0) + self.size, offs + 2 * size, + ("B", 0, -1))] else: # LabEye/IFUNC files - self.tile = [("raw", (0, 0)+self.size, offs, - (self.rawmode, 0, -1))] + self.tile = [("raw", (0, 0) + self.size, offs, + (self.rawmode, 0, -1))] def seek(self, frame): @@ -280,7 +288,7 @@ def seek(self, frame): self.fp = self.__fp - self.tile = [("raw", (0, 0)+self.size, offs, (self.rawmode, 0, -1))] + self.tile = [("raw", (0, 0) + self.size, offs, (self.rawmode, 0, -1))] def tell(self): @@ -292,21 +300,12 @@ def tell(self): SAVE = { # mode: (im type, raw mode) - "1": ("0 1", "1"), - "L": ("Greyscale", "L"), - "LA": ("LA", "LA;L"), - "P": ("Greyscale", "P"), - "PA": ("LA", "PA;L"), - "I": ("L 32S", "I;32S"), - "I;16": ("L 16", "I;16"), - "I;16L": ("L 16L", "I;16L"), - "I;16B": ("L 16B", "I;16B"), - "F": ("L 32F", "F;32F"), - "RGB": ("RGB", "RGB;L"), - "RGBA": ("RGBA", "RGBA;L"), - "RGBX": ("RGBX", "RGBX;L"), - "CMYK": ("CMYK", "CMYK;L"), - "YCbCr": ("YCC", "YCbCr;L") + "1": ("0 1", "1"), "L": ("Greyscale", "L"), "LA": ("LA", "LA;L"), "P": ( + "Greyscale", "P"), "PA": ("LA", "PA;L"), "I": ("L 32S", "I;32S" + ), "I;16": ("L 16", "I;16"), "I;16L": ("L 16L", "I;16L"), "I;16B": ( + "L 16B", "I;16B"), "F": ("L 32F", "F;32F"), "RGB": ("RGB", "RGB;L" + ), "RGBA": ("RGBA", "RGBA;L"), "RGBX": ("RGBX", "RGBX;L"), "CMYK": ( + "CMYK", "CMYK;L"), "YCbCr": ("YCC", "YCbCr;L") } @@ -332,10 +331,10 @@ def _save(im, fp, filename, check=0): fp.write(("File size (no of images): %d\r\n" % frames).encode('ascii')) if im.mode == "P": fp.write(b"Lut: 1\r\n") - fp.write(b"\000" * (511-fp.tell()) + b"\032") + fp.write(b"\000" * (511 - fp.tell()) + b"\032") if im.mode == "P": fp.write(im.im.getpalette("RGB", "RGB;L")) # 768 bytes - ImageFile._save(im, fp, [("raw", (0, 0)+im.size, 0, (rawmode, 0, -1))]) + ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, -1))]) # # -------------------------------------------------------------------- diff --git a/PIL/Image.py b/PIL/Image.py index 58944f891cd..46027ba33ce 100644 --- a/PIL/Image.py +++ b/PIL/Image.py @@ -40,7 +40,6 @@ class _imaging_not_installed: def __getattr__(self, id): raise ImportError("The _imaging C module is not installed") - # Limit to around a quarter gigabyte for a 24 bit (3 bpp) image MAX_IMAGE_PIXELS = int(1024 * 1024 * 1024 / 4 / 3) @@ -72,25 +71,20 @@ def __getattr__(self, id): # The _imaging C module is present, but not compiled for # the right version (windows only). Print a warning, if # possible. - warnings.warn( - "The _imaging extension was built for another version " - "of Python.", - RuntimeWarning - ) + warnings.warn("The _imaging extension was built for another version " + "of Python.", RuntimeWarning) elif str(v).startswith("The _imaging extension"): warnings.warn(str(v), RuntimeWarning) elif "Symbol not found: _PyUnicodeUCS2_FromString" in str(v): warnings.warn( "The _imaging extension was built for Python with UCS2 support; " "recompile PIL or build Python --without-wide-unicode. ", - RuntimeWarning - ) + RuntimeWarning) elif "Symbol not found: _PyUnicodeUCS4_FromString" in str(v): warnings.warn( "The _imaging extension was built for Python with UCS4 support; " "recompile PIL or build Python --with-wide-unicode. ", - RuntimeWarning - ) + RuntimeWarning) # Fail here anyway. Don't let people run with a mostly broken Pillow. # see docs/porting-pil-to-pillow.rst raise @@ -195,7 +189,6 @@ def isImageType(t): RLE = core.RLE FIXED = core.FIXED - # -------------------------------------------------------------------- # Registries @@ -211,25 +204,22 @@ def isImageType(t): _MODEINFO = { # NOTE: this table will be removed in future versions. use # getmode* functions or ImageMode descriptors instead. - # official modes - "1": ("L", "L", ("1",)), - "L": ("L", "L", ("L",)), - "I": ("L", "I", ("I",)), - "F": ("L", "F", ("F",)), - "P": ("RGB", "L", ("P",)), - "RGB": ("RGB", "L", ("R", "G", "B")), - "RGBX": ("RGB", "L", ("R", "G", "B", "X")), - "RGBA": ("RGB", "L", ("R", "G", "B", "A")), - "CMYK": ("RGB", "L", ("C", "M", "Y", "K")), - "YCbCr": ("RGB", "L", ("Y", "Cb", "Cr")), - "LAB": ("RGB", "L", ("L", "A", "B")), - "HSV": ("RGB", "L", ("H", "S", "V")), - + "1": ("L", "L", ("1", )), "L": ("L", "L", ("L", )), "I": ("L", "I", ("I", ) + ), "F": ("L", "F", + ("F", )), "P": ("RGB", "L", + ("P", )), "RGB": ("RGB", "L", ("R", "G", "B") + ), "RGBX": ("RGB", "L", + ("R", "G", "B", "X")), "RGBA": ("RGB", "L", + ("R", "G", "B", "A") + ), "CMYK": ("RGB", "L", + ("C", "M", "Y", "K")), "YCbCr": ("RGB", "L", + ("Y", "Cb", "Cr") + ), "LAB": ("RGB", "L", ("L", "A", "B")), "HSV": ("RGB", "L", + ("H", "S", "V")), # Experimental modes include I;16, I;16L, I;16B, RGBa, BGR;15, and # BGR;24. Use these modes only if you know exactly what you're # doing... - } if sys.byteorder == 'little': @@ -272,7 +262,7 @@ def _conv_type_shape(im): if extra is None: return shape, typ else: - return shape+(extra,), typ + return shape + (extra, ), typ MODES = sorted(_MODEINFO.keys()) @@ -386,7 +376,7 @@ def init(): for plugin in _plugins: try: if DEBUG: - print ("Importing %s" % plugin) + print("Importing %s" % plugin) __import__("PIL.%s" % plugin, globals(), locals(), []) except ImportError: if DEBUG: @@ -397,17 +387,17 @@ def init(): _initialized = 2 return 1 - # -------------------------------------------------------------------- # Codec factories (used by tobytes/frombytes and ImageFile.load) + def _getdecoder(mode, decoder_name, args, extra=()): # tweak arguments if args is None: args = () elif not isinstance(args, tuple): - args = (args,) + args = (args, ) try: # get decoder @@ -424,7 +414,7 @@ def _getencoder(mode, encoder_name, args, extra=()): if args is None: args = () elif not isinstance(args, tuple): - args = (args,) + args = (args, ) try: # get encoder @@ -434,10 +424,10 @@ def _getencoder(mode, encoder_name, args, extra=()): except AttributeError: raise IOError("encoder %s not available" % encoder_name) - # -------------------------------------------------------------------- # Simple expression analyzer + def coerce_e(value): return value if isinstance(value, _E) else _E(value) @@ -467,16 +457,16 @@ def _getscaleoffset(expr): try: ((a, b, c), d, e) = data # full syntax if (a is stub and b == "__mul__" and isinstance(c, numbers.Number) and - d == "__add__" and isinstance(e, numbers.Number)): + d == "__add__" and isinstance(e, numbers.Number)): return c, e except TypeError: pass raise ValueError("illegal expression") - # -------------------------------------------------------------------- # Implementation wrapper + class Image: """ This class represents an image object. To create @@ -545,7 +535,7 @@ def close(self): self.fp.close() except Exception as msg: if DEBUG: - print ("Error closing: %s" % msg) + print("Error closing: %s" % msg) # Instead of simply setting to None, we're setting up a # deferred error that will better explain that the core image @@ -562,7 +552,7 @@ def _dump(self, file=None, format=None): import tempfile suffix = '' if format: - suffix = '.'+format + suffix = '.' + format if not file: f, file = tempfile.mkstemp(suffix) os.close(f) @@ -594,10 +584,8 @@ def __ne__(self, other): def __repr__(self): return "<%s.%s image mode=%s size=%dx%d at 0x%X>" % ( - self.__class__.__module__, self.__class__.__name__, - self.mode, self.size[0], self.size[1], - id(self) - ) + self.__class__.__module__, self.__class__.__name__, self.mode, + self.size[0], self.size[1], id(self)) def _repr_png_(self): """ iPython display hook support @@ -621,12 +609,8 @@ def __getattr__(self, name): raise AttributeError(name) def __getstate__(self): - return [ - self.info, - self.mode, - self.size, - self.getpalette(), - self.tobytes()] + return [self.info, self.mode, self.size, self.getpalette(), + self.tobytes()] def __setstate__(self, state): Image.__init__(self) @@ -685,8 +669,7 @@ def tostring(self, *args, **kw): warnings.warn( 'tostring() is deprecated. Please call tobytes() instead.', DeprecationWarning, - stacklevel=2, - ) + stacklevel=2, ) return self.tobytes(*args, **kw) def tobitmap(self, name="image"): @@ -704,11 +687,11 @@ def tobitmap(self, name="image"): if self.mode != "1": raise ValueError("not a bitmap") data = self.tobytes("xbm") - return b"".join([ - ("#define %s_width %d\n" % (name, self.size[0])).encode('ascii'), - ("#define %s_height %d\n" % (name, self.size[1])).encode('ascii'), - ("static char %s_bits[] = {\n" % name).encode('ascii'), data, b"};" - ]) + return b"".join( + [("#define %s_width %d\n" % (name, self.size[0])).encode('ascii'), + ("#define %s_height %d\n" % (name, self.size[1])).encode('ascii'), + ("static char %s_bits[] = {\n" % name).encode('ascii'), data, + b"};"]) def frombytes(self, data, decoder_name="raw", *args): """ @@ -791,8 +774,12 @@ def verify(self): """ pass - def convert(self, mode=None, matrix=None, dither=None, - palette=WEB, colors=256): + def convert(self, + mode=None, + matrix=None, + dither=None, + palette=WEB, + colors=256): """ Returns a converted copy of this image. For the "P" mode, this method translates pixels through the palette. If mode is @@ -893,11 +880,10 @@ def convert(self, mode=None, matrix=None, dither=None, if isinstance(t, bytes): self.im.putpalettealphas(t) elif isinstance(t, int): - self.im.putpalettealpha(t,0) + self.im.putpalettealpha(t, 0) else: - raise ValueError("Transparency for P mode should" + - " be bytes or int") - + raise ValueError( + "Transparency for P mode should" + " be bytes or int") if mode == "P" and palette == ADAPTIVE: im = self.im.quantize(colors) @@ -907,16 +893,16 @@ def convert(self, mode=None, matrix=None, dither=None, if delete_trns: # This could possibly happen if we requantize to fewer colors. # The transparency would be totally off in that case. - del(new.info['transparency']) + del (new.info['transparency']) if trns is not None: try: new.info['transparency'] = new.palette.getcolor(trns) except: # if we can't make a transparent color, don't leave the old # transparency hanging around to mess us up. - del(new.info['transparency']) - warnings.warn("Couldn't allocate palette entry " + - "for transparency") + del (new.info['transparency']) + warnings.warn( + "Couldn't allocate palette entry " + "for transparency") return new # colorspace conversion @@ -936,15 +922,15 @@ def convert(self, mode=None, matrix=None, dither=None, new_im = self._new(im) if delete_trns: # crash fail if we leave a bytes transparency in an rgb/l mode. - del(new_im.info['transparency']) + del (new_im.info['transparency']) if trns is not None: if new_im.mode == 'P': try: new_im.info['transparency'] = new_im.palette.getcolor(trns) except: - del(new_im.info['transparency']) - warnings.warn("Couldn't allocate palette entry " + - "for transparency") + del (new_im.info['transparency']) + warnings.warn( + "Couldn't allocate palette entry " + "for transparency") else: new_im.info['transparency'] = trns return new_im @@ -984,8 +970,7 @@ def quantize(self, colors=256, method=None, kmeans=0, palette=None): raise ValueError("bad mode for palette image") if self.mode != "RGB" and self.mode != "L": raise ValueError( - "only RGB or L mode images can be quantized to a palette" - ) + "only RGB or L mode images can be quantized to a palette") im = self.im.convert("P", 1, palette.im) return self._makeself(im) @@ -1261,8 +1246,8 @@ def offset(self, xoffset, yoffset=None): if warnings: warnings.warn( "'offset' is deprecated; use 'ImageChops.offset' instead", - DeprecationWarning, stacklevel=2 - ) + DeprecationWarning, + stacklevel=2) from PIL import ImageChops return ImageChops.offset(self, xoffset, yoffset) @@ -1324,9 +1309,8 @@ def paste(self, im, box=None, mask=None): else: # FIXME: use self.size here? raise ValueError( - "cannot determine region size; use 4-item box" - ) - box = box + (box[0]+size[0], box[1]+size[1]) + "cannot determine region size; use 4-item box") + box = box + (box[0] + size[0], box[1] + size[1]) if isStringType(im): from PIL import ImageColor @@ -1546,7 +1530,7 @@ def resize(self, size, resample=NEAREST): self.load() - size=tuple(size) + size = tuple(size) if self.size == size: return self._new(self.im) @@ -1582,14 +1566,12 @@ def rotate(self, angle, resample=NEAREST, expand=0): if expand: import math angle = -angle * math.pi / 180 - matrix = [ - math.cos(angle), math.sin(angle), 0.0, - -math.sin(angle), math.cos(angle), 0.0 - ] + matrix = [math.cos(angle), math.sin(angle), 0.0, -math.sin(angle), + math.cos(angle), 0.0] def transform(x, y, matrix=matrix): (a, b, c, d, e, f) = matrix - return a*x + b*y + c, d*x + e*y + f + return a * x + b * y + c, d * x + e * y + f # calculate output size w, h = self.size @@ -1837,8 +1819,8 @@ def transform(self, size, method, data=None, resample=NEAREST, fill=1): """ if self.mode == 'RGBA': - return self.convert('RGBa').transform( - size, method, data, resample, fill).convert('RGBA') + return self.convert('RGBa').transform(size, method, data, resample, + fill).convert('RGBA') if isinstance(method, ImageTransformHandler): return method.transform(size, self, resample=resample, fill=fill) @@ -1854,33 +1836,32 @@ def transform(self, size, method, data=None, resample=NEAREST, fill=1): for box, quad in data: im.__transformer(box, self, QUAD, quad, resample, fill) else: - im.__transformer((0, 0)+size, self, method, data, resample, fill) + im.__transformer((0, 0) + size, self, method, data, resample, fill) return im def __transformer(self, box, image, method, data, - resample=NEAREST, fill=1): + resample=NEAREST, + fill=1): # FIXME: this should be turned into a lazy operation (?) - w = box[2]-box[0] - h = box[3]-box[1] + w = box[2] - box[0] + h = box[3] - box[1] if method == AFFINE: # change argument order to match implementation - data = (data[2], data[0], data[1], - data[5], data[3], data[4]) + data = (data[2], data[0], data[1], data[5], data[3], data[4]) elif method == EXTENT: # convert extent to an affine transform x0, y0, x1, y1 = data xs = float(x1 - x0) / w ys = float(y1 - y0) / h method = AFFINE - data = (x0 + xs/2, xs, 0, y0 + ys/2, 0, ys) + data = (x0 + xs / 2, xs, 0, y0 + ys / 2, 0, ys) elif method == PERSPECTIVE: # change argument order to match implementation - data = (data[2], data[0], data[1], - data[5], data[3], data[4], + data = (data[2], data[0], data[1], data[5], data[3], data[4], data[6], data[7]) elif method == QUAD: # quadrilateral warp. data specifies the four corners @@ -1892,10 +1873,10 @@ def __transformer(self, box, image, method, data, x0, y0 = nw As = 1.0 / w At = 1.0 / h - data = (x0, (ne[0]-x0)*As, (sw[0]-x0)*At, - (se[0]-sw[0]-ne[0]+x0)*As*At, - y0, (ne[1]-y0)*As, (sw[1]-y0)*At, - (se[1]-sw[1]-ne[1]+y0)*As*At) + data = (x0, (ne[0] - x0) * As, (sw[0] - x0) * At, + (se[0] - sw[0] - ne[0] + x0) * As * At, y0, + (ne[1] - y0) * As, (sw[1] - y0) * At, + (se[1] - sw[1] - ne[1] + y0) * As * At) else: raise ValueError("unknown transformation method") @@ -1935,12 +1916,11 @@ def effect_spread(self, distance): im = self.im.effect_spread(distance) return self._new(im) - # -------------------------------------------------------------------- # Lazy operations -class _ImageCrop(Image): +class _ImageCrop(Image): def __init__(self, im, box): Image.__init__(self) @@ -1952,7 +1932,7 @@ def __init__(self, im, box): y1 = y0 self.mode = im.mode - self.size = x1-x0, y1-y0 + self.size = x1 - x0, y1 - y0 self.__crop = x0, y0, x1, y1 @@ -1971,9 +1951,9 @@ def load(self): # FIXME: future versions should optimize crop/paste # sequences! + # -------------------------------------------------------------------- + # Abstract handlers. -# -------------------------------------------------------------------- -# Abstract handlers. class ImagePointHandler: # used as a mixin by point transforms (for use with im.point) @@ -1984,13 +1964,13 @@ class ImageTransformHandler: # used as a mixin by geometry transforms (for use with im.transform) pass - # -------------------------------------------------------------------- # Factories # # Debugging + def _wedge(): "Create greyscale wedge (for debugging only)" @@ -2070,8 +2050,7 @@ def fromstring(*args, **kw): warnings.warn( 'fromstring() is deprecated. Please call frombytes() instead.', DeprecationWarning, - stacklevel=2 - ) + stacklevel=2) return frombytes(*args, **kw) @@ -2121,14 +2100,13 @@ def frombuffer(mode, size, data, decoder_name="raw", *args): "the frombuffer defaults may change in a future release; " "for portability, change the call to read:\n" " frombuffer(mode, size, data, 'raw', mode, 0, 1)", - RuntimeWarning, stacklevel=2 - ) + RuntimeWarning, + stacklevel=2) args = mode, 0, -1 # may change to (mode, 0, 1) post-1.1.6 if args[0] in _MAPMODES: im = new(mode, (1, 1)) im = im._new( - core.map_buffer(data, size, decoder_name, None, 0, args) - ) + core.map_buffer(data, size, decoder_name, None, 0, args)) im.readonly = 1 return im @@ -2184,6 +2162,7 @@ def fromarray(obj, mode=None): return frombuffer(mode, size, obj, "raw", rawmode, 0, 1) + _fromarray_typemap = { # (shape, typestr) => mode, rawmode # first two members of shape are set to one @@ -2200,7 +2179,7 @@ def fromarray(obj, mode=None): ((1, 1), ">f8"): ("F", "F;64BF"), ((1, 1, 3), "|u1"): ("RGB", "RGB"), ((1, 1, 4), "|u1"): ("RGBA", "RGBA"), - } +} # shortcuts _fromarray_typemap[((1, 1), _ENDIAN + "i4")] = ("I", "I") @@ -2214,11 +2193,9 @@ def _decompression_bomb_check(size): pixels = size[0] * size[1] if pixels > MAX_IMAGE_PIXELS: - warnings.warn( - "Image size (%d pixels) exceeds limit of %d pixels, " - "could be decompression bomb DOS attack." % - (pixels, MAX_IMAGE_PIXELS), - DecompressionBombWarning) + warnings.warn("Image size (%d pixels) exceeds limit of %d pixels, " + "could be decompression bomb DOS attack." % + (pixels, MAX_IMAGE_PIXELS), DecompressionBombWarning) def open(fp, mode="r"): @@ -2286,13 +2263,13 @@ def open(fp, mode="r"): # traceback.print_exc() pass - raise IOError("cannot identify image file %r" - % (filename if filename else fp)) - + raise IOError("cannot identify image file %r" % (filename + if filename else fp)) # # Image processing. + def alpha_composite(im1, im2): """ Alpha composite im2 over im1. @@ -2389,10 +2366,10 @@ def merge(mode, bands): im.putband(bands[i].im, i) return bands[0]._new(im) - # -------------------------------------------------------------------- # Plugin registry + def register_open(id, factory, accept=None): """ Register an image file plugin. This function should not be used @@ -2440,10 +2417,10 @@ def register_extension(id, extension): """ EXTENSION[extension.lower()] = id.upper() - # -------------------------------------------------------------------- # Simple display support. User code may override this. + def _show(image, **options): # override me, as necessary _showxv(image, **options) @@ -2453,10 +2430,10 @@ def _showxv(image, title=None, **options): from PIL import ImageShow ImageShow.show(image, title, **options) - # -------------------------------------------------------------------- # Effects + def effect_mandelbrot(size, extent, quality): """ Generate a Mandelbrot set covering the given extent. diff --git a/PIL/ImageCms.py b/PIL/ImageCms.py index ed219f7ba00..bc0c56762b7 100644 --- a/PIL/ImageCms.py +++ b/PIL/ImageCms.py @@ -139,7 +139,6 @@ if isinstance(flag, int): _MAX_FLAG = _MAX_FLAG | flag - # --------------------------------------------------------------------. # Experimental PIL-level API # --------------------------------------------------------------------. @@ -147,8 +146,8 @@ ## # Profile. -class ImageCmsProfile: +class ImageCmsProfile: def __init__(self, profile): """ :param profile: Either a string representing a filename, @@ -193,22 +192,18 @@ class ImageCmsTransform(Image.ImagePointHandler): # Will return the output profile in the output.info['icc_profile']. def __init__(self, input, output, input_mode, output_mode, - intent=INTENT_PERCEPTUAL, proof=None, - proof_intent=INTENT_ABSOLUTE_COLORIMETRIC, flags=0): + intent=INTENT_PERCEPTUAL, + proof=None, + proof_intent=INTENT_ABSOLUTE_COLORIMETRIC, + flags=0): if proof is None: - self.transform = core.buildTransform( - input.profile, output.profile, - input_mode, output_mode, - intent, - flags - ) + self.transform = core.buildTransform(input.profile, output.profile, + input_mode, output_mode, + intent, flags) else: self.transform = core.buildProofTransform( - input.profile, output.profile, proof.profile, - input_mode, output_mode, - intent, proof_intent, - flags - ) + input.profile, output.profile, proof.profile, input_mode, + output_mode, intent, proof_intent, flags) # Note: inputMode and outputMode are for pyCMS compatibility only self.input_mode = self.inputMode = input_mode self.output_mode = self.outputMode = output_mode @@ -256,21 +251,22 @@ def get_display_profile(handle=None): profile = get() return ImageCmsProfile(profile) - # --------------------------------------------------------------------. # pyCMS compatible layer # --------------------------------------------------------------------. -class PyCMSError(Exception): +class PyCMSError(Exception): """ (pyCMS) Exception class. This is used for all errors in the pyCMS API. """ pass -def profileToProfile( - im, inputProfile, outputProfile, renderingIntent=INTENT_PERCEPTUAL, - outputMode=None, inPlace=0, flags=0): +def profileToProfile(im, inputProfile, outputProfile, + renderingIntent=INTENT_PERCEPTUAL, + outputMode=None, + inPlace=0, + flags=0): """ (pyCMS) Applies an ICC transformation to a given image, mapping from inputProfile to outputProfile. @@ -337,10 +333,9 @@ def profileToProfile( inputProfile = ImageCmsProfile(inputProfile) if not isinstance(outputProfile, ImageCmsProfile): outputProfile = ImageCmsProfile(outputProfile) - transform = ImageCmsTransform( - inputProfile, outputProfile, im.mode, outputMode, - renderingIntent, flags=flags - ) + transform = ImageCmsTransform(inputProfile, outputProfile, im.mode, + outputMode, renderingIntent, + flags=flags) if inPlace: transform.apply_in_place(im) imOut = None @@ -374,9 +369,9 @@ def getOpenProfile(profileFilename): raise PyCMSError(v) -def buildTransform( - inputProfile, outputProfile, inMode, outMode, - renderingIntent=INTENT_PERCEPTUAL, flags=0): +def buildTransform(inputProfile, outputProfile, inMode, outMode, + renderingIntent=INTENT_PERCEPTUAL, + flags=0): """ (pyCMS) Builds an ICC transform mapping from the inputProfile to the outputProfile. Use applyTransform to apply the transform to a given @@ -444,18 +439,18 @@ def buildTransform( inputProfile = ImageCmsProfile(inputProfile) if not isinstance(outputProfile, ImageCmsProfile): outputProfile = ImageCmsProfile(outputProfile) - return ImageCmsTransform( - inputProfile, outputProfile, inMode, outMode, - renderingIntent, flags=flags) + return ImageCmsTransform(inputProfile, outputProfile, inMode, outMode, + renderingIntent, + flags=flags) except (IOError, TypeError, ValueError) as v: raise PyCMSError(v) -def buildProofTransform( - inputProfile, outputProfile, proofProfile, inMode, outMode, - renderingIntent=INTENT_PERCEPTUAL, - proofRenderingIntent=INTENT_ABSOLUTE_COLORIMETRIC, - flags=FLAGS["SOFTPROOFING"]): +def buildProofTransform(inputProfile, outputProfile, proofProfile, inMode, + outMode, + renderingIntent=INTENT_PERCEPTUAL, + proofRenderingIntent=INTENT_ABSOLUTE_COLORIMETRIC, + flags=FLAGS["SOFTPROOFING"]): """ (pyCMS) Builds an ICC transform mapping from the inputProfile to the outputProfile, but tries to simulate the result that would be @@ -544,12 +539,13 @@ def buildProofTransform( outputProfile = ImageCmsProfile(outputProfile) if not isinstance(proofProfile, ImageCmsProfile): proofProfile = ImageCmsProfile(proofProfile) - return ImageCmsTransform( - inputProfile, outputProfile, inMode, outMode, renderingIntent, - proofProfile, proofRenderingIntent, flags) + return ImageCmsTransform(inputProfile, outputProfile, inMode, outMode, + renderingIntent, proofProfile, + proofRenderingIntent, flags) except (IOError, TypeError, ValueError) as v: raise PyCMSError(v) + buildTransformFromOpenProfiles = buildTransform buildProofTransformFromOpenProfiles = buildProofTransform @@ -635,16 +631,15 @@ def createProfile(colorSpace, colorTemp=-1): if colorSpace not in ["LAB", "XYZ", "sRGB"]: raise PyCMSError( - "Color space not supported for on-the-fly profile creation (%s)" - % colorSpace) + "Color space not supported for on-the-fly profile creation (%s)" % + colorSpace) if colorSpace == "LAB": try: colorTemp = float(colorTemp) except: raise PyCMSError( - "Color temperature must be numeric, \"%s\" not valid" - % colorTemp) + "Color temperature must be numeric, \"%s\" not valid" % colorTemp) try: return core.createProfile(colorSpace, colorTemp) @@ -944,10 +939,8 @@ def versions(): """ import sys - return ( - VERSION, core.littlecms_version, - sys.version.split()[0], Image.VERSION - ) + return (VERSION, core.littlecms_version, sys.version.split()[0], + Image.VERSION) # -------------------------------------------------------------------- @@ -960,7 +953,7 @@ def versions(): for f in dir(ImageCms): doc = None try: - exec("doc = %s.__doc__" % (f)) + exec ("doc = %s.__doc__" % (f)) if "pyCMS" in doc: # so we don't get the __doc__ string for imported modules print("=" * 80) diff --git a/PIL/ImageColor.py b/PIL/ImageColor.py index fc95e6d194f..376bc59f576 100644 --- a/PIL/ImageColor.py +++ b/PIL/ImageColor.py @@ -48,54 +48,31 @@ def getrgb(color): # check for known string formats m = re.match("#\w\w\w$", color) if m: - return ( - int(color[1]*2, 16), - int(color[2]*2, 16), - int(color[3]*2, 16) - ) + return (int(color[1] * 2, 16), int(color[2] * 2, 16), + int(color[3] * 2, 16)) m = re.match("#\w\w\w\w\w\w$", color) if m: - return ( - int(color[1:3], 16), - int(color[3:5], 16), - int(color[5:7], 16) - ) + return (int(color[1:3], 16), int(color[3:5], 16), int(color[5:7], 16)) m = re.match("rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$", color) if m: - return ( - int(m.group(1)), - int(m.group(2)), - int(m.group(3)) - ) + return (int(m.group(1)), int(m.group(2)), int(m.group(3))) m = re.match("rgb\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)$", color) if m: - return ( - int((int(m.group(1)) * 255) / 100.0 + 0.5), - int((int(m.group(2)) * 255) / 100.0 + 0.5), - int((int(m.group(3)) * 255) / 100.0 + 0.5) - ) + return (int((int(m.group(1)) * 255) / 100.0 + 0.5), + int((int(m.group(2)) * 255) / 100.0 + 0.5), + int((int(m.group(3)) * 255) / 100.0 + 0.5)) m = re.match("hsl\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)$", color) if m: from colorsys import hls_to_rgb - rgb = hls_to_rgb( - float(m.group(1)) / 360.0, - float(m.group(3)) / 100.0, - float(m.group(2)) / 100.0, - ) - return ( - int(rgb[0] * 255 + 0.5), - int(rgb[1] * 255 + 0.5), - int(rgb[2] * 255 + 0.5) - ) + rgb = hls_to_rgb(float(m.group(1)) / 360.0, float(m.group(3)) / 100.0, + float(m.group(2)) / 100.0, ) + return (int(rgb[0] * 255 + 0.5), int(rgb[1] * 255 + 0.5), + int(rgb[2] * 255 + 0.5)) m = re.match("rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$", color) if m: - return ( - int(m.group(1)), - int(m.group(2)), - int(m.group(3)), - int(m.group(4)) - ) + return (int(m.group(1)), int(m.group(2)), int(m.group(3)), + int(m.group(4))) raise ValueError("unknown color specifier: %r" % color) @@ -117,14 +94,15 @@ def getcolor(color, mode): if Image.getmodebase(mode) == "L": r, g, b = color - color = (r*299 + g*587 + b*114)//1000 + color = (r * 299 + g * 587 + b * 114) // 1000 if mode[-1] == 'A': return (color, alpha) else: if mode[-1] == 'A': - return color + (alpha,) + return color + (alpha, ) return color + colormap = { # X11 colour table (from "CSS3 module: Color working draft"), with # gray/grey spelling issues fixed. This is a superset of HTML 4.0 diff --git a/PIL/ImageDraw.py b/PIL/ImageDraw.py index a2a75d1c6de..f141c13028c 100644 --- a/PIL/ImageDraw.py +++ b/PIL/ImageDraw.py @@ -40,13 +40,13 @@ except ImportError: warnings = None - ## # A simple 2D drawing interface for PIL images. #

# 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[0-9]+)[\r\n]+" b"#define[ \t]+[^_]*_y_hot[ \t]+(?P[0-9]+)[\r\n]+" b")?" - b"[\\000-\\377]*_bits\\[\\]" -) + b"[\\000-\\377]*_bits\\[\\]") def _accept(prefix): return prefix.lstrip()[:7] == b"#define" - ## # Image plugin for X11 bitmaps. + class XbmImageFile(ImageFile.ImageFile): format = "XBM" @@ -58,14 +57,13 @@ def _open(self): ysize = int(m.group("height")) if m.group("hotspot"): - self.info["hotspot"] = ( - int(m.group("xhot")), int(m.group("yhot")) - ) + self.info["hotspot"] = (int(m.group("xhot")), + int(m.group("yhot"))) self.mode = "1" self.size = xsize, ysize - self.tile = [("xbm", (0, 0)+self.size, m.end(), None)] + self.tile = [("xbm", (0, 0) + self.size, m.end(), None)] def _save(im, fp, filename): @@ -83,7 +81,7 @@ def _save(im, fp, filename): fp.write(b"static char im_bits[] = {\n") - ImageFile._save(im, fp, [("xbm", (0, 0)+im.size, 0, None)]) + ImageFile._save(im, fp, [("xbm", (0, 0) + im.size, 0, None)]) fp.write(b"};\n") diff --git a/PIL/XpmImagePlugin.py b/PIL/XpmImagePlugin.py index 5175808950d..7af50682cc4 100644 --- a/PIL/XpmImagePlugin.py +++ b/PIL/XpmImagePlugin.py @@ -14,10 +14,8 @@ # See the README file for information on usage and redistribution. # - __version__ = "0.2" - import re from PIL import Image, ImageFile, ImagePalette from PIL._binary import i8, o8 @@ -29,10 +27,10 @@ def _accept(prefix): return prefix[:9] == b"/* XPM */" - ## # Image plugin for X11 pixel maps. + class XpmImageFile(ImageFile.ImageFile): format = "XPM" @@ -81,15 +79,14 @@ def _open(self): if s[i] == b"c": # process colour key - rgb = s[i+1] + rgb = s[i + 1] if rgb == b"None": self.info["transparency"] = c elif rgb[0:1] == b"#": # FIXME: handle colour names (see ImagePalette.py) rgb = int(rgb[1:], 16) - palette[c] = (o8((rgb >> 16) & 255) + - o8((rgb >> 8) & 255) + - o8(rgb & 255)) + palette[c] = (o8((rgb >> 16) & 255) + o8( + (rgb >> 8) & 255) + o8(rgb & 255)) else: # unknown colour raise ValueError("cannot read this XPM file") @@ -103,7 +100,7 @@ def _open(self): self.mode = "P" self.palette = ImagePalette.raw("RGB", b"".join(palette)) - self.tile = [("raw", (0, 0)+self.size, self.fp.tell(), ("P", 0, 1))] + self.tile = [("raw", (0, 0) + self.size, self.fp.tell(), ("P", 0, 1))] def load_read(self, bytes): @@ -115,7 +112,7 @@ def load_read(self, bytes): s = [None] * ysize for i in range(ysize): - s[i] = self.fp.readline()[1:xsize+1].ljust(xsize) + s[i] = self.fp.readline()[1:xsize + 1].ljust(xsize) self.fp = None diff --git a/PIL/__init__.py b/PIL/__init__.py index d1537769e92..6c787984f18 100644 --- a/PIL/__init__.py +++ b/PIL/__init__.py @@ -14,45 +14,17 @@ VERSION = '1.1.7' # PIL version PILLOW_VERSION = '2.8.0' # Pillow -_plugins = ['BmpImagePlugin', - 'BufrStubImagePlugin', - 'CurImagePlugin', - 'DcxImagePlugin', - 'EpsImagePlugin', - 'FitsStubImagePlugin', - 'FliImagePlugin', - 'FpxImagePlugin', - 'GbrImagePlugin', - 'GifImagePlugin', - 'GribStubImagePlugin', - 'Hdf5StubImagePlugin', - 'IcnsImagePlugin', - 'IcoImagePlugin', - 'ImImagePlugin', - 'ImtImagePlugin', - 'IptcImagePlugin', - 'JpegImagePlugin', - 'Jpeg2KImagePlugin', - 'McIdasImagePlugin', - 'MicImagePlugin', - 'MpegImagePlugin', - 'MpoImagePlugin', - 'MspImagePlugin', - 'PalmImagePlugin', - 'PcdImagePlugin', - 'PcxImagePlugin', - 'PdfImagePlugin', - 'PixarImagePlugin', - 'PngImagePlugin', - 'PpmImagePlugin', - 'PsdImagePlugin', - 'SgiImagePlugin', - 'SpiderImagePlugin', - 'SunImagePlugin', - 'TgaImagePlugin', - 'TiffImagePlugin', - 'WebPImagePlugin', - 'WmfImagePlugin', - 'XbmImagePlugin', - 'XpmImagePlugin', - 'XVThumbImagePlugin'] +_plugins = ['BmpImagePlugin', 'BufrStubImagePlugin', 'CurImagePlugin', + 'DcxImagePlugin', 'EpsImagePlugin', 'FitsStubImagePlugin', + 'FliImagePlugin', 'FpxImagePlugin', 'GbrImagePlugin', + 'GifImagePlugin', 'GribStubImagePlugin', 'Hdf5StubImagePlugin', + 'IcnsImagePlugin', 'IcoImagePlugin', 'ImImagePlugin', + 'ImtImagePlugin', 'IptcImagePlugin', 'JpegImagePlugin', + 'Jpeg2KImagePlugin', 'McIdasImagePlugin', 'MicImagePlugin', + 'MpegImagePlugin', 'MpoImagePlugin', 'MspImagePlugin', + 'PalmImagePlugin', 'PcdImagePlugin', 'PcxImagePlugin', + 'PdfImagePlugin', 'PixarImagePlugin', 'PngImagePlugin', + 'PpmImagePlugin', 'PsdImagePlugin', 'SgiImagePlugin', + 'SpiderImagePlugin', 'SunImagePlugin', 'TgaImagePlugin', + 'TiffImagePlugin', 'WebPImagePlugin', 'WmfImagePlugin', + 'XbmImagePlugin', 'XpmImagePlugin', 'XVThumbImagePlugin'] diff --git a/PIL/_binary.py b/PIL/_binary.py index 2f5e8ffd4f6..127d531abc9 100644 --- a/PIL/_binary.py +++ b/PIL/_binary.py @@ -14,17 +14,19 @@ from struct import unpack, pack if bytes is str: + def i8(c): return ord(c) def o8(i): return chr(i & 255) else: + def i8(c): return c if c.__class__ is int else c[0] def o8(i): - return bytes((i & 255,)) + return bytes((i & 255, )) # Input, le = little endian, be = big endian @@ -36,7 +38,7 @@ def i16le(c, o=0): c: string containing bytes to convert o: offset of bytes to convert in string """ - return unpack("H", c[o:o+2])[0] + return unpack(">H", c[o:o + 2])[0] def i32be(c, o=0): - return unpack(">I", c[o:o+4])[0] + return unpack(">I", c[o:o + 4])[0] # Output, le = little endian, be = big endian diff --git a/PIL/_util.py b/PIL/_util.py index 51c6f6887d3..aa019429398 100644 --- a/PIL/_util.py +++ b/PIL/_util.py @@ -1,12 +1,14 @@ import os if bytes is str: + def isStringType(t): return isinstance(t, basestring) def isPath(f): return isinstance(f, basestring) else: + def isStringType(t): return isinstance(t, str)