mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2025-12-06 14:00:55 +03:00
Replace svgSalamander with jsvg
This commit is contained in:
@@ -23,7 +23,7 @@ plugins {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation( project( ":flatlaf-core" ) )
|
implementation( project( ":flatlaf-core" ) )
|
||||||
implementation( libs.svgSalamander )
|
implementation( libs.jsvg )
|
||||||
}
|
}
|
||||||
|
|
||||||
flatlafModuleInfo {
|
flatlafModuleInfo {
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import java.awt.image.RGBImageFilter;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
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.MultiResolutionImageSupport;
|
||||||
import com.formdev.flatlaf.util.SoftCache;
|
import com.formdev.flatlaf.util.SoftCache;
|
||||||
import com.formdev.flatlaf.util.UIScale;
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
import com.kitfox.svg.SVGDiagram;
|
import com.github.weisj.jsvg.SVGDocument;
|
||||||
import com.kitfox.svg.SVGException;
|
import com.github.weisj.jsvg.geometry.size.FloatSize;
|
||||||
import com.kitfox.svg.SVGUniverse;
|
import com.github.weisj.jsvg.parser.SVGLoader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An icon that loads and paints SVG.
|
* An icon that loads and paints SVG.
|
||||||
@@ -62,11 +63,9 @@ public class FlatSVGIcon
|
|||||||
extends ImageIcon
|
extends ImageIcon
|
||||||
implements DisabledIconProvider
|
implements DisabledIconProvider
|
||||||
{
|
{
|
||||||
// cache that uses soft references for values, which allows freeing SVG diagrams if no longer used
|
// cache that uses soft references for values, which allows freeing SVG documents if no longer used
|
||||||
private static final SoftCache<URI, SVGDiagram> svgCache = new SoftCache<>();
|
private static final SoftCache<URI, SVGDocument> svgCache = new SoftCache<>();
|
||||||
|
private static final SVGLoader svgLoader = new SVGLoader();
|
||||||
// use own SVG universe so that it can not be cleared from anywhere
|
|
||||||
private static final SVGUniverse svgUniverse = new SVGUniverse();
|
|
||||||
private static int streamNumber;
|
private static int streamNumber;
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
@@ -79,7 +78,7 @@ public class FlatSVGIcon
|
|||||||
|
|
||||||
private ColorFilter colorFilter;
|
private ColorFilter colorFilter;
|
||||||
|
|
||||||
private SVGDiagram diagram;
|
private SVGDocument document;
|
||||||
private boolean dark;
|
private boolean dark;
|
||||||
private boolean loadFailed;
|
private boolean loadFailed;
|
||||||
|
|
||||||
@@ -270,7 +269,7 @@ public class FlatSVGIcon
|
|||||||
this( null, -1, -1, 1, false, null, loadFromStream( in ) );
|
this( null, -1, -1, 1, false, null, loadFromStream( in ) );
|
||||||
|
|
||||||
// since the input stream is already loaded and parsed,
|
// 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();
|
update();
|
||||||
synchronized( FlatSVGIcon.class ) {
|
synchronized( FlatSVGIcon.class ) {
|
||||||
svgCache.remove( uri );
|
svgCache.remove( uri );
|
||||||
@@ -279,7 +278,12 @@ public class FlatSVGIcon
|
|||||||
|
|
||||||
private static synchronized URI loadFromStream( InputStream in ) throws IOException {
|
private static synchronized URI loadFromStream( InputStream in ) throws IOException {
|
||||||
try( InputStream in2 = in ) {
|
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 ) {
|
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.uri );
|
||||||
colorFilter = icon.colorFilter;
|
colorFilter = icon.colorFilter;
|
||||||
diagram = icon.diagram;
|
document = icon.document;
|
||||||
dark = icon.dark;
|
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.name = name;
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
@@ -385,7 +391,7 @@ public class FlatSVGIcon
|
|||||||
|
|
||||||
FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, disabled, classLoader, uri );
|
FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, disabled, classLoader, uri );
|
||||||
icon.colorFilter = colorFilter;
|
icon.colorFilter = colorFilter;
|
||||||
icon.diagram = diagram;
|
icon.document = document;
|
||||||
icon.dark = dark;
|
icon.dark = dark;
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
@@ -404,7 +410,7 @@ public class FlatSVGIcon
|
|||||||
|
|
||||||
FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, disabled, classLoader, uri );
|
FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, disabled, classLoader, uri );
|
||||||
icon.colorFilter = colorFilter;
|
icon.colorFilter = colorFilter;
|
||||||
icon.diagram = diagram;
|
icon.document = document;
|
||||||
icon.dark = dark;
|
icon.dark = dark;
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
@@ -423,7 +429,7 @@ public class FlatSVGIcon
|
|||||||
|
|
||||||
FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, true, classLoader, uri );
|
FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, true, classLoader, uri );
|
||||||
icon.colorFilter = colorFilter;
|
icon.colorFilter = colorFilter;
|
||||||
icon.diagram = diagram;
|
icon.document = document;
|
||||||
icon.dark = dark;
|
icon.dark = dark;
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
@@ -462,18 +468,19 @@ public class FlatSVGIcon
|
|||||||
if( loadFailed )
|
if( loadFailed )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( dark == isDarkLaf() && diagram != null )
|
if( dark == isDarkLaf() && document != null )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dark = isDarkLaf();
|
dark = isDarkLaf();
|
||||||
|
|
||||||
// SVGs already loaded via url or input stream can not have light/dark variants
|
// 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;
|
return;
|
||||||
|
|
||||||
URI uri = this.uri;
|
URI uri = this.uri;
|
||||||
|
URL url = null;
|
||||||
if( uri == null ) {
|
if( uri == null ) {
|
||||||
URL url = getIconURL( name, dark );
|
url = getIconURL( name, dark );
|
||||||
if( url == null && dark )
|
if( url == null && dark )
|
||||||
url = getIconURL( name, false );
|
url = getIconURL( name, false );
|
||||||
|
|
||||||
@@ -486,29 +493,35 @@ public class FlatSVGIcon
|
|||||||
uri = url2uri( url );
|
uri = url2uri( url );
|
||||||
}
|
}
|
||||||
|
|
||||||
diagram = loadSVG( uri );
|
if( url == null ) {
|
||||||
loadFailed = (diagram == 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
|
// get from our cache
|
||||||
SVGDiagram diagram = svgCache.get( uri );
|
SVGDocument document = svgCache.get( uri );
|
||||||
if( diagram != null )
|
if( document != null )
|
||||||
return diagram;
|
return document;
|
||||||
|
|
||||||
// load/get SVG diagram
|
// load/get SVG document
|
||||||
diagram = svgUniverse.getDiagram( uri );
|
document = svgLoader.load( url );
|
||||||
|
|
||||||
if( diagram == null ) {
|
if( document == null ) {
|
||||||
LoggingFacade.INSTANCE.logSevere( "FlatSVGIcon: failed to load '" + uri + "'", null );
|
LoggingFacade.INSTANCE.logSevere( "FlatSVGIcon: failed to load '" + uri + "'", null );
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add to our (soft) cache and remove from SVGUniverse (hard) cache
|
svgCache.put( uri, document );
|
||||||
svgCache.put( uri, diagram );
|
|
||||||
svgUniverse.removeDocument( uri );
|
|
||||||
|
|
||||||
return diagram;
|
return document;
|
||||||
}
|
}
|
||||||
|
|
||||||
private URL getIconURL( String name, boolean dark ) {
|
private URL getIconURL( String name, boolean dark ) {
|
||||||
@@ -528,7 +541,7 @@ public class FlatSVGIcon
|
|||||||
*/
|
*/
|
||||||
public boolean hasFound() {
|
public boolean hasFound() {
|
||||||
update();
|
update();
|
||||||
return diagram != null;
|
return document != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -540,7 +553,7 @@ public class FlatSVGIcon
|
|||||||
return scaleSize( width );
|
return scaleSize( width );
|
||||||
|
|
||||||
update();
|
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 );
|
return scaleSize( height );
|
||||||
|
|
||||||
update();
|
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 ) {
|
private int scaleSize( int size ) {
|
||||||
@@ -597,7 +610,7 @@ public class FlatSVGIcon
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void paintSvg( Graphics2D g, int x, int y ) {
|
private void paintSvg( Graphics2D g, int x, int y ) {
|
||||||
if( diagram == null ) {
|
if( document == null ) {
|
||||||
paintSvgError( g, x, y );
|
paintSvgError( g, x, y );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -607,19 +620,18 @@ public class FlatSVGIcon
|
|||||||
|
|
||||||
UIScale.scaleGraphics( g );
|
UIScale.scaleGraphics( g );
|
||||||
if( width > 0 || height > 0 ) {
|
if( width > 0 || height > 0 ) {
|
||||||
double sx = (width > 0) ? width / diagram.getWidth() : 1;
|
FloatSize svgSize = document.size();
|
||||||
double sy = (height > 0) ? height / diagram.getHeight() : 1;
|
double sx = (width > 0) ? width / svgSize.width : 1;
|
||||||
|
double sy = (height > 0) ? height / svgSize.height : 1;
|
||||||
if( sx != 1 || sy != 1 )
|
if( sx != 1 || sy != 1 )
|
||||||
g.scale( sx, sy );
|
g.scale( sx, sy );
|
||||||
}
|
}
|
||||||
if( scale != 1 )
|
if( scale != 1 )
|
||||||
g.scale( scale, scale );
|
g.scale( scale, scale );
|
||||||
|
|
||||||
diagram.setIgnoringClipHeuristic( true );
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
diagram.render( g );
|
document.render( null, g );
|
||||||
} catch( SVGException ex ) {
|
} catch( Exception ex ) {
|
||||||
paintSvgError( g, 0, 0 );
|
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;
|
private static Boolean darkLaf;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ import java.util.List;
|
|||||||
import javax.swing.JWindow;
|
import javax.swing.JWindow;
|
||||||
import com.formdev.flatlaf.util.MultiResolutionImageSupport;
|
import com.formdev.flatlaf.util.MultiResolutionImageSupport;
|
||||||
import com.formdev.flatlaf.util.SystemInfo;
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
import com.kitfox.svg.SVGDiagram;
|
import com.github.weisj.jsvg.SVGDocument;
|
||||||
import com.kitfox.svg.SVGException;
|
import com.github.weisj.jsvg.geometry.size.FloatSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility methods for SVG.
|
* Utility methods for SVG.
|
||||||
@@ -83,7 +83,7 @@ public class FlatSVGUtils
|
|||||||
* @since 2
|
* @since 2
|
||||||
*/
|
*/
|
||||||
public static List<Image> createWindowIconImages( URL svgUrl ) {
|
public static List<Image> createWindowIconImages( URL svgUrl ) {
|
||||||
SVGDiagram diagram = loadSVG( svgUrl );
|
SVGDocument document = loadSVG( svgUrl );
|
||||||
|
|
||||||
if( SystemInfo.isWindows && MultiResolutionImageSupport.isAvailable() ) {
|
if( SystemInfo.isWindows && MultiResolutionImageSupport.isAvailable() ) {
|
||||||
// use a multi-resolution image that creates images on demand for requested sizes
|
// 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( 48, 48 ), // 300%
|
||||||
new Dimension( 64, 64 ), // 400%
|
new Dimension( 64, 64 ), // 400%
|
||||||
}, dim -> {
|
}, dim -> {
|
||||||
return svg2image( diagram, dim.width, dim.height );
|
return svg2image( document, dim.width, dim.height );
|
||||||
} ) );
|
} ) );
|
||||||
} else {
|
} else {
|
||||||
return Arrays.asList(
|
return Arrays.asList(
|
||||||
svg2image( diagram, 16, 16 ), // 100%
|
svg2image( document, 16, 16 ), // 100%
|
||||||
svg2image( diagram, 20, 20 ), // 125%
|
svg2image( document, 20, 20 ), // 125%
|
||||||
svg2image( diagram, 24, 24 ), // 150%
|
svg2image( document, 24, 24 ), // 150%
|
||||||
svg2image( diagram, 28, 28 ), // 175%
|
svg2image( document, 28, 28 ), // 175%
|
||||||
svg2image( diagram, 32, 32 ), // 200%
|
svg2image( document, 32, 32 ), // 200%
|
||||||
svg2image( diagram, 48, 48 ), // 300%
|
svg2image( document, 48, 48 ), // 300%
|
||||||
svg2image( diagram, 64, 64 ) // 400%
|
svg2image( document, 64, 64 ) // 400%
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -180,53 +180,48 @@ public class FlatSVGUtils
|
|||||||
* @since 2
|
* @since 2
|
||||||
*/
|
*/
|
||||||
public static BufferedImage svg2image( URL svgUrl, float scaleFactor ) {
|
public static BufferedImage svg2image( URL svgUrl, float scaleFactor ) {
|
||||||
SVGDiagram diagram = loadSVG( svgUrl );
|
SVGDocument document = loadSVG( svgUrl );
|
||||||
int width = (int) (diagram.getWidth() * scaleFactor);
|
FloatSize size = document.size();
|
||||||
int height = (int) (diagram.getHeight() * scaleFactor);
|
int width = (int) (size.width * scaleFactor);
|
||||||
return svg2image( diagram, width, height );
|
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 width the width of the image
|
||||||
* @param height the height of the image
|
* @param height the height of the image
|
||||||
* @return the image
|
* @return the image
|
||||||
* @throws RuntimeException if failed to render SVG file
|
* @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 {
|
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();
|
FloatSize size = document.size();
|
||||||
try {
|
double sx = width / size.width;
|
||||||
g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
|
double sy = height / size.height;
|
||||||
g.setRenderingHint( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR );
|
if( sx != 1 || sy != 1 )
|
||||||
|
g.scale( sx, sy );
|
||||||
|
|
||||||
double sx = width / diagram.getWidth();
|
document.render( null, g );
|
||||||
double sy = height / diagram.getHeight();
|
} finally {
|
||||||
if( sx != 1 || sy != 1 )
|
g.dispose();
|
||||||
g.scale( sx, sy );
|
|
||||||
|
|
||||||
diagram.setIgnoringClipHeuristic( true );
|
|
||||||
|
|
||||||
diagram.render( g );
|
|
||||||
} finally {
|
|
||||||
g.dispose();
|
|
||||||
}
|
|
||||||
return image;
|
|
||||||
|
|
||||||
} catch( SVGException ex ) {
|
|
||||||
throw new RuntimeException( ex );
|
|
||||||
}
|
}
|
||||||
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static URL getResource( String svgName ) {
|
private static URL getResource( String svgName ) {
|
||||||
return FlatSVGUtils.class.getResource( svgName );
|
return FlatSVGUtils.class.getResource( svgName );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SVGDiagram loadSVG( URL url ) {
|
private static SVGDocument loadSVG( URL url ) {
|
||||||
return FlatSVGIcon.loadSVG( FlatSVGIcon.url2uri( url ) );
|
return FlatSVGIcon.loadSVG( FlatSVGIcon.url2uri( url ), url );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
module com.formdev.flatlaf.extras {
|
module com.formdev.flatlaf.extras {
|
||||||
requires java.desktop;
|
requires java.desktop;
|
||||||
requires java.prefs;
|
requires java.prefs;
|
||||||
requires static com.kitfox.svg; // optional at runtime
|
requires static com.github.weisj.jsvg; // optional at runtime
|
||||||
requires com.formdev.flatlaf;
|
requires com.formdev.flatlaf;
|
||||||
|
|
||||||
exports com.formdev.flatlaf.extras;
|
exports com.formdev.flatlaf.extras;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ sigtest = "org.netbeans.tools:sigtest-maven-plugin:1.7"
|
|||||||
|
|
||||||
# flatlaf-extras
|
# flatlaf-extras
|
||||||
svgSalamander = "com.formdev:svgSalamander:1.1.3"
|
svgSalamander = "com.formdev:svgSalamander:1.1.3"
|
||||||
|
jsvg = "com.github.weisj:jsvg:1.0.0"
|
||||||
|
|
||||||
# flatlaf-jide-oss
|
# flatlaf-jide-oss
|
||||||
jide-oss = "com.formdev:jide-oss:3.7.12"
|
jide-oss = "com.formdev:jide-oss:3.7.12"
|
||||||
|
|||||||
Reference in New Issue
Block a user