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 .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
@ -67,7 +67,7 @@ class ArgStream(ChunkStream):
s = self.fp.read(bytes)
self.size = i32(s), i32(s[4:])
try:
self.mode, self.rawmode = _MODES[(ord(s[8]), ord(s[9]))]
self.mode, self.rawmode = _MODES[(i8(s[8]), i8(s[9]))]
except:
raise SyntaxError("unknown ARG mode")
@ -154,14 +154,14 @@ class ArgStream(ChunkStream):
size = i32(s), i32(s[4:])
try:
mode, rawmode = _MODES[(ord(s[8]), ord(s[9]))]
mode, rawmode = _MODES[(i8(s[8]), i8(s[9]))]
except:
raise SyntaxError("unknown image mode")
if full:
if ord(s[12]):
if i8(s[12]):
pass # interlace not yet supported
if ord(s[11]):
if i8(s[11]):
raise SyntaxError("unknown filter category")
return size, mode, rawmode
@ -236,7 +236,7 @@ class ArgStream(ChunkStream):
self.im = Image.core.new(mode, size)
self.decoder = Image.core.zip_decoder(rawmode)
self.decoder.setimage(self.im, (0,0) + size)
self.data = ""
self.data = b""
return s
@ -252,7 +252,7 @@ class ArgStream(ChunkStream):
size, mode, rawmode = self.__getmodesize(s)
# delta header
diff = ord(s[13])
diff = i8(s[13])
offs = i32(s[14:18]), i32(s[18:22])
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.setimage(self.im, (0,0) + size)
self.data = ""
self.data = b""
return s
@ -289,7 +289,7 @@ class ArgStream(ChunkStream):
self.im = Image.core.new(mode, size)
self.decoder = Image.core.jpeg_decoder(rawmode)
self.decoder.setimage(self.im, (0,0) + size)
self.data = ""
self.data = b""
return s
@ -309,7 +309,7 @@ class ArgStream(ChunkStream):
self.im = Image.core.new(mode, size)
self.decoder = Image.core.raw_decoder(rawmode)
self.decoder.setimage(self.im, (0,0) + size)
self.data = ""
self.data = b""
return s

View File

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

View File

