/*
GeoGebra - Dynamic Mathematics for Everyone
http://www.geogebra.org
This file is part of GeoGebra.
This program 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.
*/
package org.geogebra.desktop.util;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.PixelGrabber;
import java.util.Hashtable;
import javax.swing.ImageIcon;
import org.geogebra.common.main.App;
import org.geogebra.common.util.FileExtensions;
import org.geogebra.common.util.ImageManager;
import org.geogebra.common.util.StringUtil;
import org.geogebra.common.util.debug.Log;
import org.geogebra.desktop.gui.MyImageD;
import org.geogebra.desktop.main.AppD;
/**
* An ImageManager provides methods for loading images and icons for a JFrame.
* To save memory every image and icon will be loaded only once.
*
* @author Markus Hohenwarter
*/
public class ImageManagerD extends ImageManager {
private Hashtable<String, ImageIcon> iconTable = new Hashtable<String, ImageIcon>();
private Hashtable<String, MyImageD> internalImageTable = new Hashtable<String, MyImageD>();
private static Hashtable<String, MyImageD> externalImageTable = new Hashtable<String, MyImageD>();
private Toolkit toolKit;
private MediaTracker tracker;
private int maxIconSize = 64;// DEFAULT_ICON_SIZE;
/**
* Creates a new ImageManager for the given JFrame.
*/
public ImageManagerD(Component comp) {
toolKit = Toolkit.getDefaultToolkit();
tracker = new MediaTracker(comp);
}
public void clearAllImages() {
iconTable.clear();
internalImageTable.clear();
externalImageTable.clear();
}
/**
* Gets the icon specified by fileName.
*
* @return icon for fileName or null
*/
public ImageIcon getImageIcon(ImageResourceD fileName) {
return getImageIcon(fileName, null);
}
/**
*
* @param fileName
* icon filename
* @param borderColor
* if borderColor == null no border is added
* @return icon
*/
public ImageIcon getImageIcon(ImageResourceD fileName, Color borderColor) {
return getImageIcon(fileName, borderColor, null);
}
public ImageIcon getImageIcon(ImageResourceD fileName, Color borderColor,
Color background) {
ImageIcon icon = iconTable.get(fileName.getFilename());
if (icon == null) {
// load the icon
Image im = getImageResourceGeoGebra(fileName);
if (im != null) {
icon = new ImageIcon(addBorder(im, borderColor, background));
iconTable.put(fileName.getFilename(), icon);
}
}
return icon;
}
// draw a line around the image
public static Image addBorder(Image im, Color borderColor,
Color background) {
if (borderColor == null) {
return im;
}
BufferedImage bim = toBufferedImage(im);
Graphics g = bim.getGraphics();
if (background != null) {
g.setColor(Color.WHITE);
g.fillRect(0, 0, bim.getWidth() - 1, bim.getHeight() - 1);
g.drawImage(im, 0, 0, null);
}
g.setColor(borderColor);
g.drawRect(0, 0, bim.getWidth() - 1, bim.getHeight() - 1);
return bim;
}
/**
* Gets the image specified by fileName.
*
* @return image for fileName or null
*/
public MyImageD getInternalImage(ImageResourceD fileName) {
MyImageD img = null;
MyImageD ob = internalImageTable.get(fileName.getFilename());
if (ob != null) {
// image already loaded
img = ob;
} else {
// load the image from disk
Image imgNative = getImageResourceGeoGebra(fileName);
if (imgNative != null) {
img = new MyImageD(imgNative);
internalImageTable.put(fileName.getFilename(), img);
}
}
return img;
}
public void addExternalImage(String fileName0, MyImageD img) {
if (fileName0 != null && img != null) {
String fileName = fileName0;
// GIF saved as PNG in .ggb files so need to change extension
FileExtensions ext = StringUtil.getFileExtension(fileName);
if (!ext.isAllowedImage()) {
fileName = StringUtil.changeFileExtension(fileName,
FileExtensions.PNG);
}
fileName = fileName.replace(".GIF", ".png");
Log.debug("storing " + fileName + " " + img.isSVG());
externalImageTable.put(fileName, img);
}
}
public static MyImageD getExternalImage(String fileName0) {
String fileName = fileName0;
// GIF saved as PNG in .ggb files so need to change extension
FileExtensions ext = StringUtil.getFileExtension(fileName);
if (!ext.isAllowedImage()) {
fileName = StringUtil.changeFileExtension(fileName,
FileExtensions.PNG);
}
// Log.debug("retrieving filename = " + fileName);
MyImageD ret = externalImageTable.get(fileName);
// Log.debug("(ret == null)" + (ret == null));
return ret;
}
/*
* private class FileNamePair { File file; String name;
*
* FileNamePair(File file, String name) { this.file = file; this.name =
* name; } }
*/
/**
* get image for icons and other automatically add "/org/geogebra/desktop"
* prefix
*
* @param name
* name of the image (without "/org/geogebra/desktop" prefix)
* @return the image
*/
public Image getImageResourceGeoGebra(ImageResourceD name) {
Image img = getImageResource(name);
if (img == null) {
img = getImageResource(
"/org/geogebra/desktop" + name.getFilename());
}
if (img == null) {
Log.error("Image " + name.getFilename() + " not found");
}
return img;
}
public Image getImageResource(ImageResourceD name) {
return getImageResource(name.getFilename());
}
/**
* return image from the full path name
*
* @param name
* @return image from the full path name
*/
protected Image getImageResource(String name) {
String path = name;
if (!name.startsWith("/org")) {
path = "/org/geogebra/desktop" + path;
}
Image img = null;
try {
java.net.URL url = ImageManagerD.class.getResource(path);
if (url != null) {
img = toolKit.getImage(url);
tracker.addImage(img, 0);
try {
tracker.waitForAll();
} catch (InterruptedException e) {
Log.debug("Interrupted while loading Image: " + path);
}
tracker.removeImage(img);
}
} catch (Exception e) {
Log.debug(e.toString());
}
return img;
}
// This method returns a buffered image with the contents of an image
public static BufferedImage toBufferedImage(Image image) {
// Determine if the image has transparent pixels; for this method's
// implementation, see e661 Determining If an Image Has Transparent
// Pixels
boolean hasAlpha = hasAlpha(image);
if (hasAlpha) {
return toBufferedImage(image, Transparency.BITMASK);
}
return toBufferedImage(image, Transparency.OPAQUE);
}
public static BufferedImage toBufferedImage(Image image0,
int transparency) {
if (image0 instanceof BufferedImage) {
return (BufferedImage) image0;
}
// This code ensures that all the pixels in the image are loaded
Image image = new ImageIcon(image0).getImage();
// Create a buffered image with a format that's compatible with the
// screen
BufferedImage bimage = null;
GraphicsEnvironment ge = GraphicsEnvironment
.getLocalGraphicsEnvironment();
try {
// Create the buffered image
GraphicsDevice gs = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gs.getDefaultConfiguration();
bimage = gc.createCompatibleImage(image.getWidth(null),
image.getHeight(null), transparency);
} catch (HeadlessException e) {
// The system does not have a screen
}
if (bimage == null) {
// Create a buffered image using the default color model
int type;
if (transparency == Transparency.OPAQUE) {
type = BufferedImage.TYPE_INT_RGB;
} else {
type = BufferedImage.TYPE_INT_ARGB;
}
bimage = new BufferedImage(image.getWidth(null),
image.getHeight(null), type);
}
// Copy image to buffered image
Graphics g = bimage.createGraphics();
// Paint the image onto the buffered image
g.drawImage(image, 0, 0, null);
g.dispose();
return bimage;
}
// This method returns true if the specified image has transparent pixels
public static boolean hasAlpha(Image image) {
// If buffered image, the color model is readily available
if (image instanceof BufferedImage) {
BufferedImage bimage = (BufferedImage) image;
return bimage.getColorModel().hasAlpha();
}
// Use a pixel grabber to retrieve the image's color model;
// grabbing a single pixel is usually sufficient
PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
try {
pg.grabPixels();
} catch (InterruptedException e) {
}
// Get the image's color model
ColorModel cm = pg.getColorModel();
if (cm == null) {
return false;
}
return cm.hasAlpha();
}
public static ImageIcon getScaledIcon(ImageIcon icon, int width,
int height) {
if (icon.getIconWidth() == width && icon.getIconHeight() == height) {
return icon;
}
Image scaledImage = getScaledImage(icon.getImage(), width, height);
return new ImageIcon(scaledImage);
}
public static Image getScaledImage(Image img, int width, int height) {
// scale image
BufferedImage scaledImage = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics2D graphics2D = scaledImage.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
graphics2D.drawImage(img, 0, 0, width, height, null);
graphics2D.dispose();
return scaledImage;
}
public String createImage(ImageResourceD res, App app) {
Image im = getImageResource(res);
BufferedImage image = ImageManagerD.toBufferedImage(im);
String fileName = ((AppD) app).createImage(new MyImageD(image),
"tool.png");
return fileName;
}
public ImageResourceD getToolImageResource(String modeText) {
String filename = "mode_" + StringUtil.toLowerCase(modeText) + ".png";
String path = getToolbarIconPath() + filename;
return new ImageResourceDImpl(path);
}
public ImageIcon getFlagIcon(String filename) {
return getImageIcon(
new ImageResourceDImpl("/gui/menubar/images/" + filename),
null);
}
public String getToolbarIconPath() {
if (getMaxIconSize() <= 32) {
return "/org/geogebra/common/icons_toolbar/p32/";
}
return "/org/geogebra/common/icons_toolbar/p64/";
}
public void setMaxIconSizeAsPt(int points) {
setMaxIconSize(Math.max(32, points * 2));
}
/**
* Sets the maximum pixel size (width and height) of all icons in the user
* interface. Larger icons are scaled down.
*
* @param pixel
* max icon size between 16 and 32 pixels
*/
public void setMaxIconSize(int pixel) {
maxIconSize = Math.min(64, Math.max(16, pixel));
}
public int getMaxIconSize() {
return maxIconSize;
}
}