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.pdf;
006:
007: import java.awt.AlphaComposite;
008: import java.awt.Color;
009: import java.awt.Graphics2D;
010: import java.awt.Rectangle;
011: import java.awt.RenderingHints;
012: import java.awt.geom.AffineTransform;
013: import java.awt.image.RenderedImage;
014: import java.io.ByteArrayOutputStream;
015: import java.io.IOException;
016: import java.io.OutputStream;
017: import java.util.HashMap;
018: import java.util.Map;
019: import java.util.logging.Level;
020: import java.util.logging.Logger;
021:
022: import org.geotools.renderer.lite.RendererUtilities;
023: import org.geotools.renderer.lite.StreamingRenderer;
024: import org.vfny.geoserver.wms.RasterMapProducer;
025: import org.vfny.geoserver.wms.WmsException;
026: import org.vfny.geoserver.wms.responses.AbstractRasterMapProducer;
027:
028: import com.lowagie.text.Document;
029: import com.lowagie.text.FontFactory;
030: import com.lowagie.text.pdf.DefaultFontMapper;
031: import com.lowagie.text.pdf.PdfContentByte;
032: import com.lowagie.text.pdf.PdfTemplate;
033: import com.lowagie.text.pdf.PdfWriter;
034: import com.vividsolutions.jts.geom.Envelope;
035:
036: /**
037: * Handles a GetMap request that spects a map in PDF format.
038: *
039: * @author Pierre-Emmanuel Balageas, ALCER (http://www.alcer.com)
040: * @author Simone Giannecchini - GeoSolutions
041: * @version $Id: PDFMapProducer.java 7746 2007-11-13 15:38:35Z aaime $
042: */
043: class PDFMapProducer extends AbstractRasterMapProducer implements
044: RasterMapProducer {
045: /** A logger for this class. */
046: private static final Logger LOGGER = org.geotools.util.logging.Logging
047: .getLogger("org.vfny.geoserver.responses.wms.map.pdf");
048:
049: /** Which format to encode the image in if one is not supplied */
050: private static final String DEFAULT_MAP_FORMAT = "application/pdf";
051:
052: /** The byte code generated by the execute method. */
053: private ByteArrayOutputStream bos;
054:
055: /**
056: *
057: */
058: public PDFMapProducer() {
059: this (DEFAULT_MAP_FORMAT, PDFMapProducerFactory.MIME_TYPE);
060: }
061:
062: /**
063: *
064: */
065: public PDFMapProducer(String outputFormat, String mime) {
066: super (outputFormat, mime);
067: }
068:
069: /**
070: * Writes the image to the client.
071: *
072: * @param out
073: * The output stream to write to.
074: */
075: public void writeTo(OutputStream out)
076: throws org.vfny.geoserver.ServiceException,
077: java.io.IOException {
078: // write to out
079: out.write(bos.toByteArray());
080: }
081:
082: /**
083: * Gets the content type. This is set by the request, should only be called
084: * after execute. GetMapResponse should handle this though.
085: *
086: * @return The mime type that this response will generate.
087: *
088: * @throws IllegalStateException
089: * DOCUMENT ME!
090: */
091: public String getContentType()
092: throws java.lang.IllegalStateException {
093: if (this .format == null) {
094: throw new IllegalStateException(
095: "the output map format was not yet specified");
096: }
097:
098: return this .format;
099: }
100:
101: /**
102: * returns the content encoding for the output data (null for this class)
103: *
104: * @return <code>null</code> since no special encoding is performed while
105: * wrtting to the output stream. Do not confuse this with
106: * getMimeType().
107: */
108: public String getContentEncoding() {
109: return null;
110: }
111:
112: /**
113: * Performs the execute request using geotools rendering.
114: *
115: * @param map
116: * The information on the types requested.
117: *
118: * @throws WmsException
119: * For any problems.
120: */
121: public void produceMap() throws WmsException {
122: final int width = mapContext.getMapWidth();
123: final int height = mapContext.getMapHeight();
124:
125: if (LOGGER.isLoggable(Level.FINE)) {
126: LOGGER
127: .fine("setting up " + width + "x" + height
128: + " image");
129: }
130:
131: try {
132: ByteArrayOutputStream curOs = new ByteArrayOutputStream();
133:
134: // step 1: creation of a document-object
135: // width of document-object is width*72 inches
136: // height of document-object is height*72 inches
137: com.lowagie.text.Rectangle pageSize = new com.lowagie.text.Rectangle(
138: width, height);
139:
140: Document document = new Document(pageSize);
141: document.setMargins(0, 0, 0, 0);
142:
143: // step 2: creation of the writer
144: PdfWriter writer = PdfWriter.getInstance(document, curOs);
145:
146: // step 3: we open the document
147: document.open();
148:
149: // step 4: we grab the ContentByte and do some stuff with it
150:
151: // we create a fontMapper and read all the fonts in the font
152: // directory
153: DefaultFontMapper mapper = new DefaultFontMapper();
154: FontFactory.registerDirectories();
155:
156: // we create a template and a Graphics2D object that corresponds
157: // with it
158: PdfContentByte cb = writer.getDirectContent();
159: PdfTemplate tp = cb.createTemplate(width, height);
160: Graphics2D graphic = tp.createGraphics(width, height,
161: mapper);
162:
163: // we set graphics options
164: if (!mapContext.isTransparent()) {
165: graphic.setColor(mapContext.getBgColor());
166: graphic.fillRect(0, 0, width, height);
167: } else {
168: if (LOGGER.isLoggable(Level.FINE)) {
169: LOGGER.fine("setting to transparent");
170: }
171:
172: int type = AlphaComposite.SRC;
173: graphic.setComposite(AlphaComposite.getInstance(type));
174:
175: Color c = new Color(mapContext.getBgColor().getRed(),
176: mapContext.getBgColor().getGreen(), mapContext
177: .getBgColor().getBlue(), 0);
178: graphic.setBackground(mapContext.getBgColor());
179: graphic.setColor(c);
180: graphic.fillRect(0, 0, width, height);
181:
182: type = AlphaComposite.SRC_OVER;
183: graphic.setComposite(AlphaComposite.getInstance(type));
184: }
185:
186: Rectangle paintArea = new Rectangle(width, height);
187:
188: renderer = new StreamingRenderer();
189: renderer.setContext(mapContext);
190:
191: RenderingHints hints = new RenderingHints(
192: RenderingHints.KEY_ANTIALIASING,
193: RenderingHints.VALUE_ANTIALIAS_ON);
194: renderer.setJava2DHints(hints);
195:
196: // we already do everything that the optimized data loading does...
197: // if we set it to true then it does it all twice...
198: Map rendererParams = new HashMap();
199: rendererParams.put("optimizedDataLoadingEnabled",
200: new Boolean(true));
201: rendererParams.put("renderingBuffer", new Integer(
202: mapContext.getBuffer()));
203: renderer.setRendererHints(rendererParams);
204:
205: Envelope dataArea = mapContext.getAreaOfInterest();
206: AffineTransform at = RendererUtilities
207: .worldToScreenTransform(dataArea, paintArea);
208:
209: if (this .abortRequested) {
210: graphic.dispose();
211: // step 5: we close the document
212: document.close();
213:
214: return;
215: }
216:
217: renderer.paint(graphic, paintArea, at);
218:
219: if (!this .abortRequested) {
220: this .bos = curOs;
221: }
222:
223: graphic.dispose();
224: cb.addTemplate(tp, 0, 0);
225:
226: // step 5: we close the document
227: document.close();
228: } catch (Throwable t) {
229: LOGGER.warning("UNCAUGHT exception: " + t.getMessage());
230:
231: WmsException wmse = new WmsException("UNCAUGHT exception: "
232: + t.getMessage());
233: wmse.setStackTrace(t.getStackTrace());
234: throw wmse;
235: }
236: }
237:
238: public String getContentDisposition() {
239: if (this .mapContext.getLayer(0) != null) {
240: try {
241: String title = this .mapContext.getLayer(0)
242: .getFeatureSource().getSchema().getTypeName();
243:
244: if ((title != null) && !title.equals("")) {
245: return "attachment; filename=" + title + ".pdf";
246: }
247: } catch (NullPointerException e) {
248: }
249: }
250:
251: return "attachment; filename=geoserver.pdf";
252: }
253:
254: public void formatImageOutputStream(RenderedImage image,
255: OutputStream outStream) throws WmsException, IOException {
256: // do nothing
257: }
258: }
|