@ -27,20 +27,19 @@
__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
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 = {
# bits => mode, rawmode
1: ("P", "P;1"),
@ -52,7 +51,7 @@ BIT2MODE = {
}
def _accept(prefix):
return prefix[:2] == "BM"
return prefix[:2] == b"BM"
##
# Image plugin for the Windows BMP format.
@ -134,7 +133,7 @@ class BmpImageFile(ImageFile.ImageFile):
indices = list(range(colors))
for i in indices:
rgb = read(lutsize)[:3]
if rgb != chr(i)*3:
if rgb != o8(i)*3:
greyscale = 0
palette.append(rgb)
if greyscale:
@ -145,7 +144,7 @@ class BmpImageFile(ImageFile.ImageFile):
else:
self.mode = "P"
self.palette = ImagePalette.raw(
"BGR", "".join(palette)
"BGR", b"".join(palette)
)
if not offset:
@ -162,7 +161,7 @@ class BmpImageFile(ImageFile.ImageFile):
# HEAD
s = self.fp.read(14)
if s[:2] != "BM":
if s[:2] != b"BM":
raise SyntaxError("Not a BMP file")
offset = i32(s[10:])
@ -181,12 +180,6 @@ class DibImageFile(BmpImageFile):
# --------------------------------------------------------------------
# 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 = {
"1": ("1", 1, 2),
"L": ("L", 8, 256),
@ -204,13 +197,13 @@ def _save(im, fp, filename, check=0):
if 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
offset = 14 + header + colors * 4
image = stride * im.size[1]
# bitmap header
fp.write("BM" + # file type (magic)
fp.write(b"BM" + # file type (magic)
o32(offset+image) + # file size
o32(0) + # reserved
o32(offset)) # image data offset
@ -227,14 +220,14 @@ def _save(im, fp, filename, check=0):
o32(colors) + # colors used
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":
for i in (0, 255):
fp.write(chr(i) * 4)
fp.write(o8(i) * 4)
elif im.mode == "L":
for i in range(256):
fp.write(chr(i) * 4)
fp.write(o8(i) * 4)
elif im.mode == "P":
fp.write(im.im.getpalette("RGB", "BGRX"))

View File

@ -26,7 +26,7 @@ def register_handler(handler):
# Image adapter
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):

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -13,10 +13,9 @@
# See the README file for information on usage and redistribution.
#
from . import Image, ImageFile
from . import Image, ImageFile, _binary
def i32(c):
return ord(c[3]) + (ord(c[2])<<8) + (ord(c[1])<<16) + (ord(c[0])<<24)
i32 = _binary.i32be
def _accept(prefix):
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
self.im = Image.core.new(self.mode, self.size)
self.im.fromstring(self.data)
self.data = ""
self.im.frombytes(self.data)
self.data = b""
#
# registry

View File

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

View File

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

View File

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

View File

@ -15,6 +15,7 @@
#
import re
from ._binary import o8
##
# File handler for GIMP's palette format.
@ -25,9 +26,9 @@ class GimpPaletteFile:
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")
i = 0
@ -39,7 +40,7 @@ class GimpPaletteFile:
if not s:
break
# skip fields and comment lines
if re.match("\w+:|#", s):
if re.match(b"\w+:|#", s):
continue
if len(s) > 100:
raise SyntaxError("bad palette file")
@ -49,11 +50,11 @@ class GimpPaletteFile:
raise ValueError("bad palette entry")
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
self.palette = "".join(self.palette)
self.palette = b"".join(self.palette)
def getpalette(self):

View File

@ -26,7 +26,7 @@ def register_handler(handler):
# Image adapter
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):

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -91,14 +91,14 @@ class _Operand:
return _Operand(out)
# unary operators
if sys.version_info >= (3,0):
def __bool__(self):
# an image is "true" if it contains at least one non-zero pixel
return self.im.getbbox() is not None
else:
def __nonzero__(self):
# an image is "true" if it contains at least one non-zero pixel
return self.im.getbbox() is not None
def __bool__(self):
# an image is "true" if it contains at least one non-zero pixel
return self.im.getbbox() is not None
if bytes is str:
# Provide __nonzero__ for pre-Py3k
__nonzero__ = __bool__
del __bool__
def __abs__(self):
return self.apply("abs", self)
@ -120,9 +120,9 @@ class _Operand:
return self.apply("mul", self, other)
def __rmul__(self, other):
return self.apply("mul", other, self)
def __div__(self, other):
def __truediv__(self, other):
return self.apply("div", self, other)
def __rdiv__(self, other):
def __rtruediv__(self, other):
return self.apply("div", other, self)
def __mod__(self, other):
return self.apply("mod", self, other)
@ -133,6 +133,13 @@ class _Operand:
def __rpow__(self, other):
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
def __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):
n = n + h[ix]
# remove cutoff% pixels from the low end
cut = n * cutoff / 100
cut = n * cutoff // 100
for lo in range(256):
if cut > h[lo]:
cut = cut - h[lo]
@ -106,7 +106,7 @@ def autocontrast(image, cutoff=0, ignore=None):
if cut <= 0:
break
# remove cutoff% samples from the hi end
cut = n * cutoff / 100
cut = n * cutoff // 100
for hi in range(255, -1, -1):
if cut > h[hi]:
cut = cut - h[hi]
@ -125,7 +125,7 @@ def autocontrast(image, cutoff=0, ignore=None):
break
if hi <= lo:
# don't bother
lut.extend(range(256))
lut.extend(list(range(256)))
else:
scale = 255.0 / (hi - lo)
offset = -lo * scale
@ -156,9 +156,9 @@ def colorize(image, black, white):
white = _color(white, "RGB")
red = []; green = []; blue = []
for i in range(256):
red.append(black[0]+i*(white[0]-black[0])/255)
green.append(black[1]+i*(white[1]-black[1])/255)
blue.append(black[2]+i*(white[2]-black[2])/255)
red.append(black[0]+i*(white[0]-black[0])//255)
green.append(black[1]+i*(white[1]-black[1])//255)
blue.append(black[2]+i*(white[2]-black[2])//255)
image = image.convert("RGB")
return _lut(image, red + green + blue)
@ -212,15 +212,15 @@ def equalize(image, mask=None):
for b in range(0, len(h), 256):
histo = [_f for _f in h[b:b+256] if _f]
if len(histo) <= 1:
lut.extend(range(256))
lut.extend(list(range(256)))
else:
step = (reduce(operator.add, histo) - histo[-1]) / 255
step = (reduce(operator.add, histo) - histo[-1]) // 255
if not step:
lut.extend(range(256))
lut.extend(list(range(256)))
else:
n = step / 2
n = step // 2
for i in range(256):
lut.append(n / step)
lut.append(n // step)
n = n + h[i+b]
return _lut(image, lut)

View File

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

View File

@ -62,11 +62,11 @@ class ImageQt(QImage):
for i in range(0, len(palette), 3):
colortable.append(rgb(*palette[i:i+3]))
elif im.mode == "RGB":
data = im.tostring("raw", "BGRX")
data = im.tobytes("raw", "BGRX")
format = QImage.Format_RGB32
elif im.mode == "RGBA":
try:
data = im.tostring("raw", "BGRA")
data = im.tobytes("raw", "BGRA")
except SystemError:
# workaround for earlier versions
r, g, b, a = im.split()
@ -76,7 +76,7 @@ class ImageQt(QImage):
raise ValueError("unsupported image mode %r" % im.mode)
# 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)

View File

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

View File

@ -151,22 +151,25 @@ class Dib:
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
# data returned from <b>tostring</b>)
# @param buffer A buffer containing display data (usually
# data returned from <b>tobytes</b>)
def fromstring(self, buffer):
return self.image.fromstring(buffer)
def frombytes(self, 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):
return self.image.tostring()
def tobytes(self):
return self.image.tobytes()
if bytes is str:
tostring = tobytes
fromstring = frombytes
##
# 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.
@ -39,7 +39,7 @@ class ImtImageFile(ImageFile.ImageFile):
# Quick rejection: if there's not a LF among the first
# 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")
self.fp.seek(0)
@ -51,7 +51,7 @@ class ImtImageFile(ImageFile.ImageFile):
if not s:
break
if s == chr(12):
if s == b'\x0C':
# image data begins
self.tile = [("raw", (0,0)+self.size,
@ -67,7 +67,7 @@ class ImtImageFile(ImageFile.ImageFile):
s = s + self.fp.readline()
if len(s) == 1 or len(s) > 100:
break
if s[0] == "*":
if s[0] == b"*":
continue # comment
m = field.match(s)

View File

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

View File

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

View File

@ -22,7 +22,7 @@ import struct
from . import Image, ImageFile
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.

View File

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

View File

@ -19,17 +19,16 @@
__version__ = "0.1"
from . import Image, ImageFile
from . import Image, ImageFile, _binary
#
# read MSP files
def i16(c):
return ord(c[0]) + (ord(c[1])<<8)
i16 = _binary.i16le
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
@ -44,7 +43,7 @@ class MspImageFile(ImageFile.ImageFile):
# Header
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")
# Header checksum
@ -57,7 +56,7 @@ class MspImageFile(ImageFile.ImageFile):
self.mode = "1"
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))]
else:
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)
def o16(i):
return chr(i&255) + chr(i>>8&255)
o16 = _binary.o16le
def _save(im, fp, filename):
@ -76,7 +74,7 @@ def _save(im, fp, filename):
# create MSP header
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[4], header[5] = 1, 1
header[6], header[7] = 1, 1

View File

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

View File

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

View File

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

View File

@ -18,7 +18,9 @@
__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
@ -36,10 +38,10 @@ class PcdImageFile(ImageFile.ImageFile):
self.fp.seek(2048)
s = self.fp.read(2048)
if s[:4] != "PCD_":
if s[:4] != b"PCD_":
raise SyntaxError("not a PCD file")
orientation = ord(s[1538]) & 3
orientation = i8(s[1538]) & 3
if orientation == 1:
self.tile_post_rotate = 90 # hack
elif orientation == 3:

View File

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

View File

@ -27,13 +27,14 @@
__version__ = "0.6"
from . import Image, ImageFile, ImagePalette
from . import Image, ImageFile, ImagePalette, _binary
def i16(c,o):
return ord(c[o]) + (ord(c[o+1])<<8)
i8 = _binary.i8
i16 = _binary.i16le
o8 = _binary.o8
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.
@ -56,9 +57,9 @@ class PcxImageFile(ImageFile.ImageFile):
raise SyntaxError("bad PCX image size")
# format
version = ord(s[1])
bits = ord(s[3])
planes = ord(s[65])
version = i8(s[1])
bits = i8(s[3])
planes = i8(s[65])
stride = i16(s,66)
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 !!!
self.fp.seek(-769, 2)
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
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"
break
if mode == "P":
@ -111,8 +112,7 @@ SAVE = {
"RGB": (5, 8, 3, "RGB;L"),
}
def o16(i):
return chr(i&255) + chr(i>>8&255)
o16 = _binary.o16le
def _save(im, fp, filename, check=0):
@ -125,7 +125,7 @@ def _save(im, fp, filename, check=0):
return check
# 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
# "Image.core.display_mode()[1]", but I think that's overkill...
@ -136,11 +136,11 @@ def _save(im, fp, filename, check=0):
# PCX header
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(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]) +
chr(0)*54
b"\0"*54
)
assert fp.tell() == 128
@ -150,13 +150,13 @@ def _save(im, fp, filename, check=0):
if im.mode == "P":
# colour palette
fp.write(chr(12))
fp.write(o8(12))
fp.write(im.im.getpalette("RGB", "RGB")) # 768 bytes
elif im.mode == "L":
# greyscale palette
fp.write(chr(12))
fp.write(o8(12))
for i in range(256):
fp.write(chr(i)*3)
fp.write(o8(i)*3)
# --------------------------------------------------------------------
# registry

