mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-06-07 08:16:31 +00:00
Added Replacing morphshapes (currently only same shape for start/end)
Fixed miterLimitFactor is FIXED8 value in MORPHLINESTYLE2
This commit is contained in:
@@ -3221,7 +3221,7 @@ public class SWFInputStream implements AutoCloseable {
|
||||
ret.noClose = (int) readUB(1, "noClose") == 1;
|
||||
ret.endCapStyle = (int) readUB(2, "endCapStyle");
|
||||
if (ret.joinStyle == LINESTYLE2.MITER_JOIN) {
|
||||
ret.miterLimitFactor = readUI16("miterLimitFactor");
|
||||
ret.miterLimitFactor = readFIXED8("miterLimitFactor");
|
||||
}
|
||||
if (!ret.hasFillFlag) {
|
||||
ret.startColor = readRGBA("startColor");
|
||||
|
||||
@@ -1773,7 +1773,7 @@ public class SWFOutputStream extends OutputStream {
|
||||
writeUB(1, value.noClose ? 1 : 0);
|
||||
writeUB(2, value.endCapStyle);
|
||||
if (value.joinStyle == LINESTYLE2.MITER_JOIN) {
|
||||
writeUI16(value.miterLimitFactor);
|
||||
writeFIXED8(value.miterLimitFactor);
|
||||
}
|
||||
if (!value.hasFillFlag) {
|
||||
writeRGBA(value.startColor);
|
||||
|
||||
@@ -967,6 +967,11 @@ public final class Configuration {
|
||||
@ConfigurationDefaultBoolean(true)
|
||||
@ConfigurationCategory("ui")
|
||||
public static ConfigurationItem<Boolean> displayAs3PCodePanel = null;
|
||||
|
||||
@ConfigurationDefaultBoolean(true)
|
||||
@ConfigurationName("warning.replace.morphshape")
|
||||
@ConfigurationCategory("ui")
|
||||
public static ConfigurationItem<Boolean> warningReplaceMorphShape = null;
|
||||
|
||||
private enum OSId {
|
||||
WINDOWS, OSX, UNIX
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.jpexs.decompiler.flash.tags.DefineShapeTag;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
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.enums.ImageFormat;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
@@ -57,22 +58,55 @@ import java.util.logging.Logger;
|
||||
public class ShapeImporter {
|
||||
|
||||
public Tag importImage(ShapeTag st, byte[] newData) throws IOException {
|
||||
return importImage(st, newData, 0, true);
|
||||
return importImage((Tag) st, newData, 0, true);
|
||||
}
|
||||
|
||||
public Tag importImage(MorphShapeTag mst, byte[] newData) throws IOException {
|
||||
return importImage((Tag) mst, newData, 0, true);
|
||||
}
|
||||
|
||||
public Tag importImage(MorphShapeTag mst, byte[] newData, int tagType, boolean fill) throws IOException {
|
||||
return importImage((Tag) mst, newData, tagType, fill);
|
||||
}
|
||||
|
||||
public Tag importImage(ShapeTag st, byte[] newData, int tagType, boolean fill) throws IOException {
|
||||
return importImage((Tag) st, newData, tagType, fill);
|
||||
}
|
||||
|
||||
private Tag importImage(Tag st, byte[] newData, int tagType, boolean fill) throws IOException {
|
||||
ImageTag imageTag = addImage(st, newData, tagType);
|
||||
st.setModified(true);
|
||||
|
||||
RECT rect = st.getRect();
|
||||
RECT rect = null;
|
||||
int shapeNum = 0;
|
||||
if (st instanceof ShapeTag) {
|
||||
rect = ((ShapeTag) st).getRect();
|
||||
shapeNum = ((ShapeTag) st).getShapeNum();
|
||||
}
|
||||
if (st instanceof MorphShapeTag) {
|
||||
rect = ((MorphShapeTag) st).getRect();
|
||||
int morphShapeNum = ((MorphShapeTag) st).getShapeNum();
|
||||
if (morphShapeNum == 2) {
|
||||
shapeNum = 4;
|
||||
} else {
|
||||
shapeNum = 3;
|
||||
}
|
||||
}
|
||||
if (!fill) {
|
||||
Dimension dimension = imageTag.getImageDimension();
|
||||
rect.Xmax = rect.Xmin + (int) (SWF.unitDivisor * dimension.getWidth());
|
||||
rect.Ymax = rect.Ymin + (int) (SWF.unitDivisor * dimension.getHeight());
|
||||
}
|
||||
|
||||
SHAPEWITHSTYLE shapes = imageTag.getShape(rect, fill, st.getShapeNum());
|
||||
st.shapes = shapes;
|
||||
SHAPEWITHSTYLE shapes = imageTag.getShape(rect, fill, shapeNum);
|
||||
if (st instanceof ShapeTag) {
|
||||
ShapeTag shapeTag = (ShapeTag) st;
|
||||
shapeTag.shapes = shapes;
|
||||
}
|
||||
if (st instanceof MorphShapeTag) {
|
||||
MorphShapeTag morphShapeTag = (MorphShapeTag) st;
|
||||
shapes.updateMorphShapeTag(morphShapeTag, fill);
|
||||
}
|
||||
return (Tag) st;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,9 +28,11 @@ import com.jpexs.decompiler.flash.importers.ShapeImporter;
|
||||
import com.jpexs.decompiler.flash.importers.svg.css.CssParseException;
|
||||
import com.jpexs.decompiler.flash.importers.svg.css.CssParser;
|
||||
import com.jpexs.decompiler.flash.importers.svg.css.CssSelectorToXPath;
|
||||
import com.jpexs.decompiler.flash.tags.DefineMorphShape2Tag;
|
||||
import com.jpexs.decompiler.flash.tags.DefineShape4Tag;
|
||||
import com.jpexs.decompiler.flash.tags.ExportAssetsTag;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.tags.base.MorphShapeTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
|
||||
import com.jpexs.decompiler.flash.types.FILLSTYLE;
|
||||
import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY;
|
||||
@@ -91,16 +93,33 @@ public class SvgImporter {
|
||||
|
||||
private final Set<String> shownWarnings = new HashSet<>();
|
||||
|
||||
ShapeTag shapeTag;
|
||||
|
||||
/**
|
||||
* Shape or morphshape tag
|
||||
*/
|
||||
Tag shapeTag;
|
||||
|
||||
private Rectangle2D.Double viewBox;
|
||||
|
||||
|
||||
public Tag importSvg(ShapeTag st, String svgXml) {
|
||||
return importSvg(st, svgXml, true);
|
||||
return importSvg((Tag) st, svgXml, true);
|
||||
}
|
||||
|
||||
public Tag importSvg(MorphShapeTag mst, String svgXml) {
|
||||
return importSvg((Tag) mst, svgXml, true);
|
||||
}
|
||||
|
||||
public Tag importSvg(ShapeTag st, String svgXml, boolean fill) {
|
||||
return importSvg((Tag) st, svgXml, fill);
|
||||
}
|
||||
|
||||
public Tag importSvg(MorphShapeTag mst, String svgXml, boolean fill) {
|
||||
return importSvg((Tag) mst, svgXml, fill);
|
||||
}
|
||||
|
||||
private Tag importSvg(Tag st, String svgXml, boolean fill) {
|
||||
shapeTag = st;
|
||||
|
||||
boolean morphShape = st instanceof MorphShapeTag;
|
||||
|
||||
if (st instanceof DefineShape4Tag) {
|
||||
DefineShape4Tag shape4 = (DefineShape4Tag) st;
|
||||
@@ -115,8 +134,23 @@ public class SvgImporter {
|
||||
shapes.fillStyles.fillStyles = new FILLSTYLE[0];
|
||||
shapes.lineStyles.lineStyles = new LINESTYLE[0];
|
||||
|
||||
int shapeNum = st.getShapeNum();
|
||||
RECT rect = st.getRect();
|
||||
int shapeNum = 0;
|
||||
RECT rect = null;
|
||||
|
||||
if (st instanceof ShapeTag) {
|
||||
shapeNum = ((ShapeTag) st).getShapeNum();
|
||||
rect = ((ShapeTag) st).getRect();
|
||||
}
|
||||
if (st instanceof MorphShapeTag) {
|
||||
int morphShapeNum = ((MorphShapeTag) st).getShapeNum();
|
||||
if (morphShapeNum == 2) {
|
||||
shapeNum = 4;
|
||||
} else {
|
||||
shapeNum = 3;
|
||||
}
|
||||
rect = ((MorphShapeTag) st).getRect();
|
||||
}
|
||||
|
||||
int origXmin = rect.Xmin;
|
||||
int origYmin = rect.Ymin;
|
||||
|
||||
@@ -193,17 +227,24 @@ public class SvgImporter {
|
||||
transform.translate(origXmin / SWF.unitDivisor / ratioX, origYmin / SWF.unitDivisor / ratioY);
|
||||
}
|
||||
|
||||
processSvgObject(idMap, shapeNum, shapes, rootElement, transform, style);
|
||||
processSvgObject(idMap, shapeNum, shapes, rootElement, transform, style, morphShape);
|
||||
} catch (SAXException | IOException | ParserConfigurationException ex) {
|
||||
Logger.getLogger(ShapeImporter.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
|
||||
shapes.shapeRecords.add(new EndShapeRecord());
|
||||
|
||||
st.shapes = shapes;
|
||||
if (!fill) {
|
||||
st.updateBounds();
|
||||
if (st instanceof ShapeTag) {
|
||||
ShapeTag shape = (ShapeTag) st;
|
||||
shape.shapes = shapes;
|
||||
if (!fill) {
|
||||
shape.updateBounds();
|
||||
}
|
||||
}
|
||||
if (st instanceof MorphShapeTag) {
|
||||
shapes.updateMorphShapeTag((MorphShapeTag) st, fill);
|
||||
}
|
||||
|
||||
st.setModified(true);
|
||||
|
||||
return (Tag) st;
|
||||
@@ -272,7 +313,7 @@ public class SvgImporter {
|
||||
}
|
||||
}
|
||||
|
||||
private void processSwitch(Element element, Map<String, Element> idMap, int shapeNum, SHAPEWITHSTYLE shapes, Matrix transform, SvgStyle style) {
|
||||
private void processSwitch(Element element, Map<String, Element> idMap, int shapeNum, SHAPEWITHSTYLE shapes, Matrix transform, SvgStyle style, boolean morphShape) {
|
||||
for (int i = 0; i < element.getChildNodes().getLength(); i++) {
|
||||
Node childNode = element.getChildNodes().item(i);
|
||||
if (childNode instanceof Element) {
|
||||
@@ -283,18 +324,18 @@ public class SvgImporter {
|
||||
if (childElement.hasAttribute("systemLanguage")) {
|
||||
String systemLanguage = childElement.getAttribute("systemLanguage");
|
||||
if (systemLanguage.equals("en-us") || systemLanguage.equals("en")) {
|
||||
processElement(childElement, idMap, shapeNum, shapes, transform, style);
|
||||
processElement(childElement, idMap, shapeNum, shapes, transform, style, morphShape);
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
processElement(childElement, idMap, shapeNum, shapes, transform, style);
|
||||
processElement(childElement, idMap, shapeNum, shapes, transform, style, morphShape);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processElement(Element element, Map<String, Element> idMap, int shapeNum, SHAPEWITHSTYLE shapes, Matrix transform, SvgStyle style) {
|
||||
private void processElement(Element element, Map<String, Element> idMap, int shapeNum, SHAPEWITHSTYLE shapes, Matrix transform, SvgStyle style, boolean morphShape) {
|
||||
if (element.hasAttribute("requiredExtensions") && !element.getAttribute("requiredExtensions").isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@@ -303,25 +344,25 @@ public class SvgImporter {
|
||||
Matrix m = Matrix.parseSvgMatrix(element.getAttribute("transform"), 1, 1);
|
||||
Matrix m2 = m == null ? transform : transform.concatenate(m);
|
||||
if ("switch".equals(tagName)) {
|
||||
processSwitch(element, idMap, shapeNum, shapes, transform, style);
|
||||
processSwitch(element, idMap, shapeNum, shapes, transform, style, morphShape);
|
||||
} else if ("style".equals(tagName)) {
|
||||
processStyle(element);
|
||||
} else if ("g".equals(tagName)) {
|
||||
processSvgObject(idMap, shapeNum, shapes, element, m2, newStyle);
|
||||
processSvgObject(idMap, shapeNum, shapes, element, m2, newStyle, morphShape);
|
||||
} else if ("path".equals(tagName)) {
|
||||
processPath(shapeNum, shapes, element, m2, newStyle);
|
||||
processPath(shapeNum, shapes, element, m2, newStyle, morphShape);
|
||||
} else if ("circle".equals(tagName)) {
|
||||
processCircle(shapeNum, shapes, element, m2, newStyle);
|
||||
processCircle(shapeNum, shapes, element, m2, newStyle, morphShape);
|
||||
} else if ("ellipse".equals(tagName)) {
|
||||
processEllipse(shapeNum, shapes, element, m2, newStyle);
|
||||
processEllipse(shapeNum, shapes, element, m2, newStyle, morphShape);
|
||||
} else if ("rect".equals(tagName)) {
|
||||
processRect(shapeNum, shapes, element, m2, newStyle);
|
||||
processRect(shapeNum, shapes, element, m2, newStyle, morphShape);
|
||||
} else if ("line".equals(tagName)) {
|
||||
processLine(shapeNum, shapes, element, m2, newStyle);
|
||||
processLine(shapeNum, shapes, element, m2, newStyle, morphShape);
|
||||
} else if ("polyline".equals(tagName)) {
|
||||
processPolyline(shapeNum, shapes, element, m2, newStyle);
|
||||
processPolyline(shapeNum, shapes, element, m2, newStyle, morphShape);
|
||||
} else if ("polygon".equals(tagName)) {
|
||||
processPolygon(shapeNum, shapes, element, m2, newStyle);
|
||||
processPolygon(shapeNum, shapes, element, m2, newStyle, morphShape);
|
||||
} else if ("defs".equals(tagName)) {
|
||||
processDefs(element);
|
||||
} else if ("title".equals(tagName) || "desc".equals(tagName)
|
||||
@@ -332,12 +373,12 @@ public class SvgImporter {
|
||||
}
|
||||
}
|
||||
|
||||
private void processSvgObject(Map<String, Element> idMap, int shapeNum, SHAPEWITHSTYLE shapes, Element element, Matrix transform, SvgStyle style) {
|
||||
private void processSvgObject(Map<String, Element> idMap, int shapeNum, SHAPEWITHSTYLE shapes, Element element, Matrix transform, SvgStyle style, boolean morphShape) {
|
||||
for (int i = 0; i < element.getChildNodes().getLength(); i++) {
|
||||
Node childNode = element.getChildNodes().item(i);
|
||||
if (childNode instanceof Element) {
|
||||
Element childElement = (Element) childNode;
|
||||
processElement(childElement, idMap, shapeNum, shapes, transform, style);
|
||||
processElement(childElement, idMap, shapeNum, shapes, transform, style, morphShape);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -372,7 +413,7 @@ public class SvgImporter {
|
||||
}
|
||||
}
|
||||
|
||||
private void processCommands(int shapeNum, SHAPEWITHSTYLE shapes, List<PathCommand> commands, Matrix transform, SvgStyle style) {
|
||||
private void processCommands(int shapeNum, SHAPEWITHSTYLE shapes, List<PathCommand> commands, Matrix transform, SvgStyle style, boolean morphShape) {
|
||||
|
||||
if ("nonzero".equals(style.getFillRule())) {
|
||||
if (shapeTag instanceof DefineShape4Tag) {
|
||||
@@ -387,14 +428,18 @@ public class SvgImporter {
|
||||
double x0 = 0;
|
||||
double y0 = 0;
|
||||
|
||||
StyleChangeRecord scrStyle = getStyleChangeRecord(shapeNum, style);
|
||||
int fillStyle = scrStyle.fillStyle1;
|
||||
StyleChangeRecord scrStyle = getStyleChangeRecord(shapeNum, style, morphShape);
|
||||
int fillStyle = morphShape ? scrStyle.fillStyle0 : scrStyle.fillStyle1;
|
||||
int lineStyle = scrStyle.lineStyle;
|
||||
scrStyle.stateFillStyle0 = true;
|
||||
scrStyle.stateFillStyle1 = true;
|
||||
if (!morphShape) {
|
||||
scrStyle.stateFillStyle1 = true;
|
||||
}
|
||||
scrStyle.stateLineStyle = true;
|
||||
scrStyle.fillStyle0 = 0;
|
||||
scrStyle.fillStyle1 = 0;
|
||||
if (!morphShape) {
|
||||
scrStyle.fillStyle1 = 0;
|
||||
}
|
||||
scrStyle.lineStyle = 0;
|
||||
|
||||
List<SHAPERECORD> newRecords = new ArrayList<>();
|
||||
@@ -428,8 +473,13 @@ public class SvgImporter {
|
||||
|
||||
StyleChangeRecord scr = new StyleChangeRecord();
|
||||
if (fillStyle != 0) {
|
||||
scr.stateFillStyle1 = true;
|
||||
scr.fillStyle1 = fillStyle;
|
||||
if (morphShape) {
|
||||
scr.stateFillStyle0 = true;
|
||||
scr.fillStyle0 = fillStyle;
|
||||
} else {
|
||||
scr.stateFillStyle1 = true;
|
||||
scr.fillStyle1 = fillStyle;
|
||||
}
|
||||
}
|
||||
if (lineStyle != 0) {
|
||||
scr.lineStyle = lineStyle;
|
||||
@@ -584,7 +634,7 @@ public class SvgImporter {
|
||||
shapes.shapeRecords.addAll(newRecords);
|
||||
}
|
||||
|
||||
private void processPath(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style) {
|
||||
private void processPath(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style, boolean morphShape) {
|
||||
String data = childElement.getAttribute("d");
|
||||
|
||||
char command = 0;
|
||||
@@ -889,7 +939,7 @@ public class SvgImporter {
|
||||
// ignore remaining data as specified in SVG Specification F.2 Error processing
|
||||
}
|
||||
|
||||
processCommands(shapeNum, shapes, pathCommands, transform, style);
|
||||
processCommands(shapeNum, shapes, pathCommands, transform, style, morphShape);
|
||||
}
|
||||
|
||||
private double calcAngle(double ux, double uy, double vx, double vy) {
|
||||
@@ -903,7 +953,7 @@ public class SvgImporter {
|
||||
return sign * Math.acos(ux * vx + uy * vy / (lu * lv));
|
||||
}
|
||||
|
||||
private void processCircle(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style) {
|
||||
private void processCircle(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style, boolean morphShape) {
|
||||
String attr = childElement.getAttribute("cx");
|
||||
double cx = attr.length() > 0 ? parseCoordinate(attr, viewBox.width) : 0;
|
||||
|
||||
@@ -913,10 +963,10 @@ public class SvgImporter {
|
||||
attr = childElement.getAttribute("r");
|
||||
double r = attr.length() > 0 ? parseLength(attr, (viewBox.width + viewBox.height) / 2) : 0;
|
||||
|
||||
processEllipse(shapeNum, shapes, transform, style, cx, cy, r, r);
|
||||
processEllipse(shapeNum, shapes, transform, style, cx, cy, r, r, morphShape);
|
||||
}
|
||||
|
||||
private void processEllipse(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style) {
|
||||
private void processEllipse(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style, boolean morphShape) {
|
||||
String attr = childElement.getAttribute("cx");
|
||||
double cx = attr.length() > 0 ? parseCoordinate(attr, viewBox.width) : 0;
|
||||
|
||||
@@ -929,10 +979,10 @@ public class SvgImporter {
|
||||
attr = childElement.getAttribute("ry");
|
||||
double ry = attr.length() > 0 ? parseLength(attr, viewBox.height) : 0;
|
||||
|
||||
processEllipse(shapeNum, shapes, transform, style, cx, cy, rx, ry);
|
||||
processEllipse(shapeNum, shapes, transform, style, cx, cy, rx, ry, morphShape);
|
||||
}
|
||||
|
||||
private void processEllipse(int shapeNum, SHAPEWITHSTYLE shapes, Matrix transform, SvgStyle style, double cx, double cy, double rx, double ry) {
|
||||
private void processEllipse(int shapeNum, SHAPEWITHSTYLE shapes, Matrix transform, SvgStyle style, double cx, double cy, double rx, double ry, boolean morphShape) {
|
||||
double sqrt2RXHalf = Math.sqrt(2) * rx / 2;
|
||||
double sqrt2Minus1RX = (Math.sqrt(2) - 1) * rx;
|
||||
double sqrt2RYHalf = Math.sqrt(2) * ry / 2;
|
||||
@@ -987,10 +1037,10 @@ public class SvgImporter {
|
||||
serz.command = 'Z';
|
||||
pathCommands.add(serz);
|
||||
|
||||
processCommands(shapeNum, shapes, pathCommands, transform, style);
|
||||
processCommands(shapeNum, shapes, pathCommands, transform, style, morphShape);
|
||||
}
|
||||
|
||||
private void processRect(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style) {
|
||||
private void processRect(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style, boolean morphShape) {
|
||||
String attr = childElement.getAttribute("x");
|
||||
double x = attr.length() > 0 ? parseCoordinate(attr, viewBox.width) : 0;
|
||||
|
||||
@@ -1098,10 +1148,10 @@ public class SvgImporter {
|
||||
serz.command = 'Z';
|
||||
pathCommands.add(serz);
|
||||
|
||||
processCommands(shapeNum, shapes, pathCommands, transform, style);
|
||||
processCommands(shapeNum, shapes, pathCommands, transform, style, morphShape);
|
||||
}
|
||||
|
||||
private void processLine(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style) {
|
||||
private void processLine(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style, boolean morphShape) {
|
||||
String attr = childElement.getAttribute("x1");
|
||||
double x1 = attr.length() > 0 ? parseCoordinate(attr, viewBox.width) : 0;
|
||||
|
||||
@@ -1126,18 +1176,18 @@ public class SvgImporter {
|
||||
|
||||
pathCommands.add(cer);
|
||||
|
||||
processCommands(shapeNum, shapes, pathCommands, transform, style);
|
||||
processCommands(shapeNum, shapes, pathCommands, transform, style, morphShape);
|
||||
}
|
||||
|
||||
private void processPolygon(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style) {
|
||||
processPolyline(shapeNum, shapes, childElement, transform, style, true);
|
||||
private void processPolygon(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style, boolean morphShape) {
|
||||
processPolyline(shapeNum, shapes, childElement, transform, style, true, morphShape);
|
||||
}
|
||||
|
||||
private void processPolyline(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style) {
|
||||
processPolyline(shapeNum, shapes, childElement, transform, style, false);
|
||||
private void processPolyline(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style, boolean morphShape) {
|
||||
processPolyline(shapeNum, shapes, childElement, transform, style, false, morphShape);
|
||||
}
|
||||
|
||||
private void processPolyline(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style, boolean close) {
|
||||
private void processPolyline(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style, boolean close, boolean morphShape) {
|
||||
String data = childElement.getAttribute("points");
|
||||
|
||||
char command = 'M';
|
||||
@@ -1187,7 +1237,7 @@ public class SvgImporter {
|
||||
pathCommands.add(serz);
|
||||
}
|
||||
|
||||
processCommands(shapeNum, shapes, pathCommands, transform, style);
|
||||
processCommands(shapeNum, shapes, pathCommands, transform, style, morphShape);
|
||||
}
|
||||
|
||||
//Stub for w3 test. TODO: refactor and move to test directory. It's here because of easy access - compiling single file
|
||||
@@ -1671,12 +1721,16 @@ public class SvgImporter {
|
||||
}
|
||||
}
|
||||
|
||||
private StyleChangeRecord getStyleChangeRecord(int shapeNum, SvgStyle style) {
|
||||
private StyleChangeRecord getStyleChangeRecord(int shapeNum, SvgStyle style, boolean morphShape) {
|
||||
StyleChangeRecord scr = new StyleChangeRecord();
|
||||
|
||||
scr.stateNewStyles = true;
|
||||
scr.fillStyles = new FILLSTYLEARRAY();
|
||||
scr.stateFillStyle1 = true;
|
||||
if (morphShape) {
|
||||
scr.stateFillStyle0 = true;
|
||||
} else {
|
||||
scr.stateFillStyle1 = true;
|
||||
}
|
||||
scr.stateLineStyle = true;
|
||||
SvgFill fill = style.getFillWithOpacity();
|
||||
if (fill != null && fill != SvgTransparentFill.INSTANCE) {
|
||||
@@ -1690,10 +1744,18 @@ public class SvgImporter {
|
||||
//...apply in second step - applyStyleGradients
|
||||
}
|
||||
|
||||
scr.fillStyle1 = 1;
|
||||
if (morphShape) {
|
||||
scr.fillStyle0 = 1;
|
||||
} else {
|
||||
scr.fillStyle1 = 1;
|
||||
}
|
||||
} else {
|
||||
scr.fillStyles.fillStyles = new FILLSTYLE[0];
|
||||
scr.fillStyle1 = 0;
|
||||
if (morphShape) {
|
||||
scr.fillStyle0 = 0;
|
||||
} else {
|
||||
scr.fillStyle1 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
scr.lineStyles = new LINESTYLEARRAY();
|
||||
@@ -1717,11 +1779,19 @@ public class SvgImporter {
|
||||
DefineShape4Tag shape4 = (DefineShape4Tag) shapeTag;
|
||||
shape4.usesNonScalingStrokes = true;
|
||||
}
|
||||
if (shapeTag instanceof DefineMorphShape2Tag) {
|
||||
DefineMorphShape2Tag morph2 = (DefineMorphShape2Tag) shapeTag;
|
||||
morph2.usesNonScalingStrokes = true;
|
||||
}
|
||||
} else {
|
||||
if (shapeTag instanceof DefineShape4Tag) {
|
||||
DefineShape4Tag shape4 = (DefineShape4Tag) shapeTag;
|
||||
shape4.usesScalingStrokes = true;
|
||||
}
|
||||
if (shapeTag instanceof DefineMorphShape2Tag) {
|
||||
DefineMorphShape2Tag morph2 = (DefineMorphShape2Tag) shapeTag;
|
||||
morph2.usesScalingStrokes = true;
|
||||
}
|
||||
}
|
||||
|
||||
int swfCap = lineCap == SvgLineCap.BUTT ? LINESTYLE2.NO_CAP
|
||||
|
||||
@@ -152,4 +152,23 @@ public class FILLSTYLE implements NeedsCharacters, FieldChangeObserver, Serializ
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public MORPHFILLSTYLE toMorphStyle() {
|
||||
MORPHFILLSTYLE morphFillStyle = new MORPHFILLSTYLE();
|
||||
morphFillStyle.bitmapId = bitmapId;
|
||||
if (bitmapMatrix != null) {
|
||||
morphFillStyle.startBitmapMatrix = new MATRIX(bitmapMatrix);
|
||||
morphFillStyle.endBitmapMatrix = new MATRIX(bitmapMatrix);
|
||||
}
|
||||
if (color != null) {
|
||||
morphFillStyle.startColor = new RGBA(color);
|
||||
morphFillStyle.endColor = new RGBA(color);
|
||||
}
|
||||
morphFillStyle.fillStyleType = fillStyleType;
|
||||
if (gradient != null) {
|
||||
morphFillStyle.gradient = gradient.toMorphGradient();
|
||||
}
|
||||
|
||||
return morphFillStyle;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,4 +55,13 @@ public class FILLSTYLEARRAY implements NeedsCharacters, Serializable {
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
public MORPHFILLSTYLEARRAY toMorphFillStyleArray() {
|
||||
MORPHFILLSTYLEARRAY morphFillStyleArray = new MORPHFILLSTYLEARRAY();
|
||||
morphFillStyleArray.fillStyles = new MORPHFILLSTYLE[fillStyles.length];
|
||||
for (int i = 0; i < fillStyles.length; i++) {
|
||||
morphFillStyleArray.fillStyles[i] = fillStyles[i].toMorphStyle();
|
||||
}
|
||||
return morphFillStyleArray;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,4 +62,15 @@ public class GRADIENT implements Serializable {
|
||||
|
||||
@SWFArray(value = "record")
|
||||
public GRADRECORD[] gradientRecords = new GRADRECORD[0];
|
||||
|
||||
public MORPHGRADIENT toMorphGradient() {
|
||||
MORPHGRADIENT morphGradient = new MORPHGRADIENT();
|
||||
morphGradient.interPolationMode = interpolationMode;
|
||||
morphGradient.spreadMode = spreadMode;
|
||||
morphGradient.gradientRecords = new MORPHGRADRECORD[gradientRecords.length];
|
||||
for (int i = 0; i < gradientRecords.length; i++) {
|
||||
morphGradient.gradientRecords[i] = gradientRecords[i].toMorphGradRecord();
|
||||
}
|
||||
return morphGradient;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,4 +37,13 @@ public class GRADRECORD implements Serializable {
|
||||
public float getRatioFloat() {
|
||||
return ((float) ratio) / 255.0f;
|
||||
}
|
||||
|
||||
public MORPHGRADRECORD toMorphGradRecord() {
|
||||
MORPHGRADRECORD morphGradRecord = new MORPHGRADRECORD();
|
||||
morphGradRecord.startColor = new RGBA(color);
|
||||
morphGradRecord.endColor = new RGBA(color);
|
||||
morphGradRecord.startRatio = ratio;
|
||||
morphGradRecord.endRatio = ratio;
|
||||
return morphGradRecord;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,4 +75,13 @@ public class LINESTYLE implements NeedsCharacters, Serializable, ILINESTYLE {
|
||||
public void setWidth(int width) {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
public MORPHLINESTYLE toMorphLineStyle() {
|
||||
MORPHLINESTYLE morphLineStyle = new MORPHLINESTYLE();
|
||||
morphLineStyle.startColor = new RGBA(color);
|
||||
morphLineStyle.endColor = new RGBA(color);
|
||||
morphLineStyle.startWidth = width;
|
||||
morphLineStyle.endWidth = width;
|
||||
return morphLineStyle;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,4 +142,27 @@ public class LINESTYLE2 implements NeedsCharacters, Serializable, ILINESTYLE {
|
||||
public void setWidth(int width) {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
public MORPHLINESTYLE2 toMorphLineStyle2() {
|
||||
MORPHLINESTYLE2 morphLineStyle2 = new MORPHLINESTYLE2();
|
||||
morphLineStyle2.startWidth = width;
|
||||
morphLineStyle2.endWidth = width;
|
||||
morphLineStyle2.startCapStyle = startCapStyle;
|
||||
morphLineStyle2.joinStyle = joinStyle;
|
||||
morphLineStyle2.hasFillFlag = hasFillFlag;
|
||||
morphLineStyle2.noHScaleFlag = noHScaleFlag;
|
||||
morphLineStyle2.noVScaleFlag = noVScaleFlag;
|
||||
morphLineStyle2.pixelHintingFlag = pixelHintingFlag;
|
||||
morphLineStyle2.noClose = noClose;
|
||||
morphLineStyle2.endCapStyle = endCapStyle;
|
||||
morphLineStyle2.miterLimitFactor = miterLimitFactor;
|
||||
if (color != null) {
|
||||
morphLineStyle2.startColor = new RGBA(color);
|
||||
morphLineStyle2.endColor = new RGBA(color);
|
||||
}
|
||||
if (fillType != null) {
|
||||
morphLineStyle2.fillType = fillType.toMorphStyle();
|
||||
}
|
||||
return morphLineStyle2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,4 +87,21 @@ public class LINESTYLEARRAY implements NeedsCharacters, Serializable {
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
public MORPHLINESTYLEARRAY toMorphLineStyleArray() {
|
||||
MORPHLINESTYLEARRAY morphLineStyleArray = new MORPHLINESTYLEARRAY();
|
||||
if (lineStyles != null) {
|
||||
morphLineStyleArray.lineStyles = new MORPHLINESTYLE[lineStyles.length];
|
||||
for (int i = 0; i < lineStyles.length; i++) {
|
||||
morphLineStyleArray.lineStyles[i] = lineStyles[i].toMorphLineStyle();
|
||||
}
|
||||
}
|
||||
if (lineStyles2 != null) {
|
||||
morphLineStyleArray.lineStyles2 = new MORPHLINESTYLE2[lineStyles2.length];
|
||||
for (int i = 0; i < lineStyles2.length; i++) {
|
||||
morphLineStyleArray.lineStyles2[i] = lineStyles2[i].toMorphLineStyle2();
|
||||
}
|
||||
}
|
||||
return morphLineStyleArray;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,9 +78,9 @@ public class MORPHLINESTYLE2 implements Serializable {
|
||||
|
||||
public static final int SQUARE_CAP = 2;
|
||||
|
||||
@SWFType(value = BasicType.UI16)
|
||||
@SWFType(value = BasicType.FIXED8)
|
||||
@Conditional(value = "joinStyle", options = {MITER_JOIN})
|
||||
public int miterLimitFactor;
|
||||
public float miterLimitFactor;
|
||||
|
||||
@Conditional("!hasFillFlag")
|
||||
public RGBA startColor;
|
||||
|
||||
@@ -46,6 +46,12 @@ public class RGB implements Serializable {
|
||||
@SWFType(BasicType.UI8)
|
||||
public int blue;
|
||||
|
||||
public RGB(RGB color) {
|
||||
this.red = color.red;
|
||||
this.green = color.green;
|
||||
this.blue = color.blue;
|
||||
}
|
||||
|
||||
public RGB(int red, int green, int blue) {
|
||||
this.red = red;
|
||||
this.green = green;
|
||||
|
||||
@@ -72,6 +72,15 @@ public class RGBA extends RGB implements Serializable {
|
||||
super(rgb);
|
||||
alpha = (rgb >> 24) & 0xFF;
|
||||
}
|
||||
|
||||
public RGBA(RGB color) {
|
||||
super(color);
|
||||
if (color instanceof RGBA) {
|
||||
alpha = ((RGBA) color).alpha;
|
||||
} else {
|
||||
alpha = 255;
|
||||
}
|
||||
}
|
||||
|
||||
public RGBA() {
|
||||
}
|
||||
|
||||
@@ -17,9 +17,13 @@
|
||||
package com.jpexs.decompiler.flash.types;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.tags.base.MorphShapeTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.NeedsCharacters;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -104,4 +108,129 @@ public class SHAPEWITHSTYLE extends SHAPE implements NeedsCharacters, Serializab
|
||||
return SHAPERECORD.getBounds(shapeRecords, lineStyles, shapeNum, false);
|
||||
}
|
||||
|
||||
public void updateMorphShapeTag(MorphShapeTag morphShapeTag, boolean fill) {
|
||||
morphShapeTag.startEdges.shapeRecords.clear();
|
||||
morphShapeTag.endEdges.shapeRecords.clear();
|
||||
|
||||
FILLSTYLEARRAY mergedFillStyles = new FILLSTYLEARRAY();
|
||||
LINESTYLEARRAY mergedLineStyles = new LINESTYLEARRAY();
|
||||
|
||||
List<FILLSTYLE> mergedFillStyleList = new ArrayList<>();
|
||||
List<LINESTYLE> mergedLineStyleList = new ArrayList<>();
|
||||
List<LINESTYLE2> mergedLineStyle2List = new ArrayList<>();
|
||||
|
||||
int lastFillCount = fillStyles.fillStyles.length;
|
||||
|
||||
for (int i = 0; i < fillStyles.fillStyles.length; i++) {
|
||||
mergedFillStyleList.add(fillStyles.fillStyles[i]);
|
||||
}
|
||||
|
||||
int lastLineCount = 0;
|
||||
|
||||
if (lineStyles.lineStyles != null) {
|
||||
lastLineCount = lineStyles.lineStyles.length;
|
||||
for (int i = 0; i < lineStyles.lineStyles.length; i++) {
|
||||
mergedLineStyleList.add(lineStyles.lineStyles[i]);
|
||||
}
|
||||
}
|
||||
if (lineStyles.lineStyles2 != null) {
|
||||
lastLineCount = lineStyles.lineStyles2.length;
|
||||
for (int i = 0; i < lineStyles.lineStyles2.length; i++) {
|
||||
mergedLineStyle2List.add(lineStyles.lineStyles2[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int fillOffset = 0;
|
||||
int lineOffset = 0;
|
||||
List<SHAPERECORD> newShapeRecords = new ArrayList<>();
|
||||
for (int r = 0; r < shapeRecords.size(); r++) {
|
||||
SHAPERECORD rec = shapeRecords.get(r);
|
||||
rec = Helper.deepCopy(rec);
|
||||
if (rec instanceof StyleChangeRecord) {
|
||||
StyleChangeRecord scr = (StyleChangeRecord) rec;
|
||||
if (scr.stateNewStyles) {
|
||||
for (int i = 0; i < scr.fillStyles.fillStyles.length; i++) {
|
||||
mergedFillStyleList.add(scr.fillStyles.fillStyles[i]);
|
||||
}
|
||||
fillOffset += lastFillCount;
|
||||
lastFillCount = scr.fillStyles.fillStyles.length;
|
||||
if (scr.lineStyles.lineStyles != null) {
|
||||
for (int i = 0; i < scr.lineStyles.lineStyles.length; i++) {
|
||||
mergedLineStyleList.add(scr.lineStyles.lineStyles[i]);
|
||||
}
|
||||
lineOffset += lastLineCount;
|
||||
lastLineCount = scr.lineStyles.lineStyles.length;
|
||||
}
|
||||
if (scr.lineStyles.lineStyles2 != null) {
|
||||
for (int i = 0; i < scr.lineStyles.lineStyles2.length; i++) {
|
||||
mergedLineStyle2List.add(scr.lineStyles.lineStyles2[i]);
|
||||
}
|
||||
lineOffset += lastLineCount;
|
||||
lastLineCount = scr.lineStyles.lineStyles2.length;
|
||||
}
|
||||
scr.stateNewStyles = false;
|
||||
}
|
||||
if (scr.stateFillStyle0) {
|
||||
scr.fillStyle0 += fillOffset;
|
||||
}
|
||||
if (scr.stateFillStyle1) {
|
||||
scr.fillStyle1 += fillOffset;
|
||||
}
|
||||
if (scr.stateLineStyle) {
|
||||
scr.lineStyle += lineOffset;
|
||||
}
|
||||
}
|
||||
newShapeRecords.add(rec);
|
||||
}
|
||||
|
||||
mergedFillStyles.fillStyles = new FILLSTYLE[mergedFillStyleList.size()];
|
||||
for (int i = 0; i < mergedFillStyleList.size(); i++) {
|
||||
mergedFillStyles.fillStyles[i] = mergedFillStyleList.get(i);
|
||||
}
|
||||
mergedLineStyles.lineStyles = new LINESTYLE[mergedLineStyleList.size()];
|
||||
for (int i = 0; i < mergedLineStyleList.size(); i++) {
|
||||
mergedLineStyles.lineStyles[i] = mergedLineStyleList.get(i);
|
||||
}
|
||||
mergedLineStyles.lineStyles2 = new LINESTYLE2[mergedLineStyle2List.size()];
|
||||
for (int i = 0; i < mergedLineStyle2List.size(); i++) {
|
||||
mergedLineStyles.lineStyles2[i] = mergedLineStyle2List.get(i);
|
||||
}
|
||||
|
||||
|
||||
morphShapeTag.morphFillStyles = mergedFillStyles.toMorphFillStyleArray();
|
||||
morphShapeTag.morphLineStyles = mergedLineStyles.toMorphLineStyleArray();
|
||||
SHAPE startShapes = new SHAPE();
|
||||
startShapes.numFillBits = SWFOutputStream.getNeededBitsU(mergedFillStyleList.size());
|
||||
startShapes.numLineBits = SWFOutputStream.getNeededBitsU(mergedLineStyleList.size() + mergedLineStyle2List.size());
|
||||
startShapes.shapeRecords = newShapeRecords;
|
||||
morphShapeTag.startEdges = startShapes;
|
||||
|
||||
SHAPE endShapes = new SHAPE();
|
||||
endShapes.numFillBits = 0;
|
||||
endShapes.numLineBits = 0;
|
||||
List<SHAPERECORD> endRecords = new ArrayList<>();
|
||||
for (int i = 0; i < newShapeRecords.size(); i++) {
|
||||
SHAPERECORD rec = newShapeRecords.get(i);
|
||||
if (rec instanceof StyleChangeRecord) {
|
||||
StyleChangeRecord scr = (StyleChangeRecord) rec;
|
||||
if (scr.stateMoveTo) {
|
||||
StyleChangeRecord nscr = new StyleChangeRecord();
|
||||
nscr.stateMoveTo = true;
|
||||
nscr.moveDeltaX = scr.moveDeltaX;
|
||||
nscr.moveDeltaY = scr.moveDeltaY;
|
||||
nscr.calculateBits();
|
||||
endRecords.add(nscr);
|
||||
}
|
||||
} else {
|
||||
endRecords.add(Helper.deepCopy(rec));
|
||||
}
|
||||
}
|
||||
endShapes.shapeRecords = endRecords;
|
||||
morphShapeTag.endEdges = endShapes;
|
||||
|
||||
if (!fill) {
|
||||
morphShapeTag.updateBounds();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user