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