View File

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

View File

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

View File

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

View File

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

View File

@ -18,7 +18,7 @@
__version__ = "0.4"
from . import Image, ImageFile, ImagePalette
from . import Image, ImageFile, ImagePalette, _binary
MODES = {
# (photoshop mode, bits) -> (pil mode, required channels)
@ -36,17 +36,15 @@ MODES = {
#
# 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)
i8 = _binary.i8
i16 = _binary.i16be
i32 = _binary.i32be
# --------------------------------------------------------------------.
# read PSD images
def _accept(prefix):
return prefix[:4] == "8BPS"
return prefix[:4] == b"8BPS"
##
# Image plugin for Photoshop images.
@ -64,7 +62,7 @@ class PsdImageFile(ImageFile.ImageFile):
# header
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")
psd_bits = i16(s[22:])
@ -100,7 +98,7 @@ class PsdImageFile(ImageFile.ImageFile):
while self.fp.tell() < end:
signature = read(4)
id = i16(read(2))
name = read(ord(read(1)))
name = read(i8(read(1)))
if not (len(name) & 1):
read(1) # padding
data = read(i32(read(4)))
@ -219,9 +217,10 @@ def _layerinfo(file):
file.seek(length, 1)
combined += length + 4
length = ord(read(1))
length = i8(read(1))
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
file.seek(size - combined, 1)

View File

@ -21,14 +21,11 @@
__version__ = "0.2"
from . import Image, ImageFile
from . import Image, ImageFile, _binary
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)
i8 = _binary.i8
i16 = _binary.i16be
i32 = _binary.i32be
def _accept(prefix):
@ -50,10 +47,10 @@ class SgiImageFile(ImageFile.ImageFile):
raise SyntaxError("not an SGI image file")
# relevant header entries
compression = ord(s[2])
compression = i8(s[2])
# 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
if layout == (1, 2, 1) or layout == (1, 1, 1):

View File

@ -20,14 +20,10 @@
__version__ = "0.3"
from . import Image, ImageFile, ImagePalette
from . import Image, ImageFile, ImagePalette, _binary
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)
i16 = _binary.i16be
i32 = _binary.i32be
def _accept(prefix):
@ -71,7 +67,7 @@ class SunImageFile(ImageFile.ImageFile):
if self.mode == "L":
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:
self.tile = [("raw", (0,0)+self.size, offset, (rawmode, stride))]

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -19,14 +19,16 @@
__version__ = "0.1"
from . import Image, ImageFile, ImagePalette
from . import Image, ImageFile, ImagePalette, _binary
o8 = _binary.o8
# standard color palette for thumbnails (RGB332)
PALETTE = ""
PALETTE = b""
for r in range(8):
for g in range(8):
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.
@ -40,7 +42,7 @@ class XVThumbImageFile(ImageFile.ImageFile):
# check magic
s = self.fp.read(6)
if s != "P7 332":
if s != b"P7 332":
raise SyntaxError("not an XV thumbnail file")
# Skip to beginning of next line
@ -51,14 +53,14 @@ class XVThumbImageFile(ImageFile.ImageFile):
s = self.fp.readline()
if not s:
raise SyntaxError("Unexpected EOF reading XV thumbnail file")
if s[0] != '#':
if s[0] != b'#':
break
# parse header line (already read)
s = s.strip().split()
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)

