Added: #2453 SVG export/import - use image-rendering attribute for image smoothing

This commit is contained in:
Jindra Petřík
2025-05-08 11:07:07 +02:00
parent 8fc5125a1a
commit 4595a39a91
5 changed files with 100 additions and 6 deletions
@@ -162,7 +162,8 @@ public class SVGShapeExporter extends DefaultSVGShapeExporter {
pattern.setAttribute("width", "" + width);
pattern.setAttribute("height", "" + height);
pattern.setAttribute("viewBox", "0 0 " + width + " " + height);
pattern.setAttribute("ffdec:smoothed", smoothed ? "true" : "false");
//Smoothed attribute was used in older FFDec versions - it is now only used for reading, for backwards compatibility
//pattern.setAttribute("ffdec:smoothed", smoothed ? "true" : "false");
if (matrix != null) {
pattern.setAttribute("patternTransform", matrix.getSvgTransformationString(SWF.unitDivisor / zoom, SWF.unitDivisor / zoom));
}
@@ -170,6 +171,12 @@ public class SVGShapeExporter extends DefaultSVGShapeExporter {
imageElement.setAttribute("width", "" + width);
imageElement.setAttribute("height", "" + height);
imageElement.setAttribute("xlink:href", "data:image/" + format + ";base64," + base64ImgData);
if (smoothed) {
imageElement.setAttribute("style", "image-rendering:optimizeQuality");
} else {
//https://stackoverflow.com/questions/50184674/stop-auto-image-smoothing-inside-an-svgz
imageElement.setAttribute("style", "image-rendering:optimizeSpeed; image-rendering:pixelated");
}
pattern.appendChild(imageElement);
exporter.addToGroup(pattern);
return patternId;
@@ -0,0 +1,39 @@
/*
* Copyright (C) 2010-2024 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;
/**
*
* @author JPEXS
*/
public enum SvgImageRendering {
/**
* Optimize speed aka Pixelated
*/
OPTIMIZE_SPEED,
/**
* Optimize quality
*/
OPTIMIZE_QUALITY,
/**
* Automatic
*/
AUTO
}
@@ -657,7 +657,31 @@ class SvgStyle {
if (e.hasAttribute("patternTransform")) {
bitmapFill.patternTransform = e.getAttribute("patternTransform");
}
if (e.hasAttribute("ffdec:smoothed")) {
NodeList childNodes = e.getChildNodes();
Element element = null;
for (int i = 0; i < childNodes.getLength(); i++) {
if (childNodes.item(i) instanceof Element) {
if ("animateTransform".equals(((Element) childNodes.item(i)).getTagName())) {
continue;
}
if (element != null) {
element = null;
break;
}
element = (Element) childNodes.item(i);
}
}
SvgImageRendering imageRendering = null;
if (element != null) {
imageRendering = getValue(element, "image-rendering", true);
}
if (e.hasAttribute("ffdec:smoothed")) { //backwards compatibility
String smoothedValue = e.getAttribute("ffdec:smoothed").trim();
if ("true".equals(smoothedValue)) {
bitmapFill.smoothed = true;
@@ -665,8 +689,12 @@ class SvgStyle {
if ("false".equals(smoothedValue)) {
bitmapFill.smoothed = false;
}
} else {
bitmapFill.smoothed = true;
} else {
if (imageRendering == SvgImageRendering.OPTIMIZE_SPEED) {
bitmapFill.smoothed = false;
} else {
bitmapFill.smoothed = true;
}
}
return bitmapFill;
}
@@ -714,7 +742,8 @@ class SvgStyle {
if (e.hasAttribute("patternTransform")) {
bitmapFill.patternTransform = e.getAttribute("patternTransform");
}
if (e.hasAttribute("ffdec:smoothed")) {
SvgImageRendering imageRendering = getValue(element, "image-rendering", true);
if (e.hasAttribute("ffdec:smoothed")) { //backwards compatibility
String smoothedValue = e.getAttribute("ffdec:smoothed").trim();
if ("true".equals(smoothedValue)) {
bitmapFill.smoothed = true;
@@ -723,7 +752,11 @@ class SvgStyle {
bitmapFill.smoothed = false;
}
} else {
bitmapFill.smoothed = true;
if (imageRendering == SvgImageRendering.OPTIMIZE_SPEED) {
bitmapFill.smoothed = false;
} else {
bitmapFill.smoothed = true;
}
}
cachedBitmaps.put(elementId, imageTag.characterID);
@@ -828,6 +861,18 @@ class SvgStyle {
}
}
break;
case "image-rendering": {
switch (value) {
case "optimizeSpeed":
case "pixelated": //a weird value used by the Chrome browser
return SvgImageRendering.OPTIMIZE_SPEED;
case "optimizeQuality":
return SvgImageRendering.OPTIMIZE_QUALITY;
case "auto":
return SvgImageRendering.AUTO;
}
}
break;
case "stroke-miterlimit": {
double strokeMiterLimit = Double.parseDouble(value);
return strokeMiterLimit;
@@ -88,6 +88,7 @@ public class SvgStyleProperty {
p.put("stop-color", new SvgStyleProperty("stop-color", false, Color.BLACK));
p.put("stop-opacity", new SvgStyleProperty("stop-opacity", false, 1.0));
p.put("vector-effect", new SvgStyleProperty("vector-effect", false, "none"));
p.put("image-rendering", new SvgStyleProperty("image-rendering", true, SvgImageRendering.AUTO));
properties = p;
}