mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-06-02 11:54:36 +00:00
svg style inheritance (not ready)
This commit is contained in:
@@ -24,10 +24,6 @@ import java.awt.Color;
|
||||
*/
|
||||
class SvgColor extends SvgFill {
|
||||
|
||||
public static final Color TRANSPARENT = new Color(0, true);
|
||||
|
||||
public static final SvgColor SVG_TRANSPARENT = new SvgColor(TRANSPARENT);
|
||||
|
||||
public Color color;
|
||||
|
||||
public SvgColor(int r, int g, int b, int opacity) {
|
||||
@@ -54,8 +50,6 @@ class SvgColor extends SvgFill {
|
||||
|
||||
// named colors from: http://www.w3.org/TR/SVG/types.html#ColorKeywords
|
||||
switch (colorString) {
|
||||
case "none":
|
||||
return SVG_TRANSPARENT;
|
||||
case "aliceblue":
|
||||
return new SvgColor(240, 248, 255);
|
||||
case "antiquewhite":
|
||||
|
||||
@@ -386,86 +386,24 @@ public class SvgImporter {
|
||||
|
||||
List<PathCommand> pathCommands = new ArrayList<>();
|
||||
SvgPathReader pathReader = new SvgPathReader(data);
|
||||
while (pathReader.hasNext()) {
|
||||
char newCommand;
|
||||
if ((newCommand = pathReader.readCommand()) != 0) {
|
||||
command = newCommand;
|
||||
}
|
||||
try {
|
||||
while (pathReader.hasNext()) {
|
||||
char newCommand;
|
||||
if ((newCommand = pathReader.readCommand()) != 0) {
|
||||
command = newCommand;
|
||||
}
|
||||
|
||||
boolean isRelative = Character.isLowerCase(command);
|
||||
boolean isRelative = Character.isLowerCase(command);
|
||||
|
||||
double x = x0;
|
||||
double y = y0;
|
||||
double x = x0;
|
||||
double y = y0;
|
||||
|
||||
char cmd = Character.toUpperCase(command);
|
||||
switch (cmd) {
|
||||
case 'M':
|
||||
PathCommand scr = new PathCommand();
|
||||
scr.command = 'M';
|
||||
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;
|
||||
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) {
|
||||
@@ -473,31 +411,23 @@ public class SvgImporter {
|
||||
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);
|
||||
}
|
||||
scr.params = new double[]{x, y};
|
||||
|
||||
prevQControlPoint = pControl;
|
||||
x = pathReader.readDouble();
|
||||
y = pathReader.readDouble();
|
||||
if (isRelative) {
|
||||
x += x0;
|
||||
y += y0;
|
||||
}
|
||||
pathCommands.add(scr);
|
||||
startPoint = new Point(x, y);
|
||||
|
||||
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') {
|
||||
command = isRelative ? 'l' : 'L';
|
||||
break;
|
||||
case 'Z':
|
||||
PathCommand serz = new PathCommand();
|
||||
serz.command = 'Z';
|
||||
x = startPoint.x;
|
||||
y = startPoint.y;
|
||||
pathCommands.add(serz);
|
||||
break;
|
||||
case 'L':
|
||||
PathCommand serl = new PathCommand();
|
||||
serl.command = 'L';
|
||||
x = pathReader.readDouble();
|
||||
y = pathReader.readDouble();
|
||||
if (isRelative) {
|
||||
@@ -505,174 +435,248 @@ public class SvgImporter {
|
||||
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 fi = pathReader.readDouble() * Math.PI / 180;
|
||||
boolean largeFlag = (int) pathReader.readDouble() != 0;
|
||||
boolean sweepFlag = (int) pathReader.readDouble() != 0;
|
||||
|
||||
x = pathReader.readDouble();
|
||||
y = pathReader.readDouble();
|
||||
if (isRelative) {
|
||||
x += x0;
|
||||
y += y0;
|
||||
}
|
||||
|
||||
if (rx == 0 || ry == 0) {
|
||||
// straight line to (x, y)
|
||||
PathCommand sera = new PathCommand();
|
||||
sera.command = 'L';
|
||||
sera.params = new double[]{x, y};
|
||||
pathCommands.add(sera);
|
||||
} else {
|
||||
rx = Math.abs(rx);
|
||||
ry = Math.abs(ry);
|
||||
|
||||
double x1 = x0;
|
||||
double y1 = y0;
|
||||
double x2 = x;
|
||||
double y2 = y;
|
||||
|
||||
double d1 = (x1 - x2) / 2;
|
||||
double d2 = (y1 - y2) / 2;
|
||||
double x1Comma = Math.cos(fi) * d1 + Math.sin(fi) * d2;
|
||||
double y1Comma = -Math.sin(fi) * d1 + Math.cos(fi) * d2;
|
||||
|
||||
// Correction of out-of-range radii
|
||||
double lambda = x1Comma * x1Comma / (rx * rx) + y1Comma * y1Comma / (ry * ry);
|
||||
if (lambda > 1) {
|
||||
double sqrtLambda = Math.sqrt(lambda);
|
||||
rx = sqrtLambda * rx;
|
||||
ry = sqrtLambda * ry;
|
||||
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;
|
||||
}
|
||||
|
||||
double c = Math.sqrt((rx * rx * ry * ry - rx * rx * y1Comma * y1Comma - ry * ry * x1Comma * x1Comma) / (rx * rx * y1Comma * y1Comma + ry * ry * x1Comma * x1Comma));
|
||||
double cxComma = c * rx * y1Comma / ry;
|
||||
double cyComma = c * -ry * x1Comma / rx;
|
||||
|
||||
if (largeFlag == sweepFlag) {
|
||||
cxComma = -cxComma;
|
||||
cyComma = -cyComma;
|
||||
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;
|
||||
}
|
||||
|
||||
double cx = Math.cos(fi) * cxComma - Math.sin(fi) * cyComma + (x1 + x2) / 2;
|
||||
double cy = Math.sin(fi) * cxComma + Math.cos(fi) * cyComma + (y1 + y2) / 2;
|
||||
serv.params = new double[]{y};
|
||||
pathCommands.add(serv);
|
||||
break;
|
||||
case 'Q':
|
||||
case 'T':
|
||||
PathCommand cer = new PathCommand();
|
||||
cer.command = 'Q';
|
||||
|
||||
double px1 = (x1Comma - cxComma) / rx;
|
||||
double py1 = (y1Comma - cyComma) / ry;
|
||||
double theta1 = calcAngle(1, 0, px1, py1);
|
||||
|
||||
double px2 = (-x1Comma - cxComma) / rx;
|
||||
double py2 = (-y1Comma - cyComma) / ry;
|
||||
double deltaTheta = calcAngle(px1, py1, px2, py2);
|
||||
if (sweepFlag) {
|
||||
if (deltaTheta < 0) {
|
||||
deltaTheta += 2 * Math.PI;
|
||||
Point pControl;
|
||||
if (cmd == 'Q') {
|
||||
x = pathReader.readDouble();
|
||||
y = pathReader.readDouble();
|
||||
if (isRelative) {
|
||||
x += x0;
|
||||
y += y0;
|
||||
}
|
||||
} else if (deltaTheta > 0) {
|
||||
deltaTheta -= 2 * Math.PI;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
double rcp = Math.sqrt(4 - 2 * Math.sqrt(2));
|
||||
double delta = Math.signum(deltaTheta) * Math.PI / 4;
|
||||
prevQControlPoint = pControl;
|
||||
x = pathReader.readDouble();
|
||||
y = pathReader.readDouble();
|
||||
if (isRelative) {
|
||||
x += x0;
|
||||
y += y0;
|
||||
}
|
||||
|
||||
int segmentCount = (int) Math.ceil(deltaTheta / delta);
|
||||
double theta = theta1;
|
||||
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.");
|
||||
|
||||
PathCommand sera;
|
||||
for (int i = 0; i < segmentCount - 1; i++) {
|
||||
theta += delta;
|
||||
/*sera = new PathCommand();
|
||||
sera.command = 'L';
|
||||
double x12 = Math.cos(theta) * rx;
|
||||
double y12 = Math.sin(theta) * ry;
|
||||
x1Comma = Math.cos(fi) * x12 - Math.sin(fi) * y12;
|
||||
y1Comma = Math.sin(fi) * x12 + Math.cos(fi) * y12;
|
||||
sera.params = new double[]{cx + x1Comma, cy + y1Comma};
|
||||
pathCommands.add(sera);*/
|
||||
// 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 fi = pathReader.readDouble() * Math.PI / 180;
|
||||
boolean largeFlag = (int) pathReader.readDouble() != 0;
|
||||
boolean sweepFlag = (int) pathReader.readDouble() != 0;
|
||||
|
||||
x = pathReader.readDouble();
|
||||
y = pathReader.readDouble();
|
||||
if (isRelative) {
|
||||
x += x0;
|
||||
y += y0;
|
||||
}
|
||||
|
||||
if (rx == 0 || ry == 0) {
|
||||
// straight line to (x, y)
|
||||
PathCommand sera = new PathCommand();
|
||||
sera.command = 'L';
|
||||
sera.params = new double[]{x, y};
|
||||
pathCommands.add(sera);
|
||||
} else {
|
||||
rx = Math.abs(rx);
|
||||
ry = Math.abs(ry);
|
||||
|
||||
double x1 = x0;
|
||||
double y1 = y0;
|
||||
double x2 = x;
|
||||
double y2 = y;
|
||||
|
||||
double d1 = (x1 - x2) / 2;
|
||||
double d2 = (y1 - y2) / 2;
|
||||
double x1Comma = Math.cos(fi) * d1 + Math.sin(fi) * d2;
|
||||
double y1Comma = -Math.sin(fi) * d1 + Math.cos(fi) * d2;
|
||||
|
||||
// Correction of out-of-range radii
|
||||
double lambda = x1Comma * x1Comma / (rx * rx) + y1Comma * y1Comma / (ry * ry);
|
||||
if (lambda > 1) {
|
||||
double sqrtLambda = Math.sqrt(lambda);
|
||||
rx = sqrtLambda * rx;
|
||||
ry = sqrtLambda * ry;
|
||||
}
|
||||
|
||||
double c = Math.sqrt((rx * rx * ry * ry - rx * rx * y1Comma * y1Comma - ry * ry * x1Comma * x1Comma) / (rx * rx * y1Comma * y1Comma + ry * ry * x1Comma * x1Comma));
|
||||
double cxComma = c * rx * y1Comma / ry;
|
||||
double cyComma = c * -ry * x1Comma / rx;
|
||||
|
||||
if (largeFlag == sweepFlag) {
|
||||
cxComma = -cxComma;
|
||||
cyComma = -cyComma;
|
||||
}
|
||||
|
||||
double cx = Math.cos(fi) * cxComma - Math.sin(fi) * cyComma + (x1 + x2) / 2;
|
||||
double cy = Math.sin(fi) * cxComma + Math.cos(fi) * cyComma + (y1 + y2) / 2;
|
||||
|
||||
double px1 = (x1Comma - cxComma) / rx;
|
||||
double py1 = (y1Comma - cyComma) / ry;
|
||||
double theta1 = calcAngle(1, 0, px1, py1);
|
||||
|
||||
double px2 = (-x1Comma - cxComma) / rx;
|
||||
double py2 = (-y1Comma - cyComma) / ry;
|
||||
double deltaTheta = calcAngle(px1, py1, px2, py2);
|
||||
if (sweepFlag) {
|
||||
if (deltaTheta < 0) {
|
||||
deltaTheta += 2 * Math.PI;
|
||||
}
|
||||
} else if (deltaTheta > 0) {
|
||||
deltaTheta -= 2 * Math.PI;
|
||||
}
|
||||
|
||||
double rcp = Math.sqrt(4 - 2 * Math.sqrt(2));
|
||||
double delta = Math.signum(deltaTheta) * Math.PI / 4;
|
||||
|
||||
int segmentCount = (int) Math.ceil(deltaTheta / delta);
|
||||
double theta = theta1;
|
||||
|
||||
PathCommand sera;
|
||||
for (int i = 0; i < segmentCount - 1; i++) {
|
||||
theta += delta;
|
||||
/*sera = new PathCommand();
|
||||
sera.command = 'L';
|
||||
double x12 = Math.cos(theta) * rx;
|
||||
double y12 = Math.sin(theta) * ry;
|
||||
x1Comma = Math.cos(fi) * x12 - Math.sin(fi) * y12;
|
||||
y1Comma = Math.sin(fi) * x12 + Math.cos(fi) * y12;
|
||||
sera.params = new double[]{cx + x1Comma, cy + y1Comma};
|
||||
pathCommands.add(sera);*/
|
||||
|
||||
sera = new PathCommand();
|
||||
sera.command = 'Q';
|
||||
double x12 = Math.cos(theta) * rx;
|
||||
double y12 = Math.sin(theta) * ry;
|
||||
x1Comma = Math.cos(fi) * x12 - Math.sin(fi) * y12;
|
||||
y1Comma = Math.sin(fi) * x12 + Math.cos(fi) * y12;
|
||||
|
||||
double theta2 = theta - delta / 2;
|
||||
x12 = Math.cos(theta2) * rx * rcp;
|
||||
y12 = Math.sin(theta2) * ry * rcp;
|
||||
double x1Comma2 = Math.cos(fi) * x12 - Math.sin(fi) * y12;
|
||||
double y1Comma2 = Math.sin(fi) * x12 + Math.cos(fi) * y12;
|
||||
sera.params = new double[]{cx + x1Comma2, cy + y1Comma2, cx + x1Comma, cy + y1Comma};
|
||||
pathCommands.add(sera);
|
||||
}
|
||||
|
||||
sera = new PathCommand();
|
||||
sera.command = 'Q';
|
||||
double x12 = Math.cos(theta) * rx;
|
||||
double y12 = Math.sin(theta) * ry;
|
||||
|
||||
theta += delta;
|
||||
double diff = theta1 + deltaTheta - theta;
|
||||
diff = -delta - diff;
|
||||
theta = theta - delta - diff / 2;
|
||||
|
||||
double rcpm = 1 + (rcp - 1) * (diff / delta) * (diff / delta);
|
||||
double x12 = Math.cos(theta) * rx * rcpm;
|
||||
double y12 = Math.sin(theta) * ry * rcpm;
|
||||
x1Comma = Math.cos(fi) * x12 - Math.sin(fi) * y12;
|
||||
y1Comma = Math.sin(fi) * x12 + Math.cos(fi) * y12;
|
||||
|
||||
double theta2 = theta - delta / 2;
|
||||
x12 = Math.cos(theta2) * rx * rcp;
|
||||
y12 = Math.sin(theta2) * ry * rcp;
|
||||
double x1Comma2 = Math.cos(fi) * x12 - Math.sin(fi) * y12;
|
||||
double y1Comma2 = Math.sin(fi) * x12 + Math.cos(fi) * y12;
|
||||
sera.params = new double[]{cx + x1Comma2, cy + y1Comma2, cx + x1Comma, cy + y1Comma};
|
||||
sera.params = new double[]{cx + x1Comma, cy + y1Comma, x, y};
|
||||
pathCommands.add(sera);
|
||||
/*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;
|
||||
}
|
||||
|
||||
sera = new PathCommand();
|
||||
sera.command = 'Q';
|
||||
if (cmd != 'C' && cmd != 'S') {
|
||||
prevCControlPoint = null;
|
||||
}
|
||||
|
||||
theta += delta;
|
||||
double diff = theta1 + deltaTheta - theta;
|
||||
diff = -delta - diff;
|
||||
theta = theta - delta - diff / 2;
|
||||
if (cmd != 'Q' && cmd != 'T') {
|
||||
prevQControlPoint = null;
|
||||
}
|
||||
|
||||
double rcpm = 1 + (rcp - 1) * (diff / delta) * (diff / delta);
|
||||
double x12 = Math.cos(theta) * rx * rcpm;
|
||||
double y12 = Math.sin(theta) * ry * rcpm;
|
||||
x1Comma = Math.cos(fi) * x12 - Math.sin(fi) * y12;
|
||||
y1Comma = Math.sin(fi) * x12 + Math.cos(fi) * y12;
|
||||
sera.params = new double[]{cx + x1Comma, cy + y1Comma, x, y};
|
||||
pathCommands.add(sera);
|
||||
/*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;
|
||||
x0 = x;
|
||||
y0 = y;
|
||||
}
|
||||
|
||||
if (cmd != 'C' && cmd != 'S') {
|
||||
prevCControlPoint = null;
|
||||
}
|
||||
|
||||
if (cmd != 'Q' && cmd != 'T') {
|
||||
prevQControlPoint = null;
|
||||
}
|
||||
|
||||
x0 = x;
|
||||
y0 = y;
|
||||
} catch (NumberFormatException e) {
|
||||
// ignore remaining data as specified in SVG Specification F.2 Error processing
|
||||
}
|
||||
|
||||
processCommands(shapeNum, shapes, pathCommands, transform, style);
|
||||
@@ -932,35 +936,39 @@ public class SvgImporter {
|
||||
|
||||
List<PathCommand> pathCommands = new ArrayList<>();
|
||||
SvgPathReader pathReader = new SvgPathReader(data);
|
||||
while (pathReader.hasNext()) {
|
||||
double x = x0;
|
||||
double y = y0;
|
||||
try {
|
||||
while (pathReader.hasNext()) {
|
||||
double x = x0;
|
||||
double y = y0;
|
||||
|
||||
Point p = null;
|
||||
switch (command) {
|
||||
case 'M':
|
||||
PathCommand scr = new PathCommand();
|
||||
scr.command = 'M';
|
||||
Point p = null;
|
||||
switch (command) {
|
||||
case 'M':
|
||||
PathCommand scr = new PathCommand();
|
||||
scr.command = 'M';
|
||||
|
||||
x = pathReader.readDouble();
|
||||
y = pathReader.readDouble();
|
||||
scr.params = new double[]{x, y};
|
||||
x = pathReader.readDouble();
|
||||
y = pathReader.readDouble();
|
||||
scr.params = new double[]{x, y};
|
||||
|
||||
pathCommands.add(scr);
|
||||
break;
|
||||
case 'L':
|
||||
PathCommand serl = new PathCommand();
|
||||
serl.command = 'L';
|
||||
x = pathReader.readDouble();
|
||||
y = pathReader.readDouble();
|
||||
serl.params = new double[]{x, y};
|
||||
pathCommands.add(serl);
|
||||
break;
|
||||
pathCommands.add(scr);
|
||||
break;
|
||||
case 'L':
|
||||
PathCommand serl = new PathCommand();
|
||||
serl.command = 'L';
|
||||
x = pathReader.readDouble();
|
||||
y = pathReader.readDouble();
|
||||
serl.params = new double[]{x, y};
|
||||
pathCommands.add(serl);
|
||||
break;
|
||||
}
|
||||
|
||||
x0 = x;
|
||||
y0 = y;
|
||||
command = 'L';
|
||||
}
|
||||
|
||||
x0 = x;
|
||||
y0 = y;
|
||||
command = 'L';
|
||||
} catch (NumberFormatException e) {
|
||||
// ignore remaining data as specified in SVG Specification F.2 Error processing
|
||||
}
|
||||
|
||||
if (close) {
|
||||
@@ -983,7 +991,6 @@ public class SvgImporter {
|
||||
byte[] pngData = Helper.readStream(pngUrl.openStream());
|
||||
Helper.writeFile(name + ".original.png", pngData);
|
||||
}
|
||||
//String svgDataS = new String(svgData);
|
||||
|
||||
String svgDataS = Helper.readTextFile(name + ".original.svg");
|
||||
SWF swf = new SWF();
|
||||
|
||||
@@ -22,7 +22,6 @@ import com.jpexs.helpers.Helper;
|
||||
import java.awt.Color;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
@@ -388,18 +387,17 @@ class SvgStyle implements Cloneable {
|
||||
}
|
||||
}
|
||||
|
||||
private Color parseColor(String rgbStr) {
|
||||
SvgFill fill = parseFill(new HashMap<>(), rgbStr, null);
|
||||
return fill.toColor();
|
||||
}
|
||||
|
||||
private SvgFill parseFill(Map<String, Element> idMap, String rgbStr, SvgStyle style) {
|
||||
if (rgbStr == null) {
|
||||
private SvgFill parseFill(Map<String, Element> idMap, String fillStr, SvgStyle style) {
|
||||
if (fillStr == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (fillStr.equals("none")) {
|
||||
return SvgTransparentFill.INSTANCE;
|
||||
}
|
||||
|
||||
Pattern idPat = Pattern.compile("url\\(#([^)]+)\\).*");
|
||||
java.util.regex.Matcher mPat = idPat.matcher(rgbStr);
|
||||
java.util.regex.Matcher mPat = idPat.matcher(fillStr);
|
||||
|
||||
if (mPat.matches()) {
|
||||
String elementId = mPat.group(1);
|
||||
@@ -454,10 +452,10 @@ class SvgStyle implements Cloneable {
|
||||
return new SvgColor(random.nextInt(256), random.nextInt(256), random.nextInt(256));
|
||||
}
|
||||
|
||||
rgbStr = rgbStr.substring(elementId.length() + 6).trim(); // remove url(#...)
|
||||
fillStr = fillStr.substring(elementId.length() + 6).trim(); // remove url(#...)
|
||||
}
|
||||
|
||||
SvgColor result = SvgColor.parse(rgbStr);
|
||||
SvgColor result = SvgColor.parse(fillStr);
|
||||
if (result == null) {
|
||||
importer.showWarning("fillNotSupported", "Unknown fill style. Random color assigned.");
|
||||
return new SvgColor(random.nextInt(256), random.nextInt(256), random.nextInt(256));
|
||||
@@ -466,122 +464,183 @@ class SvgStyle implements Cloneable {
|
||||
return result;
|
||||
}
|
||||
|
||||
private void applyStyle(Map<String, Element> idMap, SvgStyle style, String name, String value) {
|
||||
if (value == null || value.length() == 0) {
|
||||
return;
|
||||
private void applyStyle(Map<String, Element> idMap, SvgStyle style, SvgStyle parentStyle, SvgStyleProperty styleProperty, String value) {
|
||||
boolean inherit = styleProperty.isInherited();
|
||||
if ("inherit".equals(value)) {
|
||||
value = "";
|
||||
inherit = true;
|
||||
}
|
||||
|
||||
switch (name) {
|
||||
case "color": {
|
||||
Color color = parseColor(value);
|
||||
if (color != null) {
|
||||
style.color = color == SvgColor.TRANSPARENT ? null : color;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "fill": {
|
||||
SvgFill fill = parseFill(idMap, value, style);
|
||||
if (fill != null) {
|
||||
style.fill = fill == SvgColor.SVG_TRANSPARENT ? null : fill;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "stop-color": {
|
||||
if ("currentColor".equals(value)) {
|
||||
if (style.parentStyle != null) {
|
||||
style.stopColor = style.parentStyle.color;
|
||||
boolean ok = value != null && value.length() != 0;
|
||||
|
||||
String name = styleProperty.name();
|
||||
try {
|
||||
if (ok) {
|
||||
ok = false;
|
||||
switch (name) {
|
||||
case "color": {
|
||||
Color color = SvgColor.parse(value).toColor();
|
||||
if (color != null) {
|
||||
style.color = color;
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
} else if ("inherit".equals(value)) {
|
||||
importer.showWarning(value + "StopColorNotSupported", "The stop color value '" + value + "' is not supported.");
|
||||
} else {
|
||||
style.stopColor = parseColor(value);
|
||||
break;
|
||||
case "fill": {
|
||||
SvgFill fill = parseFill(idMap, value, style);
|
||||
if (fill != null) {
|
||||
style.fill = fill == SvgTransparentFill.INSTANCE ? null : fill;
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "fill-opacity": {
|
||||
double opacity = Double.parseDouble(value);
|
||||
style.fillOpacity = opacity;
|
||||
ok = true;
|
||||
}
|
||||
break;
|
||||
case "stroke": {
|
||||
SvgFill strokeFill = parseFill(idMap, value, style);
|
||||
if (strokeFill != null) {
|
||||
style.strokeFill = strokeFill == SvgTransparentFill.INSTANCE ? null : strokeFill;
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "stroke-width": {
|
||||
double strokeWidth = Double.parseDouble(value);
|
||||
style.strokeWidth = strokeWidth;
|
||||
ok = true;
|
||||
}
|
||||
break;
|
||||
case "stroke-opacity": {
|
||||
double opacity = Double.parseDouble(value);
|
||||
style.strokeOpacity = opacity;
|
||||
ok = true;
|
||||
}
|
||||
break;
|
||||
case "stroke-linecap": {
|
||||
switch (value) {
|
||||
case "butt":
|
||||
style.strokeLineCap = SvgLineCap.BUTT;
|
||||
ok = true;
|
||||
break;
|
||||
case "round":
|
||||
style.strokeLineCap = SvgLineCap.ROUND;
|
||||
ok = true;
|
||||
break;
|
||||
case "square":
|
||||
style.strokeLineCap = SvgLineCap.SQUARE;
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "stroke-linejoin": {
|
||||
switch (value) {
|
||||
case "miter":
|
||||
style.strokeLineJoin = SvgLineJoin.MITER;
|
||||
ok = true;
|
||||
break;
|
||||
case "round":
|
||||
style.strokeLineJoin = SvgLineJoin.ROUND;
|
||||
ok = true;
|
||||
break;
|
||||
case "bevel":
|
||||
style.strokeLineJoin = SvgLineJoin.BEVEL;
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "stroke-miterlimit": {
|
||||
double strokeMiterLimit = Double.parseDouble(value);
|
||||
style.strokeMiterLimit = strokeMiterLimit;
|
||||
ok = true;
|
||||
}
|
||||
break;
|
||||
case "opacity": {
|
||||
double opacity = Double.parseDouble(value);
|
||||
style.opacity = opacity;
|
||||
ok = true;
|
||||
}
|
||||
break;
|
||||
case "stop-color": {
|
||||
if ("currentColor".equals(value)) {
|
||||
if (style.parentStyle != null) {
|
||||
style.stopColor = style.parentStyle.color;
|
||||
}
|
||||
} else {
|
||||
//importer.showWarning(value + "StopColorNotSupported", "The stop color value '" + value + "' is not supported.");
|
||||
style.stopColor = SvgColor.parse(value).toColor();
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "stop-opacity": {
|
||||
//importer.showWarning(value + "StopOpacityNotSupported", "The stop opacity value '" + value + "' is not supported.");
|
||||
double stopOpacity = Double.parseDouble(value);
|
||||
style.stopOpacity = stopOpacity;
|
||||
ok = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "fill-opacity": {
|
||||
double opacity = Double.parseDouble(value);
|
||||
style.fillOpacity = opacity;
|
||||
} catch (NumberFormatException ex) {
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (!ok && inherit) {
|
||||
switch (name) {
|
||||
case "color":
|
||||
style.color = parentStyle.color;
|
||||
break;
|
||||
case "fill":
|
||||
style.fill = parentStyle.fill;
|
||||
break;
|
||||
case "fill-opacity":
|
||||
style.fillOpacity = parentStyle.opacity;
|
||||
break;
|
||||
case "stroke":
|
||||
style.strokeFill = parentStyle.strokeFill;
|
||||
break;
|
||||
case "stroke-width":
|
||||
style.strokeWidth = parentStyle.strokeWidth;
|
||||
break;
|
||||
case "stroke-opacity":
|
||||
style.strokeOpacity = parentStyle.opacity;
|
||||
break;
|
||||
case "stroke-linecap":
|
||||
style.strokeLineCap = parentStyle.strokeLineCap;
|
||||
break;
|
||||
case "stroke-linejoin":
|
||||
style.strokeLineJoin = parentStyle.strokeLineJoin;
|
||||
break;
|
||||
case "stroke-miterlimit":
|
||||
style.strokeMiterLimit = parentStyle.strokeMiterLimit;
|
||||
break;
|
||||
case "opacity":
|
||||
style.opacity = parentStyle.opacity;
|
||||
break;
|
||||
case "stop-color":
|
||||
style.stopColor = parentStyle.stopColor;
|
||||
break;
|
||||
case "stop-opacity":
|
||||
style.stopOpacity = parentStyle.stopOpacity;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "stop-opacity": {
|
||||
if ("inherit".equals(value)) {
|
||||
importer.showWarning(value + "StopOpacityNotSupported", "The stop opacity value '" + value + "' is not supported.");
|
||||
} else {
|
||||
double stopOpacity = Double.parseDouble(value);
|
||||
style.stopOpacity = stopOpacity;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "stroke": {
|
||||
SvgFill strokeFill = parseFill(idMap, value, style);
|
||||
if (strokeFill != null) {
|
||||
style.strokeFill = strokeFill == SvgColor.SVG_TRANSPARENT ? null : strokeFill;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
public SvgStyle apply(Element element, Map<String, Element> idMap) {
|
||||
SvgStyle result = clone();
|
||||
SvgStyle result = new SvgStyle(importer);
|
||||
|
||||
String[] styles = new String[]{
|
||||
"color", "fill", "fill-opacity",
|
||||
"stroke", "stroke-width", "stroke-opacity", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit",
|
||||
"opacity", "stop-color", "stop-opacity"
|
||||
};
|
||||
|
||||
for (String style : styles) {
|
||||
if (element.hasAttribute(style)) {
|
||||
String attr = element.getAttribute(style).trim();
|
||||
applyStyle(idMap, result, style, attr);
|
||||
for (SvgStyleProperty styleProperty : SvgStyleProperty.getProperties()) {
|
||||
String name = styleProperty.name();
|
||||
if (element.hasAttribute(name)) {
|
||||
String attr = element.getAttribute(name).trim();
|
||||
applyStyle(idMap, result, this, styleProperty, attr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -589,7 +648,13 @@ class SvgStyle implements Cloneable {
|
||||
String[] styleDefs = element.getAttribute("style").split(";");
|
||||
for (String styleDef : styleDefs) {
|
||||
String[] parts = styleDef.split(":", 2);
|
||||
applyStyle(idMap, result, parts[0].trim(), parts[1].trim());
|
||||
String name = parts[0].trim();
|
||||
SvgStyleProperty styleProperty = SvgStyleProperty.getByName(name);
|
||||
if (styleProperty == null) {
|
||||
importer.showWarning(name + "StyleNotSupported", "The style '" + name + "' is not supported.");
|
||||
}
|
||||
|
||||
applyStyle(idMap, result, this, styleProperty, parts[1].trim());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.importers.svg;
|
||||
|
||||
import com.sun.prism.paint.Color;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class SvgStyleProperty {
|
||||
|
||||
private final String name;
|
||||
|
||||
private final boolean inherited;
|
||||
|
||||
private final Object initial;
|
||||
|
||||
public SvgStyleProperty(String name, boolean inherited, Object initial) {
|
||||
this.name = name;
|
||||
this.inherited = inherited;
|
||||
this.initial = initial;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean isInherited() {
|
||||
return inherited;
|
||||
}
|
||||
|
||||
private static final Map<String, SvgStyleProperty> properties;
|
||||
|
||||
static {
|
||||
Map<String, SvgStyleProperty> p = new HashMap<>();
|
||||
p.put("color", new SvgStyleProperty("color", true, null /* depends on user agent */));
|
||||
p.put("fill", new SvgStyleProperty("fill", true, Color.BLACK));
|
||||
p.put("fill-opacity", new SvgStyleProperty("fill-opacity", true, 1.0));
|
||||
p.put("stroke", new SvgStyleProperty("stroke", true, null));
|
||||
p.put("stroke-width", new SvgStyleProperty("stroke-width", true, 1.0));
|
||||
p.put("stroke-opacity", new SvgStyleProperty("stroke-opacity", true, 1.0));
|
||||
p.put("stroke-linecap", new SvgStyleProperty("stroke-linecap", true, SvgLineCap.BUTT));
|
||||
p.put("stroke-linejoin", new SvgStyleProperty("stroke-linejoin", true, SvgLineJoin.MITER));
|
||||
p.put("stroke-miterlimit", new SvgStyleProperty("stroke-miterlimit", true, 4.0));
|
||||
p.put("opacity", new SvgStyleProperty("opacity", false, 1.0));
|
||||
p.put("stop-color", new SvgStyleProperty("stop-color", false, Color.BLACK));
|
||||
p.put("stop-opacity", new SvgStyleProperty("stop-opacity", false, 1.0));
|
||||
properties = p;
|
||||
}
|
||||
|
||||
public static Collection<SvgStyleProperty> getProperties() {
|
||||
return properties.values();
|
||||
}
|
||||
|
||||
public static SvgStyleProperty getByName(String name) {
|
||||
return properties.get(name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.importers.svg;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
class SvgTransparentFill extends SvgFill {
|
||||
|
||||
private static final Color TRANSPARENT = new Color(0, true);
|
||||
|
||||
public static SvgTransparentFill INSTANCE = new SvgTransparentFill();
|
||||
|
||||
private SvgTransparentFill() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color toColor() {
|
||||
return TRANSPARENT;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user