001: /*
002: * This file is part of the GeOxygene project source files.
003: *
004: * GeOxygene aims at providing an open framework which implements OGC/ISO specifications for
005: * the development and deployment of geographic (GIS) applications. It is a open source
006: * contribution of the COGIT laboratory at the Institut Géographique National (the French
007: * National Mapping Agency).
008: *
009: * See: http://oxygene-project.sourceforge.net
010: *
011: * Copyright (C) 2005 Institut Géographique National
012: *
013: * This library is free software; you can redistribute it and/or modify it under the terms
014: * of the GNU Lesser General Public License as published by the Free Software Foundation;
015: * either version 2.1 of the License, or any later version.
016: *
017: * This library is distributed in the hope that it will be useful, but WITHOUT ANY
018: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
019: * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
020: *
021: * You should have received a copy of the GNU Lesser General Public License along with
022: * this library (see file LICENSE if present); if not, write to the Free Software
023: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024: *
025: */
026:
027: package fr.ign.cogit.geoxygene.util.conversion;
028:
029: import java.awt.Color;
030: import java.awt.Dimension;
031: import java.awt.Graphics2D;
032: import java.awt.Shape;
033: import java.awt.geom.AffineTransform;
034: import java.awt.geom.GeneralPath;
035: import java.awt.geom.Rectangle2D;
036: import java.awt.image.BufferedImage;
037: import java.io.File;
038: import java.io.FileOutputStream;
039: import java.io.IOException;
040: import java.io.OutputStream;
041: import java.io.OutputStreamWriter;
042: import java.io.PipedReader;
043: import java.io.PipedWriter;
044: import java.io.Writer;
045: import java.util.List;
046: import java.util.zip.GZIPOutputStream;
047:
048: import javax.imageio.ImageIO;
049:
050: import org.apache.batik.dom.GenericDOMImplementation;
051: import org.apache.batik.svggen.SVGGraphics2D;
052: import org.apache.batik.transcoder.TranscoderInput;
053: import org.apache.batik.transcoder.TranscoderOutput;
054: import org.apache.fop.svg.PDFTranscoder;
055: import org.w3c.dom.DOMImplementation;
056: import org.w3c.dom.Document;
057:
058: import fr.ign.cogit.geoxygene.spatial.coordgeom.DirectPosition;
059: import fr.ign.cogit.geoxygene.spatial.coordgeom.GM_LineString;
060: import fr.ign.cogit.geoxygene.spatial.coordgeom.GM_Polygon;
061: import fr.ign.cogit.geoxygene.spatial.geomaggr.GM_Aggregate;
062: import fr.ign.cogit.geoxygene.spatial.geomprim.GM_Point;
063: import fr.ign.cogit.geoxygene.spatial.geomroot.GM_Object;
064:
065: public class ImgUtil {
066:
067: /*--------------------------------------------------------------*/
068: /*-- drawGeom() ------------------------------------------------*/
069: /*--------------------------------------------------------------*/
070:
071: private static void drawGeom(Graphics2D g, GM_Object[] geoms,
072: Color[] colors, AffineTransform transform) throws Exception {
073: if (geoms.length != colors.length)
074: throw new IllegalArgumentException(
075: "geoms.length!=colors.length");
076: for (int i = 0; i < geoms.length; i++) {
077: drawGeom(g, geoms[i], colors[i], transform);
078: }
079: }
080:
081: private static void drawGeom(Graphics2D g, GM_Object geom,
082: Color color, AffineTransform transform) throws Exception {
083: if (isEmpty(geom))
084: return;
085: else
086: drawGeom(g, WktGeOxygene.makeWkt(geom), color, transform);
087: }
088:
089: private static void drawGeom(Graphics2D g, String wkt, Color color,
090: AffineTransform transform) throws Exception {
091: drawGeom(g, WktAwt.makeAwtShape(wkt), color, transform);
092: }
093:
094: private static void drawGeom(Graphics2D g, AwtShape geom,
095: Color color, AffineTransform transform) {
096: g.setTransform(transform);
097: g.setColor(color);
098: geom.draw(g);
099: }
100:
101: /*--------------------------------------------------------------*/
102: /*-- makeScaleTransform() --------------------------------------*/
103: /*--------------------------------------------------------------*/
104:
105: private static AffineTransform makeScaleTransform(
106: GM_Object[] geoms, int width, int height) throws Exception {
107: GeneralPath all = new GeneralPath();
108: for (int i = 0; i < geoms.length; i++) {
109: if (!isEmpty(geoms[i])) {
110: all.append(WktAwt.makeAwtShape(
111: WktGeOxygene.makeWkt(geoms[i])).getBounds(),
112: false);
113: }
114: }
115: AffineTransform transform = ImgUtil.makeScaleTransform(all,
116: width, height);
117: return transform;
118: }
119:
120: private static AffineTransform makeScaleTransform(Shape geom,
121: int width, int height) {
122: Rectangle2D bbox = geom.getBounds2D();
123: bbox.setRect(bbox.getX(), bbox.getY(), bbox.getWidth(), bbox
124: .getHeight());
125:
126: double scaleX = width / bbox.getWidth();
127: double scaleY = height / bbox.getHeight();
128: double scale = (scaleX < scaleY) ? scaleX : scaleY;
129: double offsetX = -bbox.getX();
130: double offsetY = -bbox.getY() - bbox.getHeight();
131: AffineTransform transform = new AffineTransform();
132: transform.scale(scale, -scale);
133: transform.translate(offsetX, offsetY);
134: return transform;
135: }
136:
137: private static AffineTransform makeScaleTransform(Shape[] geoms,
138: int width, int height) {
139: GeneralPath geom = new GeneralPath();
140: for (int i = 0; i < geoms.length; i++) {
141: geom.append(geoms[i], false);
142: }
143: return makeScaleTransform(geom, width, height);
144: }
145:
146: /*--------------------------------------------------------------*/
147: /*--------------------------------------------------------------*/
148: /*--------------------------------------------------------------*/
149:
150: public static BufferedImage make(Color bg, int width, int height) {
151: BufferedImage image = new BufferedImage(width, height,
152: BufferedImage.TYPE_INT_RGB);
153: Graphics2D g = image.createGraphics();
154: g.setColor(bg);
155: g.fillRect(0, 0, width, height);
156: g.dispose();
157: return image;
158: }
159:
160: /*-----------------------------------------------------------*/
161: /*-- save() -------------------------------------------------*/
162: /*-----------------------------------------------------------*/
163:
164: public static void saveImage(BufferedImage image, String path)
165: throws IOException {
166: String format = "";
167: String[] formatNames = ImageIO.getWriterFormatNames();
168: for (int i = 0; i < formatNames.length; i++) {
169: if (path.endsWith("." + formatNames[i]))
170: format = formatNames[i];
171: }
172: if (format.equals("")) {
173: path += ".png";
174: format = "png";
175: }
176: ImageIO.write(image, format, new File(path));
177: }
178:
179: public static void saveImage(GM_Object geom, String path)
180: throws Exception {
181: saveImage(geom, path, Color.BLACK, Color.WHITE, 800, 800);
182: }
183:
184: public static void saveImage(List geomList, String path)
185: throws Exception {
186: saveImage(geomList, path, Color.BLACK, Color.WHITE, 800, 800);
187: }
188:
189: public static void saveImage(List geomList, String path, Color fg,
190: Color bg, int width, int height) throws Exception {
191: saveImage(new GM_Aggregate(geomList), path, fg, bg, width,
192: height);
193: }
194:
195: public static void saveImage(GM_Object geom, String path, Color fg,
196: Color bg, int width, int height) throws Exception {
197: String wkt = WktGeOxygene.makeWkt(geom);
198: AwtShape awt;
199:
200: awt = WktAwt.makeAwtShape(wkt);
201:
202: Rectangle2D bbox = awt.getBounds();
203:
204: AffineTransform transform = ImgUtil.makeScaleTransform(bbox,
205: width, height);
206: BufferedImage image = ImgUtil.make(bg, width, height);
207: ImgUtil.drawGeom(image.createGraphics(), awt, fg, transform);
208:
209: ImgUtil.saveImage(image, path);
210: }
211:
212: public static void saveImage(GM_Object[] geoms, String path,
213: Color[] foregrounds, Color background, int width, int height)
214: throws Exception {
215: AffineTransform transform = ImgUtil.makeScaleTransform(geoms,
216: width, height);
217: BufferedImage image = ImgUtil.make(background, width, height);
218: Graphics2D g = image.createGraphics();
219: ImgUtil.drawGeom(g, geoms, foregrounds, transform);
220: ImgUtil.saveImage(image, path);
221: }
222:
223: public static void savePdf(GM_Object[] geoms, String path,
224: Color[] foregrounds, Color background, int width, int height)
225: throws Exception {
226: DOMImplementation impl = GenericDOMImplementation
227: .getDOMImplementation();
228: Document svgDoc = impl.createDocument(null, "svg", null);
229:
230: AffineTransform transform = ImgUtil.makeScaleTransform(geoms,
231: width, height);
232: final SVGGraphics2D svgGenerator = new SVGGraphics2D(svgDoc);
233: svgGenerator.setSVGCanvasSize(new Dimension(width, height));
234: ImgUtil.drawGeom(svgGenerator, geoms, foregrounds, transform);
235:
236: final PipedWriter svgGenOut = new PipedWriter();
237: final PipedReader pdfTransIn = new PipedReader(svgGenOut);
238: final OutputStream pdfOut = new FileOutputStream(path);
239:
240: Thread generateSvg = new Thread() {
241: public void run() {
242: boolean useCss = true;
243: try {
244: svgGenerator.stream(svgGenOut, useCss);
245: svgGenOut.flush();
246: svgGenOut.close();
247: } catch (Exception e) {
248: throw new RuntimeException(e);
249: }
250: }
251: };
252:
253: Thread transcodeToPdf = new Thread() {
254: public void run() {
255: PDFTranscoder pdfTranscoder = new PDFTranscoder();
256: TranscoderInput tIn = new TranscoderInput(pdfTransIn);
257: TranscoderOutput tOut = new TranscoderOutput(pdfOut);
258: try {
259: pdfTranscoder.transcode(tIn, tOut);
260: } catch (Exception e) {
261: throw new RuntimeException(e);
262: }
263: }
264: };
265:
266: generateSvg.start();
267: transcodeToPdf.start();
268: generateSvg.join();
269: transcodeToPdf.join();
270: }
271:
272: public static void saveSvgz(GM_Object[] geoms, String path,
273: Color[] foregrounds, Color background, int width, int height)
274: throws Exception {
275: DOMImplementation impl = GenericDOMImplementation
276: .getDOMImplementation();
277: Document svgDoc = impl.createDocument(null, "svg", null);
278:
279: AffineTransform transform = ImgUtil.makeScaleTransform(geoms,
280: width, height);
281:
282: final SVGGraphics2D svgGenerator = new SVGGraphics2D(svgDoc);
283: svgGenerator.setSVGCanvasSize(new Dimension(width, height));
284:
285: // Stroke stroke=new BasicStroke(.4f);
286: // svgGenerator.setStroke(stroke);
287:
288: ImgUtil.drawGeom(svgGenerator, geoms, foregrounds, transform);
289: svgGenerator.setTransform(new AffineTransform());
290:
291: Writer svgGenOut = new OutputStreamWriter(new GZIPOutputStream(
292: new FileOutputStream(path)), "UTF-8");
293:
294: boolean useCss = true;
295: svgGenerator.stream(svgGenOut, useCss);
296: svgGenOut.flush();
297: svgGenOut.close();
298: }
299:
300: // utils //
301: public static boolean isEmpty(GM_Object geom) {
302: if (geom == null)
303: return true;
304: if (geom instanceof GM_Point)
305: return isEmpty((GM_Point) geom);
306: if (geom instanceof GM_Polygon)
307: return isEmpty((GM_Polygon) geom);
308: if (geom instanceof GM_LineString)
309: return isEmpty((GM_LineString) geom);
310: if (geom instanceof GM_Aggregate)
311: return isEmpty((GM_Aggregate) geom);
312: return false;
313: }
314:
315: public static boolean isEmpty(GM_Point point) {
316: DirectPosition position = point.getPosition();
317: double x = position.getX();
318: double y = position.getY();
319: double z = position.getZ();
320: return (x == Double.NaN || y == Double.NaN || z == Double.NaN);
321: }
322:
323: public static boolean isEmpty(GM_Polygon poly) {
324: return poly.coord().size() == 0;
325: }
326:
327: public static boolean isEmpty(GM_LineString lineString) {
328: return lineString.sizeControlPoint() == 0;
329: }
330:
331: static boolean isEmpty(GM_Aggregate aggr) {
332: if (aggr.size() == 0)
333: return true;
334: else {
335: aggr.initIterator();
336: while (aggr.hasNext()) {
337: GM_Object geom = aggr.next();
338: if (!isEmpty(geom))
339: return false;
340: }
341: return true;
342: }
343: }
344:
345: } // class
|