/* (c) 2014 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.wms.legendgraphic; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import javax.imageio.IIOImage; import javax.imageio.ImageIO; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; import javax.imageio.metadata.IIOMetadata; import javax.imageio.stream.ImageOutputStream; import org.geotools.image.io.ImageIOExt; /** * Helper class to deal with JAI availability and image encoding */ public final class JAISupport { /** shared package's logger */ private static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger(JAISupport.class.getPackage().getName()); /** * Array of mime types that have been tested to work. * Many of the mime types that JAI says it supports does not actually work. * These are mostly because of colour problems (ie. only supports grey scale, and we're giving it a ARGB). * Update this list as the supported formats are handled better! * If you dont do this, clients might request an non-functional format (cite does this). * * The getSupportedFormats() will return a sub-set of these formats. */ static ArrayList testedFormats = new ArrayList(); static { testedFormats.add("image/jpeg"); //testedFormats.add("image/png"); } ; /** * Set<String> of the MIME types the available JAI library supports, * or the empty set if it is not available. */ private static Set supportedFormats; /** * Returns the set of supported formats by the available JAI library, or * the empty set if not available. * * @return Set<String> of the MIME types the available JAI library * supports, or the empty set if it is not available. */ public static Set getSupportedFormats() { if (supportedFormats == null) { String[] mimeTypes = null; try { mimeTypes = ImageIO.getWriterMIMETypes(); } catch (NoClassDefFoundError ncdfe) { supportedFormats = Collections.EMPTY_SET; LOGGER.warning("could not find jai: " + ncdfe); //this will occur if JAI is not present, so please do not //delete, or we get really nasty messages on getCaps for wms. } if (mimeTypes == null) { LOGGER.info("Jai not found? Should be always there"); supportedFormats = Collections.EMPTY_SET; } else { supportedFormats = new HashSet(); List formatsList = Arrays.asList(mimeTypes); for (Iterator it = formatsList.iterator(); it.hasNext();) { String curFormat = it.next().toString(); if (!curFormat.equals("")) { //DJB: check to see if the JAI format has been tested to work! if (testedFormats.contains(curFormat)) { supportedFormats.add(curFormat); } } } if (LOGGER.isLoggable(Level.CONFIG)) { StringBuffer sb = new StringBuffer("Supported JAIMapResponse's MIME Types: ["); for (Iterator it = supportedFormats.iterator(); it.hasNext();) { sb.append(it.next()); if (it.hasNext()) { sb.append(", "); } } sb.append("]"); LOGGER.config(sb.toString()); } } } return supportedFormats; } /** * Returns wether the JAI library is available by checking the available * formats. * * @return <code>true</code> if JAI is available * * @see #getSupportedFormats() */ public static boolean isJaiAvailable() { return getSupportedFormats().size() > 0; } /** * Encodes a BufferedImage using JAI in <code>format</code> format and * sends it to <code>outStream</code>. * * @param format the MIME type of the output image in which to encode * <code>image</code> through JAI * @param image the actual image to be encoded in <code>format</code> * format. * @param outStream the encoded image destination. * * @throws IOException if the image writing to <code>outStream</code> * fails. * @throws IllegalArgumentException if <code>format</code> is not a * supported output format for the installed JAI library. */ public static void encode(String format, BufferedImage image, OutputStream outStream) throws IOException { if (format.equalsIgnoreCase("jpeg")) { format = "image/jpeg"; } Iterator it = ImageIO.getImageWritersByMIMEType(format); if (!it.hasNext()) { throw new IllegalArgumentException("Format not supported: " + format); } ImageWriter writer = (ImageWriter) it.next(); ImageOutputStream ioutstream = null; IIOMetadata meta = writer.getDefaultStreamMetadata(writer.getDefaultWriteParam()); ImageWriteParam param = writer.getDefaultWriteParam(); // DJB: jpeg does not support ARGB (alpha) colour // this converts the image from ARGB to RGB // TODO: make this more abstract - it should be smarter for more image // writer types (Ie. ask the writer what it supports) // Alternately, make a jpeg writer and png writer, as these are // mostly what we get from jai! if (format.equalsIgnoreCase("image/jpeg")) { param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); param.setCompressionQuality(0.9f); // DJB: only do this for jpegs - png freaks when you do this! meta = writer.getDefaultStreamMetadata(param); // WritableRaster raster = image.getRaster(); // WritableRaster newRaster = raster.createWritableChild(0, 0, image.getWidth(), image.getHeight(), 0, 0, new int[] {0, 1, 2}); // create a ColorModel that represents the one of the ARGB except the alpha channel: // DirectColorModel cm = (DirectColorModel)image.getColorModel(); // DirectColorModel newCM = new DirectColorModel(cm.getPixelSize(), cm.getRedMask(), cm.getGreenMask(), cm.getBlueMask()); // now create the new buffer that is used ot write the image: // BufferedImage rgbBuffer = new BufferedImage(newCM, newRaster, false, null); BufferedImage curImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_3BYTE_BGR); Graphics2D g = (Graphics2D) curImage.createGraphics(); g.drawImage(image, 0, 0, null); image = curImage; ioutstream = ImageIOExt.createImageOutputStream(image, outStream); writer.setOutput(ioutstream); writer.write(image); ioutstream.close(); writer.dispose(); return; } ioutstream = ImageIOExt.createImageOutputStream(image, outStream); writer.setOutput(ioutstream); writer.write(meta, new IIOImage(image, null, meta), param); ioutstream.close(); writer.dispose(); } }