Fixed: #2589 SVG export - subsprite animation, sprite offsets

This commit is contained in:
Jindra Petřík
2025-12-20 14:29:28 +01:00
parent e3866d93c1
commit 0d19653b8e
16 changed files with 48 additions and 27 deletions

View File

@@ -131,7 +131,7 @@ public class MorphShapeExporter {
rect2.xMin *= settings.zoom;
rect2.yMin *= settings.zoom;
SVGExporter exporter = new SVGExporter(rect2, settings.zoom, "shape");
mst.getStartShapeTag().toSVG(exporter, -2, new CXFORMWITHALPHA(), 0, m, m);
mst.getStartShapeTag().toSVG(0, 0, exporter, -2, new CXFORMWITHALPHA(), 0, m, m);
fos.write(Utf8Helper.getBytes(exporter.getSVG()));
}
try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(fileEnd))) {
@@ -141,7 +141,7 @@ public class MorphShapeExporter {
rect2.xMin *= settings.zoom;
rect2.yMin *= settings.zoom;
SVGExporter exporter = new SVGExporter(rect2, settings.zoom, "shape");
mst.getEndShapeTag().toSVG(exporter, -2, new CXFORMWITHALPHA(), 0, m, m);
mst.getEndShapeTag().toSVG(0, 0, exporter, -2, new CXFORMWITHALPHA(), 0, m, m);
fos.write(Utf8Helper.getBytes(exporter.getSVG()));
}
break;
@@ -153,7 +153,7 @@ public class MorphShapeExporter {
rect2.xMin *= settings.zoom;
rect2.yMin *= settings.zoom;
SVGExporter exporter = new SVGExporter(rect2, settings.zoom, "morphshape");
mst.toSVG(exporter, -2, new CXFORMWITHALPHA(), 0, m, m);
mst.toSVG(0, 0, exporter, -2, new CXFORMWITHALPHA(), 0, m, m);
fos.write(Utf8Helper.getBytes(exporter.getSVG()));
}
break;

View File

@@ -117,7 +117,7 @@ public class ShapeExporter {
rect2.xMin *= settings.zoom;
rect2.yMin *= settings.zoom;
SVGExporter exporter = new SVGExporter(rect2, settings.zoom, "shape");
st.toSVG(exporter, -2, new CXFORMWITHALPHA(), 0, m, m);
st.toSVG(0, 0, exporter, -2, new CXFORMWITHALPHA(), 0, m, m);
fos.write(Utf8Helper.getBytes(exporter.getSVG()));
}
break;

View File

@@ -91,7 +91,7 @@ public class TextExporter {
try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(file))) {
ExportRectangle rect = new ExportRectangle(textTag.getRect());
SVGExporter exporter = new SVGExporter(rect, settings.zoom, "text");
textTag.toSVG(exporter, -2, new CXFORMWITHALPHA(), 0, m, m);
textTag.toSVG(0, 0, exporter, -2, new CXFORMWITHALPHA(), 0, m, m);
fos.write(Utf8Helper.getBytes(exporter.getSVG()));
}
}, handler).run();

View File

