Package org.geoserver.wms.svg

Source Code of org.geoserver.wms.svg.SVGBatikMapOutputFormat

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

import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.batik.svggen.SVGGeneratorContext;
import org.apache.batik.svggen.SVGGraphics2D;
import org.geoserver.platform.ServiceException;
import org.geoserver.wms.DefaultWebMapService;
import org.geoserver.wms.GetMapOutputFormat;
import org.geoserver.wms.MapProducerCapabilities;
import org.geoserver.wms.WMS;
import org.geoserver.wms.WMSMapContent;
import org.geoserver.wms.map.MaxErrorEnforcer;
import org.geoserver.wms.map.RenderExceptionStrategy;
import org.geotools.map.MapContent;
import org.geotools.renderer.lite.StreamingRenderer;
import org.w3c.dom.Document;

/**
* Renders svg using the Batik SVG Toolkit. An SVG context is created for a map and then passed of
* to {@link org.geotools.renderer.lite.StreamingRenderer}.
*
* @author Justin Deoliveira, The Open Planning Project
*
*/
public final class SVGBatikMapOutputFormat implements GetMapOutputFormat {
   
    /**
     * Default capabilities for SVG format.
     *
     * <p>
     * <ol>
     *         <li>tiled = unsupported</li>
     *         <li>multipleValues = unsupported</li>
     *         <li>paletteSupported = unsupported</li>
     *         <li>transparency = supported</li>
     * </ol>
     */
    private static MapProducerCapabilities CAPABILITIES= new MapProducerCapabilities(false, false, false, true, null);

    private final WMS wms;

    public SVGBatikMapOutputFormat(WMS wms) {
        this.wms = wms;
    }

    /**
     * @return {@code ["image/svg+xml", "image/svg xml", "image/svg"]}
     * @see org.geoserver.wms.GetMapOutputFormat#getOutputFormatNames()
     */
    public Set<String> getOutputFormatNames() {
        return SVG.OUTPUT_FORMATS;
    }

    /**
     * @return {@code "image/svg+xml"}
     * @see org.geoserver.wms.GetMapOutputFormat#getMimeType()
     */
    public String getMimeType() {
        return SVG.MIME_TYPE;
    }

    /**
     *
     * @see org.geoserver.wms.GetMapOutputFormat#produceMap(org.geoserver.wms.WMSMapContent)
     */
    public BatikSVGMap produceMap(WMSMapContent mapContent) throws ServiceException, IOException {

        StreamingRenderer renderer = setUpRenderer(mapContent);
        SVGGraphics2D g = createSVGMap(renderer, mapContent);
        renderer = null;

        // This method of output does not output the DOCTYPE definiition
        // TODO: make a config option that toggles wether doctype is
        // written out.
        // OutputFormat format = new OutputFormat();
        // XMLSerializer serializer = new XMLSerializer(new OutputStreamWriter(out, "UTF-8"),
        // format);

        return new BatikSVGMap(mapContent, g);
    }

    private StreamingRenderer setUpRenderer(WMSMapContent mapContent) {
        StreamingRenderer renderer;
        renderer = new StreamingRenderer();

        // optimized data loading was not here, but yet it seems sensible to
        // have it...
        Map<String, Object> rendererParams = new HashMap<String, Object>();
        rendererParams.put("optimizedDataLoadingEnabled", Boolean.TRUE);
        // we need the renderer to draw everything on the batik provided graphics object
        rendererParams.put(StreamingRenderer.OPTIMIZE_FTS_RENDERING_KEY, Boolean.FALSE);
        // render everything in vector form if possible
        rendererParams.put(StreamingRenderer.VECTOR_RENDERING_KEY, Boolean.TRUE);
        rendererParams.put("renderingBuffer", new Integer(mapContent.getBuffer()));
        if (DefaultWebMapService.isLineWidthOptimizationEnabled()) {
            rendererParams.put(StreamingRenderer.LINE_WIDTH_OPTIMIZATION_KEY, true);
        }
        rendererParams.put(StreamingRenderer.SCALE_COMPUTATION_METHOD_KEY,
                mapContent.getRendererScaleMethod());
        renderer.setRendererHints(rendererParams);
        renderer.setMapContent(mapContent);
        return renderer;
    }

    public SVGGraphics2D createSVGMap(final StreamingRenderer renderer,
            final WMSMapContent mapContent) throws ServiceException, IOException {
        try {
            MapContent map = renderer.getMapContent();
            double width = -1;
            double height = -1;

            if (map instanceof WMSMapContent) {
                WMSMapContent wmsMap = (WMSMapContent) map;
                width = wmsMap.getMapWidth();
                height = wmsMap.getMapHeight();
            } else {
                // get fromt he map content
                Rectangle screenArea = map.getViewport().getScreenArea();
                width = screenArea.getWidth();
                height = screenArea.getHeight();
            }

            if ((height == -1) || (width == -1)) {
                throw new IOException("Could not determine map dimensions");
            }

            SVGGeneratorContext context = setupContext();
            SVGGraphics2D g = new SVGGraphics2D(context, true);

            g.setSVGCanvasSize(new Dimension((int) width, (int) height));

            // turn off/on anti aliasing
            if (wms.isSvgAntiAlias()) {
                g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                        RenderingHints.VALUE_ANTIALIAS_ON);
            } else {
                g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                        RenderingHints.VALUE_ANTIALIAS_OFF);
            }

            // enforce no more than x rendering errors
            int maxErrors = wms.getMaxRenderingErrors();
            MaxErrorEnforcer errorChecker = new MaxErrorEnforcer(renderer, maxErrors);

            // Add a render listener that ignores well known rendering exceptions and reports back
            // non
            // ignorable ones
            final RenderExceptionStrategy nonIgnorableExceptionListener;
            nonIgnorableExceptionListener = new RenderExceptionStrategy(renderer);
            renderer.addRenderListener(nonIgnorableExceptionListener);

            renderer.paint(g, new Rectangle(g.getSVGCanvasSize()), mapContent.getRenderingArea(),
                    mapContent.getRenderingTransform());

            // check if too many errors occurred
            if (errorChecker.exceedsMaxErrors()) {
                throw new ServiceException("More than " + maxErrors
                        + " rendering errors occurred, bailing out.",
                        errorChecker.getLastException(), "internalError");
            }

            // check if a non ignorable error occurred
            if (nonIgnorableExceptionListener.exceptionOccurred()) {
                Exception renderError = nonIgnorableExceptionListener.getException();
                throw new ServiceException("Rendering process failed", renderError, "internalError");
            }

            return g;
        } catch (ParserConfigurationException e) {
            throw new ServiceException("Unexpected exception", e, "internalError");
        }
    }

    private SVGGeneratorContext setupContext() throws FactoryConfigurationError,
            ParserConfigurationException {
        Document document = null;

        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

        DocumentBuilder db = dbf.newDocumentBuilder();

        // Create an instance of org.w3c.dom.Document
        String svgNamespaceURI = "http://www.w3.org/2000/svg";
        document = db.getDOMImplementation().createDocument(svgNamespaceURI, "svg", null);

        // Set up the context
        return SVGGeneratorContext.createDefault(document);
    }

    public MapProducerCapabilities getCapabilities(String format) {
        return CAPABILITIES;
    }

}
TOP

Related Classes of org.geoserver.wms.svg.SVGBatikMapOutputFormat

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.