py3k: The big push

There are two main issues fixed with this commit:

* bytes vs. str: All file, image, and palette data are now handled as
  bytes. A new _binary module consolidates the hacks needed to do this
  across Python versions. tostring/fromstring methods have been renamed to
  tobytes/frombytes, but the Python 2.6/2.7 versions alias them to the old
  names for compatibility. Users should move to tobytes/frombytes.

  One other potentially-breaking change is that text data in image files
  (such as tags, comments) are now explicitly handled with a specific
  character encoding in mind. This works well with the Unicode str in
  Python 3, but may trip up old code expecting a straight byte-for-byte
  translation to a Python string. This also required a change to Gohlke's
  tags tests (in Tests/test_file_png.py) to expect Unicode strings from
  the code.

* True div vs. floor div: Many division operations used the "/" operator
  to do floor division, which is now the "//" operator in Python 3. These
  were fixed.

As of this commit, on the first pass, I have one failing test (improper
handling of a slice object in a C module, test_imagepath.py) in Python 3,
and three that that I haven't tried running yet (test_imagegl,
test_imagegrab, and test_imageqt). I also haven't tested anything on
Windows. All but the three skipped tests run flawlessly against Pythons
2.6 and 2.7.
This commit is contained in:
Brian Crowell 2012-10-20 16:01:53 -05:00 committed by Brian Crowell
parent 8b704e3005
commit a7e3b2e47b
66 changed files with 882 additions and 819 deletions

View File

@ -24,9 +24,9 @@ __version__ = "0.4"
from . import Image, ImageFile, ImagePalette from . import Image, ImageFile, ImagePalette
from .PngImagePlugin import i16, i32, ChunkStream, _MODES from .PngImagePlugin import i8, i16, i32, ChunkStream, _MODES
MAGIC = "\212ARG\r\n\032\n" MAGIC = b"\212ARG\r\n\032\n"
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# ARG parser # ARG parser
@ -67,7 +67,7 @@ class ArgStream(ChunkStream):
s = self.fp.read(bytes) s = self.fp.read(bytes)
self.size = i32(s), i32(s[4:]) self.size = i32(s), i32(s[4:])
try: try:
self.mode, self.rawmode = _MODES[(ord(s[8]), ord(s[9]))] self.mode, self.rawmode = _MODES[(i8(s[8]), i8(s[9]))]
except: except:
raise SyntaxError("unknown ARG mode") raise SyntaxError("unknown ARG mode")
@ -154,14 +154,14 @@ class ArgStream(ChunkStream):
size = i32(s), i32(s[4:]) size = i32(s), i32(s[4:])
try: try:
mode, rawmode = _MODES[(ord(s[8]), ord(s[9]))] mode, rawmode = _MODES[(i8(s[8]), i8(s[9]))]
except: except:
raise SyntaxError("unknown image mode") raise SyntaxError("unknown image mode")
if full: if full:
if ord(s[12]): if i8(s[12]):
pass # interlace not yet supported pass # interlace not yet supported
if ord(s[11]): if i8(s[11]):
raise SyntaxError("unknown filter category") raise SyntaxError("unknown filter category")
return size, mode, rawmode return size, mode, rawmode
@ -236,7 +236,7 @@ class ArgStream(ChunkStream):
self.im = Image.core.new(mode, size) self.im = Image.core.new(mode, size)
self.decoder = Image.core.zip_decoder(rawmode) self.decoder = Image.core.zip_decoder(rawmode)
self.decoder.setimage(self.im, (0,0) + size) self.decoder.setimage(self.im, (0,0) + size)
self.data = "" self.data = b""
return s return s
@ -252,7 +252,7 @@ class ArgStream(ChunkStream):
size, mode, rawmode = self.__getmodesize(s) size, mode, rawmode = self.__getmodesize(s)
# delta header # delta header
diff = ord(s[13]) diff = i8(s[13])
offs = i32(s[14:18]), i32(s[18:22]) offs = i32(s[14:18]), i32(s[18:22])
bbox = offs + (offs[0]+size[0], offs[1]+size[1]) bbox = offs + (offs[0]+size[0], offs[1]+size[1])
@ -269,7 +269,7 @@ class ArgStream(ChunkStream):
self.decoder = Image.core.zip_decoder(rawmode) self.decoder = Image.core.zip_decoder(rawmode)
self.decoder.setimage(self.im, (0,0) + size) self.decoder.setimage(self.im, (0,0) + size)
self.data = "" self.data = b""
return s return s
@ -289,7 +289,7 @@ class ArgStream(ChunkStream):
self.im = Image.core.new(mode, size) self.im = Image.core.new(mode, size)
self.decoder = Image.core.jpeg_decoder(rawmode) self.decoder = Image.core.jpeg_decoder(rawmode)
self.decoder.setimage(self.im, (0,0) + size) self.decoder.setimage(self.im, (0,0) + size)
self.data = "" self.data = b""
return s return s
@ -309,7 +309,7 @@ class ArgStream(ChunkStream):
self.im = Image.core.new(mode, size) self.im = Image.core.new(mode, size)
self.decoder = Image.core.raw_decoder(rawmode) self.decoder = Image.core.raw_decoder(rawmode)
self.decoder.setimage(self.im, (0,0) + size) self.decoder.setimage(self.im, (0,0) + size)
self.data = "" self.data = b""
return s return s

View File

@ -47,27 +47,27 @@ def bdf_char(f):
s = f.readline() s = f.readline()
if not s: if not s:
return None return None
if s[:9] == "STARTCHAR": if s[:9] == b"STARTCHAR":
break break
id = s[9:].strip() id = s[9:].strip().decode('ascii')
# load symbol properties # load symbol properties
props = {} props = {}
while True: while True:
s = f.readline() s = f.readline()
if not s or s[:6] == "BITMAP": if not s or s[:6] == b"BITMAP":
break break
i = s.find(" ") i = s.find(b" ")
props[s[:i]] = s[i+1:-1] props[s[:i].decode('ascii')] = s[i+1:-1].decode('ascii')
# load bitmap # load bitmap
bitmap = [] bitmap = []
while True: while True:
s = f.readline() s = f.readline()
if not s or s[:7] == "ENDCHAR": if not s or s[:7] == b"ENDCHAR":
break break
bitmap.append(s[:-1]) bitmap.append(s[:-1])
bitmap = "".join(bitmap) bitmap = b"".join(bitmap)
[x, y, l, d] = [int(s) for s in props["BBX"].split()] [x, y, l, d] = [int(s) for s in props["BBX"].split()]
[dx, dy] = [int(s) for s in props["DWIDTH"].split()] [dx, dy] = [int(s) for s in props["DWIDTH"].split()]
@ -75,7 +75,7 @@ def bdf_char(f):
bbox = (dx, dy), (l, -d-y, x+l, -d), (0, 0, x, y) bbox = (dx, dy), (l, -d-y, x+l, -d), (0, 0, x, y)
try: try:
im = Image.fromstring("1", (x, y), bitmap, "hex", "1") im = Image.frombytes("1", (x, y), bitmap, "hex", "1")
except ValueError: except ValueError:
# deal with zero-width characters # deal with zero-width characters
im = Image.new("1", (x, y)) im = Image.new("1", (x, y))
@ -92,7 +92,7 @@ class BdfFontFile(FontFile.FontFile):
FontFile.FontFile.__init__(self) FontFile.FontFile.__init__(self)
s = fp.readline() s = fp.readline()
if s[:13] != "STARTFONT 2.1": if s[:13] != b"STARTFONT 2.1":
raise SyntaxError("not a valid BDF file") raise SyntaxError("not a valid BDF file")
props = {} props = {}
@ -100,13 +100,13 @@ class BdfFontFile(FontFile.FontFile):
while True: while True:
s = fp.readline() s = fp.readline()
if not s or s[:13] == "ENDPROPERTIES": if not s or s[:13] == b"ENDPROPERTIES":
break break
i = s.find(" ") i = s.find(b" ")
props[s[:i]] = s[i+1:-1] props[s[:i].decode('ascii')] = s[i+1:-1].decode('ascii')
if s[:i] in ["COMMENT", "COPYRIGHT"]: if s[:i] in [b"COMMENT", b"COPYRIGHT"]:
if s.find("LogicalFontDescription") < 0: if s.find(b"LogicalFontDescription") < 0:
comments.append(s[i+1:-1]) comments.append(s[i+1:-1].decode('ascii'))
font = props["FONT"].split("-") font = props["FONT"].split("-")

View File

