Added Export Morphshape as start and end shape (SVG, PNG, BMP)

This commit is contained in:
Jindra Petřík
2023-11-05 21:11:10 +01:00
parent 524a199f26
commit fd5c938c48
9 changed files with 133 additions and 2 deletions
@@ -23,18 +23,30 @@ import com.jpexs.decompiler.flash.RetryTask;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.action.parser.ActionParseException;
import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle;
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
import com.jpexs.decompiler.flash.exporters.modes.MorphShapeExportMode;
import com.jpexs.decompiler.flash.exporters.modes.ShapeExportMode;
import com.jpexs.decompiler.flash.exporters.morphshape.CanvasMorphShapeExporter;
import com.jpexs.decompiler.flash.exporters.settings.MorphShapeExportSettings;
import com.jpexs.decompiler.flash.helpers.BMPFile;
import com.jpexs.decompiler.flash.helpers.ImageHelper;
import com.jpexs.decompiler.flash.tags.DefineMorphShapeTag;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
import com.jpexs.decompiler.flash.tags.base.MorphShapeTag;
import com.jpexs.decompiler.flash.tags.base.RenderContext;
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
import com.jpexs.decompiler.flash.tags.enums.ImageFormat;
import com.jpexs.decompiler.flash.timeline.Timeline;
import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA;
import com.jpexs.decompiler.flash.types.RECT;
import com.jpexs.decompiler.flash.types.RGB;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.Path;
import com.jpexs.helpers.SerializableImage;
import com.jpexs.helpers.utf8.Utf8Helper;
import java.awt.Graphics2D;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -92,9 +104,33 @@ public class MorphShapeExporter {
}
final File file = new File(outdir + File.separator + characterID + settings.getFileExtension());
final File fileStart = new File(outdir + File.separator + characterID + ".start" + settings.getFileExtension());
final File fileEnd = new File(outdir + File.separator + characterID + ".end" + settings.getFileExtension());
new RetryTask(() -> {
MorphShapeTag mst = (MorphShapeTag) t;
switch (settings.mode) {
case SVG_START_END:
try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(fileStart))) {
ExportRectangle rect = new ExportRectangle(mst.getStartBounds());
rect.xMax *= settings.zoom;
rect.yMax *= settings.zoom;
rect.xMin *= settings.zoom;
rect.yMin *= settings.zoom;
SVGExporter exporter = new SVGExporter(rect, settings.zoom, "shape");
mst.getStartShapeTag().toSVG(exporter, -2, new CXFORMWITHALPHA(), 0);
fos.write(Utf8Helper.getBytes(exporter.getSVG()));
}
try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(fileEnd))) {
ExportRectangle rect = new ExportRectangle(mst.getStartBounds());
rect.xMax *= settings.zoom;
rect.yMax *= settings.zoom;
rect.xMin *= settings.zoom;
rect.yMin *= settings.zoom;
SVGExporter exporter = new SVGExporter(rect, settings.zoom, "shape");
mst.getEndShapeTag().toSVG(exporter, -2, new CXFORMWITHALPHA(), 0);
fos.write(Utf8Helper.getBytes(exporter.getSVG()));
}
break;
case SVG:
try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(file))) {
ExportRectangle rect = new ExportRectangle(mst.getRect());
@@ -107,6 +143,55 @@ public class MorphShapeExporter {
fos.write(Utf8Helper.getBytes(exporter.getSVG()));
}
break;
case PNG_START_END:
case BMP_START_END:
double unzoom = settings.zoom;
ShapeTag st = mst.getStartShapeTag();
RECT rect = st.getRect();
int newWidth = (int) (rect.getWidth() * settings.zoom / SWF.unitDivisor) + 1;
int newHeight = (int) (rect.getHeight() * settings.zoom / SWF.unitDivisor) + 1;
SerializableImage img = new SerializableImage(newWidth, newHeight, SerializableImage.TYPE_INT_ARGB_PRE);
img.fillTransparent();
if (settings.mode == MorphShapeExportMode.BMP_START_END) {
RGB backColor = t.getSwf().getBackgroundColor().backgroundColor;
if (backColor != null) {
Graphics2D g = (Graphics2D) img.getGraphics();
g.setColor(backColor.toColor());
g.fillRect(0, 0, img.getWidth(), img.getHeight());
}
}
Matrix m = Matrix.getScaleInstance(settings.zoom);
m.translate(-rect.Xmin, -rect.Ymin);
st.toImage(0, 0, 0, new RenderContext(), img, img, false, m, m, m, m, new CXFORMWITHALPHA(), unzoom, false, new ExportRectangle(rect), true, Timeline.DRAW_MODE_ALL, 0, true);
if (settings.mode == MorphShapeExportMode.PNG_START_END) {
ImageHelper.write(img.getBufferedImage(), ImageFormat.PNG, fileStart);
} else {
BMPFile.saveBitmap(img.getBufferedImage(), fileStart);
}
st = mst.getEndShapeTag();
rect = st.getRect();
newWidth = (int) (rect.getWidth() * settings.zoom / SWF.unitDivisor) + 1;
newHeight = (int) (rect.getHeight() * settings.zoom / SWF.unitDivisor) + 1;
img = new SerializableImage(newWidth, newHeight, SerializableImage.TYPE_INT_ARGB_PRE);
img.fillTransparent();
if (settings.mode == MorphShapeExportMode.BMP_START_END) {
RGB backColor = t.getSwf().getBackgroundColor().backgroundColor;
if (backColor != null) {
Graphics2D g = (Graphics2D) img.getGraphics();
g.setColor(backColor.toColor());
g.fillRect(0, 0, img.getWidth(), img.getHeight());
}
}
m = Matrix.getScaleInstance(settings.zoom);
m.translate(-rect.Xmin, -rect.Ymin);
st.toImage(0, 0, 0, new RenderContext(), img, img, false, m, m, m, m, new CXFORMWITHALPHA(), unzoom, false, new ExportRectangle(rect), true, Timeline.DRAW_MODE_ALL, 0, true);
if (settings.mode == MorphShapeExportMode.PNG_START_END) {
ImageHelper.write(img.getBufferedImage(), ImageFormat.PNG, fileEnd);
} else {
BMPFile.saveBitmap(img.getBufferedImage(), fileEnd);
}
break;
case CANVAS:
try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(file))) {
int deltaX = -Math.min(mst.getStartBounds().Xmin, mst.getEndBounds().Xmin);
@@ -23,8 +23,10 @@ package com.jpexs.decompiler.flash.exporters.modes;
public enum MorphShapeExportMode {
//TODO: implement other morphshape export modes
SVG,
SVG_START_END,
CANVAS,
//PNG,
PNG_START_END,
BMP_START_END,
//GIF,
//AVI,
SWF,
@@ -37,7 +37,12 @@ public class MorphShapeExportSettings {
public String getFileExtension() {
switch (mode) {
case PNG_START_END:
return ".png";
case BMP_START_END:
return ".bmp";
case SVG:
case SVG_START_END:
return ".svg";
case CANVAS:
return ".html";
@@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.tags.base.MorphShapeTag;
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
import com.jpexs.decompiler.flash.types.BasicType;
import com.jpexs.decompiler.flash.types.MORPHFILLSTYLE;
import com.jpexs.decompiler.flash.types.MORPHFILLSTYLEARRAY;
@@ -151,4 +152,14 @@ public class DefineMorphShape2Tag extends MorphShapeTag {
endEdgeBounds = SHAPERECORD.getBounds(endEdges.shapeRecords, null, 4, true);
}
@Override
public ShapeTag getShapeTagAtRatio(int ratio) {
DefineShape4Tag ret = new DefineShape4Tag(swf);
ret.usesNonScalingStrokes = usesNonScalingStrokes;
ret.usesScalingStrokes = usesScalingStrokes;
ret.shapes = getShapeAtRatio(ratio);
ret.updateBounds();
ret.setTimelined(swf);
return ret;
}
}
@@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.tags.base.MorphShapeTag;
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
import com.jpexs.decompiler.flash.types.MORPHFILLSTYLE;
import com.jpexs.decompiler.flash.types.MORPHFILLSTYLEARRAY;
import com.jpexs.decompiler.flash.types.MORPHLINESTYLE;
@@ -110,4 +111,13 @@ public class DefineMorphShapeTag extends MorphShapeTag {
public int getShapeNum() {
return 1;
}
@Override
public ShapeTag getShapeTagAtRatio(int ratio) {
DefineShape3Tag ret = new DefineShape3Tag(swf);
ret.shapes = getShapeAtRatio(ratio);
ret.updateBounds();
ret.setTimelined(swf);
return ret;
}
}
@@ -24,6 +24,7 @@ import com.jpexs.decompiler.flash.exporters.morphshape.CanvasMorphShapeExporter;
import com.jpexs.decompiler.flash.exporters.morphshape.SVGMorphShapeExporter;
import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter;
import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter;
import com.jpexs.decompiler.flash.tags.DefineShape4Tag;
import com.jpexs.decompiler.flash.types.BasicType;
import com.jpexs.decompiler.flash.types.ColorTransform;
import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY;
@@ -188,8 +189,18 @@ public abstract class MorphShapeTag extends DrawableTag {
public SHAPE getEndEdges() {
return endEdges;
}
public abstract ShapeTag getShapeTagAtRatio(int ratio);
public ShapeTag getStartShapeTag() {
return getShapeTagAtRatio(0);
}
public ShapeTag getEndShapeTag() {
return getShapeTagAtRatio(65535);
}
public SHAPEWITHSTYLE getShapeAtRatio(int ratio) {
List<SHAPERECORD> finalRecords = new ArrayList<>();
FILLSTYLEARRAY fillStyles = morphFillStyles.getFillStylesAt(ratio);