View File

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

View File

@ -20,13 +20,14 @@ __version__ = "0.2"
import re
from . import Image, ImageFile, ImagePalette
from ._binary import i8, o8
# 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):
return prefix[:9] == "/* XPM */"
return prefix[:9] == b"/* XPM */"
##
# Image plugin for X11 pixel maps.
@ -61,17 +62,17 @@ class XpmImageFile(ImageFile.ImageFile):
#
# load palette description
palette = ["\0\0\0"] * 256
palette = [b"\0\0\0"] * 256
for i in range(pal):
s = self.fp.readline()
if s[-2:] == '\r\n':
if s[-2:] == b'\r\n':
s = s[:-2]
elif s[-1:] in '\r\n':
elif s[-1:] in b'\r\n':
s = s[:-1]
c = ord(s[1])
c = i8(s[1])
s = s[2:-2].split()
for i in range(0, len(s), 2):
@ -80,14 +81,14 @@ class XpmImageFile(ImageFile.ImageFile):
# process colour key
rgb = s[i+1]
if rgb == "None":
if rgb == b"None":
self.info["transparency"] = c
elif rgb[0] == "#":
elif rgb[0] == b"#":
# FIXME: handle colour names (see ImagePalette.py)
rgb = int(rgb[1:], 16)
palette[c] = chr((rgb >> 16) & 255) +\
chr((rgb >> 8) & 255) +\
chr(rgb & 255)
palette[c] = o8((rgb >> 16) & 255) +\
o8((rgb >> 8) & 255) +\
o8(rgb & 255)
else:
# unknown colour
raise ValueError("cannot read this XPM file")
@ -99,7 +100,7 @@ class XpmImageFile(ImageFile.ImageFile):
raise ValueError("cannot read this XPM file")
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))]
@ -117,7 +118,7 @@ class XpmImageFile(ImageFile.ImageFile):
self.fp = None
return "".join(s)
return b"".join(s)
#
# 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):
if arr.type().bytes == 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:
arr_c = arr - arr.min()
arr_c *= (255./arr_c.max())
arr = arr_c.astype(UInt8)
# 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
print('SANE version:', sane.init())

