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.

163 lines
4.0 KiB

4 years ago
  1. #
  2. # The Python Imaging Library.
  3. # $Id$
  4. #
  5. # FLI/FLC file handling.
  6. #
  7. # History:
  8. # 95-09-01 fl Created
  9. # 97-01-03 fl Fixed parser, setup decoder tile
  10. # 98-07-15 fl Renamed offset attribute to avoid name clash
  11. #
  12. # Copyright (c) Secret Labs AB 1997-98.
  13. # Copyright (c) Fredrik Lundh 1995-97.
  14. #
  15. # See the README file for information on usage and redistribution.
  16. #
  17. from . import Image, ImageFile, ImagePalette
  18. from ._binary import i8, i16le as i16, i32le as i32, o8
  19. __version__ = "0.2"
  20. #
  21. # decoder
  22. def _accept(prefix):
  23. return len(prefix) >= 6 and i16(prefix[4:6]) in [0xAF11, 0xAF12]
  24. ##
  25. # Image plugin for the FLI/FLC animation format. Use the <b>seek</b>
  26. # method to load individual frames.
  27. class FliImageFile(ImageFile.ImageFile):
  28. format = "FLI"
  29. format_description = "Autodesk FLI/FLC Animation"
  30. _close_exclusive_fp_after_loading = False
  31. def _open(self):
  32. # HEAD
  33. s = self.fp.read(128)
  34. magic = i16(s[4:6])
  35. if not (magic in [0xAF11, 0xAF12] and
  36. i16(s[14:16]) in [0, 3] and # flags
  37. s[20:22] == b"\x00\x00"): # reserved
  38. raise SyntaxError("not an FLI/FLC file")
  39. # frames
  40. self.__framecount = i16(s[6:8])
  41. # image characteristics
  42. self.mode = "P"
  43. self._size = i16(s[8:10]), i16(s[10:12])
  44. # animation speed
  45. duration = i32(s[16:20])
  46. if magic == 0xAF11:
  47. duration = (duration * 1000) // 70
  48. self.info["duration"] = duration
  49. # look for palette
  50. palette = [(a, a, a) for a in range(256)]
  51. s = self.fp.read(16)
  52. self.__offset = 128
  53. if i16(s[4:6]) == 0xF100:
  54. # prefix chunk; ignore it
  55. self.__offset = self.__offset + i32(s)
  56. s = self.fp.read(16)
  57. if i16(s[4:6]) == 0xF1FA:
  58. # look for palette chunk
  59. s = self.fp.read(6)
  60. if i16(s[4:6]) == 11:
  61. self._palette(palette, 2)
  62. elif i16(s[4:6]) == 4:
  63. self._palette(palette, 0)
  64. palette = [o8(r)+o8(g)+o8(b) for (r, g, b) in palette]
  65. self.palette = ImagePalette.raw("RGB", b"".join(palette))
  66. # set things up to decode first frame
  67. self.__frame = -1
  68. self.__fp = self.fp
  69. self.__rewind = self.fp.tell()
  70. self.seek(0)
  71. def _palette(self, palette, shift):
  72. # load palette
  73. i = 0
  74. for e in range(i16(self.fp.read(2))):
  75. s = self.fp.read(2)
  76. i = i + i8(s[0])
  77. n = i8(s[1])
  78. if n == 0:
  79. n = 256
  80. s = self.fp.read(n * 3)
  81. for n in range(0, len(s), 3):
  82. r = i8(s[n]) << shift
  83. g = i8(s[n+1]) << shift
  84. b = i8(s[n+2]) << shift
  85. palette[i] = (r, g, b)
  86. i += 1
  87. @property
  88. def n_frames(self):
  89. return self.__framecount
  90. @property
  91. def is_animated(self):
  92. return self.__framecount > 1
  93. def seek(self, frame):
  94. if not self._seek_check(frame):
  95. return
  96. if frame < self.__frame:
  97. self._seek(0)
  98. for f in range(self.__frame + 1, frame + 1):
  99. self._seek(f)
  100. def _seek(self, frame):
  101. if frame == 0:
  102. self.__frame = -1
  103. self.__fp.seek(self.__rewind)
  104. self.__offset = 128
  105. if frame != self.__frame + 1:
  106. raise ValueError("cannot seek to frame %d" % frame)
  107. self.__frame = frame
  108. # move to next frame
  109. self.fp = self.__fp
  110. self.fp.seek(self.__offset)
  111. s = self.fp.read(4)
  112. if not s:
  113. raise EOFError
  114. framesize = i32(s)
  115. self.decodermaxblock = framesize
  116. self.tile = [("fli", (0, 0)+self.size, self.__offset, None)]
  117. self.__offset += framesize
  118. def tell(self):
  119. return self.__frame
  120. #
  121. # registry
  122. Image.register_open(FliImageFile.format, FliImageFile, _accept)
  123. Image.register_extensions(FliImageFile.format, [".fli", ".flc"])