001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/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 13:32:12 +0100 (Do, 27 Dez 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, Envelope bbox, Geometry geom ) 107 throws GeometryException, XMLParsingException { 108 109 int blurScale = 8; 110 float alpha = 0.2f; 111 112 // Create output image 113 BufferedImage output = null; 114 if ( image.getType() == BufferedImage.TYPE_INT_RGB ) { 115 System.out.println( "setting rgb" ); 116 output = new BufferedImage( image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB ); 117 } else { 118 System.out.println( "setting rgba" ); 119 output = new BufferedImage( image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB ); 120 } 121 122 // Transform the world coordinates to screen coordinates. 123 WorldToScreenTransform wsTransform = new WorldToScreenTransform( bbox.getMin().getX(), bbox.getMin().getY(), 124 bbox.getMax().getX(), bbox.getMax().getY(), 125 image.getMinX(), image.getMinY(), 126 image.getWidth(), image.getHeight() ); 127 128 Graphics2D graphics = output.createGraphics(); 129 Composite composite = graphics.getComposite(); 130 graphics.setComposite( AlphaComposite.getInstance( AlphaComposite.SRC_OVER, alpha ) ); 131 // blur image, along with the blur scale. 132 graphics.drawImage( blur( grayScale( image ), blurScale ), null, image.getMinX(), image.getMinY() ); 133 graphics.setComposite( composite ); 134 try { 135 // convert bbox to geometry. 136 StringBuffer envelope = GMLGeometryAdapter.exportAsBox( bbox ); 137 Geometry boundingBOX = GMLGeometryAdapter.wrap( envelope.toString(), null ); 138 Geometry intersection = boundingBOX.intersection( geom ); 139 if ( intersection instanceof Surface ) { 140 Surface surface = (Surface) intersection; 141 Polygon polygon = retrieveSurfacePolygon( surface, wsTransform ); 142 graphics = renderClip( graphics, polygon, image ); 143 } else if ( intersection instanceof MultiSurface ) { 144 MultiSurface multiSurface = (MultiSurface) intersection; 145 Surface[] surfaces = multiSurface.getAllSurfaces(); 146 for ( int i = 0; i < surfaces.length; i++ ) { 147 Surface surface = surfaces[i]; 148 Polygon polygon = retrieveSurfacePolygon( surface, wsTransform ); 149 graphics = renderClip( graphics, polygon, image ); 150 } 151 } 152 } catch ( GeometryException e ) { 153 throw new GeometryException( "Error creating a geometry from the bounding box. " + e ); 154 } catch ( XMLParsingException e ) { 155 throw new XMLParsingException( "Error exporting the bounding box to its " + "string format. " + e ); 156 } 157 graphics.dispose(); 158 return output; 159 } 160 161 /** 162 * Render the clip image on the output graphics context. 163 * 164 * @param graphics 165 * @param polygon 166 * @param image 167 * @return Graphics2D 168 */ 169 private Graphics2D renderClip( Graphics2D graphics, Polygon polygon, BufferedImage image ) { 170 171 // clip the region which the user is allowed to see 172 graphics.setClip( polygon ); 173 // draw region 174 graphics.drawImage( image, null, image.getMinX(), image.getMinY() ); 175 176 return graphics; 177 178 } 179 180 /** 181 * Retrieve the surface as a java.awt.Polygon. The exterior and interior rings are retrieved and 182 * the coordinates transformed to screen coordinates. 183 * 184 * @param surface 185 * @param wsTransform 186 * @return Polygon 187 */ 188 private Polygon retrieveSurfacePolygon( Surface surface, WorldToScreenTransform wsTransform ) { 189 190 Ring exteriorRing = surface.getSurfaceBoundary().getExteriorRing(); 191 Position[] exteriorPositions = exteriorRing.getPositions(); 192 Ring[] interiorRings = surface.getSurfaceBoundary().getInteriorRings(); 193 194 Position[][] interiorPositions; 195 if ( interiorRings != null ) { 196 interiorPositions = new Position[interiorRings.length][]; 197 for ( int i = 0; i < interiorPositions.length; i++ ) { 198 interiorPositions[i] = interiorRings[i].getPositions(); 199 } 200 } else { 201 interiorPositions = new Position[0][]; 202 } 203 204 int[] xArray = getXArray( exteriorPositions, interiorPositions, wsTransform ); 205 int[] yArray = getYArray( exteriorPositions, interiorPositions, wsTransform ); 206 207 Polygon polygon = new Polygon( xArray, yArray, xArray.length ); 208 209 return polygon; 210 } 211 212 /** 213 * Retrieve the array of x-coordinates after transformation to screen coordinates. 214 * 215 * @param exteriorRing 216 * @param interiorRing 217 * @param wsTransform 218 * @return int[] 219 */ 220 private int[] getXArray( Position[] exteriorRing, Position[][] interiorRing, WorldToScreenTransform wsTransform ) { 221 222 List<Double> xList = new ArrayList<Double>(); 223 for ( int i = 0; i < exteriorRing.length; i++ ) { 224 Position position = exteriorRing[i]; 225 xList.add( wsTransform.getDestX( position.getX() ) ); 226 } 227 for ( int i = 0; i < interiorRing.length; i++ ) { 228 Position[] positions = interiorRing[i]; 229 for ( int j = 0; j < positions.length; j++ ) { 230 Position position = positions[j]; 231 xList.add( wsTransform.getDestX( position.getX() ) ); 232 } 233 } 234 235 int[] xArray = new int[xList.size()]; 236 for ( int i = 0; i < xList.size(); i++ ) { 237 Double tmp = xList.get( i ); 238 xArray[i] = tmp.intValue(); 239 } 240 return xArray; 241 } 242 243 /** 244 * Retrieve the array of y-coordinates after transformation to screen coordinates. 245 * 246 * @param exteriorRing 247 * @param interiorRing 248 * @param wsTransform 249 * @return int[] 250 */ 251 private int[] getYArray( Position[] exteriorRing, Position[][] interiorRing, WorldToScreenTransform wsTransform ) { 252 253 List<Double> yList = new ArrayList<Double>(); 254 for ( int i = 0; i < exteriorRing.length; i++ ) { 255 Position position = exteriorRing[i]; 256 yList.add( wsTransform.getDestY( position.getY() ) ); 257 } 258 for ( int i = 0; i < interiorRing.length; i++ ) { 259 Position[] positions = interiorRing[i]; 260 for ( int j = 0; j < positions.length; j++ ) { 261 Position position = positions[j]; 262 yList.add( wsTransform.getDestY( position.getY() ) ); 263 } 264 } 265 266 int[] yArray = new int[yList.size()]; 267 for ( int i = 0; i < yList.size(); i++ ) { 268 Double tmp = yList.get( i ); 269 yArray[i] = tmp.intValue(); 270 } 271 return yArray; 272 } 273 274 /** 275 * Blur effect carried out on the image. The blur scale defines the intensity of the blur. 276 * 277 * @param image 278 * @param blurScale 279 * @return BufferedImage 280 */ 281 private BufferedImage blur( BufferedImage image, int blurScale ) { 282 283 BufferedImage destination = null; 284 if ( image.getType() == BufferedImage.TYPE_INT_RGB ) { 285 destination = new BufferedImage( image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB ); 286 } else { 287 destination = new BufferedImage( image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB ); 288 } 289 290 float[] data = new float[blurScale * blurScale]; 291 float value = 1.0f / ( blurScale * blurScale ); 292 for ( int i = 0; i < data.length; i++ ) { 293 data[i] = value; 294 } 295 Kernel kernel = new Kernel( blurScale, blurScale, data ); 296 ConvolveOp convolve = new ConvolveOp( kernel, ConvolveOp.EDGE_NO_OP, null ); 297 convolve.filter( image, destination ); 298 299 return destination; 300 } 301 302 /** 303 * Convert BufferedImage RGB to black and white image 304 * 305 * @param image 306 * @return BufferedImage 307 */ 308 private BufferedImage grayScale( BufferedImage image ) { 309 310 BufferedImage destination = null; 311 if ( image.getType() == BufferedImage.TYPE_INT_RGB ) { 312 destination = new BufferedImage( image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB ); 313 } else { 314 destination = new BufferedImage( image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB ); 315 } 316 ColorConvertOp colorConvert = new ColorConvertOp( ColorSpace.getInstance( ColorSpace.CS_GRAY ), null ); 317 colorConvert.filter( image, destination ); 318 319 return destination; 320 } 321 322 }