diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/MultiResolutionImageSupport.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/MultiResolutionImageSupport.java
index 259db6ff..ace4a720 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/MultiResolutionImageSupport.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/MultiResolutionImageSupport.java
@@ -16,11 +16,20 @@
package com.formdev.flatlaf.util;
+import java.awt.Dimension;
import java.awt.Image;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
+//
+// NOTE:
+// This implementation is for Java 8 only.
+// There is also a variant for Java 9 and later.
+//
+// Make sure that the API is in sync.
+//
+
/**
* Support for multi-resolution images available since Java 9.
*
@@ -28,26 +37,86 @@ import java.util.function.Function;
*/
public class MultiResolutionImageSupport
{
+ /**
+ * Checks whether multi-resolution image support is available.
+ *
+ * @return {@code true} when running on Java 9 or later; {@code false} on Java 8
+ */
public static boolean isAvailable() {
return false;
}
+ /**
+ * Checks whether the given image is a multi-resolution image that implements
+ * the interface {@code java.awt.image.MultiResolutionImage}.
+ */
public static boolean isMultiResolutionImage( Image image ) {
return false;
}
+ /**
+ * Creates a multi-resolution image from the given resolution variants.
+ *
+ * @param baseImageIndex index of the base image in the resolution variants array
+ * @param resolutionVariants image resolution variants (sorted by size; smallest first)
+ * @return a multi-resolution image on Java 9 or later; the base image on Java 8
+ */
public static Image create( int baseImageIndex, Image... resolutionVariants ) {
return resolutionVariants[baseImageIndex];
}
+ /**
+ * Creates a multi-resolution image for the given dimensions.
+ * Initially the image does not contain any image data.
+ * The real images are created (and cached) on demand by invoking the given producer function.
+ *
+ * The given dimensions array is only used for {@link #getResolutionVariants(Image)}.
+ * The producer function may be invoked with any dimension (that is not contained in
+ * dimensions array) and is expected to produce a image for the passed in dimension.
+ *
+ * @param baseImageIndex index of the base image in the dimensions array
+ * @param dimensions dimensions of resolution variants (sorted by size; smallest first)
+ * @param producer producer function that creates a real image for the requested size
+ * @return a multi-resolution image on Java 9 or later; the base image on Java 8
+ */
+ public static Image create( int baseImageIndex, Dimension[] dimensions, Function producer ) {
+ return producer.apply( dimensions[baseImageIndex] );
+ }
+
+ /**
+ * Creates a multi-resolution image that maps images from another multi-resolution image
+ * using the given mapper function.
+ *
+ * Can be used to apply filter to multi-resolution images on demand.
+ * E.g. passed in image is for "enabled" state and mapper function creates images
+ * for "disabled" state.
+ *
+ * @param image a multi-resolution image that is mapped using the given mapper function
+ * @param mapper mapper function that maps a single resolution variant to a new image (e.g. applying an filter)
+ * @return a multi-resolution image on Java 9 or later; a mapped image on Java 8
+ */
public static Image map( Image image, Function mapper ) {
return mapper.apply( image );
}
+ /**
+ * Get the image variant that best matches the given width and height.
+ *
+ * If the given image is a multi-resolution image then invokes
+ * {@code java.awt.image.MultiResolutionImage.getResolutionVariant(destImageWidth, destImageHeight)}.
+ * Otherwise returns the given image.
+ */
public static Image getResolutionVariant( Image image, int destImageWidth, int destImageHeight ) {
return image;
}
+ /**
+ * Get a list of all resolution variants.
+ *
+ * If the given image is a multi-resolution image then invokes
+ * {@code java.awt.image.MultiResolutionImage.getResolutionVariants()}.
+ * Otherwise returns a list containing only the given image.
+ */
public static List getResolutionVariants( Image image ) {
return Collections.singletonList( image );
}
diff --git a/flatlaf-core/src/main/java9/com/formdev/flatlaf/util/MultiResolutionImageSupport.java b/flatlaf-core/src/main/java9/com/formdev/flatlaf/util/MultiResolutionImageSupport.java
index b23178d9..dd73d202 100644
--- a/flatlaf-core/src/main/java9/com/formdev/flatlaf/util/MultiResolutionImageSupport.java
+++ b/flatlaf-core/src/main/java9/com/formdev/flatlaf/util/MultiResolutionImageSupport.java
@@ -16,6 +16,7 @@
package com.formdev.flatlaf.util;
+import java.awt.Dimension;
import java.awt.Image;
import java.awt.image.AbstractMultiResolutionImage;
import java.awt.image.BaseMultiResolutionImage;
@@ -27,6 +28,14 @@ import java.util.List;
import java.util.function.Function;
import javax.swing.ImageIcon;
+//
+// NOTE:
+// This implementation is for Java 9 and later.
+// There is also a variant for Java 8.
+//
+// Make sure that the API is in sync.
+//
+
/**
* Support for multi-resolution images available since Java 9.
*
@@ -46,6 +55,10 @@ public class MultiResolutionImageSupport
return new BaseMultiResolutionImage( baseImageIndex, resolutionVariants );
}
+ public static Image create( int baseImageIndex, Dimension[] dimensions, Function producer ) {
+ return new ProducerMultiResolutionImage( dimensions, producer );
+ }
+
public static Image map( Image image, Function mapper ) {
return image instanceof MultiResolutionImage
? new MappedMultiResolutionImage( image, mapper )
@@ -66,6 +79,9 @@ public class MultiResolutionImageSupport
//---- class MappedMultiResolutionImage -----------------------------------
+ /**
+ * A multi-resolution image implementation that maps images on demand for requested sizes.
+ */
private static class MappedMultiResolutionImage
extends AbstractMultiResolutionImage
{
@@ -102,8 +118,52 @@ public class MultiResolutionImageSupport
private Image mapAndCacheImage( Image image ) {
return cache.computeIfAbsent( image, img -> {
+ // using ImageIcon here makes sure that the image is loaded
return new ImageIcon( mapper.apply( img ) ).getImage();
} );
}
}
+
+ //---- class ProducerMultiResolutionImage ---------------------------------
+
+ /**
+ * A multi-resolution image implementation that produces images on demand for requested sizes.
+ */
+ private static class ProducerMultiResolutionImage
+ extends AbstractMultiResolutionImage
+ {
+ private final Dimension[] dimensions;
+ private final Function producer;
+ private final IdentityHashMap cache = new IdentityHashMap<>();
+
+ ProducerMultiResolutionImage( Dimension[] dimensions, Function producer ) {
+ this.dimensions = dimensions;
+ this.producer = producer;
+ }
+
+ @Override
+ public Image getResolutionVariant( double destImageWidth, double destImageHeight ) {
+ return produceAndCacheImage( new Dimension( (int) destImageWidth, (int) destImageHeight ) );
+ }
+
+ @Override
+ public List getResolutionVariants() {
+ List mappedVariants = new ArrayList<>();
+ for( Dimension size : dimensions )
+ mappedVariants.add( produceAndCacheImage( size ) );
+ return mappedVariants;
+ }
+
+ @Override
+ protected Image getBaseImage() {
+ return produceAndCacheImage( dimensions[0] );
+ }
+
+ private Image produceAndCacheImage( Dimension size ) {
+ return cache.computeIfAbsent( size, size2 -> {
+ // using ImageIcon here makes sure that the image is loaded
+ return new ImageIcon( producer.apply( size2 ) ).getImage();
+ } );
+ }
+ }
}
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 c6789e84..ff7655b4 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
@@ -18,6 +18,7 @@ package com.formdev.flatlaf.extras;
import java.awt.Color;
import java.awt.Component;
+import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
@@ -30,6 +31,7 @@ import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
+import java.util.function.Function;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.UIManager;
@@ -39,6 +41,7 @@ import com.formdev.flatlaf.FlatLaf.DisabledIconProvider;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.Graphics2DProxy;
import com.formdev.flatlaf.util.GrayFilter;
+import com.formdev.flatlaf.util.MultiResolutionImageSupport;
import com.formdev.flatlaf.util.UIScale;
import com.kitfox.svg.SVGDiagram;
import com.kitfox.svg.SVGException;
@@ -349,14 +352,33 @@ public class FlatSVGIcon
public Image getImage() {
update();
- BufferedImage image = new BufferedImage( getIconWidth(), getIconHeight(), BufferedImage.TYPE_INT_ARGB );
- Graphics2D g = image.createGraphics();
- try {
- paintIcon( null, g, 0, 0 );
- } finally {
- g.dispose();
- }
- return image;
+ // base size
+ int iconWidth = getIconWidth();
+ int iconHeight = getIconHeight();
+
+ Dimension[] dimensions = new Dimension[] {
+ new Dimension( iconWidth, iconHeight ),
+ new Dimension( iconWidth * 2, iconHeight * 2 ),
+ };
+
+ Function producer = size -> {
+ BufferedImage image = new BufferedImage( size.width, size.height, BufferedImage.TYPE_INT_ARGB );
+ Graphics2D g = image.createGraphics();
+ try {
+ // scale from base size to passed size
+ double sx = (size.width > 0) ? (float) size.width / iconWidth : 1;
+ double sy = (size.height > 0) ? (float) size.height / iconHeight : 1;
+ if( sx != 1 || sy != 1 )
+ g.scale( sx, sy );
+
+ paintIcon( null, g, 0, 0 );
+ } finally {
+ g.dispose();
+ }
+ return image;
+ };
+
+ return MultiResolutionImageSupport.create( 0, dimensions, producer );
}
private static Boolean darkLaf;