You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

227 lines
5.9 KiB

4 years ago
  1. #
  2. # The Python Imaging Library.
  3. # $Id$
  4. #
  5. # TGA file handling
  6. #
  7. # History:
  8. # 95-09-01 fl created (reads 24-bit files only)
  9. # 97-01-04 fl support more TGA versions, including compressed images
  10. # 98-07-04 fl fixed orientation and alpha layer bugs
  11. # 98-09-11 fl fixed orientation for runlength decoder
  12. #
  13. # Copyright (c) Secret Labs AB 1997-98.
  14. # Copyright (c) Fredrik Lundh 1995-97.
  15. #
  16. # See the README file for information on usage and redistribution.
  17. #
  18. from . import Image, ImageFile, ImagePalette
  19. from ._binary import i8, i16le as i16, o8, o16le as o16
  20. import warnings
  21. __version__ = "0.3"
  22. #
  23. # --------------------------------------------------------------------
  24. # Read RGA file
  25. MODES = {
  26. # map imagetype/depth to rawmode
  27. (1, 8): "P",
  28. (3, 1): "1",
  29. (3, 8): "L",
  30. (3, 16): "LA",
  31. (2, 16): "BGR;5",
  32. (2, 24): "BGR",
  33. (2, 32): "BGRA",
  34. }
  35. ##
  36. # Image plugin for Targa files.
  37. class TgaImageFile(ImageFile.ImageFile):
  38. format = "TGA"
  39. format_description = "Targa"
  40. def _open(self):
  41. # process header
  42. s = self.fp.read(18)
  43. id_len = i8(s[0])
  44. colormaptype = i8(s[1])
  45. imagetype = i8(s[2])
  46. depth = i8(s[16])
  47. flags = i8(s[17])
  48. self._size = i16(s[12:]), i16(s[14:])
  49. # validate header fields
  50. if colormaptype not in (0, 1) or\
  51. self.size[0] <= 0 or self.size[1] <= 0 or\
  52. depth not in (1, 8, 16, 24, 32):
  53. raise SyntaxError("not a TGA file")
  54. # image mode
  55. if imagetype in (3, 11):
  56. self.mode = "L"
  57. if depth == 1:
  58. self.mode = "1" # ???
  59. elif depth == 16:
  60. self.mode = "LA"
  61. elif imagetype in (1, 9):
  62. self.mode = "P"
  63. elif imagetype in (2, 10):
  64. self.mode = "RGB"
  65. if depth == 32:
  66. self.mode = "RGBA"
  67. else:
  68. raise SyntaxError("unknown TGA mode")
  69. # orientation
  70. orientation = flags & 0x30
  71. if orientation == 0x20:
  72. orientation = 1
  73. elif not orientation:
  74. orientation = -1
  75. else:
  76. raise SyntaxError("unknown TGA orientation")
  77. self.info["orientation"] = orientation
  78. if imagetype & 8:
  79. self.info["compression"] = "tga_rle"
  80. if id_len:
  81. self.info["id_section"] = self.fp.read(id_len)
  82. if colormaptype:
  83. # read palette
  84. start, size, mapdepth = i16(s[3:]), i16(s[5:]), i16(s[7:])
  85. if mapdepth == 16:
  86. self.palette = ImagePalette.raw(
  87. "BGR;16", b"\0"*2*start + self.fp.read(2*size))
  88. elif mapdepth == 24:
  89. self.palette = ImagePalette.raw(
  90. "BGR", b"\0"*3*start + self.fp.read(3*size))
  91. elif mapdepth == 32:
  92. self.palette = ImagePalette.raw(
  93. "BGRA", b"\0"*4*start + self.fp.read(4*size))
  94. # setup tile descriptor
  95. try:
  96. rawmode = MODES[(imagetype & 7, depth)]
  97. if imagetype & 8:
  98. # compressed
  99. self.tile = [("tga_rle", (0, 0)+self.size,
  100. self.fp.tell(), (rawmode, orientation, depth))]
  101. else:
  102. self.tile = [("raw", (0, 0)+self.size,
  103. self.fp.tell(), (rawmode, 0, orientation))]
  104. except KeyError:
  105. pass # cannot decode
  106. #
  107. # --------------------------------------------------------------------
  108. # Write TGA file
  109. SAVE = {
  110. "1": ("1", 1, 0, 3),
  111. "L": ("L", 8, 0, 3),
  112. "LA": ("LA", 16, 0, 3),
  113. "P": ("P", 8, 1, 1),
  114. "RGB": ("BGR", 24, 0, 2),
  115. "RGBA": ("BGRA", 32, 0, 2),
  116. }
  117. def _save(im, fp, filename):
  118. try:
  119. rawmode, bits, colormaptype, imagetype = SAVE[im.mode]
  120. except KeyError:
  121. raise IOError("cannot write mode %s as TGA" % im.mode)
  122. if "rle" in im.encoderinfo:
  123. rle = im.encoderinfo["rle"]
  124. else:
  125. compression = im.encoderinfo.get("compression",
  126. im.info.get("compression"))
  127. rle = compression == "tga_rle"
  128. if rle:
  129. imagetype += 8
  130. id_section = im.encoderinfo.get("id_section",
  131. im.info.get("id_section", ""))
  132. id_len = len(id_section)
  133. if id_len > 255:
  134. id_len = 255
  135. id_section = id_section[:255]
  136. warnings.warn("id_section has been trimmed to 255 characters")
  137. if colormaptype:
  138. colormapfirst, colormaplength, colormapentry = 0, 256, 24
  139. else:
  140. colormapfirst, colormaplength, colormapentry = 0, 0, 0
  141. if im.mode in ("LA", "RGBA"):
  142. flags = 8
  143. else:
  144. flags = 0
  145. orientation = im.encoderinfo.get("orientation",
  146. im.info.get("orientation", -1))
  147. if orientation > 0:
  148. flags = flags | 0x20
  149. fp.write(o8(id_len) +
  150. o8(colormaptype) +
  151. o8(imagetype) +
  152. o16(colormapfirst) +
  153. o16(colormaplength) +
  154. o8(colormapentry) +
  155. o16(0) +
  156. o16(0) +
  157. o16(im.size[0]) +
  158. o16(im.size[1]) +
  159. o8(bits) +
  160. o8(flags))
  161. if id_section:
  162. fp.write(id_section)
  163. if colormaptype:
  164. fp.write(im.im.getpalette("RGB", "BGR"))
  165. if rle:
  166. ImageFile._save(
  167. im,
  168. fp,
  169. [("tga_rle", (0, 0) + im.size, 0, (rawmode, orientation))])
  170. else:
  171. ImageFile._save(
  172. im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, orientation))])
  173. # write targa version 2 footer
  174. fp.write(b"\000" * 8 + b"TRUEVISION-XFILE." + b"\000")
  175. #
  176. # --------------------------------------------------------------------
  177. # Registry
  178. Image.register_open(TgaImageFile.format, TgaImageFile)
  179. Image.register_save(TgaImageFile.format, _save)
  180. Image.register_extension(TgaImageFile.format, ".tga")