View File

@ -88,16 +88,16 @@ def test_bad_text():
assert_equal(im.info, {})
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)
assert_equal(im.info, {b'spam': b''})
assert_equal(im.info, {'spam': ''})
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)
assert_equal(im.info, {b'spam': b'egg\x00'})
assert_equal(im.info, {'spam': 'egg\x00'})
def test_interlace():
@ -141,12 +141,12 @@ def test_roundtrip_text():
im = Image.open(file)
info = PngImagePlugin.PngInfo()
info.add_text(b"TXT", b"VALUE")
info.add_text(b"ZIP", b"VALUE", 1)
info.add_text("TXT", "VALUE")
info.add_text("ZIP", "VALUE", 1)
im = roundtrip(im, pnginfo=info)
assert_equal(im.info, {b'TXT': b'VALUE', b'ZIP': b'VALUE'})
assert_equal(im.text, {b'TXT': b'VALUE', b'ZIP': b'VALUE'})
assert_equal(im.info, {'TXT': 'VALUE', 'ZIP': 'VALUE'})
assert_equal(im.text, {'TXT': 'VALUE', 'ZIP': 'VALUE'})
def test_scary():
# 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)**
[`# <#PIL.Image.frombuffer-function>`_]
(New in 1.1.4) Creates an image memory from pixel data in a string
or byte buffer.
(New in 1.1.4) Creates an image memory referencing pixel data in a
byte buffer.
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
original buffer object are reflected in this image). Not all modes
can share memory; support modes include "L", "RGBX", "RGBA", and
@ -56,9 +56,9 @@ The PIL.Image Module
*\*args*
Returns:
**fromstring(mode, size, data, decoder\_name="raw", \*args)**
[`# <#PIL.Image.fromstring-function>`_]
Creates an image memory from pixel data in a string.
**frombytes(mode, size, data, decoder\_name="raw", \*args)**
[`# <#PIL.Image.frombytes-function>`_]
Creates a copy of an image memory from pixel data in a buffer.
In its simplest form, this function takes three arguments (mode,
size, and unpacked pixel data).
@ -233,14 +233,16 @@ The Image Class
*filter*
Returns:
**fromstring(data, decoder\_name="raw", \*args)**
[`# <#PIL.Image.Image.fromstring-method>`_]
Loads this image with pixel data from a string.
**frombytes(data, decoder\_name="raw", \*args)**
[`# <#PIL.Image.Image.frombytes-method>`_]
Loads this image with pixel data from a byte uffer.
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.
(In Python 2.6 and 2.7, this is also available as fromstring().)
**getbands()** [`# <#PIL.Image.Image.getbands-method>`_]
Returns a tuple containing the name of each band in this image. For
example, **getbands** on an RGB image returns ("R", "G", "B").
@ -516,8 +518,9 @@ The Image Class
Returns:
Raises **ValueError**:
**tostring(encoder\_name="raw", \*args)**
[`# <#PIL.Image.Image.tostring-method>`_]
**tobytes(encoder\_name="raw", \*args)**
[`# <#PIL.Image.Image.tobytes-method>`_]
(In Python 2.6 and 2.7, this is also available as tostring().)
*encoder\_name*
*\*args*

View File

@ -58,11 +58,12 @@ The Dib Class
instance. In PythonWin, you can use the **GetHandleAttrib**
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*
A string buffer containing display data (usually data returned
from **tostring**)
A byte buffer containing display data (usually data returned
from **tobytes**)
**paste(im, box=None)** [`# <#PIL.ImageWin.Dib.paste-method>`_]
@ -82,7 +83,7 @@ The Dib Class
*handle*
Returns:
**tostring()** [`# <#PIL.ImageWin.Dib.tostring-method>`_]
**tobytes()** [`# <#PIL.ImageWin.Dib.tobytes-method>`_]
Returns: