svg import improved

This commit is contained in:
honfika@gmail.com
2015-12-18 12:24:56 +01:00
parent 57f9cbe2e7
commit 0f416b0944
4 changed files with 550 additions and 175 deletions

View File

@@ -16,7 +16,6 @@
*/
package com.jpexs.decompiler.flash.exporters.commonshape;
import com.jpexs.decompiler.flash.importers.SvgPathReader;
import com.jpexs.decompiler.flash.types.MATRIX;
import java.awt.geom.AffineTransform;
@@ -241,45 +240,107 @@ public final class Matrix implements Cloneable {
+ rotateSkew1 + ", " + scaleY + ", " + translateX + ", " + translateY + ")";
}
public static Matrix parseSvgMatrix(String matrixStr, double translateDivisor, double unitDivisor) {
matrixStr = matrixStr.trim();
if (matrixStr.startsWith("matrix")) {
matrixStr = matrixStr.substring(6).trim();
if (matrixStr.startsWith("(") && matrixStr.endsWith(")")) {
matrixStr = matrixStr.substring(1, matrixStr.length() - 1);
SvgPathReader reader = new SvgPathReader(matrixStr);
double scaleX = reader.readDouble() * unitDivisor;
double rotateSkew0 = reader.readDouble() * unitDivisor;
double rotateSkew1 = reader.readDouble() * unitDivisor;
double scaleY = reader.readDouble() * unitDivisor;
double translateX = reader.readDouble() * translateDivisor;
double translateY = reader.readDouble() * translateDivisor;
Matrix result = new Matrix();
result.translateX = translateX;
result.translateY = translateY;
result.rotateSkew0 = rotateSkew0;
result.rotateSkew1 = rotateSkew1;
result.scaleX = scaleX;
result.scaleY = scaleY;
return result;
}
} else if (matrixStr.startsWith("translate")) {
matrixStr = matrixStr.substring(9).trim();
if (matrixStr.startsWith("(") && matrixStr.endsWith(")")) {
matrixStr = matrixStr.substring(1, matrixStr.length() - 1);
SvgPathReader reader = new SvgPathReader(matrixStr);
double translateX = reader.readDouble() * translateDivisor;
double translateY = reader.readDouble() * translateDivisor;
Matrix result = new Matrix();
result.translateX = translateX;
result.translateY = translateY;
result.scaleX = unitDivisor;
result.scaleY = unitDivisor;
return result;
public static Matrix parseSvgMatrix(String transformStr, double translateDivisor, double unitDivisor) {
Matrix ret = new Matrix();
while (transformStr.length() > 0) {
String funcName = transformStr.split("\\(")[0];
transformStr = transformStr.substring(funcName.length() + 1);
String params = transformStr.split("\\)")[0];
transformStr = transformStr.substring(params.length() + 1);
String[] args = params.split(",");
funcName = funcName.trim();
switch (funcName) {
case "matrix":
if (args.length == 6) {
double scaleX = Double.parseDouble(args[0].trim()) * unitDivisor;
double rotateSkew0 = Double.parseDouble(args[1].trim()) * unitDivisor;
double rotateSkew1 = Double.parseDouble(args[2].trim()) * unitDivisor;
double scaleY = Double.parseDouble(args[3].trim()) * unitDivisor;
double translateX = Double.parseDouble(args[4].trim()) * translateDivisor;
double translateY = Double.parseDouble(args[5].trim()) * translateDivisor;
Matrix result = new Matrix();
result.translateX = translateX;
result.translateY = translateY;
result.rotateSkew0 = rotateSkew0;
result.rotateSkew1 = rotateSkew1;
result.scaleX = scaleX;
result.scaleY = scaleY;
ret = ret.concatenate(result);
}
break;
case "translate":
if (args.length == 1 || args.length == 2) {
double translateX = Double.parseDouble(args[0].trim()) * translateDivisor;
double translateY = 0;
if (args.length == 2) {
translateY = Double.parseDouble(args[1].trim()) * translateDivisor;
}
Matrix result = new Matrix();
result.translateX = translateX;
result.translateY = translateY;
result.scaleX = unitDivisor;
result.scaleY = unitDivisor;
ret = ret.concatenate(result);
}
break;
case "scale":
if (args.length == 1 || args.length == 2) {
double scaleX = Double.parseDouble(args[0].trim());
double scaleY = scaleX;
if (args.length == 2) {
scaleY = Double.parseDouble(args[1].trim());
}
Matrix result = new Matrix();
result.scaleX = scaleX;
result.scaleY = scaleY;
ret = ret.concatenate(result);
}
break;
case "skewX":
if (args.length == 1) {
double angle = Double.parseDouble(args[0].trim()) * Math.PI / 180;
Matrix result = new Matrix();
result.rotateSkew1 = Math.tan(angle);
ret = ret.concatenate(result);
}
break;
case "skewY":
if (args.length == 1) {
double angle = Double.parseDouble(args[0].trim()) * Math.PI / 180;
Matrix result = new Matrix();
result.rotateSkew0 = Math.tan(angle);
ret = ret.concatenate(result);
}
break;
case "rotate":
if (args.length == 1 || args.length == 3) {
double rotateAngle = Double.parseDouble(args[0].trim());
double tx = 0;
double ty = 0;
if (args.length > 1) {
tx = Double.parseDouble(args[1].trim());
ty = Double.parseDouble(args[2].trim());
}
double angleRad = -rotateAngle * Math.PI / 180;
Matrix result = new Matrix();
result.rotateSkew0 = -Math.sin(angleRad);
result.rotateSkew1 = Math.sin(angleRad);
result.scaleX = Math.cos(angleRad);
result.scaleY = Math.cos(angleRad);
result = result.preConcatenate(getTranslateInstance(tx * translateDivisor, ty * translateDivisor))
.concatenate(getTranslateInstance(-tx * translateDivisor, -ty * translateDivisor));
ret = ret.concatenate(result);
}
break;
}
}
return null;
return ret;
}
private double roundPixels400(double pixels) {

View File

@@ -54,7 +54,10 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
@@ -72,7 +75,11 @@ import org.xml.sax.SAXException;
*/
public class ShapeImporter {
private boolean cubicWarning = false;
private final Set<String> shownWarnings = new HashSet<>();
private static final Color TRANSPARENT = new Color(0, true);
private final Random random = new Random();
public Tag importImage(ShapeTag st, byte[] newData) throws IOException {
return importImage(st, newData, 0, true);
@@ -212,58 +219,56 @@ public class ShapeImporter {
Element childElement = (Element) childNode;
String tagName = childElement.getTagName();
SvgStyle newStyle = style.apply(childElement);
Matrix m = Matrix.parseSvgMatrix(childElement.getAttribute("transform"), SWF.unitDivisor, 1);
Matrix m2 = m == null ? transform : m.concatenate(transform);
if ("g".equals(tagName)) {
Matrix m = Matrix.parseSvgMatrix(childElement.getAttribute("transform"), SWF.unitDivisor, 1);
Matrix m2 = m == null ? transform : m.concatenate(transform);
processSvgObject(shapeNum, shapes, childElement, m2, newStyle);
} else if ("path".equals(tagName)) {
processPath(shapeNum, shapes, childElement, transform, newStyle);
processPath(shapeNum, shapes, childElement, m2, newStyle);
} else {
showWarning(tagName + "tagNotSupported", "The SVG tag '" + tagName + "' is not supported.");
}
}
}
}
private void processPath(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style) {
String data = childElement.getAttribute("d");
char command = 0;
private void processCommands(int shapeNum, SHAPEWITHSTYLE shapes, List<PathCommand> commands, Matrix transform, SvgStyle style) {
Point prevPoint = new Point(0, 0);
Point startPoint = prevPoint;
Point prevCControlPoint = null;
double x0 = 0;
double y0 = 0;
boolean newShape = true;
SvgPathReader pathReader = new SvgPathReader(data);
while (pathReader.hasNext()) {
char newCommand;
if ((newCommand = pathReader.readCommand()) != 0) {
command = newCommand;
}
StyleChangeRecord scrStyle = getStyleChangeRecord(shapeNum, style);
int fillStyle = scrStyle.fillStyle1;
int lineStyle = scrStyle.lineStyle;
scrStyle.stateFillStyle0 = true;
scrStyle.stateFillStyle1 = true;
scrStyle.stateLineStyle = true;
scrStyle.fillStyle0 = 0;
scrStyle.fillStyle1 = 0;
scrStyle.lineStyle = 0;
shapes.shapeRecords.add(scrStyle);
boolean isRelative = Character.isLowerCase(command);
for (PathCommand command : commands) {
double x = x0;
double y = y0;
Point p = null;
char cmd = Character.toUpperCase(command);
char cmd = Character.toUpperCase(command.command);
switch (cmd) {
case 'M':
StyleChangeRecord scr;
if (newShape) {
newShape = false;
scr = getStyleChangeRecord(shapeNum, style);
} else {
scr = new StyleChangeRecord();
StyleChangeRecord scr = new StyleChangeRecord();
if (fillStyle != 0) {
scr.stateFillStyle1 = true;
scr.fillStyle1 = fillStyle;
}
if (lineStyle != 0) {
scr.lineStyle = lineStyle;
scr.stateLineStyle = true;
}
x = pathReader.readDouble();
y = pathReader.readDouble();
if (isRelative) {
x += x0;
y += y0;
}
x = command.params[0];
y = command.params[1];
p = transform.transform(x, y);
scr.moveDeltaX = (int) Math.round(p.x);
@@ -287,12 +292,8 @@ public class ShapeImporter {
break;
case 'L':
StraightEdgeRecord serl = new StraightEdgeRecord();
x = pathReader.readDouble();
y = pathReader.readDouble();
if (isRelative) {
x += x0;
y += y0;
}
x = command.params[0];
y = command.params[1];
p = transform.transform(x, y);
serl.deltaX = (int) Math.round(p.x - prevPoint.x);
@@ -300,14 +301,12 @@ public class ShapeImporter {
prevPoint = p;
System.out.println("L" + serl.deltaX + "," + serl.deltaY);
serl.generalLineFlag = true;
serl.simplify();
shapes.shapeRecords.add(serl);
break;
case 'H':
StraightEdgeRecord serh = new StraightEdgeRecord();
x = pathReader.readDouble();
if (isRelative) {
x += x0;
}
x = command.params[0];
p = transform.transform(x, y);
serh.deltaX = (int) Math.round(p.x - prevPoint.x);
@@ -317,38 +316,27 @@ public class ShapeImporter {
break;
case 'V':
StraightEdgeRecord serv = new StraightEdgeRecord();
y = pathReader.readDouble();
if (isRelative) {
y += y0;
}
y = command.params[0];
p = transform.transform(x, y);
serv.deltaY = (int) Math.round(p.x - prevPoint.x);
serv.deltaY = (int) Math.round(p.y - prevPoint.y);
prevPoint = p;
System.out.println("V" + serv.deltaX);
System.out.println("V" + serv.deltaY);
serv.vertLineFlag = true;
shapes.shapeRecords.add(serv);
break;
case 'Q':
CurvedEdgeRecord cer = new CurvedEdgeRecord();
x = pathReader.readDouble();
y = pathReader.readDouble();
if (isRelative) {
x += x0;
y += y0;
}
x = command.params[0];
y = command.params[1];
p = transform.transform(x, y);
cer.controlDeltaX = (int) Math.round(p.x - prevPoint.x);
cer.controlDeltaY = (int) Math.round(p.y - prevPoint.y);
prevPoint = p;
x = pathReader.readDouble();
y = pathReader.readDouble();
if (isRelative) {
x += x0;
y += y0;
}
x = command.params[2];
y = command.params[3];
p = transform.transform(x, y);
cer.anchorDeltaX = (int) Math.round(p.x - prevPoint.x);
@@ -358,49 +346,24 @@ public class ShapeImporter {
shapes.shapeRecords.add(cer);
break;
case 'C':
case 'S':
if (!cubicWarning) {
cubicWarning = true;
Logger.getLogger(ShapeImporter.class.getName()).log(Level.WARNING, "Cubic curves are not supported by Flash.");
}
showWarning("cubicCurvesNotSupported", "Cubic curves are not supported by Flash.");
// create at least something...
Point pStart = prevPoint;
Point pControl1;
if (cmd == 'C') {
x = pathReader.readDouble();
y = pathReader.readDouble();
if (isRelative) {
x += x0;
y += y0;
}
x = command.params[0];
y = command.params[1];
pControl1 = transform.transform(x, y);
} else {
if (prevCControlPoint != null) {
pControl1 = new Point(2 * pStart.x - prevCControlPoint.x, 2 * pStart.y - prevCControlPoint.y);
} else {
pControl1 = pStart;
}
}
pControl1 = transform.transform(x, y);
x = pathReader.readDouble();
y = pathReader.readDouble();
if (isRelative) {
x += x0;
y += y0;
}
x = command.params[2];
y = command.params[3];
Point pControl2 = transform.transform(x, y);
prevCControlPoint = pControl2;
x = pathReader.readDouble();
y = pathReader.readDouble();
if (isRelative) {
x += x0;
y += y0;
}
x = command.params[4];
y = command.params[5];
p = transform.transform(x, y);
@@ -430,13 +393,216 @@ public class ShapeImporter {
return;
}
if (cmd != 'C') {
x0 = x;
y0 = y;
}
}
private void processPath(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style) {
String data = childElement.getAttribute("d");
char command = 0;
Point startPoint = new Point(0, 0);
Point prevCControlPoint = null;
Point prevQControlPoint = null;
double x0 = 0;
double y0 = 0;
List<PathCommand> pathCommands = new ArrayList<>();
SvgPathReader pathReader = new SvgPathReader(data);
while (pathReader.hasNext()) {
char newCommand;
if ((newCommand = pathReader.readCommand()) != 0) {
command = newCommand;
}
boolean isRelative = Character.isLowerCase(command);
double x = x0;
double y = y0;
char cmd = Character.toUpperCase(command);
switch (cmd) {
case 'M':
PathCommand scr = new PathCommand();
scr.command = 'M';
x = pathReader.readDouble();
y = pathReader.readDouble();
if (isRelative) {
x += x0;
y += y0;
}
scr.params = new double[]{x, y};
pathCommands.add(scr);
startPoint = new Point(x, y);
command = isRelative ? 'l' : 'L';
break;
case 'Z':
PathCommand serz = new PathCommand();
serz.command = 'Z';
x = startPoint.x;
y = startPoint.y;
serz.params = new double[]{x, y};
pathCommands.add(serz);
break;
case 'L':
PathCommand serl = new PathCommand();
serl.command = 'L';
x = pathReader.readDouble();
y = pathReader.readDouble();
if (isRelative) {
x += x0;
y += y0;
}
serl.params = new double[]{x, y};
pathCommands.add(serl);
break;
case 'H':
PathCommand serh = new PathCommand();
serh.command = 'H';
x = pathReader.readDouble();
if (isRelative) {
x += x0;
}
serh.params = new double[]{x};
pathCommands.add(serh);
break;
case 'V':
PathCommand serv = new PathCommand();
serv.command = 'V';
y = pathReader.readDouble();
if (isRelative) {
y += y0;
}
serv.params = new double[]{y};
pathCommands.add(serv);
break;
case 'Q':
case 'T':
PathCommand cer = new PathCommand();
cer.command = 'Q';
Point pControl;
if (cmd == 'Q') {
x = pathReader.readDouble();
y = pathReader.readDouble();
if (isRelative) {
x += x0;
y += y0;
}
pControl = new Point(x, y);
} else {
if (prevQControlPoint != null) {
pControl = new Point(2 * x0 - prevQControlPoint.x, 2 * y0 - prevQControlPoint.y);
} else {
pControl = new Point(x0, y0);
}
}
prevQControlPoint = pControl;
x = pathReader.readDouble();
y = pathReader.readDouble();
if (isRelative) {
x += x0;
y += y0;
}
cer.params = new double[]{pControl.x, pControl.y, x, y};
pathCommands.add(cer);
break;
case 'C':
case 'S':
showWarning("cubicCurvesNotSupported", "Cubic curves are not supported by Flash.");
// create at least something...
Point pControl1;
if (cmd == 'C') {
x = pathReader.readDouble();
y = pathReader.readDouble();
if (isRelative) {
x += x0;
y += y0;
}
pControl1 = new Point(x, y);
} else {
if (prevCControlPoint != null) {
pControl1 = new Point(2 * x0 - prevCControlPoint.x, 2 * y0 - prevCControlPoint.y);
} else {
pControl1 = new Point(x0, y0);
}
}
x = pathReader.readDouble();
y = pathReader.readDouble();
if (isRelative) {
x += x0;
y += y0;
}
Point pControl2 = new Point(x, y);
prevCControlPoint = pControl2;
x = pathReader.readDouble();
y = pathReader.readDouble();
if (isRelative) {
x += x0;
y += y0;
}
PathCommand cerc = new PathCommand();
cerc.command = 'C';
cerc.params = new double[]{pControl1.x, pControl1.y, pControl2.x, pControl2.y, x, y};
pathCommands.add(cerc);
break;
case 'A':
double rx = pathReader.readDouble();
double ry = pathReader.readDouble();
double xRot = pathReader.readDouble();
int largeFlag = (int) pathReader.readDouble();
int sweepFlag = (int) pathReader.readDouble();
x = pathReader.readDouble();
y = pathReader.readDouble();
if (isRelative) {
x += x0;
y += y0;
}
// todo: draw arc, now draw only a line
PathCommand sera = new PathCommand();
sera.command = 'L';
sera.params = new double[]{x, y};
pathCommands.add(sera);
break;
default:
Logger.getLogger(ShapeImporter.class.getName()).log(Level.WARNING, "Unknown command: {0}", command);
return;
}
if (cmd != 'C' && cmd != 'S') {
prevCControlPoint = null;
}
if (cmd != 'Q' && cmd != 'T') {
prevQControlPoint = null;
}
x0 = x;
y0 = y;
}
processCommands(shapeNum, shapes, pathCommands, transform, style);
}
private StyleChangeRecord getStyleChangeRecord(int shapeNum, SvgStyle style) {
@@ -462,9 +628,34 @@ public class ShapeImporter {
Color lineColor = style.getStrokeColorWithOpacity();
if (lineColor != null) {
scr.lineStyles.lineStyles = new LINESTYLE[1];
scr.lineStyles.lineStyles[0] = shapeNum <= 3 ? new LINESTYLE() : new LINESTYLE2();
scr.lineStyles.lineStyles[0].color = shapeNum >= 3 ? new RGBA(lineColor) : new RGB(lineColor);
scr.lineStyles.lineStyles[0].width = (int) Math.round(style.strokeWidth * SWF.unitDivisor);
LINESTYLE lineStyle = shapeNum <= 3 ? new LINESTYLE() : new LINESTYLE2();;
lineStyle.color = shapeNum >= 3 ? new RGBA(lineColor) : new RGB(lineColor);
lineStyle.width = (int) Math.round(style.strokeWidth * SWF.unitDivisor);
SvgLineCap lineCap = style.strokeLineCap;
SvgLineJoin lineJoin = style.strokeLineJoin;
if (lineStyle instanceof LINESTYLE2) {
LINESTYLE2 lineStyle2 = (LINESTYLE2) lineStyle;
int swfCap = lineCap == SvgLineCap.BUTT ? LINESTYLE2.NO_CAP
: lineCap == SvgLineCap.ROUND ? LINESTYLE2.ROUND_CAP
: lineCap == SvgLineCap.SQUARE ? LINESTYLE2.SQUARE_CAP : 0;
lineStyle2.startCapStyle = swfCap;
lineStyle2.endCapStyle = swfCap;
int swfJoin = lineJoin == SvgLineJoin.MITER ? LINESTYLE2.MITER_JOIN
: lineJoin == SvgLineJoin.ROUND ? LINESTYLE2.ROUND_JOIN
: lineJoin == SvgLineJoin.BEVEL ? LINESTYLE2.BEVEL_JOIN : 0;
lineStyle2.joinStyle = swfJoin;
lineStyle2.miterLimitFactor = (int) style.strokeMiterLimit;
} else {
if (lineCap != SvgLineCap.ROUND) {
showWarning("lineCapNotSupported", "LineCap style not supported in shape " + shapeNum);
}
if (lineJoin != SvgLineJoin.ROUND) {
showWarning("lineJoinNotSupported", "LineJoin style not supported in shape " + shapeNum);
}
}
scr.lineStyles.lineStyles[0] = lineStyle;
scr.lineStyle = 1;
} else {
scr.lineStyles.lineStyles = new LINESTYLE[0];
@@ -482,7 +673,7 @@ public class ShapeImporter {
// todo: honfika: named colors: http://www.w3.org/TR/SVG/types.html#ColorKeywords
switch (rgbStr) {
case "none":
return new Color(0, true);
return TRANSPARENT;
}
if (rgbStr.startsWith("#")) {
@@ -493,12 +684,30 @@ public class ShapeImporter {
int i = Integer.parseInt(s, 16);
return new Color(i, false);
} else {
showWarning("fillNotSupported", "Only solid fills are supported. Random color assigned.");
return new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256));
}
return null;
}
class SvgStyle {
class PathCommand {
public char command;
public double[] params;
}
enum SvgLineCap {
BUTT, ROUND, SQUARE
}
enum SvgLineJoin {
MITER, ROUND, BEVEL
}
class SvgStyle implements Cloneable {
public Color fillColor;
@@ -510,12 +719,24 @@ public class ShapeImporter {
public double strokeWidth;
public double strokeOpacity;
public SvgLineCap strokeLineCap;
public SvgLineJoin strokeLineJoin;
public double strokeMiterLimit;
public SvgStyle() {
fillColor = Color.BLACK;
fillOpacity = 1;
strokeColor = null;
strokeWidth = 1;
strokeOpacity = 1;
opacity = 1;
strokeLineCap = SvgLineCap.BUTT;
strokeLineJoin = SvgLineJoin.MITER;
strokeMiterLimit = 4;
}
public Color getFillColorWithOpacity() {
@@ -536,7 +757,7 @@ public class ShapeImporter {
return null;
}
int opacity = (int) Math.round(this.opacity * 255);
int opacity = (int) Math.round(this.opacity * strokeOpacity * 255);
if (opacity == 255) {
return strokeColor;
}
@@ -544,47 +765,127 @@ public class ShapeImporter {
return new Color(strokeColor.getRed(), strokeColor.getGreen(), strokeColor.getBlue(), opacity);
}
@Override
public SvgStyle clone() {
try {
SvgStyle ret = (SvgStyle) super.clone();
return ret;
} catch (CloneNotSupportedException ex) {
throw new RuntimeException();
}
}
private void applyStyle(SvgStyle style, String name, String value) {
if (value == null || value.length() == 0) {
return;
}
switch (name) {
case "fill": {
Color fillColor = parseColor(value);
if (fillColor != null) {
style.fillColor = fillColor == TRANSPARENT ? null : fillColor;
}
}
break;
case "fill-opacity": {
double opacity = Double.parseDouble(value);
style.fillOpacity = opacity;
}
break;
case "stroke": {
Color strokeColor = parseColor(value);
if (strokeColor != null) {
style.strokeColor = strokeColor == TRANSPARENT ? null : strokeColor;
}
}
break;
case "stroke-width": {
double strokeWidth = Double.parseDouble(value);
style.strokeWidth = strokeWidth;
}
break;
case "stroke-opacity": {
double opacity = Double.parseDouble(value);
style.strokeOpacity = opacity;
}
break;
case "stroke-linecap": {
switch (value) {
case "butt":
style.strokeLineCap = SvgLineCap.BUTT;
break;
case "round":
style.strokeLineCap = SvgLineCap.ROUND;
break;
case "square":
style.strokeLineCap = SvgLineCap.SQUARE;
break;
}
}
break;
case "stroke-linejoin": {
switch (value) {
case "miter":
style.strokeLineJoin = SvgLineJoin.MITER;
break;
case "round":
style.strokeLineJoin = SvgLineJoin.ROUND;
break;
case "bevel":
style.strokeLineJoin = SvgLineJoin.BEVEL;
break;
}
}
break;
case "stroke-miterlimit": {
double strokeMiterLimit = Double.parseDouble(value);
style.strokeMiterLimit = strokeMiterLimit;
}
case "opacity": {
double opacity = Double.parseDouble(value);
style.opacity = opacity;
}
break;
}
}
private SvgStyle apply(Element element) {
SvgStyle result = new SvgStyle();
result.fillColor = fillColor;
result.fillOpacity = fillOpacity;
result.strokeColor = strokeColor;
result.strokeWidth = strokeWidth;
SvgStyle result = clone();
String attr = element.getAttribute("fill");
Color fillColor = parseColor(attr);
if (fillColor != null) {
result.fillColor = fillColor;
String[] styles = new String[]{
"fill", "fill-opacity",
"stroke", "stroke-width", "stroke-opacity", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit",
"opacity"
};
for (String style : styles) {
if (element.hasAttribute(style)) {
String attr = element.getAttribute(style);
applyStyle(result, style, attr);
}
}
attr = element.getAttribute("fill-opacity");
if (attr.length() > 0) {
double opacity = Double.parseDouble(attr);
result.fillOpacity = opacity;
}
attr = element.getAttribute("stroke");
Color strokeColor = parseColor(attr);
if (strokeColor != null) {
result.strokeColor = strokeColor;
}
attr = element.getAttribute("stroke-width");
if (attr.length() > 0) {
double strokeWidth = Double.parseDouble(attr);
result.strokeWidth = strokeWidth;
}
attr = element.getAttribute("opacity");
if (attr.length() > 0) {
double opacity = Double.parseDouble(attr);
result.opacity = opacity;
if (element.hasAttribute("style")) {
String[] styleDefs = element.getAttribute("style").split(";");
for (String styleDef : styleDefs) {
String[] parts = styleDef.split(":", 2);
applyStyle(result, parts[0], parts[1].trim());
}
}
return result;
}
}
private void showWarning(String name, String text) {
if (!shownWarnings.contains(name)) {
Logger.getLogger(ShapeImporter.class.getName()).log(Level.WARNING, text);
shownWarnings.add(name);
}
}
public static int getShapeTagType(String format) {
int res = 0;
switch (format) {

View File

@@ -49,6 +49,7 @@ public class SvgPathReader {
return 0;
}
readWhiteSpaces();
char ch = peek();
char command = 0;
if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) {
@@ -63,6 +64,7 @@ public class SvgPathReader {
public double readDouble() {
int startPos = pos;
readWhiteSpaces();
if (peek() == '-') {
pos++;
}
@@ -89,6 +91,17 @@ public class SvgPathReader {
return result;
}
private void readWhiteSpaces() {
while (hasNext()) {
char ch = peek();
if (ch != ' ' && ch != '\r' && ch != '\n') {
return;
}
readChar();
}
}
private void readSeparators() {
while (hasNext()) {
char ch = peek();

View File

@@ -34,6 +34,12 @@ public class LINESTYLE2 extends LINESTYLE implements Serializable {
@SWFType(value = BasicType.UB, count = 2)
public int joinStyle;
public static final int ROUND_CAP = 0;
public static final int NO_CAP = 1;
public static final int SQUARE_CAP = 2;
public static final int ROUND_JOIN = 0;
public static final int BEVEL_JOIN = 1;
@@ -57,12 +63,6 @@ public class LINESTYLE2 extends LINESTYLE implements Serializable {
@SWFType(value = BasicType.UB, count = 2)
public int endCapStyle;
public static final int ROUND_CAP = 0;
public static final int NO_CAP = 1;
public static final int SQUARE_CAP = 2;
@SWFType(BasicType.UI16)
@Conditional(value = "joinStyle", options = MITER_JOIN)
public int miterLimitFactor;