Package org.geoserver.wms.map

Source Code of org.geoserver.wms.map.RenderedImageMapResponse

/* (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.map;

import java.awt.Transparency;
import java.awt.image.IndexColorModel;
import java.awt.image.RenderedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;

import org.geoserver.platform.Operation;
import org.geoserver.platform.ServiceException;
import org.geoserver.wms.GetMapOutputFormat;
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.kvp.PaletteManager;
import org.geoserver.wms.map.PNGMapResponse.QuantizeMethod;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.image.ImageWorker;
import org.geotools.image.palette.CachingColorIndexer;
import org.geotools.image.palette.ColorIndexer;
import org.geotools.image.palette.ColorIndexerDescriptor;
import org.geotools.image.palette.InverseColorMapOp;
import org.geotools.image.palette.LRUColorIndexer;
import org.geotools.image.palette.Quantizer;
import org.springframework.util.Assert;

/**
* Abstract base class for GetMapProducers that relies in LiteRenderer for creating the raster map
* and then outputs it in the format they specializes in.
*
* <p>
* This class does the job of producing a BufferedImage using geotools LiteRenderer, so it should be
* enough for a subclass to implement {@linkplain #formatImageOutputStream}
* </p>
*
* <p>
* Generates a map using the geotools jai rendering classes. Uses the Lite renderer, loading the
* data on the fly, which is quite nice. Thanks Andrea and Gabriel. The word is that we should
* eventually switch over to StyledMapRenderer and do some fancy stuff with caching layers, but I
* think we are a ways off with its maturity to try that yet. So Lite treats us quite well, as it is
* stateless and therefore loads up nice and fast.
* </p>
*
* <p>
* </p>
*
* @author Chris Holmes, TOPP
* @author Simone Giannecchini, GeoSolutions
* @version $Id$
*/
public abstract class RenderedImageMapResponse extends AbstractMapResponse {

    /** Which format to encode the image in if one is not supplied */
    private static final String DEFAULT_MAP_FORMAT = "image/png";

    /** WMS Service configuration * */
    protected final WMS wms;

    /**
     *
     */
    public RenderedImageMapResponse(WMS wms) {
        this(DEFAULT_MAP_FORMAT, wms);
    }

    /**
     * @param the
     *            mime type to be written down as an HTTP header when a map of this format is
     *            generated
     */
    public RenderedImageMapResponse(String mime, WMS wms) {
        super(RenderedImageMap.class, mime);
        this.wms = wms;
    }

    public RenderedImageMapResponse(String[] outputFormats, WMS wms) {
        super(RenderedImageMap.class, outputFormats);
        this.wms = wms;
    }

    /**
     * Transforms a rendered image into the appropriate format, streaming to the output stream.
     *
     * @param image
     *            The image to be formatted.
     * @param outStream
     *            The stream to write to.
     *
     * @throws ServiceException
     * @throws IOException
     */
    public abstract void formatImageOutputStream(RenderedImage image, OutputStream outStream,
            WMSMapContent mapContent) throws ServiceException, IOException;

    /**
     * Writes the image to the given destination.
     *
     * @param value
     *            must be a {@link RenderedImageMap}
     * @see GetMapOutputFormat#write(org.geoserver.wms.WebMap, OutputStream)
     * @see #formatImageOutputStream(RenderedImage, OutputStream, WMSMapContent)
     */
    @Override
    public final void write(final Object value, final OutputStream output, final Operation operation)
            throws IOException, ServiceException {

        Assert.isInstanceOf(RenderedImageMap.class, value);

        final RenderedImageMap imageMap = (RenderedImageMap) value;
        try {
            final RenderedImage image = imageMap.getImage();
            final List<GridCoverage2D> renderedCoverages = imageMap.getRenderedCoverages();
            final WMSMapContent mapContent = imageMap.getMapContext();
            try {
                formatImageOutputStream(image, output, mapContent);
                output.flush();
            } finally {
                // let go of the coverages created for rendering
                for (GridCoverage2D coverage : renderedCoverages) {
                    RasterCleaner.addCoverage(coverage);
                }
                RasterCleaner.addImage(image);
            }
        } finally {
            imageMap.dispose();
        }
    }
   
    /**
     * Applies a transformation to 8 bits + palette in case the user requested a specific palette or
     * the palette format has been requested, applying a bitmask or translucent palette inverter
     * according to the user request and the image structure

     * @param image
     * @param mapContent
     * @param palettedFormatName
     * @param supportsTranslucency If false the code will always apply the bitmask transformer
     * @return
     */
    protected RenderedImage applyPalette(RenderedImage image, WMSMapContent mapContent,
            String palettedFormatName, boolean supportsTranslucency) {
        // check to see if we have to see a translucent or bitmask quantizer
        GetMapRequest request = mapContent.getRequest();
        QuantizeMethod method = (QuantizeMethod) request.getFormatOptions().get(
                PaletteManager.QUANTIZER);
        boolean useBitmaskQuantizer = method == QuantizeMethod.Octree
                || !supportsTranslucency
                || (method == null && image.getColorModel().getTransparency() != Transparency.TRANSLUCENT);


        // format: split on ';' to handle subtypes like 'image/gif;subtype=animated'
        final String format = request.getFormat().split(";")[0];
        // do we have to use the bitmask quantizer?
        IndexColorModel icm = mapContent.getPalette();
        if (useBitmaskQuantizer) {
            // user provided palette?
            if (icm != null) {
                image = forceIndexed8Bitmask(image, PaletteManager.getInverseColorMapOp(icm));
            } else if (palettedFormatName.equalsIgnoreCase(format)) {
                // or format that needs palette to be applied?
                image = forceIndexed8Bitmask(image, null);
            }
        } else {
            if (!(image.getColorModel() instanceof IndexColorModel)) {
                // try to force a RGBA setup
                image = new ImageWorker(image).rescaleToBytes().forceComponentColorModel()
                        .getRenderedImage();
                ColorIndexer indexer = null;
               
                // user provided palette?
                if (mapContent.getPalette() != null) {
                    indexer = new CachingColorIndexer(new LRUColorIndexer(icm, 1024));
                } else if (palettedFormatName.equalsIgnoreCase(format)) {
                    // build the palette and grab the optimized color indexer
                    indexer = new Quantizer(256).subsample().buildColorIndexer(image);
                }

                // if we have an indexer transform the image
                if (indexer != null) {
                    image = ColorIndexerDescriptor.create(image, indexer, null);
                }
            }
        }

        return image;
    }
   
    /**
     * @param originalImage
     * @return
     */
    protected RenderedImage forceIndexed8Bitmask(RenderedImage originalImage,
            InverseColorMapOp paletteInverter) {
        return ImageUtils.forceIndexed8Bitmask(originalImage, paletteInverter);
    }

    /**
     * Returns the capabilities for this output format
     * @param outputFormat
     * @return
     */
    public abstract MapProducerCapabilities getCapabilities(String outputFormat);
}
TOP

Related Classes of org.geoserver.wms.map.RenderedImageMapResponse

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.