svg style inheritance (not ready)

This commit is contained in:
honfika@gmail.com
2015-12-27 17:34:36 +01:00
parent 0940243fa1
commit d0e03b7be9
5 changed files with 575 additions and 395 deletions

View File

@@ -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":

View File

@@ -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();

View File

@@ -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());
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}