Skip to content

Commit 9cf8de8

Browse files
committed
Fixed: SVG importer - improper stroke width when using width/height with viewBox
1 parent 87b895e commit 9cf8de8

3 files changed

Lines changed: 52 additions & 10 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ All notable changes to this project will be documented in this file.
3232
- Substance LAF - Shadow in text (mostly in window titles) drawn incorrectly
3333
- Incorrect icons for `New empty` action - with dashed borders
3434
- [#2443] SVG importer - converting cubic bezier curves to quadratic
35+
- SVG importer - improper stroke width when using width/height with viewBox
3536

3637
## [22.0.2] - 2025-01-17
3738
### Added

libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgImporter.java

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,12 @@ public class SvgImporter {
103103

104104
private Rectangle2D.Double viewBox;
105105

106+
private double width;
107+
108+
private double height;
109+
110+
private double unitRatio;
111+
106112
/**
107113
* Constructor.
108114
* @param st Shape tag
@@ -273,22 +279,33 @@ private Tag importSvg(Tag st, ShapeTag endShape, String svgXml, boolean fill) {
273279
}
274280

275281
this.viewBox = viewBox;
282+
this.width = width;
283+
this.height = height;
276284

277285
Map<String, Integer> cachedBitmaps = new HashMap<>();
278286
SvgStyle style = new SvgStyle(this, idMap, rootElement, cachedBitmaps);
279287
Matrix transform = new Matrix();
280288

289+
double ratioX = 1;
290+
double ratioY = 1;
291+
281292
if (fill) {
282-
double ratioX = rect.getWidth() / width / SWF.unitDivisor;
283-
double ratioY = rect.getHeight() / height / SWF.unitDivisor;
284-
transform = Matrix.getScaleInstance(ratioX, ratioY);
285-
transform.translate(origXmin / SWF.unitDivisor / ratioX, origYmin / SWF.unitDivisor / ratioY);
293+
ratioX = rect.getWidth() / width;
294+
ratioY = rect.getHeight() / height;
295+
transform = Matrix.getScaleInstance(ratioX / SWF.unitDivisor, ratioY / SWF.unitDivisor);
296+
transform.translate(origXmin / ratioX, origYmin / ratioY);
286297
}
287298

288299
transform = transform.preConcatenate(Matrix.getTranslateInstance(-viewBox.x, -viewBox.y));
289300
if (viewBox.height != 0 && viewBox.width != 0) {
290-
transform = transform.preConcatenate(Matrix.getScaleInstance(width / viewBox.width, height / viewBox.height));
301+
double ratio2x = width / viewBox.width;
302+
double ratio2y = height / viewBox.height;
303+
ratioX *= ratio2x;
304+
ratioY *= ratio2y;
305+
transform = transform.preConcatenate(Matrix.getScaleInstance(ratio2x, ratio2y));
291306
}
307+
308+
this.unitRatio = (ratioX + ratioY) / 2;
292309

293310
processSvgObject(idMap, shapeNum, shapes, rootElement, transform, style, morphShape, cachedBitmaps, false);
294311
if (rootElement.hasAttribute("ffdec:objectType")
@@ -327,6 +344,14 @@ && applyAnimation(rootElement)) {
327344
return (Tag) st;
328345
}
329346

347+
/**
348+
* Gets unit ratio.
349+
* @return Ratio value
350+
*/
351+
public double getUnitRatio() {
352+
return unitRatio;
353+
}
354+
330355
/**
331356
* Applies animation to the element.
332357
* @param element Element
@@ -1440,6 +1465,18 @@ private void processPolyline(int shapeNum, SHAPEWITHSTYLE shapes, Element childE
14401465
processCommands(shapeNum, shapes, pathCommands, transform, style, morphShape, false);
14411466
}
14421467

1468+
public double getWidth() {
1469+
return width;
1470+
}
1471+
1472+
public double getHeight() {
1473+
return height;
1474+
}
1475+
1476+
public Rectangle2D.Double getViewBox() {
1477+
return viewBox;
1478+
}
1479+
14431480
//Stub for w3 test. TODO: refactor and move to test directory. It's here because of easy access - compiling single file
14441481
private static void svgTest(String name) throws IOException, InterruptedException {
14451482
System.err.println("running test " + name);
@@ -2007,8 +2044,8 @@ private StyleChangeRecord getStyleChangeRecord(int shapeNum, SvgStyle style, boo
20072044
Color lineColor = strokeFill.toColor();
20082045

20092046
ILINESTYLE lineStyle = shapeNum <= 3 ? new LINESTYLE() : new LINESTYLE2();
2010-
lineStyle.setColor(getRGB(shapeNum, lineColor));
2011-
lineStyle.setWidth((int) Math.round(style.getStrokeWidth() * SWF.unitDivisor));
2047+
lineStyle.setColor(getRGB(shapeNum, lineColor));
2048+
lineStyle.setWidth((int) Math.round(style.getStrokeWidth() * this.unitRatio * SWF.unitDivisor));
20122049
SvgLineCap lineCap = style.getStrokeLineCap();
20132050
SvgLineJoin lineJoin = style.getStrokeLineJoin();
20142051
if (lineStyle instanceof LINESTYLE2) {
@@ -2088,7 +2125,7 @@ private double parseCoordinate(String value, double relativeTo) {
20882125
return parseLength(value, relativeTo);
20892126
}
20902127

2091-
private double parseLength(String value, double relativeTo) {
2128+
public double parseLength(String value, double relativeTo) {
20922129
if (value == null) {
20932130
throw new NumberFormatException();
20942131
}

libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgStyle.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -791,8 +791,12 @@ private Object getStyleValue(SvgStyle style, String name, String value) {
791791
}
792792
break;
793793
case "stroke-width": {
794-
double strokeWidth = Double.parseDouble(value);
795-
return strokeWidth;
794+
return importer.parseLength(value,
795+
Math.sqrt(
796+
importer.getViewBox().width * importer.getViewBox().width
797+
+ importer.getViewBox().height * importer.getViewBox().height
798+
) / Math.sqrt(2)
799+
);
796800
}
797801
case "stroke-opacity": {
798802
double opacity = Double.parseDouble(value);

0 commit comments

Comments
 (0)