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.map.svg;
006:
007: import java.awt.Dimension;
008: import java.awt.Rectangle;
009: import java.awt.RenderingHints;
010: import java.awt.geom.AffineTransform;
011: import java.io.IOException;
012: import java.io.OutputStream;
013: import java.io.OutputStreamWriter;
014: import java.util.HashMap;
015: import java.util.Map;
016:
017: import javax.xml.parsers.DocumentBuilder;
018: import javax.xml.parsers.DocumentBuilderFactory;
019: import javax.xml.parsers.FactoryConfigurationError;
020: import javax.xml.parsers.ParserConfigurationException;
021:
022: import org.apache.batik.svggen.SVGGeneratorContext;
023: import org.apache.batik.svggen.SVGGraphics2D;
024: import org.apache.xml.serialize.OutputFormat;
025: import org.apache.xml.serialize.XMLSerializer;
026: import org.geotools.map.MapContext;
027: import org.geotools.renderer.lite.RendererUtilities;
028: import org.geotools.renderer.lite.StreamingRenderer;
029: import org.vfny.geoserver.ServiceException;
030: import org.vfny.geoserver.global.Service;
031: import org.vfny.geoserver.global.WMS;
032: import org.vfny.geoserver.wms.GetMapProducer;
033: import org.vfny.geoserver.wms.WMSMapContext;
034: import org.vfny.geoserver.wms.WmsException;
035: import org.vfny.geoserver.wms.responses.AbstractGetMapProducer;
036: import org.w3c.dom.Document;
037: import org.w3c.dom.Element;
038:
039: import com.vividsolutions.jts.geom.Envelope;
040:
041: /**
042: * Renders svg using the Batik SVG Toolkit. An SVG context is created for a map
043: * and then passed of to {@link org.geotools.renderer.lite.StreamingRenderer}.
044: *
045: * @author Justin Deoliveira, The Open Planning Project
046: *
047: */
048: public class SVGBatikMapProducer extends AbstractGetMapProducer
049: implements GetMapProducer {
050: StreamingRenderer renderer;
051:
052: WMS wms;
053:
054: public SVGBatikMapProducer(WMS wms) {
055: this .wms = wms;
056: }
057:
058: public void abort() {
059: if (renderer != null) {
060: renderer.stopRendering();
061: }
062: }
063:
064: public void abort(Service gs) {
065: if (renderer != null) {
066: renderer.stopRendering();
067: }
068: }
069:
070: public String getContentType() {
071: return SvgMapProducerFactory.MIME_TYPE;
072: }
073:
074: public String getContentEncoding() {
075: return null;
076: }
077:
078: public void produceMap() throws WmsException {
079: renderer = new StreamingRenderer();
080:
081: // optimized data loading was not here, but yet it seems sensible to
082: // have it...
083: Map rendererParams = new HashMap();
084: rendererParams.put("optimizedDataLoadingEnabled", new Boolean(
085: true));
086: rendererParams.put("renderingBuffer", new Integer(mapContext
087: .getBuffer()));
088: renderer.setRendererHints(rendererParams);
089: renderer.setContext(mapContext);
090: }
091:
092: public void writeTo(OutputStream out) throws ServiceException,
093: IOException {
094: try {
095: MapContext map = renderer.getContext();
096: double width = -1;
097: double height = -1;
098:
099: if (map instanceof WMSMapContext) {
100: WMSMapContext wmsMap = (WMSMapContext) map;
101: width = wmsMap.getMapWidth();
102: height = wmsMap.getMapHeight();
103: } else {
104: // guess a width and height based on the envelope
105: Envelope area = map.getAreaOfInterest();
106:
107: if ((area.getHeight() > 0) && (area.getWidth() > 0)) {
108: if (area.getHeight() >= area.getWidth()) {
109: height = 600;
110: width = height
111: * (area.getWidth() / area.getHeight());
112: } else {
113: width = 800;
114: height = width
115: * (area.getHeight() / area.getWidth());
116: }
117: }
118: }
119:
120: if ((height == -1) || (width == -1)) {
121: throw new IOException(
122: "Could not determine map dimensions");
123: }
124:
125: SVGGeneratorContext context = setupContext();
126: SVGGraphics2D g = new SVGGraphics2D(context, true);
127:
128: g
129: .setSVGCanvasSize(new Dimension((int) width,
130: (int) height));
131:
132: // turn off/on anti aliasing
133: if (wms.isSvgAntiAlias()) {
134: g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
135: RenderingHints.VALUE_ANTIALIAS_ON);
136: } else {
137: g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
138: RenderingHints.VALUE_ANTIALIAS_OFF);
139: }
140:
141: Rectangle r = new Rectangle(g.getSVGCanvasSize());
142:
143: renderer.paint(g, r, renderer.getContext()
144: .getAreaOfInterest());
145:
146: // This method of output does not output the DOCTYPE definiition
147: // TODO: make a config option that toggles wether doctype is
148: // written out.
149: OutputFormat format = new OutputFormat();
150: XMLSerializer serializer = new XMLSerializer(
151: new OutputStreamWriter(out, "UTF-8"), format);
152:
153: // this method does output the DOCTYPE def
154: g.stream(new OutputStreamWriter(out, "UTF-8"));
155: } catch (Exception e) {
156: new IOException().initCause(e);
157: } finally {
158: // free up memory
159: renderer = null;
160: }
161: }
162:
163: private SVGGeneratorContext setupContext()
164: throws FactoryConfigurationError,
165: ParserConfigurationException {
166: Document document = null;
167:
168: DocumentBuilderFactory dbf = DocumentBuilderFactory
169: .newInstance();
170:
171: DocumentBuilder db = dbf.newDocumentBuilder();
172:
173: // Create an instance of org.w3c.dom.Document
174: String svgNamespaceURI = "http://www.w3.org/2000/svg";
175: document = db.getDOMImplementation().createDocument(
176: svgNamespaceURI, "svg", null);
177:
178: // Set up the context
179: return SVGGeneratorContext.createDefault(document);
180: }
181:
182: public String getContentDisposition() {
183: // can be null
184: return null;
185: }
186: }
|