| # | 
| # The Python Imaging Library. | 
| # $Id$ | 
| # | 
| # TGA file handling | 
| # | 
| # History: | 
| # 95-09-01 fl   created (reads 24-bit files only) | 
| # 97-01-04 fl   support more TGA versions, including compressed images | 
| # 98-07-04 fl   fixed orientation and alpha layer bugs | 
| # 98-09-11 fl   fixed orientation for runlength decoder | 
| # | 
| # Copyright (c) Secret Labs AB 1997-98. | 
| # Copyright (c) Fredrik Lundh 1995-97. | 
| # | 
| # See the README file for information on usage and redistribution. | 
| # | 
|   | 
|   | 
| __version__ = "0.3" | 
|   | 
| import Image, ImageFile, ImagePalette | 
|   | 
|   | 
| # | 
| # -------------------------------------------------------------------- | 
| # 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) | 
|   | 
|   | 
| MODES = { | 
|     # map imagetype/depth to rawmode | 
|     (1, 8):  "P", | 
|     (3, 1):  "1", | 
|     (3, 8):  "L", | 
|     (2, 16): "BGR;5", | 
|     (2, 24): "BGR", | 
|     (2, 32): "BGRA", | 
| } | 
|   | 
|   | 
| def _accept(prefix): | 
|     return prefix[0] == "\0" | 
|   | 
| ## | 
| # Image plugin for Targa files. | 
|   | 
| class TgaImageFile(ImageFile.ImageFile): | 
|   | 
|     format = "TGA" | 
|     format_description = "Targa" | 
|   | 
|     def _open(self): | 
|   | 
|         # process header | 
|         s = self.fp.read(18) | 
|   | 
|         id = ord(s[0]) | 
|   | 
|         colormaptype = ord(s[1]) | 
|         imagetype = ord(s[2]) | 
|   | 
|         depth = ord(s[16]) | 
|   | 
|         flags = ord(s[17]) | 
|   | 
|         self.size = i16(s[12:]), i16(s[14:]) | 
|   | 
|         # validate header fields | 
|         if id != 0 or colormaptype not in (0, 1) or\ | 
|            self.size[0] <= 0 or self.size[1] <= 0 or\ | 
|            depth not in (1, 8, 16, 24, 32): | 
|             raise SyntaxError, "not a TGA file" | 
|   | 
|         # image mode | 
|         if imagetype in (3, 11): | 
|             self.mode = "L" | 
|             if depth == 1: | 
|                 self.mode = "1" # ??? | 
|         elif imagetype in (1, 9): | 
|             self.mode = "P" | 
|         elif imagetype in (2, 10): | 
|             self.mode = "RGB" | 
|             if depth == 32: | 
|                 self.mode = "RGBA" | 
|         else: | 
|             raise SyntaxError, "unknown TGA mode" | 
|   | 
|         # orientation | 
|         orientation = flags & 0x30 | 
|         if orientation == 0x20: | 
|             orientation = 1 | 
|         elif not orientation: | 
|             orientation = -1 | 
|         else: | 
|             raise SyntaxError, "unknown TGA orientation" | 
|   | 
|         self.info["orientation"] = orientation | 
|   | 
|         if imagetype & 8: | 
|             self.info["compression"] = "tga_rle" | 
|   | 
|         if colormaptype: | 
|             # read palette | 
|             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)) | 
|             elif mapdepth == 24: | 
|                 self.palette = ImagePalette.raw("BGR", | 
|                     "\0"*3*start + self.fp.read(3*size)) | 
|             elif mapdepth == 32: | 
|                 self.palette = ImagePalette.raw("BGRA", | 
|                     "\0"*4*start + self.fp.read(4*size)) | 
|   | 
|         # setup tile descriptor | 
|         try: | 
|             rawmode = MODES[(imagetype&7, depth)] | 
|             if imagetype & 8: | 
|                 # compressed | 
|                 self.tile = [("tga_rle", (0, 0)+self.size, | 
|                               self.fp.tell(), (rawmode, orientation, depth))] | 
|             else: | 
|                 self.tile = [("raw", (0, 0)+self.size, | 
|                               self.fp.tell(), (rawmode, 0, orientation))] | 
|         except KeyError: | 
|             pass # cannot decode | 
|   | 
| # | 
| # -------------------------------------------------------------------- | 
| # 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) | 
|   | 
| SAVE = { | 
|     "1": ("1", 1, 0, 3), | 
|     "L": ("L", 8, 0, 3), | 
|     "P": ("P", 8, 1, 1), | 
|     "RGB": ("BGR", 24, 0, 2), | 
|     "RGBA": ("BGRA", 32, 0, 2), | 
| } | 
|   | 
| def _save(im, fp, filename, check=0): | 
|   | 
|     try: | 
|         rawmode, bits, colormaptype, imagetype = SAVE[im.mode] | 
|     except KeyError: | 
|         raise IOError("cannot write mode %s as TGA" % im.mode) | 
|   | 
|     if check: | 
|         return check | 
|   | 
|     if colormaptype: | 
|         colormapfirst, colormaplength, colormapentry = 0, 256, 24 | 
|     else: | 
|         colormapfirst, colormaplength, colormapentry = 0, 0, 0 | 
|   | 
|     if im.mode == "RGBA": | 
|         flags = 8 | 
|     else: | 
|         flags = 0 | 
|   | 
|     orientation = im.info.get("orientation", -1) | 
|     if orientation > 0: | 
|         flags = flags | 0x20 | 
|   | 
|     fp.write("\000" + | 
|              chr(colormaptype) + | 
|              chr(imagetype) + | 
|              o16(colormapfirst) + | 
|              o16(colormaplength) + | 
|              chr(colormapentry) + | 
|              o16(0) + | 
|              o16(0) + | 
|              o16(im.size[0]) + | 
|              o16(im.size[1]) + | 
|              chr(bits) + | 
|              chr(flags)) | 
|   | 
|     if colormaptype: | 
|         fp.write(im.im.getpalette("RGB", "BGR")) | 
|   | 
|     ImageFile._save(im, fp, [("raw", (0,0)+im.size, 0, (rawmode, 0, orientation))]) | 
|   | 
| # | 
| # -------------------------------------------------------------------- | 
| # Registry | 
|   | 
| Image.register_open("TGA", TgaImageFile, _accept) | 
| Image.register_save("TGA", _save) | 
|   | 
| Image.register_extension("TGA", ".tga") |