/** * Copyright (C) 2002-2012 The FreeCol Team * * This file is part of FreeCol. * * FreeCol is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * FreeCol is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with FreeCol. If not, see <http://www.gnu.org/licenses/>. */ package net.sf.freecol.common.resources; import java.io.InputStream; import java.net.URI; import java.net.URL; import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; import org.freecolandroid.repackaged.java.awt.Component; import org.freecolandroid.repackaged.java.awt.Dimension; import org.freecolandroid.repackaged.java.awt.Image; import org.freecolandroid.repackaged.java.awt.MediaTracker; import org.freecolandroid.repackaged.java.awt.Toolkit; import org.freecolandroid.repackaged.java.awt.image.BufferedImage; /** * A <code>Resource</code> wrapping an <code>Image</code>. * @see Resource */ public class ImageResource extends Resource { private static final Logger logger = Logger.getLogger(ImageResource.class.getName()); private Map<Dimension, Image> grayscaleImages = new HashMap<Dimension, Image>(); private Map<Dimension, Image> scaledImages = new HashMap<Dimension, Image>(); private Image image = null; private final Object loadingLock = new Object(); private static final Component _c = new Component() {}; /** * Do not use directly. * @param resourceLocator The <code>URI</code> used when loading this * resource. * @see ResourceFactory#createResource(URI) */ ImageResource(URI resourceLocator) { super(resourceLocator); } public ImageResource(Image image) { this.image = image; } @Override public void preload() { // No enough memory to preload all images. Instead we load them when // they are needed. } /** * Load the image. */ public void load() { synchronized (loadingLock) { if (image == null) { MediaTracker mt = new MediaTracker(_c); Image im; try { // Explicitly check that the URI is valid before // letting createImage go off and look for it, as the // error it throws is cryptic. URL url = getResourceLocator().toURL(); InputStream is = url.openStream(); is.close(); im = Toolkit.getDefaultToolkit().createImage(url); mt.addImage(im, 0); mt.waitForID(0); if (mt.statusID(0, false) == MediaTracker.COMPLETE) { image = im; } } catch (Throwable e) { logger.warning("Failed to load image from: " + getResourceLocator() + "\r\nProblem: " + e ); } } } } /** * Gets the <code>Image</code> represented by this resource. * * @return The image in it's original size. */ public Image getImage() { if (image == null) load(); return image; } /** * Returns the image using the specified scale. * * @param scale The size of the requested image (with 1 being normal size, * 2 twice the size, 0.5 half the size etc). Rescaling * will be performed unless using 1. * @return The scaled <code>Image</code>. */ public Image getImage(double scale) { final Image im = getImage(); if (im == null) return im; return getImage(new Dimension((int) (im.getWidth(null) * scale), (int) (im.getHeight(null) * scale))); } /** * Returns the image using the specified dimension. * * @param d The dimension of the requested image. Rescaling * will be performed if necessary. * @return The <code>Image</code>. */ public Image getImage(Dimension d) { final Image im = getImage(); if (im == null || ((im.getWidth(null)==d.width && im.getHeight(null)==d.height))) { return im; } final Image cachedScaledImage = scaledImages.get(d); if (cachedScaledImage != null) return cachedScaledImage; synchronized (loadingLock) { final Image cached = scaledImages.get(d); if (cached != null) return cached; MediaTracker mt = new MediaTracker(_c); try { //use SCALE_REPLICATE instead of SCALE_SMOOTH to avoid ClassCastException //TODO (perhaps): find better solution Image scaledVersion = im.getScaledInstance(d.width, d.height, Image.SCALE_REPLICATE); mt.addImage(scaledVersion, 0, d.width, d.height); mt.waitForID(0); if (mt.statusID(0, false) == MediaTracker.COMPLETE) { scaledImages.put(d, scaledVersion); return scaledVersion; } } catch (Exception e) { logger.warning("Failed to scale image: " + getResourceLocator() + "\r\nProblem: " + e ); } } return null; } /** * Gets a grayscale version of the image of the given size. * * @param d The requested size. * @return The <code>Image</code>. */ public Image getGrayscaleImage(Dimension d) { final Image im = getImage(d); // if (im == null) return null; // final Image cachedGrayscaleImage = grayscaleImages.get(d); // if (cachedGrayscaleImage != null) return cachedGrayscaleImage; // synchronized (loadingLock) { // final Image cached = grayscaleImages.get(d); // if (cached != null) return cached; // int width = im.getWidth(null); // int height = im.getHeight(null); // ColorConvertOp filter = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null); // BufferedImage srcImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); // srcImage.createGraphics().drawImage(im, 0, 0, null); // final Image grayscaleImage = filter.filter(srcImage, null); // grayscaleImages.put(d, grayscaleImage); // return grayscaleImage; // } return im; } /** * Returns the image using the specified scale. * * @param scale The size of the requested image (with 1 being normal size, * 2 twice the size, 0.5 half the size etc). Rescaling * will be performed unless using 1. * @return The <code>Image</code>. */ public Image getGrayscaleImage(double scale) { final Image im = getImage(); if (im == null) return im; return getGrayscaleImage(new Dimension((int) (im.getWidth(null) * scale), (int) (im.getHeight(null) * scale))); } public int getCount() { return grayscaleImages.size() + scaledImages.size(); } }