mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-09-25 02:30:44 +00:00
#559 morphshapes as animated SVG/CSS3 (Currenly only the edges are morphed, the style is not ready)
This commit is contained in:
@@ -99,6 +99,7 @@ import com.jpexs.decompiler.flash.tags.base.ContainerItem;
|
||||
import com.jpexs.decompiler.flash.tags.base.DrawableTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.FontTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.MorphShapeTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.RemoveTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
|
||||
@@ -1479,24 +1480,6 @@ public final class SWF implements TreeItem, Timelined {
|
||||
fos.write(chunkBytes);
|
||||
}
|
||||
|
||||
//TODO: implement morphshape export. How to handle 65536 frames?
|
||||
public List<File> exportMorphShapes(AbortRetryIgnoreHandler handler, String outdir, List<Tag> tags, final MorphshapeExportMode mode) throws IOException {
|
||||
List<File> ret = new ArrayList<>();
|
||||
if (tags.isEmpty()) {
|
||||
return ret;
|
||||
}
|
||||
File foutdir = new File(outdir);
|
||||
if (!foutdir.exists()) {
|
||||
if (!foutdir.mkdirs()) {
|
||||
if (!foutdir.exists()) {
|
||||
throw new IOException("Cannot create directory " + outdir);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new UnsupportedOperationException("Not implemented");
|
||||
//return ret;
|
||||
}
|
||||
|
||||
private static void makeAVI(List<BufferedImage> images, int frameRate, File file) throws IOException {
|
||||
if (images.isEmpty()) {
|
||||
return;
|
||||
@@ -1840,7 +1823,7 @@ public final class SWF implements TreeItem, Timelined {
|
||||
}
|
||||
}
|
||||
}
|
||||
loopb:
|
||||
|
||||
for (final Tag t : tags) {
|
||||
if (t instanceof ShapeTag) {
|
||||
int characterID = 0;
|
||||
@@ -1884,6 +1867,50 @@ public final class SWF implements TreeItem, Timelined {
|
||||
return ret;
|
||||
}
|
||||
|
||||
//TODO: implement morphshape export. How to handle 65536 frames?
|
||||
public static List<File> exportMorphShapes(AbortRetryIgnoreHandler handler, String outdir, List<Tag> tags, final MorphshapeExportMode mode) throws IOException {
|
||||
List<File> ret = new ArrayList<>();
|
||||
if (tags.isEmpty()) {
|
||||
return ret;
|
||||
}
|
||||
File foutdir = new File(outdir);
|
||||
if (!foutdir.exists()) {
|
||||
if (!foutdir.mkdirs()) {
|
||||
if (!foutdir.exists()) {
|
||||
throw new IOException("Cannot create directory " + outdir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (final Tag t : tags) {
|
||||
if (t instanceof MorphShapeTag) {
|
||||
int characterID = 0;
|
||||
if (t instanceof CharacterTag) {
|
||||
characterID = ((CharacterTag) t).getCharacterId();
|
||||
}
|
||||
String ext = "svg";
|
||||
|
||||
final File file = new File(outdir + File.separator + characterID + "." + ext);
|
||||
new RetryTask(new RunnableIOEx() {
|
||||
@Override
|
||||
public void run() throws IOException {
|
||||
MorphShapeTag mst = (MorphShapeTag) t;
|
||||
switch (mode) {
|
||||
case SVG:
|
||||
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||
fos.write(Utf8Helper.getBytes(mst.toSVG()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}, handler).run();
|
||||
ret.add(file);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static List<File> exportBinaryData(AbortRetryIgnoreHandler handler, String outdir, List<Tag> tags, BinaryDataExportMode mode) throws IOException {
|
||||
List<File> ret = new ArrayList<>();
|
||||
if (tags.isEmpty()) {
|
||||
@@ -1897,7 +1924,7 @@ public final class SWF implements TreeItem, Timelined {
|
||||
}
|
||||
}
|
||||
}
|
||||
loopb:
|
||||
|
||||
for (final Tag t : tags) {
|
||||
if (t instanceof DefineBinaryDataTag) {
|
||||
int characterID = ((DefineBinaryDataTag) t).getCharacterId();
|
||||
@@ -1964,6 +1991,10 @@ public final class SWF implements TreeItem, Timelined {
|
||||
exportShapes(handler, outdir, tags, mode);
|
||||
}
|
||||
|
||||
public void exportMorphShapes(AbortRetryIgnoreHandler handler, String outdir, MorphshapeExportMode mode) throws IOException {
|
||||
exportMorphShapes(handler, outdir, tags, mode);
|
||||
}
|
||||
|
||||
public void exportBinaryData(AbortRetryIgnoreHandler handler, String outdir, BinaryDataExportMode mode) throws IOException {
|
||||
exportBinaryData(handler, outdir, tags, mode);
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ import java.util.List;
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class BitmapExporter extends ShapeExporterBase implements IShapeExporter {
|
||||
public class BitmapExporter extends ShapeExporterBase {
|
||||
|
||||
private SerializableImage image;
|
||||
private Graphics2D graphics;
|
||||
@@ -94,7 +94,7 @@ public class BitmapExporter extends ShapeExporterBase implements IShapeExporter
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endShape(double xMin, double yMin, double xMax, double yMax) {
|
||||
public void endShape() {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.exporters;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class CurvedMorphEdge extends StraightMorphEdge implements IMorphEdge {
|
||||
|
||||
private final PointInt control;
|
||||
private final PointInt controlEnd;
|
||||
|
||||
CurvedMorphEdge(PointInt from, PointInt control, PointInt to,
|
||||
PointInt fromEnd, PointInt controlEnd, PointInt toEnd, int lineStyleIdx, int fillStyleIdx) {
|
||||
super(from, to, fromEnd, toEnd, lineStyleIdx, fillStyleIdx);
|
||||
this.control = control;
|
||||
this.controlEnd = controlEnd;
|
||||
}
|
||||
|
||||
public PointInt getControl() {
|
||||
return control;
|
||||
}
|
||||
|
||||
public PointInt getControlEnd() {
|
||||
return controlEnd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMorphEdge reverseWithNewFillStyle(int newFillStyleIdx) {
|
||||
return new CurvedMorphEdge(to, control, from, toEnd, controlEnd, fromEnd, lineStyleIdx, newFillStyleIdx);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.exporters;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
import com.jpexs.decompiler.flash.types.GRADRECORD;
|
||||
import com.jpexs.decompiler.flash.types.RGB;
|
||||
import com.jpexs.decompiler.flash.types.SHAPE;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS, Claus Wahlers
|
||||
*/
|
||||
public abstract class DefaultSVGMorphShapeExporter extends MorphShapeExporterBase {
|
||||
|
||||
protected static final String DRAW_COMMAND_L = "L";
|
||||
protected static final String DRAW_COMMAND_Q = "Q";
|
||||
|
||||
protected String currentDrawCommand = "";
|
||||
protected String pathData;
|
||||
protected String pathDataEnd;
|
||||
|
||||
public DefaultSVGMorphShapeExporter(SHAPE shape, SHAPE endShape, ColorTransform colorTransform) {
|
||||
super(shape, endShape, colorTransform);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginShape() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endShape() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginFills() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endFills() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginLines() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endLines() {
|
||||
finalizePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginFill(RGB color) {
|
||||
finalizePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginGradientFill(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) {
|
||||
finalizePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginBitmapFill(int bitmapId, Matrix matrix, boolean repeat, boolean smooth, ColorTransform colorTransform) {
|
||||
finalizePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endFill() {
|
||||
finalizePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lineStyle(double thickness, RGB color, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, int miterLimit) {
|
||||
finalizePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveTo(double x, double y, double x2, double y2) {
|
||||
currentDrawCommand = "";
|
||||
pathData += "M"
|
||||
+ roundPixels20(x / SWF.unitDivisor) + " "
|
||||
+ roundPixels20(y / SWF.unitDivisor) + " ";
|
||||
pathDataEnd += "M"
|
||||
+ roundPixels20(x2 / SWF.unitDivisor) + " "
|
||||
+ roundPixels20(y2 / SWF.unitDivisor) + " ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lineTo(double x, double y, double x2, double y2) {
|
||||
if (!currentDrawCommand.equals(DRAW_COMMAND_L)) {
|
||||
currentDrawCommand = DRAW_COMMAND_L;
|
||||
pathData += "L";
|
||||
pathDataEnd += "L";
|
||||
}
|
||||
pathData += roundPixels20(x / SWF.unitDivisor) + " "
|
||||
+ roundPixels20(y / SWF.unitDivisor) + " ";
|
||||
pathDataEnd += roundPixels20(x2 / SWF.unitDivisor) + " "
|
||||
+ roundPixels20(y2 / SWF.unitDivisor) + " ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void curveTo(double controlX, double controlY, double anchorX, double anchorY, double controlX2, double controlY2, double anchorX2, double anchorY2) {
|
||||
if (!currentDrawCommand.equals(DRAW_COMMAND_Q)) {
|
||||
currentDrawCommand = DRAW_COMMAND_Q;
|
||||
pathData += "Q";
|
||||
pathDataEnd += "Q";
|
||||
}
|
||||
pathData += roundPixels20(controlX / SWF.unitDivisor) + " "
|
||||
+ roundPixels20(controlY / SWF.unitDivisor) + " "
|
||||
+ roundPixels20(anchorX / SWF.unitDivisor) + " "
|
||||
+ roundPixels20(anchorY / SWF.unitDivisor) + " ";
|
||||
pathDataEnd += roundPixels20(controlX2 / SWF.unitDivisor) + " "
|
||||
+ roundPixels20(controlY2 / SWF.unitDivisor) + " "
|
||||
+ roundPixels20(anchorX2 / SWF.unitDivisor) + " "
|
||||
+ roundPixels20(anchorY2 / SWF.unitDivisor) + " ";
|
||||
}
|
||||
|
||||
protected void finalizePath() {
|
||||
pathData = "";
|
||||
pathDataEnd = "";
|
||||
currentDrawCommand = "";
|
||||
}
|
||||
|
||||
protected double roundPixels20(double pixels) {
|
||||
return Math.round(pixels * 100) / 100.0;
|
||||
}
|
||||
|
||||
protected double roundPixels400(double pixels) {
|
||||
return Math.round(pixels * 10000) / 10000.0;
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ import com.jpexs.decompiler.flash.types.SHAPE;
|
||||
*
|
||||
* @author JPEXS, Claus Wahlers
|
||||
*/
|
||||
public class DefaultSVGShapeExporter extends ShapeExporterBase implements IShapeExporter {
|
||||
public abstract class DefaultSVGShapeExporter extends ShapeExporterBase {
|
||||
|
||||
protected static final String DRAW_COMMAND_L = "L";
|
||||
protected static final String DRAW_COMMAND_Q = "Q";
|
||||
@@ -43,7 +43,7 @@ public class DefaultSVGShapeExporter extends ShapeExporterBase implements IShape
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endShape(double xMin, double yMin, double xMax, double yMax) {
|
||||
public void endShape() {
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -102,7 +102,7 @@ public class DefaultSVGShapeExporter extends ShapeExporterBase implements IShape
|
||||
|
||||
@Override
|
||||
public void lineTo(double x, double y) {
|
||||
if (currentDrawCommand != DRAW_COMMAND_L) {
|
||||
if (!currentDrawCommand.equals(DRAW_COMMAND_L)) {
|
||||
currentDrawCommand = DRAW_COMMAND_L;
|
||||
pathData += "L";
|
||||
}
|
||||
@@ -112,7 +112,7 @@ public class DefaultSVGShapeExporter extends ShapeExporterBase implements IShape
|
||||
|
||||
@Override
|
||||
public void curveTo(double controlX, double controlY, double anchorX, double anchorY) {
|
||||
if (currentDrawCommand != DRAW_COMMAND_Q) {
|
||||
if (!currentDrawCommand.equals(DRAW_COMMAND_Q)) {
|
||||
currentDrawCommand = DRAW_COMMAND_Q;
|
||||
pathData += "Q";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.exporters;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface IMorphEdge {
|
||||
|
||||
public PointInt getFrom();
|
||||
|
||||
public PointInt getTo();
|
||||
|
||||
public PointInt getFromEnd();
|
||||
|
||||
public PointInt getToEnd();
|
||||
|
||||
public int getLineStyleIdx();
|
||||
|
||||
public int getFillStyleIdx();
|
||||
|
||||
public IMorphEdge reverseWithNewFillStyle(int newFillStyleIdx);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.exporters;
|
||||
|
||||
import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
import com.jpexs.decompiler.flash.types.GRADRECORD;
|
||||
import com.jpexs.decompiler.flash.types.RGB;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface IMorphShapeExporter {
|
||||
|
||||
public void beginShape();
|
||||
|
||||
public void endShape();
|
||||
|
||||
public void beginFills();
|
||||
|
||||
public void endFills();
|
||||
|
||||
public void beginLines();
|
||||
|
||||
public void endLines();
|
||||
|
||||
public void beginFill(RGB color);
|
||||
|
||||
public void beginGradientFill(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio);
|
||||
|
||||
public void beginBitmapFill(int bitmapId, Matrix matrix, boolean repeat, boolean smooth, ColorTransform colorTransform);
|
||||
|
||||
public void endFill();
|
||||
|
||||
public void lineStyle(double thickness, RGB color, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, int miterLimit);
|
||||
|
||||
public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio);
|
||||
|
||||
public void moveTo(double x, double y, double x2, double y2);
|
||||
|
||||
public void lineTo(double x, double y, double x2, double y2);
|
||||
|
||||
public void curveTo(double controlX, double controlY, double anchorX, double anchorY, double controlX2, double controlY2, double anchorX2, double anchorY2);
|
||||
}
|
||||
@@ -28,7 +28,7 @@ public interface IShapeExporter {
|
||||
|
||||
public void beginShape();
|
||||
|
||||
public void endShape(double xMin, double yMin, double xMax, double yMax);
|
||||
public void endShape();
|
||||
|
||||
public void beginFills();
|
||||
|
||||
|
||||
@@ -0,0 +1,546 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.exporters;
|
||||
|
||||
import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
import com.jpexs.decompiler.flash.types.FILLSTYLE;
|
||||
import com.jpexs.decompiler.flash.types.FOCALGRADIENT;
|
||||
import com.jpexs.decompiler.flash.types.LINESTYLE;
|
||||
import com.jpexs.decompiler.flash.types.LINESTYLE2;
|
||||
import com.jpexs.decompiler.flash.types.RGB;
|
||||
import com.jpexs.decompiler.flash.types.SHAPE;
|
||||
import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord;
|
||||
import java.awt.Color;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS, Claus Wahlers
|
||||
*/
|
||||
public abstract class MorphShapeExporterBase implements IMorphShapeExporter {
|
||||
|
||||
protected final SHAPE shape;
|
||||
protected final SHAPE shapeEnd;
|
||||
|
||||
protected List<FILLSTYLE> _fillStyles;
|
||||
protected List<LINESTYLE> _lineStyles;
|
||||
|
||||
protected List<FILLSTYLE> _fillStylesEnd;
|
||||
protected List<LINESTYLE> _lineStylesEnd;
|
||||
|
||||
protected List<Map<Integer, List<IMorphEdge>>> _fillEdgeMaps;
|
||||
protected List<Map<Integer, List<IMorphEdge>>> _lineEdgeMaps;
|
||||
|
||||
private boolean edgeMapsCreated;
|
||||
protected ColorTransform colorTransform;
|
||||
|
||||
public MorphShapeExporterBase(SHAPE shape, SHAPE endShape, ColorTransform colorTransform) {
|
||||
this.shape = shape;
|
||||
this.shapeEnd = endShape;
|
||||
this.colorTransform = colorTransform;
|
||||
_fillStyles = new ArrayList<>();
|
||||
_lineStyles = new ArrayList<>();
|
||||
if (shape instanceof SHAPEWITHSTYLE) {
|
||||
SHAPEWITHSTYLE shapeWithStyle = (SHAPEWITHSTYLE) shape;
|
||||
_fillStyles.addAll(Arrays.asList(shapeWithStyle.fillStyles.fillStyles));
|
||||
_lineStyles.addAll(Arrays.asList(shapeWithStyle.lineStyles.lineStyles));
|
||||
}
|
||||
_fillStylesEnd = new ArrayList<>();
|
||||
_lineStylesEnd = new ArrayList<>();
|
||||
if (endShape instanceof SHAPEWITHSTYLE) {
|
||||
SHAPEWITHSTYLE shapeWithStyle = (SHAPEWITHSTYLE) endShape;
|
||||
_fillStylesEnd.addAll(Arrays.asList(shapeWithStyle.fillStyles.fillStyles));
|
||||
_lineStylesEnd.addAll(Arrays.asList(shapeWithStyle.lineStyles.lineStyles));
|
||||
}
|
||||
}
|
||||
|
||||
public void export() {
|
||||
// Create edge maps
|
||||
_fillEdgeMaps = new ArrayList<>();
|
||||
_lineEdgeMaps = new ArrayList<>();
|
||||
createEdgeMaps(_fillStyles, _lineStyles, _fillEdgeMaps, _lineEdgeMaps);
|
||||
|
||||
// Let the doc handler know that a shape export starts
|
||||
beginShape();
|
||||
// Export fills and strokes for each group separately
|
||||
for (int i = 0; i < _lineEdgeMaps.size(); i++) {
|
||||
// Export fills first
|
||||
exportFillPath(i);
|
||||
// Export strokes last
|
||||
exportLinePath(i);
|
||||
}
|
||||
// Let the doc handler know that we're done exporting a shape
|
||||
endShape();
|
||||
}
|
||||
|
||||
protected void createEdgeMaps(List<FILLSTYLE> fillStyles, List<LINESTYLE> lineStyles,
|
||||
List<Map<Integer, List<IMorphEdge>>> fillEdgeMaps, List<Map<Integer, List<IMorphEdge>>> lineEdgeMaps) {
|
||||
if (!edgeMapsCreated) {
|
||||
int xPos = 0;
|
||||
int yPos = 0;
|
||||
int xPosEnd = 0;
|
||||
int yPosEnd = 0;
|
||||
int fillStyleIdxOffset = 0;
|
||||
int lineStyleIdxOffset = 0;
|
||||
int currentFillStyleIdx0 = 0;
|
||||
int currentFillStyleIdx1 = 0;
|
||||
int currentLineStyleIdx = 0;
|
||||
List<IMorphEdge> subPath = new ArrayList<>();
|
||||
Map<Integer, List<IMorphEdge>> currentFillEdgeMap = new HashMap<>();
|
||||
Map<Integer, List<IMorphEdge>> currentLineEdgeMap = new HashMap<>();
|
||||
List<SHAPERECORD> records = shape.shapeRecords;
|
||||
List<SHAPERECORD> recordsEnd = shapeEnd.shapeRecords;
|
||||
if (records.size() != recordsEnd.size()) {
|
||||
throw new Error("Begin and end shaperecord list length should be the same.");
|
||||
}
|
||||
for (int i = 0; i < records.size(); i++) {
|
||||
SHAPERECORD shapeRecord = records.get(i);
|
||||
SHAPERECORD shapeRecordEnd = recordsEnd.get(i);
|
||||
if ((shapeRecord instanceof StyleChangeRecord && !(shapeRecordEnd instanceof StyleChangeRecord)) ||
|
||||
(shapeRecord instanceof StraightEdgeRecord && !(shapeRecordEnd instanceof StraightEdgeRecord)) ||
|
||||
(shapeRecord instanceof CurvedEdgeRecord && !(shapeRecordEnd instanceof CurvedEdgeRecord)) ||
|
||||
(shapeRecord instanceof EndShapeRecord && !(shapeRecordEnd instanceof EndShapeRecord))) {
|
||||
throw new Error("Begin and end shaperecord should have the same type.");
|
||||
}
|
||||
if (shapeRecord instanceof StyleChangeRecord) {
|
||||
StyleChangeRecord styleChangeRecord = (StyleChangeRecord) shapeRecord;
|
||||
if (styleChangeRecord.stateLineStyle || styleChangeRecord.stateFillStyle0 || styleChangeRecord.stateFillStyle1) {
|
||||
processSubPath(subPath, currentLineStyleIdx, currentFillStyleIdx0, currentFillStyleIdx1, currentFillEdgeMap, currentLineEdgeMap);
|
||||
subPath = new ArrayList<>();
|
||||
}
|
||||
if (styleChangeRecord.stateNewStyles) {
|
||||
fillStyleIdxOffset = fillStyles.size();
|
||||
lineStyleIdxOffset = lineStyles.size();
|
||||
appendFillStyles(fillStyles, styleChangeRecord.fillStyles.fillStyles);
|
||||
appendLineStyles(lineStyles, styleChangeRecord.lineStyles.lineStyles);
|
||||
}
|
||||
// Check if all styles are reset to 0.
|
||||
// This (probably) means that a new group starts with the next record
|
||||
if (styleChangeRecord.stateLineStyle && styleChangeRecord.lineStyle == 0
|
||||
&& styleChangeRecord.stateFillStyle0 && styleChangeRecord.fillStyle0 == 0
|
||||
&& styleChangeRecord.stateFillStyle1 && styleChangeRecord.fillStyle1 == 0) {
|
||||
// do not clean the edges for morphshapes
|
||||
//cleanEdgeMap(currentFillEdgeMap);
|
||||
//cleanEdgeMap(currentLineEdgeMap);
|
||||
fillEdgeMaps.add(currentFillEdgeMap);
|
||||
lineEdgeMaps.add(currentLineEdgeMap);
|
||||
currentFillEdgeMap = new HashMap<>();
|
||||
currentLineEdgeMap = new HashMap<>();
|
||||
currentLineStyleIdx = 0;
|
||||
currentFillStyleIdx0 = 0;
|
||||
currentFillStyleIdx1 = 0;
|
||||
} else {
|
||||
if (styleChangeRecord.stateLineStyle) {
|
||||
currentLineStyleIdx = styleChangeRecord.lineStyle;
|
||||
if (currentLineStyleIdx > 0) {
|
||||
currentLineStyleIdx += lineStyleIdxOffset;
|
||||
}
|
||||
}
|
||||
if (styleChangeRecord.stateFillStyle0) {
|
||||
currentFillStyleIdx0 = styleChangeRecord.fillStyle0;
|
||||
if (currentFillStyleIdx0 > 0) {
|
||||
currentFillStyleIdx0 += fillStyleIdxOffset;
|
||||
}
|
||||
}
|
||||
if (styleChangeRecord.stateFillStyle1) {
|
||||
currentFillStyleIdx1 = styleChangeRecord.fillStyle1;
|
||||
if (currentFillStyleIdx1 > 0) {
|
||||
currentFillStyleIdx1 += fillStyleIdxOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (styleChangeRecord.stateMoveTo) {
|
||||
xPos = styleChangeRecord.moveDeltaX;
|
||||
yPos = styleChangeRecord.moveDeltaY;
|
||||
}
|
||||
|
||||
StyleChangeRecord styleChangeRecordEnd = (StyleChangeRecord) shapeRecordEnd;
|
||||
if (styleChangeRecordEnd.stateMoveTo) {
|
||||
xPosEnd = styleChangeRecordEnd.moveDeltaX;
|
||||
yPosEnd = styleChangeRecordEnd.moveDeltaY;
|
||||
}
|
||||
} else if (shapeRecord instanceof StraightEdgeRecord) {
|
||||
StraightEdgeRecord straightEdgeRecord = (StraightEdgeRecord) shapeRecord;
|
||||
PointInt from = new PointInt(xPos, yPos);
|
||||
if (straightEdgeRecord.generalLineFlag) {
|
||||
xPos += straightEdgeRecord.deltaX;
|
||||
yPos += straightEdgeRecord.deltaY;
|
||||
} else {
|
||||
if (straightEdgeRecord.vertLineFlag) {
|
||||
yPos += straightEdgeRecord.deltaY;
|
||||
} else {
|
||||
xPos += straightEdgeRecord.deltaX;
|
||||
}
|
||||
}
|
||||
PointInt to = new PointInt(xPos, yPos);
|
||||
|
||||
StraightEdgeRecord straightEdgeRecordEnd = (StraightEdgeRecord) shapeRecordEnd;
|
||||
PointInt fromEnd = new PointInt(xPosEnd, yPosEnd);
|
||||
if (straightEdgeRecordEnd.generalLineFlag) {
|
||||
xPosEnd += straightEdgeRecordEnd.deltaX;
|
||||
yPosEnd += straightEdgeRecordEnd.deltaY;
|
||||
} else {
|
||||
if (straightEdgeRecordEnd.vertLineFlag) {
|
||||
yPosEnd += straightEdgeRecordEnd.deltaY;
|
||||
} else {
|
||||
xPosEnd += straightEdgeRecordEnd.deltaX;
|
||||
}
|
||||
}
|
||||
PointInt toEnd = new PointInt(xPosEnd, yPosEnd);
|
||||
|
||||
subPath.add(new StraightMorphEdge(from, to, fromEnd, toEnd, currentLineStyleIdx, currentFillStyleIdx1));
|
||||
} else if (shapeRecord instanceof CurvedEdgeRecord) {
|
||||
CurvedEdgeRecord curvedEdgeRecord = (CurvedEdgeRecord) shapeRecord;
|
||||
PointInt from = new PointInt(xPos, yPos);
|
||||
int xPosControl = xPos + curvedEdgeRecord.controlDeltaX;
|
||||
int yPosControl = yPos + curvedEdgeRecord.controlDeltaY;
|
||||
xPos = xPosControl + curvedEdgeRecord.anchorDeltaX;
|
||||
yPos = yPosControl + curvedEdgeRecord.anchorDeltaY;
|
||||
PointInt control = new PointInt(xPosControl, yPosControl);
|
||||
PointInt to = new PointInt(xPos, yPos);
|
||||
|
||||
CurvedEdgeRecord curvedEdgeRecordEnd = (CurvedEdgeRecord) shapeRecordEnd;
|
||||
PointInt fromEnd = new PointInt(xPosEnd, yPosEnd);
|
||||
int xPosControlEnd = xPosEnd + curvedEdgeRecordEnd.controlDeltaX;
|
||||
int yPosControlEnd = yPosEnd + curvedEdgeRecordEnd.controlDeltaY;
|
||||
xPosEnd = xPosControlEnd + curvedEdgeRecordEnd.anchorDeltaX;
|
||||
yPosEnd = yPosControlEnd + curvedEdgeRecordEnd.anchorDeltaY;
|
||||
PointInt controlEnd = new PointInt(xPosControlEnd, yPosControlEnd);
|
||||
PointInt toEnd = new PointInt(xPosEnd, yPosEnd);
|
||||
|
||||
subPath.add(new CurvedMorphEdge(from, control, to, fromEnd, controlEnd, toEnd, currentLineStyleIdx, currentFillStyleIdx1));
|
||||
} else if (shapeRecord instanceof EndShapeRecord) {
|
||||
// We're done. Process the last subpath, if any
|
||||
processSubPath(subPath, currentLineStyleIdx, currentFillStyleIdx0, currentFillStyleIdx1, currentFillEdgeMap, currentLineEdgeMap);
|
||||
// do not clean the edges for morphshapes
|
||||
//cleanEdgeMap(currentFillEdgeMap);
|
||||
//cleanEdgeMap(currentLineEdgeMap);
|
||||
fillEdgeMaps.add(currentFillEdgeMap);
|
||||
lineEdgeMaps.add(currentLineEdgeMap);
|
||||
}
|
||||
}
|
||||
edgeMapsCreated = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected void processSubPath(List<IMorphEdge> subPath, int lineStyleIdx, int fillStyleIdx0, int fillStyleIdx1,
|
||||
Map<Integer, List<IMorphEdge>> currentFillEdgeMap, Map<Integer, List<IMorphEdge>> currentLineEdgeMap) {
|
||||
List<IMorphEdge> path;
|
||||
if (fillStyleIdx0 != 0) {
|
||||
path = currentFillEdgeMap.get(fillStyleIdx0);
|
||||
if (path == null) {
|
||||
path = new ArrayList<>();
|
||||
currentFillEdgeMap.put(fillStyleIdx0, path);
|
||||
}
|
||||
for (int j = subPath.size() - 1; j >= 0; j--) {
|
||||
path.add(subPath.get(j).reverseWithNewFillStyle(fillStyleIdx0));
|
||||
}
|
||||
}
|
||||
if (fillStyleIdx1 != 0) {
|
||||
path = currentFillEdgeMap.get(fillStyleIdx1);
|
||||
if (path == null) {
|
||||
path = new ArrayList<>();
|
||||
currentFillEdgeMap.put(fillStyleIdx1, path);
|
||||
}
|
||||
appendEdges(path, subPath);
|
||||
}
|
||||
if (lineStyleIdx != 0) {
|
||||
path = currentLineEdgeMap.get(lineStyleIdx);
|
||||
if (path == null) {
|
||||
path = new ArrayList<>();
|
||||
currentLineEdgeMap.put(lineStyleIdx, path);
|
||||
}
|
||||
appendEdges(path, subPath);
|
||||
}
|
||||
}
|
||||
|
||||
protected void exportFillPath(int groupIndex) {
|
||||
List<IMorphEdge> path = createPathFromEdgeMap(_fillEdgeMaps.get(groupIndex));
|
||||
PointInt pos = new PointInt(Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||
int fillStyleIdx = Integer.MAX_VALUE;
|
||||
if (path.size() > 0) {
|
||||
beginFills();
|
||||
for (int i = 0; i < path.size(); i++) {
|
||||
IMorphEdge e = path.get(i);
|
||||
if (fillStyleIdx != e.getFillStyleIdx()) {
|
||||
if (fillStyleIdx != Integer.MAX_VALUE) {
|
||||
endFill();
|
||||
}
|
||||
fillStyleIdx = e.getFillStyleIdx();
|
||||
pos = new PointInt(Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||
try {
|
||||
Matrix matrix;
|
||||
FILLSTYLE fillStyle = _fillStyles.get(fillStyleIdx - 1);
|
||||
switch (fillStyle.fillStyleType) {
|
||||
case FILLSTYLE.SOLID:
|
||||
// Solid fill
|
||||
beginFill(colorTransform.apply(fillStyle.color));
|
||||
break;
|
||||
case FILLSTYLE.LINEAR_GRADIENT:
|
||||
case FILLSTYLE.RADIAL_GRADIENT:
|
||||
case FILLSTYLE.FOCAL_RADIAL_GRADIENT:
|
||||
// Gradient fill
|
||||
matrix = new Matrix(fillStyle.gradientMatrix);
|
||||
beginGradientFill(
|
||||
fillStyle.fillStyleType,
|
||||
colorTransform.apply(fillStyle.gradient.gradientRecords),
|
||||
matrix,
|
||||
fillStyle.gradient.spreadMode,
|
||||
fillStyle.gradient.interpolationMode,
|
||||
(fillStyle.gradient instanceof FOCALGRADIENT) ? ((FOCALGRADIENT) fillStyle.gradient).focalPoint : 0
|
||||
);
|
||||
break;
|
||||
case FILLSTYLE.REPEATING_BITMAP:
|
||||
case FILLSTYLE.CLIPPED_BITMAP:
|
||||
case FILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP:
|
||||
case FILLSTYLE.NON_SMOOTHED_CLIPPED_BITMAP:
|
||||
// Bitmap fill
|
||||
matrix = new Matrix(fillStyle.bitmapMatrix);
|
||||
beginBitmapFill(
|
||||
fillStyle.bitmapId,
|
||||
matrix,
|
||||
(fillStyle.fillStyleType == FILLSTYLE.REPEATING_BITMAP || fillStyle.fillStyleType == FILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP),
|
||||
(fillStyle.fillStyleType == FILLSTYLE.REPEATING_BITMAP || fillStyle.fillStyleType == FILLSTYLE.CLIPPED_BITMAP),
|
||||
colorTransform
|
||||
);
|
||||
break;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// Font shapes define no fillstyles per se, but do reference fillstyle index 1,
|
||||
// which represents the font color. We just report null in this case.
|
||||
beginFill(null);
|
||||
}
|
||||
}
|
||||
if (!pos.equals(e.getFrom())) {
|
||||
moveTo(e.getFrom().x, e.getFrom().y, e.getFromEnd().x, e.getFromEnd().y);
|
||||
}
|
||||
if (e instanceof CurvedMorphEdge) {
|
||||
CurvedMorphEdge c = (CurvedMorphEdge) e;
|
||||
curveTo(c.getControl().x, c.getControl().y, c.to.x, c.to.y, c.getControlEnd().x, c.getControlEnd().y, c.toEnd.x, c.toEnd.y);
|
||||
} else {
|
||||
lineTo(e.getTo().x, e.getTo().y, e.getToEnd().x, e.getToEnd().y);
|
||||
}
|
||||
pos = e.getTo();
|
||||
}
|
||||
if (fillStyleIdx != Integer.MAX_VALUE) {
|
||||
endFill();
|
||||
}
|
||||
endFills();
|
||||
}
|
||||
}
|
||||
|
||||
protected void exportLinePath(int groupIndex) {
|
||||
List<IMorphEdge> path = createPathFromEdgeMap(_lineEdgeMaps.get(groupIndex));
|
||||
PointInt pos = new PointInt(Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||
int lineStyleIdx = Integer.MAX_VALUE;
|
||||
LINESTYLE lineStyle;
|
||||
if (path.size() > 0) {
|
||||
beginLines();
|
||||
for (int i = 0; i < path.size(); i++) {
|
||||
IMorphEdge e = path.get(i);
|
||||
if (lineStyleIdx != e.getLineStyleIdx()) {
|
||||
lineStyleIdx = e.getLineStyleIdx();
|
||||
pos = new PointInt(Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||
try {
|
||||
lineStyle = _lineStyles.get(lineStyleIdx - 1);
|
||||
} catch (Exception ex) {
|
||||
lineStyle = null;
|
||||
}
|
||||
if (lineStyle != null) {
|
||||
String scaleMode = "NORMAL";
|
||||
boolean pixelHintingFlag = false;
|
||||
int startCapStyle = LINESTYLE2.ROUND_CAP;
|
||||
int endCapStyle = LINESTYLE2.ROUND_CAP;
|
||||
int joinStyle = LINESTYLE2.ROUND_JOIN;
|
||||
int miterLimitFactor = 3;
|
||||
boolean hasFillFlag = false;
|
||||
if (lineStyle instanceof LINESTYLE2) {
|
||||
LINESTYLE2 lineStyle2 = (LINESTYLE2) lineStyle;
|
||||
if (lineStyle2.noHScaleFlag && lineStyle2.noVScaleFlag) {
|
||||
scaleMode = "NONE";
|
||||
} else if (lineStyle2.noHScaleFlag) {
|
||||
scaleMode = "HORIZONTAL";
|
||||
} else if (lineStyle2.noVScaleFlag) {
|
||||
scaleMode = "VERTICAL";
|
||||
}
|
||||
pixelHintingFlag = lineStyle2.pixelHintingFlag;
|
||||
startCapStyle = lineStyle2.startCapStyle;
|
||||
endCapStyle = lineStyle2.endCapStyle;
|
||||
joinStyle = lineStyle2.joinStyle;
|
||||
miterLimitFactor = lineStyle2.miterLimitFactor;
|
||||
hasFillFlag = lineStyle2.hasFillFlag;
|
||||
}
|
||||
lineStyle(
|
||||
lineStyle.width,
|
||||
colorTransform.apply(lineStyle.color),
|
||||
pixelHintingFlag,
|
||||
scaleMode,
|
||||
startCapStyle,
|
||||
endCapStyle,
|
||||
joinStyle,
|
||||
miterLimitFactor);
|
||||
|
||||
if (hasFillFlag) {
|
||||
LINESTYLE2 lineStyle2 = (LINESTYLE2) lineStyle;
|
||||
FILLSTYLE fillStyle = lineStyle2.fillType;
|
||||
switch (fillStyle.fillStyleType) {
|
||||
case FILLSTYLE.LINEAR_GRADIENT:
|
||||
case FILLSTYLE.RADIAL_GRADIENT:
|
||||
case FILLSTYLE.FOCAL_RADIAL_GRADIENT:
|
||||
// Gradient fill
|
||||
Matrix matrix = new Matrix(fillStyle.gradientMatrix);
|
||||
lineGradientStyle(
|
||||
fillStyle.fillStyleType,
|
||||
fillStyle.gradient.gradientRecords,
|
||||
matrix,
|
||||
fillStyle.gradient.spreadMode,
|
||||
fillStyle.gradient.interpolationMode,
|
||||
(fillStyle.gradient instanceof FOCALGRADIENT) ? ((FOCALGRADIENT) fillStyle.gradient).focalPoint : 0
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We should never get here
|
||||
lineStyle(1, new RGB(Color.BLACK), false, "NORMAL", 0, 0, 0, 3);
|
||||
}
|
||||
}
|
||||
if (!e.getFrom().equals(pos)) {
|
||||
moveTo(e.getFrom().x, e.getFrom().y, e.getFromEnd().x, e.getFromEnd().y);
|
||||
}
|
||||
if (e instanceof CurvedMorphEdge) {
|
||||
CurvedMorphEdge c = (CurvedMorphEdge) e;
|
||||
curveTo(c.getControl().x, c.getControl().y, c.to.x, c.to.y, c.getControlEnd().x, c.getControlEnd().y, c.toEnd.x, c.toEnd.y);
|
||||
} else {
|
||||
lineTo(e.getTo().x, e.getTo().y, e.getToEnd().x, e.getToEnd().y);
|
||||
}
|
||||
pos = e.getTo();
|
||||
}
|
||||
endLines();
|
||||
}
|
||||
}
|
||||
|
||||
protected List<IMorphEdge> createPathFromEdgeMap(Map<Integer, List<IMorphEdge>> edgeMap) {
|
||||
List<IMorphEdge> newPath = new ArrayList<>();
|
||||
List<Integer> styleIdxArray = new ArrayList<>();
|
||||
for (Integer styleIdx : edgeMap.keySet()) {
|
||||
styleIdxArray.add(styleIdx);
|
||||
}
|
||||
Collections.sort(styleIdxArray);
|
||||
for (int i = 0; i < styleIdxArray.size(); i++) {
|
||||
appendEdges(newPath, edgeMap.get(styleIdxArray.get(i)));
|
||||
}
|
||||
return newPath;
|
||||
}
|
||||
|
||||
protected void cleanEdgeMap(Map<Integer, List<IMorphEdge>> edgeMap) {
|
||||
for (Integer styleIdx : edgeMap.keySet()) {
|
||||
List<IMorphEdge> subPath = edgeMap.get(styleIdx);
|
||||
if (subPath != null && subPath.size() > 0) {
|
||||
int idx;
|
||||
IMorphEdge prevEdge = null;
|
||||
List<IMorphEdge> tmpPath = new ArrayList<>();
|
||||
Map<String, List<IMorphEdge>> coordMap = createCoordMap(subPath);
|
||||
while (subPath.size() > 0) {
|
||||
idx = 0;
|
||||
while (idx < subPath.size()) {
|
||||
if (prevEdge == null || prevEdge.getTo().equals(subPath.get(idx).getFrom())) {
|
||||
IMorphEdge edge = subPath.remove(idx);
|
||||
tmpPath.add(edge);
|
||||
removeEdgeFromCoordMap(coordMap, edge);
|
||||
prevEdge = edge;
|
||||
} else {
|
||||
IMorphEdge edge = findNextEdgeInCoordMap(coordMap, prevEdge);
|
||||
if (edge != null) {
|
||||
idx = subPath.indexOf(edge);
|
||||
} else {
|
||||
idx = 0;
|
||||
prevEdge = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
edgeMap.put(styleIdx, tmpPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Map<String, List<IMorphEdge>> createCoordMap(List<IMorphEdge> path) {
|
||||
Map<String, List<IMorphEdge>> coordMap = new HashMap<>();
|
||||
for (int i = 0; i < path.size(); i++) {
|
||||
PointInt from = path.get(i).getFrom();
|
||||
String key = from.x + "_" + from.y;
|
||||
List<IMorphEdge> coordMapArray = coordMap.get(key);
|
||||
if (coordMapArray == null) {
|
||||
List<IMorphEdge> list = new ArrayList<>();
|
||||
list.add(path.get(i));
|
||||
coordMap.put(key, list);
|
||||
} else {
|
||||
coordMapArray.add(path.get(i));
|
||||
}
|
||||
}
|
||||
return coordMap;
|
||||
}
|
||||
|
||||
protected void removeEdgeFromCoordMap(Map<String, List<IMorphEdge>> coordMap, IMorphEdge edge) {
|
||||
String key = edge.getFrom().x + "_" + edge.getFrom().y;
|
||||
List<IMorphEdge> coordMapArray = coordMap.get(key);
|
||||
if (coordMapArray != null) {
|
||||
if (coordMapArray.size() == 1) {
|
||||
coordMap.remove(key);
|
||||
} else {
|
||||
int i = coordMapArray.indexOf(edge);
|
||||
if (i > -1) {
|
||||
coordMapArray.remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected IMorphEdge findNextEdgeInCoordMap(Map<String, List<IMorphEdge>> coordMap, IMorphEdge edge) {
|
||||
String key = edge.getTo().x + "_" + edge.getTo().y;
|
||||
List<IMorphEdge> coordMapArray = coordMap.get(key);
|
||||
if (coordMapArray != null && coordMapArray.size() > 0) {
|
||||
return coordMapArray.get(0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void appendFillStyles(List<FILLSTYLE> v1, FILLSTYLE[] v2) {
|
||||
v1.addAll(Arrays.asList(v2));
|
||||
}
|
||||
|
||||
protected void appendLineStyles(List<LINESTYLE> v1, LINESTYLE[] v2) {
|
||||
v1.addAll(Arrays.asList(v2));
|
||||
}
|
||||
|
||||
protected void appendEdges(List<IMorphEdge> v1, List<IMorphEdge> v2) {
|
||||
for (int i = 0; i < v2.size(); i++) {
|
||||
v1.add(v2.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,7 @@ public class PathExporter extends ShapeExporterBase {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endShape(double xMin, double yMin, double xMax, double yMax) {
|
||||
public void endShape() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,353 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.exporters;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
import com.jpexs.decompiler.flash.types.FILLSTYLE;
|
||||
import com.jpexs.decompiler.flash.types.GRADIENT;
|
||||
import com.jpexs.decompiler.flash.types.GRADRECORD;
|
||||
import com.jpexs.decompiler.flash.types.LINESTYLE2;
|
||||
import com.jpexs.decompiler.flash.types.RGB;
|
||||
import com.jpexs.decompiler.flash.types.RGBA;
|
||||
import com.jpexs.decompiler.flash.types.SHAPE;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import java.awt.Color;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.OutputKeys;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import org.w3c.dom.DOMImplementation;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.DocumentType;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS, Claus Wahlers
|
||||
*/
|
||||
public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter {
|
||||
|
||||
protected static final String sNamespace = "http://www.w3.org/2000/svg";
|
||||
protected static final String xlinkNamespace = "http://www.w3.org/1999/xlink";
|
||||
|
||||
protected Document _svg;
|
||||
protected Element _svgDefs;
|
||||
protected Element _svgG;
|
||||
protected Element path;
|
||||
protected List<Element> gradients;
|
||||
protected int lastPatternId;
|
||||
private final SWF swf;
|
||||
private double maxLineWidth;
|
||||
private final ExportRectangle bounds;
|
||||
|
||||
public SVGMorphShapeExporter(SWF swf, SHAPE shape, SHAPE endShape, ExportRectangle bounds, ColorTransform colorTransform) {
|
||||
super(shape, endShape, colorTransform);
|
||||
this.swf = swf;
|
||||
this.bounds = bounds;
|
||||
}
|
||||
|
||||
public String getSVG() {
|
||||
TransformerFactory transformerFactory = TransformerFactory.newInstance();
|
||||
StringWriter writer = new StringWriter();
|
||||
try {
|
||||
Transformer transformer = transformerFactory.newTransformer();
|
||||
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
||||
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
|
||||
DOMSource source = new DOMSource(_svg);
|
||||
StreamResult result = new StreamResult(writer);
|
||||
transformer.transform(source, result);
|
||||
} catch (TransformerException ex) {
|
||||
Logger.getLogger(SVGShapeExporter.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginShape() {
|
||||
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
|
||||
try {
|
||||
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
|
||||
DOMImplementation impl = docBuilder.getDOMImplementation();
|
||||
DocumentType svgDocType = impl.createDocumentType("svg", "-//W3C//DTD SVG 1.0//EN",
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd");
|
||||
_svg = impl.createDocument(sNamespace, "svg", svgDocType);
|
||||
Element svgRoot = _svg.getDocumentElement();
|
||||
svgRoot.setAttribute("xmlns:xlink", xlinkNamespace);
|
||||
_svgDefs = _svg.createElement("defs");
|
||||
svgRoot.appendChild(_svgDefs);
|
||||
_svgG = _svg.createElement("g");
|
||||
_svgG.setAttribute("transform", "matrix(1, 0, 0, 1, "
|
||||
+ roundPixels20(-bounds.xMin / (double) SWF.unitDivisor) + ", " + roundPixels20(-bounds.yMin / (double) SWF.unitDivisor) + ")");
|
||||
svgRoot.appendChild(_svgG);
|
||||
} catch (ParserConfigurationException ex) {
|
||||
Logger.getLogger(SVGShapeExporter.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
gradients = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginFill(RGB color) {
|
||||
if (color == null) {
|
||||
color = new RGB(Color.BLACK);
|
||||
}
|
||||
finalizePath();
|
||||
path.setAttribute("stroke", "none");
|
||||
path.setAttribute("fill", color.toHexRGB());
|
||||
if (color instanceof RGBA) {
|
||||
RGBA colorA = (RGBA) color;
|
||||
if (colorA.alpha != 255) {
|
||||
path.setAttribute("fill-opacity", Float.toString(colorA.getAlphaFloat()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginGradientFill(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) {
|
||||
finalizePath();
|
||||
Element gradient = (type == FILLSTYLE.LINEAR_GRADIENT)
|
||||
? _svg.createElement("linearGradient")
|
||||
: _svg.createElement("radialGradient");
|
||||
populateGradientElement(gradient, type, gradientRecords, matrix, spreadMethod, interpolationMethod, focalPointRatio);
|
||||
int id = gradients.indexOf(gradient);
|
||||
if (id < 0) {
|
||||
// todo: filter same gradients
|
||||
id = gradients.size();
|
||||
gradients.add(gradient);
|
||||
}
|
||||
gradient.setAttribute("id", "gradient" + id);
|
||||
path.setAttribute("stroke", "none");
|
||||
path.setAttribute("fill", "url(#gradient" + id + ")");
|
||||
_svgDefs.appendChild(gradient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginBitmapFill(int bitmapId, Matrix matrix, boolean repeat, boolean smooth, ColorTransform colorTransform) {
|
||||
finalizePath();
|
||||
ImageTag image = null;
|
||||
for (Tag t : swf.tags) {
|
||||
if (t instanceof ImageTag) {
|
||||
ImageTag i = (ImageTag) t;
|
||||
if (i.getCharacterId() == bitmapId) {
|
||||
image = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (image != null) {
|
||||
SerializableImage img = image.getImage();
|
||||
if (img != null) {
|
||||
colorTransform.apply(img);
|
||||
int width = img.getWidth();
|
||||
int height = img.getHeight();
|
||||
lastPatternId++;
|
||||
String patternId = "PatternID_" + lastPatternId;
|
||||
String format = image.getImageFormat();
|
||||
InputStream imageStream = image.getImageData();
|
||||
byte[] imageData;
|
||||
if (imageStream != null) {
|
||||
imageData = Helper.readStream(image.getImageData());
|
||||
} else {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try {
|
||||
ImageIO.write(img.getBufferedImage(), format.toUpperCase(Locale.ENGLISH), baos);
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
imageData = baos.toByteArray();
|
||||
}
|
||||
String base64ImgData = DatatypeConverter.printBase64Binary(imageData);
|
||||
path.setAttribute("style", "fill:url(#" + patternId + ")");
|
||||
Element pattern = _svg.createElement("pattern");
|
||||
pattern.setAttribute("id", patternId);
|
||||
pattern.setAttribute("patternUnits", "userSpaceOnUse");
|
||||
pattern.setAttribute("overflow", "visible");
|
||||
pattern.setAttribute("width", "" + width);
|
||||
pattern.setAttribute("height", "" + height);
|
||||
pattern.setAttribute("viewBox", "0 0 " + width + " " + height);
|
||||
if (matrix != null) {
|
||||
double translateX = roundPixels400(matrix.translateX / SWF.unitDivisor);
|
||||
double translateY = roundPixels400(matrix.translateY / SWF.unitDivisor);
|
||||
double rotateSkew0 = roundPixels400(matrix.rotateSkew0 / SWF.unitDivisor);
|
||||
double rotateSkew1 = roundPixels400(matrix.rotateSkew1 / SWF.unitDivisor);
|
||||
double scaleX = roundPixels400(matrix.scaleX / SWF.unitDivisor);
|
||||
double scaleY = roundPixels400(matrix.scaleY / SWF.unitDivisor);
|
||||
pattern.setAttribute("patternTransform", "matrix(" + scaleX + ", " + rotateSkew0
|
||||
+ ", " + rotateSkew1 + ", " + scaleY + ", " + translateX + ", " + translateY + ")");
|
||||
}
|
||||
Element imageElement = _svg.createElement("image");
|
||||
imageElement.setAttribute("width", "" + width);
|
||||
imageElement.setAttribute("height", "" + height);
|
||||
imageElement.setAttribute("xlink:href", "data:image/" + format + ";base64," + base64ImgData);
|
||||
pattern.appendChild(imageElement);
|
||||
_svgG.appendChild(pattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lineStyle(double thickness, RGB color, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, int miterLimit) {
|
||||
finalizePath();
|
||||
if (thickness > maxLineWidth) {
|
||||
maxLineWidth = thickness;
|
||||
}
|
||||
thickness /= SWF.unitDivisor;
|
||||
path.setAttribute("fill", "none");
|
||||
path.setAttribute("stroke", color.toHexRGB());
|
||||
path.setAttribute("stroke-width", Double.toString(thickness == 0 ? 1 : thickness));
|
||||
if (color instanceof RGBA) {
|
||||
RGBA colorA = (RGBA) color;
|
||||
if (colorA.alpha != 255) {
|
||||
path.setAttribute("stroke-opacity", Float.toString(colorA.getAlphaFloat()));
|
||||
}
|
||||
}
|
||||
switch (startCaps) {
|
||||
case LINESTYLE2.NO_CAP:
|
||||
path.setAttribute("stroke-linecap", "butt");
|
||||
break;
|
||||
case LINESTYLE2.SQUARE_CAP:
|
||||
path.setAttribute("stroke-linecap", "square");
|
||||
break;
|
||||
default:
|
||||
path.setAttribute("stroke-linecap", "round");
|
||||
break;
|
||||
}
|
||||
switch (joints) {
|
||||
case LINESTYLE2.BEVEL_JOIN:
|
||||
path.setAttribute("stroke-linejoin", "bevel");
|
||||
break;
|
||||
case LINESTYLE2.ROUND_JOIN:
|
||||
path.setAttribute("stroke-linejoin", "round");
|
||||
break;
|
||||
default:
|
||||
path.setAttribute("stroke-linejoin", "miter");
|
||||
if (miterLimit >= 1 && miterLimit != 4) {
|
||||
path.setAttribute("stroke-miterlimit", Integer.toString(miterLimit));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) {
|
||||
path.removeAttribute("stroke-opacity");
|
||||
Element gradient = (type == FILLSTYLE.LINEAR_GRADIENT)
|
||||
? _svg.createElement("linearGradient")
|
||||
: _svg.createElement("radialGradient");
|
||||
populateGradientElement(gradient, type, gradientRecords, matrix, spreadMethod, interpolationMethod, focalPointRatio);
|
||||
int id = gradients.indexOf(gradient);
|
||||
if (id < 0) {
|
||||
// todo: filter same gradients
|
||||
id = gradients.size();
|
||||
gradients.add(gradient);
|
||||
}
|
||||
gradient.setAttribute("id", "gradient" + id);
|
||||
path.setAttribute("stroke", "url(#gradient" + id + ")");
|
||||
path.setAttribute("fill", "none");
|
||||
_svgDefs.appendChild(gradient);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalizePath() {
|
||||
if (path != null && !"".equals(pathData)) {
|
||||
path.setAttribute("d", pathData.trim());
|
||||
Element animatePath = _svg.createElement("animate");
|
||||
animatePath.setAttribute("dur", "2s"); // todo
|
||||
animatePath.setAttribute("repeatCount", "indefinite");
|
||||
animatePath.setAttribute("attributeName", "d");
|
||||
animatePath.setAttribute("values", pathData.trim() + ";" + pathDataEnd.trim());
|
||||
path.appendChild(animatePath);
|
||||
_svgG.appendChild(path);
|
||||
}
|
||||
path = _svg.createElement("path");
|
||||
super.finalizePath();
|
||||
}
|
||||
|
||||
protected void populateGradientElement(Element gradient, int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) {
|
||||
gradient.setAttribute("gradientUnits", "userSpaceOnUse");
|
||||
if (type == FILLSTYLE.LINEAR_GRADIENT) {
|
||||
gradient.setAttribute("x1", "-819.2");
|
||||
gradient.setAttribute("x2", "819.2");
|
||||
} else {
|
||||
gradient.setAttribute("r", "819.2");
|
||||
gradient.setAttribute("cx", "0");
|
||||
gradient.setAttribute("cy", "0");
|
||||
if (focalPointRatio != 0) {
|
||||
gradient.setAttribute("fx", Double.toString(819.2 * focalPointRatio));
|
||||
gradient.setAttribute("fy", "0");
|
||||
}
|
||||
}
|
||||
switch (spreadMethod) {
|
||||
case GRADIENT.SPREAD_PAD_MODE:
|
||||
gradient.setAttribute("spreadMethod", "pad");
|
||||
break;
|
||||
case GRADIENT.SPREAD_REFLECT_MODE:
|
||||
gradient.setAttribute("spreadMethod", "reflect");
|
||||
break;
|
||||
case GRADIENT.SPREAD_REPEAT_MODE:
|
||||
gradient.setAttribute("spreadMethod", "repeat");
|
||||
break;
|
||||
}
|
||||
if (interpolationMethod == GRADIENT.INTERPOLATION_LINEAR_RGB_MODE) {
|
||||
gradient.setAttribute("color-interpolation", "linearRGB");
|
||||
}
|
||||
if (matrix != null) {
|
||||
double translateX = roundPixels400(matrix.translateX / SWF.unitDivisor);
|
||||
double translateY = roundPixels400(matrix.translateY / SWF.unitDivisor);
|
||||
double rotateSkew0 = roundPixels400(matrix.rotateSkew0);
|
||||
double rotateSkew1 = roundPixels400(matrix.rotateSkew1);
|
||||
double scaleX = roundPixels400(matrix.scaleX);
|
||||
double scaleY = roundPixels400(matrix.scaleY);
|
||||
gradient.setAttribute("gradientTransform", "matrix(" + scaleX + ", " + rotateSkew0
|
||||
+ ", " + rotateSkew1 + ", " + scaleY + ", " + translateX + ", " + translateY + ")");
|
||||
}
|
||||
for (int i = 0; i < gradientRecords.length; i++) {
|
||||
GRADRECORD record = gradientRecords[i];
|
||||
Element gradientEntry = _svg.createElement("stop");
|
||||
gradientEntry.setAttribute("offset", Double.toString(record.ratio / 255.0));
|
||||
RGB color = record.color;
|
||||
//if(colors.get(i) != 0) {
|
||||
gradientEntry.setAttribute("stop-color", color.toHexRGB());
|
||||
//}
|
||||
if (color instanceof RGBA) {
|
||||
RGBA colorA = (RGBA) color;
|
||||
if (colorA.alpha != 255) {
|
||||
gradientEntry.setAttribute("stop-opacity", Float.toString(colorA.getAlphaFloat()));
|
||||
}
|
||||
}
|
||||
gradient.appendChild(gradientEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,10 +72,12 @@ public class SVGShapeExporter extends DefaultSVGShapeExporter {
|
||||
protected int lastPatternId;
|
||||
private final SWF swf;
|
||||
private double maxLineWidth;
|
||||
private final ExportRectangle bounds;
|
||||
|
||||
public SVGShapeExporter(SWF swf, SHAPE shape, ColorTransform colorTransform) {
|
||||
public SVGShapeExporter(SWF swf, SHAPE shape, ExportRectangle bounds, ColorTransform colorTransform) {
|
||||
super(shape, colorTransform);
|
||||
this.swf = swf;
|
||||
this.bounds = bounds;
|
||||
}
|
||||
|
||||
public String getSVG() {
|
||||
@@ -103,6 +105,8 @@ public class SVGShapeExporter extends DefaultSVGShapeExporter {
|
||||
DocumentType svgDocType = impl.createDocumentType("svg", "-//W3C//DTD SVG 1.0//EN",
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd");
|
||||
_svg = impl.createDocument(sNamespace, "svg", svgDocType);
|
||||
_svgG.setAttribute("transform", "matrix(1, 0, 0, 1, "
|
||||
+ roundPixels20(-bounds.xMin / (double) SWF.unitDivisor) + ", " + roundPixels20(-bounds.yMin / (double) SWF.unitDivisor) + ")");
|
||||
Element svgRoot = _svg.getDocumentElement();
|
||||
svgRoot.setAttribute("xmlns:xlink", xlinkNamespace);
|
||||
_svgDefs = _svg.createElement("defs");
|
||||
@@ -115,16 +119,6 @@ public class SVGShapeExporter extends DefaultSVGShapeExporter {
|
||||
gradients = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endShape(double xMin, double yMin, double xMax, double yMax) {
|
||||
xMin /= SWF.unitDivisor;
|
||||
yMin /= SWF.unitDivisor;
|
||||
xMin -= maxLineWidth / SWF.unitDivisor;
|
||||
yMin -= maxLineWidth / SWF.unitDivisor;
|
||||
_svgG.setAttribute("transform", "matrix(1, 0, 0, 1, "
|
||||
+ roundPixels20(-xMin) + ", " + roundPixels20(-yMin) + ")");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginFill(RGB color) {
|
||||
if (color == null) {
|
||||
@@ -287,7 +281,7 @@ public class SVGShapeExporter extends DefaultSVGShapeExporter {
|
||||
|
||||
@Override
|
||||
protected void finalizePath() {
|
||||
if (path != null && pathData != "") {
|
||||
if (path != null && !"".equals(pathData)) {
|
||||
path.setAttribute("d", pathData.trim());
|
||||
_svgG.appendChild(path);
|
||||
}
|
||||
|
||||
@@ -48,13 +48,8 @@ public abstract class ShapeExporterBase implements IShapeExporter {
|
||||
protected List<FILLSTYLE> _fillStyles;
|
||||
protected List<LINESTYLE> _lineStyles;
|
||||
|
||||
protected List<Map<Integer, List<IEdge>>> fillEdgeMaps;
|
||||
protected List<Map<Integer, List<IEdge>>> lineEdgeMaps;
|
||||
protected Map<Integer, List<IEdge>> currentFillEdgeMap;
|
||||
protected Map<Integer, List<IEdge>> currentLineEdgeMap;
|
||||
private int numGroups;
|
||||
protected Map<String, List<IEdge>> coordMap;
|
||||
private final ExportRectangle bounds = new ExportRectangle(Double.MAX_VALUE, Double.MAX_VALUE, Double.MIN_VALUE, Double.MIN_VALUE);
|
||||
protected List<Map<Integer, List<IEdge>>> _fillEdgeMaps;
|
||||
protected List<Map<Integer, List<IEdge>>> _lineEdgeMaps;
|
||||
|
||||
private boolean edgeMapsCreated;
|
||||
protected ColorTransform colorTransform;
|
||||
@@ -73,21 +68,25 @@ public abstract class ShapeExporterBase implements IShapeExporter {
|
||||
|
||||
public void export() {
|
||||
// Create edge maps
|
||||
createEdgeMaps();
|
||||
_fillEdgeMaps = new ArrayList<>();
|
||||
_lineEdgeMaps = new ArrayList<>();
|
||||
createEdgeMaps(_fillStyles, _lineStyles, _fillEdgeMaps, _lineEdgeMaps);
|
||||
|
||||
// Let the doc handler know that a shape export starts
|
||||
beginShape();
|
||||
// Export fills and strokes for each group separately
|
||||
for (int i = 0; i < numGroups; i++) {
|
||||
for (int i = 0; i < _lineEdgeMaps.size(); i++) {
|
||||
// Export fills first
|
||||
exportFillPath(i);
|
||||
// Export strokes last
|
||||
exportLinePath(i);
|
||||
}
|
||||
// Let the doc handler know that we're done exporting a shape
|
||||
endShape(bounds.xMin, bounds.yMin, bounds.xMax, bounds.yMax);
|
||||
endShape();
|
||||
}
|
||||
|
||||
protected void createEdgeMaps() {
|
||||
protected void createEdgeMaps(List<FILLSTYLE> fillStyles, List<LINESTYLE> lineStyles,
|
||||
List<Map<Integer, List<IEdge>>> fillEdgeMaps, List<Map<Integer, List<IEdge>>> lineEdgeMaps) {
|
||||
if (!edgeMapsCreated) {
|
||||
int xPos = 0;
|
||||
int yPos = 0;
|
||||
@@ -97,25 +96,22 @@ public abstract class ShapeExporterBase implements IShapeExporter {
|
||||
int currentFillStyleIdx1 = 0;
|
||||
int currentLineStyleIdx = 0;
|
||||
List<IEdge> subPath = new ArrayList<>();
|
||||
numGroups = 0;
|
||||
fillEdgeMaps = new ArrayList<>();
|
||||
lineEdgeMaps = new ArrayList<>();
|
||||
currentFillEdgeMap = new HashMap<>();
|
||||
currentLineEdgeMap = new HashMap<>();
|
||||
Map<Integer, List<IEdge>> currentFillEdgeMap = new HashMap<>();
|
||||
Map<Integer, List<IEdge>> currentLineEdgeMap = new HashMap<>();
|
||||
List<SHAPERECORD> records = shape.shapeRecords;
|
||||
for (int i = 0; i < records.size(); i++) {
|
||||
SHAPERECORD shapeRecord = records.get(i);
|
||||
if (shapeRecord instanceof StyleChangeRecord) {
|
||||
StyleChangeRecord styleChangeRecord = (StyleChangeRecord) shapeRecord;
|
||||
if (styleChangeRecord.stateLineStyle || styleChangeRecord.stateFillStyle0 || styleChangeRecord.stateFillStyle1) {
|
||||
processSubPath(subPath, currentLineStyleIdx, currentFillStyleIdx0, currentFillStyleIdx1);
|
||||
processSubPath(subPath, currentLineStyleIdx, currentFillStyleIdx0, currentFillStyleIdx1, currentFillEdgeMap, currentLineEdgeMap);
|
||||
subPath = new ArrayList<>();
|
||||
}
|
||||
if (styleChangeRecord.stateNewStyles) {
|
||||
fillStyleIdxOffset = _fillStyles.size();
|
||||
lineStyleIdxOffset = _lineStyles.size();
|
||||
appendFillStyles(_fillStyles, styleChangeRecord.fillStyles.fillStyles);
|
||||
appendLineStyles(_lineStyles, styleChangeRecord.lineStyles.lineStyles);
|
||||
fillStyleIdxOffset = fillStyles.size();
|
||||
lineStyleIdxOffset = lineStyles.size();
|
||||
appendFillStyles(fillStyles, styleChangeRecord.fillStyles.fillStyles);
|
||||
appendLineStyles(lineStyles, styleChangeRecord.lineStyles.lineStyles);
|
||||
}
|
||||
// Check if all styles are reset to 0.
|
||||
// This (probably) means that a new group starts with the next record
|
||||
@@ -131,7 +127,6 @@ public abstract class ShapeExporterBase implements IShapeExporter {
|
||||
currentLineStyleIdx = 0;
|
||||
currentFillStyleIdx0 = 0;
|
||||
currentFillStyleIdx1 = 0;
|
||||
numGroups++;
|
||||
} else {
|
||||
if (styleChangeRecord.stateLineStyle) {
|
||||
currentLineStyleIdx = styleChangeRecord.lineStyle;
|
||||
@@ -183,19 +178,19 @@ public abstract class ShapeExporterBase implements IShapeExporter {
|
||||
subPath.add(new CurvedEdge(from, control, to, currentLineStyleIdx, currentFillStyleIdx1));
|
||||
} else if (shapeRecord instanceof EndShapeRecord) {
|
||||
// We're done. Process the last subpath, if any
|
||||
processSubPath(subPath, currentLineStyleIdx, currentFillStyleIdx0, currentFillStyleIdx1);
|
||||
processSubPath(subPath, currentLineStyleIdx, currentFillStyleIdx0, currentFillStyleIdx1, currentFillEdgeMap, currentLineEdgeMap);
|
||||
cleanEdgeMap(currentFillEdgeMap);
|
||||
cleanEdgeMap(currentLineEdgeMap);
|
||||
fillEdgeMaps.add(currentFillEdgeMap);
|
||||
lineEdgeMaps.add(currentLineEdgeMap);
|
||||
numGroups++;
|
||||
}
|
||||
}
|
||||
edgeMapsCreated = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected void processSubPath(List<IEdge> subPath, int lineStyleIdx, int fillStyleIdx0, int fillStyleIdx1) {
|
||||
protected void processSubPath(List<IEdge> subPath, int lineStyleIdx, int fillStyleIdx0, int fillStyleIdx1,
|
||||
Map<Integer, List<IEdge>> currentFillEdgeMap, Map<Integer, List<IEdge>> currentLineEdgeMap) {
|
||||
List<IEdge> path;
|
||||
if (fillStyleIdx0 != 0) {
|
||||
path = currentFillEdgeMap.get(fillStyleIdx0);
|
||||
@@ -225,42 +220,14 @@ public abstract class ShapeExporterBase implements IShapeExporter {
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateBound(IEdge edge) {
|
||||
PointInt from = edge.getFrom();
|
||||
PointInt to = edge.getTo();
|
||||
calculateBound(from);
|
||||
calculateBound(to);
|
||||
if (edge instanceof CurvedEdge) {
|
||||
CurvedEdge curvedEdge = (CurvedEdge) edge;
|
||||
PointInt control = curvedEdge.getControl();
|
||||
calculateBound(control);
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateBound(PointInt point) {
|
||||
if (point.x < bounds.xMin) {
|
||||
bounds.xMin = point.x;
|
||||
}
|
||||
if (point.x > bounds.xMax) {
|
||||
bounds.xMax = point.x;
|
||||
}
|
||||
if (point.y < bounds.yMin) {
|
||||
bounds.yMin = point.y;
|
||||
}
|
||||
if (point.y > bounds.yMax) {
|
||||
bounds.yMax = point.y;
|
||||
}
|
||||
}
|
||||
|
||||
protected void exportFillPath(int groupIndex) {
|
||||
List<IEdge> path = createPathFromEdgeMap(fillEdgeMaps.get(groupIndex));
|
||||
List<IEdge> path = createPathFromEdgeMap(_fillEdgeMaps.get(groupIndex));
|
||||
PointInt pos = new PointInt(Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||
int fillStyleIdx = Integer.MAX_VALUE;
|
||||
if (path.size() > 0) {
|
||||
beginFills();
|
||||
for (int i = 0; i < path.size(); i++) {
|
||||
IEdge e = path.get(i);
|
||||
calculateBound(e);
|
||||
if (fillStyleIdx != e.getFillStyleIdx()) {
|
||||
if (fillStyleIdx != Integer.MAX_VALUE) {
|
||||
endFill();
|
||||
@@ -329,7 +296,7 @@ public abstract class ShapeExporterBase implements IShapeExporter {
|
||||
}
|
||||
|
||||
protected void exportLinePath(int groupIndex) {
|
||||
List<IEdge> path = createPathFromEdgeMap(lineEdgeMaps.get(groupIndex));
|
||||
List<IEdge> path = createPathFromEdgeMap(_lineEdgeMaps.get(groupIndex));
|
||||
PointInt pos = new PointInt(Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||
int lineStyleIdx = Integer.MAX_VALUE;
|
||||
LINESTYLE lineStyle;
|
||||
@@ -337,7 +304,6 @@ public abstract class ShapeExporterBase implements IShapeExporter {
|
||||
beginLines();
|
||||
for (int i = 0; i < path.size(); i++) {
|
||||
IEdge e = path.get(i);
|
||||
calculateBound(e);
|
||||
if (lineStyleIdx != e.getLineStyleIdx()) {
|
||||
lineStyleIdx = e.getLineStyleIdx();
|
||||
pos = new PointInt(Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||
@@ -440,17 +406,17 @@ public abstract class ShapeExporterBase implements IShapeExporter {
|
||||
int idx;
|
||||
IEdge prevEdge = null;
|
||||
List<IEdge> tmpPath = new ArrayList<>();
|
||||
createCoordMap(subPath);
|
||||
Map<String, List<IEdge>> coordMap = createCoordMap(subPath);
|
||||
while (subPath.size() > 0) {
|
||||
idx = 0;
|
||||
while (idx < subPath.size()) {
|
||||
if (prevEdge == null || prevEdge.getTo().equals(subPath.get(idx).getFrom())) {
|
||||
IEdge edge = subPath.remove(idx);
|
||||
tmpPath.add(edge);
|
||||
removeEdgeFromCoordMap(edge);
|
||||
removeEdgeFromCoordMap(coordMap, edge);
|
||||
prevEdge = edge;
|
||||
} else {
|
||||
IEdge edge = findNextEdgeInCoordMap(prevEdge);
|
||||
IEdge edge = findNextEdgeInCoordMap(coordMap, prevEdge);
|
||||
if (edge != null) {
|
||||
idx = subPath.indexOf(edge);
|
||||
} else {
|
||||
@@ -465,8 +431,8 @@ public abstract class ShapeExporterBase implements IShapeExporter {
|
||||
}
|
||||
}
|
||||
|
||||
protected void createCoordMap(List<IEdge> path) {
|
||||
coordMap = new HashMap<>();
|
||||
protected Map<String, List<IEdge>> createCoordMap(List<IEdge> path) {
|
||||
Map<String, List<IEdge>> coordMap = new HashMap<>();
|
||||
for (int i = 0; i < path.size(); i++) {
|
||||
PointInt from = path.get(i).getFrom();
|
||||
String key = from.x + "_" + from.y;
|
||||
@@ -479,9 +445,10 @@ public abstract class ShapeExporterBase implements IShapeExporter {
|
||||
coordMapArray.add(path.get(i));
|
||||
}
|
||||
}
|
||||
return coordMap;
|
||||
}
|
||||
|
||||
protected void removeEdgeFromCoordMap(IEdge edge) {
|
||||
protected void removeEdgeFromCoordMap(Map<String, List<IEdge>> coordMap, IEdge edge) {
|
||||
String key = edge.getFrom().x + "_" + edge.getFrom().y;
|
||||
List<IEdge> coordMapArray = coordMap.get(key);
|
||||
if (coordMapArray != null) {
|
||||
@@ -496,7 +463,7 @@ public abstract class ShapeExporterBase implements IShapeExporter {
|
||||
}
|
||||
}
|
||||
|
||||
protected IEdge findNextEdgeInCoordMap(IEdge edge) {
|
||||
protected IEdge findNextEdgeInCoordMap(Map<String, List<IEdge>> coordMap, IEdge edge) {
|
||||
String key = edge.getTo().x + "_" + edge.getTo().y;
|
||||
List<IEdge> coordMapArray = coordMap.get(key);
|
||||
if (coordMapArray != null && coordMapArray.size() > 0) {
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.exporters;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class StraightMorphEdge implements IMorphEdge {
|
||||
|
||||
protected final PointInt from;
|
||||
protected final PointInt to;
|
||||
protected final PointInt fromEnd;
|
||||
protected final PointInt toEnd;
|
||||
protected final int lineStyleIdx;
|
||||
private final int fillStyleIdx;
|
||||
|
||||
StraightMorphEdge(PointInt from, PointInt to, PointInt fromEnd, PointInt toEnd, int lineStyleIdx, int fillStyleIdx) {
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.fromEnd = fromEnd;
|
||||
this.toEnd = toEnd;
|
||||
this.lineStyleIdx = lineStyleIdx;
|
||||
this.fillStyleIdx = fillStyleIdx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PointInt getFrom() {
|
||||
return from;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PointInt getTo() {
|
||||
return to;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PointInt getFromEnd() {
|
||||
return fromEnd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PointInt getToEnd() {
|
||||
return toEnd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLineStyleIdx() {
|
||||
return lineStyleIdx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFillStyleIdx() {
|
||||
return fillStyleIdx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMorphEdge reverseWithNewFillStyle(int newFillStyleIdx) {
|
||||
return new StraightMorphEdge(to, from, toEnd, fromEnd, lineStyleIdx, newFillStyleIdx);
|
||||
}
|
||||
}
|
||||
@@ -22,8 +22,9 @@ package com.jpexs.decompiler.flash.exporters.modes;
|
||||
*/
|
||||
public enum MorphshapeExportMode {
|
||||
|
||||
//TODO: implement morphshape export
|
||||
PNG,
|
||||
GIF,
|
||||
AVI
|
||||
//TODO: implement other morphshape export modes
|
||||
SVG
|
||||
//PNG,
|
||||
//GIF,
|
||||
//AVI
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.exporters.modes.BinaryDataExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.FontExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.FramesExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ImageExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.MorphshapeExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.MovieExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ShapeExportMode;
|
||||
@@ -31,6 +32,7 @@ import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
|
||||
import com.jpexs.decompiler.flash.tags.DefineVideoStreamTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.FontTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.MorphShapeTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.SoundTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.TextTag;
|
||||
@@ -68,8 +70,8 @@ public class ExportDialog extends AppDialog {
|
||||
"scripts",
|
||||
"binaryData",
|
||||
"frames",
|
||||
"fonts"
|
||||
//,"morphshapes"
|
||||
"fonts",
|
||||
"morphshapes"
|
||||
};
|
||||
|
||||
//Display options only when these classes found
|
||||
@@ -82,8 +84,8 @@ public class ExportDialog extends AppDialog {
|
||||
{TreeNode.class, ScriptPack.class},
|
||||
{DefineBinaryDataTag.class},
|
||||
{FrameNodeItem.class},
|
||||
{FontTag.class}
|
||||
//,{MorphShapeTag.class}
|
||||
{FontTag.class},
|
||||
{MorphShapeTag.class}
|
||||
};
|
||||
|
||||
//Enum classes for values
|
||||
@@ -96,8 +98,8 @@ public class ExportDialog extends AppDialog {
|
||||
ScriptExportMode.class,
|
||||
BinaryDataExportMode.class,
|
||||
FramesExportMode.class,
|
||||
FontExportMode.class
|
||||
//MorphshapeExportMode.class
|
||||
FontExportMode.class,
|
||||
MorphshapeExportMode.class
|
||||
};
|
||||
|
||||
private final JComboBox[] combos;
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.jpexs.decompiler.flash.exporters.modes.BinaryDataExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.FontExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.FramesExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ImageExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.MorphshapeExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.MovieExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ShapeExportMode;
|
||||
@@ -234,7 +235,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
|
||||
|
||||
// play morph shape in 2 second(s)
|
||||
// this settings should be synchronized with frameCount and frameRate
|
||||
// settings in Mainpanel.createAndShowTempSwf
|
||||
// settings in MainPanel.createAndShowTempSwf
|
||||
static final int morphShapeAnimationLength = 2;
|
||||
|
||||
static final int morphShapeAnimationFrameRate = 30;
|
||||
@@ -1138,6 +1139,9 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
|
||||
if (nodeType == TreeNodeType.SHAPE) {
|
||||
ret.add((Tag) n.getItem());
|
||||
}
|
||||
if (nodeType == TreeNodeType.MORPH_SHAPE) {
|
||||
ret.add((Tag) n.getItem());
|
||||
}
|
||||
if (nodeType == TreeNodeType.AS) {
|
||||
ret.add(n);
|
||||
}
|
||||
@@ -1183,6 +1187,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
|
||||
List<ScriptPack> as3scripts = new ArrayList<>();
|
||||
List<Tag> images = new ArrayList<>();
|
||||
List<Tag> shapes = new ArrayList<>();
|
||||
List<Tag> morphshapes = new ArrayList<>();
|
||||
List<Tag> movies = new ArrayList<>();
|
||||
List<Tag> sounds = new ArrayList<>();
|
||||
List<Tag> texts = new ArrayList<>();
|
||||
@@ -1204,6 +1209,9 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
|
||||
if (nodeType == TreeNodeType.SHAPE) {
|
||||
shapes.add((Tag) n.getItem());
|
||||
}
|
||||
if (nodeType == TreeNodeType.MORPH_SHAPE) {
|
||||
morphshapes.add((Tag) n.getItem());
|
||||
}
|
||||
if (nodeType == TreeNodeType.AS) {
|
||||
as12scripts.add(n);
|
||||
}
|
||||
@@ -1258,6 +1266,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
|
||||
final ScriptExportMode scriptMode = export.getValue(ScriptExportMode.class);
|
||||
ret.addAll(swf.exportImages(handler, selFile + File.separator + "images", images, export.getValue(ImageExportMode.class)));
|
||||
ret.addAll(SWF.exportShapes(handler, selFile + File.separator + "shapes", shapes, export.getValue(ShapeExportMode.class)));
|
||||
ret.addAll(SWF.exportMorphShapes(handler, selFile + File.separator + "morphshapes", morphshapes, export.getValue(MorphshapeExportMode.class)));
|
||||
ret.addAll(swf.exportTexts(handler, selFile + File.separator + "texts", texts, export.getValue(TextExportMode.class)));
|
||||
ret.addAll(swf.exportMovies(handler, selFile + File.separator + "movies", movies, export.getValue(MovieExportMode.class)));
|
||||
ret.addAll(swf.exportSounds(handler, selFile + File.separator + "sounds", sounds, export.getValue(SoundExportMode.class)));
|
||||
@@ -1666,6 +1675,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
|
||||
} else {
|
||||
swf.exportImages(errorHandler, selFile + File.separator + "images", export.getValue(ImageExportMode.class));
|
||||
swf.exportShapes(errorHandler, selFile + File.separator + "shapes", export.getValue(ShapeExportMode.class));
|
||||
swf.exportMorphShapes(errorHandler, selFile + File.separator + "morphshapes", export.getValue(MorphshapeExportMode.class));
|
||||
swf.exportTexts(errorHandler, selFile + File.separator + "texts", export.getValue(TextExportMode.class));
|
||||
swf.exportMovies(errorHandler, selFile + File.separator + "movies", export.getValue(MovieExportMode.class));
|
||||
swf.exportSounds(errorHandler, selFile + File.separator + "sounds", export.getValue(SoundExportMode.class));
|
||||
|
||||
@@ -50,6 +50,7 @@ button.cancel = Cancel
|
||||
|
||||
morphshapes = Morphshapes
|
||||
morphshapes.gif = GIF
|
||||
morphshapes.svg = SVG
|
||||
|
||||
frames = Frames
|
||||
frames.png = PNG
|
||||
|
||||
@@ -20,8 +20,10 @@ import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.exporters.BitmapExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.ExportRectangle;
|
||||
import com.jpexs.decompiler.flash.exporters.Matrix;
|
||||
import com.jpexs.decompiler.flash.exporters.Point;
|
||||
import com.jpexs.decompiler.flash.exporters.SVGMorphShapeExporter;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.DrawableTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.MorphShapeTag;
|
||||
@@ -96,6 +98,16 @@ public class DefineMorphShape2Tag extends CharacterTag implements MorphShapeTag,
|
||||
return rect;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toSVG() {
|
||||
ExportRectangle rect = new ExportRectangle(getRect());
|
||||
SHAPEWITHSTYLE beginShapes = getShapeAtRatio(0);
|
||||
SHAPEWITHSTYLE endShapes = getShapeAtRatio(65535);
|
||||
SVGMorphShapeExporter exporter = new SVGMorphShapeExporter(swf, beginShapes, endShapes, rect, new ColorTransform() /*FIXME?*/);
|
||||
exporter.export();
|
||||
return exporter.getSVG();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCharacterId() {
|
||||
return characterId;
|
||||
|
||||
@@ -20,8 +20,10 @@ import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.exporters.BitmapExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.ExportRectangle;
|
||||
import com.jpexs.decompiler.flash.exporters.Matrix;
|
||||
import com.jpexs.decompiler.flash.exporters.Point;
|
||||
import com.jpexs.decompiler.flash.exporters.SVGMorphShapeExporter;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.DrawableTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.MorphShapeTag;
|
||||
@@ -144,6 +146,16 @@ public class DefineMorphShapeTag extends CharacterTag implements MorphShapeTag,
|
||||
return rect;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toSVG() {
|
||||
ExportRectangle rect = new ExportRectangle(getRect());
|
||||
SHAPEWITHSTYLE beginShapes = getShapeAtRatio(0);
|
||||
SHAPEWITHSTYLE endShapes = getShapeAtRatio(65535);
|
||||
SVGMorphShapeExporter exporter = new SVGMorphShapeExporter(swf, beginShapes, endShapes, rect, new ColorTransform() /*FIXME?*/);
|
||||
exporter.export();
|
||||
return exporter.getSVG();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getStartBounds() {
|
||||
return startBounds;
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.exporters.ExportRectangle;
|
||||
import com.jpexs.decompiler.flash.exporters.Point;
|
||||
import com.jpexs.decompiler.flash.exporters.SVGShapeExporter;
|
||||
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
|
||||
@@ -60,7 +61,8 @@ public class DefineShape2Tag extends ShapeTag {
|
||||
|
||||
@Override
|
||||
public String toSVG() {
|
||||
SVGShapeExporter exporter = new SVGShapeExporter(swf, getShapes(), new ColorTransform() /*FIXME?*/);
|
||||
ExportRectangle rect = new ExportRectangle(getRect());
|
||||
SVGShapeExporter exporter = new SVGShapeExporter(swf, getShapes(), rect, new ColorTransform() /*FIXME?*/);
|
||||
exporter.export();
|
||||
return exporter.getSVG();
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.exporters.ExportRectangle;
|
||||
import com.jpexs.decompiler.flash.exporters.Point;
|
||||
import com.jpexs.decompiler.flash.exporters.SVGShapeExporter;
|
||||
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
|
||||
@@ -65,7 +66,8 @@ public class DefineShape3Tag extends ShapeTag {
|
||||
|
||||
@Override
|
||||
public String toSVG() {
|
||||
SVGShapeExporter exporter = new SVGShapeExporter(swf, getShapes(), new ColorTransform() /*FIXME?*/);
|
||||
ExportRectangle rect = new ExportRectangle(getRect());
|
||||
SVGShapeExporter exporter = new SVGShapeExporter(swf, getShapes(), rect, new ColorTransform() /*FIXME?*/);
|
||||
exporter.export();
|
||||
return exporter.getSVG();
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.exporters.ExportRectangle;
|
||||
import com.jpexs.decompiler.flash.exporters.Point;
|
||||
import com.jpexs.decompiler.flash.exporters.SVGShapeExporter;
|
||||
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
|
||||
@@ -68,7 +69,8 @@ public class DefineShape4Tag extends ShapeTag {
|
||||
|
||||
@Override
|
||||
public String toSVG() {
|
||||
SVGShapeExporter exporter = new SVGShapeExporter(swf, getShapes(), new ColorTransform() /*FIXME?*/);
|
||||
ExportRectangle rect = new ExportRectangle(getRect());
|
||||
SVGShapeExporter exporter = new SVGShapeExporter(swf, getShapes(), rect, new ColorTransform() /*FIXME?*/);
|
||||
exporter.export();
|
||||
return exporter.getSVG();
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash.tags;
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.exporters.ExportRectangle;
|
||||
import com.jpexs.decompiler.flash.exporters.Point;
|
||||
import com.jpexs.decompiler.flash.exporters.SVGShapeExporter;
|
||||
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
|
||||
@@ -93,7 +94,8 @@ public class DefineShapeTag extends ShapeTag {
|
||||
|
||||
@Override
|
||||
public String toSVG() {
|
||||
SVGShapeExporter exporter = new SVGShapeExporter(swf, getShapes(), new ColorTransform() /*FIXME?*/);
|
||||
ExportRectangle rect = new ExportRectangle(getRect());
|
||||
SVGShapeExporter exporter = new SVGShapeExporter(swf, getShapes(), rect, new ColorTransform() /*FIXME?*/);
|
||||
exporter.export();
|
||||
return exporter.getSVG();
|
||||
}
|
||||
|
||||
@@ -40,6 +40,8 @@ public interface MorphShapeTag {
|
||||
|
||||
public SHAPE getEndEdges();
|
||||
|
||||
public abstract String toSVG();
|
||||
|
||||
public int getShapeNum();
|
||||
|
||||
public SHAPEWITHSTYLE getShapeAtRatio(int ratio);
|
||||
|
||||
Reference in New Issue
Block a user