001: /*
002: * @(#)Images.java 2.0 2006-12-24
003: *
004: * Copyright (c) 2005 Werner Randelshofer
005: * Staldenmattweg 2, Immensee, CH-6405, Switzerland.
006: * All rights reserved.
007: *
008: * This software is the confidential and proprietary information of
009: * Werner Randelshofer. ("Confidential Information"). You shall not
010: * disclose such Confidential Information and shall use it only in
011: * accordance with the terms of the license agreement you entered into
012: * with Werner Randelshofer.
013: */
014:
015: package contrib.ch.randelshofer.quaqua.util;
016:
017: import java.awt.*;
018: import java.awt.image.*;
019: import java.io.*;
020: import java.net.*;
021: import java.util.*;
022:
023: import javax.swing.*;
024:
025: import contrib.ch.randelshofer.quaqua.*;
026:
027: /**
028: * Image processing methods.
029: *
030: * @author Werner Randelshofer, Karl von Randow
031: * @version 2.0 2006-12-24 by Karl von Randow: On the fly conversion from Aqua
032: * Blue to Aqua Graphite appearance added.
033: * <br>1.0.2 2005-09-12 Brought my work-around for Java 1.4.1 back to
034: * live.
035: * <br>1.0.1 2005-05-21 Accidentaly used bitmask transparency
036: * instead of translucent transparency.
037: * <br>1.0 13 March 2005 Created.
038: */
039: public class Images {
040:
041: /** Prevent instance creation. */
042: private Images() {
043: }
044:
045: private static GraphiteFilter graphiteFilter = new GraphiteFilter();
046:
047: public static Image createImage(URL resource) {
048: Image image = Toolkit.getDefaultToolkit().createImage(resource);
049: // if (Preferences.getString("AppleAquaColorVariant").equals("6")) {
050: // if (canGraphite(resource)) {
051: // image = toGraphite(image);
052: // }
053: // }
054: return image;
055: }
056:
057: private static Properties canGraphite;
058:
059: private static boolean canGraphite(URL resource) {
060: if (canGraphite == null) {
061: synchronized (Images.class) {
062: if (canGraphite == null) {
063: Properties p = new Properties();
064: try {
065: p
066: .load(Images.class
067: .getResourceAsStream("graphiteable.properties"));
068: } catch (IOException e) {
069: System.err
070: .println("Failed to load graphiteable.properties: "
071: + e);
072: }
073: canGraphite = p;
074: }
075: }
076: }
077: String file = resource.getFile();
078: int i = file.lastIndexOf(File.separatorChar);
079: if (i != -1) {
080: file = file.substring(i + 1);
081: }
082: return canGraphite.containsKey(file);
083: }
084:
085: /**
086: * This method returns a buffered image with the contents of an image.
087: *
088: * Code derived from the Java Developers Almanac 1.4
089: * http://javaalmanac.com/egs/java.awt.image/Image2Buf.html?l=rel
090: */
091: private static Image toGraphite(Image image) {
092: return Toolkit.getDefaultToolkit().createImage(
093: new FilteredImageSource(image.getSource(),
094: graphiteFilter));
095: }
096:
097: /**
098: * Based on a code example from:
099: * http://tams-www.informatik.uni-hamburg.de/applets/hades/webdemos/00-intro/02-imageprocessing/saturation.html
100: * @author karlvr
101: *
102: */
103: public static class GraphiteFilter extends RGBImageFilter {
104: private final static float saturationAdjust = 0.179f;
105: private static float hueAdjust = 0.0052f;
106: private static float brightnessAdjust = 0.09f;
107:
108: private float[] hsb = new float[3];
109:
110: public int filterRGB(int x, int y, int rgb) {
111: int alpha = rgb & 0xff000000;
112: int red = (rgb >> 16) & 0xff;
113: int green = (rgb >> 8) & 0xff;
114: int blue = rgb & 0xff;
115: /*
116: float RW = (1f - saturationAdjust) * 0.3086f; // or 0.299 for YIV values
117: float RG = (1f - saturationAdjust) * 0.6084f; // or 0.587 for YIV values
118: float RB = (1f - saturationAdjust) * 0.0820f; // or 0.114 for YIV values
119: */
120: float RW = (1f - saturationAdjust) * 0.333f; // or 0.299 for YIV values
121: float RG = (1f - saturationAdjust) * 0.333f; // or 0.587 for YIV values
122: float RB = (1f - saturationAdjust) * 0.333f; // or 0.114 for YIV values
123:
124: float a = RW + saturationAdjust;
125: float b = RW;
126: float c = RW;
127: float d = RG;
128: float e = RG + saturationAdjust;
129: float f = RG;
130: float g = RB;
131: float h = RB;
132: float i = RB + saturationAdjust;
133:
134: int outputRed = (int) (a * red + d * green + g * blue);
135: int outputGreen = (int) (b * red + e * green + h * blue);
136: int outputBlue = (int) (c * red + f * green + i * blue);
137: return alpha | (outputRed << 16) | (outputGreen << 8)
138: | (outputBlue);
139: }
140: }
141:
142: public static BufferedImage toBufferedImage(Image image) {
143: if (image instanceof BufferedImage) {
144: return (BufferedImage) image;
145: }
146:
147: // This code ensures that all the pixels in the image are loaded
148: image = new ImageIcon(image).getImage();
149:
150: // Create a buffered image with a format that's compatible with the screen
151: BufferedImage bimage = null;
152:
153: if (System.getProperty("java.version").startsWith("1.4.1_")) {
154: // Workaround for Java 1.4.1 on Mac OS X.
155: // For this JVM, we always create an ARGB image to prevent a class
156: // cast exception in
157: // sun.awt.image.BufImgSurfaceData.createData(BufImgSurfaceData.java:434)
158: // when we attempt to draw the buffered image.
159: bimage = new BufferedImage(image.getWidth(null), image
160: .getHeight(null), BufferedImage.TYPE_INT_ARGB);
161: } else {
162: // Determine if the image has transparent pixels; for this method's
163: // implementation, see e661 Determining If an Image Has Transparent Pixels
164: boolean hasAlpha;
165: try {
166: hasAlpha = hasAlpha(image);
167: } catch (IllegalAccessError e) {
168: // If we can't determine this, we assume that we have an alpha,
169: // in order not to loose data.
170: hasAlpha = true;
171: }
172:
173: GraphicsEnvironment ge = GraphicsEnvironment
174: .getLocalGraphicsEnvironment();
175: try {
176: // Determine the type of transparency of the new buffered image
177: int transparency = Transparency.OPAQUE;
178: if (hasAlpha) {
179: transparency = Transparency.TRANSLUCENT;
180: }
181:
182: // Create the buffered image
183: GraphicsDevice gs = ge.getDefaultScreenDevice();
184: GraphicsConfiguration gc = gs.getDefaultConfiguration();
185: bimage = gc.createCompatibleImage(image.getWidth(null),
186: image.getHeight(null), transparency);
187: } catch (Exception e) {
188: //} catch (HeadlessException e) {
189: // The system does not have a screen
190: }
191:
192: if (bimage == null) {
193: // Create a buffered image using the default color model
194: int type = BufferedImage.TYPE_INT_RGB;
195: if (hasAlpha) {
196: type = BufferedImage.TYPE_INT_ARGB;
197: }
198: bimage = new BufferedImage(image.getWidth(null), image
199: .getHeight(null), type);
200: }
201: }
202:
203: // Copy image to buffered image
204: Graphics g = bimage.createGraphics();
205:
206: // Paint the image onto the buffered image
207: g.drawImage(image, 0, 0, null);
208: g.dispose();
209:
210: return bimage;
211:
212: // My own implementation:
213: /*
214: if (image instanceof BufferedImage) {
215: return (BufferedImage) image;
216: } else {
217: BufferedImage bufImg;
218: Frame f = new Frame();
219: f.pack();
220: MediaTracker t = new MediaTracker(f);
221: t.addImage(image, 0);
222: try { t.waitForAll(); } catch (InterruptedException e) {}
223:
224: // Workaround for Java 1.4.1 on Mac OS X.
225: if (System.getProperty("java.version").startsWith("1.4.1_")) {
226: bufImg = new BufferedImage(image.getWidth(f), image.getHeight(f), BufferedImage.TYPE_INT_ARGB);
227: } else {
228: bufImg = GraphicsEnvironment
229: .getLocalGraphicsEnvironment()
230: .getDefaultScreenDevice()
231: .getDefaultConfiguration()
232: .createCompatibleImage(image.getWidth(null), image.getHeight(null), Transparency.TRANSLUCENT);
233: }
234: Graphics2D imgGraphics = bufImg.createGraphics();
235: imgGraphics.drawImage(image, 0, 0, f);
236: imgGraphics.dispose();
237: f.dispose();
238: return bufImg;
239: }*/
240: }
241:
242: /**
243: * This method returns true if the specified image has transparent pixels
244: *
245: * Code taken from the Java Developers Almanac 1.4
246: * http://javaalmanac.com/egs/java.awt.image/HasAlpha.html
247: */
248: public static boolean hasAlpha(Image image) {
249: // If buffered image, the color model is readily available
250: if (image instanceof BufferedImage) {
251: BufferedImage bimage = (BufferedImage) image;
252: return bimage.getColorModel().hasAlpha();
253: }
254:
255: // Use a pixel grabber to retrieve the image's color model;
256: // grabbing a single pixel is usually sufficient
257: PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
258: try {
259: pg.grabPixels();
260: } catch (InterruptedException e) {
261: }
262:
263: // Get the image's color model
264: ColorModel cm = pg.getColorModel();
265: return cm.hasAlpha();
266: }
267:
268: /**
269: * Splits an image into count subimages.
270: */
271: public static BufferedImage[] split(Image image, int count,
272: boolean isHorizontal) {
273: BufferedImage src = Images.toBufferedImage(image);
274: if (count == 1) {
275: return new BufferedImage[] { src };
276: }
277:
278: BufferedImage[] parts = new BufferedImage[count];
279: for (int i = 0; i < count; i++) {
280: if (isHorizontal) {
281: parts[i] = src.getSubimage(src.getWidth() / count * i,
282: 0, src.getWidth() / count, src.getHeight());
283: } else {
284: parts[i] = src.getSubimage(0, src.getHeight() / count
285: * i, src.getWidth(), src.getHeight() / count);
286: }
287: }
288: return parts;
289: }
290: }
|