movie.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. """
  2. SWF
  3. """
  4. from .tag import SWFTimelineContainer
  5. from .stream import SWFStream
  6. from .export import SVGExporter
  7. try:
  8. import cStringIO as StringIO
  9. except ImportError:
  10. from io import BytesIO
  11. class SWFHeaderException(Exception):
  12. """ Exception raised in case of an invalid SWFHeader """
  13. def __init__(self, message):
  14. super(SWFHeaderException, self).__init__(message)
  15. class SWFHeader(object):
  16. """ SWF header """
  17. def __init__(self, stream):
  18. a = stream.readUI8()
  19. b = stream.readUI8()
  20. c = stream.readUI8()
  21. if not a in [0x43, 0x46, 0x5A] or b != 0x57 or c != 0x53:
  22. # Invalid signature! ('FWS' or 'CWS' or 'ZFS')
  23. raise SWFHeaderException("not a SWF file! (invalid signature)")
  24. self._compressed_zlib = (a == 0x43)
  25. self._compressed_lzma = (a == 0x5A)
  26. self._version = stream.readUI8()
  27. self._file_length = stream.readUI32()
  28. if not (self._compressed_zlib or self._compressed_lzma):
  29. self._frame_size = stream.readRECT()
  30. self._frame_rate = stream.readFIXED8()
  31. self._frame_count = stream.readUI16()
  32. @property
  33. def frame_size(self):
  34. """ Return frame size as a SWFRectangle """
  35. return self._frame_size
  36. @property
  37. def frame_rate(self):
  38. """ Return frame rate """
  39. return self._frame_rate
  40. @property
  41. def frame_count(self):
  42. """ Return number of frames """
  43. return self._frame_count
  44. @property
  45. def file_length(self):
  46. """ Return uncompressed file length """
  47. return self._file_length
  48. @property
  49. def version(self):
  50. """ Return SWF version """
  51. return self._version
  52. @property
  53. def compressed(self):
  54. """ Whether the SWF is compressed """
  55. return self._compressed_zlib or self._compressed_lzma
  56. @property
  57. def compressed_zlib(self):
  58. """ Whether the SWF is compressed using ZLIB """
  59. return self._compressed_zlib
  60. @property
  61. def compressed_lzma(self):
  62. """ Whether the SWF is compressed using LZMA """
  63. return self._compressed_lzma
  64. def __str__(self):
  65. return " [SWFHeader]\n" + \
  66. " Version: %d\n" % self.version + \
  67. " FileLength: %d\n" % self.file_length + \
  68. " FrameSize: %s\n" % self.frame_size.__str__() + \
  69. " FrameRate: %d\n" % self.frame_rate + \
  70. " FrameCount: %d\n" % self.frame_count
  71. class SWF(SWFTimelineContainer):
  72. """
  73. SWF class
  74. The SWF (pronounced 'swiff') file format delivers vector graphics, text,
  75. video, and sound over the Internet and is supported by Adobe Flash
  76. Player software. The SWF file format is designed to be an efficient
  77. delivery format, not a format for exchanging graphics between graphics
  78. editors.
  79. @param file: a file object with read(), seek(), tell() methods.
  80. """
  81. def __init__(self, file=None):
  82. super(SWF, self).__init__()
  83. self._data = None if file is None else SWFStream(file)
  84. self._header = None
  85. if self._data is not None:
  86. self.parse(self._data)
  87. @property
  88. def data(self):
  89. """
  90. Return the SWFStream object (READ ONLY)
  91. """
  92. return self._data
  93. @property
  94. def header(self):
  95. """ Return the SWFHeader """
  96. return self._header
  97. def export(self, exporter=None, force_stroke=False):
  98. """
  99. Export this SWF using the specified exporter.
  100. When no exporter is passed in the default exporter used
  101. is swf.export.SVGExporter.
  102. Exporters should extend the swf.export.BaseExporter class.
  103. @param exporter : the exporter to use
  104. @param force_stroke : set to true to force strokes on fills,
  105. useful for some edge cases.
  106. """
  107. exporter = SVGExporter() if exporter is None else exporter
  108. if self._data is None:
  109. raise Exception("This SWF was not loaded! (no data)")
  110. if len(self.tags) == 0:
  111. raise Exception("This SWF doesn't contain any tags!")
  112. return exporter.export(self, force_stroke)
  113. def parse_file(self, filename):
  114. """ Parses the SWF from a filename """
  115. self.parse(open(filename, 'rb'))
  116. def parse(self, data):
  117. """
  118. Parses the SWF.
  119. The @data parameter can be a file object or a SWFStream
  120. """
  121. self._data = data = data if isinstance(data, SWFStream) else SWFStream(data)
  122. self._header = SWFHeader(self._data)
  123. if self._header.compressed:
  124. temp = BytesIO()
  125. if self._header.compressed_zlib:
  126. import zlib
  127. data = data.f.read()
  128. zip = zlib.decompressobj()
  129. temp.write(zip.decompress(data))
  130. else:
  131. import pylzma
  132. data.readUI32() #consume compressed length
  133. data = data.f.read()
  134. temp.write(pylzma.decompress(data))
  135. temp.seek(0)
  136. data = SWFStream(temp)
  137. self._header._frame_size = data.readRECT()
  138. self._header._frame_rate = data.readFIXED8()
  139. self._header._frame_count = data.readUI16()
  140. self.parse_tags(data)
  141. def __str__(self):
  142. s = "[SWF]\n"
  143. s += self._header.__str__()
  144. for tag in self.tags:
  145. s += tag.__str__() + "\n"
  146. return s