From a40b8376343eec7f235e31d18910fe57f36f4aad Mon Sep 17 00:00:00 2001 From: Jannis Weis <31143295+weisJ@users.noreply.github.com> Date: Mon, 29 May 2023 16:30:12 +0200 Subject: [PATCH 1/6] Replace svgSalamander with jsvg --- flatlaf-extras/build.gradle.kts | 2 +- .../formdev/flatlaf/extras/FlatSVGIcon.java | 104 +++++++++++------- .../formdev/flatlaf/extras/FlatSVGUtils.java | 75 ++++++------- .../src/main/module-info/module-info.java | 2 +- gradle/libs.versions.toml | 1 + 5 files changed, 100 insertions(+), 84 deletions(-) diff --git a/flatlaf-extras/build.gradle.kts b/flatlaf-extras/build.gradle.kts index c8982f65..1a16a848 100644 --- a/flatlaf-extras/build.gradle.kts +++ b/flatlaf-extras/build.gradle.kts @@ -23,7 +23,7 @@ plugins { dependencies { implementation( project( ":flatlaf-core" ) ) - implementation( libs.svgSalamander ) + implementation( libs.jsvg ) } flatlafModuleInfo { diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java index e6e034aa..9527eea2 100644 --- a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java +++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java @@ -30,6 +30,7 @@ import java.awt.image.RGBImageFilter; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; @@ -49,9 +50,9 @@ import com.formdev.flatlaf.util.LoggingFacade; import com.formdev.flatlaf.util.MultiResolutionImageSupport; import com.formdev.flatlaf.util.SoftCache; import com.formdev.flatlaf.util.UIScale; -import com.kitfox.svg.SVGDiagram; -import com.kitfox.svg.SVGException; -import com.kitfox.svg.SVGUniverse; +import com.github.weisj.jsvg.SVGDocument; +import com.github.weisj.jsvg.geometry.size.FloatSize; +import com.github.weisj.jsvg.parser.SVGLoader; /** * An icon that loads and paints SVG. @@ -62,11 +63,9 @@ public class FlatSVGIcon extends ImageIcon implements DisabledIconProvider { - // cache that uses soft references for values, which allows freeing SVG diagrams if no longer used - private static final SoftCache svgCache = new SoftCache<>(); - - // use own SVG universe so that it can not be cleared from anywhere - private static final SVGUniverse svgUniverse = new SVGUniverse(); + // cache that uses soft references for values, which allows freeing SVG documents if no longer used + private static final SoftCache svgCache = new SoftCache<>(); + private static final SVGLoader svgLoader = new SVGLoader(); private static int streamNumber; private final String name; @@ -79,7 +78,7 @@ public class FlatSVGIcon private ColorFilter colorFilter; - private SVGDiagram diagram; + private SVGDocument document; private boolean dark; private boolean loadFailed; @@ -270,7 +269,7 @@ public class FlatSVGIcon this( null, -1, -1, 1, false, null, loadFromStream( in ) ); // since the input stream is already loaded and parsed, - // get diagram here and remove it from cache + // get the document here and remove it from cache update(); synchronized( FlatSVGIcon.class ) { svgCache.remove( uri ); @@ -279,7 +278,12 @@ public class FlatSVGIcon private static synchronized URI loadFromStream( InputStream in ) throws IOException { try( InputStream in2 = in ) { - return svgUniverse.loadSVG( in2, "/flatlaf-stream-" + streamNumber++ ); + SVGDocument document = svgLoader.load( in2 ); + URI dummyUri = new URI( "inputStreamSVG", "/flatlaf-stream-" + streamNumber++, null ); + svgCache.put( dummyUri, document ); + return dummyUri; + } catch( URISyntaxException e ) { + throw new IllegalStateException( e ); } } @@ -293,11 +297,13 @@ public class FlatSVGIcon public FlatSVGIcon( FlatSVGIcon icon ) { this( icon.name, icon.width, icon.height, icon.scale, icon.disabled, icon.classLoader, icon.uri ); colorFilter = icon.colorFilter; - diagram = icon.diagram; + document = icon.document; dark = icon.dark; } - protected FlatSVGIcon( String name, int width, int height, float scale, boolean disabled, ClassLoader classLoader, URI uri ) { + protected FlatSVGIcon( String name, int width, int height, float scale, boolean disabled, ClassLoader classLoader, + URI uri ) + { this.name = name; this.width = width; this.height = height; @@ -385,7 +391,7 @@ public class FlatSVGIcon FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, disabled, classLoader, uri ); icon.colorFilter = colorFilter; - icon.diagram = diagram; + icon.document = document; icon.dark = dark; return icon; } @@ -404,7 +410,7 @@ public class FlatSVGIcon FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, disabled, classLoader, uri ); icon.colorFilter = colorFilter; - icon.diagram = diagram; + icon.document = document; icon.dark = dark; return icon; } @@ -423,7 +429,7 @@ public class FlatSVGIcon FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, true, classLoader, uri ); icon.colorFilter = colorFilter; - icon.diagram = diagram; + icon.document = document; icon.dark = dark; return icon; } @@ -462,18 +468,19 @@ public class FlatSVGIcon if( loadFailed ) return; - if( dark == isDarkLaf() && diagram != null ) + if( dark == isDarkLaf() && document != null ) return; dark = isDarkLaf(); // SVGs already loaded via url or input stream can not have light/dark variants - if( uri != null && diagram != null ) + if( uri != null && document != null ) return; URI uri = this.uri; + URL url = null; if( uri == null ) { - URL url = getIconURL( name, dark ); + url = getIconURL( name, dark ); if( url == null && dark ) url = getIconURL( name, false ); @@ -486,29 +493,35 @@ public class FlatSVGIcon uri = url2uri( url ); } - diagram = loadSVG( uri ); - loadFailed = (diagram == null); + if( url == null ) { + url = uri2url( uri ); + } + + document = loadSVG( uri, url ); + loadFailed = (document == null); } - static synchronized SVGDiagram loadSVG( URI uri ) { + /* + * The uri and url parameters should always match each other in the sense that they represent the same + * location. We pass both as most places + */ + static synchronized SVGDocument loadSVG( URI uri, URL url ) { // get from our cache - SVGDiagram diagram = svgCache.get( uri ); - if( diagram != null ) - return diagram; + SVGDocument document = svgCache.get( uri ); + if( document != null ) + return document; - // load/get SVG diagram - diagram = svgUniverse.getDiagram( uri ); + // load/get SVG document + document = svgLoader.load( url ); - if( diagram == null ) { + if( document == null ) { LoggingFacade.INSTANCE.logSevere( "FlatSVGIcon: failed to load '" + uri + "'", null ); return null; } - // add to our (soft) cache and remove from SVGUniverse (hard) cache - svgCache.put( uri, diagram ); - svgUniverse.removeDocument( uri ); + svgCache.put( uri, document ); - return diagram; + return document; } private URL getIconURL( String name, boolean dark ) { @@ -528,7 +541,7 @@ public class FlatSVGIcon */ public boolean hasFound() { update(); - return diagram != null; + return document != null; } /** @@ -540,7 +553,7 @@ public class FlatSVGIcon return scaleSize( width ); update(); - return scaleSize( (diagram != null) ? Math.round( diagram.getWidth() ) : 16 ); + return scaleSize( (document != null) ? Math.round( document.size().width ) : 16 ); } /** @@ -552,7 +565,7 @@ public class FlatSVGIcon return scaleSize( height ); update(); - return scaleSize( (diagram != null) ? Math.round( diagram.getHeight() ) : 16 ); + return scaleSize( (document != null) ? Math.round( document.size().height ) : 16 ); } private int scaleSize( int size ) { @@ -597,7 +610,7 @@ public class FlatSVGIcon } private void paintSvg( Graphics2D g, int x, int y ) { - if( diagram == null ) { + if( document == null ) { paintSvgError( g, x, y ); return; } @@ -607,19 +620,18 @@ public class FlatSVGIcon UIScale.scaleGraphics( g ); if( width > 0 || height > 0 ) { - double sx = (width > 0) ? width / diagram.getWidth() : 1; - double sy = (height > 0) ? height / diagram.getHeight() : 1; + FloatSize svgSize = document.size(); + double sx = (width > 0) ? width / svgSize.width : 1; + double sy = (height > 0) ? height / svgSize.height : 1; if( sx != 1 || sy != 1 ) g.scale( sx, sy ); } if( scale != 1 ) g.scale( scale, scale ); - diagram.setIgnoringClipHeuristic( true ); - try { - diagram.render( g ); - } catch( SVGException ex ) { + document.render( null, g ); + } catch( Exception ex ) { paintSvgError( g, 0, 0 ); } } @@ -670,6 +682,14 @@ public class FlatSVGIcon } } + static URL uri2url( URI uri ) { + try { + return uri.toURL(); + } catch( MalformedURLException ex ) { + throw new IllegalArgumentException( ex ); + } + } + private static Boolean darkLaf; /** diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGUtils.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGUtils.java index 8caf5992..273dca31 100644 --- a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGUtils.java +++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGUtils.java @@ -28,8 +28,8 @@ import java.util.List; import javax.swing.JWindow; import com.formdev.flatlaf.util.MultiResolutionImageSupport; import com.formdev.flatlaf.util.SystemInfo; -import com.kitfox.svg.SVGDiagram; -import com.kitfox.svg.SVGException; +import com.github.weisj.jsvg.SVGDocument; +import com.github.weisj.jsvg.geometry.size.FloatSize; /** * Utility methods for SVG. @@ -83,7 +83,7 @@ public class FlatSVGUtils * @since 2 */ public static List createWindowIconImages( URL svgUrl ) { - SVGDiagram diagram = loadSVG( svgUrl ); + SVGDocument document = loadSVG( svgUrl ); if( SystemInfo.isWindows && MultiResolutionImageSupport.isAvailable() ) { // use a multi-resolution image that creates images on demand for requested sizes @@ -102,17 +102,17 @@ public class FlatSVGUtils new Dimension( 48, 48 ), // 300% new Dimension( 64, 64 ), // 400% }, dim -> { - return svg2image( diagram, dim.width, dim.height ); + return svg2image( document, dim.width, dim.height ); } ) ); } else { return Arrays.asList( - svg2image( diagram, 16, 16 ), // 100% - svg2image( diagram, 20, 20 ), // 125% - svg2image( diagram, 24, 24 ), // 150% - svg2image( diagram, 28, 28 ), // 175% - svg2image( diagram, 32, 32 ), // 200% - svg2image( diagram, 48, 48 ), // 300% - svg2image( diagram, 64, 64 ) // 400% + svg2image( document, 16, 16 ), // 100% + svg2image( document, 20, 20 ), // 125% + svg2image( document, 24, 24 ), // 150% + svg2image( document, 28, 28 ), // 175% + svg2image( document, 32, 32 ), // 200% + svg2image( document, 48, 48 ), // 300% + svg2image( document, 64, 64 ) // 400% ); } } @@ -180,53 +180,48 @@ public class FlatSVGUtils * @since 2 */ public static BufferedImage svg2image( URL svgUrl, float scaleFactor ) { - SVGDiagram diagram = loadSVG( svgUrl ); - int width = (int) (diagram.getWidth() * scaleFactor); - int height = (int) (diagram.getHeight() * scaleFactor); - return svg2image( diagram, width, height ); + SVGDocument document = loadSVG( svgUrl ); + FloatSize size = document.size(); + int width = (int) (size.width * scaleFactor); + int height = (int) (size.height * scaleFactor); + return svg2image( document, width, height ); } /** - * Creates a buffered image and renders the given SVGDiagram into it. + * Creates a buffered image and renders the given SVGDocument into it. * - * @param diagram the SVG diagram + * @param document the SVG document * @param width the width of the image * @param height the height of the image * @return the image * @throws RuntimeException if failed to render SVG file */ - public static BufferedImage svg2image( SVGDiagram diagram, int width, int height ) { + public static BufferedImage svg2image( SVGDocument document, int width, int height ) { + BufferedImage image = new BufferedImage( width, height, BufferedImage.TYPE_INT_ARGB ); + + Graphics2D g = image.createGraphics(); try { - BufferedImage image = new BufferedImage( width, height, BufferedImage.TYPE_INT_ARGB ); + g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON ); + g.setRenderingHint( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR ); - Graphics2D g = image.createGraphics(); - try { - g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON ); - g.setRenderingHint( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR ); + FloatSize size = document.size(); + double sx = width / size.width; + double sy = height / size.height; + if( sx != 1 || sy != 1 ) + g.scale( sx, sy ); - double sx = width / diagram.getWidth(); - double sy = height / diagram.getHeight(); - if( sx != 1 || sy != 1 ) - g.scale( sx, sy ); - - diagram.setIgnoringClipHeuristic( true ); - - diagram.render( g ); - } finally { - g.dispose(); - } - return image; - - } catch( SVGException ex ) { - throw new RuntimeException( ex ); + document.render( null, g ); + } finally { + g.dispose(); } + return image; } private static URL getResource( String svgName ) { return FlatSVGUtils.class.getResource( svgName ); } - private static SVGDiagram loadSVG( URL url ) { - return FlatSVGIcon.loadSVG( FlatSVGIcon.url2uri( url ) ); + private static SVGDocument loadSVG( URL url ) { + return FlatSVGIcon.loadSVG( FlatSVGIcon.url2uri( url ), url ); } } diff --git a/flatlaf-extras/src/main/module-info/module-info.java b/flatlaf-extras/src/main/module-info/module-info.java index 2baec393..743dc506 100644 --- a/flatlaf-extras/src/main/module-info/module-info.java +++ b/flatlaf-extras/src/main/module-info/module-info.java @@ -20,7 +20,7 @@ module com.formdev.flatlaf.extras { requires java.desktop; requires java.prefs; - requires static com.kitfox.svg; // optional at runtime + requires static com.github.weisj.jsvg; // optional at runtime requires com.formdev.flatlaf; exports com.formdev.flatlaf.extras; diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5539769d..764a7cff 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -25,6 +25,7 @@ sigtest = "org.netbeans.tools:sigtest-maven-plugin:1.7" # flatlaf-extras svgSalamander = "com.formdev:svgSalamander:1.1.3" +jsvg = "com.github.weisj:jsvg:1.0.0" # flatlaf-jide-oss jide-oss = "com.formdev:jide-oss:3.7.12" From f6062e1ec46221b9bd06579c9a33478d3a54abf3 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Sun, 9 Jul 2023 23:16:50 +0200 Subject: [PATCH 2/6] jsvg: fixed color filter in FlatSVGIcon --- .../java/com/formdev/flatlaf/extras/FlatSVGIcon.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java index 9527eea2..1f6f775b 100644 --- a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java +++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java @@ -984,6 +984,18 @@ public class FlatSVGIcon this.grayFilter = grayFilter; } + @Override + public Graphics create() { + return new GraphicsFilter( (Graphics2D) super.create(), + colorFilter, globalColorFilter, grayFilter ); + } + + @Override + public Graphics create( int x, int y, int width, int height ) { + return new GraphicsFilter( (Graphics2D) super.create( x, y, width, height ), + colorFilter, globalColorFilter, grayFilter ); + } + @Override public void setColor( Color c ) { super.setColor( filterColor( c ) ); From 799f8efe2202559333e3b189dd0662ac9c12ded1 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Mon, 10 Jul 2023 13:41:54 +0200 Subject: [PATCH 3/6] jsvg: simplified/fixed loading from input stream; replaced internal usage of URI with URL --- .../formdev/flatlaf/extras/FlatSVGIcon.java | 88 ++++++------------- .../formdev/flatlaf/extras/FlatSVGUtils.java | 12 +-- 2 files changed, 33 insertions(+), 67 deletions(-) diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java index 1f6f775b..c8ea11a2 100644 --- a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java +++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java @@ -32,7 +32,6 @@ import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URI; -import java.net.URISyntaxException; import java.net.URL; import java.util.Collections; import java.util.HashMap; @@ -64,9 +63,8 @@ public class FlatSVGIcon implements DisabledIconProvider { // cache that uses soft references for values, which allows freeing SVG documents if no longer used - private static final SoftCache svgCache = new SoftCache<>(); + private static final SoftCache svgCache = new SoftCache<>(); private static final SVGLoader svgLoader = new SVGLoader(); - private static int streamNumber; private final String name; private final int width; @@ -74,7 +72,7 @@ public class FlatSVGIcon private final float scale; private final boolean disabled; private final ClassLoader classLoader; - private final URI uri; + private final URL url; private ColorFilter colorFilter; @@ -219,7 +217,7 @@ public class FlatSVGIcon * @since 2 */ public FlatSVGIcon( URL url ) { - this( null, -1, -1, 1, false, null, url2uri( url ) ); + this( null, -1, -1, 1, false, null, url ); } /** @@ -235,7 +233,7 @@ public class FlatSVGIcon * @since 2 */ public FlatSVGIcon( URI uri ) { - this( null, -1, -1, 1, false, null, uri ); + this( null, -1, -1, 1, false, null, uri2url( uri ) ); } /** @@ -250,7 +248,7 @@ public class FlatSVGIcon * @since 2 */ public FlatSVGIcon( File file ) { - this( null, -1, -1, 1, false, null, file.toURI() ); + this( null, -1, -1, 1, false, null, uri2url( file.toURI() ) ); } /** @@ -266,24 +264,15 @@ public class FlatSVGIcon * @since 2 */ public FlatSVGIcon( InputStream in ) throws IOException { - this( null, -1, -1, 1, false, null, loadFromStream( in ) ); + this( null, -1, -1, 1, false, null, null ); - // since the input stream is already loaded and parsed, - // get the document here and remove it from cache - update(); - synchronized( FlatSVGIcon.class ) { - svgCache.remove( uri ); - } - } - - private static synchronized URI loadFromStream( InputStream in ) throws IOException { try( InputStream in2 = in ) { - SVGDocument document = svgLoader.load( in2 ); - URI dummyUri = new URI( "inputStreamSVG", "/flatlaf-stream-" + streamNumber++, null ); - svgCache.put( dummyUri, document ); - return dummyUri; - } catch( URISyntaxException e ) { - throw new IllegalStateException( e ); + document = svgLoader.load( in2 ); + + if( document == null ) { + loadFailed = true; + LoggingFacade.INSTANCE.logSevere( "FlatSVGIcon: failed to load SVG icon from input stream", null ); + } } } @@ -295,14 +284,14 @@ public class FlatSVGIcon * @since 2.0.1 */ public FlatSVGIcon( FlatSVGIcon icon ) { - this( icon.name, icon.width, icon.height, icon.scale, icon.disabled, icon.classLoader, icon.uri ); + this( icon.name, icon.width, icon.height, icon.scale, icon.disabled, icon.classLoader, icon.url ); colorFilter = icon.colorFilter; document = icon.document; dark = icon.dark; } - protected FlatSVGIcon( String name, int width, int height, float scale, boolean disabled, ClassLoader classLoader, - URI uri ) + protected FlatSVGIcon( String name, int width, int height, float scale, + boolean disabled, ClassLoader classLoader, URL url ) { this.name = name; this.width = width; @@ -310,7 +299,7 @@ public class FlatSVGIcon this.scale = scale; this.disabled = disabled; this.classLoader = classLoader; - this.uri = uri; + this.url = url; } /** @@ -389,7 +378,7 @@ public class FlatSVGIcon if( width == this.width && height == this.height ) return this; - FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, disabled, classLoader, uri ); + FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, disabled, classLoader, url ); icon.colorFilter = colorFilter; icon.document = document; icon.dark = dark; @@ -408,7 +397,7 @@ public class FlatSVGIcon if( scale == this.scale ) return this; - FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, disabled, classLoader, uri ); + FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, disabled, classLoader, url ); icon.colorFilter = colorFilter; icon.document = document; icon.dark = dark; @@ -427,7 +416,7 @@ public class FlatSVGIcon if( disabled ) return this; - FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, true, classLoader, uri ); + FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, true, classLoader, url ); icon.colorFilter = colorFilter; icon.document = document; icon.dark = dark; @@ -473,13 +462,12 @@ public class FlatSVGIcon dark = isDarkLaf(); - // SVGs already loaded via url or input stream can not have light/dark variants - if( uri != null && document != null ) + // SVGs already loaded via url, file or input stream can not have light/dark variants + if( document != null && name == null ) return; - URI uri = this.uri; - URL url = null; - if( uri == null ) { + URL url = this.url; + if( url == null ) { url = getIconURL( name, dark ); if( url == null && dark ) url = getIconURL( name, false ); @@ -489,37 +477,27 @@ public class FlatSVGIcon LoggingFacade.INSTANCE.logConfig( "FlatSVGIcon: resource '" + name + "' not found (if using Java modules, check whether icon package is opened in module-info.java)", null ); return; } - - uri = url2uri( url ); } - if( url == null ) { - url = uri2url( uri ); - } - - document = loadSVG( uri, url ); + document = loadSVG( url ); loadFailed = (document == null); } - /* - * The uri and url parameters should always match each other in the sense that they represent the same - * location. We pass both as most places - */ - static synchronized SVGDocument loadSVG( URI uri, URL url ) { + static synchronized SVGDocument loadSVG( URL url ) { // get from our cache - SVGDocument document = svgCache.get( uri ); + SVGDocument document = svgCache.get( url ); if( document != null ) return document; - // load/get SVG document + // load SVG document document = svgLoader.load( url ); if( document == null ) { - LoggingFacade.INSTANCE.logSevere( "FlatSVGIcon: failed to load '" + uri + "'", null ); + LoggingFacade.INSTANCE.logSevere( "FlatSVGIcon: failed to load '" + url + "'", null ); return null; } - svgCache.put( uri, document ); + svgCache.put( url, document ); return document; } @@ -674,14 +652,6 @@ public class FlatSVGIcon return MultiResolutionImageSupport.create( 0, dimensions, producer ); } - static URI url2uri( URL url ) { - try { - return url.toURI(); - } catch( URISyntaxException ex ) { - throw new IllegalArgumentException( ex ); - } - } - static URL uri2url( URI uri ) { try { return uri.toURL(); diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGUtils.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGUtils.java index 273dca31..2c8d012e 100644 --- a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGUtils.java +++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGUtils.java @@ -83,7 +83,7 @@ public class FlatSVGUtils * @since 2 */ public static List createWindowIconImages( URL svgUrl ) { - SVGDocument document = loadSVG( svgUrl ); + SVGDocument document = FlatSVGIcon.loadSVG( svgUrl ); if( SystemInfo.isWindows && MultiResolutionImageSupport.isAvailable() ) { // use a multi-resolution image that creates images on demand for requested sizes @@ -148,7 +148,7 @@ public class FlatSVGUtils * @since 2 */ public static BufferedImage svg2image( URL svgUrl, int width, int height ) { - return svg2image( loadSVG( svgUrl ), width, height ); + return svg2image( FlatSVGIcon.loadSVG( svgUrl ), width, height ); } /** @@ -180,7 +180,7 @@ public class FlatSVGUtils * @since 2 */ public static BufferedImage svg2image( URL svgUrl, float scaleFactor ) { - SVGDocument document = loadSVG( svgUrl ); + SVGDocument document = FlatSVGIcon.loadSVG( svgUrl ); FloatSize size = document.size(); int width = (int) (size.width * scaleFactor); int height = (int) (size.height * scaleFactor); @@ -196,7 +196,7 @@ public class FlatSVGUtils * @return the image * @throws RuntimeException if failed to render SVG file */ - public static BufferedImage svg2image( SVGDocument document, int width, int height ) { + private static BufferedImage svg2image( SVGDocument document, int width, int height ) { BufferedImage image = new BufferedImage( width, height, BufferedImage.TYPE_INT_ARGB ); Graphics2D g = image.createGraphics(); @@ -220,8 +220,4 @@ public class FlatSVGUtils private static URL getResource( String svgName ) { return FlatSVGUtils.class.getResource( svgName ); } - - private static SVGDocument loadSVG( URL url ) { - return FlatSVGIcon.loadSVG( FlatSVGIcon.url2uri( url ), url ); - } } From 193da2bc4d347560d2d3656bfb3406e8495b1df9 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Mon, 10 Jul 2023 13:49:30 +0200 Subject: [PATCH 4/6] jsvg: updated flatlaf-extras/README.md; removed svgSalamander from libs.versions.toml --- flatlaf-extras/README.md | 7 +++---- gradle/libs.versions.toml | 1 - 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/flatlaf-extras/README.md b/flatlaf-extras/README.md index 2933d1e4..55e38664 100644 --- a/flatlaf-extras/README.md +++ b/flatlaf-extras/README.md @@ -4,8 +4,7 @@ FlatLaf Extras This sub-project provides some additional components and classes: - [FlatSVGIcon](https://www.javadoc.io/doc/com.formdev/flatlaf-extras/latest/com/formdev/flatlaf/extras/FlatSVGIcon.html): - An icon that displays SVG using - [svgSalamander](https://github.com/JFormDesigner/svgSalamander).\ + An icon that displays SVG using [JSVG](https://github.com/weisJ/jsvg).\ ![FlatSVGIcon.png](../images/extras-FlatSVGIcon.png) - [FlatTriStateCheckBox](https://www.javadoc.io/doc/com.formdev/flatlaf-extras/latest/com/formdev/flatlaf/extras/components/FlatTriStateCheckBox.html): A tri-state check box.\ @@ -38,9 +37,9 @@ Otherwise download `flatlaf-extras-.jar` here: [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf-extras/badge.svg?style=flat-square&color=007ec6)](https://maven-badges.herokuapp.com/maven-central/com.formdev/flatlaf-extras) -If SVG classes are used, `svgSalamander-.jar` is also required: +If SVG classes are used, `jsvg-.jar` is also required: -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.formdev/svgSalamander/badge.svg?style=flat-square&color=007ec6)](https://maven-badges.herokuapp.com/maven-central/com.formdev/svgSalamander) +[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.weisj/jsvg/badge.svg?style=flat-square&color=007ec6)](https://maven-badges.herokuapp.com/maven-central/com.github.weisj/jsvg) Tools diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 764a7cff..c7d0dd9d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -24,7 +24,6 @@ junit = "5.7.2" sigtest = "org.netbeans.tools:sigtest-maven-plugin:1.7" # flatlaf-extras -svgSalamander = "com.formdev:svgSalamander:1.1.3" jsvg = "com.github.weisj:jsvg:1.0.0" # flatlaf-jide-oss From 4715d8d16c351a2c3e26e2657e6f42ad99c6d676 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Mon, 17 Jul 2023 12:43:09 +0200 Subject: [PATCH 5/6] jsvg: use `RenderingHints.VALUE_STROKE_PURE` for correct line rendering --- .../formdev/flatlaf/extras/FlatSVGIcon.java | 18 ++++++++++++------ .../formdev/flatlaf/extras/FlatSVGUtils.java | 4 +--- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java index c8ea11a2..ebc31143 100644 --- a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java +++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java @@ -574,12 +574,7 @@ public class FlatSVGIcon Graphics2D g2 = new GraphicsFilter( (Graphics2D) g.create(), colorFilter, ColorFilter.getInstance(), grayFilter ); try { - // same hints as in FlatUIUtils.setRenderingHints() - g2.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON ); - g2.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE ); - - // enable better image scaling - g2.setRenderingHint( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR ); + setRenderingHints( g2 ); paintSvg( g2, x, y ); } finally { @@ -652,6 +647,17 @@ public class FlatSVGIcon return MultiResolutionImageSupport.create( 0, dimensions, producer ); } + static void setRenderingHints( Graphics2D g ) { + // enable anti-aliasing + g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON ); + + // disable coordinate normalization for correct line rendering + g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE ); + + // enable better image scaling + g.setRenderingHint( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR ); + } + static URL uri2url( URI uri ) { try { return uri.toURL(); diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGUtils.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGUtils.java index 2c8d012e..bb546fa7 100644 --- a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGUtils.java +++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGUtils.java @@ -19,7 +19,6 @@ package com.formdev.flatlaf.extras; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Image; -import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.net.URL; import java.util.Arrays; @@ -201,8 +200,7 @@ public class FlatSVGUtils Graphics2D g = image.createGraphics(); try { - g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON ); - g.setRenderingHint( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR ); + FlatSVGIcon.setRenderingHints( g ); FloatSize size = document.size(); double sx = width / size.width; From 798a6d061cc6c050e7396d6f58d47e6a20ea989b Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Mon, 17 Jul 2023 23:42:26 +0200 Subject: [PATCH 6/6] jsvg: use String instead of URL as cache key to avoid this problem: https://errorprone.info/bugpattern/URLEqualsHashCode --- .../main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java index ebc31143..76117603 100644 --- a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java +++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java @@ -63,7 +63,7 @@ public class FlatSVGIcon implements DisabledIconProvider { // cache that uses soft references for values, which allows freeing SVG documents if no longer used - private static final SoftCache svgCache = new SoftCache<>(); + private static final SoftCache svgCache = new SoftCache<>(); private static final SVGLoader svgLoader = new SVGLoader(); private final String name; @@ -485,7 +485,8 @@ public class FlatSVGIcon static synchronized SVGDocument loadSVG( URL url ) { // get from our cache - SVGDocument document = svgCache.get( url ); + String cacheKey = url.toString(); + SVGDocument document = svgCache.get( cacheKey ); if( document != null ) return document; @@ -497,7 +498,7 @@ public class FlatSVGIcon return null; } - svgCache.put( url, document ); + svgCache.put( cacheKey, document ); return document; }