home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 April / enter-2004-04.iso / files / EVE_1424_100181.exe / BmpImagePlugin.py < prev    next >
Encoding:
Text File  |  2004-04-20  |  5.5 KB  |  209 lines

  1. #
  2. # The Python Imaging Library.
  3. # $Id: //modules/pil/PIL/BmpImagePlugin.py#3 $
  4. #
  5. # BMP file handler
  6. #
  7. # Windows (and OS/2) native bitmap storage format.
  8. #
  9. # History:
  10. # 95-09-01 fl   Created
  11. # 96-04-30 fl   Added save
  12. # 97-08-27 fl   Fixed save of 1-bit images
  13. # 98-03-06 fl   Load P images as L where possible
  14. # 98-07-03 fl   Load P images as 1 where possible
  15. # 98-12-29 fl   Handle small palettes
  16. #
  17. # Copyright (c) Secret Labs AB 1997-98.
  18. # Copyright (c) Fredrik Lundh 1995-97.
  19. #
  20. # See the README file for information on usage and redistribution.
  21. #
  22.  
  23.  
  24. __version__ = "0.5"
  25.  
  26.  
  27. import string
  28. import Image, ImageFile, ImagePalette
  29.  
  30.  
  31. #
  32. # --------------------------------------------------------------------
  33. # Read BMP file
  34.  
  35. def i16(c):
  36.     return ord(c[0]) + (ord(c[1])<<8)
  37.  
  38. def i32(c):
  39.     return ord(c[0]) + (ord(c[1])<<8) + (ord(c[2])<<16) + (ord(c[3])<<24)
  40.  
  41.  
  42. BIT2MODE = {
  43.     # mode, rawmode
  44.     1: ("P", "1"),
  45.     4: ("P", "P;4"),
  46.     8: ("P", "P"),
  47.     24: ("RGB", "BGR")
  48. }
  49.  
  50. def _accept(prefix):
  51.     return prefix[:2] == "BM"
  52.  
  53. class BmpImageFile(ImageFile.ImageFile):
  54.  
  55.     format = "BMP"
  56.     format_description = "Windows Bitmap"
  57.  
  58.     def _bitmap(self, header = 0, offset = 0):
  59.  
  60.         if header:
  61.             self.fp.seek(header)
  62.  
  63.         # CORE/INFO
  64.         s = self.fp.read(4)
  65.         s = s + self.fp.read(i32(s)-4)
  66.  
  67.         if len(s) == 12:
  68.  
  69.             # OS/2 1.0 CORE
  70.             bits = i16(s[10:])
  71.             self.size = i16(s[4:]), i16(s[6:])
  72.             lutsize = 3
  73.             colors = 0
  74.  
  75.         elif len(s) in [40, 64]:
  76.  
  77.             # WIN 3.1 or OS/2 2.0 INFO
  78.             bits = i16(s[14:])
  79.             self.size = i32(s[4:]), i32(s[8:])
  80.             self.info["compression"] = i32(s[16:])
  81.             lutsize = 4
  82.             colors = i32(s[32:])
  83.  
  84.         else:
  85.             raise IOError, "Unknown BMP header type"
  86.  
  87.         if not colors:
  88.             colors = 1 << bits
  89.  
  90.         # MODE
  91.         try:
  92.             self.mode, rawmode = BIT2MODE[bits]
  93.         except KeyError:
  94.             raise IOError, "Unsupported BMP pixel depth"
  95.  
  96.         # LUT
  97.         if self.mode == "P":
  98.             palette = []
  99.             greyscale = 1
  100.             if colors == 2:
  101.                 indices = (0, 255)
  102.             else:
  103.                 indices = range(colors)
  104.             for i in indices:
  105.                 rgb = self.fp.read(lutsize)[:3]
  106.                 if rgb != chr(i)*3:
  107.                     greyscale = 0
  108.                 palette.append(rgb)
  109.             if greyscale:
  110.                 if colors == 2:
  111.                     self.mode = "1"
  112.                 else:
  113.                     self.mode = rawmode = "L"
  114.             else:
  115.                 self.mode = "P"
  116.                 self.palette = ImagePalette.raw(
  117.                     "BGR", string.join(palette, "")
  118.                     )
  119.  
  120.         if not offset:
  121.             offset = self.fp.tell()
  122.  
  123.         self.tile = [("raw",
  124.                      (0, 0) + self.size,
  125.                      offset,
  126.                      (rawmode, ((self.size[0]*bits+31)>>3)&(~3), -1))]
  127.  
  128.     def _open(self):
  129.  
  130.         # HEAD
  131.         s = self.fp.read(14)
  132.         if s[:2] != "BM":
  133.             raise SyntaxError, "Not a BMP file"
  134.         offset = i32(s[10:])
  135.  
  136.         self._bitmap()
  137.  
  138. #
  139. # --------------------------------------------------------------------
  140. # Write BMP file
  141.  
  142. def o16(i):
  143.     return chr(i&255) + chr(i>>8&255)
  144.  
  145. def o32(i):
  146.     return chr(i&255) + chr(i>>8&255) + chr(i>>16&255) + chr(i>>24&255)
  147.  
  148. SAVE = {
  149.     "1": ("1", 1, 2),
  150.     "L": ("L", 8, 256),
  151.     "P": ("P", 8, 256),
  152.     "RGB": ("BGR", 24, 0),
  153. }
  154.  
  155. def _save(im, fp, filename, check=0):
  156.  
  157.     try:
  158.         rawmode, bits, colors = SAVE[im.mode]
  159.     except KeyError:
  160.         raise IOError, "cannot write mode %s as BMP" % im.mode
  161.  
  162.     if check:
  163.         return check
  164.  
  165.     stride = ((im.size[0]*bits+7)/8+3)&(~3)
  166.     header = 40 # or 64 for OS/2 version 2
  167.     offset = 14 + header + colors * 4
  168.     image  = stride * im.size[1]
  169.  
  170.     # bitmap header
  171.     fp.write("BM" +                     # file type (magic)
  172.              o32(offset+image) +        # file size
  173.              o32(0) +                   # reserved
  174.              o32(offset))               # image data offset
  175.  
  176.     # bitmap info header
  177.     fp.write(o32(header) +              # info header size
  178.              o32(im.size[0]) +          # width
  179.              o32(im.size[1]) +          # height
  180.              o16(1) +                   # planes
  181.              o16(bits) +                # depth
  182.              o32(0) +                   # compression (0=uncompressed)
  183.              o32(image) +               # size of bitmap
  184.              o32(1) + o32(1) +          # resolution
  185.              o32(colors) +              # colors used
  186.              o32(colors))               # colors important
  187.  
  188.     fp.write("\000" * (header - 40))    # padding (for OS/2 format)
  189.  
  190.     if im.mode == "1":
  191.         for i in (0, 255):
  192.             fp.write(chr(i) * 4)
  193.     elif im.mode == "L":
  194.         for i in range(256):
  195.             fp.write(chr(i) * 4)
  196.     elif im.mode == "P":
  197.         fp.write(im.im.getpalette("RGB", "BGRX"))
  198.  
  199.     ImageFile._save(im, fp, [("raw", (0,0)+im.size, 0, (rawmode, stride, -1))])
  200.  
  201. #
  202. # --------------------------------------------------------------------
  203. # Registry
  204.  
  205. Image.register_open(BmpImageFile.format, BmpImageFile, _accept)
  206. Image.register_save(BmpImageFile.format, _save)
  207.  
  208. Image.register_extension(BmpImageFile.format, ".bmp")
  209.