Ignore:
Timestamp:
2013-08-21T18:15:12+02:00 (11 years ago)
Author:
Don-vip
Message:

fix #8849:

  • Used scaled down (16x16 pixels) of large (.svg) images if no size is explicitely defined
  • rendering of emergency=aed with recently added svg
  • optimizations/refactoring in icons rotating/rescaling code
  • fix of various warnings, javadoc
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/tools/ImageProvider.java

    r6151 r6172  
    44import static org.openstreetmap.josm.tools.I18n.tr;
    55
    6 import java.awt.Component;
    76import java.awt.Cursor;
    87import java.awt.Dimension;
     
    8382    }
    8483
     84    /**
     85     * Supported image types
     86     */
    8587    public static enum ImageType {
    86         SVG,    // scalable vector graphics
    87         OTHER   // everything else, e.g. png, gif (must be supported by Java)
     88        /** Scalable vector graphics */
     89        SVG,
     90        /** Everything else, e.g. png, gif (must be supported by Java) */
     91        OTHER
    8892    }
    8993
     
    107111     * The icon cache
    108112     */
    109     private static Map<String, ImageResource> cache = new HashMap<String, ImageResource>();
    110 
    111     private final static ExecutorService imageFetcher = Executors.newSingleThreadExecutor();
     113    private static final Map<String, ImageResource> cache = new HashMap<String, ImageResource>();
     114
     115    /**
     116     * Caches the image data for rotated versions of the same image.
     117     */
     118    private static final Map<Image, Map<Long, ImageResource>> rotateCache = new HashMap<Image, Map<Long, ImageResource>>();
     119
     120    private static final ExecutorService imageFetcher = Executors.newSingleThreadExecutor();
    112121
    113122    public interface ImageCallback {
     
    116125
    117126    /**
     127     * Constructs a new {@code ImageProvider} from a filename in a given directory.
    118128     * @param subdir    subdirectory the image lies in
    119129     * @param name      the name of the image. If it does not end with '.png' or '.svg',
     
    125135    }
    126136
     137    /**
     138     * Constructs a new {@code ImageProvider} from a filename.
     139     * @param name      the name of the image. If it does not end with '.png' or '.svg',
     140     *                  both extensions are tried.
     141     */
    127142    public ImageProvider(String name) {
    128143        this.name = name;
     
    131146    /**
    132147     * Directories to look for the image.
     148     * @param dirs The directories to look for.
     149     * @return the current object, for convenience
    133150     */
    134151    public ImageProvider setDirs(Collection<String> dirs) {
     
    141158     * If name starts with <tt>http://</tt> Id is not used for the cache.
    142159     * (A URL is unique anyway.)
     160     * @return the current object, for convenience
    143161     */
    144162    public ImageProvider setId(String id) {
     
    151169     *
    152170     * (optional)
     171     * @return the current object, for convenience
    153172     */
    154173    public ImageProvider setArchive(File archive) {
     
    163182     *
    164183     * (optional)
     184     * @return the current object, for convenience
    165185     */
    166186    public ImageProvider setInArchiveDir(String inArchiveDir) {
     
    175195     * The width part of the dimension can be -1. Then it will only set the height but
    176196     * keep the aspect ratio. (And the other way around.)
     197     * @return the current object, for convenience
    177198     */
    178199    public ImageProvider setSize(Dimension size) {
     
    184205    /**
    185206     * @see #setSize
     207     * @return the current object, for convenience
    186208     */
    187209    public ImageProvider setWidth(int width) {
     
    192214    /**
    193215     * @see #setSize
     216     * @return the current object, for convenience
    194217     */
    195218    public ImageProvider setHeight(int height) {
     
    205228     *
    206229     * 'size' and 'maxSize' are not compatible, you should set only one of them.
     230     * @return the current object, for convenience
    207231     */
    208232    public ImageProvider setMaxSize(Dimension maxSize) {
     
    214238    /**
    215239     * Convenience method, see {@link #setMaxSize(Dimension)}.
     240     * @return the current object, for convenience
    216241     */
    217242    public ImageProvider setMaxSize(int maxSize) {
     
    221246    /**
    222247     * @see #setMaxSize
     248     * @return the current object, for convenience
    223249     */
    224250    public ImageProvider setMaxWidth(int maxWidth) {
     
    229255    /**
    230256     * @see #setMaxSize
     257     * @return the current object, for convenience
    231258     */
    232259    public ImageProvider setMaxHeight(int maxHeight) {
     
    253280     *
    254281     * In combination with setOptional(true);
     282     * @return the current object, for convenience
    255283     */
    256284    public ImageProvider setSuppressWarnings(boolean suppressWarnings) {
     
    261289    /**
    262290     * Add a collection of additional class loaders to search image for.
     291     * @return the current object, for convenience
    263292     */
    264293    public ImageProvider setAdditionalClassLoaders(Collection<ClassLoader> additionalClassLoaders) {
     
    388417                }
    389418            } catch (UnsupportedEncodingException ex) {
    390                 throw new RuntimeException(ex.getMessage(), ex);
    391             } catch (IOException ex) {
    392419                throw new RuntimeException(ex.getMessage(), ex);
    393420            }
     
    482509
    483510    private static ImageResource getIfAvailableHttp(String url, ImageType type) {
     511        MirroredInputStream is = null;
    484512        try {
    485             MirroredInputStream is = new MirroredInputStream(url,
     513            is = new MirroredInputStream(url,
    486514                    new File(Main.pref.getCacheDirectory(), "images").getPath());
    487515            switch (type) {
     
    501529        } catch (IOException e) {
    502530            return null;
     531        } finally {
     532            Utils.close(is);
    503533        }
    504534    }
     
    791821     * Creates a rotated version of the input image.
    792822     *
    793      * @param c The component to get properties useful for painting, e.g. the foreground or
    794      * background color.
    795823     * @param img the image to be rotated.
    796824     * @param rotatedAngle the rotated angle, in degree, clockwise. It could be any double but we
    797      * will mod it with 360 before using it.
     825     * will mod it with 360 before using it. More over for caching performance, it will be rounded to
     826     * an entire value between 0 and 360.
    798827     *
    799828     * @return the image after rotating.
    800      */
    801     public static Image createRotatedImage(Component c, Image img, double rotatedAngle) {
    802         // convert rotatedAngle to a value from 0 to 360
    803         double originalAngle = rotatedAngle % 360;
     829     * @since 6172
     830     */
     831    public static Image createRotatedImage(Image img, double rotatedAngle) {
     832        return createRotatedImage(img, rotatedAngle, ImageResource.DEFAULT_DIMENSION);
     833    }
     834   
     835    /**
     836     * Creates a rotated version of the input image, scaled to the given dimension.
     837     *
     838     * @param img the image to be rotated.
     839     * @param rotatedAngle the rotated angle, in degree, clockwise. It could be any double but we
     840     * will mod it with 360 before using it. More over for caching performance, it will be rounded to
     841     * an entire value between 0 and 360.
     842     * @param dimension The requested dimensions. Use (-1,-1) for the original size
     843     * and (width, -1) to set the width, but otherwise scale the image proportionally.
     844     * @return the image after rotating and scaling.
     845     * @since 6172
     846     */
     847    public static Image createRotatedImage(Image img, double rotatedAngle, Dimension dimension) {
     848        CheckParameterUtil.ensureParameterNotNull(img, "img");
     849       
     850        // convert rotatedAngle to an integer value from 0 to 360
     851        Long originalAngle = Math.round(rotatedAngle % 360);
    804852        if (rotatedAngle != 0 && originalAngle == 0) {
    805             originalAngle = 360.0;
    806         }
    807 
    808         // convert originalAngle to a value from 0 to 90
    809         double angle = originalAngle % 90;
    810         if (originalAngle != 0.0 && angle == 0.0) {
    811             angle = 90.0;
    812         }
    813 
    814         double radian = Math.toRadians(angle);
    815 
    816         new ImageIcon(img); // load completely
    817         int iw = img.getWidth(null);
    818         int ih = img.getHeight(null);
    819         int w;
    820         int h;
    821 
    822         if ((originalAngle >= 0 && originalAngle <= 90) || (originalAngle > 180 && originalAngle <= 270)) {
    823             w = (int) (iw * Math.sin(DEGREE_90 - radian) + ih * Math.sin(radian));
    824             h = (int) (iw * Math.sin(radian) + ih * Math.sin(DEGREE_90 - radian));
    825         } else {
    826             w = (int) (ih * Math.sin(DEGREE_90 - radian) + iw * Math.sin(radian));
    827             h = (int) (ih * Math.sin(radian) + iw * Math.sin(DEGREE_90 - radian));
    828         }
    829         BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
    830         Graphics g = image.getGraphics();
    831         Graphics2D g2d = (Graphics2D) g.create();
    832 
    833         // calculate the center of the icon.
    834         int cx = iw / 2;
    835         int cy = ih / 2;
    836 
    837         // move the graphics center point to the center of the icon.
    838         g2d.translate(w / 2, h / 2);
    839 
    840         // rotate the graphics about the center point of the icon
    841         g2d.rotate(Math.toRadians(originalAngle));
    842 
    843         g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
    844         g2d.drawImage(img, -cx, -cy, c);
    845 
    846         g2d.dispose();
    847         new ImageIcon(image); // load completely
    848         return image;
     853            originalAngle = 360L;
     854        }
     855       
     856        ImageResource imageResource = null;
     857
     858        synchronized (rotateCache) {
     859            Map<Long, ImageResource> cacheByAngle = rotateCache.get(img);
     860            if (cacheByAngle == null) {
     861                rotateCache.put(img, cacheByAngle = new HashMap<Long, ImageResource>());
     862            }
     863           
     864            imageResource = cacheByAngle.get(originalAngle);
     865           
     866            if (imageResource == null) {
     867                // convert originalAngle to a value from 0 to 90
     868                double angle = originalAngle % 90;
     869                if (originalAngle != 0.0 && angle == 0.0) {
     870                    angle = 90.0;
     871                }
     872       
     873                double radian = Math.toRadians(angle);
     874       
     875                new ImageIcon(img); // load completely
     876                int iw = img.getWidth(null);
     877                int ih = img.getHeight(null);
     878                int w;
     879                int h;
     880       
     881                if ((originalAngle >= 0 && originalAngle <= 90) || (originalAngle > 180 && originalAngle <= 270)) {
     882                    w = (int) (iw * Math.sin(DEGREE_90 - radian) + ih * Math.sin(radian));
     883                    h = (int) (iw * Math.sin(radian) + ih * Math.sin(DEGREE_90 - radian));
     884                } else {
     885                    w = (int) (ih * Math.sin(DEGREE_90 - radian) + iw * Math.sin(radian));
     886                    h = (int) (ih * Math.sin(radian) + iw * Math.sin(DEGREE_90 - radian));
     887                }
     888                Image image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
     889                cacheByAngle.put(originalAngle, imageResource = new ImageResource(image));
     890                Graphics g = image.getGraphics();
     891                Graphics2D g2d = (Graphics2D) g.create();
     892       
     893                // calculate the center of the icon.
     894                int cx = iw / 2;
     895                int cy = ih / 2;
     896       
     897                // move the graphics center point to the center of the icon.
     898                g2d.translate(w / 2, h / 2);
     899       
     900                // rotate the graphics about the center point of the icon
     901                g2d.rotate(Math.toRadians(originalAngle));
     902       
     903                g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
     904                g2d.drawImage(img, -cx, -cy, null);
     905       
     906                g2d.dispose();
     907                new ImageIcon(image); // load completely
     908            }
     909            return imageResource.getImageIcon(dimension).getImage();
     910        }
     911    }
     912   
     913    /**
     914     * Creates a scaled down version of the input image to fit maximum dimensions. (Keeps aspect ratio)
     915     *
     916     * @param img the image to be scaled down.
     917     * @param maxSize the maximum size in pixels (both for width and height)
     918     *
     919     * @return the image after scaling.
     920     * @since 6172
     921     */
     922    public static Image createBoundedImage(Image img, int maxSize) {
     923        return new ImageResource(img).getImageIconBounded(new Dimension(maxSize, maxSize)).getImage();
    849924    }
    850925
     
    886961        Graphics2D g = img.createGraphics();
    887962        g.setClip(0, 0, width, height);
    888         if (scaleX != null) {
     963        if (scaleX != null && scaleY != null) {
    889964            g.scale(scaleX, scaleY);
    890965        }
Note: See TracChangeset for help on using the changeset viewer.