Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/PIL/BmpImagePlugin.py
diff options
context:
space:
mode:
Diffstat (limited to 'PIL/BmpImagePlugin.py')
-rw-r--r--PIL/BmpImagePlugin.py245
1 files changed, 245 insertions, 0 deletions
diff --git a/PIL/BmpImagePlugin.py b/PIL/BmpImagePlugin.py
new file mode 100644
index 0000000..a939d9b
--- /dev/null
+++ b/PIL/BmpImagePlugin.py
@@ -0,0 +1,245 @@
+#
+# The Python Imaging Library.
+# $Id: BmpImagePlugin.py 2134 2004-10-06 08:55:20Z fredrik $
+#
+# BMP file handler
+#
+# Windows (and OS/2) native bitmap storage format.
+#
+# history:
+# 1995-09-01 fl Created
+# 1996-04-30 fl Added save
+# 1997-08-27 fl Fixed save of 1-bit images
+# 1998-03-06 fl Load P images as L where possible
+# 1998-07-03 fl Load P images as 1 where possible
+# 1998-12-29 fl Handle small palettes
+# 2002-12-30 fl Fixed load of 1-bit palette images
+# 2003-04-21 fl Fixed load of 1-bit monochrome images
+# 2003-04-23 fl Added limited support for BI_BITFIELDS compression
+#
+# Copyright (c) 1997-2003 by Secret Labs AB
+# Copyright (c) 1995-2003 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+
+__version__ = "0.7"
+
+
+import string
+import Image, ImageFile, ImagePalette
+
+
+#
+# --------------------------------------------------------------------
+# 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"),
+ 4: ("P", "P;4"),
+ 8: ("P", "P"),
+ 16: ("RGB", "BGR;16"),
+ 24: ("RGB", "BGR"),
+ 32: ("RGB", "BGRX")
+}
+
+def _accept(prefix):
+ return prefix[:2] == "BM"
+
+##
+# Image plugin for the Windows BMP format.
+
+class BmpImageFile(ImageFile.ImageFile):
+
+ format = "BMP"
+ format_description = "Windows Bitmap"
+
+ def _bitmap(self, header = 0, offset = 0):
+
+ if header:
+ self.fp.seek(header)
+
+ read = self.fp.read
+
+ # CORE/INFO
+ s = read(4)
+ s = s + ImageFile._safe_read(self.fp, i32(s)-4)
+
+ if len(s) == 12:
+
+ # OS/2 1.0 CORE
+ bits = i16(s[10:])
+ self.size = i16(s[4:]), i16(s[6:])
+ compression = 0
+ lutsize = 3
+ colors = 0
+
+ elif len(s) in [40, 64]:
+
+ # WIN 3.1 or OS/2 2.0 INFO
+ bits = i16(s[14:])
+ self.size = i32(s[4:]), i32(s[8:])
+ compression = i32(s[16:])
+ lutsize = 4
+ colors = i32(s[32:])
+
+ else:
+ raise IOError("Unsupported BMP header type (%d)" % len(s))
+
+ if not colors:
+ colors = 1 << bits
+
+ # MODE
+ try:
+ self.mode, rawmode = BIT2MODE[bits]
+ except KeyError:
+ raise IOError("Unsupported BMP pixel depth (%d)" % bits)
+
+ if compression == 3:
+ # BI_BITFIELDS compression
+ mask = i32(read(4)), i32(read(4)), i32(read(4))
+ if bits == 32 and mask == (0xff0000, 0x00ff00, 0x0000ff):
+ rawmode = "BGRX"
+ elif bits == 16 and mask == (0x00f800, 0x0007e0, 0x00001f):
+ rawmode = "BGR;16"
+ elif bits == 16 and mask == (0x007c00, 0x0003e0, 0x00001f):
+ rawmode = "BGR;15"
+ else:
+ # print bits, map(hex, mask)
+ raise IOError("Unsupported BMP bitfields layout")
+ elif compression != 0:
+ raise IOError("Unsupported BMP compression (%d)" % compression)
+
+ # LUT
+ if self.mode == "P":
+ palette = []
+ greyscale = 1
+ if colors == 2:
+ indices = (0, 255)
+ else:
+ indices = range(colors)
+ for i in indices:
+ rgb = read(lutsize)[:3]
+ if rgb != chr(i)*3:
+ greyscale = 0
+ palette.append(rgb)
+ if greyscale:
+ if colors == 2:
+ self.mode = rawmode = "1"
+ else:
+ self.mode = rawmode = "L"
+ else:
+ self.mode = "P"
+ self.palette = ImagePalette.raw(
+ "BGR", string.join(palette, "")
+ )
+
+ if not offset:
+ offset = self.fp.tell()
+
+ self.tile = [("raw",
+ (0, 0) + self.size,
+ offset,
+ (rawmode, ((self.size[0]*bits+31)>>3)&(~3), -1))]
+
+ self.info["compression"] = compression
+
+ def _open(self):
+
+ # HEAD
+ s = self.fp.read(14)
+ if s[:2] != "BM":
+ raise SyntaxError("Not a BMP file")
+ offset = i32(s[10:])
+
+ self._bitmap(offset=offset)
+
+
+class DibImageFile(BmpImageFile):
+
+ format = "DIB"
+ format_description = "Windows Bitmap"
+
+ def _open(self):
+ self._bitmap()
+
+#
+# --------------------------------------------------------------------
+# 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),
+ "P": ("P", 8, 256),
+ "RGB": ("BGR", 24, 0),
+}
+
+def _save(im, fp, filename, check=0):
+
+ try:
+ rawmode, bits, colors = SAVE[im.mode]
+ except KeyError:
+ raise IOError("cannot write mode %s as BMP" % im.mode)
+
+ if check:
+ return check
+
+ 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)
+ o32(offset+image) + # file size
+ o32(0) + # reserved
+ o32(offset)) # image data offset
+
+ # bitmap info header
+ fp.write(o32(header) + # info header size
+ o32(im.size[0]) + # width
+ o32(im.size[1]) + # height
+ o16(1) + # planes
+ o16(bits) + # depth
+ o32(0) + # compression (0=uncompressed)
+ o32(image) + # size of bitmap
+ o32(1) + o32(1) + # resolution
+ o32(colors) + # colors used
+ o32(colors)) # colors important
+
+ fp.write("\000" * (header - 40)) # padding (for OS/2 format)
+
+ if im.mode == "1":
+ for i in (0, 255):
+ fp.write(chr(i) * 4)
+ elif im.mode == "L":
+ for i in range(256):
+ fp.write(chr(i) * 4)
+ elif im.mode == "P":
+ fp.write(im.im.getpalette("RGB", "BGRX"))
+
+ ImageFile._save(im, fp, [("raw", (0,0)+im.size, 0, (rawmode, stride, -1))])
+
+#
+# --------------------------------------------------------------------
+# Registry
+
+Image.register_open(BmpImageFile.format, BmpImageFile, _accept)
+Image.register_save(BmpImageFile.format, _save)
+
+Image.register_extension(BmpImageFile.format, ".bmp")