@@ -123,21 +123,27 @@ public class SVGExporter implements RequiresNormalizedFonts {
public final ColorTransform colorTransform;
public final int ratio;
public final boolean clipped;
public int frame;
public int time;
public ExportKey(Tag tag, ColorTransform colorTransform, int ratio, boolean clipped) {
public ExportKey(Tag tag, ColorTransform colorTransform, int ratio, boolean clipped, int frame, int time) {
this.tag = tag;
this.colorTransform = colorTransform;
this.ratio = ratio;
this.clipped = clipped;
this.frame = frame;
this.time = time;
}
@Override
public int hashCode() {
int hash = 7;
hash = 79 * hash + Objects.hashCode(this.tag);
hash = 79 * hash + Objects.hashCode(this.colorTransform);
hash = 79 * hash + this.ratio;
hash = 79 * hash + (this.clipped ? 1 : 0);
hash = 11 * hash + Objects.hashCode(this.tag);
hash = 11 * hash + Objects.hashCode(this.colorTransform);
hash = 11 * hash + this.ratio;
hash = 11 * hash + (this.clipped ? 1 : 0);
hash = 11 * hash + this.frame;
hash = 11 * hash + this.time;
return hash;
}
@@ -159,11 +165,17 @@ public class SVGExporter implements RequiresNormalizedFonts {
if (this.clipped != other.clipped) {
return false;
}
if (this.frame != other.frame) {
return false;
}
if (this.time != other.time) {
return false;
}
if (!Objects.equals(this.tag, other.tag)) {
return false;
}
return Objects.equals(this.colorTransform, other.colorTransform);
}
}
}
public SVGExporter(ExportRectangle bounds, double zoom, String objectType) {

View File

@@ -1283,7 +1283,7 @@ public class DefineEditTextTag extends TextTag {
}
@Override
public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, Matrix transformation, Matrix strokeTransformation) {
public void toSVG(int frame, int time, SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, Matrix transformation, Matrix strokeTransformation) {
int realTextId = getSwf().getCharacterId(this);
if (exporter.getNormalizedTexts().containsKey(realTextId) && exporter.getNormalizedTexts().get(realTextId) instanceof DefineEditTextTag) {
DefineEditTextTag normalizedText = (DefineEditTextTag) exporter.getNormalizedTexts().get(realTextId);

View File

@@ -466,8 +466,8 @@ public class DefineSpriteTag extends DrawableTag implements Timelined {
}
@Override
public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, Matrix transformation, Matrix strokeTransformation) throws IOException {
getTimeline().toSVG(0, 0, null, 0, exporter, colorTransform, level + 1, transformation, strokeTransformation);
public void toSVG(int frame, int time, SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, Matrix transformation, Matrix strokeTransformation) throws IOException {
getTimeline().toSVG(frame, time, null, 0, exporter, colorTransform, level + 1, transformation, strokeTransformation);
}
@Override

View File

@@ -420,7 +420,7 @@ public class DefineVideoStreamTag extends DrawableTag implements BoundedTag, Tim
}
@Override
public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, Matrix transformation, Matrix strokeTransformation) throws IOException {
public void toSVG(int frame, int time, SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, Matrix transformation, Matrix strokeTransformation) throws IOException {
}
@Override

View File

@@ -131,7 +131,7 @@ public abstract class ButtonTag extends DrawableTag implements Timelined {
}
@Override
public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, Matrix transformation, Matrix strokeTransformation) throws IOException {
public void toSVG(int frame, int time, SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, Matrix transformation, Matrix strokeTransformation) throws IOException {
getTimeline().toSVG(0, 0, null, 0, exporter, colorTransform, level + 1, transformation, strokeTransformation);
}

View File

@@ -109,6 +109,8 @@ public abstract class DrawableTag extends CharacterTag implements BoundedTag {
/**
* Converts the drawable to SVG.
* @param frame Frame
* @param time Time
* @param exporter SVG exporter
* @param ratio Ratio
* @param colorTransform Color transform
@@ -117,7 +119,7 @@ public abstract class DrawableTag extends CharacterTag implements BoundedTag {
* @param strokeTransformation Stroke transformation
* @throws IOException On I/O error
*/
public abstract void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, Matrix transformation, Matrix strokeTransformation) throws IOException;
public abstract void toSVG(int frame, int time, SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, Matrix transformation, Matrix strokeTransformation) throws IOException;
/**
* Converts the drawable to HTML canvas.

View File

@@ -724,7 +724,7 @@ public abstract class FontTag extends DrawableTag implements AloneTag {
}
@Override
public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, Matrix transformation, Matrix strokeTransformation) {
public void toSVG(int frame, int time, SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, Matrix transformation, Matrix strokeTransformation) {
}

View File

@@ -346,7 +346,7 @@ public abstract class ImageTag extends DrawableTag {
}
@Override
public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, Matrix transformation, Matrix strokeTransformation) throws IOException {
public void toSVG(int frame, int time, SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, Matrix transformation, Matrix strokeTransformation) throws IOException {
SVGShapeExporter shapeExporter = new SVGShapeExporter(ShapeTag.WIND_EVEN_ODD, 1, swf, getShape(1), getCharacterId(), exporter, null, colorTransform, 1, exporter.getZoom(), strokeTransformation);
shapeExporter.export();
}

View File

@@ -420,7 +420,7 @@ public abstract class MorphShapeTag extends DrawableTag {
}
@Override
public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, Matrix transformation, Matrix strokeTransformation) {
public void toSVG(int frame, int time, SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, Matrix transformation, Matrix strokeTransformation) {
if (ratio == -2) {
SHAPEWITHSTYLE beginShapes = getShapeAtRatio(0);

View File

@@ -277,7 +277,7 @@ public abstract class ShapeTag extends DrawableTag implements LazyObject {
}
@Override
public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, Matrix transformation, Matrix strokeTransformation) throws IOException {
public void toSVG(int frame, int time, SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, Matrix transformation, Matrix strokeTransformation) throws IOException {
SVGShapeExporter shapeExporter = new SVGShapeExporter(getWindingRule(), getShapeNum(), swf, getShapes(), getCharacterId(), exporter, null, colorTransform, 1, exporter.getZoom(), strokeTransformation);
shapeExporter.export();
}

View File

@@ -1051,7 +1051,7 @@ public abstract class StaticTextTag extends TextTag {
}
@Override
public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, Matrix transformation, Matrix strokeTransformation) {
public void toSVG(int frame, int time, SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, Matrix transformation, Matrix strokeTransformation) {
int realTextId = getSwf().getCharacterId(this);
if (exporter.getNormalizedTexts().containsKey(realTextId) && exporter.getNormalizedTexts().get(realTextId) instanceof StaticTextTag) {
StaticTextTag normalizedText = (StaticTextTag) exporter.getNormalizedTexts().get(realTextId);

View File

@@ -1963,7 +1963,7 @@ public class Timeline {
Tag drawableTag = (Tag) drawable;
RECT boundRect = drawable.getRect();
ExportRectangle rect = new ExportRectangle(boundRect);
//ExportRectangle rect = new ExportRectangle(boundRect);
DefineScalingGridTag scalingGrid = character.getScalingGridTag();
@@ -1975,8 +1975,12 @@ public class Timeline {
clips.add(clip);
} else {
boolean createNew = false;
int mtime = time + layer.time;
SVGExporter.ExportKey exportKey = new SVGExporter.ExportKey(drawableTag, clrTrans, layer.ratio, layer.clipDepth > -1);
int dframe = mtime % drawable.getNumFrames();
int dtime = mtime - dframe;
SVGExporter.ExportKey exportKey = new SVGExporter.ExportKey(drawableTag, clrTrans, layer.ratio, layer.clipDepth > -1, dframe, dtime);
boolean hasSmallStroke = tagHasSmallStrokes(exporter, drawable, absMat);
if (!hasSmallStroke && exporter.exportedTags.containsKey(exportKey)) {
@@ -1989,11 +1993,12 @@ public class Timeline {
createNew = true;
}
if (createNew) {
exporter.createDefGroup(new ExportRectangle(boundRect), assetName);
drawable.toSVG(exporter, layer.ratio, clrTrans, level + 1, transformation, absMat);
exporter.createDefGroup(new ExportRectangle(boundRect), assetName);
drawable.toSVG(dframe, dtime, exporter, layer.ratio, clrTrans, level + 1, transformation, absMat);
exporter.endGroup();
}
Matrix mat = Matrix.getTranslateInstance(rect.xMin, rect.yMin).preConcatenate(new Matrix(layer.matrix));
Matrix mat = new Matrix(layer.matrix); //Matrix.getTranslateInstance(rect.xMin, rect.yMin).preConcatenate(new Matrix(layer.matrix));
exporter.addUse(mat, boundRect, assetName, layer.instanceName, scalingGrid == null ? null : scalingGrid.splitter, String.valueOf(drawable.getCharacterId()), String.join("___", drawable.getClassNames()), layer.blendMode, layer.filters);
}
}