def chunk_fcTL(self, pos, length): s = PIL.ImageFile._safe_read(self.fp, length) sequence_number = i32(s) width = i32(s[4:]) height = i32(s[8:]) x_offset = i32(s[12:]) y_offset = i32(s[16:]) delay_num = i16(s[20:]) delay_den = i16(s[22:]) dispose_op = i8(s[24]) blend_op = i8(s[25]) self.frame_control.append( (sequence_number, (x_offset, y_offset, width, height), dispose_op, blend_op)) if delay_num == 0: self.duration.append(0) else: if delay_den == 0: delay_den = 100 self.duration.append(int(round(delay_num / delay_den * 1000, 0))) return s
def read_32(fobj, start_length, size): """ Read a 32bit RGB icon resource. Seems to be either uncompressed or an RLE packbits-like scheme. """ (start, length) = start_length fobj.seek(start) pixel_size = (size[0] * size[2], size[1] * size[2]) sizesq = pixel_size[0] * pixel_size[1] if length == sizesq * 3: # uncompressed ("RGBRGBGB") indata = fobj.read(length) im = Image.frombuffer("RGB", pixel_size, indata, "raw", "RGB", 0, 1) else: # decode image im = Image.new("RGB", pixel_size, None) for band_ix in range(3): data = [] bytesleft = sizesq while bytesleft > 0: byte = fobj.read(1) if not byte: break byte = i8(byte) if byte & 0x80: blocksize = byte - 125 byte = fobj.read(1) for i in range(blocksize): data.append(byte) else: blocksize = byte + 1 data.append(fobj.read(blocksize)) bytesleft -= blocksize if bytesleft <= 0: 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 ) im.im.putband(band.im, band_ix) return {"RGB": im}
def _open(self): if not _accept(self.fp.read(9)): raise SyntaxError("not an XPM file") # skip forward to next string while True: s = self.fp.readline() if not s: raise SyntaxError("broken XPM file") m = xpm_head.match(s) if m: break self.size = int(m.group(1)), int(m.group(2)) pal = int(m.group(3)) bpp = int(m.group(4)) if pal > 256 or bpp != 1: raise ValueError("cannot read this XPM file") # # load palette description palette = [b"\0\0\0"] * 256 for i in range(pal): s = self.fp.readline() if s[-2:] == b'\r\n': s = s[:-2] elif s[-1:] in b'\r\n': s = s[:-1] c = i8(s[1]) s = s[2:-2].split() for i in range(0, len(s), 2): if s[i] == b"c": # process colour key 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)) else: # unknown colour raise ValueError("cannot read this XPM file") break else: # missing colour key raise ValueError("cannot read this XPM file") self.mode = "P" self.palette = ImagePalette.raw("RGB", b"".join(palette)) self.tile = [("raw", (0, 0) + self.size, self.fp.tell(), ("P", 0, 1))]
def _open(self): if not _accept(self.fp.read(9)): raise SyntaxError("not an XPM file") # skip forward to next string while True: s = self.fp.readline() if not s: raise SyntaxError("broken XPM file") m = xpm_head.match(s) if m: break self.size = int(m.group(1)), int(m.group(2)) pal = int(m.group(3)) bpp = int(m.group(4)) if pal > 256 or bpp != 1: raise ValueError("cannot read this XPM file") # # load palette description palette = [b"\0\0\0"] * 256 for i in range(pal): s = self.fp.readline() if s[-2:] == b'\r\n': s = s[:-2] elif s[-1:] in b'\r\n': s = s[:-1] c = i8(s[1]) s = s[2:-2].split() for i in range(0, len(s), 2): if s[i] == b"c": # process colour key 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) else: # unknown colour raise ValueError("cannot read this XPM file") break else: # missing colour key raise ValueError("cannot read this XPM file") self.mode = "P" self.palette = ImagePalette.raw("RGB", b"".join(palette)) self.tile = [("raw", (0, 0)+self.size, self.fp.tell(), ("P", 0, 1))]
def test_standard(self): self.assertEqual(_binary.i8(b'*'), 42) self.assertEqual(_binary.o8(42), b'*')
def skip(self, bits): while self.bits < bits: self.bitbuffer = (self.bitbuffer << 8) + i8(self.fp.read(1)) self.bits += 8 self.bits = self.bits - bits
def next(self): return i8(self.fp.read(1))
def _save(im, fp, filename): resolution = im.encoderinfo.get("resolution", 72.0) # # make sure image data is available im.load() xref = [0] * (5 + 1) # placeholders class TextWriter: def __init__(self, fp): self.fp = fp def __getattr__(self, name): return getattr(self.fp, name) def write(self, value): self.fp.write(value.encode('latin-1')) fp = TextWriter(fp) fp.write("%PDF-1.2\n") fp.write("% created by PIL PDF driver " + __version__ + "\n") # # Get image characteristics width, height = im.size # FIXME: Should replace ASCIIHexDecode with RunLengthDecode (packbits) # or LZWDecode (tiff/lzw compression). Note that PDF 1.2 also supports # Flatedecode (zip compression). bits = 8 params = None if im.mode == "1": filter = "/ASCIIHexDecode" colorspace = "/DeviceGray" procset = "/ImageB" # grayscale bits = 1 elif im.mode == "L": filter = "/DCTDecode" # params = "<< /Predictor 15 /Columns %d >>" % (width-2) colorspace = "/DeviceGray" procset = "/ImageB" # grayscale elif im.mode == "P": filter = "/ASCIIHexDecode" 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]) colorspace = colorspace + "%02x%02x%02x " % (r, g, b) colorspace = colorspace + b"> ]" procset = "/ImageI" # indexed color elif im.mode == "RGB": filter = "/DCTDecode" colorspace = "/DeviceRGB" procset = "/ImageC" # color images elif im.mode == "CMYK": filter = "/DCTDecode" colorspace = "/DeviceCMYK" procset = "/ImageC" # color images else: raise ValueError("cannot save mode %s" % im.mode) # # catalogue xref[1] = fp.tell() _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]") _endobj(fp) # # image op = io.BytesIO() if filter == "/ASCIIHexDecode": if bits == 1: # FIXME: the hex encoder doesn't support packed 1-bit # images; do things the hard way... data = im.tostring("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)]) elif filter == "/DCTDecode": Image.SAVE["JPEG"](im, op, filename) elif filter == "/FlateDecode": 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)]) 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) fp.write("stream\n") fp.fp.write(op.getvalue()) fp.write("\nendstream\n") _endobj(fp) # # page 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))) _endobj(fp) # # page contents 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))) xref[5] = fp.tell() _obj(fp, 5, Length=len(op.fp.getvalue())) fp.write("stream\n") fp.fp.write(op.fp.getvalue()) fp.write("\nendstream\n") _endobj(fp) # # trailer startxref = fp.tell() fp.write("xref\n0 %d\n0000000000 65535 f \n" % len(xref)) for x in xref[1:]: fp.write("%010d 00000 n \n" % x) fp.write("trailer\n<<\n/Size %d\n/Root 1 0 R\n>>\n" % len(xref)) fp.write("startxref\n%d\n%%%%EOF\n" % startxref) fp.flush()
def _open(self): # Quick rejection: if there's not an LF among the first # 100 bytes, this is (probably) not a text header. if not b"\n" in self.fp.read(100): raise SyntaxError("not an IM file") self.fp.seek(0) n = 0 # Default values self.info[MODE] = "L" self.info[SIZE] = (512, 512) self.info[FRAMES] = 1 self.rawmode = "L" while True: s = self.fp.read(1) # Some versions of IFUNC uses \n\r instead of \r\n... if s == b"\r": continue if not s or s == b'\0' or s == b'\x1A': break # FIXME: this may read whole file if not a text file s = s + self.fp.readline() if len(s) > 100: raise SyntaxError("not an IM file") if s[-2:] == b'\r\n': s = s[:-2] elif s[-1:] == b'\n': s = s[:-1] try: m = split.match(s) except re.error as v: raise SyntaxError("not an IM file") if m: k, v = m.group(1,2) # Don't know if this is the correct encoding, but a decent guess # (I guess) k = k.decode('latin-1', 'replace') v = v.decode('latin-1', 'replace') # Convert value as appropriate if k in [FRAMES, SCALE, SIZE]: v = v.replace("*", ",") v = tuple(map(number, v.split(","))) if len(v) == 1: v = v[0] elif k == MODE and v in OPEN: v, self.rawmode = OPEN[v] # Add to dictionary. Note that COMMENT tags are # combined into a list of strings. if k == COMMENT: if k in self.info: self.info[k].append(v) else: self.info[k] = [v] else: self.info[k] = v if k in TAGS: n = n + 1 else: raise SyntaxError("Syntax error in IM header: " + s.decode('ascii', 'replace')) if not n: raise SyntaxError("Not an IM file") # Basic attributes self.size = self.info[SIZE] self.mode = self.info[MODE] # Skip forward to start of image data while s and s[0:1] != b'\x1A': s = self.fp.read(1) if not s: raise SyntaxError("File truncated") if LUT in self.info: # convert lookup table to palette or lut attribute palette = self.fp.read(768) greyscale = 1 # greyscale palette linear = 1 # linear greyscale palette for i in range(256): if palette[i] == palette[i+256] == palette[i+512]: if i8(palette[i]) != i: linear = 0 else: greyscale = 0 if self.mode == "L" or self.mode == "LA": if greyscale: if not linear: self.lut = [i8(c) for c in palette[:256]] else: if self.mode == "L": self.mode = self.rawmode = "P" elif self.mode == "LA": self.mode = self.rawmode = "PA" self.palette = ImagePalette.raw("RGB;L", palette) elif self.mode == "RGB": if not greyscale or not linear: self.lut = [i8(c) for c in palette] self.frame = 0 self.__offset = offs = self.fp.tell() self.__fp = self.fp # FIXME: hack if self.rawmode[:2] == "F;": # ifunc95 formats try: # 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))] return except ValueError: pass if self.rawmode in ["RGB;T", "RYB;T"]: # 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))] else: # LabEye/IFUNC files self.tile = [("raw", (0,0)+self.size, offs, (self.rawmode, 0, -1))]
def _save(im, fp, filename): resolution = im.encoderinfo.get("resolution", 72.0) # # make sure image data is available im.load() xref = [0]*(5+1) # placeholders class TextWriter: def __init__(self, fp): self.fp = fp def __getattr__(self, name): return getattr(self.fp, name) def write(self, value): self.fp.write(value.encode('latin-1')) fp = TextWriter(fp) fp.write("%PDF-1.2\n") fp.write("% created by PIL PDF driver " + __version__ + "\n") # # Get image characteristics width, height = im.size # FIXME: Should replace ASCIIHexDecode with RunLengthDecode (packbits) # or LZWDecode (tiff/lzw compression). Note that PDF 1.2 also supports # Flatedecode (zip compression). bits = 8 params = None if im.mode == "1": filter = "/ASCIIHexDecode" colorspace = "/DeviceGray" procset = "/ImageB" # grayscale bits = 1 elif im.mode == "L": filter = "/DCTDecode" # params = "<< /Predictor 15 /Columns %d >>" % (width-2) colorspace = "/DeviceGray" procset = "/ImageB" # grayscale elif im.mode == "P": filter = "/ASCIIHexDecode" 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]) colorspace = colorspace + "%02x%02x%02x " % (r, g, b) colorspace = colorspace + b"> ]" procset = "/ImageI" # indexed color elif im.mode == "RGB": filter = "/DCTDecode" colorspace = "/DeviceRGB" procset = "/ImageC" # color images elif im.mode == "CMYK": filter = "/DCTDecode" colorspace = "/DeviceCMYK" procset = "/ImageC" # color images else: raise ValueError("cannot save mode %s" % im.mode) # # catalogue xref[1] = fp.tell() _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]") _endobj(fp) # # image op = io.BytesIO() if filter == "/ASCIIHexDecode": if bits == 1: # FIXME: the hex encoder doesn't support packed 1-bit # images; do things the hard way... data = im.tostring("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)]) elif filter == "/DCTDecode": ImageFile._save(im, op, [("jpeg", (0,0)+im.size, 0, im.mode)]) elif filter == "/FlateDecode": 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)]) 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) fp.write("stream\n") fp.fp.write(op.getvalue()) fp.write("\nendstream\n") _endobj(fp) # # page 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))) _endobj(fp) # # page contents 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))) xref[5] = fp.tell() _obj(fp, 5, Length = len(op.fp.getvalue())) fp.write("stream\n") fp.fp.write(op.fp.getvalue()) fp.write("\nendstream\n") _endobj(fp) # # trailer startxref = fp.tell() fp.write("xref\n0 %d\n0000000000 65535 f \n" % len(xref)) for x in xref[1:]: fp.write("%010d 00000 n \n" % x) fp.write("trailer\n<<\n/Size %d\n/Root 1 0 R\n>>\n" % len(xref)) fp.write("startxref\n%d\n%%%%EOF\n" % startxref) fp.flush()
def _open(self): # Quick rejection: if there's not an LF among the first # 100 bytes, this is (probably) not a text header. if b"\n" not in self.fp.read(100): raise InvalidFileType("not an IM file") self.fp.seek(0) n = 0 # Default values self.info[MODE] = "L" self.info[SIZE] = (512, 512) self.info[FRAMES] = 1 self.rawmode = "L" while True: s = self.fp.read(1) # Some versions of IFUNC uses \n\r instead of \r\n... if s == b"\r": continue if not s or s == b'\0' or s == b'\x1A': break # FIXME: this may read whole file if not a text file s = s + self.fp.readline() if len(s) > 100: raise InvalidFileType("not an IM file") if s[-2:] == b'\r\n': s = s[:-2] elif s[-1:] == b'\n': s = s[:-1] try: m = split.match(s) except re.error as v: raise InvalidFileType("not an IM file") if m: k, v = m.group(1, 2) # Don't know if this is the correct encoding, # but a decent guess (I guess) k = k.decode('latin-1', 'replace') v = v.decode('latin-1', 'replace') # Convert value as appropriate if k in [FRAMES, SCALE, SIZE]: v = v.replace("*", ",") v = tuple(map(number, v.split(","))) if len(v) == 1: v = v[0] elif k == MODE and v in OPEN: v, self.rawmode = OPEN[v] # Add to dictionary. Note that COMMENT tags are # combined into a list of strings. if k == COMMENT: if k in self.info: self.info[k].append(v) else: self.info[k] = [v] else: self.info[k] = v if k in TAGS: n += 1 else: s = s.decode("ascii", "replace") raise PILReadError("Bad IM header: %r" % (s)) if not n: raise InvalidFileType("Not an IM file") # Basic attributes self.size = self.info[SIZE] self.mode = self.info[MODE] # Skip forward to start of image data while s and s[0:1] != b'\x1A': s = self.fp.read(1) if not s: raise PILReadError("File truncated") if LUT in self.info: # convert lookup table to palette or lut attribute palette = self.fp.read(768) greyscale = 1 # greyscale palette linear = 1 # linear greyscale palette for i in range(256): if palette[i] == palette[i + 256] == palette[i + 512]: if i8(palette[i]) != i: linear = 0 else: greyscale = 0 if self.mode == "L" or self.mode == "LA": if greyscale: if not linear: self.lut = [i8(c) for c in palette[:256]] else: if self.mode == "L": self.mode = self.rawmode = "P" elif self.mode == "LA": self.mode = self.rawmode = "PA" self.palette = ImagePalette.raw("RGB;L", palette) elif self.mode == "RGB": if not greyscale or not linear: self.lut = [i8(c) for c in palette] self.frame = 0 self.__offset = offs = self.fp.tell() self.__fp = self.fp # FIXME: hack if self.rawmode[:2] == "F;": # ifunc95 formats try: # 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))] return except ValueError: pass if self.rawmode in ["RGB;T", "RYB;T"]: # 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)) ] else: # LabEye/IFUNC files self.tile = [("raw", (0, 0) + self.size, offs, (self.rawmode, 0, -1))]
def test_standard(self): self.assertEqual(_binary.i8(b"*"), 42) self.assertEqual(_binary.o8(42), b"*")
def test_standard(): assert _binary.i8(b"*") == 42 assert _binary.o8(42) == b"*"