/* (c) 2014-2015 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.map;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.io.IOException;
import java.io.OutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.geoserver.config.JAIInfo;
import org.geoserver.platform.Operation;
import org.geoserver.platform.ServiceException;
import org.geoserver.wms.GetMapRequest;
import org.geoserver.wms.MapProducerCapabilities;
import org.geoserver.wms.RasterCleaner;
import org.geoserver.wms.WMS;
import org.geoserver.wms.WMSMapContent;
import org.geoserver.wms.map.png.PNGJWriter;
import org.geotools.image.ImageWorker;
import org.geotools.util.logging.Logging;
/**
* Handles a GetMap request that spects a map in GIF format.
*
* @author Simone Giannecchini
* @author Didier Richard
* @version $Id
*/
public class PNGMapResponse extends RenderedImageMapResponse {
/** Logger */
private static final Logger LOGGER = Logging.getLogger(PNGMapResponse.class);
private static final String MIME_TYPE = "image/png";
private static final String MIME_TYPE_8BIT = "image/png; mode=8bit";
private static final String[] OUTPUT_FORMATS = { MIME_TYPE, MIME_TYPE_8BIT, "image/png8" };
/**
* The two quantizers available for PNG images
*/
public enum QuantizeMethod {
Octree, MedianCut
};
/**
* Default capabilities for PNG format.
*
* <p>
* <ol>
* <li>tiled = supported</li>
* <li>multipleValues = unsupported</li>
* <li>paletteSupported = supported</li>
* <li>transparency = supported</li>
* </ol>
*/
private static MapProducerCapabilities CAPABILITIES = new MapProducerCapabilities(true, false,
true, true, null);
/**
* @param format the format name as to be reported in the capabilities document
* @param wms
*/
public PNGMapResponse(WMS wms) {
super(OUTPUT_FORMATS, wms);
}
@Override
public String getMimeType(Object value, Operation operation) throws ServiceException {
GetMapRequest request = (GetMapRequest) operation.getParameters()[0];
if (request.getFormat().contains("8")) {
return MIME_TYPE_8BIT;
} else {
return MIME_TYPE;
}
}
/**
* Transforms the rendered image into the appropriate format, streaming to the output stream.
*
* @see RasterMapOutputFormat#formatImageOutputStream(RenderedImage, OutputStream)
*/
public void formatImageOutputStream(RenderedImage image, OutputStream outStream,
WMSMapContent mapContent) throws ServiceException, IOException {
// /////////////////////////////////////////////////////////////////
//
// Reformatting this image for png
//
// /////////////////////////////////////////////////////////////////
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("Writing png image ...");
}
// check to see if we have to see a translucent or bitmask quantizer
image = applyPalette(image, mapContent, "image/png8", true);
float quality = (100 - wms.getPngCompression()) / 100.0f;
JAIInfo.PngEncoderType encoder = wms.getPNGEncoderType();
if(encoder == JAIInfo.PngEncoderType.PNGJ) {
image = new PNGJWriter().writePNG(image, outStream, quality, mapContent);
RasterCleaner.addImage(image);
} else {
Boolean PNGNativeAcc = (encoder == JAIInfo.PngEncoderType.NATIVE);
SampleModel sm = image.getSampleModel();
int numBits = sm.getSampleSize(0);
// png acceleration only works on 2 bit and 8 bit images, crashes on 4 bits
boolean nativeAcceleration = PNGNativeAcc.booleanValue() && !(numBits > 1 && numBits < 8);
ImageWorker iw = new ImageWorker(image);
iw.writePNG(outStream, "FILTERED", quality, nativeAcceleration, false);
RasterCleaner.addImage(iw.getRenderedImage());
}
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("Writing png image ... done!");
}
}
@Override
public MapProducerCapabilities getCapabilities(String outputFormat) {
return CAPABILITIES;
}
}