001/*
002 * Copyright 2006 - 2013
003 *     Stefan Balev     <stefan.balev@graphstream-project.org>
004 *     Julien Baudry    <julien.baudry@graphstream-project.org>
005 *     Antoine Dutot    <antoine.dutot@graphstream-project.org>
006 *     Yoann Pigné      <yoann.pigne@graphstream-project.org>
007 *     Guilhelm Savin   <guilhelm.savin@graphstream-project.org>
008 * 
009 * This file is part of GraphStream <http://graphstream-project.org>.
010 * 
011 * GraphStream is a library whose purpose is to handle static or dynamic
012 * graph, create them from scratch, file or any source and display them.
013 * 
014 * This program is free software distributed under the terms of two licenses, the
015 * CeCILL-C license that fits European law, and the GNU Lesser General Public
016 * License. You can  use, modify and/ or redistribute the software under the terms
017 * of the CeCILL-C license as circulated by CEA, CNRS and INRIA at the following
018 * URL <http://www.cecill.info> or under the terms of the GNU LGPL as published by
019 * the Free Software Foundation, either version 3 of the License, or (at your
020 * option) any later version.
021 * 
022 * This program is distributed in the hope that it will be useful, but WITHOUT ANY
023 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
024 * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
025 * 
026 * You should have received a copy of the GNU Lesser General Public License
027 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
028 * 
029 * The fact that you are presently reading this means that you have had
030 * knowledge of the CeCILL-C and LGPL licenses and that you accept their terms.
031 */
032package org.graphstream.ui.swingViewer.util;
033
034import java.awt.Color;
035import java.awt.Graphics2D;
036import java.awt.Image;
037import java.awt.image.BufferedImage;
038import java.io.File;
039import java.io.IOException;
040import java.net.URL;
041import java.util.HashMap;
042
043import javax.imageio.ImageIO;
044
045/**
046 * A simple cache for images to avoid reloading them constantly and to allow
047 * sharing.
048 * 
049 * TODO have a policy to release images if they have not been used for a given
050 * time.
051 */
052public class ImageCache {
053        /**
054         * The image cache.
055         */
056        protected HashMap<String, Image> imageCache = new HashMap<String, Image>();
057
058        /**
059         * The dummy image used to mark a not found image (and avoid trying to
060         * reload it again and again).
061         */
062        protected Image dummy;
063
064        /**
065         * The default singleton image cache instance.
066         */
067        protected static ImageCache defaultImageCache;
068
069        /**
070         * New empty image cache.
071         */
072        public ImageCache() {
073                BufferedImage img = new BufferedImage(16, 16,
074                                BufferedImage.TYPE_INT_RGB);
075                Graphics2D g2 = img.createGraphics();
076
077                g2.setColor(Color.RED);
078                g2.drawRect(0, 0, img.getWidth() - 1, img.getHeight() - 1);
079                g2.drawLine(0, 0, img.getWidth() - 1, img.getHeight() - 1);
080                g2.drawLine(0, img.getHeight() - 1, img.getWidth() - 1, 0);
081
082                dummy = img;
083        }
084
085        /**
086         * Default singleton image cache instance that can be shared. This method
087         * and singleton must be used only in the Swing thread.
088         * 
089         * @return The default singleton image cache instance.
090         */
091        public static ImageCache defaultImageCache() {
092                if (defaultImageCache == null)
093                        defaultImageCache = new ImageCache();
094
095                return defaultImageCache;
096        }
097
098        /**
099         * Lookup an image based on its name, if found return it, else try to load
100         * it. If an image is not found once, the cache remembers it and will not
101         * try to reload it again if the same image is requested anew. Therefore
102         * using getImage() is fast and smooth.
103         * 
104         * @param fileNameOrUrl
105         *            A file name or an URL pointing at the image.
106         * @return An image or null if the image cannot be found.
107         */
108        public Image getImage(String fileNameOrUrl) {
109                return getImage(fileNameOrUrl, false);
110        }
111
112        /**
113         * The same as {@link #getImage(String)} but you can force the cache to try
114         * to reload an image that where not found before.
115         * 
116         * @param fileNameOrUrl
117         *            A file name or an URL pointing at the image.
118         * @param forceTryReload
119         *            If true, try to reload an image that where not found before.
120         * @return An image or null if the image cannot be found.
121         */
122        public Image getImage(String fileNameOrUrl, boolean forceTryReload) {
123                Image ii = imageCache.get(fileNameOrUrl);
124
125                if (ii == dummy && !forceTryReload)
126                        return null;
127
128                if (ii == null) {
129                        URL url = ImageCache.class.getClassLoader().getResource(
130                                        fileNameOrUrl);
131
132                        if (url != null) {
133                                try {
134                                        ii = ImageIO.read(url);
135                                        imageCache.put(fileNameOrUrl, ii);
136                                } catch (IOException e) {
137                                        e.printStackTrace();
138                                }
139                        } else {
140                                try {
141                                        url = new URL(fileNameOrUrl);
142
143                                        ii = ImageIO.read(url);
144                                        imageCache.put(fileNameOrUrl, ii);
145                                } catch (Exception e) {
146                                        try {
147                                                ii = ImageIO.read(new File(fileNameOrUrl));
148                                                imageCache.put(fileNameOrUrl, ii);
149                                        } catch (IOException ee) {
150                                                imageCache.put(fileNameOrUrl, dummy);
151                                                // ee.printStackTrace();
152                                                System.err.printf("Cannot read image '%s'%n",
153                                                                fileNameOrUrl);
154                                        }
155                                }
156                        }
157                }
158
159                return ii;
160        }
161
162        /**
163         * A dummy 16x16 image.
164         * 
165         * @return An image.
166         */
167        public Image getDummyImage() {
168                return dummy;
169        }
170}