001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.tools;
003
004import java.awt.Dimension;
005import java.awt.Image;
006import java.awt.image.BufferedImage;
007import java.util.HashMap;
008import java.util.Map;
009
010import javax.swing.ImageIcon;
011
012import com.kitfox.svg.SVGDiagram;
013
014/**
015 * Holds data for one particular image.
016 * It can be backed by a svg or raster image.
017 *
018 * In the first case, 'svg' is not null and in the latter case, 'imgCache' has
019 * at least one entry for the key DEFAULT_DIMENSION.
020 * @since 4271
021 */
022class ImageResource {
023
024    /**
025     * Caches the image data for resized versions of the same image.
026     */
027    private Map<Dimension, Image> imgCache = new HashMap<>();
028    private SVGDiagram svg;
029    public static final Dimension DEFAULT_DIMENSION = new Dimension(-1, -1);
030
031    public ImageResource(Image img) {
032        CheckParameterUtil.ensureParameterNotNull(img);
033        imgCache.put(DEFAULT_DIMENSION, img);
034    }
035
036    public ImageResource(SVGDiagram svg) {
037        CheckParameterUtil.ensureParameterNotNull(svg);
038        this.svg = svg;
039    }
040
041    public ImageIcon getImageIcon() {
042        return getImageIcon(DEFAULT_DIMENSION);
043    }
044
045    /**
046     * Get an ImageIcon object for the image of this resource
047     * @param   dim The requested dimensions. Use (-1,-1) for the original size
048     *          and (width, -1) to set the width, but otherwise scale the image
049     *          proportionally.
050     * @return ImageIcon object for the image of this resource, scaled according to dim
051     */
052    public ImageIcon getImageIcon(Dimension dim) {
053        if (dim.width < -1 || dim.width == 0 || dim.height < -1 || dim.height == 0)
054            throw new IllegalArgumentException();
055        Image img = imgCache.get(dim);
056        if (img != null) {
057            return new ImageIcon(img);
058        }
059        if (svg != null) {
060            img = ImageProvider.createImageFromSvg(svg, dim);
061            if (img == null) {
062                return null;
063            }
064            imgCache.put(dim, img);
065            return new ImageIcon(img);
066        } else {
067            Image base = imgCache.get(DEFAULT_DIMENSION);
068            if (base == null) throw new AssertionError();
069
070            int width = dim.width;
071            int height = dim.height;
072            ImageIcon icon = new ImageIcon(base);
073            if (width == -1) {
074                width = Math.max(1, icon.getIconWidth() * height / icon.getIconHeight());
075            } else if (height == -1) {
076                height = Math.max(1, icon.getIconHeight() * width / icon.getIconWidth());
077            }
078            Image i = icon.getImage().getScaledInstance(width, height, Image.SCALE_SMOOTH);
079            img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
080            img.getGraphics().drawImage(i, 0, 0, null);
081            imgCache.put(dim, img);
082            return new ImageIcon(img);
083        }
084    }
085
086    /**
087     * Get image icon with a certain maximum size. The image is scaled down
088     * to fit maximum dimensions. (Keeps aspect ratio)
089     *
090     * @param maxSize The maximum size. One of the dimensions (widht or height) can be -1,
091     * which means it is not bounded.
092     * @return ImageIcon object for the image of this resource, scaled down if needed, according to maxSize
093     */
094    public ImageIcon getImageIconBounded(Dimension maxSize) {
095        if (maxSize.width < -1 || maxSize.width == 0 || maxSize.height < -1 || maxSize.height == 0)
096            throw new IllegalArgumentException();
097        float realWidth;
098        float realHeight;
099        if (svg != null) {
100            realWidth = svg.getWidth();
101            realHeight = svg.getHeight();
102        } else {
103            Image base = imgCache.get(DEFAULT_DIMENSION);
104            if (base == null) throw new AssertionError();
105            ImageIcon icon = new ImageIcon(base);
106            realWidth = icon.getIconWidth();
107            realHeight = icon.getIconHeight();
108        }
109        int maxWidth = maxSize.width;
110        int maxHeight = maxSize.height;
111
112        if (realWidth <= maxWidth) {
113            maxWidth = -1;
114        }
115        if (realHeight <= maxHeight) {
116            maxHeight = -1;
117        }
118
119        if (maxWidth == -1 && maxHeight == -1)
120            return getImageIcon(DEFAULT_DIMENSION);
121        else if (maxWidth == -1)
122            return getImageIcon(new Dimension(-1, maxHeight));
123        else if (maxHeight == -1)
124            return getImageIcon(new Dimension(maxWidth, -1));
125        else
126            if (realWidth / maxWidth > realHeight / maxHeight)
127                return getImageIcon(new Dimension(maxWidth, -1));
128            else
129                return getImageIcon(new Dimension(-1, maxHeight));
130   }
131}