@ -27,20 +27,19 @@
__version__ = "0.7" __version__ = "0.7"
from . import Image, ImageFile, ImagePalette from . import Image, ImageFile, ImagePalette, _binary
i8 = _binary.i8
i16 = _binary.i16le
i32 = _binary.i32le
o8 = _binary.o8
o16 = _binary.o16le
o32 = _binary.o32le
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Read BMP file # Read BMP file
def i16(c):
return ord(c[0]) + (ord(c[1])<<8)
def i32(c):
return ord(c[0]) + (ord(c[1])<<8) + (ord(c[2])<<16) + (ord(c[3])<<24)
BIT2MODE = { BIT2MODE = {
# bits => mode, rawmode # bits => mode, rawmode
1: ("P", "P;1"), 1: ("P", "P;1"),
@ -52,7 +51,7 @@ BIT2MODE = {
} }
def _accept(prefix): def _accept(prefix):
return prefix[:2] == "BM" return prefix[:2] == b"BM"
## ##
# Image plugin for the Windows BMP format. # Image plugin for the Windows BMP format.
@ -134,7 +133,7 @@ class BmpImageFile(ImageFile.ImageFile):
indices = list(range(colors)) indices = list(range(colors))
for i in indices: for i in indices:
rgb = read(lutsize)[:3] rgb = read(lutsize)[:3]
if rgb != chr(i)*3: if rgb != o8(i)*3:
greyscale = 0 greyscale = 0
palette.append(rgb) palette.append(rgb)
if greyscale: if greyscale:
@ -145,7 +144,7 @@ class BmpImageFile(ImageFile.ImageFile):
else: else:
self.mode = "P" self.mode = "P"
self.palette = ImagePalette.raw( self.palette = ImagePalette.raw(
"BGR", "".join(palette) "BGR", b"".join(palette)
) )
if not offset: if not offset:
@ -162,7 +161,7 @@ class BmpImageFile(ImageFile.ImageFile):
# HEAD # HEAD
s = self.fp.read(14) s = self.fp.read(14)
if s[:2] != "BM": if s[:2] != b"BM":
raise SyntaxError("Not a BMP file") raise SyntaxError("Not a BMP file")
offset = i32(s[10:]) offset = i32(s[10:])
@ -181,12 +180,6 @@ class DibImageFile(BmpImageFile):
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Write BMP file # Write BMP file
def o16(i):
return chr(i&255) + chr(i>>8&255)
def o32(i):
return chr(i&255) + chr(i>>8&255) + chr(i>>16&255) + chr(i>>24&255)
SAVE = { SAVE = {
"1": ("1", 1, 2), "1": ("1", 1, 2),
"L": ("L", 8, 256), "L": ("L", 8, 256),
@ -204,13 +197,13 @@ def _save(im, fp, filename, check=0):
if check: if check:
return check return check
stride = ((im.size[0]*bits+7)/8+3)&(~3) stride = ((im.size[0]*bits+7)//8+3)&(~3)
header = 40 # or 64 for OS/2 version 2 header = 40 # or 64 for OS/2 version 2
offset = 14 + header + colors * 4 offset = 14 + header + colors * 4
image = stride * im.size[1] image = stride * im.size[1]
# bitmap header # bitmap header
fp.write("BM" + # file type (magic) fp.write(b"BM" + # file type (magic)
o32(offset+image) + # file size o32(offset+image) + # file size
o32(0) + # reserved o32(0) + # reserved
o32(offset)) # image data offset o32(offset)) # image data offset
@ -227,14 +220,14 @@ def _save(im, fp, filename, check=0):
o32(colors) + # colors used o32(colors) + # colors used
o32(colors)) # colors important o32(colors)) # colors important
fp.write("\000" * (header - 40)) # padding (for OS/2 format) fp.write(b"\0" * (header - 40)) # padding (for OS/2 format)
if im.mode == "1": if im.mode == "1":
for i in (0, 255): for i in (0, 255):
fp.write(chr(i) * 4) fp.write(o8(i) * 4)
elif im.mode == "L": elif im.mode == "L":
for i in range(256): for i in range(256):
fp.write(chr(i) * 4) fp.write(o8(i) * 4)
elif im.mode == "P": elif im.mode == "P":
fp.write(im.im.getpalette("RGB", "BGRX")) fp.write(im.im.getpalette("RGB", "BGRX"))

View File

@ -26,7 +26,7 @@ def register_handler(handler):
# Image adapter # Image adapter
def _accept(prefix): def _accept(prefix):
return prefix[:4] == "BUFR" or prefix[:4] == "ZCZC" return prefix[:4] == b"BUFR" or prefix[:4] == b"ZCZC"
class BufrStubImageFile(ImageFile.StubImageFile): class BufrStubImageFile(ImageFile.StubImageFile):

View File

@ -19,21 +19,19 @@
__version__ = "0.1" __version__ = "0.1"
from . import Image, BmpImagePlugin from . import Image, BmpImagePlugin, _binary
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
def i16(c): i8 = _binary.i8
return ord(c[0]) + (ord(c[1])<<8) i16 = _binary.i16le
i32 = _binary.i32le
def i32(c):
return ord(c[0]) + (ord(c[1])<<8) + (ord(c[2])<<16) + (ord(c[3])<<24)
def _accept(prefix): def _accept(prefix):
return prefix[:4] == "\0\0\2\0" return prefix[:4] == b"\0\0\2\0"
## ##
# Image plugin for Windows Cursor files. # Image plugin for Windows Cursor files.
@ -53,17 +51,17 @@ class CurImageFile(BmpImagePlugin.BmpImageFile):
raise SyntaxError("not an CUR file") raise SyntaxError("not an CUR file")
# pick the largest cursor in the file # pick the largest cursor in the file
m = "" m = b""
for i in range(i16(s[4:])): for i in range(i16(s[4:])):
s = self.fp.read(16) s = self.fp.read(16)
if not m: if not m:
m = s m = s
elif ord(s[0]) > ord(m[0]) and ord(s[1]) > ord(m[1]): elif i8(s[0]) > i8(m[0]) and i8(s[1]) > i8(m[1]):
m = s m = s
#print "width", ord(s[0]) #print "width", i8(s[0])
#print "height", ord(s[1]) #print "height", i8(s[1])
#print "colors", ord(s[2]) #print "colors", i8(s[2])
#print "reserved", ord(s[3]) #print "reserved", i8(s[3])
#print "hotspot x", i16(s[4:]) #print "hotspot x", i16(s[4:])
#print "hotspot y", i16(s[6:]) #print "hotspot y", i16(s[6:])
#print "bytes", i32(s[8:]) #print "bytes", i32(s[8:])
@ -73,7 +71,7 @@ class CurImageFile(BmpImagePlugin.BmpImageFile):
self._bitmap(i32(m[12:]) + offset) self._bitmap(i32(m[12:]) + offset)
# patch up the bitmap height # patch up the bitmap height
self.size = self.size[0], self.size[1]/2 self.size = self.size[0], self.size[1]//2
d, e, o, a = self.tile[0] d, e, o, a = self.tile[0]
self.tile[0] = d, (0,0)+self.size, o, a self.tile[0] = d, (0,0)+self.size, o, a

View File

@ -23,14 +23,13 @@
__version__ = "0.2" __version__ = "0.2"
from . import Image from . import Image, _binary
from .PcxImagePlugin import PcxImageFile from .PcxImagePlugin import PcxImageFile
MAGIC = 0x3ADE68B1 # QUIZ: what's this value, then? MAGIC = 0x3ADE68B1 # QUIZ: what's this value, then?
def i32(c): i32 = _binary.i32le
return ord(c[0]) + (ord(c[1])<<8) + (ord(c[2])<<16) + (ord(c[3])<<24)
def _accept(prefix): def _accept(prefix):
return i32(prefix) == MAGIC return i32(prefix) == MAGIC

View File

@ -21,16 +21,13 @@
__version__ = "0.5" __version__ = "0.5"
import re import re
from . import Image, ImageFile from . import Image, ImageFile, _binary
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
def i32(c): i32 = _binary.i32le
return ord(c[0]) + (ord(c[1])<<8) + (ord(c[2])<<16) + (ord(c[3])<<24) o32 = _binary.o32le
def o32(i):
return chr(i&255) + chr(i>>8&255) + chr(i>>16&255) + chr(i>>24&255)
split = re.compile(r"^%%([^:]*):[ \t]*(.*)[ \t]*$") split = re.compile(r"^%%([^:]*):[ \t]*(.*)[ \t]*$")
field = re.compile(r"^%[%!\w]([^:]*)[ \t]*$") field = re.compile(r"^%[%!\w]([^:]*)[ \t]*$")
@ -99,24 +96,24 @@ class PSFile:
pos = pos - 1 pos = pos - 1
return pos return pos
def readline(self): def readline(self):
s = "" s = b""
if self.char: if self.char:
c = self.char c = self.char
self.char = None self.char = None
else: else:
c = self.fp.read(1) c = self.fp.read(1)
while c not in "\r\n": while c not in b"\r\n":
s = s + c s = s + c
c = self.fp.read(1) c = self.fp.read(1)
if c == "\r": if c == b"\r":
self.char = self.fp.read(1) self.char = self.fp.read(1)
if self.char == "\n": if self.char == b"\n":
self.char = None self.char = None
return s + "\n" return s + b"\n"
def _accept(prefix): def _accept(prefix):
return prefix[:4] == "%!PS" or i32(prefix) == 0xC6D3D0C5 return prefix[:4] == b"%!PS" or i32(prefix) == 0xC6D3D0C5
## ##
# Image plugin for Encapsulated Postscript. This plugin supports only # Image plugin for Encapsulated Postscript. This plugin supports only
@ -302,42 +299,42 @@ def _save(im, fp, filename, eps=1):
# #
# determine postscript image mode # determine postscript image mode
if im.mode == "L": if im.mode == "L":
operator = (8, 1, "image") operator = (8, 1, b"image")
elif im.mode == "RGB": elif im.mode == "RGB":
operator = (8, 3, "false 3 colorimage") operator = (8, 3, b"false 3 colorimage")
elif im.mode == "CMYK": elif im.mode == "CMYK":
operator = (8, 4, "false 4 colorimage") operator = (8, 4, b"false 4 colorimage")
else: else:
raise ValueError("image mode is not supported") raise ValueError("image mode is not supported")
if eps: if eps:
# #
# write EPS header # write EPS header
fp.write("%!PS-Adobe-3.0 EPSF-3.0\n") fp.write(b"%!PS-Adobe-3.0 EPSF-3.0\n")
fp.write("%%Creator: PIL 0.1 EpsEncode\n") fp.write(b"%%Creator: PIL 0.1 EpsEncode\n")
#fp.write("%%CreationDate: %s"...) #fp.write("%%CreationDate: %s"...)
fp.write("%%%%BoundingBox: 0 0 %d %d\n" % im.size) fp.write(("%%%%BoundingBox: 0 0 %d %d\n" % im.size).encode('ascii'))
fp.write("%%Pages: 1\n") fp.write(b"%%Pages: 1\n")
fp.write("%%EndComments\n") fp.write(b"%%EndComments\n")
fp.write("%%Page: 1 1\n") fp.write(b"%%Page: 1 1\n")
fp.write("%%ImageData: %d %d " % im.size) fp.write(("%%ImageData: %d %d " % im.size).encode('ascii'))
fp.write("%d %d 0 1 1 \"%s\"\n" % operator) fp.write(("%d %d 0 1 1 \"%s\"\n" % operator).encode('ascii'))
# #
# image header # image header
fp.write("gsave\n") fp.write(b"gsave\n")
fp.write("10 dict begin\n") fp.write(b"10 dict begin\n")
fp.write("/buf %d string def\n" % (im.size[0] * operator[1])) fp.write(("/buf %d string def\n" % (im.size[0] * operator[1])).encode('ascii'))
fp.write("%d %d scale\n" % im.size) fp.write(("%d %d scale\n" % im.size).encode('ascii'))
fp.write("%d %d 8\n" % im.size) # <= bits fp.write(("%d %d 8\n" % im.size).encode('ascii')) # <= bits
fp.write("[%d 0 0 -%d 0 %d]\n" % (im.size[0], im.size[1], im.size[1])) fp.write(("[%d 0 0 -%d 0 %d]\n" % (im.size[0], im.size[1], im.size[1])).encode('ascii'))
fp.write("{ currentfile buf readhexstring pop } bind\n") fp.write(b"{ currentfile buf readhexstring pop } bind\n")
fp.write("%s\n" % operator[2]) fp.write(operator[2] + b"\n")
ImageFile._save(im, fp, [("eps", (0,0)+im.size, 0, None)]) ImageFile._save(im, fp, [("eps", (0,0)+im.size, 0, None)])
fp.write("\n%%%%EndBinary\n") fp.write(b"\n%%%%EndBinary\n")
fp.write("grestore end\n") fp.write(b"grestore end\n")
fp.flush() fp.flush()
# #

View File

@ -26,7 +26,7 @@ def register_handler(handler):
# Image adapter # Image adapter
def _accept(prefix): def _accept(prefix):
return prefix[:6] == "SIMPLE" return prefix[:6] == b"SIMPLE"
class FITSStubImageFile(ImageFile.StubImageFile): class FITSStubImageFile(ImageFile.StubImageFile):

View File

@ -18,14 +18,12 @@
__version__ = "0.2" __version__ = "0.2"
from . import Image, ImageFile, ImagePalette from . import Image, ImageFile, ImagePalette, _binary
i8 = _binary.i8
def i16(c): i16 = _binary.i16le
return ord(c[0]) + (ord(c[1])<<8) i32 = _binary.i32le
o8 = _binary.o8
def i32(c):
return ord(c[0]) + (ord(c[1])<<8) + (ord(c[2])<<16) + (ord(c[3])<<24)
# #
# decoder # decoder
@ -82,7 +80,7 @@ class FliImageFile(ImageFile.ImageFile):
elif i16(s[4:6]) == 4: elif i16(s[4:6]) == 4:
self._palette(palette, 0) self._palette(palette, 0)
palette = [chr(r)+chr(g)+chr(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", "".join(palette)) self.palette = ImagePalette.raw("RGB", "".join(palette))
# set things up to decode first frame # set things up to decode first frame
@ -97,15 +95,15 @@ class FliImageFile(ImageFile.ImageFile):
i = 0 i = 0
for e in range(i16(self.fp.read(2))): for e in range(i16(self.fp.read(2))):
s = self.fp.read(2) s = self.fp.read(2)
i = i + ord(s[0]) i = i + i8(s[0])
n = ord(s[1]) n = i8(s[1])
if n == 0: if n == 0:
n = 256 n = 256
s = self.fp.read(n * 3) s = self.fp.read(n * 3)
for n in range(0, len(s), 3): for n in range(0, len(s), 3):
r = ord(s[n]) << shift r = i8(s[n]) << shift
g = ord(s[n+1]) << shift g = i8(s[n+1]) << shift
b = ord(s[n+2]) << shift b = i8(s[n+2]) << shift
palette[i] = (r, g, b) palette[i] = (r, g, b)
i = i + 1 i = i + 1

View File

@ -15,7 +15,7 @@
# #
import os import os
from . import Image from . import Image, _binary
import marshal import marshal
@ -31,7 +31,7 @@ def puti16(fp, values):
for v in values: for v in values:
if v < 0: if v < 0:
v = v + 65536 v = v + 65536
fp.write(chr(v>>8&255) + chr(v&255)) fp.write(_binary.o16be(v))
## ##
# Base class for raster font file handlers. # Base class for raster font file handlers.
@ -106,9 +106,9 @@ class FontFile:
# font metrics # font metrics
fp = open(os.path.splitext(filename)[0] + ".pil", "wb") fp = open(os.path.splitext(filename)[0] + ".pil", "wb")
fp.write("PILfont\n") fp.write(b"PILfont\n")
fp.write(";;;;;;%d;\n" % self.ysize) # HACK!!! fp.write((";;;;;;%d;\n" % self.ysize).encode('ascii')) # HACK!!!
fp.write("DATA\n") fp.write(b"DATA\n")
for id in range(256): for id in range(256):
m = self.metrics[id] m = self.metrics[id]
if not m: if not m:
@ -128,13 +128,13 @@ class FontFile:
data = marshal.dumps((self.metrics, self.info)) data = marshal.dumps((self.metrics, self.info))
if zlib: if zlib:
data = "z" + zlib.compress(data, 9) data = b"z" + zlib.compress(data, 9)
else: else:
data = "u" + data data = b"u" + data
fp = open(os.path.splitext(filename)[0] + ".pil", "wb") fp = open(os.path.splitext(filename)[0] + ".pil", "wb")
fp.write("PILfont2\n" + self.name + "\n" + "DATA\n") fp.write(b"PILfont2\n" + self.name + "\n" + "DATA\n")
fp.write(data) fp.write(data)

View File

@ -170,8 +170,8 @@ class FpxImageFile(ImageFile.ImageFile):
elif compression == 2: elif compression == 2:
internal_color_conversion = ord(s[14]) internal_color_conversion = i8(s[14])
jpeg_tables = ord(s[15]) jpeg_tables = i8(s[15])
rawmode = self.rawmode rawmode = self.rawmode
if internal_color_conversion: if internal_color_conversion:

View File

@ -13,10 +13,9 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
from . import Image, ImageFile from . import Image, ImageFile, _binary
def i32(c): i32 = _binary.i32be
return ord(c[3]) + (ord(c[2])<<8) + (ord(c[1])<<16) + (ord(c[0])<<24)
def _accept(prefix): def _accept(prefix):
return i32(prefix) >= 20 and i32(prefix[4:8]) == 1 return i32(prefix) >= 20 and i32(prefix[4:8]) == 1
@ -59,8 +58,8 @@ class GbrImageFile(ImageFile.ImageFile):
# create an image out of the brush data block # create an image out of the brush data block
self.im = Image.core.new(self.mode, self.size) self.im = Image.core.new(self.mode, self.size)
self.im.fromstring(self.data) self.im.frombytes(self.data)
self.data = "" self.data = b""
# #
# registry # registry

View File

@ -25,7 +25,7 @@
__version__ = "0.1" __version__ = "0.1"
from . import ImageFile, ImagePalette from . import ImageFile, ImagePalette, _binary
try: try:
import builtins import builtins
@ -33,8 +33,7 @@ except ImportError:
import __builtin__ import __builtin__
builtins = __builtin__ builtins = __builtin__
def i16(c): i16 = _binary.i16be
return ord(c[1]) + (ord(c[0])<<8)
## ##
# Image plugin for the GD uncompressed format. Note that this format # Image plugin for the GD uncompressed format. Note that this format

View File

@ -28,24 +28,23 @@
__version__ = "0.9" __version__ = "0.9"
from . import Image, ImageFile, ImagePalette from . import Image, ImageFile, ImagePalette, _binary
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Helpers # Helpers
def i16(c): i8 = _binary.i8
return ord(c[0]) + (ord(c[1])<<8) i16 = _binary.i16le
o8 = _binary.o8
def o16(i): o16 = _binary.o16le
return chr(i&255) + chr(i>>8&255)
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Identify/read GIF files # Identify/read GIF files
def _accept(prefix): def _accept(prefix):
return prefix[:6] in ["GIF87a", "GIF89a"] return prefix[:6] in [b"GIF87a", b"GIF89a"]
## ##
# Image plugin for GIF images. This plugin supports both GIF87 and # Image plugin for GIF images. This plugin supports both GIF87 and
@ -60,15 +59,15 @@ class GifImageFile(ImageFile.ImageFile):
def data(self): def data(self):
s = self.fp.read(1) s = self.fp.read(1)
if s and ord(s): if s and i8(s):
return self.fp.read(ord(s)) return self.fp.read(i8(s))
return None return None
def _open(self): def _open(self):
# Screen # Screen
s = self.fp.read(13) s = self.fp.read(13)
if s[:6] not in ["GIF87a", "GIF89a"]: if s[:6] not in [b"GIF87a", b"GIF89a"]:
raise SyntaxError("not a GIF file") raise SyntaxError("not a GIF file")
self.info["version"] = s[:6] self.info["version"] = s[:6]
@ -77,17 +76,17 @@ class GifImageFile(ImageFile.ImageFile):
self.tile = [] self.tile = []
flags = ord(s[10]) flags = i8(s[10])
bits = (flags & 7) + 1 bits = (flags & 7) + 1
if flags & 128: if flags & 128:
# get global palette # get global palette
self.info["background"] = ord(s[11]) self.info["background"] = i8(s[11])
# check if palette contains colour indices # check if palette contains colour indices
p = self.fp.read(3<<bits) p = self.fp.read(3<<bits)
for i in range(0, len(p), 3): for i in range(0, len(p), 3):
if not (chr(i/3) == p[i] == p[i+1] == p[i+2]): if not (i//3 == i8(p[i]) == i8(p[i+1]) == i8(p[i+2])):
p = ImagePalette.raw("RGB", p) p = ImagePalette.raw("RGB", p)
self.global_palette = self.palette = p self.global_palette = self.palette = p
break break
@ -128,22 +127,22 @@ class GifImageFile(ImageFile.ImageFile):
while True: while True:
s = self.fp.read(1) s = self.fp.read(1)
if not s or s == ";": if not s or s == b";":
break break
elif s == "!": elif s == b"!":
# #
# extensions # extensions
# #
s = self.fp.read(1) s = self.fp.read(1)
block = self.data() block = self.data()
if ord(s) == 249: if i8(s) == 249:
# #
# graphic control extension # graphic control extension
# #
flags = ord(block[0]) flags = i8(block[0])
if flags & 1: if flags & 1:
self.info["transparency"] = ord(block[3]) self.info["transparency"] = i8(block[3])
self.info["duration"] = i16(block[1:3]) * 10 self.info["duration"] = i16(block[1:3]) * 10
try: try:
# disposal methods # disposal methods
@ -156,19 +155,19 @@ class GifImageFile(ImageFile.ImageFile):
self.dispose = self.im.copy() self.dispose = self.im.copy()
except (AttributeError, KeyError): except (AttributeError, KeyError):
pass pass
elif ord(s) == 255: elif i8(s) == 255:
# #
# application extension # application extension
# #
self.info["extension"] = block, self.fp.tell() self.info["extension"] = block, self.fp.tell()
if block[:11] == "NETSCAPE2.0": if block[:11] == b"NETSCAPE2.0":
block = self.data() block = self.data()
if len(block) >= 3 and ord(block[0]) == 1: if len(block) >= 3 and i8(block[0]) == 1:
self.info["loop"] = i16(block[1:3]) self.info["loop"] = i16(block[1:3])
while self.data(): while self.data():
pass pass
elif s == ",": elif s == b",":
# #
# local image # local image
# #
@ -177,7 +176,7 @@ class GifImageFile(ImageFile.ImageFile):
# extent # extent
x0, y0 = i16(s[0:]), i16(s[2:]) x0, y0 = i16(s[0:]), i16(s[2:])
x1, y1 = x0 + i16(s[4:]), y0 + i16(s[6:]) x1, y1 = x0 + i16(s[4:]), y0 + i16(s[6:])
flags = ord(s[8]) flags = i8(s[8])
interlace = (flags & 64) != 0 interlace = (flags & 64) != 0
@ -187,7 +186,7 @@ class GifImageFile(ImageFile.ImageFile):
ImagePalette.raw("RGB", self.fp.read(3<<bits)) ImagePalette.raw("RGB", self.fp.read(3<<bits))
# image data # image data
bits = ord(self.fp.read(1)) bits = i8(self.fp.read(1))
self.__offset = self.fp.tell() self.__offset = self.fp.tell()
self.tile = [("gif", self.tile = [("gif",
(x0, y0, x1, y1), (x0, y0, x1, y1),
@ -197,7 +196,7 @@ class GifImageFile(ImageFile.ImageFile):
else: else:
pass pass
# raise IOError, "illegal GIF tag `%x`" % ord(s) # raise IOError, "illegal GIF tag `%x`" % i8(s)
if not self.tile: if not self.tile:
# self.__fp = None # self.__fp = None
@ -272,29 +271,29 @@ def _save(im, fp, filename):
pass pass
else: else:
# transparency extension block # transparency extension block
fp.write("!" + fp.write(b"!" +
chr(249) + # extension intro o8(249) + # extension intro
chr(4) + # length o8(4) + # length
chr(1) + # transparency info present o8(1) + # transparency info present
o16(0) + # duration o16(0) + # duration
chr(int(transparency)) # transparency index o8(int(transparency)) # transparency index
+ chr(0)) + o8(0))
# local image header # local image header
fp.write("," + fp.write(b"," +
o16(0) + o16(0) + # bounding box o16(0) + o16(0) + # bounding box
o16(im.size[0]) + # size o16(im.size[0]) + # size
o16(im.size[1]) + o16(im.size[1]) +
chr(flags) + # flags o8(flags) + # flags
chr(8)) # bits o8(8)) # bits
imOut.encoderconfig = (8, interlace) imOut.encoderconfig = (8, interlace)
ImageFile._save(imOut, fp, [("gif", (0,0)+im.size, 0, rawmode)]) ImageFile._save(imOut, fp, [("gif", (0,0)+im.size, 0, rawmode)])
fp.write("\0") # end of image data fp.write(b"\0") # end of image data
fp.write(";") # end of file fp.write(b";") # end of file
try: try:
fp.flush() fp.flush()
@ -326,12 +325,12 @@ def getheader(im, info=None):
optimize = info and info.get("optimize", 0) optimize = info and info.get("optimize", 0)
s = [ s = [
"GIF87a" + # magic b"GIF87a" + # magic
o16(im.size[0]) + # size o16(im.size[0]) + # size
o16(im.size[1]) + o16(im.size[1]) +
chr(7 + 128) + # flags: bits + palette o8(7 + 128) + # flags: bits + palette
chr(0) + # background o8(0) + # background
chr(0) # reserved/aspect o8(0) # reserved/aspect
] ]
if optimize: if optimize:
@ -352,7 +351,7 @@ def getheader(im, info=None):
else: else:
# greyscale # greyscale
for i in range(maxcolor): for i in range(maxcolor):
s.append(chr(i) * 3) s.append(o8(i) * 3)
return s return s
@ -374,17 +373,17 @@ def getdata(im, offset = (0, 0), **params):
im.encoderinfo = params im.encoderinfo = params
# local image header # local image header
fp.write("," + fp.write(b"," +
o16(offset[0]) + # offset o16(offset[0]) + # offset
o16(offset[1]) + o16(offset[1]) +
o16(im.size[0]) + # size o16(im.size[0]) + # size
o16(im.size[1]) + o16(im.size[1]) +
chr(0) + # flags o8(0) + # flags
chr(8)) # bits o8(8)) # bits
ImageFile._save(im, fp, [("gif", (0,0)+im.size, 0, RAWMODE[im.mode])]) ImageFile._save(im, fp, [("gif", (0,0)+im.size, 0, RAWMODE[im.mode])])
fp.write("\0") # end of image data fp.write(b"\0") # end of image data
finally: finally:
del im.encoderinfo del im.encoderinfo

View File

@ -14,6 +14,7 @@
# #
from math import pi, log, sin, sqrt from math import pi, log, sin, sqrt
from ._binary import o8
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Stuff to translate curve segments to palette values (derived from # Stuff to translate curve segments to palette values (derived from
@ -78,15 +79,15 @@ class GradientFile:
scale = segment((xm - x0) / w, (x - x0) / w) scale = segment((xm - x0) / w, (x - x0) / w)
# expand to RGBA # expand to RGBA
r = chr(int(255 * ((rgb1[0] - rgb0[0]) * scale + rgb0[0]) + 0.5)) r = o8(int(255 * ((rgb1[0] - rgb0[0]) * scale + rgb0[0]) + 0.5))
g = chr(int(255 * ((rgb1[1] - rgb0[1]) * scale + rgb0[1]) + 0.5)) g = o8(int(255 * ((rgb1[1] - rgb0[1]) * scale + rgb0[1]) + 0.5))
b = chr(int(255 * ((rgb1[2] - rgb0[2]) * scale + rgb0[2]) + 0.5)) b = o8(int(255 * ((rgb1[2] - rgb0[2]) * scale + rgb0[2]) + 0.5))
a = chr(int(255 * ((rgb1[3] - rgb0[3]) * scale + rgb0[3]) + 0.5)) a = o8(int(255 * ((rgb1[3] - rgb0[3]) * scale + rgb0[3]) + 0.5))
# add to palette # add to palette
palette.append(r + g + b + a) palette.append(r + g + b + a)
return "".join(palette), "RGBA" return b"".join(palette), "RGBA"
## ##
# File handler for GIMP's gradient format. # File handler for GIMP's gradient format.
@ -95,7 +96,7 @@ class GimpGradientFile(GradientFile):
def __init__(self, fp): def __init__(self, fp):
if fp.readline()[:13] != "GIMP Gradient": if fp.readline()[:13] != b"GIMP Gradient":
raise SyntaxError("not a GIMP gradient file") raise SyntaxError("not a GIMP gradient file")
count = int(fp.readline()) count = int(fp.readline())

View File

@ -15,6 +15,7 @@
# #
import re import re
from ._binary import o8
## ##
# File handler for GIMP's palette format. # File handler for GIMP's palette format.
@ -25,9 +26,9 @@ class GimpPaletteFile:
def __init__(self, fp): def __init__(self, fp):
self.palette = [chr(i)*3 for i in range(256)] self.palette = [o8(i)*3 for i in range(256)]
if fp.readline()[:12] != "GIMP Palette": if fp.readline()[:12] != b"GIMP Palette":
raise SyntaxError("not a GIMP palette file") raise SyntaxError("not a GIMP palette file")
i = 0 i = 0
@ -39,7 +40,7 @@ class GimpPaletteFile:
if not s: if not s:
break break
# skip fields and comment lines # skip fields and comment lines
if re.match("\w+:|#", s): if re.match(b"\w+:|#", s):
continue continue
if len(s) > 100: if len(s) > 100:
raise SyntaxError("bad palette file") raise SyntaxError("bad palette file")
@ -49,11 +50,11 @@ class GimpPaletteFile:
raise ValueError("bad palette entry") raise ValueError("bad palette entry")
if 0 <= i <= 255: if 0 <= i <= 255:
self.palette[i] = chr(v[0]) + chr(v[1]) + chr(v[2]) self.palette[i] = o8(v[0]) + o8(v[1]) + o8(v[2])
i = i + 1 i = i + 1
self.palette = "".join(self.palette) self.palette = b"".join(self.palette)
def getpalette(self): def getpalette(self):

View File

@ -26,7 +26,7 @@ def register_handler(handler):
# Image adapter # Image adapter
def _accept(prefix): def _accept(prefix):
return prefix[0:4] == "GRIB" and prefix[7] == chr(1) return prefix[0:4] == b"GRIB" and prefix[7] == b'\x01'
class GribStubImageFile(ImageFile.StubImageFile): class GribStubImageFile(ImageFile.StubImageFile):

View File

@ -26,7 +26,7 @@ def register_handler(handler):
# Image adapter # Image adapter
def _accept(prefix): def _accept(prefix):
return prefix[:8] == "\x89HDF\r\n\x1a\n" return prefix[:8] == b"\x89HDF\r\n\x1a\n"
class HDF5StubImageFile(ImageFile.StubImageFile): class HDF5StubImageFile(ImageFile.StubImageFile):

View File

@ -14,9 +14,11 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
from . import Image, ImageFile from . import Image, ImageFile, _binary
import struct import struct
i8 = _binary.i8
HEADERSIZE = 8 HEADERSIZE = 8
def nextheader(fobj): def nextheader(fobj):
@ -27,7 +29,7 @@ def read_32t(fobj, start_length, size):
(start, length) = start_length (start, length) = start_length
fobj.seek(start) fobj.seek(start)
sig = fobj.read(4) sig = fobj.read(4)
if sig != '\x00\x00\x00\x00': if sig != b'\x00\x00\x00\x00':
raise SyntaxError('Unknown signature, expecting 0x00000000') raise SyntaxError('Unknown signature, expecting 0x00000000')
return read_32(fobj, (start + 4, length - 4), size) return read_32(fobj, (start + 4, length - 4), size)
@ -53,7 +55,7 @@ def read_32(fobj, start_length, size):
byte = fobj.read(1) byte = fobj.read(1)
if not byte: if not byte:
break break
byte = ord(byte) byte = i8(byte)
if byte & 0x80: if byte & 0x80:
blocksize = byte - 125 blocksize = byte - 125
byte = fobj.read(1) byte = fobj.read(1)
@ -70,7 +72,7 @@ def read_32(fobj, start_length, size):
"Error reading channel [%r left]" % bytesleft "Error reading channel [%r left]" % bytesleft
) )
band = Image.frombuffer( band = Image.frombuffer(
"L", size, "".join(data), "raw", "L", 0, 1 "L", size, b"".join(data), "raw", "L", 0, 1
) )
im.im.putband(band.im, band_ix) im.im.putband(band.im, band_ix)
return {"RGB": im} return {"RGB": im}
@ -88,20 +90,20 @@ class IcnsFile:
SIZES = { SIZES = {
(128, 128): [ (128, 128): [
('it32', read_32t), (b'it32', read_32t),
('t8mk', read_mk), (b't8mk', read_mk),
], ],
(48, 48): [ (48, 48): [
('ih32', read_32), (b'ih32', read_32),
('h8mk', read_mk), (b'h8mk', read_mk),
], ],
(32, 32): [ (32, 32): [
('il32', read_32), (b'il32', read_32),
('l8mk', read_mk), (b'l8mk', read_mk),
], ],
(16, 16): [ (16, 16): [
('is32', read_32), (b'is32', read_32),
('s8mk', read_mk), (b's8mk', read_mk),
], ],
} }
@ -204,7 +206,7 @@ class IcnsImageFile(ImageFile.ImageFile):
self.load_end() self.load_end()
Image.register_open("ICNS", IcnsImageFile, lambda x: x[:4] == 'icns') Image.register_open("ICNS", IcnsImageFile, lambda x: x[:4] == b'icns')
Image.register_extension("ICNS", '.icns') Image.register_extension("ICNS", '.icns')
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -19,21 +19,19 @@
__version__ = "0.1" __version__ = "0.1"
from . import Image, BmpImagePlugin from . import Image, BmpImagePlugin, _binary
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
def i16(c): i8 = _binary.i8
return ord(c[0]) + (ord(c[1])<<8) i16 = _binary.i16le
i32 = _binary.i32le
def i32(c):
return ord(c[0]) + (ord(c[1])<<8) + (ord(c[2])<<16) + (ord(c[3])<<24)
def _accept(prefix): def _accept(prefix):
return prefix[:4] == "\0\0\1\0" return prefix[:4] == b"\0\0\1\0"
## ##
# Image plugin for Windows Icon files. # Image plugin for Windows Icon files.
@ -56,12 +54,12 @@ class IcoImageFile(BmpImagePlugin.BmpImageFile):
s = self.fp.read(16) s = self.fp.read(16)
if not m: if not m:
m = s m = s
elif ord(s[0]) > ord(m[0]) and ord(s[1]) > ord(m[1]): elif i8(s[0]) > i8(m[0]) and i8(s[1]) > i8(m[1]):
m = s m = s
#print "width", ord(s[0]) #print "width", i8(s[0])
#print "height", ord(s[1]) #print "height", i8(s[1])
#print "colors", ord(s[2]) #print "colors", i8(s[2])
#print "reserved", ord(s[3]) #print "reserved", i8(s[3])
#print "planes", i16(s[4:]) #print "planes", i16(s[4:])
#print "bitcount", i16(s[6:]) #print "bitcount", i16(s[6:])
#print "bytes", i32(s[8:]) #print "bytes", i32(s[8:])
@ -71,7 +69,7 @@ class IcoImageFile(BmpImagePlugin.BmpImageFile):
self._bitmap(i32(m[12:])) self._bitmap(i32(m[12:]))
# patch up the bitmap height # patch up the bitmap height
self.size = self.size[0], self.size[1]/2 self.size = self.size[0], self.size[1]//2
d, e, o, a = self.tile[0] d, e, o, a = self.tile[0]
self.tile[0] = d, (0,0)+self.size, o, a self.tile[0] = d, (0,0)+self.size, o, a

View File

@ -30,6 +30,7 @@ __version__ = "0.7"
import re import re
from . import Image, ImageFile, ImagePalette from . import Image, ImageFile, ImagePalette
from ._binary import i8, o8
# -------------------------------------------------------------------- # --------------------------------------------------------------------
@ -91,7 +92,7 @@ for i in range(2, 33):
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Read IM directory # Read IM directory
split = re.compile(r"^([A-Za-z][^:]*):[ \t]*(.*)[ \t]*$") split = re.compile(br"^([A-Za-z][^:]*):[ \t]*(.*)[ \t]*$")
def number(s): def number(s):
try: try:
@ -112,7 +113,7 @@ class ImImageFile(ImageFile.ImageFile):
# Quick rejection: if there's not an LF among the first # Quick rejection: if there's not an LF among the first
# 100 bytes, this is (probably) not a text header. # 100 bytes, this is (probably) not a text header.
if not "\n" in self.fp.read(100): if not b"\n" in self.fp.read(100):
raise SyntaxError("not an IM file") raise SyntaxError("not an IM file")
self.fp.seek(0) self.fp.seek(0)
@ -130,10 +131,10 @@ class ImImageFile(ImageFile.ImageFile):
s = self.fp.read(1) s = self.fp.read(1)
# Some versions of IFUNC uses \n\r instead of \r\n... # Some versions of IFUNC uses \n\r instead of \r\n...
if s == "\r": if s == b"\r":
continue continue
if not s or s[0] == chr(0) or s[0] == chr(26): if not s or s == b'\0' or s == b'\x1A':
break break
# FIXME: this may read whole file if not a text file # FIXME: this may read whole file if not a text file
@ -142,9 +143,9 @@ class ImImageFile(ImageFile.ImageFile):
if len(s) > 100: if len(s) > 100:
raise SyntaxError("not an IM file") raise SyntaxError("not an IM file")
if s[-2:] == '\r\n': if s[-2:] == b'\r\n':
s = s[:-2] s = s[:-2]
elif s[-1:] == '\n': elif s[-1:] == b'\n':
s = s[:-1] s = s[:-1]
try: try:
@ -156,6 +157,11 @@ class ImImageFile(ImageFile.ImageFile):
k, v = m.group(1,2) 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 # Convert value as appropriate
if k in [FRAMES, SCALE, SIZE]: if k in [FRAMES, SCALE, SIZE]:
v = v.replace("*", ",") v = v.replace("*", ",")
@ -180,7 +186,7 @@ class ImImageFile(ImageFile.ImageFile):
else: else:
raise SyntaxError("Syntax error in IM header: " + s) raise SyntaxError("Syntax error in IM header: " + s.decode('ascii', 'replace'))
if not n: if not n:
raise SyntaxError("Not an IM file") raise SyntaxError("Not an IM file")
@ -190,7 +196,7 @@ class ImImageFile(ImageFile.ImageFile):
self.mode = self.info[MODE] self.mode = self.info[MODE]
# Skip forward to start of image data # Skip forward to start of image data
while s and s[0] != chr(26): while s and s[0:1] != b'\x1A':
s = self.fp.read(1) s = self.fp.read(1)
if not s: if not s:
raise SyntaxError("File truncated") raise SyntaxError("File truncated")
@ -202,14 +208,14 @@ class ImImageFile(ImageFile.ImageFile):
linear = 1 # linear greyscale palette linear = 1 # linear greyscale palette
for i in range(256): for i in range(256):
if palette[i] == palette[i+256] == palette[i+512]: if palette[i] == palette[i+256] == palette[i+512]:
if palette[i] != chr(i): if i8(palette[i]) != i:
linear = 0 linear = 0
else: else:
greyscale = 0 greyscale = 0
if self.mode == "L" or self.mode == "LA": if self.mode == "L" or self.mode == "LA":
if greyscale: if greyscale:
if not linear: if not linear:
self.lut = [ord(c) for c in palette[:256]] self.lut = [i8(c) for c in palette[:256]]
else: else:
if self.mode == "L": if self.mode == "L":
self.mode = self.rawmode = "P" self.mode = self.rawmode = "P"
@ -218,7 +224,7 @@ class ImImageFile(ImageFile.ImageFile):
self.palette = ImagePalette.raw("RGB;L", palette) self.palette = ImagePalette.raw("RGB;L", palette)
elif self.mode == "RGB": elif self.mode == "RGB":
if not greyscale or not linear: if not greyscale or not linear:
self.lut = [ord(c) for c in palette] self.lut = [i8(c) for c in palette]
self.frame = 0 self.frame = 0
@ -265,7 +271,7 @@ class ImImageFile(ImageFile.ImageFile):
else: else:
bits = 8 * len(self.mode) bits = 8 * len(self.mode)
size = ((self.size[0] * bits + 7) / 8) * self.size[1] size = ((self.size[0] * bits + 7) // 8) * self.size[1]
offs = self.__offset + frame * size offs = self.__offset + frame * size
self.fp = self.__fp self.fp = self.__fp
@ -314,14 +320,14 @@ def _save(im, fp, filename, check=0):
if check: if check:
return check return check
fp.write("Image type: %s image\r\n" % type) fp.write(("Image type: %s image\r\n" % type).encode('ascii'))
if filename: if filename:
fp.write("Name: %s\r\n" % filename) fp.write(("Name: %s\r\n" % filename).encode('ascii'))
fp.write("Image size (x*y): %d*%d\r\n" % im.size) fp.write(("Image size (x*y): %d*%d\r\n" % im.size).encode('ascii'))
fp.write("File size (no of images): %d\r\n" % frames) fp.write(("File size (no of images): %d\r\n" % frames).encode('ascii'))
if im.mode == "P": if im.mode == "P":
fp.write("Lut: 1\r\n") fp.write(b"Lut: 1\r\n")
fp.write("\000" * (511-fp.tell()) + "\032") fp.write(b"\000" * (511-fp.tell()) + b"\032")
if im.mode == "P": if im.mode == "P":
fp.write(im.im.getpalette("RGB", "RGB;L")) # 768 bytes fp.write(im.im.getpalette("RGB", "RGB;L")) # 768 bytes
ImageFile._save(im, fp, [("raw", (0,0)+im.size, 0, (rawmode, 0, -1))]) ImageFile._save(im, fp, [("raw", (0,0)+im.size, 0, (rawmode, 0, -1))])

View File

@ -73,6 +73,7 @@ except ImportError:
builtins = __builtin__ builtins = __builtin__
from . import ImageMode from . import ImageMode
from ._binary import i8, o8
import os, sys import os, sys
@ -80,12 +81,12 @@ import os, sys
import collections import collections
import numbers import numbers
if sys.version_info >= (3,0): if bytes is str:
def isStringType(t):
return isinstance(t, str)
else:
def isStringType(t): def isStringType(t):
return isinstance(t, basestring) return isinstance(t, basestring)
else:
def isStringType(t):
return isinstance(t, str)
## ##
# (Internal) Checks if an object is an image object. # (Internal) Checks if an object is an image object.
@ -181,16 +182,7 @@ _MODEINFO = {
} }
try: if sys.byteorder == 'little':
byteorder = sys.byteorder
except AttributeError:
import struct
if struct.unpack("h", "\0\1")[0] == 1:
byteorder = "big"
else:
byteorder = "little"
if byteorder == 'little':
_ENDIAN = '<' _ENDIAN = '<'
else: else:
_ENDIAN = '>' _ENDIAN = '>'
@ -358,7 +350,7 @@ def init():
return 1 return 1
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Codec factories (used by tostring/fromstring and ImageFile.load) # Codec factories (used by tobytes/frombytes and ImageFile.load)
def _getdecoder(mode, decoder_name, args, extra=()): def _getdecoder(mode, decoder_name, args, extra=()):
@ -436,7 +428,7 @@ def _getscaleoffset(expr):
# #
# @see #open # @see #open
# @see #new # @see #new
# @see #fromstring # @see #frombytes
class Image: class Image:
@ -505,7 +497,7 @@ class Image:
shape, typestr = _conv_type_shape(self) shape, typestr = _conv_type_shape(self)
new['shape'] = shape new['shape'] = shape
new['typestr'] = typestr new['typestr'] = typestr
new['data'] = self.tostring() new['data'] = self.tobytes()
return new return new
raise AttributeError(name) raise AttributeError(name)
@ -515,10 +507,10 @@ class Image:
# @param encoder_name What encoder to use. The default is to # @param encoder_name What encoder to use. The default is to
# use the standard "raw" encoder. # use the standard "raw" encoder.
# @param *args Extra arguments to the encoder. # @param *args Extra arguments to the encoder.
# @return An 8-bit string. # @return A bytes object.
def tostring(self, encoder_name="raw", *args): def tobytes(self, encoder_name="raw", *args):
"Return image as a binary string" "Return image as a bytes object"
# may pass tuple instead of argument list # may pass tuple instead of argument list
if len(args) == 1 and isinstance(args[0], tuple): if len(args) == 1 and isinstance(args[0], tuple):
@ -542,9 +534,13 @@ class Image:
if s: if s:
break break
if s < 0: if s < 0:
raise RuntimeError("encoder error %d in tostring" % s) raise RuntimeError("encoder error %d in tobytes" % s)
return "".join(data) return b"".join(data)
if bytes is str:
# Declare tostring as alias to tobytes
tostring = tobytes
## ##
# Returns the image converted to an X11 bitmap. This method # Returns the image converted to an X11 bitmap. This method
@ -560,20 +556,20 @@ class Image:
self.load() self.load()
if self.mode != "1": if self.mode != "1":
raise ValueError("not a bitmap") raise ValueError("not a bitmap")
data = self.tostring("xbm") data = self.tobytes("xbm")
return "".join(["#define %s_width %d\n" % (name, self.size[0]), return b"".join([("#define %s_width %d\n" % (name, self.size[0])).encode('ascii'),
"#define %s_height %d\n"% (name, self.size[1]), ("#define %s_height %d\n"% (name, self.size[1])).encode('ascii'),
"static char %s_bits[] = {\n" % name, data, "};"]) ("static char %s_bits[] = {\n" % name).encode('ascii'), data, b"};"])
## ##
# Loads this image with pixel data from a string. # Loads this image with pixel data from a bytes object.
# <p> # <p>
# This method is similar to the {@link #fromstring} function, but # This method is similar to the {@link #frombytes} function, but
# loads data into this image instead of creating a new image # loads data into this image instead of creating a new image
# object. # object.
def fromstring(self, data, decoder_name="raw", *args): def frombytes(self, data, decoder_name="raw", *args):
"Load data to image from binary string" "Load data to image from a bytes object"
# may pass tuple instead of argument list # may pass tuple instead of argument list
if len(args) == 1 and isinstance(args[0], tuple): if len(args) == 1 and isinstance(args[0], tuple):
@ -593,6 +589,10 @@ class Image:
if s[1] != 0: if s[1] != 0:
raise ValueError("cannot decode image data") raise ValueError("cannot decode image data")
if bytes is str:
# Declare fromstring as alias to frombytes
fromstring = frombytes
## ##
# Allocates storage for the image and loads the pixel data. In # Allocates storage for the image and loads the pixel data. In
# normal cases, you don't need to call this method, since the # normal cases, you don't need to call this method, since the
@ -929,7 +929,10 @@ class Image:
self.load() self.load()
try: try:
return [ord(c) for c in self.im.getpalette()] if bytes is str:
return [i8(c) for c in self.im.getpalette()]
else:
return list(self.im.getpalette())
except ValueError: except ValueError:
return None # no palette return None # no palette
@ -958,7 +961,7 @@ class Image:
self.load() self.load()
x, y = self.im.getprojection() x, y = self.im.getprojection()
return [ord(c) for c in x], [ord(c) for c in y] return [i8(c) for c in x], [i8(c) for c in y]
## ##
# Returns a histogram for the image. The histogram is returned as # Returns a histogram for the image. The histogram is returned as
@ -1233,8 +1236,11 @@ class Image:
if isinstance(data, ImagePalette.ImagePalette): if isinstance(data, ImagePalette.ImagePalette):
palette = ImagePalette.raw(data.rawmode, data.palette) palette = ImagePalette.raw(data.rawmode, data.palette)
else: else:
if not isStringType(data): if not isinstance(data, bytes):
data = "".join(map(chr, data)) if bytes is str:
data = "".join(chr(x) for x in data)
else:
data = bytes(data)
palette = ImagePalette.raw(rawmode, data) palette = ImagePalette.raw(rawmode, data)
self.mode = "P" self.mode = "P"
self.palette = palette self.palette = palette
@ -1762,7 +1768,7 @@ def new(mode, size, color=0):
return Image()._new(core.fill(mode, size, color)) return Image()._new(core.fill(mode, size, color))
## ##
# Creates an image memory from pixel data in a string. # Creates a copy of an image memory from pixel data in a buffer.
# <p> # <p>
# In its simplest form, this function takes three arguments # In its simplest form, this function takes three arguments
# (mode, size, and unpacked pixel data). # (mode, size, and unpacked pixel data).
@ -1773,17 +1779,17 @@ def new(mode, size, color=0):
# <p> # <p>
# Note that this function decodes pixel data only, not entire images. # Note that this function decodes pixel data only, not entire images.
# If you have an entire image in a string, wrap it in a # If you have an entire image in a string, wrap it in a
# <b>StringIO</b> object, and use {@link #open} to load it. # <b>BytesIO</b> object, and use {@link #open} to load it.
# #
# @param mode The image mode. # @param mode The image mode.
# @param size The image size. # @param size The image size.
# @param data An 8-bit string containing raw data for the given mode. # @param data A byte buffer containing raw data for the given mode.
# @param decoder_name What decoder to use. # @param decoder_name What decoder to use.
# @param *args Additional parameters for the given decoder. # @param *args Additional parameters for the given decoder.
# @return An Image object. # @return An Image object.
def fromstring(mode, size, data, decoder_name="raw", *args): def frombytes(mode, size, data, decoder_name="raw", *args):
"Load image from string" "Load image from byte buffer"
# may pass tuple instead of argument list # may pass tuple instead of argument list
if len(args) == 1 and isinstance(args[0], tuple): if len(args) == 1 and isinstance(args[0], tuple):
@ -1793,14 +1799,18 @@ def fromstring(mode, size, data, decoder_name="raw", *args):
args = mode args = mode
im = new(mode, size) im = new(mode, size)
im.fromstring(data, decoder_name, args) im.frombytes(data, decoder_name, args)
return im return im
if bytes is str:
# Declare fromstring as an alias for frombytes
fromstring = frombytes
## ##
# (New in 1.1.4) Creates an image memory from pixel data in a string # (New in 1.1.4) Creates an image memory referencing pixel data in a
# or byte buffer. # byte buffer.
# <p> # <p>
# This function is similar to {@link #fromstring}, but uses data in # This function is similar to {@link #frombytes}, but uses data in
# the byte buffer, where possible. This means that changes to the # the byte buffer, where possible. This means that changes to the
# original buffer object are reflected in this image). Not all modes # original buffer object are reflected in this image). Not all modes
# can share memory; supported modes include "L", "RGBX", "RGBA", and # can share memory; supported modes include "L", "RGBX", "RGBA", and
@ -1808,7 +1818,7 @@ def fromstring(mode, size, data, decoder_name="raw", *args):
# <p> # <p>
# Note that this function decodes pixel data only, not entire images. # Note that this function decodes pixel data only, not entire images.
# If you have an entire image file in a string, wrap it in a # If you have an entire image file in a string, wrap it in a
# <b>StringIO</b> object, and use {@link #open} to load it. # <b>BytesIO</b> object, and use {@link #open} to load it.
# <p> # <p>
# In the current version, the default parameters used for the "raw" # In the current version, the default parameters used for the "raw"
# decoder differs from that used for {@link fromstring}. This is a # decoder differs from that used for {@link fromstring}. This is a
@ -1819,7 +1829,7 @@ def fromstring(mode, size, data, decoder_name="raw", *args):
# #
# @param mode The image mode. # @param mode The image mode.
# @param size The image size. # @param size The image size.
# @param data An 8-bit string or other buffer object containing raw # @param data A bytes or other buffer object containing raw
# data for the given mode. # data for the given mode.
# @param decoder_name What decoder to use. # @param decoder_name What decoder to use.
# @param *args Additional parameters for the given decoder. For the # @param *args Additional parameters for the given decoder. For the
@ -1830,7 +1840,7 @@ def fromstring(mode, size, data, decoder_name="raw", *args):
# @since 1.1.4 # @since 1.1.4
def frombuffer(mode, size, data, decoder_name="raw", *args): def frombuffer(mode, size, data, decoder_name="raw", *args):
"Load image from string or buffer" "Load image from bytes or buffer"
# may pass tuple instead of argument list # may pass tuple instead of argument list
if len(args) == 1 and isinstance(args[0], tuple): if len(args) == 1 and isinstance(args[0], tuple):
@ -1854,14 +1864,14 @@ def frombuffer(mode, size, data, decoder_name="raw", *args):
im.readonly = 1 im.readonly = 1
return im return im
return fromstring(mode, size, data, decoder_name, args) return frombytes(mode, size, data, decoder_name, args)
## ##
# (New in 1.1.6) Creates an image memory from an object exporting # (New in 1.1.6) Creates an image memory from an object exporting
# the array interface (using the buffer protocol). # the array interface (using the buffer protocol).
# #
# If obj is not contiguous, then the tostring method is called # If obj is not contiguous, then the tobytes method is called
# and {@link frombuffer} is used. # and {@link frombuffer} is used.
# #
# @param obj Object with array interface # @param obj Object with array interface
@ -1896,7 +1906,7 @@ def fromarray(obj, mode=None):
size = shape[1], shape[0] size = shape[1], shape[0]
if strides is not None: if strides is not None:
obj = obj.tostring() obj = obj.tobytes()
return frombuffer(mode, size, obj, "raw", rawmode, 0, 1) return frombuffer(mode, size, obj, "raw", rawmode, 0, 1)
@ -1962,6 +1972,8 @@ def open(fp, mode="r"):
fp.seek(0) fp.seek(0)
return factory(fp, filename) return factory(fp, filename)
except (SyntaxError, IndexError, TypeError): except (SyntaxError, IndexError, TypeError):
#import traceback
#traceback.print_exc()
pass pass
if init(): if init():
@ -1973,6 +1985,8 @@ def open(fp, mode="r"):
fp.seek(0) fp.seek(0)
return factory(fp, filename) return factory(fp, filename)
except (SyntaxError, IndexError, TypeError): except (SyntaxError, IndexError, TypeError):
#import traceback
#traceback.print_exc()
pass pass
raise IOError("cannot identify image file") raise IOError("cannot identify image file")

View File

@ -142,7 +142,7 @@ class ImageCmsProfile:
if Image.isStringType(profile): if Image.isStringType(profile):
self._set(core.profile_open(profile), profile) self._set(core.profile_open(profile), profile)
elif hasattr(profile, "read"): elif hasattr(profile, "read"):
self._set(core.profile_fromstring(profile.read())) self._set(core.profile_frombytes(profile.read()))
else: else:
self._set(profile) # assume it's already a profile self._set(profile) # assume it's already a profile

View File

@ -99,7 +99,7 @@ def getcolor(color, mode):
return r, g, b, 255 return r, g, b, 255
if Image.getmodebase(mode) == "L": if Image.getmodebase(mode) == "L":
r, g, b = color r, g, b = color
return (r*299 + g*587 + b*114)/1000 return (r*299 + g*587 + b*114)//1000
return color return color
colormap = { colormap = {

View File

@ -184,7 +184,7 @@ class ImageFile(Image.Image):
# FIXME: This is a hack to handle TIFF's JpegTables tag. # FIXME: This is a hack to handle TIFF's JpegTables tag.
prefix = self.tile_prefix prefix = self.tile_prefix
except AttributeError: except AttributeError:
prefix = "" prefix = b""
for d, e, o, a in self.tile: for d, e, o, a in self.tile:
d = Image._getdecoder(self.mode, d, a, self.decoderconfig) d = Image._getdecoder(self.mode, d, a, self.decoderconfig)
@ -314,13 +314,13 @@ class _ParserFile:
def readline(self): def readline(self):
# FIXME: this is slow! # FIXME: this is slow!
s = "" s = b""
while True: while True:
c = self.read(1) c = self.read(1)
if not c: if not c:
break break
s = s + c s = s + c
if c == "\n": if c == b"\n":
break break
return s return s
@ -404,6 +404,7 @@ class Parser:
finally: finally:
fp.close() # explicitly close the virtual file fp.close() # explicitly close the virtual file
except IOError: except IOError:
# traceback.print_exc()
pass # not enough data pass # not enough data
else: else:
flag = hasattr(im, "load_seek") or hasattr(im, "load_read") flag = hasattr(im, "load_seek") or hasattr(im, "load_read")
@ -438,7 +439,7 @@ class Parser:
# finish decoding # finish decoding
if self.decoder: if self.decoder:
# get rid of what's left in the buffers # get rid of what's left in the buffers
self.feed("") self.feed(b"")
self.data = self.decoder = None self.data = self.decoder = None
if not self.finished: if not self.finished:
raise IOError("image was incomplete") raise IOError("image was incomplete")
@ -516,7 +517,7 @@ def _save(im, fp, tile):
def _safe_read(fp, size): def _safe_read(fp, size):
if size <= 0: if size <= 0:
return "" return b""
if size <= SAFEBLOCK: if size <= SAFEBLOCK:
return fp.read(size) return fp.read(size)
data = [] data = []
@ -526,4 +527,4 @@ def _safe_read(fp, size):
break break
data.append(block) data.append(block)
size = size - len(block) size = size - len(block)
return "".join(data) return b"".join(data)

View File

@ -82,7 +82,7 @@ class RankFilter(Filter):
def filter(self, image): def filter(self, image):
if image.mode == "P": if image.mode == "P":
raise ValueError("cannot filter palette images") raise ValueError("cannot filter palette images")
image = image.expand(self.size/2, self.size/2) image = image.expand(self.size//2, self.size//2)
return image.rankfilter(self.size, self.rank) return image.rankfilter(self.size, self.rank)
## ##
@ -99,7 +99,7 @@ class MedianFilter(RankFilter):
def __init__(self, size=3): def __init__(self, size=3):
self.size = size self.size = size
self.rank = size*size/2 self.rank = size*size//2
## ##
# Min filter. Picks the lowest pixel value in a window with the given # Min filter. Picks the lowest pixel value in a window with the given

View File

@ -99,13 +99,13 @@ class ImageFont:
def _load_pilfont_data(self, file, image): def _load_pilfont_data(self, file, image):
# read PILfont header # read PILfont header
if file.readline() != "PILfont\n": if file.readline() != b"PILfont\n":
raise SyntaxError("Not a PILfont file") raise SyntaxError("Not a PILfont file")
d = file.readline().split(";") d = file.readline().split(b";")
self.info = [] # FIXME: should be a dictionary self.info = [] # FIXME: should be a dictionary
while True: while True:
s = file.readline() s = file.readline()
if not s or s == "DATA\n": if not s or s == b"DATA\n":
break break
self.info.append(s) self.info.append(s)

View File

@ -45,7 +45,7 @@ except AttributeError:
def grab(bbox=None): def grab(bbox=None):
size, data = grabber() size, data = grabber()
im = Image.fromstring( im = Image.frombytes(
"RGB", size, data, "RGB", size, data,
# RGB, 32-bit line padding, origo in lower left corner # RGB, 32-bit line padding, origo in lower left corner
"raw", "BGR", (size[0]*3 + 3) & -4, -1 "raw", "BGR", (size[0]*3 + 3) & -4, -1
@ -65,7 +65,7 @@ def grab(bbox=None):
def grabclipboard(): def grabclipboard():
debug = 0 # temporary interface debug = 0 # temporary interface
data = Image.core.grabclipboard(debug) data = Image.core.grabclipboard(debug)
if Image.isStringType(data): if isinstance(data, bytes):
from . import BmpImagePlugin from . import BmpImagePlugin
import io import io
return BmpImagePlugin.DibImageFile(io.BytesIO(data)) return BmpImagePlugin.DibImageFile(io.BytesIO(data))

View File

@ -91,14 +91,14 @@ class _Operand:
return _Operand(out) return _Operand(out)
# unary operators # unary operators
if sys.version_info >= (3,0): def __bool__(self):
def __bool__(self): # an image is "true" if it contains at least one non-zero pixel
# an image is "true" if it contains at least one non-zero pixel return self.im.getbbox() is not None
return self.im.getbbox() is not None
else: if bytes is str:
def __nonzero__(self): # Provide __nonzero__ for pre-Py3k
# an image is "true" if it contains at least one non-zero pixel __nonzero__ = __bool__
return self.im.getbbox() is not None del __bool__
def __abs__(self): def __abs__(self):
return self.apply("abs", self) return self.apply("abs", self)
@ -120,9 +120,9 @@ class _Operand:
return self.apply("mul", self, other) return self.apply("mul", self, other)
def __rmul__(self, other): def __rmul__(self, other):
return self.apply("mul", other, self) return self.apply("mul", other, self)
def __div__(self, other): def __truediv__(self, other):
return self.apply("div", self, other) return self.apply("div", self, other)
def __rdiv__(self, other): def __rtruediv__(self, other):
return self.apply("div", other, self) return self.apply("div", other, self)
def __mod__(self, other): def __mod__(self, other):
return self.apply("mod", self, other) return self.apply("mod", self, other)
@ -133,6 +133,13 @@ class _Operand:
def __rpow__(self, other): def __rpow__(self, other):
return self.apply("pow", other, self) return self.apply("pow", other, self)
if bytes is str:
# Provide __div__ and __rdiv__ for pre-Py3k
__div__ = __truediv__
__rdiv__ = __rtruediv__
del __truediv__
del __rtruediv__
# bitwise # bitwise
def __invert__(self): def __invert__(self):
return self.apply("invert", self) return self.apply("invert", self)

View File

@ -95,7 +95,7 @@ def autocontrast(image, cutoff=0, ignore=None):
for ix in range(256): for ix in range(256):
n = n + h[ix] n = n + h[ix]
# remove cutoff% pixels from the low end # remove cutoff% pixels from the low end
cut = n * cutoff / 100 cut = n * cutoff // 100
for lo in range(256): for lo in range(256):
if cut > h[lo]: if cut > h[lo]:
cut = cut - h[lo] cut = cut - h[lo]
@ -106,7 +106,7 @@ def autocontrast(image, cutoff=0, ignore=None):
if cut <= 0: if cut <= 0:
break break
# remove cutoff% samples from the hi end # remove cutoff% samples from the hi end
cut = n * cutoff / 100 cut = n * cutoff // 100
for hi in range(255, -1, -1): for hi in range(255, -1, -1):
if cut > h[hi]: if cut > h[hi]:
cut = cut - h[hi] cut = cut - h[hi]
@ -125,7 +125,7 @@ def autocontrast(image, cutoff=0, ignore=None):
break break
if hi <= lo: if hi <= lo:
# don't bother # don't bother
lut.extend(range(256)) lut.extend(list(range(256)))
else: else:
scale = 255.0 / (hi - lo) scale = 255.0 / (hi - lo)
offset = -lo * scale offset = -lo * scale
@ -156,9 +156,9 @@ def colorize(image, black, white):
white = _color(white, "RGB") white = _color(white, "RGB")
red = []; green = []; blue = [] red = []; green = []; blue = []
for i in range(256): for i in range(256):
red.append(black[0]+i*(white[0]-black[0])/255) red.append(black[0]+i*(white[0]-black[0])//255)
green.append(black[1]+i*(white[1]-black[1])/255) green.append(black[1]+i*(white[1]-black[1])//255)
blue.append(black[2]+i*(white[2]-black[2])/255) blue.append(black[2]+i*(white[2]-black[2])//255)
image = image.convert("RGB") image = image.convert("RGB")
return _lut(image, red + green + blue) return _lut(image, red + green + blue)
@ -212,15 +212,15 @@ def equalize(image, mask=None):
for b in range(0, len(h), 256): for b in range(0, len(h), 256):
histo = [_f for _f in h[b:b+256] if _f] histo = [_f for _f in h[b:b+256] if _f]
if len(histo) <= 1: if len(histo) <= 1:
lut.extend(range(256)) lut.extend(list(range(256)))
else: else:
step = (reduce(operator.add, histo) - histo[-1]) / 255 step = (reduce(operator.add, histo) - histo[-1]) // 255
if not step: if not step:
lut.extend(range(256)) lut.extend(list(range(256)))
else: else:
n = step / 2 n = step // 2
for i in range(256): for i in range(256):
lut.append(n / step) lut.append(n // step)
n = n + h[i+b] n = n + h[i+b]
return _lut(image, lut) return _lut(image, lut)

View File

@ -39,16 +39,20 @@ class ImagePalette:
# for the low-level im.putpalette primitive # for the low-level im.putpalette primitive
if self.rawmode: if self.rawmode:
return self.rawmode, self.palette return self.rawmode, self.palette
return self.mode + ";L", self.tostring() return self.mode + ";L", self.tobytes()
def tostring(self): def tobytes(self):
# experimental: convert palette to string # experimental: convert palette to bytes
if self.rawmode: if self.rawmode:
raise ValueError("palette contains raw palette data") raise ValueError("palette contains raw palette data")
if Image.isStringType(self.palette): if isinstance(self.palette, bytes):
return self.palette return self.palette
return array.array("B", self.palette).tostring() return array.array("B", self.palette).tostring()
if bytes is str:
# Declare tostring as an alias for tobytes
tostring = tobytes
def getcolor(self, color): def getcolor(self, color):
# experimental: given an rgb tuple, allocate palette entry # experimental: given an rgb tuple, allocate palette entry
if self.rawmode: if self.rawmode:
@ -58,7 +62,7 @@ class ImagePalette:
return self.colors[color] return self.colors[color]
except KeyError: except KeyError:
# allocate new color slot # allocate new color slot
if Image.isStringType(self.palette): if isinstance(self.palette, bytes):
self.palette = [int(x) for x in self.palette] self.palette = [int(x) for x in self.palette]
index = len(self.colors) index = len(self.colors)
if index >= 256: if index >= 256:
@ -104,7 +108,7 @@ def _make_linear_lut(black, white):
lut = [] lut = []
if black == 0: if black == 0:
for i in range(256): for i in range(256):
lut.append(white*i/255) lut.append(white*i//255)
else: else:
raise NotImplementedError # FIXME raise NotImplementedError # FIXME
return lut return lut
@ -155,6 +159,8 @@ def load(filename):
p = GimpPaletteFile.GimpPaletteFile(fp) p = GimpPaletteFile.GimpPaletteFile(fp)
lut = p.getpalette() lut = p.getpalette()
except (SyntaxError, ValueError): except (SyntaxError, ValueError):
#import traceback
#traceback.print_exc()
pass pass
if not lut: if not lut:
@ -164,6 +170,8 @@ def load(filename):
p = GimpGradientFile.GimpGradientFile(fp) p = GimpGradientFile.GimpGradientFile(fp)
lut = p.getpalette() lut = p.getpalette()
except (SyntaxError, ValueError): except (SyntaxError, ValueError):
#import traceback
#traceback.print_exc()
pass pass
if not lut: if not lut:
@ -173,6 +181,8 @@ def load(filename):
p = PaletteFile.PaletteFile(fp) p = PaletteFile.PaletteFile(fp)
lut = p.getpalette() lut = p.getpalette()
except (SyntaxError, ValueError): except (SyntaxError, ValueError):
import traceback
traceback.print_exc()
pass pass
if not lut: if not lut:

View File

@ -62,11 +62,11 @@ class ImageQt(QImage):
for i in range(0, len(palette), 3): for i in range(0, len(palette), 3):
colortable.append(rgb(*palette[i:i+3])) colortable.append(rgb(*palette[i:i+3]))
elif im.mode == "RGB": elif im.mode == "RGB":
data = im.tostring("raw", "BGRX") data = im.tobytes("raw", "BGRX")
format = QImage.Format_RGB32 format = QImage.Format_RGB32
elif im.mode == "RGBA": elif im.mode == "RGBA":
try: try:
data = im.tostring("raw", "BGRA") data = im.tobytes("raw", "BGRA")
except SystemError: except SystemError:
# workaround for earlier versions # workaround for earlier versions
r, g, b, a = im.split() r, g, b, a = im.split()
@ -76,7 +76,7 @@ class ImageQt(QImage):
raise ValueError("unsupported image mode %r" % im.mode) raise ValueError("unsupported image mode %r" % im.mode)
# must keep a reference, or Qt will crash! # must keep a reference, or Qt will crash!
self.__data = data or im.tostring() self.__data = data or im.tobytes()
QImage.__init__(self, self.__data, im.size[0], im.size[1], format) QImage.__init__(self, self.__data, im.size[0], im.size[1], format)

View File

@ -127,7 +127,7 @@ class Stat:
v = [] v = []
for i in self.bands: for i in self.bands:
s = 0 s = 0
l = self.count[i]/2 l = self.count[i]//2
b = i * 256 b = i * 256
for j in range(256): for j in range(256):
s = s + self.h[b+j] s = s + self.h[b+j]

View File

@ -151,22 +151,25 @@ class Dib:
self.image.paste(im.im) self.image.paste(im.im)
## ##
# Load display memory contents from string buffer. # Load display memory contents from byte data.
# #
# @param buffer A string buffer containing display data (usually # @param buffer A buffer containing display data (usually
# data returned from <b>tostring</b>) # data returned from <b>tobytes</b>)
def fromstring(self, buffer): def frombytes(self, buffer):
return self.image.fromstring(buffer) return self.image.frombytes(buffer)
## ##
# Copy display memory contents to string buffer. # Copy display memory contents to bytes object.
# #
# @return A string buffer containing display data. # @return A bytes object containing display data.
def tostring(self): def tobytes(self):
return self.image.tostring() return self.image.tobytes()
if bytes is str:
tostring = tobytes
fromstring = frombytes
## ##
# Create a Window with the given title size. # Create a Window with the given title size.

View File

@ -24,7 +24,7 @@ from . import Image, ImageFile
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
field = re.compile(r"([a-z]*) ([^ \r\n]*)") field = re.compile(br"([a-z]*) ([^ \r\n]*)")
## ##
# Image plugin for IM Tools images. # Image plugin for IM Tools images.
@ -39,7 +39,7 @@ class ImtImageFile(ImageFile.ImageFile):
# Quick rejection: if there's not a LF among the first # Quick rejection: if there's not a LF among the first
# 100 bytes, this is (probably) not a text header. # 100 bytes, this is (probably) not a text header.
if not "\n" in self.fp.read(100): if not b"\n" in self.fp.read(100):
raise SyntaxError("not an IM file") raise SyntaxError("not an IM file")
self.fp.seek(0) self.fp.seek(0)
@ -51,7 +51,7 @@ class ImtImageFile(ImageFile.ImageFile):
if not s: if not s:
break break
if s == chr(12): if s == b'\x0C':
# image data begins # image data begins
self.tile = [("raw", (0,0)+self.size, self.tile = [("raw", (0,0)+self.size,
@ -67,7 +67,7 @@ class ImtImageFile(ImageFile.ImageFile):
s = s + self.fp.readline() s = s + self.fp.readline()
if len(s) == 1 or len(s) > 100: if len(s) == 1 or len(s) > 100:
break break
if s[0] == "*": if s[0] == b"*":
continue # comment continue # comment
m = field.match(s) m = field.match(s)

View File

@ -20,32 +20,30 @@ from __future__ import print_function
__version__ = "0.3" __version__ = "0.3"
from . import Image, ImageFile from . import Image, ImageFile, _binary
import os, tempfile import os, tempfile
i8 = _binary.i8
i16 = _binary.i16be
i32 = _binary.i32be
o8 = _binary.o8
COMPRESSION = { COMPRESSION = {
1: "raw", 1: "raw",
5: "jpeg" 5: "jpeg"
} }
PAD = chr(0) * 4 PAD = o8(0) * 4
# #
# Helpers # Helpers
def i16(c):
return ord(c[1]) + (ord(c[0])<<8)
def i32(c):
return ord(c[3]) + (ord(c[2])<<8) + (ord(c[1])<<16) + (ord(c[0])<<24)
def i(c): def i(c):
return i32((PAD + c)[-4:]) return i32((PAD + c)[-4:])
def dump(c): def dump(c):
for i in c: for i in c:
print("%02x" % ord(i), end=' ') print("%02x" % i8(i), end=' ')
print() print()
## ##
@ -67,14 +65,14 @@ class IptcImageFile(ImageFile.ImageFile):
if not len(s): if not len(s):
return None, 0 return None, 0
tag = ord(s[1]), ord(s[2]) tag = i8(s[1]), i8(s[2])
# syntax # syntax
if ord(s[0]) != 0x1C or tag[0] < 1 or tag[0] > 9: if i8(s[0]) != 0x1C or tag[0] < 1 or tag[0] > 9:
raise SyntaxError("invalid IPTC/NAA file") raise SyntaxError("invalid IPTC/NAA file")
# field size # field size
size = ord(s[3]) size = i8(s[3])
if size > 132: if size > 132:
raise IOError("illegal field length in IPTC/NAA file") raise IOError("illegal field length in IPTC/NAA file")
elif size == 128: elif size == 128:
@ -131,10 +129,10 @@ class IptcImageFile(ImageFile.ImageFile):
# print tag, self.info[tag] # print tag, self.info[tag]
# mode # mode
layers = ord(self.info[(3,60)][0]) layers = i8(self.info[(3,60)][0])
component = ord(self.info[(3,60)][1]) component = i8(self.info[(3,60)][1])
if (3,65) in self.info: if (3,65) in self.info:
id = ord(self.info[(3,65)][0])-1 id = i8(self.info[(3,65)][0])-1
else: else:
id = 0 id = 0
if layers == 1 and not component: if layers == 1 and not component:
@ -242,7 +240,7 @@ def getiptcinfo(im):
code = JpegImagePlugin.i16(app, offset) code = JpegImagePlugin.i16(app, offset)
offset = offset + 2 offset = offset + 2
# resource name (usually empty) # resource name (usually empty)
name_len = ord(app[offset]) name_len = i8(app[offset])
name = app[offset+1:offset+1+name_len] name = app[offset+1:offset+1+name_len]
offset = 1 + offset + name_len offset = 1 + offset + name_len
if offset & 1: if offset & 1:

View File

@ -35,13 +35,12 @@
__version__ = "0.6" __version__ = "0.6"
import array, struct import array, struct
from . import Image, ImageFile from . import Image, ImageFile, _binary
def i16(c,o=0): i8 = _binary.i8
return ord(c[o+1]) + (ord(c[o])<<8) o8 = _binary.o8
i16 = _binary.i16be
def i32(c,o=0): i32 = _binary.i32be
return ord(c[o+3]) + (ord(c[o+2])<<8) + (ord(c[o+1])<<16) + (ord(c[o])<<24)
# #
# Parser # Parser
@ -63,13 +62,13 @@ def APP(self, marker):
self.app[app] = s # compatibility self.app[app] = s # compatibility
self.applist.append((app, s)) self.applist.append((app, s))
if marker == 0xFFE0 and s[:4] == "JFIF": if marker == 0xFFE0 and s[:4] == b"JFIF":
# extract JFIF information # extract JFIF information
self.info["jfif"] = version = i16(s, 5) # version self.info["jfif"] = version = i16(s, 5) # version
self.info["jfif_version"] = divmod(version, 256) self.info["jfif_version"] = divmod(version, 256)
# extract JFIF properties # extract JFIF properties
try: try:
jfif_unit = ord(s[7]) jfif_unit = i8(s[7])
jfif_density = i16(s, 8), i16(s, 10) jfif_density = i16(s, 8), i16(s, 10)
except: except:
pass pass
@ -78,13 +77,13 @@ def APP(self, marker):
self.info["dpi"] = jfif_density self.info["dpi"] = jfif_density
self.info["jfif_unit"] = jfif_unit self.info["jfif_unit"] = jfif_unit
self.info["jfif_density"] = jfif_density self.info["jfif_density"] = jfif_density
elif marker == 0xFFE1 and s[:5] == "Exif\0": elif marker == 0xFFE1 and s[:5] == b"Exif\0":
# extract Exif information (incomplete) # extract Exif information (incomplete)
self.info["exif"] = s # FIXME: value will change self.info["exif"] = s # FIXME: value will change
elif marker == 0xFFE2 and s[:5] == "FPXR\0": elif marker == 0xFFE2 and s[:5] == b"FPXR\0":
# extract FlashPix information (incomplete) # extract FlashPix information (incomplete)
self.info["flashpix"] = s # FIXME: value will change self.info["flashpix"] = s # FIXME: value will change
elif marker == 0xFFE2 and s[:12] == "ICC_PROFILE\0": elif marker == 0xFFE2 and s[:12] == b"ICC_PROFILE\0":
# Since an ICC profile can be larger than the maximum size of # Since an ICC profile can be larger than the maximum size of
# a JPEG marker (64K), we need provisions to split it into # a JPEG marker (64K), we need provisions to split it into
# multiple markers. The format defined by the ICC specifies # multiple markers. The format defined by the ICC specifies
@ -97,11 +96,11 @@ def APP(self, marker):
# reassemble the profile, rather than assuming that the APP2 # reassemble the profile, rather than assuming that the APP2
# markers appear in the correct sequence. # markers appear in the correct sequence.
self.icclist.append(s) self.icclist.append(s)
elif marker == 0xFFEE and s[:5] == "Adobe": elif marker == 0xFFEE and s[:5] == b"Adobe":
self.info["adobe"] = i16(s, 5) self.info["adobe"] = i16(s, 5)
# extract Adobe custom properties # extract Adobe custom properties
try: try:
adobe_transform = ord(s[1]) adobe_transform = i8(s[1])
except: except:
pass pass
else: else:
@ -129,11 +128,11 @@ def SOF(self, marker):
s = ImageFile._safe_read(self.fp, n) s = ImageFile._safe_read(self.fp, n)
self.size = i16(s[3:]), i16(s[1:]) self.size = i16(s[3:]), i16(s[1:])
self.bits = ord(s[0]) self.bits = i8(s[0])
if self.bits != 8: if self.bits != 8:
raise SyntaxError("cannot handle %d-bit layers" % self.bits) raise SyntaxError("cannot handle %d-bit layers" % self.bits)
self.layers = ord(s[5]) self.layers = i8(s[5])
if self.layers == 1: if self.layers == 1:
self.mode = "L" self.mode = "L"
elif self.layers == 3: elif self.layers == 3:
@ -149,11 +148,11 @@ def SOF(self, marker):
if self.icclist: if self.icclist:
# fixup icc profile # fixup icc profile
self.icclist.sort() # sort by sequence number self.icclist.sort() # sort by sequence number
if ord(self.icclist[0][13]) == len(self.icclist): if i8(self.icclist[0][13]) == len(self.icclist):
profile = [] profile = []
for p in self.icclist: for p in self.icclist:
profile.append(p[14:]) profile.append(p[14:])
icc_profile = "".join(profile) icc_profile = b"".join(profile)
else: else:
icc_profile = None # wrong number of fragments icc_profile = None # wrong number of fragments
self.info["icc_profile"] = icc_profile self.info["icc_profile"] = icc_profile
@ -162,7 +161,7 @@ def SOF(self, marker):
for i in range(6, len(s), 3): for i in range(6, len(s), 3):
t = s[i:i+3] t = s[i:i+3]
# 4-tuples: id, vsamp, hsamp, qtable # 4-tuples: id, vsamp, hsamp, qtable
self.layer.append((t[0], ord(t[1])/16, ord(t[1])&15, ord(t[2]))) self.layer.append((t[0], i8(t[1])//16, i8(t[1])&15, i8(t[2])))
def DQT(self, marker): def DQT(self, marker):
# #
@ -178,8 +177,8 @@ def DQT(self, marker):
while len(s): while len(s):
if len(s) < 65: if len(s) < 65:
raise SyntaxError("bad quantization table marker") raise SyntaxError("bad quantization table marker")
v = ord(s[0]) v = i8(s[0])
if v/16 == 0: if v//16 == 0:
self.quantization[v&15] = array.array("b", s[1:65]) self.quantization[v&15] = array.array("b", s[1:65])
s = s[65:] s = s[65:]
else: else:
@ -258,7 +257,7 @@ MARKER = {
def _accept(prefix): def _accept(prefix):
return prefix[0] == "\377" return prefix[0:1] == b"\377"
## ##
# Image plugin for JPEG and JFIF images. # Image plugin for JPEG and JFIF images.
@ -272,7 +271,7 @@ class JpegImageFile(ImageFile.ImageFile):
s = self.fp.read(1) s = self.fp.read(1)
if ord(s[0]) != 255: if i8(s[0]) != 255:
raise SyntaxError("not a JPEG file") raise SyntaxError("not a JPEG file")
# Create attributes # Create attributes
@ -325,12 +324,12 @@ class JpegImageFile(ImageFile.ImageFile):
a = mode, "" a = mode, ""
if size: if size:
scale = max(self.size[0] / size[0], self.size[1] / size[1]) scale = max(self.size[0] // size[0], self.size[1] // size[1])
for s in [8, 4, 2, 1]: for s in [8, 4, 2, 1]:
if scale >= s: if scale >= s:
break break
e = e[0], e[1], (e[2]-e[0]+s-1)/s+e[0], (e[3]-e[1]+s-1)/s+e[1] e = e[0], e[1], (e[2]-e[0]+s-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) self.size = ((self.size[0]+s-1)//s, (self.size[1]+s-1)//s)
scale = s scale = s
self.tile = [(d, e, o, a)] self.tile = [(d, e, o, a)]
@ -436,7 +435,7 @@ def _save(im, fp, filename):
elif subsampling == "4:1:1": elif subsampling == "4:1:1":
subsampling = 2 subsampling = 2
extra = "" extra = b""
icc_profile = info.get("icc_profile") icc_profile = info.get("icc_profile")
if icc_profile: if icc_profile:
@ -450,7 +449,7 @@ def _save(im, fp, filename):
i = 1 i = 1
for marker in markers: for marker in markers:
size = struct.pack(">H", 2 + ICC_OVERHEAD_LEN + len(marker)) size = struct.pack(">H", 2 + ICC_OVERHEAD_LEN + len(marker))
extra = extra + ("\xFF\xE2" + size + "ICC_PROFILE\0" + chr(i) + chr(len(markers)) + marker) extra = extra + (b"\xFF\xE2" + size + b"ICC_PROFILE\0" + o8(i) + o8(len(markers)) + marker)
i = i + 1 i = i + 1
# get keyword arguments # get keyword arguments

View File

@ -22,7 +22,7 @@ import struct
from . import Image, ImageFile from . import Image, ImageFile
def _accept(s): def _accept(s):
return s[:8] == "\x00\x00\x00\x00\x00\x00\x00\x04" return s[:8] == b"\x00\x00\x00\x00\x00\x00\x00\x04"
## ##
# Image plugin for McIdas area images. # Image plugin for McIdas area images.

View File

@ -16,6 +16,7 @@
__version__ = "0.1" __version__ = "0.1"
from . import Image, ImageFile from . import Image, ImageFile
from ._binary import i8
# #
# Bitstream parser # Bitstream parser
@ -28,7 +29,7 @@ class BitStream:
self.bitbuffer = 0 self.bitbuffer = 0
def next(self): def next(self):
return ord(self.fp.read(1)) return i8(self.fp.read(1))
def peek(self, bits): def peek(self, bits):
while self.bits < bits: while self.bits < bits:
@ -42,7 +43,7 @@ class BitStream:
def skip(self, bits): def skip(self, bits):
while self.bits < bits: while self.bits < bits:
self.bitbuffer = (self.bitbuffer << 8) + ord(self.fp.read(1)) self.bitbuffer = (self.bitbuffer << 8) + i8(self.fp.read(1))
self.bits = self.bits + 8 self.bits = self.bits + 8
self.bits = self.bits - bits self.bits = self.bits - bits

View File

@ -19,17 +19,16 @@
__version__ = "0.1" __version__ = "0.1"
from . import Image, ImageFile from . import Image, ImageFile, _binary
# #
# read MSP files # read MSP files
def i16(c): i16 = _binary.i16le
return ord(c[0]) + (ord(c[1])<<8)
def _accept(prefix): def _accept(prefix):
return prefix[:4] in ["DanM", "LinS"] return prefix[:4] in [b"DanM", b"LinS"]
## ##
# Image plugin for Windows MSP images. This plugin supports both # Image plugin for Windows MSP images. This plugin supports both
@ -44,7 +43,7 @@ class MspImageFile(ImageFile.ImageFile):
# Header # Header
s = self.fp.read(32) s = self.fp.read(32)
if s[:4] not in ["DanM", "LinS"]: if s[:4] not in [b"DanM", b"LinS"]:
raise SyntaxError("not an MSP file") raise SyntaxError("not an MSP file")
# Header checksum # Header checksum
@ -57,7 +56,7 @@ class MspImageFile(ImageFile.ImageFile):
self.mode = "1" self.mode = "1"
self.size = i16(s[4:]), i16(s[6:]) self.size = i16(s[4:]), i16(s[6:])
if s[:4] == "DanM": if s[:4] == b"DanM":
self.tile = [("raw", (0,0)+self.size, 32, ("1", 0, 1))] self.tile = [("raw", (0,0)+self.size, 32, ("1", 0, 1))]
else: else:
self.tile = [("msp", (0,0)+self.size, 32+2*self.size[1], None)] self.tile = [("msp", (0,0)+self.size, 32+2*self.size[1], None)]
@ -65,8 +64,7 @@ class MspImageFile(ImageFile.ImageFile):
# #
# write MSP files (uncompressed only) # write MSP files (uncompressed only)
def o16(i): o16 = _binary.o16le
return chr(i&255) + chr(i>>8&255)
def _save(im, fp, filename): def _save(im, fp, filename):
@ -76,7 +74,7 @@ def _save(im, fp, filename):
# create MSP header # create MSP header
header = [0] * 16 header = [0] * 16
header[0], header[1] = i16("Da"), i16("nM") # version 1 header[0], header[1] = i16(b"Da"), i16(b"nM") # version 1
header[2], header[3] = im.size header[2], header[3] = im.size
header[4], header[5] = 1, 1 header[4], header[5] = 1, 1
header[6], header[7] = 1, 1 header[6], header[7] = 1, 1

View File

@ -40,18 +40,17 @@ from __future__ import print_function
import io import io
import sys import sys
from . import _binary
if str != bytes: if str is not bytes:
long = int long = int
def i16(c, o = 0): i8 = _binary.i8
return ord(c[o])+(ord(c[o+1])<<8) i16 = _binary.i16le
i32 = _binary.i32le
def i32(c, o = 0):
return ord(c[o])+(ord(c[o+1])<<8)+(ord(c[o+2])<<16)+(ord(c[o+3])<<24)
MAGIC = '\320\317\021\340\241\261\032\341' MAGIC = b'\320\317\021\340\241\261\032\341'
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
@ -332,12 +331,12 @@ class OleFileIO:
def _unicode(self, s): def _unicode(self, s):
# Map unicode string to Latin 1 # Map unicode string to Latin 1
if sys.version_info >= (3,0): if bytes is str:
# Provide actual Unicode string
return s.decode('utf-16')
else:
# Old version tried to produce a Latin-1 str # Old version tried to produce a Latin-1 str
return s.decode('utf-16').encode('latin-1', 'replace') return s.decode('utf-16').encode('latin-1', 'replace')
else:
# Provide actual Unicode string
return s.decode('utf-16')
def loaddirectory(self, sect): def loaddirectory(self, sect):
# Load the directory. The directory is stored in a standard # Load the directory. The directory is stored in a standard
@ -352,7 +351,7 @@ class OleFileIO:
entry = fp.read(128) entry = fp.read(128)
if not entry: if not entry:
break break
type = ord(entry[66]) type = i8(entry[66])
name = self._unicode(entry[0:0+i16(entry, 64)]) name = self._unicode(entry[0:0+i16(entry, 64)])
ptrs = i32(entry, 68), i32(entry, 72), i32(entry, 76) ptrs = i32(entry, 68), i32(entry, 72), i32(entry, 76)
sect, size = i32(entry, 116), i32(entry, 120) sect, size = i32(entry, 116), i32(entry, 120)
@ -372,7 +371,7 @@ class OleFileIO:
return "" return ""
return (("%08X-%04X-%04X-%02X%02X-" + "%02X" * 6) % return (("%08X-%04X-%04X-%02X%02X-" + "%02X" * 6) %
((i32(clsid, 0), i16(clsid, 4), i16(clsid, 6)) + ((i32(clsid, 0), i16(clsid, 4), i16(clsid, 6)) +
tuple(map(ord, clsid[8:16])))) tuple(map(i8, clsid[8:16]))))
def _list(self, files, prefix, node): def _list(self, files, prefix, node):
# listdir helper # listdir helper
@ -488,9 +487,9 @@ class OleFileIO:
value = long(i32(s, offset+4)) + (long(i32(s, offset+8))<<32) value = long(i32(s, offset+4)) + (long(i32(s, offset+8))<<32)
# FIXME: this is a 64-bit int: "number of 100ns periods # FIXME: this is a 64-bit int: "number of 100ns periods
# since Jan 1,1601". Should map this to Python time # since Jan 1,1601". Should map this to Python time
value = value / 10000000 # seconds value = value // 10000000 # seconds
elif type == VT_UI1: elif type == VT_UI1:
value = ord(s[offset+4]) value = i8(s[offset+4])
elif type == VT_CLSID: elif type == VT_CLSID:
value = self._clsid(s[offset+4:offset+20]) value = self._clsid(s[offset+4:offset+20])
elif type == VT_CF: elif type == VT_CF:

View File

@ -13,6 +13,8 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
from ._binary import o8
## ##
# File handler for Teragon-style palette files. # File handler for Teragon-style palette files.
@ -30,7 +32,7 @@ class PaletteFile:
if not s: if not s:
break break
if s[0] == "#": if s[0:1] == b"#":
continue continue
if len(s) > 100: if len(s) > 100:
raise SyntaxError("bad palette file") raise SyntaxError("bad palette file")
@ -43,9 +45,9 @@ class PaletteFile:
g = b = r g = b = r
if 0 <= i <= 255: if 0 <= i <= 255:
self.palette[i] = chr(r) + chr(g) + chr(b) self.palette[i] = o8(r) + o8(g) + o8(b)
self.palette = "".join(self.palette) self.palette = b"".join(self.palette)
def getpalette(self): def getpalette(self):

View File

@ -9,7 +9,7 @@
__version__ = "1.0" __version__ = "1.0"
from . import Image, ImageFile from . import Image, ImageFile, _binary
_Palm8BitColormapValues = ( _Palm8BitColormapValues = (
( 255, 255, 255 ), ( 255, 204, 255 ), ( 255, 153, 255 ), ( 255, 102, 255 ), ( 255, 255, 255 ), ( 255, 204, 255 ), ( 255, 153, 255 ), ( 255, 102, 255 ),
@ -107,8 +107,8 @@ _COMPRESSION_TYPES = {
"scanline": 0x00, "scanline": 0x00,
} }
def o16b(i): o8 = _binary.o8
return chr(i>>8&255) + chr(i&255) o16b = _binary.o16be
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
@ -172,7 +172,7 @@ def _save(im, fp, filename, check=0):
cols = im.size[0] cols = im.size[0]
rows = im.size[1] rows = im.size[1]
rowbytes = ((cols + (16/bpp - 1)) / (16 / bpp)) * 2; rowbytes = ((cols + (16//bpp - 1)) / (16 // bpp)) * 2;
transparent_index = 0 transparent_index = 0
compression_type = _COMPRESSION_TYPES["none"] compression_type = _COMPRESSION_TYPES["none"]
@ -186,16 +186,16 @@ def _save(im, fp, filename, check=0):
colormapsize = 0 colormapsize = 0
if "offset" in im.info: if "offset" in im.info:
offset = (rowbytes * rows + 16 + 3 + colormapsize) / 4; offset = (rowbytes * rows + 16 + 3 + colormapsize) // 4;
else: else:
offset = 0 offset = 0
fp.write(o16b(cols) + o16b(rows) + o16b(rowbytes) + o16b(flags)) fp.write(o16b(cols) + o16b(rows) + o16b(rowbytes) + o16b(flags))
fp.write(chr(bpp)) fp.write(o8(bpp))
fp.write(chr(version)) fp.write(o8(version))
fp.write(o16b(offset)) fp.write(o16b(offset))
fp.write(chr(transparent_index)) fp.write(o8(transparent_index))
fp.write(chr(compression_type)) fp.write(o8(compression_type))
fp.write(o16b(0)) # reserved by Palm fp.write(o16b(0)) # reserved by Palm
# now write colormap if necessary # now write colormap if necessary
@ -203,11 +203,11 @@ def _save(im, fp, filename, check=0):
if colormapsize > 0: if colormapsize > 0:
fp.write(o16b(256)) fp.write(o16b(256))
for i in range(256): for i in range(256):
fp.write(chr(i)) fp.write(o8(i))
if colormapmode == 'RGB': if colormapmode == 'RGB':
fp.write(chr(colormap[3 * i]) + chr(colormap[3 * i + 1]) + chr(colormap[3 * i + 2])) fp.write(o8(colormap[3 * i]) + o8(colormap[3 * i + 1]) + o8(colormap[3 * i + 2]))
elif colormapmode == 'RGBA': elif colormapmode == 'RGBA':
fp.write(chr(colormap[4 * i]) + chr(colormap[4 * i + 1]) + chr(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 # 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))])

View File

@ -18,7 +18,9 @@
__version__ = "0.1" __version__ = "0.1"
from . import Image, ImageFile from . import Image, ImageFile, _binary
i8 = _binary.i8
## ##
# Image plugin for PhotoCD images. This plugin only reads the 768x512 # Image plugin for PhotoCD images. This plugin only reads the 768x512
@ -36,10 +38,10 @@ class PcdImageFile(ImageFile.ImageFile):
self.fp.seek(2048) self.fp.seek(2048)
s = self.fp.read(2048) s = self.fp.read(2048)
if s[:4] != "PCD_": if s[:4] != b"PCD_":
raise SyntaxError("not a PCD file") raise SyntaxError("not a PCD file")
orientation = ord(s[1538]) & 3 orientation = i8(s[1538]) & 3
if orientation == 1: if orientation == 1:
self.tile_post_rotate = 90 # hack self.tile_post_rotate = 90 # hack
elif orientation == 3: elif orientation == 3:

View File

@ -18,6 +18,7 @@
from . import Image from . import Image
from . import FontFile from . import FontFile
from . import _binary
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# declarations # declarations
@ -41,19 +42,14 @@ BYTES_PER_ROW = [
lambda bits: ((bits+63) >> 3) & ~7, lambda bits: ((bits+63) >> 3) & ~7,
] ]
i8 = _binary.i8
def l16(c): l16 = _binary.i16le
return ord(c[0]) + (ord(c[1])<<8) l32 = _binary.i32le
def l32(c): b16 = _binary.i16be
return ord(c[0]) + (ord(c[1])<<8) + (ord(c[2])<<16) + (ord(c[3])<<24) b32 = _binary.i32be
def b16(c):
return ord(c[1]) + (ord(c[0])<<8)
def b32(c):
return ord(c[3]) + (ord(c[2])<<8) + (ord(c[1])<<16) + (ord(c[0])<<24)
def sz(s, o): def sz(s, o):
return s[o:s.index("\0", o)] return s[o:s.index(b"\0", o)]
## ##
# Font file plugin for the X11 PCF format. # Font file plugin for the X11 PCF format.
@ -124,7 +120,7 @@ class PcfFontFile(FontFile.FontFile):
# read property description # read property description
p = [] p = []
for i in range(nprops): for i in range(nprops):
p.append((i32(fp.read(4)), ord(fp.read(1)), i32(fp.read(4)))) p.append((i32(fp.read(4)), i8(fp.read(1)), i32(fp.read(4))))
if nprops & 3: if nprops & 3:
fp.seek(4 - (nprops & 3), 1) # pad fp.seek(4 - (nprops & 3), 1) # pad
@ -153,11 +149,11 @@ class PcfFontFile(FontFile.FontFile):
# "compressed" metrics # "compressed" metrics
for i in range(i16(fp.read(2))): for i in range(i16(fp.read(2))):
left = ord(fp.read(1)) - 128 left = i8(fp.read(1)) - 128
right = ord(fp.read(1)) - 128 right = i8(fp.read(1)) - 128
width = ord(fp.read(1)) - 128 width = i8(fp.read(1)) - 128
ascent = ord(fp.read(1)) - 128 ascent = i8(fp.read(1)) - 128
descent = ord(fp.read(1)) - 128 descent = i8(fp.read(1)) - 128
xsize = right - left xsize = right - left
ysize = ascent + descent ysize = ascent + descent
append( append(
@ -224,7 +220,7 @@ class PcfFontFile(FontFile.FontFile):
x, y, l, r, w, a, d, f = metrics[i] x, y, l, r, w, a, d, f = metrics[i]
b, e = offsets[i], offsets[i+1] b, e = offsets[i], offsets[i+1]
bitmaps.append( bitmaps.append(
Image.fromstring("1", (x, y), data[b:e], "raw", mode, pad(x)) Image.frombytes("1", (x, y), data[b:e], "raw", mode, pad(x))
) )
return bitmaps return bitmaps

View File

@ -27,13 +27,14 @@
__version__ = "0.6" __version__ = "0.6"
from . import Image, ImageFile, ImagePalette from . import Image, ImageFile, ImagePalette, _binary
def i16(c,o): i8 = _binary.i8
return ord(c[o]) + (ord(c[o+1])<<8) i16 = _binary.i16le
o8 = _binary.o8
def _accept(prefix): def _accept(prefix):
return ord(prefix[0]) == 10 and ord(prefix[1]) in [0, 2, 3, 5] return i8(prefix[0]) == 10 and i8(prefix[1]) in [0, 2, 3, 5]
## ##
# Image plugin for Paintbrush images. # Image plugin for Paintbrush images.
@ -56,9 +57,9 @@ class PcxImageFile(ImageFile.ImageFile):
raise SyntaxError("bad PCX image size") raise SyntaxError("bad PCX image size")
# format # format
version = ord(s[1]) version = i8(s[1])
bits = ord(s[3]) bits = i8(s[3])
planes = ord(s[65]) planes = i8(s[65])
stride = i16(s,66) stride = i16(s,66)
self.info["dpi"] = i16(s,12), i16(s,14) self.info["dpi"] = i16(s,12), i16(s,14)
@ -76,10 +77,10 @@ class PcxImageFile(ImageFile.ImageFile):
# FIXME: hey, this doesn't work with the incremental loader !!! # FIXME: hey, this doesn't work with the incremental loader !!!
self.fp.seek(-769, 2) self.fp.seek(-769, 2)
s = self.fp.read(769) s = self.fp.read(769)
if len(s) == 769 and ord(s[0]) == 12: if len(s) == 769 and i8(s[0]) == 12:
# check if the palette is linear greyscale # check if the palette is linear greyscale
for i in range(256): for i in range(256):
if s[i*3+1:i*3+4] != chr(i)*3: if s[i*3+1:i*3+4] != o8(i)*3:
mode = rawmode = "P" mode = rawmode = "P"
break break
if mode == "P": if mode == "P":
@ -111,8 +112,7 @@ SAVE = {
"RGB": (5, 8, 3, "RGB;L"), "RGB": (5, 8, 3, "RGB;L"),
} }
def o16(i): o16 = _binary.o16le
return chr(i&255) + chr(i>>8&255)
def _save(im, fp, filename, check=0): def _save(im, fp, filename, check=0):
@ -125,7 +125,7 @@ def _save(im, fp, filename, check=0):
return check return check
# bytes per plane # bytes per plane
stride = (im.size[0] * bits + 7) / 8 stride = (im.size[0] * bits + 7) // 8
# under windows, we could determine the current screen size with # under windows, we could determine the current screen size with
# "Image.core.display_mode()[1]", but I think that's overkill... # "Image.core.display_mode()[1]", but I think that's overkill...
@ -136,11 +136,11 @@ def _save(im, fp, filename, check=0):
# PCX header # PCX header
fp.write( fp.write(
chr(10) + chr(version) + chr(1) + chr(bits) + o16(0) + 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(0) + o16(im.size[0]-1) + o16(im.size[1]-1) + o16(dpi[0]) +
o16(dpi[1]) + chr(0)*24 + chr(255)*24 + chr(0) + chr(planes) + o16(dpi[1]) + b"\0"*24 + b"\xFF"*24 + b"\0" + o8(planes) +
o16(stride) + o16(1) + o16(screen[0]) + o16(screen[1]) + o16(stride) + o16(1) + o16(screen[0]) + o16(screen[1]) +
chr(0)*54 b"\0"*54
) )
assert fp.tell() == 128 assert fp.tell() == 128
@ -150,13 +150,13 @@ def _save(im, fp, filename, check=0):
if im.mode == "P": if im.mode == "P":
# colour palette # colour palette
fp.write(chr(12)) fp.write(o8(12))
fp.write(im.im.getpalette("RGB", "RGB")) # 768 bytes fp.write(im.im.getpalette("RGB", "RGB")) # 768 bytes
elif im.mode == "L": elif im.mode == "L":
# greyscale palette # greyscale palette
fp.write(chr(12)) fp.write(o8(12))
for i in range(256): for i in range(256):
fp.write(chr(i)*3) fp.write(o8(i)*3)
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# registry # registry

View File

@ -23,6 +23,7 @@
__version__ = "0.4" __version__ = "0.4"
from . import Image, ImageFile from . import Image, ImageFile
from ._binary import i8
import io import io
@ -37,12 +38,15 @@ import io
# 5. page contents # 5. page contents
def _obj(fp, obj, **dict): def _obj(fp, obj, **dict):
fp.write(b"%d 0 obj\n" % obj) fp.write(("%d 0 obj\n" % obj).encode('ascii'))
if dict: if dict:
fp.write(b"<<\n") fp.write(b"<<\n")
for k, v in dict.items(): for k, v in dict.items():
if v is not None: if v is not None:
fp.write(b"/%s %s\n" % (k, v)) if not isinstance(v, bytes):
v = str(v).encode('ascii')
fp.write(b"/" + k.encode('ascii') + b" " + v + b"\n")
fp.write(b">>\n") fp.write(b">>\n")
def _endobj(fp): def _endobj(fp):
@ -61,7 +65,7 @@ def _save(im, fp, filename):
xref = [0]*(5+1) # placeholders xref = [0]*(5+1) # placeholders
fp.write(b"%PDF-1.2\n") fp.write(b"%PDF-1.2\n")
fp.write(b"% created by PIL PDF driver " + __version__ + "\n") fp.write(b"% created by PIL PDF driver " + __version__.encode('ascii') + b"\n")
# #
# Get image characteristics # Get image characteristics
@ -78,32 +82,32 @@ def _save(im, fp, filename):
if im.mode == "1": if im.mode == "1":
filter = b"/ASCIIHexDecode" filter = b"/ASCIIHexDecode"
colorspace = b"/DeviceGray" colorspace = b"/DeviceGray"
procset = b"/ImageB" # grayscale procset = "/ImageB" # grayscale
bits = 1 bits = 1
elif im.mode == "L": elif im.mode == "L":
filter = b"/DCTDecode" filter = b"/DCTDecode"
# params = "<< /Predictor 15 /Columns %d >>" % (width-2) # params = "<< /Predictor 15 /Columns %d >>" % (width-2)
colorspace = b"/DeviceGray" colorspace = b"/DeviceGray"
procset = b"/ImageB" # grayscale procset = "/ImageB" # grayscale
elif im.mode == "P": elif im.mode == "P":
filter = b"/ASCIIHexDecode" filter = b"/ASCIIHexDecode"
colorspace = b"[ /Indexed /DeviceRGB 255 <" colorspace = b"[ /Indexed /DeviceRGB 255 <"
palette = im.im.getpalette("RGB") palette = im.im.getpalette("RGB")
for i in range(256): for i in range(256):
r = ord(palette[i*3]) r = i8(palette[i*3])
g = ord(palette[i*3+1]) g = i8(palette[i*3+1])
b = ord(palette[i*3+2]) b = i8(palette[i*3+2])
colorspace = colorspace + b"%02x%02x%02x " % (r, g, b) colorspace = colorspace + ("%02x%02x%02x " % (r, g, b)).encode('ascii')
colorspace = colorspace + b"> ]" colorspace = colorspace + b"> ]"
procset = b"/ImageI" # indexed color procset = "/ImageI" # indexed color
elif im.mode == "RGB": elif im.mode == "RGB":
filter = b"/DCTDecode" filter = b"/DCTDecode"
colorspace = b"/DeviceRGB" colorspace = b"/DeviceRGB"
procset = b"/ImageC" # color images procset = "/ImageC" # color images
elif im.mode == "CMYK": elif im.mode == "CMYK":
filter = b"/DCTDecode" filter = b"/DCTDecode"
colorspace = b"/DeviceCMYK" colorspace = b"/DeviceCMYK"
procset = b"/ImageC" # color images procset = "/ImageC" # color images
else: else:
raise ValueError("cannot save mode %s" % im.mode) raise ValueError("cannot save mode %s" % im.mode)
@ -168,11 +172,11 @@ def _save(im, fp, filename):
xref[4] = fp.tell() xref[4] = fp.tell()
_obj(fp, 4) _obj(fp, 4)
fp.write(b"<<\n/Type /Page\n/Parent 2 0 R\n"\ fp.write(("<<\n/Type /Page\n/Parent 2 0 R\n"\
b"/Resources <<\n/ProcSet [ /PDF %s ]\n"\ "/Resources <<\n/ProcSet [ /PDF %s ]\n"\
b"/XObject << /image 3 0 R >>\n>>\n"\ "/XObject << /image 3 0 R >>\n>>\n"\
b"/MediaBox [ 0 0 %d %d ]\n/Contents 5 0 R\n>>\n" %\ "/MediaBox [ 0 0 %d %d ]\n/Contents 5 0 R\n>>\n" %\
(procset, int(width * 72.0 /resolution) , int(height * 72.0 / resolution))) (procset, int(width * 72.0 /resolution) , int(height * 72.0 / resolution))).encode('ascii'))
_endobj(fp) _endobj(fp)
# #
@ -180,7 +184,7 @@ def _save(im, fp, filename):
op = io.BytesIO() op = io.BytesIO()
op.write(b"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))).encode('ascii'))
xref[5] = fp.tell() xref[5] = fp.tell()
_obj(fp, 5, Length = len(op.getvalue())) _obj(fp, 5, Length = len(op.getvalue()))
@ -194,11 +198,11 @@ def _save(im, fp, filename):
# #
# trailer # trailer
startxref = fp.tell() startxref = fp.tell()
fp.write(b"xref\n0 %d\n0000000000 65535 f \n" % len(xref)) fp.write(("xref\n0 %d\n0000000000 65535 f \n" % len(xref)).encode('ascii'))
for x in xref[1:]: for x in xref[1:]:
fp.write(b"%010d 00000 n \n" % x) fp.write(("%010d 00000 n \n" % x).encode('ascii'))
fp.write(b"trailer\n<<\n/Size %d\n/Root 1 0 R\n>>\n" % len(xref)) fp.write(("trailer\n<<\n/Size %d\n/Root 1 0 R\n>>\n" % len(xref)).encode('ascii'))
fp.write(b"startxref\n%d\n%%%%EOF\n" % startxref) fp.write(("startxref\n%d\n%%%%EOF\n" % startxref).encode('ascii'))
fp.flush() fp.flush()
# #

View File

@ -21,16 +21,13 @@
__version__ = "0.1" __version__ = "0.1"
from . import Image, ImageFile from . import Image, ImageFile, _binary
# #
# helpers # helpers
def i16(c): i16 = _binary.i16le
return ord(c[0]) + (ord(c[1])<<8) i32 = _binary.i32le
def i32(c):
return ord(c[0]) + (ord(c[1])<<8) + (ord(c[2])<<16) + (ord(c[3])<<24)
## ##
# Image plugin for PIXAR raster images. # Image plugin for PIXAR raster images.
@ -44,7 +41,7 @@ class PixarImageFile(ImageFile.ImageFile):
# assuming a 4-byte magic label (FIXME: add "_accept" hook) # assuming a 4-byte magic label (FIXME: add "_accept" hook)
s = self.fp.read(4) s = self.fp.read(4)
if s != "\200\350\000\000": if s != b"\200\350\000\000":
raise SyntaxError("not a PIXAR file") raise SyntaxError("not a PIXAR file")
# read rest of header # read rest of header

View File

@ -37,19 +37,17 @@ __version__ = "0.9"
import re import re
from . import Image, ImageFile, ImagePalette from . import Image, ImageFile, ImagePalette, _binary
import zlib import zlib
i8 = _binary.i8
i16 = _binary.i16be
i32 = _binary.i32be
def i16(c): is_cid = re.compile(b"\w\w\w\w").match
return ord(c[1]) + (ord(c[0])<<8)
def i32(c):
return ord(c[3]) + (ord(c[2])<<8) + (ord(c[1])<<16) + (ord(c[0])<<24)
is_cid = re.compile("\w\w\w\w").match
_MAGIC = "\211PNG\r\n\032\n" _MAGIC = b"\211PNG\r\n\032\n"
_MODES = { _MODES = {
@ -115,7 +113,7 @@ class ChunkStream:
if Image.DEBUG: if Image.DEBUG:
print("STREAM", cid, pos, len) print("STREAM", cid, pos, len)
return getattr(self, "chunk_" + cid)(pos, len) return getattr(self, "chunk_" + cid.decode('ascii'))(pos, len)
def crc(self, cid, data): def crc(self, cid, data):
"Read and verify checksum" "Read and verify checksum"
@ -131,7 +129,7 @@ class ChunkStream:
self.fp.read(4) self.fp.read(4)
def verify(self, endchunk = "IEND"): def verify(self, endchunk = b"IEND"):
# Simple approach; just calculate checksum for all remaining # Simple approach; just calculate checksum for all remaining
# blocks. Must be called directly after open. # blocks. Must be called directly after open.
@ -160,11 +158,18 @@ class PngInfo:
self.chunks.append((cid, data)) self.chunks.append((cid, data))
def add_text(self, key, value, zip=0): def add_text(self, key, value, zip=0):
# The tEXt chunk stores latin-1 text
if not isinstance(key, bytes):
key = key.encode('latin-1', 'strict')
if not isinstance(value, bytes):
value = value.encode('latin-1', 'replace')
if zip: if zip:
import zlib import zlib
self.add("zTXt", key + "\0\0" + zlib.compress(value)) self.add(b"zTXt", key + b"\0\0" + zlib.compress(value))
else: else:
self.add("tEXt", key + "\0" + value) self.add(b"tEXt", key + b"\0" + value)
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# PNG image stream (IHDR/IEND) # PNG image stream (IHDR/IEND)
@ -192,11 +197,11 @@ class PngStream(ChunkStream):
# Null separator 1 byte (null character) # Null separator 1 byte (null character)
# Compression method 1 byte (0) # Compression method 1 byte (0)
# Compressed profile n bytes (zlib with deflate compression) # Compressed profile n bytes (zlib with deflate compression)
i = s.find(chr(0)) i = s.find(b"\0")
if Image.DEBUG: if Image.DEBUG:
print("iCCP profile name", s[:i]) print("iCCP profile name", s[:i])
print("Compression method", ord(s[i])) print("Compression method", i8(s[i]))
comp_method = ord(s[i]) comp_method = i8(s[i])
if comp_method != 0: 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: try:
@ -212,12 +217,12 @@ class PngStream(ChunkStream):
s = ImageFile._safe_read(self.fp, len) s = ImageFile._safe_read(self.fp, len)
self.im_size = i32(s), i32(s[4:]) self.im_size = i32(s), i32(s[4:])
try: try:
self.im_mode, self.im_rawmode = _MODES[(ord(s[8]), ord(s[9]))] self.im_mode, self.im_rawmode = _MODES[(i8(s[8]), i8(s[9]))]
except: except:
pass pass
if ord(s[12]): if i8(s[12]):
self.im_info["interlace"] = 1 self.im_info["interlace"] = 1
if ord(s[11]): if i8(s[11]):
raise SyntaxError("unknown filter category") raise SyntaxError("unknown filter category")
return s return s
@ -246,7 +251,7 @@ class PngStream(ChunkStream):
# transparency # transparency
s = ImageFile._safe_read(self.fp, len) s = ImageFile._safe_read(self.fp, len)
if self.im_mode == "P": if self.im_mode == "P":
i = s.find(chr(0)) i = s.find(b"\0")
if i >= 0: if i >= 0:
self.im_info["transparency"] = i self.im_info["transparency"] = i
elif self.im_mode == "L": elif self.im_mode == "L":
@ -267,7 +272,7 @@ class PngStream(ChunkStream):
# pixels per unit # pixels per unit
s = ImageFile._safe_read(self.fp, len) s = ImageFile._safe_read(self.fp, len)
px, py = i32(s), i32(s[4:]) px, py = i32(s), i32(s[4:])
unit = ord(s[8]) unit = i8(s[8])
if unit == 1: # meter if unit == 1: # meter
dpi = int(px * 0.0254 + 0.5), int(py * 0.0254 + 0.5) dpi = int(px * 0.0254 + 0.5), int(py * 0.0254 + 0.5)
self.im_info["dpi"] = dpi self.im_info["dpi"] = dpi
@ -280,10 +285,14 @@ class PngStream(ChunkStream):
# text # text
s = ImageFile._safe_read(self.fp, len) s = ImageFile._safe_read(self.fp, len)
try: try:
k, v = s.split("\0", 1) k, v = s.split(b"\0", 1)
except ValueError: except ValueError:
k = s; v = "" # fallback for broken tEXt tags k = s; v = b"" # fallback for broken tEXt tags
if k: if k:
if bytes is not str:
k = k.decode('latin-1', 'strict')
v = v.decode('latin-1', 'replace')
self.im_info[k] = self.im_text[k] = v self.im_info[k] = self.im_text[k] = v
return s return s
@ -291,12 +300,18 @@ class PngStream(ChunkStream):
# compressed text # compressed text
s = ImageFile._safe_read(self.fp, len) s = ImageFile._safe_read(self.fp, len)
k, v = s.split("\0", 1) k, v = s.split(b"\0", 1)
comp_method = ord(v[0]) comp_method = i8(v[0])
if 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)
import zlib import zlib
self.im_info[k] = self.im_text[k] = zlib.decompress(v[1:]) v = zlib.decompress(v[1:])
if bytes is not str:
k = k.decode('latin-1', 'strict')
v = v.decode('latin-1', 'replace')
self.im_info[k] = self.im_text[k] = v
return s return s
# -------------------------------------------------------------------- # --------------------------------------------------------------------
@ -393,9 +408,9 @@ class PngImageFile(ImageFile.ImageFile):
cid, pos, len = self.png.read() cid, pos, len = self.png.read()
if cid not in ["IDAT", "DDAT"]: if cid not in [b"IDAT", b"DDAT"]:
self.png.push(cid, pos, len) self.png.push(cid, pos, len)
return "" return b""
self.__idat = len # empty chunks are allowed self.__idat = len # empty chunks are allowed
@ -420,33 +435,31 @@ class PngImageFile(ImageFile.ImageFile):
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# PNG writer # PNG writer
def o16(i): o8 = _binary.o8
return chr(i>>8&255) + chr(i&255) o16 = _binary.o16be
o32 = _binary.o32be
def o32(i):
return chr(i>>24&255) + chr(i>>16&255) + chr(i>>8&255) + chr(i&255)
_OUTMODES = { _OUTMODES = {
# supported PIL modes, and corresponding rawmodes/bits/color combinations # supported PIL modes, and corresponding rawmodes/bits/color combinations
"1": ("1", chr(1)+chr(0)), "1": ("1", b'\x01\x00'),
"L;1": ("L;1", chr(1)+chr(0)), "L;1": ("L;1", b'\x01\x00'),
"L;2": ("L;2", chr(2)+chr(0)), "L;2": ("L;2", b'\x02\x00'),
"L;4": ("L;4", chr(4)+chr(0)), "L;4": ("L;4", b'\x04\x00'),
"L": ("L", chr(8)+chr(0)), "L": ("L", b'\x08\x00'),
"LA": ("LA", chr(8)+chr(4)), "LA": ("LA", b'\x08\x04'),
"I": ("I;16B", chr(16)+chr(0)), "I": ("I;16B", b'\x10\x00'),
"P;1": ("P;1", chr(1)+chr(3)), "P;1": ("P;1", b'\x01\x03'),
"P;2": ("P;2", chr(2)+chr(3)), "P;2": ("P;2", b'\x02\x03'),
"P;4": ("P;4", chr(4)+chr(3)), "P;4": ("P;4", b'\x04\x03'),
"P": ("P", chr(8)+chr(3)), "P": ("P", b'\x08\x03'),
"RGB": ("RGB", chr(8)+chr(2)), "RGB": ("RGB", b'\x08\x02'),
"RGBA":("RGBA", chr(8)+chr(6)), "RGBA":("RGBA", b'\x08\x06'),
} }
def putchunk(fp, cid, *data): def putchunk(fp, cid, *data):
"Write a PNG chunk (including CRC field)" "Write a PNG chunk (including CRC field)"
data = "".join(data) data = b"".join(data)
fp.write(o32(len(data)) + cid) fp.write(o32(len(data)) + cid)
fp.write(data) fp.write(data)
@ -460,7 +473,7 @@ class _idat:
self.fp = fp self.fp = fp
self.chunk = chunk self.chunk = chunk
def write(self, data): def write(self, data):
self.chunk(self.fp, "IDAT", data) self.chunk(self.fp, b"IDAT", data)
def _save(im, fp, filename, chunk=putchunk, check=0): def _save(im, fp, filename, chunk=putchunk, check=0):
# save an image to disk (called by the save method) # save an image to disk (called by the save method)
@ -498,7 +511,7 @@ def _save(im, fp, filename, chunk=putchunk, check=0):
if "dictionary" in im.encoderinfo: if "dictionary" in im.encoderinfo:
dictionary = im.encoderinfo["dictionary"] dictionary = im.encoderinfo["dictionary"]
else: else:
dictionary = "" dictionary = b""
im.encoderconfig = ("optimize" in im.encoderinfo, dictionary) im.encoderconfig = ("optimize" in im.encoderinfo, dictionary)
@ -516,39 +529,39 @@ def _save(im, fp, filename, chunk=putchunk, check=0):
fp.write(_MAGIC) fp.write(_MAGIC)
chunk(fp, "IHDR", chunk(fp, b"IHDR",
o32(im.size[0]), o32(im.size[1]), # 0: size o32(im.size[0]), o32(im.size[1]), # 0: size
mode, # 8: depth/type mode, # 8: depth/type
chr(0), # 10: compression b'\0', # 10: compression
chr(0), # 11: filter category b'\0', # 11: filter category
chr(0)) # 12: interlace flag b'\0') # 12: interlace flag
if im.mode == "P": if im.mode == "P":
chunk(fp, "PLTE", im.im.getpalette("RGB")) chunk(fp, b"PLTE", im.im.getpalette("RGB"))
if "transparency" in im.encoderinfo: if "transparency" in im.encoderinfo:
if im.mode == "P": if im.mode == "P":
transparency = max(0, min(255, im.encoderinfo["transparency"])) transparency = max(0, min(255, im.encoderinfo["transparency"]))
chunk(fp, "tRNS", chr(255) * transparency + chr(0)) chunk(fp, b"tRNS", b'\xFF' * transparency + b'\0')
elif im.mode == "L": elif im.mode == "L":
transparency = max(0, min(65535, im.encoderinfo["transparency"])) transparency = max(0, min(65535, im.encoderinfo["transparency"]))
chunk(fp, "tRNS", o16(transparency)) chunk(fp, b"tRNS", o16(transparency))
elif im.mode == "RGB": elif im.mode == "RGB":
red, green, blue = im.encoderinfo["transparency"] red, green, blue = im.encoderinfo["transparency"]
chunk(fp, "tRNS", o16(red) + o16(green) + o16(blue)) chunk(fp, b"tRNS", o16(red) + o16(green) + o16(blue))
else: else:
raise IOError("cannot use transparency for this mode") raise IOError("cannot use transparency for this mode")
if 0: if 0:
# FIXME: to be supported some day # FIXME: to be supported some day
chunk(fp, "gAMA", o32(int(gamma * 100000.0))) chunk(fp, b"gAMA", o32(int(gamma * 100000.0)))
dpi = im.encoderinfo.get("dpi") dpi = im.encoderinfo.get("dpi")
if dpi: if dpi:
chunk(fp, "pHYs", chunk(fp, b"pHYs",
o32(int(dpi[0] / 0.0254 + 0.5)), o32(int(dpi[0] / 0.0254 + 0.5)),
o32(int(dpi[1] / 0.0254 + 0.5)), o32(int(dpi[1] / 0.0254 + 0.5)),
chr(1)) b'\x01')
info = im.encoderinfo.get("pnginfo") info = im.encoderinfo.get("pnginfo")
if info: if info:
@ -568,13 +581,13 @@ def _save(im, fp, filename, chunk=putchunk, check=0):
p = ICCProfile.ICCProfile(im.info["icc_profile"]) p = ICCProfile.ICCProfile(im.info["icc_profile"])
name = p.tags.desc.get("ASCII", p.tags.desc.get("Unicode", p.tags.desc.get("Macintosh", p.tags.desc.get("en", {}).get("US", "ICC Profile")))).encode("latin1", "replace")[:79] name = p.tags.desc.get("ASCII", p.tags.desc.get("Unicode", p.tags.desc.get("Macintosh", p.tags.desc.get("en", {}).get("US", "ICC Profile")))).encode("latin1", "replace")[:79]
except ImportError: except ImportError:
name = "ICC Profile" name = b"ICC Profile"
data = name + "\0\0" + zlib.compress(im.info["icc_profile"]) data = name + b"\0\0" + zlib.compress(im.info["icc_profile"])
chunk(fp, "iCCP", data) 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, "IEND", "") chunk(fp, b"IEND", b"")
try: try:
fp.flush() fp.flush()
@ -596,7 +609,7 @@ def getchunks(im, **params):
self.data.append(chunk) self.data.append(chunk)
def append(fp, cid, *data): def append(fp, cid, *data):
data = "".join(data) data = b"".join(data)
hi, lo = Image.core.crc32(data, Image.core.crc32(cid)) hi, lo = Image.core.crc32(data, Image.core.crc32(cid))
crc = o16(hi) + o16(lo) crc = o16(hi) + o16(lo)
fp.append((cid, data, crc)) fp.append((cid, data, crc))

View File

@ -24,21 +24,23 @@ from . import Image, ImageFile
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
b_whitespace = string.whitespace.encode()
MODES = { MODES = {
# standard # standard
"P4": "1", b"P4": "1",
"P5": "L", b"P5": "L",
"P6": "RGB", b"P6": "RGB",
# extensions # extensions
"P0CMYK": "CMYK", b"P0CMYK": "CMYK",
# PIL extensions (for test purposes only) # PIL extensions (for test purposes only)
"PyP": "P", b"PyP": "P",
"PyRGBA": "RGBA", b"PyRGBA": "RGBA",
"PyCMYK": "CMYK" b"PyCMYK": "CMYK"
} }
def _accept(prefix): def _accept(prefix):
return prefix[0] == "P" and prefix[1] in "0456y" return prefix[0:1] == b"P" and prefix[1] in b"0456y"
## ##
# Image plugin for PBM, PGM, and PPM images. # Image plugin for PBM, PGM, and PPM images.
@ -48,10 +50,10 @@ class PpmImageFile(ImageFile.ImageFile):
format = "PPM" format = "PPM"
format_description = "Pbmplus image" format_description = "Pbmplus image"
def _token(self, s = ""): def _token(self, s = b""):
while True: # read until next whitespace while True: # read until next whitespace
c = self.fp.read(1) c = self.fp.read(1)
if not c or c in string.whitespace: if not c or c in b_whitespace:
break break
s = s + c s = s + c
return s return s
@ -60,7 +62,7 @@ class PpmImageFile(ImageFile.ImageFile):
# check magic # check magic
s = self.fp.read(1) s = self.fp.read(1)
if s != "P": if s != b"P":
raise SyntaxError("not a PPM file") raise SyntaxError("not a PPM file")
mode = MODES[self._token(s)] mode = MODES[self._token(s)]
@ -74,9 +76,9 @@ class PpmImageFile(ImageFile.ImageFile):
while True: while True:
while True: while True:
s = self.fp.read(1) s = self.fp.read(1)
if s not in string.whitespace: if s not in b_whitespace:
break break
if s != "#": if s != b"#":
break break
s = self.fp.readline() s = self.fp.readline()
s = int(self._token(s)) s = int(self._token(s))
@ -103,18 +105,18 @@ class PpmImageFile(ImageFile.ImageFile):
def _save(im, fp, filename): def _save(im, fp, filename):
if im.mode == "1": if im.mode == "1":
rawmode, head = "1;I", "P4" rawmode, head = "1;I", b"P4"
elif im.mode == "L": elif im.mode == "L":
rawmode, head = "L", "P5" rawmode, head = "L", b"P5"
elif im.mode == "RGB": elif im.mode == "RGB":
rawmode, head = "RGB", "P6" rawmode, head = "RGB", b"P6"
elif im.mode == "RGBA": elif im.mode == "RGBA":
rawmode, head = "RGB", "P6" rawmode, head = "RGB", b"P6"
else: else:
raise IOError("cannot write mode %s as PPM" % im.mode) raise IOError("cannot write mode %s as PPM" % im.mode)
fp.write(head + "\n%d %d\n" % im.size) fp.write(head + ("\n%d %d\n" % im.size).encode('ascii'))
if head != "P4": if head != b"P4":
fp.write("255\n") fp.write(b"255\n")
ImageFile._save(im, fp, [("raw", (0,0)+im.size, 0, (rawmode, 0, 1))]) ImageFile._save(im, fp, [("raw", (0,0)+im.size, 0, (rawmode, 0, 1))])
# ALTERNATIVE: save via builtin debug function # ALTERNATIVE: save via builtin debug function

View File

@ -18,7 +18,7 @@
__version__ = "0.4" __version__ = "0.4"
from . import Image, ImageFile, ImagePalette from . import Image, ImageFile, ImagePalette, _binary
MODES = { MODES = {
# (photoshop mode, bits) -> (pil mode, required channels) # (photoshop mode, bits) -> (pil mode, required channels)
@ -36,17 +36,15 @@ MODES = {
# #
# helpers # helpers
def i16(c): i8 = _binary.i8
return ord(c[1]) + (ord(c[0])<<8) i16 = _binary.i16be
i32 = _binary.i32be
def i32(c):
return ord(c[3]) + (ord(c[2])<<8) + (ord(c[1])<<16) + (ord(c[0])<<24)
# --------------------------------------------------------------------. # --------------------------------------------------------------------.
# read PSD images # read PSD images
def _accept(prefix): def _accept(prefix):
return prefix[:4] == "8BPS" return prefix[:4] == b"8BPS"
## ##
# Image plugin for Photoshop images. # Image plugin for Photoshop images.
@ -64,7 +62,7 @@ class PsdImageFile(ImageFile.ImageFile):
# header # header
s = read(26) s = read(26)
if s[:4] != "8BPS" or i16(s[4:]) != 1: if s[:4] != b"8BPS" or i16(s[4:]) != 1:
raise SyntaxError("not a PSD file") raise SyntaxError("not a PSD file")
psd_bits = i16(s[22:]) psd_bits = i16(s[22:])
@ -100,7 +98,7 @@ class PsdImageFile(ImageFile.ImageFile):
while self.fp.tell() < end: while self.fp.tell() < end:
signature = read(4) signature = read(4)
id = i16(read(2)) id = i16(read(2))
name = read(ord(read(1))) name = read(i8(read(1)))
if not (len(name) & 1): if not (len(name) & 1):
read(1) # padding read(1) # padding
data = read(i32(read(4))) data = read(i32(read(4)))
@ -219,9 +217,10 @@ def _layerinfo(file):
file.seek(length, 1) file.seek(length, 1)
combined += length + 4 combined += length + 4
length = ord(read(1)) length = i8(read(1))
if length: if length:
name = read(length) # Don't know the proper encoding, Latin-1 should be a good guess
name = read(length).decode('latin-1', 'replace')
combined += length + 1 combined += length + 1
file.seek(size - combined, 1) file.seek(size - combined, 1)

View File

@ -21,14 +21,11 @@
__version__ = "0.2" __version__ = "0.2"
from . import Image, ImageFile from . import Image, ImageFile, _binary
i8 = _binary.i8
def i16(c): i16 = _binary.i16be
return ord(c[1]) + (ord(c[0])<<8) i32 = _binary.i32be
def i32(c):
return ord(c[3]) + (ord(c[2])<<8) + (ord(c[1])<<16) + (ord(c[0])<<24)
def _accept(prefix): def _accept(prefix):
@ -50,10 +47,10 @@ class SgiImageFile(ImageFile.ImageFile):
raise SyntaxError("not an SGI image file") raise SyntaxError("not an SGI image file")
# relevant header entries # relevant header entries
compression = ord(s[2]) compression = i8(s[2])
# bytes, dimension, zsize # bytes, dimension, zsize
layout = ord(s[3]), i16(s[4:]), i16(s[10:]) layout = i8(s[3]), i16(s[4:]), i16(s[10:])
# determine mode from bytes/zsize # determine mode from bytes/zsize
if layout == (1, 2, 1) or layout == (1, 1, 1): if layout == (1, 2, 1) or layout == (1, 1, 1):

View File

@ -20,14 +20,10 @@
__version__ = "0.3" __version__ = "0.3"
from . import Image, ImageFile, ImagePalette from . import Image, ImageFile, ImagePalette, _binary
i16 = _binary.i16be
def i16(c): i32 = _binary.i32be
return ord(c[1]) + (ord(c[0])<<8)
def i32(c):
return ord(c[3]) + (ord(c[2])<<8) + (ord(c[1])<<16) + (ord(c[0])<<24)
def _accept(prefix): def _accept(prefix):
@ -71,7 +67,7 @@ class SunImageFile(ImageFile.ImageFile):
if self.mode == "L": if self.mode == "L":
self.mode = rawmode = "P" self.mode = rawmode = "P"
stride = (((self.size[0] * depth + 7) / 8) + 3) & (~3) stride = (((self.size[0] * depth + 7) // 8) + 3) & (~3)
if compression == 1: if compression == 1:
self.tile = [("raw", (0,0)+self.size, offset, (rawmode, stride))] self.tile = [("raw", (0,0)+self.size, offset, (rawmode, stride))]

View File

@ -38,8 +38,8 @@ class TarIO(ContainerIO.ContainerIO):
if len(s) != 512: if len(s) != 512:
raise IOError("unexpected end of tar file") raise IOError("unexpected end of tar file")
name = s[:100] name = s[:100].decode('utf-8')
i = name.find(chr(0)) i = name.find(b'\0')
if i == 0: if i == 0:
raise IOError("cannot find subfile") raise IOError("cannot find subfile")
if i > 0: if i > 0:

View File

@ -19,18 +19,16 @@
__version__ = "0.3" __version__ = "0.3"
from . import Image, ImageFile, ImagePalette from . import Image, ImageFile, ImagePalette, _binary
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Read RGA file # Read RGA file
def i16(c): i8 = _binary.i8
return ord(c[0]) + (ord(c[1])<<8) i16 = _binary.i16le
i32 = _binary.i32le
def i32(c):
return ord(c[0]) + (ord(c[1])<<8) + (ord(c[2])<<16) + (ord(c[3])<<24)
MODES = { MODES = {
@ -45,7 +43,7 @@ MODES = {
def _accept(prefix): def _accept(prefix):
return prefix[0] == "\0" return prefix[0:1] == b"\0"
## ##
# Image plugin for Targa files. # Image plugin for Targa files.
@ -60,14 +58,14 @@ class TgaImageFile(ImageFile.ImageFile):
# process header # process header
s = self.fp.read(18) s = self.fp.read(18)
id = ord(s[0]) id = i8(s[0])
colormaptype = ord(s[1]) colormaptype = i8(s[1])
imagetype = ord(s[2]) imagetype = i8(s[2])
depth = ord(s[16]) depth = i8(s[16])
flags = ord(s[17]) flags = i8(s[17])
self.size = i16(s[12:]), i16(s[14:]) self.size = i16(s[12:]), i16(s[14:])
@ -110,13 +108,13 @@ class TgaImageFile(ImageFile.ImageFile):
start, size, mapdepth = i16(s[3:]), i16(s[5:]), i16(s[7:]) start, size, mapdepth = i16(s[3:]), i16(s[5:]), i16(s[7:])
if mapdepth == 16: if mapdepth == 16:
self.palette = ImagePalette.raw("BGR;16", self.palette = ImagePalette.raw("BGR;16",
"\0"*2*start + self.fp.read(2*size)) b"\0"*2*start + self.fp.read(2*size))
elif mapdepth == 24: elif mapdepth == 24:
self.palette = ImagePalette.raw("BGR", self.palette = ImagePalette.raw("BGR",
"\0"*3*start + self.fp.read(3*size)) b"\0"*3*start + self.fp.read(3*size))
elif mapdepth == 32: elif mapdepth == 32:
self.palette = ImagePalette.raw("BGRA", self.palette = ImagePalette.raw("BGRA",
"\0"*4*start + self.fp.read(4*size)) b"\0"*4*start + self.fp.read(4*size))
# setup tile descriptor # setup tile descriptor
try: try:
@ -135,11 +133,8 @@ class TgaImageFile(ImageFile.ImageFile):
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Write TGA file # Write TGA file
def o16(i): o16 = _binary.o16le
return chr(i&255) + chr(i>>8&255) o32 = _binary.o32le
def o32(i):
return chr(i&255) + chr(i>>8&255) + chr(i>>16&255) + chr(i>>24&255)
SAVE = { SAVE = {
"1": ("1", 1, 0, 3), "1": ("1", 1, 0, 3),
@ -173,18 +168,18 @@ def _save(im, fp, filename, check=0):
if orientation > 0: if orientation > 0:
flags = flags | 0x20 flags = flags | 0x20
fp.write("\000" + fp.write(b"\000" +
chr(colormaptype) + o8(colormaptype) +
chr(imagetype) + o8(imagetype) +
o16(colormapfirst) + o16(colormapfirst) +
o16(colormaplength) + o16(colormaplength) +
chr(colormapentry) + o8(colormapentry) +
o16(0) + o16(0) +
o16(0) + o16(0) +
o16(im.size[0]) + o16(im.size[0]) +
o16(im.size[1]) + o16(im.size[1]) +
chr(bits) + o8(bits) +
chr(flags)) o8(flags))
if colormaptype: if colormaptype:
fp.write(im.im.getpalette("RGB", "BGR")) fp.write(im.im.getpalette("RGB", "BGR"))

View File

@ -45,46 +45,36 @@ __version__ = "1.3.5"
from . import Image, ImageFile from . import Image, ImageFile
from . import ImagePalette from . import ImagePalette
from . import _binary
import array, sys import array, sys
import collections import collections
import itertools import itertools
II = "II" # little-endian (intel-style) II = b"II" # little-endian (intel-style)
MM = "MM" # big-endian (motorola-style) MM = b"MM" # big-endian (motorola-style)
try: i8 = _binary.i8
if sys.byteorder == "little": o8 = _binary.o8
native_prefix = II
else: if sys.byteorder == "little":
native_prefix = MM native_prefix = II
except AttributeError: else:
if ord(array.array("i",[1]).tostring()[0]): native_prefix = MM
native_prefix = II
else:
native_prefix = MM
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Read TIFF files # Read TIFF files
def il16(c,o=0): il16 = _binary.i16le
return ord(c[o]) + (ord(c[o+1])<<8) il32 = _binary.i32le
def il32(c,o=0): ol16 = _binary.o16le
return ord(c[o]) + (ord(c[o+1])<<8) + (ord(c[o+2])<<16) + (ord(c[o+3])<<24) ol32 = _binary.o32le
def ol16(i):
return chr(i&255) + chr(i>>8&255)
def ol32(i):
return chr(i&255) + chr(i>>8&255) + chr(i>>16&255) + chr(i>>24&255)
def ib16(c,o=0): ib16 = _binary.i16be
return ord(c[o+1]) + (ord(c[o])<<8) ib32 = _binary.i32be
def ib32(c,o=0): ob16 = _binary.o16be
return ord(c[o+3]) + (ord(c[o+2])<<8) + (ord(c[o+1])<<16) + (ord(c[o])<<24) ob32 = _binary.o32be
def ob16(i):
return chr(i>>8&255) + chr(i&255)
def ob32(i):
return chr(i>>24&255) + chr(i>>16&255) + chr(i>>8&255) + chr(i&255)
# a few tag names, just to make the code below a bit more readable # a few tag names, just to make the code below a bit more readable
IMAGEWIDTH = 256 IMAGEWIDTH = 256
@ -200,7 +190,7 @@ OPEN_INFO = {
} }
PREFIXES = ["MM\000\052", "II\052\000", "II\xBC\000"] PREFIXES = [b"MM\000\052", b"II\052\000", b"II\xBC\000"]
def _accept(prefix): def _accept(prefix):
return prefix[:4] in PREFIXES return prefix[:4] in PREFIXES
@ -264,7 +254,7 @@ class ImageFileDirectory(collections.MutableMapping):
def __contains__(self, tag): def __contains__(self, tag):
return tag in self.tags or tag in self.tagdata return tag in self.tags or tag in self.tagdata
if sys.version_info < (3,0): if bytes is str:
def has_key(self, tag): def has_key(self, tag):
return tag in self return tag in self
@ -284,16 +274,13 @@ class ImageFileDirectory(collections.MutableMapping):
load_dispatch = {} load_dispatch = {}
def load_byte(self, data): def load_byte(self, data):
l = [] return data
for i in range(len(data)):
l.append(ord(data[i]))
return tuple(l)
load_dispatch[1] = (1, load_byte) load_dispatch[1] = (1, load_byte)
def load_string(self, data): def load_string(self, data):
if data[-1:] == '\0': if data[-1:] == b'\0':
data = data[:-1] data = data[:-1]
return data return data.decode('latin-1', 'replace')
load_dispatch[2] = (1, load_string) load_dispatch[2] = (1, load_string)
def load_short(self, data): def load_short(self, data):
@ -420,14 +407,14 @@ class ImageFileDirectory(collections.MutableMapping):
if typ == 1: if typ == 1:
# byte data # byte data
data = value = "".join(map(chr, value)) data = value
elif typ == 7: elif typ == 7:
# untyped data # untyped data
data = value = "".join(value) data = value = b"".join(value)
elif isinstance(value[0], str): elif isinstance(value[0], str):
# string data # string data
typ = 2 typ = 2
data = value = "\0".join(value) + "\0" data = value = b"\0".join(value.encode('ascii', 'replace')) + b"\0"
else: else:
# integer data # integer data
if tag == STRIPOFFSETS: if tag == STRIPOFFSETS:
@ -442,9 +429,9 @@ class ImageFileDirectory(collections.MutableMapping):
if v >= 65536: if v >= 65536:
typ = 4 typ = 4
if typ == 3: if typ == 3:
data = "".join(map(o16, value)) data = b"".join(map(o16, value))
else: else:
data = "".join(map(o32, value)) data = b"".join(map(o32, value))
if Image.DEBUG: if Image.DEBUG:
from . import TiffTags from . import TiffTags
@ -460,13 +447,13 @@ class ImageFileDirectory(collections.MutableMapping):
# figure out if data fits into the directory # figure out if data fits into the directory
if len(data) == 4: if len(data) == 4:
append((tag, typ, len(value), data, "")) append((tag, typ, len(value), data, b""))
elif len(data) < 4: elif len(data) < 4:
append((tag, typ, len(value), data + (4-len(data))*"\0", "")) append((tag, typ, len(value), data + (4-len(data))*b"\0", b""))
else: else:
count = len(value) count = len(value)
if typ == 5: if typ == 5:
count = count / 2 # adjust for rational data field count = count // 2 # adjust for rational data field
append((tag, typ, count, o32(offset), data)) append((tag, typ, count, o32(offset), data))
offset = offset + len(data) offset = offset + len(data)
if offset & 1: if offset & 1:
@ -486,13 +473,13 @@ class ImageFileDirectory(collections.MutableMapping):
fp.write(o16(tag) + o16(typ) + o32(count) + value) fp.write(o16(tag) + o16(typ) + o32(count) + value)
# -- overwrite here for multi-page -- # -- overwrite here for multi-page --
fp.write("\0\0\0\0") # end of directory fp.write(b"\0\0\0\0") # end of directory
# pass 3: write auxiliary data to file # pass 3: write auxiliary data to file
for tag, typ, count, value, data in directory: for tag, typ, count, value, data in directory:
fp.write(data) fp.write(data)
if len(data) & 1: if len(data) & 1:
fp.write("\0") fp.write(b"\0")
return offset return offset
@ -702,8 +689,8 @@ class TiffImageFile(ImageFile.ImageFile):
# fixup palette descriptor # fixup palette descriptor
if self.mode == "P": if self.mode == "P":
palette = [chr(a / 256) for a in self.tag[COLORMAP]] palette = [o8(a // 256) for a in self.tag[COLORMAP]]
self.palette = ImagePalette.raw("RGB;L", "".join(palette)) self.palette = ImagePalette.raw("RGB;L", b"".join(palette))
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Write TIFF files # Write TIFF files
@ -824,10 +811,10 @@ def _save(im, fp, filename):
if im.mode == "P": if im.mode == "P":
lut = im.im.getpalette("RGB", "RGB;L") lut = im.im.getpalette("RGB", "RGB;L")
ifd[COLORMAP] = tuple(ord(v) * 256 for v in lut) ifd[COLORMAP] = tuple(i8(v) * 256 for v in lut)
# data orientation # data orientation
stride = len(bits) * ((im.size[0]*bits[0]+7)/8) stride = len(bits) * ((im.size[0]*bits[0]+7)//8)
ifd[ROWSPERSTRIP] = im.size[1] ifd[ROWSPERSTRIP] = im.size[1]
ifd[STRIPBYTECOUNTS] = stride * im.size[1] ifd[STRIPBYTECOUNTS] = stride * im.size[1]
ifd[STRIPOFFSETS] = 0 # this is adjusted by IFD writer ifd[STRIPOFFSETS] = 0 # this is adjusted by IFD writer

View File

@ -23,7 +23,7 @@
from __future__ import print_function from __future__ import print_function
from . import Image from . import Image, _binary
try: try:
import builtins import builtins
@ -31,8 +31,7 @@ except ImportError:
import __builtin__ import __builtin__
builtins = __builtin__ builtins = __builtin__
def i32(c, o=0): i32 = _binary.i32le
return ord(c[o])+(ord(c[o+1])<<8)+(ord(c[o+2])<<16)+(ord(c[o+3])<<24)
## ##
# Load texture from a Quake2 WAL texture file. # Load texture from a Quake2 WAL texture file.
@ -60,15 +59,15 @@ def open(filename):
# load pixel data # load pixel data
fp.seek(offset) fp.seek(offset)
im = Image.fromstring("P", size, fp.read(size[0] * size[1])) im = Image.frombytes("P", size, fp.read(size[0] * size[1]))
im.putpalette(quake2palette) im.putpalette(quake2palette)
im.format = "WAL" im.format = "WAL"
im.format_description = "Quake2 Texture" im.format_description = "Quake2 Texture"
# strings are null-terminated # strings are null-terminated
im.info["name"] = header[:32].split("\0", 1)[0] im.info["name"] = header[:32].split(b"\0", 1)[0]
next_name = header[56:56+32].split("\0", 1)[0] next_name = header[56:56+32].split(b"\0", 1)[0]
if next_name: if next_name:
im.info["next_name"] = next_name im.info["next_name"] = next_name
@ -77,54 +76,54 @@ def open(filename):
quake2palette = ( quake2palette = (
# default palette taken from piffo 0.93 by Hans Häggström # default palette taken from piffo 0.93 by Hans Häggström
"\x01\x01\x01\x0b\x0b\x0b\x12\x12\x12\x17\x17\x17\x1b\x1b\x1b\x1e" b"\x01\x01\x01\x0b\x0b\x0b\x12\x12\x12\x17\x17\x17\x1b\x1b\x1b\x1e"
"\x1e\x1e\x22\x22\x22\x26\x26\x26\x29\x29\x29\x2c\x2c\x2c\x2f\x2f" b"\x1e\x1e\x22\x22\x22\x26\x26\x26\x29\x29\x29\x2c\x2c\x2c\x2f\x2f"
"\x2f\x32\x32\x32\x35\x35\x35\x37\x37\x37\x3a\x3a\x3a\x3c\x3c\x3c" b"\x2f\x32\x32\x32\x35\x35\x35\x37\x37\x37\x3a\x3a\x3a\x3c\x3c\x3c"
"\x24\x1e\x13\x22\x1c\x12\x20\x1b\x12\x1f\x1a\x10\x1d\x19\x10\x1b" b"\x24\x1e\x13\x22\x1c\x12\x20\x1b\x12\x1f\x1a\x10\x1d\x19\x10\x1b"
"\x17\x0f\x1a\x16\x0f\x18\x14\x0d\x17\x13\x0d\x16\x12\x0d\x14\x10" b"\x17\x0f\x1a\x16\x0f\x18\x14\x0d\x17\x13\x0d\x16\x12\x0d\x14\x10"
"\x0b\x13\x0f\x0b\x10\x0d\x0a\x0f\x0b\x0a\x0d\x0b\x07\x0b\x0a\x07" b"\x0b\x13\x0f\x0b\x10\x0d\x0a\x0f\x0b\x0a\x0d\x0b\x07\x0b\x0a\x07"
"\x23\x23\x26\x22\x22\x25\x22\x20\x23\x21\x1f\x22\x20\x1e\x20\x1f" b"\x23\x23\x26\x22\x22\x25\x22\x20\x23\x21\x1f\x22\x20\x1e\x20\x1f"
"\x1d\x1e\x1d\x1b\x1c\x1b\x1a\x1a\x1a\x19\x19\x18\x17\x17\x17\x16" b"\x1d\x1e\x1d\x1b\x1c\x1b\x1a\x1a\x1a\x19\x19\x18\x17\x17\x17\x16"
"\x16\x14\x14\x14\x13\x13\x13\x10\x10\x10\x0f\x0f\x0f\x0d\x0d\x0d" b"\x16\x14\x14\x14\x13\x13\x13\x10\x10\x10\x0f\x0f\x0f\x0d\x0d\x0d"
"\x2d\x28\x20\x29\x24\x1c\x27\x22\x1a\x25\x1f\x17\x38\x2e\x1e\x31" b"\x2d\x28\x20\x29\x24\x1c\x27\x22\x1a\x25\x1f\x17\x38\x2e\x1e\x31"
"\x29\x1a\x2c\x25\x17\x26\x20\x14\x3c\x30\x14\x37\x2c\x13\x33\x28" b"\x29\x1a\x2c\x25\x17\x26\x20\x14\x3c\x30\x14\x37\x2c\x13\x33\x28"
"\x12\x2d\x24\x10\x28\x1f\x0f\x22\x1a\x0b\x1b\x14\x0a\x13\x0f\x07" b"\x12\x2d\x24\x10\x28\x1f\x0f\x22\x1a\x0b\x1b\x14\x0a\x13\x0f\x07"
"\x31\x1a\x16\x30\x17\x13\x2e\x16\x10\x2c\x14\x0d\x2a\x12\x0b\x27" b"\x31\x1a\x16\x30\x17\x13\x2e\x16\x10\x2c\x14\x0d\x2a\x12\x0b\x27"
"\x0f\x0a\x25\x0f\x07\x21\x0d\x01\x1e\x0b\x01\x1c\x0b\x01\x1a\x0b" b"\x0f\x0a\x25\x0f\x07\x21\x0d\x01\x1e\x0b\x01\x1c\x0b\x01\x1a\x0b"
"\x01\x18\x0a\x01\x16\x0a\x01\x13\x0a\x01\x10\x07\x01\x0d\x07\x01" b"\x01\x18\x0a\x01\x16\x0a\x01\x13\x0a\x01\x10\x07\x01\x0d\x07\x01"
"\x29\x23\x1e\x27\x21\x1c\x26\x20\x1b\x25\x1f\x1a\x23\x1d\x19\x21" b"\x29\x23\x1e\x27\x21\x1c\x26\x20\x1b\x25\x1f\x1a\x23\x1d\x19\x21"
"\x1c\x18\x20\x1b\x17\x1e\x19\x16\x1c\x18\x14\x1b\x17\x13\x19\x14" b"\x1c\x18\x20\x1b\x17\x1e\x19\x16\x1c\x18\x14\x1b\x17\x13\x19\x14"
"\x10\x17\x13\x0f\x14\x10\x0d\x12\x0f\x0b\x0f\x0b\x0a\x0b\x0a\x07" b"\x10\x17\x13\x0f\x14\x10\x0d\x12\x0f\x0b\x0f\x0b\x0a\x0b\x0a\x07"
"\x26\x1a\x0f\x23\x19\x0f\x20\x17\x0f\x1c\x16\x0f\x19\x13\x0d\x14" b"\x26\x1a\x0f\x23\x19\x0f\x20\x17\x0f\x1c\x16\x0f\x19\x13\x0d\x14"
"\x10\x0b\x10\x0d\x0a\x0b\x0a\x07\x33\x22\x1f\x35\x29\x26\x37\x2f" b"\x10\x0b\x10\x0d\x0a\x0b\x0a\x07\x33\x22\x1f\x35\x29\x26\x37\x2f"
"\x2d\x39\x35\x34\x37\x39\x3a\x33\x37\x39\x30\x34\x36\x2b\x31\x34" b"\x2d\x39\x35\x34\x37\x39\x3a\x33\x37\x39\x30\x34\x36\x2b\x31\x34"
"\x27\x2e\x31\x22\x2b\x2f\x1d\x28\x2c\x17\x25\x2a\x0f\x20\x26\x0d" b"\x27\x2e\x31\x22\x2b\x2f\x1d\x28\x2c\x17\x25\x2a\x0f\x20\x26\x0d"
"\x1e\x25\x0b\x1c\x22\x0a\x1b\x20\x07\x19\x1e\x07\x17\x1b\x07\x14" b"\x1e\x25\x0b\x1c\x22\x0a\x1b\x20\x07\x19\x1e\x07\x17\x1b\x07\x14"
"\x18\x01\x12\x16\x01\x0f\x12\x01\x0b\x0d\x01\x07\x0a\x01\x01\x01" b"\x18\x01\x12\x16\x01\x0f\x12\x01\x0b\x0d\x01\x07\x0a\x01\x01\x01"
"\x2c\x21\x21\x2a\x1f\x1f\x29\x1d\x1d\x27\x1c\x1c\x26\x1a\x1a\x24" b"\x2c\x21\x21\x2a\x1f\x1f\x29\x1d\x1d\x27\x1c\x1c\x26\x1a\x1a\x24"
"\x18\x18\x22\x17\x17\x21\x16\x16\x1e\x13\x13\x1b\x12\x12\x18\x10" b"\x18\x18\x22\x17\x17\x21\x16\x16\x1e\x13\x13\x1b\x12\x12\x18\x10"
"\x10\x16\x0d\x0d\x12\x0b\x0b\x0d\x0a\x0a\x0a\x07\x07\x01\x01\x01" b"\x10\x16\x0d\x0d\x12\x0b\x0b\x0d\x0a\x0a\x0a\x07\x07\x01\x01\x01"
"\x2e\x30\x29\x2d\x2e\x27\x2b\x2c\x26\x2a\x2a\x24\x28\x29\x23\x27" b"\x2e\x30\x29\x2d\x2e\x27\x2b\x2c\x26\x2a\x2a\x24\x28\x29\x23\x27"
"\x27\x21\x26\x26\x1f\x24\x24\x1d\x22\x22\x1c\x1f\x1f\x1a\x1c\x1c" b"\x27\x21\x26\x26\x1f\x24\x24\x1d\x22\x22\x1c\x1f\x1f\x1a\x1c\x1c"
"\x18\x19\x19\x16\x17\x17\x13\x13\x13\x10\x0f\x0f\x0d\x0b\x0b\x0a" b"\x18\x19\x19\x16\x17\x17\x13\x13\x13\x10\x0f\x0f\x0d\x0b\x0b\x0a"
"\x30\x1e\x1b\x2d\x1c\x19\x2c\x1a\x17\x2a\x19\x14\x28\x17\x13\x26" b"\x30\x1e\x1b\x2d\x1c\x19\x2c\x1a\x17\x2a\x19\x14\x28\x17\x13\x26"
"\x16\x10\x24\x13\x0f\x21\x12\x0d\x1f\x10\x0b\x1c\x0f\x0a\x19\x0d" b"\x16\x10\x24\x13\x0f\x21\x12\x0d\x1f\x10\x0b\x1c\x0f\x0a\x19\x0d"
"\x0a\x16\x0b\x07\x12\x0a\x07\x0f\x07\x01\x0a\x01\x01\x01\x01\x01" b"\x0a\x16\x0b\x07\x12\x0a\x07\x0f\x07\x01\x0a\x01\x01\x01\x01\x01"
"\x28\x29\x38\x26\x27\x36\x25\x26\x34\x24\x24\x31\x22\x22\x2f\x20" b"\x28\x29\x38\x26\x27\x36\x25\x26\x34\x24\x24\x31\x22\x22\x2f\x20"
"\x21\x2d\x1e\x1f\x2a\x1d\x1d\x27\x1b\x1b\x25\x19\x19\x21\x17\x17" b"\x21\x2d\x1e\x1f\x2a\x1d\x1d\x27\x1b\x1b\x25\x19\x19\x21\x17\x17"
"\x1e\x14\x14\x1b\x13\x12\x17\x10\x0f\x13\x0d\x0b\x0f\x0a\x07\x07" b"\x1e\x14\x14\x1b\x13\x12\x17\x10\x0f\x13\x0d\x0b\x0f\x0a\x07\x07"
"\x2f\x32\x29\x2d\x30\x26\x2b\x2e\x24\x29\x2c\x21\x27\x2a\x1e\x25" b"\x2f\x32\x29\x2d\x30\x26\x2b\x2e\x24\x29\x2c\x21\x27\x2a\x1e\x25"
"\x28\x1c\x23\x26\x1a\x21\x25\x18\x1e\x22\x14\x1b\x1f\x10\x19\x1c" b"\x28\x1c\x23\x26\x1a\x21\x25\x18\x1e\x22\x14\x1b\x1f\x10\x19\x1c"
"\x0d\x17\x1a\x0a\x13\x17\x07\x10\x13\x01\x0d\x0f\x01\x0a\x0b\x01" b"\x0d\x17\x1a\x0a\x13\x17\x07\x10\x13\x01\x0d\x0f\x01\x0a\x0b\x01"
"\x01\x3f\x01\x13\x3c\x0b\x1b\x39\x10\x20\x35\x14\x23\x31\x17\x23" b"\x01\x3f\x01\x13\x3c\x0b\x1b\x39\x10\x20\x35\x14\x23\x31\x17\x23"
"\x2d\x18\x23\x29\x18\x3f\x3f\x3f\x3f\x3f\x39\x3f\x3f\x31\x3f\x3f" b"\x2d\x18\x23\x29\x18\x3f\x3f\x3f\x3f\x3f\x39\x3f\x3f\x31\x3f\x3f"
"\x2a\x3f\x3f\x20\x3f\x3f\x14\x3f\x3c\x12\x3f\x39\x0f\x3f\x35\x0b" b"\x2a\x3f\x3f\x20\x3f\x3f\x14\x3f\x3c\x12\x3f\x39\x0f\x3f\x35\x0b"
"\x3f\x32\x07\x3f\x2d\x01\x3d\x2a\x01\x3b\x26\x01\x39\x21\x01\x37" b"\x3f\x32\x07\x3f\x2d\x01\x3d\x2a\x01\x3b\x26\x01\x39\x21\x01\x37"
"\x1d\x01\x34\x1a\x01\x32\x16\x01\x2f\x12\x01\x2d\x0f\x01\x2a\x0b" b"\x1d\x01\x34\x1a\x01\x32\x16\x01\x2f\x12\x01\x2d\x0f\x01\x2a\x0b"
"\x01\x27\x07\x01\x23\x01\x01\x1d\x01\x01\x17\x01\x01\x10\x01\x01" b"\x01\x27\x07\x01\x23\x01\x01\x1d\x01\x01\x17\x01\x01\x10\x01\x01"
"\x3d\x01\x01\x19\x19\x3f\x3f\x01\x01\x01\x01\x3f\x16\x16\x13\x10" b"\x3d\x01\x01\x19\x19\x3f\x3f\x01\x01\x01\x01\x3f\x16\x16\x13\x10"
"\x10\x0f\x0d\x0d\x0b\x3c\x2e\x2a\x36\x27\x20\x30\x21\x18\x29\x1b" b"\x10\x0f\x0d\x0d\x0b\x3c\x2e\x2a\x36\x27\x20\x30\x21\x18\x29\x1b"
"\x10\x3c\x39\x37\x37\x32\x2f\x31\x2c\x28\x2b\x26\x21\x30\x22\x20" b"\x10\x3c\x39\x37\x37\x32\x2f\x31\x2c\x28\x2b\x26\x21\x30\x22\x20"
) )
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -17,7 +17,7 @@
__version__ = "0.2" __version__ = "0.2"
from . import Image, ImageFile from . import Image, ImageFile, _binary
_handler = None _handler = None
@ -44,7 +44,7 @@ if hasattr(Image.core, "drawwmf"):
def load(self, im): def load(self, im):
im.fp.seek(0) # rewind im.fp.seek(0) # rewind
return Image.fromstring( return Image.frombytes(
"RGB", im.size, "RGB", im.size,
Image.core.drawwmf(im.fp.read(), im.size, self.bbox), Image.core.drawwmf(im.fp.read(), im.size, self.bbox),
"raw", "BGR", (im.size[0]*3 + 3) & -4, -1 "raw", "BGR", (im.size[0]*3 + 3) & -4, -1
@ -54,20 +54,15 @@ if hasattr(Image.core, "drawwmf"):
# -------------------------------------------------------------------- # --------------------------------------------------------------------
def word(c, o=0): word = _binary.i16le
return ord(c[o]) + (ord(c[o+1])<<8)
def short(c, o=0): def short(c, o=0):
v = ord(c[o]) + (ord(c[o+1])<<8) v = word(c, o)
if v >= 32768: if v >= 32768:
v = v - 65536 v = v - 65536
return v return v
def dword(c, o=0): dword = _binary.i32le
return ord(c[o]) + (ord(c[o+1])<<8) + (ord(c[o+2])<<16) + (ord(c[o+3])<<24)
def long(c, o=0):
return dword(c, o)
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
@ -75,8 +70,8 @@ def long(c, o=0):
def _accept(prefix): def _accept(prefix):
return ( return (
prefix[:6] == "\xd7\xcd\xc6\x9a\x00\x00" or prefix[:6] == b"\xd7\xcd\xc6\x9a\x00\x00" or
prefix[:4] == "\x01\x00\x00\x00" prefix[:4] == b"\x01\x00\x00\x00"
) )
## ##
@ -92,7 +87,7 @@ class WmfStubImageFile(ImageFile.StubImageFile):
# check placable header # check placable header
s = self.fp.read(80) s = self.fp.read(80)
if s[:6] == "\xd7\xcd\xc6\x9a\x00\x00": if s[:6] == b"\xd7\xcd\xc6\x9a\x00\x00":
# placeable windows metafile # placeable windows metafile
@ -104,7 +99,7 @@ class WmfStubImageFile(ImageFile.StubImageFile):
x1 = short(s, 10); y1 = short(s, 12) x1 = short(s, 10); y1 = short(s, 12)
# normalize size to 72 dots per inch # normalize size to 72 dots per inch
size = (x1 - x0) * 72 / inch, (y1 - y0) * 72 / inch size = (x1 - x0) * 72 // inch, (y1 - y0) * 72 // inch
self.info["wmf_bbox"] = x0, y0, x1, y1 self.info["wmf_bbox"] = x0, y0, x1, y1
@ -113,25 +108,25 @@ class WmfStubImageFile(ImageFile.StubImageFile):
# print self.mode, self.size, self.info # print self.mode, self.size, self.info
# sanity check (standard metafile header) # sanity check (standard metafile header)
if s[22:26] != "\x01\x00\t\x00": if s[22:26] != b"\x01\x00\t\x00":
raise SyntaxError("Unsupported WMF file format") raise SyntaxError("Unsupported WMF file format")
elif long(s) == 1 and s[40:44] == " EMF": elif dword(s) == 1 and s[40:44] == b" EMF":
# enhanced metafile # enhanced metafile
# get bounding box # get bounding box
x0 = long(s, 8); y0 = long(s, 12) x0 = dword(s, 8); y0 = dword(s, 12)
x1 = long(s, 16); y1 = long(s, 20) x1 = dword(s, 16); y1 = dword(s, 20)
# get frame (in 0.01 millimeter units) # get frame (in 0.01 millimeter units)
frame = long(s, 24), long(s, 28), long(s, 32), long(s, 36) frame = dword(s, 24), dword(s, 28), dword(s, 32), dword(s, 36)
# normalize size to 72 dots per inch # normalize size to 72 dots per inch
size = x1 - x0, y1 - y0 size = x1 - x0, y1 - y0
# calculate dots per inch from bbox and frame # calculate dots per inch from bbox and frame
xdpi = 2540 * (x1 - y0) / (frame[2] - frame[0]) xdpi = 2540 * (x1 - y0) // (frame[2] - frame[0])
ydpi = 2540 * (y1 - y0) / (frame[3] - frame[1]) ydpi = 2540 * (y1 - y0) // (frame[3] - frame[1])
self.info["wmf_bbox"] = x0, y0, x1, y1 self.info["wmf_bbox"] = x0, y0, x1, y1

View File

@ -19,14 +19,16 @@
__version__ = "0.1" __version__ = "0.1"
from . import Image, ImageFile, ImagePalette from . import Image, ImageFile, ImagePalette, _binary
o8 = _binary.o8
# standard color palette for thumbnails (RGB332) # standard color palette for thumbnails (RGB332)
PALETTE = "" PALETTE = b""
for r in range(8): for r in range(8):
for g in range(8): for g in range(8):
for b in range(4): for b in range(4):
PALETTE = PALETTE + (chr((r*255)/7)+chr((g*255)/7)+chr((b*255)/3)) PALETTE = PALETTE + (o8((r*255)//7)+o8((g*255)//7)+o8((b*255)//3))
## ##
# Image plugin for XV thumbnail images. # Image plugin for XV thumbnail images.
@ -40,7 +42,7 @@ class XVThumbImageFile(ImageFile.ImageFile):
# check magic # check magic
s = self.fp.read(6) s = self.fp.read(6)
if s != "P7 332": if s != b"P7 332":
raise SyntaxError("not an XV thumbnail file") raise SyntaxError("not an XV thumbnail file")
# Skip to beginning of next line # Skip to beginning of next line
@ -51,14 +53,14 @@ class XVThumbImageFile(ImageFile.ImageFile):
s = self.fp.readline() s = self.fp.readline()
if not s: if not s:
raise SyntaxError("Unexpected EOF reading XV thumbnail file") raise SyntaxError("Unexpected EOF reading XV thumbnail file")
if s[0] != '#': if s[0] != b'#':
break break
# parse header line (already read) # parse header line (already read)
s = s.strip().split() s = s.strip().split()
self.mode = "P" self.mode = "P"
self.size = int(s[0]), int(s[1]) self.size = int(s[0:1]), int(s[1:2])
self.palette = ImagePalette.raw("RGB", PALETTE) self.palette = ImagePalette.raw("RGB", PALETTE)

View File

@ -26,17 +26,17 @@ from . import Image, ImageFile
# XBM header # XBM header
xbm_head = re.compile( xbm_head = re.compile(
"\s*#define[ \t]+[^_]*_width[ \t]+(?P<width>[0-9]+)[\r\n]+" b"\s*#define[ \t]+[^_]*_width[ \t]+(?P<width>[0-9]+)[\r\n]+"
"#define[ \t]+[^_]*_height[ \t]+(?P<height>[0-9]+)[\r\n]+" b"#define[ \t]+[^_]*_height[ \t]+(?P<height>[0-9]+)[\r\n]+"
"(?P<hotspot>" b"(?P<hotspot>"
"#define[ \t]+[^_]*_x_hot[ \t]+(?P<xhot>[0-9]+)[\r\n]+" b"#define[ \t]+[^_]*_x_hot[ \t]+(?P<xhot>[0-9]+)[\r\n]+"
"#define[ \t]+[^_]*_y_hot[ \t]+(?P<yhot>[0-9]+)[\r\n]+" b"#define[ \t]+[^_]*_y_hot[ \t]+(?P<yhot>[0-9]+)[\r\n]+"
")?" b")?"
"[\\000-\\377]*_bits\\[\\]" b"[\\000-\\377]*_bits\\[\\]"
) )
def _accept(prefix): def _accept(prefix):
return prefix.lstrip()[:7] == "#define" return prefix.lstrip()[:7] == b"#define"
## ##
# Image plugin for X11 bitmaps. # Image plugin for X11 bitmaps.
@ -71,19 +71,19 @@ def _save(im, fp, filename):
if im.mode != "1": if im.mode != "1":
raise IOError("cannot write mode %s as XBM" % im.mode) raise IOError("cannot write mode %s as XBM" % im.mode)
fp.write("#define im_width %d\n" % im.size[0]) fp.write(("#define im_width %d\n" % im.size[0]).encode('ascii'))
fp.write("#define im_height %d\n" % im.size[1]) fp.write(("#define im_height %d\n" % im.size[1]).encode('ascii'))
hotspot = im.encoderinfo.get("hotspot") hotspot = im.encoderinfo.get("hotspot")
if hotspot: if hotspot:
fp.write("#define im_x_hot %d\n" % hotspot[0]) fp.write(("#define im_x_hot %d\n" % hotspot[0]).encode('ascii'))
fp.write("#define im_y_hot %d\n" % hotspot[1]) fp.write(("#define im_y_hot %d\n" % hotspot[1]).encode('ascii'))
fp.write("static char im_bits[] = {\n") fp.write(b"static char im_bits[] = {\n")
ImageFile._save(im, fp, [("xbm", (0,0)+im.size, 0, None)]) ImageFile._save(im, fp, [("xbm", (0,0)+im.size, 0, None)])
fp.write("};\n") fp.write(b"};\n")
Image.register_open("XBM", XbmImageFile, _accept) Image.register_open("XBM", XbmImageFile, _accept)

View File

@ -20,13 +20,14 @@ __version__ = "0.2"
import re import re
from . import Image, ImageFile, ImagePalette from . import Image, ImageFile, ImagePalette
from ._binary import i8, o8
# XPM header # XPM header
xpm_head = re.compile("\"([0-9]*) ([0-9]*) ([0-9]*) ([0-9]*)") xpm_head = re.compile(b"\"([0-9]*) ([0-9]*) ([0-9]*) ([0-9]*)")
def _accept(prefix): def _accept(prefix):
return prefix[:9] == "/* XPM */" return prefix[:9] == b"/* XPM */"
## ##
# Image plugin for X11 pixel maps. # Image plugin for X11 pixel maps.
@ -61,17 +62,17 @@ class XpmImageFile(ImageFile.ImageFile):
# #
# load palette description # load palette description
palette = ["\0\0\0"] * 256 palette = [b"\0\0\0"] * 256
for i in range(pal): for i in range(pal):
s = self.fp.readline() s = self.fp.readline()
if s[-2:] == '\r\n': if s[-2:] == b'\r\n':
s = s[:-2] s = s[:-2]
elif s[-1:] in '\r\n': elif s[-1:] in b'\r\n':
s = s[:-1] s = s[:-1]
c = ord(s[1]) c = i8(s[1])
s = s[2:-2].split() s = s[2:-2].split()
for i in range(0, len(s), 2): for i in range(0, len(s), 2):
@ -80,14 +81,14 @@ class XpmImageFile(ImageFile.ImageFile):
# process colour key # process colour key
rgb = s[i+1] rgb = s[i+1]
if rgb == "None": if rgb == b"None":
self.info["transparency"] = c self.info["transparency"] = c
elif rgb[0] == "#": elif rgb[0] == b"#":
# FIXME: handle colour names (see ImagePalette.py) # FIXME: handle colour names (see ImagePalette.py)
rgb = int(rgb[1:], 16) rgb = int(rgb[1:], 16)
palette[c] = chr((rgb >> 16) & 255) +\ palette[c] = o8((rgb >> 16) & 255) +\
chr((rgb >> 8) & 255) +\ o8((rgb >> 8) & 255) +\
chr(rgb & 255) o8(rgb & 255)
else: else:
# unknown colour # unknown colour
raise ValueError("cannot read this XPM file") raise ValueError("cannot read this XPM file")
@ -99,7 +100,7 @@ class XpmImageFile(ImageFile.ImageFile):
raise ValueError("cannot read this XPM file") raise ValueError("cannot read this XPM file")
self.mode = "P" self.mode = "P"
self.palette = ImagePalette.raw("RGB", "".join(palette)) self.palette = ImagePalette.raw("RGB", b"".join(palette))
self.tile = [("raw", (0, 0)+self.size, self.fp.tell(), ("P", 0, 1))] self.tile = [("raw", (0, 0)+self.size, self.fp.tell(), ("P", 0, 1))]
@ -117,7 +118,7 @@ class XpmImageFile(ImageFile.ImageFile):
self.fp = None self.fp = None
return "".join(s) return b"".join(s)
# #
# Registry # Registry

52
PIL/_binary.py Normal file
View File

@ -0,0 +1,52 @@
#
# The Python Imaging Library.
# $Id$
#
# Binary input/output support routines.
#
# Copyright (c) 1997-2003 by Secret Labs AB
# Copyright (c) 1995-2003 by Fredrik Lundh
# Copyright (c) 2012 by Brian Crowell
#
# See the README file for information on usage and redistribution.
#
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,))
# Input, le = little endian, be = big endian
def i16le(c, o=0):
return i8(c[o]) | (i8(c[o+1])<<8)
def i32le(c, o=0):
return i8(c[o]) | (i8(c[o+1])<<8) | (i8(c[o+2])<<16) | (i8(c[o+3])<<24)
def i16be(c, o=0):
return (i8(c[o])<<8) | i8(c[o+1])
def i32be(c, o=0):
return (i8(c[o])<<24) | (i8(c[o+1])<<16) | (i8(c[o+2])<<8) | i8(c[o+3])
# Output, le = little endian, be = big endian
def o16le(i):
return o8(i) + o8(i>>8)
def o32le(i):
return o8(i) + o8(i>>8) + o8(i>>16) + o8(i>>24)
def o16be(i):
return o8(i>>8) + o8(i)
def o32be(i):
return o8(i>>24) + o8(i>>16) + o8(i>>8) + o8(i)

View File

@ -16,13 +16,13 @@ import Image
def toImage(arr): def toImage(arr):
if arr.type().bytes == 1: if arr.type().bytes == 1:
# need to swap coordinates btw array and image (with [::-1]) # need to swap coordinates btw array and image (with [::-1])
im = Image.fromstring('L', arr.shape[::-1], arr.tostring()) im = Image.frombytes('L', arr.shape[::-1], arr.tostring())
else: else:
arr_c = arr - arr.min() arr_c = arr - arr.min()
arr_c *= (255./arr_c.max()) arr_c *= (255./arr_c.max())
arr = arr_c.astype(UInt8) arr = arr_c.astype(UInt8)
# need to swap coordinates btw array and image (with [::-1]) # need to swap coordinates btw array and image (with [::-1])
im = Image.fromstring('L', arr.shape[::-1], arr.tostring()) im = Image.frombytes('L', arr.shape[::-1], arr.tostring())
return im return im
print('SANE version:', sane.init()) print('SANE version:', sane.init())

View File

@ -88,16 +88,16 @@ def test_bad_text():
assert_equal(im.info, {}) assert_equal(im.info, {})
im = load(HEAD + chunk(b'tEXt', b'spam') + TAIL) im = load(HEAD + chunk(b'tEXt', b'spam') + TAIL)
assert_equal(im.info, {b'spam': b''}) assert_equal(im.info, {'spam': ''})
im = load(HEAD + chunk(b'tEXt', b'spam\0') + TAIL) im = load(HEAD + chunk(b'tEXt', b'spam\0') + TAIL)
assert_equal(im.info, {b'spam': b''}) assert_equal(im.info, {'spam': ''})
im = load(HEAD + chunk(b'tEXt', b'spam\0egg') + TAIL) im = load(HEAD + chunk(b'tEXt', b'spam\0egg') + TAIL)
assert_equal(im.info, {b'spam': b'egg'}) assert_equal(im.info, {'spam': 'egg'})
im = load(HEAD + chunk(b'tEXt', b'spam\0egg\0') + TAIL) im = load(HEAD + chunk(b'tEXt', b'spam\0egg\0') + TAIL)
assert_equal(im.info, {b'spam': b'egg\x00'}) assert_equal(im.info, {'spam': 'egg\x00'})
def test_interlace(): def test_interlace():
@ -141,12 +141,12 @@ def test_roundtrip_text():
im = Image.open(file) im = Image.open(file)
info = PngImagePlugin.PngInfo() info = PngImagePlugin.PngInfo()
info.add_text(b"TXT", b"VALUE") info.add_text("TXT", "VALUE")
info.add_text(b"ZIP", b"VALUE", 1) info.add_text("ZIP", "VALUE", 1)
im = roundtrip(im, pnginfo=info) im = roundtrip(im, pnginfo=info)
assert_equal(im.info, {b'TXT': b'VALUE', b'ZIP': b'VALUE'}) assert_equal(im.info, {'TXT': 'VALUE', 'ZIP': 'VALUE'})
assert_equal(im.text, {b'TXT': b'VALUE', b'ZIP': b'VALUE'}) assert_equal(im.text, {'TXT': 'VALUE', 'ZIP': 'VALUE'})
def test_scary(): def test_scary():
# Check reading of evil PNG file. For information, see: # Check reading of evil PNG file. For information, see:

View File

@ -33,11 +33,11 @@ The PIL.Image Module
**frombuffer(mode, size, data, decoder\_name="raw", \*args)** **frombuffer(mode, size, data, decoder\_name="raw", \*args)**
[`# <#PIL.Image.frombuffer-function>`_] [`# <#PIL.Image.frombuffer-function>`_]
(New in 1.1.4) Creates an image memory from pixel data in a string (New in 1.1.4) Creates an image memory referencing pixel data in a
or byte buffer. byte buffer.
This function is similar to This function is similar to
`**fromstring** <#PIL.Image.fromstring-function>`_, but uses data in `**frombytes** <#PIL.Image.frombytes-function>`_, but uses data in
the byte buffer, where possible. This means that changes to the the byte buffer, where possible. This means that changes to the
original buffer object are reflected in this image). Not all modes original buffer object are reflected in this image). Not all modes
can share memory; support modes include "L", "RGBX", "RGBA", and can share memory; support modes include "L", "RGBX", "RGBA", and
@ -56,9 +56,9 @@ The PIL.Image Module
*\*args* *\*args*
Returns: Returns:
**fromstring(mode, size, data, decoder\_name="raw", \*args)** **frombytes(mode, size, data, decoder\_name="raw", \*args)**
[`# <#PIL.Image.fromstring-function>`_] [`# <#PIL.Image.frombytes-function>`_]
Creates an image memory from pixel data in a string. Creates a copy of an image memory from pixel data in a buffer.
In its simplest form, this function takes three arguments (mode, In its simplest form, this function takes three arguments (mode,
size, and unpacked pixel data). size, and unpacked pixel data).
@ -233,14 +233,16 @@ The Image Class
*filter* *filter*
Returns: Returns:
**fromstring(data, decoder\_name="raw", \*args)** **frombytes(data, decoder\_name="raw", \*args)**
[`# <#PIL.Image.Image.fromstring-method>`_] [`# <#PIL.Image.Image.frombytes-method>`_]
Loads this image with pixel data from a string. Loads this image with pixel data from a byte uffer.
This method is similar to the This method is similar to the
`**fromstring** <#PIL.Image.fromstring-function>`_ function, but `**frombytes** <#PIL.Image.frombytes-function>`_ function, but
loads data into this image instead of creating a new image object. loads data into this image instead of creating a new image object.
(In Python 2.6 and 2.7, this is also available as fromstring().)
**getbands()** [`# <#PIL.Image.Image.getbands-method>`_] **getbands()** [`# <#PIL.Image.Image.getbands-method>`_]
Returns a tuple containing the name of each band in this image. For Returns a tuple containing the name of each band in this image. For
example, **getbands** on an RGB image returns ("R", "G", "B"). example, **getbands** on an RGB image returns ("R", "G", "B").
@ -516,8 +518,9 @@ The Image Class
Returns: Returns:
Raises **ValueError**: Raises **ValueError**:
**tostring(encoder\_name="raw", \*args)** **tobytes(encoder\_name="raw", \*args)**
[`# <#PIL.Image.Image.tostring-method>`_] [`# <#PIL.Image.Image.tobytes-method>`_]
(In Python 2.6 and 2.7, this is also available as tostring().)
*encoder\_name* *encoder\_name*
*\*args* *\*args*

View File

@ -58,11 +58,12 @@ The Dib Class
instance. In PythonWin, you can use the **GetHandleAttrib** instance. In PythonWin, you can use the **GetHandleAttrib**
method of the **CDC** class to get a suitable handle. method of the **CDC** class to get a suitable handle.
**fromstring(buffer)** [`# <#PIL.ImageWin.Dib.fromstring-method>`_] **frombytes(buffer)** [`# <#PIL.ImageWin.Dib.frombytes-method>`_]
(For Python 2.6/2.7, this is also available as fromstring(buffer).)
*buffer* *buffer*
A string buffer containing display data (usually data returned A byte buffer containing display data (usually data returned
from **tostring**) from **tobytes**)
**paste(im, box=None)** [`# <#PIL.ImageWin.Dib.paste-method>`_] **paste(im, box=None)** [`# <#PIL.ImageWin.Dib.paste-method>`_]
@ -82,7 +83,7 @@ The Dib Class
*handle* *handle*
Returns: Returns:
**tostring()** [`# <#PIL.ImageWin.Dib.tostring-method>`_] **tobytes()** [`# <#PIL.ImageWin.Dib.tobytes-method>`_]
Returns: Returns: