[swfmill] Wrapping of SVG elements
Gerrit Karius
g99k at hotmail.com
Fri Jul 28 12:13:39 EDT 2006
Hi everyone. I fixed the "simple-svg.xslt" sheet to the point where it fits
my purposes, so I will stop working on it for the time being. The swf output
structure has now changed as follows:
* All shape, sprite and text definitions are now spread out flat in the
first frame. This means you can now access all assets with actionscript, not
just the outermost element.
* The svg:g nodes of the svg tree are not wrapped anymore. This means that
every g node now corresponds to exactly one DefineSprite tag. Paths and text
are still wrapped in sprites (I don't know if they could be exported
otherwise).
* svg:use elements don't get a swf definition anymore. They are converted to
simple references that place an existing asset on the stage.
* In the PlaceObject2 tag, if an inkscape:label attribute is present, it is
used for naming an instance instead of the id. A leading # character gets
removed. This allows for several instances to have the same name. Before,
the svg:id was used, which must be unique. The id is still used for naming
the asset itself in the Export tag.
The xslt sheet's structure has has also changed a bit. In case someone
cares, here's an explanation:
* The template modes "svg" and "svg-inner" have ceased to exist. I've
replaced them with 3 new modes: "queue", "definition" and "placement":
1. queue mode just iterates without producing output, so that the innermost
elements get queued to the start and the tree flattens out.
2. after queue has finished, definition mode calls the type-specific
templates, which call the child elements in placement mode.
3. placement mode simply places the elements inside their parent's
definition.
* I introduced 3 named templates for redundant code: "placeObject",
"wrapElement" and "exportElement".
* I removed the template "svg:g[@regard-pivot]" (as you suggested, dan). The
templates for "svg:text" and "svg:flowRoot" have been adjusted to the new
structure, and should work as before (which they apparently did not). I'm
not really interested in importing text, so I leave that part to someone
else. :-)
So much for the introduction. Here comes the xml. If anyone cares to test
this sheet, please post your findings, changes or suggestions.
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:swft="http://subsignal.org/swfml/swft"
xmlns:str="http://exslt.org/strings"
xmlns:xlink="http://www.w3.org/1999/xlink"
extension-element-prefixes="swft"
version='1.0'>
<!-- named template for redundant placing -->
<xsl:template name="placeObject">
<!-- place the element, or the referenced element (if it's a reference).
-->
<xsl:variable name="id">
<xsl:choose>
<xsl:when test="name()='use'">
<xsl:value-of select="swft:map-id(substring(@xlink:href,2))"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="swft:map-id(@id)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<!-- use inkscape label as an instance name instead of id, allowing
multiple instances with the same name. -->
<xsl:variable name="name">
<xsl:choose>
<xsl:when test="@inkscape:label">
<xsl:choose>
<xsl:when test="substring(@inkscape:label,1,1)='#'">
<xsl:value-of select="substring(@inkscape:label,2)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="@inkscape:label"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="@id"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<!-- place the object. -->
<PlaceObject2 replace="0" depth="{swft:next-depth()}" name="{$name}"
objectID="{$id}">
<transform>
<xsl:choose>
<xsl:when test="@transform">
<xsl:copy-of select="swft:transform(@transform)"/>
</xsl:when>
<xsl:otherwise>
<Transform transX="0" transY="0"/>
</xsl:otherwise>
</xsl:choose>
</transform>
</PlaceObject2>
</xsl:template>
<!-- named template for redundant wrappers -->
<xsl:template name="wrapElement">
<xsl:param name="innerid" />
<xsl:variable name="id" select="swft:map-id(@id)" />
<DefineSprite objectID="{$id}" frames="1">
<tags>
<PlaceObject2 replace="0" depth="{swft:next-depth()}"
objectID="{$innerid}">
<transform>
<Transform transX="0" transY="0"/>
</transform>
</PlaceObject2>
<ShowFrame/>
<End/>
</tags>
</DefineSprite>
</xsl:template>
<!-- named template for redundant exports -->
<xsl:template name="exportElement">
<xsl:variable name="id" select="swft:map-id(@id)" />
<xsl:variable name="name" select="@id" />
<!-- export the element. -->
<xsl:if test="@id">
<Export>
<symbols>
<Symbol objectID="{$id}" name="{$name}"/>
</symbols>
</Export>
</xsl:if>
<!-- define a class, if applicable. -->
<xsl:variable name="class" select="@class"/>
<xsl:if test="string-length($class) > 0">
<xsl:call-template name="register-class">
<xsl:with-param name="class" select="$class"/>
<xsl:with-param name="linkage-id" select="$name"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<!-- entry point: starts 2 passes, one for queuing up the definitions, one
for placing the elements. -->
<xsl:template match="svg:svg" mode="svg">
<xsl:param name="id"/>
<!-- initiate the definition pass. -->
<xsl:apply-templates mode="queue" />
<!-- define svg as sprite. -->
<DefineSprite objectID="{$id}" frames="1">
<tags>
<!-- initiate the placement pass. -->
<xsl:apply-templates mode="placement" />
<ShowFrame/>
<End/>
</tags>
</DefineSprite>
</xsl:template>
<xsl:template match="svg:g|svg:path|svg:rect|svg:use|svg:text" mode="queue">
<xsl:variable name="id"><xsl:value-of
select="swft:map-id(@id)"/></xsl:variable>
<xsl:variable name="name" select="@id"/>
<!-- first define the subparts, so that we get the innermost ones queued
first. -->
<xsl:apply-templates mode="queue" />
<!-- now define this element, which is based on the subparts. -->
<xsl:apply-templates select="." mode="definition">
<xsl:with-param name="id" select="$id"/>
<xsl:with-param name="name" select="$name"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="svg:g|svg:path|svg:rect|svg:use|svg:text"
mode="placement">
<!-- no definition. just place this element. -->
<xsl:call-template name="placeObject" />
</xsl:template>
<xsl:template match="svg:g" mode="definition" priority="-1">
<xsl:param name="id"/>
<xsl:param name="name"/>
<!-- define the group and place the subparts -->
<DefineSprite objectID="{$id}" frames="1">
<tags>
<xsl:apply-templates mode="placement" />
<ShowFrame/>
<End/>
</tags>
</DefineSprite>
<!-- export -->
<xsl:call-template name="exportElement" />
</xsl:template>
<xsl:template match="svg:path" mode="definition">
<xsl:param name="id"/>
<xsl:variable name="shapeid"><xsl:value-of
select="swft:next-id()"/></xsl:variable>
<!-- define the path -->
<xsl:copy-of select="swft:path( @d, $shapeid, @style )"/>
<!-- wrap in sprite -->
<xsl:call-template name="wrapElement">
<xsl:with-param name="innerid" select="$shapeid" />
</xsl:call-template>
<!-- export -->
<xsl:call-template name="exportElement" />
</xsl:template>
<xsl:template match="svg:rect" mode="definition">
<xsl:param name="id"/>
<xsl:param name="name"/>
<xsl:variable name="shapeid"><xsl:value-of
select="swft:next-id()"/></xsl:variable>
<!-- define the element -->
<DefineShape3 objectID="{$shapeid}">
<bounds>
<Rectangle left="{@x}" right="{(@x+ at width)*20}" top="{@y}"
bottom="{(@y+ at height)*20}"/>
</bounds>
<styles>
<StyleList>
<xsl:copy-of select="swft:css(@style)/tmp/*"/>
</StyleList>
</styles>
<shapes>
<Shape>
<edges>
<ShapeSetup x="{(@x+ at width)*20}" y="{(@y+ at height)*20}" fillStyle0="1"
lineStyle="1"/>
<LineTo x="-{(@width)*20}" y="0"/>
<LineTo x="0" y="-{(@height)*20}"/>
<LineTo x="{(@width)*20}" y="0"/>
<LineTo x="0" y="{(@height)*20}"/>
<ShapeSetup/>
</edges>
</Shape>
</shapes>
</DefineShape3>
<!-- wrap in sprite -->
<xsl:call-template name="wrapElement">
<xsl:with-param name="innerid" select="$shapeid" />
</xsl:call-template>
<!-- export -->
<xsl:call-template name="exportElement" />
</xsl:template>
<xsl:template match="svg:flowRoot" mode="definition">
<xsl:param name="id"/>
<xsl:param name="name"/>
<xsl:variable name="shapeid"><xsl:value-of
select="swft:next-id()"/></xsl:variable>
<!-- define the element -->
<DefineEditText objectID="{$shapeid}" wordWrap="1" multiLine="1"
password="0"
readOnly="0" autoSize="0" hasLayout="1"
notSelectable="0" hasBorder="1" isHTML="0" useOutlines="1"
fontRef="{swft:map-id('vera')}" fontHeight="240"
align="0" leftMargin="0" rightMargin="0" indent="0" leading="41"
variableName="{@name}">
<xsl:attribute name="initialText">
<xsl:value-of select="normalize-space(.)"/>
</xsl:attribute>
<size>
<Rectangle left="{svg:flowRegion/svg:rect/@x * 20}"
right="{(svg:flowRegion/svg:rect/@x + svg:flowRegion/svg:rect/@width)*
20}"
top="{svg:flowRegion/svg:rect/@y * 20}"
bottom="{(svg:flowRegion/svg:rect/@y +
svg:flowRegion/svg:rect/@height)* 20}"/>
</size>
<color>
<ColorRGBA red="100" green="150" blue="200" alpha="127"/>
</color>
</DefineEditText>
<!-- wrap in sprite -->
<xsl:call-template name="wrapElement">
<xsl:with-param name="innerid" select="$shapeid" />
</xsl:call-template>
<!-- export -->
<xsl:call-template name="exportElement" />
</xsl:template>
<xsl:template match="svg:text" mode="definition">
<xsl:param name="id"/>
<xsl:param name="name"/>
<xsl:variable name="shapeid"><xsl:value-of
select="swft:next-id()"/></xsl:variable>
<!-- define the element -->
<DefineEditText objectID="{$shapeid}" wordWrap="0" multiLine="1"
password="0"
readOnly="1" autoSize="1" hasLayout="1"
notSelectable="1" hasBorder="0" isHTML="0" useOutlines="1"
fontRef="{swft:map-id('vera')}" fontHeight="240"
align="0" leftMargin="0" rightMargin="0" indent="0" leading="1"
variableName="{@name}">
<xsl:attribute name="initialText">
<xsl:apply-templates mode="svg-text"/>
</xsl:attribute>
<size>
<Rectangle left="{@x * 20}"
right="{@x * 30}"
top="{@y * 20}"
bottom="{@y * 30}"/>
</size>
<color>
<ColorRGBA red="255" green="255" blue="255" alpha="255"/>
</color>
</DefineEditText>
<!-- wrap in sprite -->
<xsl:call-template name="wrapElement">
<xsl:with-param name="innerid" select="$shapeid" />
</xsl:call-template>
<!-- export -->
<xsl:call-template name="exportElement" />
</xsl:template>
<xsl:template match="svg:tspan[position()=1]" mode="svg-text">
<xsl:apply-templates mode="svg-text"/>
</xsl:template>
<xsl:template match="svg:tspan" mode="svg-text" priority="-1">
<xsl:text>
</xsl:text>
<xsl:apply-templates mode="svg-text"/>
</xsl:template>
<xsl:template match="text()" mode="svg-text">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="*|@*|text()" mode="svg" priority="-1"/>
<xsl:template match="ShapeSetup" mode="shape">
<ShapeSetup fillStyle0="1" fillStyle1="2" lineStyle="1">
<xsl:apply-templates select="*|@*" mode="shape"/>
</ShapeSetup>
</xsl:template>
<xsl:template match="*|@*|text()" mode="shape" priority="-1">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
More information about the swfmill
mailing list