001: /* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
002: * This code is licensed under the GPL 2.0 license, availible at the root
003: * application directory.
004: */
005: package org.vfny.geoserver.wms.responses.helpers;
006:
007: import org.geotools.renderer.lite.StreamingRenderer;
008: import java.awt.Graphics2D;
009: import java.awt.image.BufferedImage;
010: import java.io.IOException;
011: import java.io.OutputStream;
012: import java.util.ArrayList;
013: import java.util.Arrays;
014: import java.util.Collections;
015: import java.util.HashSet;
016: import java.util.Iterator;
017: import java.util.List;
018: import java.util.Set;
019: import java.util.logging.Level;
020: import java.util.logging.Logger;
021: import javax.imageio.IIOImage;
022: import javax.imageio.ImageIO;
023: import javax.imageio.ImageWriteParam;
024: import javax.imageio.ImageWriter;
025: import javax.imageio.metadata.IIOMetadata;
026: import javax.imageio.stream.ImageOutputStream;
027:
028: /**
029: * Helper class to deal with JAI availability and image encoding
030: */
031: public final class JAISupport {
032: /** shared package's logger */
033: private static final Logger LOGGER = org.geotools.util.logging.Logging
034: .getLogger(JAISupport.class.getPackage().getName());
035:
036: /**
037: * Array of mime types that have been tested to work.
038: * Many of the mime types that JAI says it supports does not actually work.
039: * These are mostly because of colour problems (ie. only supports grey scale, and we're giving it a ARGB).
040: * Update this list as the supported formats are handled better!
041: * If you dont do this, clients might request an non-functional format (cite does this).
042: *
043: * The getSupportedFormats() will return a sub-set of these formats.
044: */
045: static ArrayList testedFormats = new ArrayList();
046:
047: static {
048: testedFormats.add("image/jpeg");
049:
050: //testedFormats.add("image/png");
051: };
052:
053: /**
054: * Set<String> of the MIME types the available JAI library supports,
055: * or the empty set if it is not available.
056: */
057: private static Set supportedFormats;
058:
059: /**
060: * Returns the set of supported formats by the available JAI library, or
061: * the empty set if not available.
062: *
063: * @return Set<String> of the MIME types the available JAI library
064: * supports, or the empty set if it is not available.
065: */
066: public static Set getSupportedFormats() {
067: if (supportedFormats == null) {
068: String[] mimeTypes = null;
069:
070: try {
071: mimeTypes = ImageIO.getWriterMIMETypes();
072: } catch (NoClassDefFoundError ncdfe) {
073: supportedFormats = Collections.EMPTY_SET;
074: LOGGER.warning("could not find jai: " + ncdfe);
075:
076: //this will occur if JAI is not present, so please do not
077: //delete, or we get really nasty messages on getCaps for wms.
078: }
079:
080: if (mimeTypes == null) {
081: LOGGER.info("Jai not found? Should be always there");
082: supportedFormats = Collections.EMPTY_SET;
083: } else {
084: supportedFormats = new HashSet();
085:
086: List formatsList = Arrays.asList(mimeTypes);
087:
088: for (Iterator it = formatsList.iterator(); it.hasNext();) {
089: String curFormat = it.next().toString();
090:
091: if (!curFormat.equals("")) {
092: //DJB: check to see if the JAI format has been tested to work!
093: if (testedFormats.contains(curFormat)) {
094: supportedFormats.add(curFormat);
095: }
096: }
097: }
098:
099: if (LOGGER.isLoggable(Level.CONFIG)) {
100: StringBuffer sb = new StringBuffer(
101: "Supported JAIMapResponse's MIME Types: [");
102:
103: for (Iterator it = supportedFormats.iterator(); it
104: .hasNext();) {
105: sb.append(it.next());
106:
107: if (it.hasNext()) {
108: sb.append(", ");
109: }
110: }
111:
112: sb.append("]");
113: LOGGER.config(sb.toString());
114: }
115: }
116: }
117:
118: return supportedFormats;
119: }
120:
121: /**
122: * Returns wether the JAI library is available by checking the available
123: * formats.
124: *
125: * @return <code>true</code> if JAI is available
126: *
127: * @see #getSupportedFormats()
128: */
129: public static boolean isJaiAvailable() {
130: return getSupportedFormats().size() > 0;
131: }
132:
133: /**
134: * Encodes a BufferedImage using JAI in <code>format</code> format and
135: * sends it to <code>outStream</code>.
136: *
137: * @param format the MIME type of the output image in which to encode
138: * <code>image</code> through JAI
139: * @param image the actual image to be encoded in <code>format</code>
140: * format.
141: * @param outStream the encoded image destination.
142: *
143: * @throws IOException if the image writing to <code>outStream</code>
144: * fails.
145: * @throws IllegalArgumentException if <code>format</code> is not a
146: * supported output format for the installed JAI library.
147: */
148: public static void encode(String format, BufferedImage image,
149: OutputStream outStream) throws IOException {
150: if (format.equalsIgnoreCase("jpeg")) {
151: format = "image/jpeg";
152: }
153:
154: Iterator it = ImageIO.getImageWritersByMIMEType(format);
155:
156: if (!it.hasNext()) {
157: throw new IllegalArgumentException("Format not supported: "
158: + format);
159: }
160:
161: ImageWriter writer = (ImageWriter) it.next();
162: ImageOutputStream ioutstream = null;
163:
164: IIOMetadata meta = writer.getDefaultStreamMetadata(writer
165: .getDefaultWriteParam());
166: ImageWriteParam param = writer.getDefaultWriteParam();
167:
168: // DJB: jpeg does not support ARGB (alpha) colour
169: // this converts the image from ARGB to RGB
170: // TODO: make this more abstract - it should be smarter for more image
171: // writer types (Ie. ask the writer what it supports)
172: // Alternately, make a jpeg writer and png writer, as these are
173: // mostly what we get from jai!
174: if (format.equalsIgnoreCase("image/jpeg")) {
175: param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
176: param.setCompressionQuality(0.9f); // DJB: only do this for jpegs - png freaks when you do this!
177:
178: meta = writer.getDefaultStreamMetadata(param);
179:
180: // WritableRaster raster = image.getRaster();
181: // WritableRaster newRaster = raster.createWritableChild(0, 0, image.getWidth(), image.getHeight(), 0, 0, new int[] {0, 1, 2});
182: // create a ColorModel that represents the one of the ARGB except the alpha channel:
183: // DirectColorModel cm = (DirectColorModel)image.getColorModel();
184: // DirectColorModel newCM = new DirectColorModel(cm.getPixelSize(), cm.getRedMask(), cm.getGreenMask(), cm.getBlueMask());
185: // now create the new buffer that is used ot write the image:
186: // BufferedImage rgbBuffer = new BufferedImage(newCM, newRaster, false, null);
187: BufferedImage curImage = new BufferedImage(
188: image.getWidth(), image.getHeight(),
189: BufferedImage.TYPE_3BYTE_BGR);
190: Graphics2D g = (Graphics2D) curImage.createGraphics();
191: g.drawImage(image, 0, 0, null);
192:
193: image = curImage;
194:
195: ioutstream = ImageIO.createImageOutputStream(outStream);
196: writer.setOutput(ioutstream);
197: writer.write(image);
198: ioutstream.close();
199: writer.dispose();
200:
201: return;
202: }
203:
204: ioutstream = ImageIO.createImageOutputStream(outStream);
205: writer.setOutput(ioutstream);
206: writer.write(meta, new IIOImage(image, null, meta), param);
207: ioutstream.close();
208: writer.dispose();
209: }
210: }
|