Morphshape replace - use whole file when it was exported by FFDec

Fixed Morphshape SVG export - focalPoint animation
This commit is contained in:
Jindra Petřík
2023-10-27 17:13:28 +02:00
parent 87d0bfc761
commit 87e7db594e
16 changed files with 297 additions and 100 deletions

View File

@@ -224,7 +224,7 @@ public class FrameExporter {
rect.yMax *= settings.zoom;
rect.xMin *= settings.zoom;
rect.yMin *= settings.zoom;
SVGExporter exporter = new SVGExporter(rect, settings.zoom);
SVGExporter exporter = new SVGExporter(rect, settings.zoom, "frame");
if (fbackgroundColor != null) {
exporter.setBackGroundColor(fbackgroundColor);
}

View File

@@ -102,7 +102,7 @@ public class MorphShapeExporter {
rect.yMax *= settings.zoom;
rect.xMin *= settings.zoom;
rect.yMin *= settings.zoom;
SVGExporter exporter = new SVGExporter(rect, settings.zoom);
SVGExporter exporter = new SVGExporter(rect, settings.zoom, "morphshape");
mst.toSVG(exporter, -2, new CXFORMWITHALPHA(), 0);
fos.write(Utf8Helper.getBytes(exporter.getSVG()));
}

View File

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

View File

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

View File

@@ -42,6 +42,36 @@ public final class Matrix implements Cloneable {
mat.scale(scale);
return mat;
}
public static Matrix getRotateInstance(double rotateAngle) {
return getRotateInstance(rotateAngle, 0, 0);
}
public static Matrix getRotateInstance(double rotateAngle, double tx, double ty) {
double angleRad = -rotateAngle * Math.PI / 180;
Matrix mat = new Matrix();
mat.rotateSkew0 = -Math.sin(angleRad);
mat.rotateSkew1 = Math.sin(angleRad);
mat.scaleX = Math.cos(angleRad);
mat.scaleY = Math.cos(angleRad);
mat = mat.preConcatenate(getTranslateInstance(tx, ty))
.concatenate(getTranslateInstance(-tx, -ty));
return mat;
}
public static Matrix getSkewXInstance(double skewAngle) {
double angleRad = skewAngle * Math.PI / 180;
Matrix mat = new Matrix();
mat.rotateSkew1 = Math.tan(angleRad);
return mat;
}
public static Matrix getSkewYInstance(double skewAngle) {
double angleRad = skewAngle * Math.PI / 180;
Matrix mat = new Matrix();
mat.rotateSkew0 = Math.tan(angleRad);
return mat;
}
public static Matrix getScaleInstance(double scaleX, double scaleY) {
Matrix mat = new Matrix();

View File

@@ -88,7 +88,7 @@ public class SVGExporter {
public boolean useTextTag = Configuration.textExportExportFontFace.get();
public SVGExporter(ExportRectangle bounds, double zoom) {
public SVGExporter(ExportRectangle bounds, double zoom, String objectType) {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
try {
@@ -110,11 +110,12 @@ public class SVGExporter {
}
createDefGroup(bounds, null, zoom);
}
svgRoot.setAttribute("ffdec:objectType", objectType);
} catch (ParserConfigurationException ex) {
Logger.getLogger(SVGExporter.class.getName()).log(Level.SEVERE, null, ex);
}
gradients = new ArrayList<>();
}
}
private Element getDefs() {
if (_svgDefs == null) {

View File

@@ -89,7 +89,7 @@ public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter {
Element gradient = (type == FILLSTYLE.LINEAR_GRADIENT)
? exporter.createElement("linearGradient")
: exporter.createElement("radialGradient");
populateGradientElement(gradient, type, gradientRecords, gradientRecordsEnd, matrix, matrixEnd, spreadMethod, interpolationMethod, focalPointRatio);
populateGradientElement(gradient, type, gradientRecords, gradientRecordsEnd, matrix, matrixEnd, spreadMethod, interpolationMethod, focalPointRatio, focalPointRatioEnd);
int id = exporter.gradients.indexOf(gradient);
if (id < 0) {
// todo: filter same gradients
@@ -206,7 +206,7 @@ public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter {
Element gradient = (type == FILLSTYLE.LINEAR_GRADIENT)
? exporter.createElement("linearGradient")
: exporter.createElement("radialGradient");
populateGradientElement(gradient, type, gradientRecords, gradientRecordsEnd, matrix, matrixEnd, spreadMethod, interpolationMethod, focalPointRatio);
populateGradientElement(gradient, type, gradientRecords, gradientRecordsEnd, matrix, matrixEnd, spreadMethod, interpolationMethod, focalPointRatio, focalPointRatioEnd);
int id = exporter.gradients.indexOf(gradient);
if (id < 0) {
// todo: filter same gradients
@@ -247,7 +247,7 @@ public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter {
// QR decomposition
double translateX = roundPixels400(matrix.translateX * zoom / SWF.unitDivisor);
double translateY = roundPixels400(matrix.translateY * zoom / SWF.unitDivisor);
double translateY = roundPixels400(matrix.translateY * zoom / SWF.unitDivisor);
double a = matrix.scaleX;
double b = matrix.rotateSkew0;
double c = matrix.rotateSkew1;
@@ -402,7 +402,7 @@ public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter {
element.appendChild(animateSkewX);*/
}
protected void populateGradientElement(Element gradient, int type, GRADRECORD[] gradientRecords, GRADRECORD[] gradientRecordsEnd, Matrix matrix, Matrix matrixEnd, int spreadMethod, int interpolationMethod, float focalPointRatio) {
protected void populateGradientElement(Element gradient, int type, GRADRECORD[] gradientRecords, GRADRECORD[] gradientRecordsEnd, Matrix matrix, Matrix matrixEnd, int spreadMethod, int interpolationMethod, float focalPointRatio, float focalPointRatioEnd) {
gradient.setAttribute("gradientUnits", "userSpaceOnUse");
if (type == FILLSTYLE.LINEAR_GRADIENT) {
gradient.setAttribute("x1", "-819.2");
@@ -415,6 +415,9 @@ public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter {
gradient.setAttribute("fx", Double.toString(819.2 * focalPointRatio));
gradient.setAttribute("fy", "0");
}
if (focalPointRatio != 0 || focalPointRatioEnd != 0) {
gradient.appendChild(createAnimateElement("fx", Double.toString(819.2 * focalPointRatio), Double.toString(819.2 * focalPointRatioEnd)));
}
}
switch (spreadMethod) {
case GRADIENT.SPREAD_PAD_MODE:

View File

@@ -211,8 +211,9 @@ public class MorphShapeGenerator {
}
for (int i = 0; i < endFillStyles.size(); i++) {
FILLSTYLE fsStart = startFillStyles.get(i);
FILLSTYLE fsEnd = endFillStyles.get(i);
if (fsEnd.hasBitmap()) {
if (fsEnd.hasBitmap() && fsEnd.bitmapId != fsStart.bitmapId) {
swf.removeTag(swf.getImage(fsEnd.bitmapId));
}
}

View File

@@ -245,7 +245,7 @@ public class ShapeForMorphExporter extends ShapeExporterBase {
currentFillStyle = fillStyles.size();
FILLSTYLE fillStyle = new FILLSTYLE();
fillStyle.fillStyleType = type;
fillStyle.gradient = focalPointRatio == 0 ? new FOCALGRADIENT() : new GRADIENT();
fillStyle.gradient = focalPointRatio == 0 ? new GRADIENT() : new FOCALGRADIENT();
fillStyle.gradient.gradientRecords = Helper.deepCopy(gradientRecords);
fillStyle.gradientMatrix = matrix.toMATRIX();
fillStyle.gradient.spreadMode = spreadMethod;

View File

@@ -69,6 +69,7 @@ import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import javax.imageio.ImageIO;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
@@ -97,28 +98,35 @@ public class SvgImporter {
* Shape or morphshape tag
*/
Tag shapeTag;
ShapeTag endShape;
private Rectangle2D.Double viewBox;
public Tag importSvg(ShapeTag st, String svgXml) {
return importSvg((Tag) st, svgXml, true);
return importSvg((Tag) st, null, svgXml, true);
}
public Tag importSvg(MorphShapeTag mst, String svgXml) {
return importSvg((Tag) mst, svgXml, true);
return importSvg((Tag) mst, null, svgXml, true);
}
public Tag importSvg(ShapeTag st, String svgXml, boolean fill) {
return importSvg((Tag) st, svgXml, fill);
return importSvg((Tag) st, null, svgXml, fill);
}
public Tag importSvg(MorphShapeTag mst, String svgXml, boolean fill) {
return importSvg((Tag) mst, svgXml, fill);
return importSvg((Tag) mst, null, svgXml, fill);
}
private Tag importSvg(Tag st, String svgXml, boolean fill) {
public Tag importSvg(ShapeTag startShape, ShapeTag endShape, String svgXml, boolean fill) {
return importSvg((Tag) startShape, endShape, svgXml, fill);
}
private Tag importSvg(Tag st, ShapeTag endShape, String svgXml, boolean fill) {
shapeTag = st;
this.endShape = endShape;
boolean morphShape = st instanceof MorphShapeTag;
if (st instanceof DefineShape4Tag) {
@@ -134,10 +142,16 @@ public class SvgImporter {
shapes.fillStyles.fillStyles = new FILLSTYLE[0];
shapes.lineStyles.lineStyles = new LINESTYLE[0];
SHAPEWITHSTYLE shapes2 = new SHAPEWITHSTYLE();
shapes2.fillStyles = new FILLSTYLEARRAY();
shapes2.lineStyles = new LINESTYLEARRAY();
shapes2.fillStyles.fillStyles = new FILLSTYLE[0];
shapes2.lineStyles.lineStyles = new LINESTYLE[0];
int shapeNum = 0;
RECT rect = null;
if (st instanceof ShapeTag) {
if (st instanceof ShapeTag) {
shapeNum = ((ShapeTag) st).getShapeNum();
rect = ((ShapeTag) st).getRect();
}
@@ -150,11 +164,12 @@ public class SvgImporter {
}
rect = ((MorphShapeTag) st).getRect();
}
int origXmin = rect.Xmin;
int origYmin = rect.Ymin;
shapes.shapeRecords = new ArrayList<>();
shapes2.shapeRecords = new ArrayList<>();
Rectangle2D.Double viewBox = null;
try {
@@ -217,8 +232,8 @@ public class SvgImporter {
this.viewBox = viewBox;
Map<String, SvgFill> cachedFills = new HashMap<>();
SvgStyle style = new SvgStyle(this, idMap, rootElement, cachedFills);
Map<String, Integer> cachedBitmaps = new HashMap<>();
SvgStyle style = new SvgStyle(this, idMap, rootElement, cachedBitmaps);
Matrix transform = new Matrix();
if (fill) {
@@ -227,18 +242,26 @@ public class SvgImporter {
transform = Matrix.getScaleInstance(ratioX, ratioY);
transform.translate(origXmin / SWF.unitDivisor / ratioX, origYmin / SWF.unitDivisor / ratioY);
}
transform = transform.preConcatenate(Matrix.getTranslateInstance(-viewBox.x, -viewBox.y));
transform = transform.preConcatenate(Matrix.getTranslateInstance(-viewBox.x, -viewBox.y));
if (viewBox.height != 0 && viewBox.width != 0) {
transform = transform.preConcatenate(Matrix.getScaleInstance(width / viewBox.width, height / viewBox.height));
}
processSvgObject(idMap, shapeNum, shapes, rootElement, transform, style, morphShape, cachedFills);
processSvgObject(idMap, shapeNum, shapes, rootElement, transform, style, morphShape, cachedBitmaps, false);
if (
rootElement.hasAttribute("ffdec:objectType")
&& "morphshape".equals(rootElement.getAttribute("ffdec:objectType"))
&& applyAnimation(rootElement)
) {
processSvgObject(idMap, shapeNum, shapes2, rootElement, transform, style, morphShape, cachedBitmaps, true);
}
} catch (SAXException | IOException | ParserConfigurationException ex) {
Logger.getLogger(ShapeImporter.class.getName()).log(Level.SEVERE, null, ex);
}
shapes.shapeRecords.add(new EndShapeRecord());
shapes2.shapeRecords.add(new EndShapeRecord());
if (st instanceof ShapeTag) {
ShapeTag shape = (ShapeTag) st;
@@ -247,15 +270,127 @@ public class SvgImporter {
shape.updateBounds();
}
}
if (endShape != null) {
endShape.shapes = shapes2;
endShape.updateBounds();
}
if (st instanceof MorphShapeTag) {
shapes.updateMorphShapeTag((MorphShapeTag) st, fill);
}
st.setModified(true);
if (endShape != null) {
endShape.setModified(true);
}
return (Tag) st;
}
protected boolean applyAnimation(Element element) {
NodeList nodeList = element.getChildNodes();
boolean result = false;
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (node instanceof Element) {
Element childElement = (Element) node;
if ("animate".equals(childElement.getTagName())) {
if (childElement.hasAttribute("attributeName") && childElement.hasAttribute("values")) {
String values = childElement.getAttribute("values");
String attributeName = childElement.getAttribute("attributeName");
if (values.contains(";")) {
String parts[] = values.split(";");
if (parts.length >= 2) {
element.setAttribute(attributeName, parts[1]);
result = true;
}
}
}
} else if ("animateTransform".equals(childElement.getTagName())) {
if (childElement.hasAttribute("attributeName")
&& childElement.hasAttribute("type")
&& (childElement.hasAttribute("to") || childElement.hasAttribute("values"))
) {
String type = childElement.getAttribute("type");
String additive = childElement.hasAttribute("additive") ? childElement.getAttribute("additive") : "replace";
String attributeName = childElement.getAttribute("attributeName");
Matrix originalMatrix = Matrix.parseSvgMatrix(element.getAttribute(attributeName), 1, 1);
String to = "";
if (childElement.hasAttribute("values") && childElement.getAttribute("values").contains(";")) {
to = childElement.getAttribute("values").split(";")[1];
} else if (childElement.hasAttribute("to")) {
to = childElement.getAttribute("to");
}
String toParts[] = Matrix.parseSvgNumberList(to);
Matrix newMatrix = null;
switch (type) {
case "scale":
double scaleX;
double scaleY;
if (toParts.length == 2) {
scaleX = parseNumber(toParts[0]);
scaleY = parseNumber(toParts[1]);
} else if (toParts.length == 1) {
scaleX = parseNumber(toParts[0]);
scaleY = scaleX;
} else {
break;
}
newMatrix = Matrix.getScaleInstance(scaleX, scaleY);
break;
case "translate":
if (toParts.length == 2) {
double translateX = parseNumber(toParts[0]);
double translateY = parseNumber(toParts[1]);
newMatrix = Matrix.getTranslateInstance(translateX, translateY);
}
break;
case "rotate":
if (toParts.length == 1 || toParts.length == 3) {
double rotateAngle = parseNumber(toParts[0]);
double tx = 0;
double ty = 0;
if (toParts.length == 3) {
tx = parseNumber(toParts[1]);
ty = parseNumber(toParts[2]);
}
newMatrix = Matrix.getRotateInstance(rotateAngle, tx, ty);
}
break;
case "skewX":
if (toParts.length == 1) {
double skewXAngle = parseNumber(toParts[0]);
newMatrix = Matrix.getSkewXInstance(skewXAngle);
}
break;
case "skewY":
if (toParts.length == 1) {
double skewYAngle = parseNumber(toParts[0]);
newMatrix = Matrix.getSkewYInstance(skewYAngle);
}
break;
}
if (newMatrix != null) {
if ("replace".equals(additive)) {
element.setAttribute(attributeName, newMatrix.getSvgTransformationString(1, 1));
}
if ("sum".equals(additive)) {
element.setAttribute(attributeName, originalMatrix.concatenate(newMatrix).getSvgTransformationString(1, 1));
}
}
}
} else {
if (applyAnimation(childElement)) {
result = true;
}
}
}
}
return result;
}
// Generate id-element map, because getElementById does not work in some cases (namespaces?)
protected void populateIds(Element el, Map<String, Element> out) {
if (el.hasAttribute("id")) {
@@ -319,7 +454,7 @@ public class SvgImporter {
}
}
private void processSwitch(Element element, Map<String, Element> idMap, int shapeNum, SHAPEWITHSTYLE shapes, Matrix transform, SvgStyle style, boolean morphShape, Map<String, SvgFill> cachedFills) {
private void processSwitch(Element element, Map<String, Element> idMap, int shapeNum, SHAPEWITHSTYLE shapes, Matrix transform, SvgStyle style, boolean morphShape, Map<String, Integer> cachedBitmaps, boolean shape2) {
for (int i = 0; i < element.getChildNodes().getLength(); i++) {
Node childNode = element.getChildNodes().item(i);
if (childNode instanceof Element) {
@@ -330,33 +465,33 @@ 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, morphShape, cachedFills);
processElement(childElement, idMap, shapeNum, shapes, transform, style, morphShape, cachedBitmaps, shape2);
return;
}
continue;
}
processElement(childElement, idMap, shapeNum, shapes, transform, style, morphShape, cachedFills);
processElement(childElement, idMap, shapeNum, shapes, transform, style, morphShape, cachedBitmaps, shape2);
return;
}
}
}
private void processElement(Element element, Map<String, Element> idMap, int shapeNum, SHAPEWITHSTYLE shapes, Matrix transform, SvgStyle style, boolean morphShape, Map<String, SvgFill> cachedFills) {
private void processElement(Element element, Map<String, Element> idMap, int shapeNum, SHAPEWITHSTYLE shapes, Matrix transform, SvgStyle style, boolean morphShape, Map<String, Integer> cachedBitmaps, boolean shape2) {
if (element.hasAttribute("requiredExtensions") && !element.getAttribute("requiredExtensions").isEmpty()) {
return;
}
String tagName = element.getTagName();
SvgStyle newStyle = new SvgStyle(this, idMap, element, cachedFills);
SvgStyle newStyle = new SvgStyle(this, idMap, element, cachedBitmaps);
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, morphShape, cachedFills);
processSwitch(element, idMap, shapeNum, shapes, transform, style, morphShape, cachedBitmaps, shape2);
} else if ("style".equals(tagName)) {
processStyle(element);
} else if ("g".equals(tagName)) {
processSvgObject(idMap, shapeNum, shapes, element, m2, newStyle, morphShape, cachedFills);
processSvgObject(idMap, shapeNum, shapes, element, m2, newStyle, morphShape, cachedBitmaps, shape2);
} else if ("path".equals(tagName)) {
processPath(shapeNum, shapes, element, m2, newStyle, morphShape);
processPath(shapeNum, shapes, element, m2, newStyle, morphShape, shape2);
} else if ("circle".equals(tagName)) {
processCircle(shapeNum, shapes, element, m2, newStyle, morphShape);
} else if ("ellipse".equals(tagName)) {
@@ -379,12 +514,12 @@ public class SvgImporter {
}
}
private void processSvgObject(Map<String, Element> idMap, int shapeNum, SHAPEWITHSTYLE shapes, Element element, Matrix transform, SvgStyle style, boolean morphShape, Map<String, SvgFill> cachedFills) {
private void processSvgObject(Map<String, Element> idMap, int shapeNum, SHAPEWITHSTYLE shapes, Element element, Matrix transform, SvgStyle style, boolean morphShape, Map<String, Integer> cachedFills, boolean shape2) {
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, morphShape, cachedFills);
processElement(childElement, idMap, shapeNum, shapes, transform, style, morphShape, cachedFills, shape2);
}
}
}
@@ -419,15 +554,19 @@ public class SvgImporter {
}
}
private void processCommands(int shapeNum, SHAPEWITHSTYLE shapes, List<PathCommand> commands, Matrix transform, SvgStyle style, boolean morphShape) {
private void processCommands(int shapeNum, SHAPEWITHSTYLE shapes, List<PathCommand> commands, Matrix transform, SvgStyle style, boolean morphShape, boolean shape2) {
if ("nonzero".equals(style.getFillRule())) {
if (shapeTag instanceof DefineShape4Tag) {
if (!shape2 && (shapeTag instanceof DefineShape4Tag)) {
DefineShape4Tag shape4 = (DefineShape4Tag) shapeTag;
shape4.usesFillWindingRule = true;
}
if (shape2 && (endShape instanceof DefineShape4Tag)) {
DefineShape4Tag shape4 = (DefineShape4Tag) endShape;
shape4.usesFillWindingRule = true;
}
}
Matrix transform2 = transform.preConcatenate(Matrix.getScaleInstance(SWF.unitDivisor));
Point prevPoint = new Point(0, 0);
Point startPoint = prevPoint;
@@ -484,7 +623,7 @@ public class SvgImporter {
scr.fillStyle0 = fillStyle;
} else {
scr.stateFillStyle1 = true;
scr.fillStyle1 = fillStyle;
scr.fillStyle1 = fillStyle;
}
}
if (lineStyle != 0) {
@@ -640,9 +779,7 @@ public class SvgImporter {
shapes.shapeRecords.addAll(newRecords);
}
private void processPath(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style, boolean morphShape) {
String data = childElement.getAttribute("d");
private List<PathCommand> processPathD(String data) {
char command = 0;
Point startPoint = new Point(0, 0);
Point prevCControlPoint = null;
@@ -927,7 +1064,7 @@ public class SvgImporter {
break;
default:
Logger.getLogger(ShapeImporter.class.getName()).log(Level.WARNING, "Unknown command: {0}", command);
return;
return new ArrayList<>();
}
if (cmd != 'C' && cmd != 'S') {
@@ -944,8 +1081,13 @@ public class SvgImporter {
} catch (NumberFormatException e) {
// ignore remaining data as specified in SVG Specification F.2 Error processing
}
return pathCommands;
}
processCommands(shapeNum, shapes, pathCommands, transform, style, morphShape);
private void processPath(int shapeNum, SHAPEWITHSTYLE shapes, Element element, Matrix transform, SvgStyle style, boolean morphShape, boolean shape2) {
String data = element.getAttribute("d");
List<PathCommand> pathCommands = processPathD(data);
processCommands(shapeNum, shapes, pathCommands, transform, style, morphShape, shape2);
}
private double calcAngle(double ux, double uy, double vx, double vy) {
@@ -1043,7 +1185,7 @@ public class SvgImporter {
serz.command = 'Z';
pathCommands.add(serz);
processCommands(shapeNum, shapes, pathCommands, transform, style, morphShape);
processCommands(shapeNum, shapes, pathCommands, transform, style, morphShape, false);
}
private void processRect(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style, boolean morphShape) {
@@ -1154,7 +1296,7 @@ public class SvgImporter {
serz.command = 'Z';
pathCommands.add(serz);
processCommands(shapeNum, shapes, pathCommands, transform, style, morphShape);
processCommands(shapeNum, shapes, pathCommands, transform, style, morphShape, false);
}
private void processLine(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style, boolean morphShape) {
@@ -1182,8 +1324,8 @@ public class SvgImporter {
pathCommands.add(cer);
processCommands(shapeNum, shapes, pathCommands, transform, style, morphShape);
}
processCommands(shapeNum, shapes, pathCommands, transform, style, morphShape, false);
}
private void processPolygon(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style, boolean morphShape) {
processPolyline(shapeNum, shapes, childElement, transform, style, true, morphShape);
@@ -1243,7 +1385,7 @@ public class SvgImporter {
pathCommands.add(serz);
}
processCommands(shapeNum, shapes, pathCommands, transform, style, morphShape);
processCommands(shapeNum, shapes, pathCommands, transform, style, morphShape, false);
}
//Stub for w3 test. TODO: refactor and move to test directory. It's here because of easy access - compiling single file
@@ -1776,7 +1918,7 @@ public class SvgImporter {
SvgLineJoin lineJoin = style.getStrokeLineJoin();
if (lineStyle instanceof LINESTYLE2) {
LINESTYLE2 lineStyle2 = (LINESTYLE2) lineStyle;
String vectorEffect = style.getVectorEffect();
if ("non-scaling-stroke".equals(vectorEffect)) {
lineStyle2.noHScaleFlag = true;
@@ -1799,7 +1941,7 @@ public class SvgImporter {
morph2.usesScalingStrokes = true;
}
}
int swfCap = lineCap == SvgLineCap.BUTT ? LINESTYLE2.NO_CAP
: lineCap == SvgLineCap.ROUND ? LINESTYLE2.ROUND_CAP
: lineCap == SvgLineCap.SQUARE ? LINESTYLE2.SQUARE_CAP : 0;

View File

@@ -47,17 +47,17 @@ class SvgStyle {
private final Map<String, Element> idMap;
private final Map<String, SvgFill> cachedFills;
private final Map<String, Integer> cachedBitmaps;
private final double epsilon = 0.001;
private final Random random = new Random();
public SvgStyle(SvgImporter importer, Map<String, Element> idMap, Element element, Map<String, SvgFill> cachedFills) {
public SvgStyle(SvgImporter importer, Map<String, Element> idMap, Element element, Map<String, Integer> cachedBitmaps) {
this.importer = importer;
this.idMap = idMap;
this.element = element;
this.cachedFills = cachedFills;
this.cachedBitmaps = cachedBitmaps;
}
private Map<String, String> getStyleAttributeValues(Element element) {
@@ -470,7 +470,7 @@ class SvgStyle {
Node node = stopNodes.item(i);
if (node instanceof Element) {
Element stopEl = (Element) node;
SvgStyle newStyle = new SvgStyle(importer, idMap, stopEl, cachedFills);
SvgStyle newStyle = new SvgStyle(importer, idMap, stopEl, cachedBitmaps);
String offsetStr = stopEl.getAttribute("offset");
double offset = importer.parseNumberOrPercent(offsetStr);
@@ -563,21 +563,26 @@ class SvgStyle {
if (mPat.matches()) {
String elementId = mPat.group(1);
if (cachedFills.containsKey(elementId)) {
return cachedFills.get(elementId);
}
Element e = idMap.get(elementId);
Element e = idMap.get(elementId);
if (e != null) {
if (cachedBitmaps.containsKey(elementId)) {
SvgBitmapFill bitmapFill = new SvgBitmapFill();
int bitmapId = cachedBitmaps.get(elementId);
bitmapFill.characterId = bitmapId;
if (e.hasAttribute("patternTransform")) {
bitmapFill.patternTransform = e.getAttribute("patternTransform");
}
return bitmapFill;
}
String tagName = e.getTagName();
if ("linearGradient".equals(tagName)) {
SvgFill ret = parseGradient(idMap, e);
cachedFills.put(elementId, ret);
return ret;
}
if ("radialGradient".equals(tagName)) {
SvgFill ret = parseGradient(idMap, e);
cachedFills.put(elementId, ret);
return ret;
}
@@ -586,9 +591,14 @@ class SvgStyle {
NodeList childNodes = e.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
if (childNodes.item(i) instanceof Element) {
if (element != null) {
if ("animateTransform".equals(((Element)childNodes.item(i)).getTagName())) {
continue;
}
if (element != null) {
element = null;
break;
break;
}
element = (Element) childNodes.item(i);
@@ -609,7 +619,7 @@ class SvgStyle {
bitmapFill.patternTransform = e.getAttribute("patternTransform");
}
cachedFills.put(elementId, bitmapFill);
cachedBitmaps.put(elementId, imageTag.characterID);
return bitmapFill;
} catch (IOException ex) {
Logger.getLogger(SvgStyle.class.getName()).log(Level.SEVERE, null, ex);

View File

@@ -213,6 +213,8 @@ public class FILLSTYLE implements NeedsCharacters, FieldChangeObserver, Serializ
}
morphFillStyle.fillStyleType = fillStyleType;
if (gradient != null) {
morphFillStyle.startGradientMatrix = gradientMatrix;
morphFillStyle.endGradientMatrix = gradientMatrix;
morphFillStyle.gradient = gradient.toMorphGradient();
}
@@ -239,6 +241,8 @@ public class FILLSTYLE implements NeedsCharacters, FieldChangeObserver, Serializ
}
morphFillStyle.fillStyleType = fillStyleType;
if (gradient != null) {
morphFillStyle.startGradientMatrix = gradientMatrix;
morphFillStyle.endGradientMatrix = endFillStyle.gradientMatrix;
morphFillStyle.gradient = gradient.toMorphGradient(endFillStyle.gradient);
}

View File

@@ -67,8 +67,8 @@ public class FOCALGRADIENT extends GRADIENT implements Serializable {
morphGradient.spreadMode = spreadMode;
morphGradient.gradientRecords = new MORPHGRADRECORD[gradientRecords.length];
for (int i = 0; i < gradientRecords.length; i++) {
morphGradient.gradientRecords[i] = gradientRecords[i].toMorphGradRecord();
}
morphGradient.gradientRecords[i] = gradientRecords[i].toMorphGradRecord(endGradient.gradientRecords[i]);
}
morphGradient.startFocalPoint = focalPoint;
if (endGradient instanceof FOCALGRADIENT) {
morphGradient.endFocalPoint = ((FOCALGRADIENT)endGradient).focalPoint;

View File

@@ -101,7 +101,7 @@ public class GRADIENT implements Serializable {
morphGradient.spreadMode = spreadMode;
morphGradient.gradientRecords = new MORPHGRADRECORD[gradientRecords.length];
for (int i = 0; i < gradientRecords.length; i++) {
morphGradient.gradientRecords[i] = gradientRecords[i].toMorphGradRecord();
morphGradient.gradientRecords[i] = gradientRecords[i].toMorphGradRecord(endGradient.gradientRecords[i]);
}
if (endGradient instanceof FOCALGRADIENT) {
((MORPHFOCALGRADIENT)morphGradient).startFocalPoint = 0;