[Image-SIG] BMP color palette bug fix

Su, Yuan-Liang zsu@iii.org.tw
Thu, 4 Jun 1998 09:30:19 +0800


This is a multi-part message in MIME format.

------=_NextPart_000_0027_01BD8F9B.63CC05E0
Content-Type: multipart/alternative;
	boundary="----=_NextPart_001_0028_01BD8F9B.63CC05E0"


------=_NextPart_001_0028_01BD8F9B.63CC05E0
Content-Type: text/plain;
	charset="big5"
Content-Transfer-Encoding: quoted-printable

There is a bug in BmpImagePlugin.py module which is caused
by ignoring the palette size field in BMP header.

I mark the changed parts with #!+ for addition and #!* for
modification.

Su, Yuan-Liang
Institute for Infomation Industry

------=_NextPart_001_0028_01BD8F9B.63CC05E0
Content-Type: text/html;
	charset="big5"
Content-Transfer-Encoding: quoted-printable

<!DOCTYPE HTML PUBLIC "-//W3C//DTD W3 HTML//EN">
<HTML>
<HEAD>

<META content=3Dtext/html;charset=3Dbig5 http-equiv=3DContent-Type>
<META content=3D'"MSHTML 4.72.2106.11"' name=3DGENERATOR>
</HEAD>
<BODY bgColor=3D#ffffff>
<DIV><FONT face=3D=B7s=B2=D3=A9=FA=C5=E9 size=3D2>There is a bug in =
BmpImagePlugin.py module which is=20
caused</FONT></DIV>
<DIV><FONT face=3D=B7s=B2=D3=A9=FA=C5=E9 size=3D2>by ignoring the =
palette size field in BMP=20
header.</FONT></DIV>
<DIV><FONT face=3D=B7s=B2=D3=A9=FA=C5=E9 size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3D=B7s=B2=D3=A9=FA=C5=E9 size=3D2>I mark the changed =
parts with #!+ for addition and=20
#!* for</FONT></DIV>
<DIV><FONT face=3D=B7s=B2=D3=A9=FA=C5=E9 =
size=3D2>modification.</FONT></DIV>
<DIV><FONT face=3D=B7s=B2=D3=A9=FA=C5=E9 size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3D=B7s=B2=D3=A9=FA=C5=E9 size=3D2>Su, =
Yuan-Liang</FONT></DIV>
<DIV><FONT face=3D=B7s=B2=D3=A9=FA=C5=E9 size=3D2>Institute for =
Infomation=20
Industry</FONT></DIV></BODY></HTML>

------=_NextPart_001_0028_01BD8F9B.63CC05E0--

------=_NextPart_000_0027_01BD8F9B.63CC05E0
Content-Type: application/octet-stream;
	name="BmpImagePlugin.py"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="BmpImagePlugin.py"

#
# The Python Imaging Library.
# $Id: BmpImagePlugin.py,v 1.5 1996/11/10 17:52:14 fredrik Exp $
#
# BMP file handler
#
# Windows (and OS/2) native bitmap storage format.
#
# History:
#	95-09-01 fl	Created
#	96-04-30 fl	Added save
#
# Copyright (c) Fredrik Lundh 1995-96.  All rights reserved.
#
# See the README file for information on usage and redistribution.
#


__version__ =3D "0.1"


import array
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 =3D {
    1: ("1", "1"),
    4: ("P", "P;4"),
    8: ("P", "P"),
    24: ("RGB", "BGR")
}

def _accept(prefix):
    return prefix[:2] =3D=3D "BM"

class BmpImageFile(ImageFile.ImageFile):

    format =3D "BMP"
    format_description =3D "Windows Bitmap"

    def _bitmap(self, header =3D 0, offset =3D 0):

	if header:
	    self.fp.seek(header)

	# CORE/INFO
	s =3D self.fp.read(4)
	s =3D s + self.fp.read(i32(s)-4)

	colors =3D 0

	if len(s) =3D=3D 12:

	    # OS/2 1.0 CORE
	    bits =3D i16(s[10:])
	    self.size =3D i16(s[4:]), i16(s[6:])
	    lutsize =3D 3

	elif len(s) in [40, 64]:

	    # WIN 3.1 or OS/2 2.0 INFO
	    bits =3D i16(s[14:])
	    self.size =3D i32(s[4:]), i32(s[8:])
	    self.info["compression"] =3D i32(s[16:])
	    #!+ Su, Yuan-Liang
	    colors =3D i32(s[32:])
	    #!!
	    lutsize =3D 4

	else:
	    raise IOError, "Unknown BMP header type"

	# MODE
	try:
	    self.mode, rawmode =3D BIT2MODE[bits]
	except KeyError:
	    raise IOError, "Unsupported BMP pixel depth"

	# LUT
	if self.mode !=3D "RGB":
	    #!* Su, Yuan-Liang
	    if colors =3D=3D 0:
	    	colors =3D 1<<bits
	    #!!
	    if lutsize =3D=3D 3:
		self.palette =3D ImagePalette.raw("BGR", self.fp.read(colors*3))
	    else:
		self.palette =3D ImagePalette.raw("BGRX", self.fp.read(colors*4))
	    if self.mode =3D=3D "L":
		self.mode =3D "P"

	if offset =3D=3D 0:
	    offset =3D self.fp.tell()
	=09
	self.tile =3D [("raw",
		     (0, 0) + self.size,
		     offset,
		     (rawmode, ((self.size[0]*bits+31)>>3)&(-4), -1))]

    def _open(self):

	# HEAD
	s =3D self.fp.read(14)
	if s[:2] !=3D "BM":
	    raise SyntaxError, "Not a BMP file"
	offset =3D i32(s[10:])

	#!* Su, Yuan-Liang
	self._bitmap(0, offset)
	#!!


#
# --------------------------------------------------------------------
# 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)

def _save(im, fp, filename):

    if im.mode =3D=3D "1":
	rawmode, bits, colors =3D "1I", 1, 2
    elif im.mode in ["L", "P"]:
	rawmode, bits, colors =3D "L", 8, 256
    elif im.mode =3D=3D "RGB":
	rawmode, bits, colors =3D "BGR", 24, 0
    else:
	raise IOError, "cannot write mode %s as BMP" % im.mode

    stride =3D ((im.size[0]*bits+7)/8+3)&-4
    header =3D 40 # or 64 for OS/2 version 2
    offset =3D 14 + header + colors * 4
    image  =3D 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=3Duncompressed)
	     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 =3D=3D "1":
	for i in (0, 255):
	    fp.write(chr(i) * 4)
    elif im.mode =3D=3D "L":
	for i in range(256):
	    fp.write(chr(i) * 4)
    elif im.mode =3D=3D "P":
	fp.write(im.im.getpalette("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")

------=_NextPart_000_0027_01BD8F9B.63CC05E0--