001: //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/trunk/src/org/deegree/graphics/BlurImage.java $
002: /*---------------- FILE HEADER ------------------------------------------
003:
004: This file is part of deegree.
005: Copyright (C) 2001-2008 by:
006: EXSE, Department of Geography, University of Bonn
007: http://www.giub.uni-bonn.de/deegree/
008: lat/lon GmbH
009: http://www.lat-lon.de
010:
011: This library is free software; you can redistribute it and/or
012: modify it under the terms of the GNU Lesser General Public
013: License as published by the Free Software Foundation; either
014: version 2.1 of the License, or (at your option) any later version.
015:
016: This library is distributed in the hope that it will be useful,
017: but WITHOUT ANY WARRANTY; without even the implied warranty of
018: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019: Lesser General Public License for more details.
020:
021: You should have received a copy of the GNU Lesser General Public
022: License along with this library; if not, write to the Free Software
023: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024:
025: Contact:
026:
027: Andreas Poth
028: lat/lon GmbH
029: Aennchenstr. 19
030: 53115 Bonn
031: Germany
032: E-Mail: poth@lat-lon.de
033:
034: Prof. Dr. Klaus Greve
035: Department of Geography
036: University of Bonn
037: Meckenheimer Allee 166
038: 53115 Bonn
039: Germany
040: E-Mail: greve@giub.uni-bonn.de
041:
042:
043: ---------------------------------------------------------------------------*/
044:
045: package org.deegree.graphics;
046:
047: import java.awt.AlphaComposite;
048: import java.awt.Composite;
049: import java.awt.Graphics2D;
050: import java.awt.Polygon;
051: import java.awt.color.ColorSpace;
052: import java.awt.image.BufferedImage;
053: import java.awt.image.ColorConvertOp;
054: import java.awt.image.ConvolveOp;
055: import java.awt.image.Kernel;
056: import java.util.ArrayList;
057: import java.util.List;
058:
059: import org.deegree.framework.xml.XMLParsingException;
060: import org.deegree.graphics.transformation.WorldToScreenTransform;
061: import org.deegree.model.spatialschema.Envelope;
062: import org.deegree.model.spatialschema.GMLGeometryAdapter;
063: import org.deegree.model.spatialschema.Geometry;
064: import org.deegree.model.spatialschema.GeometryException;
065: import org.deegree.model.spatialschema.MultiSurface;
066: import org.deegree.model.spatialschema.Position;
067: import org.deegree.model.spatialschema.Ring;
068: import org.deegree.model.spatialschema.Surface;
069:
070: /**
071: * Display map surface depending on the security parameters. The rest of the Map Image will be
072: * blurred allowing the user a clear view of only the allowed surface.
073: *
074: * @author <a href="mailto:deshmukh@lat-lon.de">Anup Deshmukh</a>
075: *
076: * @author last edited by: $Author: apoth $
077: *
078: * @version 2.0, $Revision: 9340 $, $Date: 2007-12-27 04:32:12 -0800 (Thu, 27 Dec 2007) $
079: *
080: * @since 2.0
081: */
082:
083: public class BlurImage {
084:
085: /**
086: * Create a new BlurImage instance.
087: */
088: public BlurImage() {
089: }
090:
091: /**
092: * Render the surface geometry the user is allowed to see. The geometry must be within the
093: * bounding box of the map image.
094: *
095: * 1. Geometry contains bbox -> no need to blur the image 2. Geometry complety within bbox. 3.
096: * BBOX intersects Geometry a. Returns a MultiSurface b. Returns a Surface 4. BBOX disjunkt
097: * Geometry
098: *
099: * @param image
100: * @param bbox
101: * @param geom
102: * @return BufferedImage
103: * @throws GeometryException
104: * @throws XMLParsingException
105: */
106: public BufferedImage renderUserRealm(BufferedImage image,
107: Envelope bbox, Geometry geom) throws GeometryException,
108: XMLParsingException {
109:
110: int blurScale = 8;
111: float alpha = 0.2f;
112:
113: // Create output image
114: BufferedImage output = null;
115: if (image.getType() == BufferedImage.TYPE_INT_RGB) {
116: System.out.println("setting rgb");
117: output = new BufferedImage(image.getWidth(), image
118: .getHeight(), BufferedImage.TYPE_INT_RGB);
119: } else {
120: System.out.println("setting rgba");
121: output = new BufferedImage(image.getWidth(), image
122: .getHeight(), BufferedImage.TYPE_INT_ARGB);
123: }
124:
125: // Transform the world coordinates to screen coordinates.
126: WorldToScreenTransform wsTransform = new WorldToScreenTransform(
127: bbox.getMin().getX(), bbox.getMin().getY(), bbox
128: .getMax().getX(), bbox.getMax().getY(), image
129: .getMinX(), image.getMinY(), image.getWidth(),
130: image.getHeight());
131:
132: Graphics2D graphics = output.createGraphics();
133: Composite composite = graphics.getComposite();
134: graphics.setComposite(AlphaComposite.getInstance(
135: AlphaComposite.SRC_OVER, alpha));
136: // blur image, along with the blur scale.
137: graphics.drawImage(blur(grayScale(image), blurScale), null,
138: image.getMinX(), image.getMinY());
139: graphics.setComposite(composite);
140: try {
141: // convert bbox to geometry.
142: StringBuffer envelope = GMLGeometryAdapter
143: .exportAsBox(bbox);
144: Geometry boundingBOX = GMLGeometryAdapter.wrap(envelope
145: .toString(), null);
146: Geometry intersection = boundingBOX.intersection(geom);
147: if (intersection instanceof Surface) {
148: Surface surface = (Surface) intersection;
149: Polygon polygon = retrieveSurfacePolygon(surface,
150: wsTransform);
151: graphics = renderClip(graphics, polygon, image);
152: } else if (intersection instanceof MultiSurface) {
153: MultiSurface multiSurface = (MultiSurface) intersection;
154: Surface[] surfaces = multiSurface.getAllSurfaces();
155: for (int i = 0; i < surfaces.length; i++) {
156: Surface surface = surfaces[i];
157: Polygon polygon = retrieveSurfacePolygon(surface,
158: wsTransform);
159: graphics = renderClip(graphics, polygon, image);
160: }
161: }
162: } catch (GeometryException e) {
163: throw new GeometryException(
164: "Error creating a geometry from the bounding box. "
165: + e);
166: } catch (XMLParsingException e) {
167: throw new XMLParsingException(
168: "Error exporting the bounding box to its "
169: + "string format. " + e);
170: }
171: graphics.dispose();
172: return output;
173: }
174:
175: /**
176: * Render the clip image on the output graphics context.
177: *
178: * @param graphics
179: * @param polygon
180: * @param image
181: * @return Graphics2D
182: */
183: private Graphics2D renderClip(Graphics2D graphics, Polygon polygon,
184: BufferedImage image) {
185:
186: // clip the region which the user is allowed to see
187: graphics.setClip(polygon);
188: // draw region
189: graphics.drawImage(image, null, image.getMinX(), image
190: .getMinY());
191:
192: return graphics;
193:
194: }
195:
196: /**
197: * Retrieve the surface as a java.awt.Polygon. The exterior and interior rings are retrieved and
198: * the coordinates transformed to screen coordinates.
199: *
200: * @param surface
201: * @param wsTransform
202: * @return Polygon
203: */
204: private Polygon retrieveSurfacePolygon(Surface surface,
205: WorldToScreenTransform wsTransform) {
206:
207: Ring exteriorRing = surface.getSurfaceBoundary()
208: .getExteriorRing();
209: Position[] exteriorPositions = exteriorRing.getPositions();
210: Ring[] interiorRings = surface.getSurfaceBoundary()
211: .getInteriorRings();
212:
213: Position[][] interiorPositions;
214: if (interiorRings != null) {
215: interiorPositions = new Position[interiorRings.length][];
216: for (int i = 0; i < interiorPositions.length; i++) {
217: interiorPositions[i] = interiorRings[i].getPositions();
218: }
219: } else {
220: interiorPositions = new Position[0][];
221: }
222:
223: int[] xArray = getXArray(exteriorPositions, interiorPositions,
224: wsTransform);
225: int[] yArray = getYArray(exteriorPositions, interiorPositions,
226: wsTransform);
227:
228: Polygon polygon = new Polygon(xArray, yArray, xArray.length);
229:
230: return polygon;
231: }
232:
233: /**
234: * Retrieve the array of x-coordinates after transformation to screen coordinates.
235: *
236: * @param exteriorRing
237: * @param interiorRing
238: * @param wsTransform
239: * @return int[]
240: */
241: private int[] getXArray(Position[] exteriorRing,
242: Position[][] interiorRing,
243: WorldToScreenTransform wsTransform) {
244:
245: List<Double> xList = new ArrayList<Double>();
246: for (int i = 0; i < exteriorRing.length; i++) {
247: Position position = exteriorRing[i];
248: xList.add(wsTransform.getDestX(position.getX()));
249: }
250: for (int i = 0; i < interiorRing.length; i++) {
251: Position[] positions = interiorRing[i];
252: for (int j = 0; j < positions.length; j++) {
253: Position position = positions[j];
254: xList.add(wsTransform.getDestX(position.getX()));
255: }
256: }
257:
258: int[] xArray = new int[xList.size()];
259: for (int i = 0; i < xList.size(); i++) {
260: Double tmp = xList.get(i);
261: xArray[i] = tmp.intValue();
262: }
263: return xArray;
264: }
265:
266: /**
267: * Retrieve the array of y-coordinates after transformation to screen coordinates.
268: *
269: * @param exteriorRing
270: * @param interiorRing
271: * @param wsTransform
272: * @return int[]
273: */
274: private int[] getYArray(Position[] exteriorRing,
275: Position[][] interiorRing,
276: WorldToScreenTransform wsTransform) {
277:
278: List<Double> yList = new ArrayList<Double>();
279: for (int i = 0; i < exteriorRing.length; i++) {
280: Position position = exteriorRing[i];
281: yList.add(wsTransform.getDestY(position.getY()));
282: }
283: for (int i = 0; i < interiorRing.length; i++) {
284: Position[] positions = interiorRing[i];
285: for (int j = 0; j < positions.length; j++) {
286: Position position = positions[j];
287: yList.add(wsTransform.getDestY(position.getY()));
288: }
289: }
290:
291: int[] yArray = new int[yList.size()];
292: for (int i = 0; i < yList.size(); i++) {
293: Double tmp = yList.get(i);
294: yArray[i] = tmp.intValue();
295: }
296: return yArray;
297: }
298:
299: /**
300: * Blur effect carried out on the image. The blur scale defines the intensity of the blur.
301: *
302: * @param image
303: * @param blurScale
304: * @return BufferedImage
305: */
306: private BufferedImage blur(BufferedImage image, int blurScale) {
307:
308: BufferedImage destination = null;
309: if (image.getType() == BufferedImage.TYPE_INT_RGB) {
310: destination = new BufferedImage(image.getWidth(), image
311: .getHeight(), BufferedImage.TYPE_INT_RGB);
312: } else {
313: destination = new BufferedImage(image.getWidth(), image
314: .getHeight(), BufferedImage.TYPE_INT_ARGB);
315: }
316:
317: float[] data = new float[blurScale * blurScale];
318: float value = 1.0f / (blurScale * blurScale);
319: for (int i = 0; i < data.length; i++) {
320: data[i] = value;
321: }
322: Kernel kernel = new Kernel(blurScale, blurScale, data);
323: ConvolveOp convolve = new ConvolveOp(kernel,
324: ConvolveOp.EDGE_NO_OP, null);
325: convolve.filter(image, destination);
326:
327: return destination;
328: }
329:
330: /**
331: * Convert BufferedImage RGB to black and white image
332: *
333: * @param image
334: * @return BufferedImage
335: */
336: private BufferedImage grayScale(BufferedImage image) {
337:
338: BufferedImage destination = null;
339: if (image.getType() == BufferedImage.TYPE_INT_RGB) {
340: destination = new BufferedImage(image.getWidth(), image
341: .getHeight(), BufferedImage.TYPE_INT_RGB);
342: } else {
343: destination = new BufferedImage(image.getWidth(), image
344: .getHeight(), BufferedImage.TYPE_INT_ARGB);
345: }
346: ColorConvertOp colorConvert = new ColorConvertOp(ColorSpace
347: .getInstance(ColorSpace.CS_GRAY), null);
348: colorConvert.filter(image, destination);
349:
350: return destination;
351: }
352:
353: }
|