Skip to content

Commit

Permalink
Add --shape and --frame options; use mixins instead of SVGExporter su…
Browse files Browse the repository at this point in the history
…bclasses
  • Loading branch information
tuomassalo committed Jan 9, 2016
1 parent 6dcc9b9 commit 1f1bf68
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 3 deletions.
25 changes: 23 additions & 2 deletions bin/swf2svg.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,45 @@
import argparse
from swf.movie import SWF
from swf.export import SVGExporter
from swf.export import SVGExporter, SingleShapeSVGExporterMixin, FrameSVGExporterMixin

parser = argparse.ArgumentParser(description="Convert an SWF file into an SVG")
parser.add_argument("--swf", type=argparse.FileType('rb'),
help="Location of SWG file to convert", required=True)
parser.add_argument("--svg", type=argparse.FileType('wb'),
help="Location of converted SVG file", required=True)
parser.add_argument("--shape", type=int,
help="Only export shape SHAPE (integer)", required=False)
parser.add_argument("--frame", type=int,
help="Export frame FRAME (0-based index) instead of frame 0", required=False)

options = parser.parse_args()
argparse.swf_file = options.swf

# load and parse the SWF
swf = SWF(options.swf)

export_opts = {}
export_mixins = []


# process the optional arguments

if options.shape is not None:
export_mixins.append(SingleShapeSVGExporterMixin)
export_opts['shape'] = options.shape

if options.frame is not None:
export_mixins.append(FrameSVGExporterMixin)
export_opts['frame'] = options.frame

# create the SVG exporter
svg_exporter = SVGExporter()

# NB: Construct the class dynamically, since the chosen options dictate which mixins to use.
svg_exporter.__class__ = type('ThisExporter', tuple(export_mixins + [SVGExporter]), {})

# export!
svg = swf.export(svg_exporter)
svg = svg_exporter.export(swf, **export_opts)

# save the SVG
options.svg.write(svg.read())
59 changes: 58 additions & 1 deletion swf/export.py
Original file line number Diff line number Diff line change
Expand Up @@ -810,11 +810,36 @@ def export_image(self, tag, image=None):
class SingleShapeSVGExporter(SVGExporter):
"""
An SVG exporter which knows how to export a single shape.
NB: This class is here just for backward compatibility.
Use SingleShapeSVGExporterMixin instead to mix with other functionality.
"""
def __init__(self, margin=0):
super(SingleShapeSVGExporter, self).__init__(margin = margin)

def export_single_shape(self, shape_tag, swf):
class MySingleShapeSVGExporter(SingleShapeSVGExporterMixin, SVGExporter):
pass
exporter = MySingleShapeSVGExporter()
return exporter.export(swf, shape=shape_tag)

class SingleShapeSVGExporterMixin(object):
def export(self, swf, shape, **export_opts):
""" Exports the specified shape of the SWF to SVG.
@param swf The SWF.
@param shape Which shape to export, either by characterId(int) or as a Tag object.
"""

# If `shape` is given as int, find corresponding shape tag.
if isinstance(shape, Tag):
shape_tag = shape
else:
shapes = [x for x in swf.all_tags_of_type((TagDefineShape, TagDefineSprite)) if x.characterId == shape]
if len(shapes):
shape_tag = shapes[0]
else:
raise Exception("Shape %s not found" % shape)

from swf.movie import SWF

# find a typical use of this shape
Expand Down Expand Up @@ -847,7 +872,39 @@ def export_single_shape(self, shape_tag, swf):
stunt_swf = SWF()
stunt_swf.tags = tags_to_export

return super(SingleShapeSVGExporter, self).export(stunt_swf)
return super(SingleShapeSVGExporterMixin, self).export(stunt_swf, **export_opts)

class FrameSVGExporterMixin(object):
def export(self, swf, frame, **export_opts):
""" Exports a frame of the specified SWF to SVG.
@param swf The SWF.
@param frame Which frame to export, by 0-based index (int)
"""
self.wanted_frame = frame
return super(FrameSVGExporterMixin, self).export(swf, *export_opts)

def get_display_tags(self, tags, z_sorted=True):

current_frame = 0
frame_tags = dict() # keys are depths, values are placeobject tags
for tag in tags:
if isinstance(tag, TagShowFrame):
if current_frame == self.wanted_frame:
break
current_frame += 1
elif isinstance(tag, TagPlaceObject):
if tag.hasMove:
orig_tag = frame_tags.pop(tag.depth)

if not tag.hasCharacter:
tag.characterId = orig_tag.characterId
frame_tags[tag.depth] = tag
elif isinstance(tag, TagRemoveObject):
del frame_tags[tag.depth]

return super(FrameSVGExporterMixin, self).get_display_tags(frame_tags.values(), z_sorted)


class SVGFilterFactory(object):
# http://commons.oreilly.com/wiki/index.php/SVG_Essentials/Filters
Expand Down

0 comments on commit 1f1bf68

Please sign in to comment.