//$Header$ /*---------------- FILE HEADER ------------------------------------------ This file is part of deegree. Copyright (C) 2001-2005 by: EXSE, Department of Geography, University of Bonn http://www.giub.uni-bonn.de/deegree/ lat/lon GmbH http://www.lat-lon.de This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Contact: Andreas Poth lat/lon GmbH Aennchenstraße 19 53177 Bonn Germany E-Mail: poth@lat-lon.de Jens Fitzke Department of Geography University of Bonn Meckenheimer Allee 166 53115 Bonn Germany E-Mail: greve@giub.uni-bonn.de ---------------------------------------------------------------------------*/ package org.deegree.graphics; import java.awt.AlphaComposite; import java.awt.Composite; import java.awt.Graphics2D; import java.awt.Polygon; import java.awt.color.ColorSpace; import java.awt.image.BufferedImage; import java.awt.image.ColorConvertOp; import java.awt.image.ConvolveOp; import java.awt.image.Kernel; import java.util.ArrayList; import java.util.List; import org.deegree.framework.xml.XMLParsingException; import org.deegree.graphics.transformation.WorldToScreenTransform; import org.deegree.model.spatialschema.Envelope; import org.deegree.model.spatialschema.GMLGeometryAdapter; import org.deegree.model.spatialschema.Geometry; import org.deegree.model.spatialschema.GeometryException; import org.deegree.model.spatialschema.MultiSurface; import org.deegree.model.spatialschema.Position; import org.deegree.model.spatialschema.Ring; import org.deegree.model.spatialschema.Surface; /** * Display map surface depending on the security parameters. The rest of the Map Image will be * blurred allowing the user a clear view of only the allowed surface. * * @author <a href="mailto:deshmukh@lat-lon.de">Anup Deshmukh</a> * * @author last edited by: $Author$ * * @version 2.0, $Revision$, $Date$ * * @since 2.0 */ public class BlurImage { /** * Create a new BlurImage instance. */ public BlurImage() { } /** * Render the surface geometry the user is allowed to see. The geometry must be within the * bounding box of the map image. * * 1. Geometry contains bbox -> no need to blur the image 2. Geometry complety within bbox. 3. * BBOX intersects Geometry a. Returns a MultiSurface b. Returns a Surface 4. BBOX disjunkt * Geometry * * @param image * @param bbox * @param geom * @return BufferedImage * @throws GeometryException * @throws XMLParsingException */ public BufferedImage renderUserRealm( BufferedImage image, Envelope bbox, Geometry geom ) throws GeometryException, XMLParsingException { int blurScale = 8; float alpha = 0.2f; // Create output image BufferedImage output = null; if ( image.getType() == BufferedImage.TYPE_INT_RGB ) { System.out.println( "setting rgb" ); output = new BufferedImage( image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB ); } else { System.out.println( "setting rgba" ); output = new BufferedImage( image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB ); } // Transform the world coordinates to screen coordinates. WorldToScreenTransform wsTransform = new WorldToScreenTransform( bbox.getMin().getX(), bbox.getMin().getY(), bbox.getMax().getX(), bbox.getMax().getY(), image.getMinX(), image.getMinY(), image.getWidth(), image.getHeight() ); Graphics2D graphics = output.createGraphics(); Composite composite = graphics.getComposite(); graphics.setComposite( AlphaComposite.getInstance( AlphaComposite.SRC_OVER, alpha ) ); // blur image, along with the blur scale. graphics.drawImage( blur( grayScale( image ), blurScale ), null, image.getMinX(), image.getMinY() ); graphics.setComposite( composite ); try { // convert bbox to geometry. StringBuffer envelope = GMLGeometryAdapter.exportAsBox( bbox ); Geometry boundingBOX = GMLGeometryAdapter.wrap( envelope.toString() ); Geometry intersection = boundingBOX.intersection( geom ); if ( intersection instanceof Surface ) { Surface surface = (Surface) intersection; Polygon polygon = retrieveSurfacePolygon( surface, wsTransform ); graphics = renderClip( graphics, polygon, image ); } else if ( intersection instanceof MultiSurface ) { MultiSurface multiSurface = (MultiSurface) intersection; Surface[] surfaces = multiSurface.getAllSurfaces(); for ( int i = 0; i < surfaces.length; i++ ) { Surface surface = surfaces[i]; Polygon polygon = retrieveSurfacePolygon( surface, wsTransform ); graphics = renderClip( graphics, polygon, image ); } } } catch ( GeometryException e ) { throw new GeometryException( "Error creating a geometry from the bounding box. " + e ); } catch ( XMLParsingException e ) { throw new XMLParsingException( "Error exporting the bounding box to its " + "string format. " + e ); } graphics.dispose(); return output; } /** * Render the clip image on the output graphics context. * * @param graphics * @param polygon * @param image * @return Graphics2D */ private Graphics2D renderClip( Graphics2D graphics, Polygon polygon, BufferedImage image ) { // clip the region which the user is allowed to see graphics.setClip( polygon ); // draw region graphics.drawImage( image, null, image.getMinX(), image.getMinY() ); return graphics; } /** * Retrieve the surface as a java.awt.Polygon. The exterior and interior rings are retrieved and * the coordinates transformed to screen coordinates. * * @param surface * @param wsTransform * @return Polygon */ private Polygon retrieveSurfacePolygon( Surface surface, WorldToScreenTransform wsTransform ) { Ring exteriorRing = surface.getSurfaceBoundary().getExteriorRing(); Position[] exteriorPositions = exteriorRing.getPositions(); Ring[] interiorRings = surface.getSurfaceBoundary().getInteriorRings(); Position[][] interiorPositions; if ( interiorRings != null ) { interiorPositions = new Position[interiorRings.length][]; for ( int i = 0; i < interiorPositions.length; i++ ) { interiorPositions[i] = interiorRings[i].getPositions(); } } else { interiorPositions = new Position[0][]; } int[] xArray = getXArray( exteriorPositions, interiorPositions, wsTransform ); int[] yArray = getYArray( exteriorPositions, interiorPositions, wsTransform ); Polygon polygon = new Polygon( xArray, yArray, xArray.length ); return polygon; } /** * Retrieve the array of x-coordinates after transformation to screen coordinates. * * @param exteriorRing * @param interiorRing * @param wsTransform * @return int[] */ private int[] getXArray( Position[] exteriorRing, Position[][] interiorRing, WorldToScreenTransform wsTransform ) { List xList = new ArrayList(); for ( int i = 0; i < exteriorRing.length; i++ ) { Position position = exteriorRing[i]; xList.add( wsTransform.getDestX( position.getX() ) ); } for ( int i = 0; i < interiorRing.length; i++ ) { Position[] positions = interiorRing[i]; for ( int j = 0; j < positions.length; j++ ) { Position position = positions[j]; xList.add( wsTransform.getDestX( position.getX() ) ); } } int[] xArray = new int[xList.size()]; for ( int i = 0; i < xList.size(); i++ ) { Double tmp = (Double) xList.get( i ); xArray[i] = tmp.intValue(); } return xArray; } /** * Retrieve the array of y-coordinates after transformation to screen coordinates. * * @param exteriorRing * @param interiorRing * @param wsTransform * @return int[] */ private int[] getYArray( Position[] exteriorRing, Position[][] interiorRing, WorldToScreenTransform wsTransform ) { List yList = new ArrayList(); for ( int i = 0; i < exteriorRing.length; i++ ) { Position position = exteriorRing[i]; yList.add( wsTransform.getDestY( position.getY() ) ); } for ( int i = 0; i < interiorRing.length; i++ ) { Position[] positions = interiorRing[i]; for ( int j = 0; j < positions.length; j++ ) { Position position = positions[j]; yList.add( wsTransform.getDestY( position.getY() ) ); } } int[] yArray = new int[yList.size()]; for ( int i = 0; i < yList.size(); i++ ) { Double tmp = (Double) yList.get( i ); yArray[i] = tmp.intValue(); } return yArray; } /** * Blur effect carried out on the image. The blur scale defines the intensity of the blur. * * @param image * @param blurScale * @return BufferedImage */ private BufferedImage blur( BufferedImage image, int blurScale ) { BufferedImage destination = null; if ( image.getType() == BufferedImage.TYPE_INT_RGB ) { destination = new BufferedImage( image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB ); } else { destination = new BufferedImage( image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB ); } float[] data = new float[blurScale * blurScale]; float value = 1.0f / ( blurScale * blurScale ); for ( int i = 0; i < data.length; i++ ) { data[i] = value; } Kernel kernel = new Kernel( blurScale, blurScale, data ); ConvolveOp convolve = new ConvolveOp( kernel, ConvolveOp.EDGE_NO_OP, null ); convolve.filter( image, destination ); return destination; } /** * Convert BufferedImage RGB to black and white image * * @param image * @return BufferedImage */ private BufferedImage grayScale( BufferedImage image ) { BufferedImage destination = null; if ( image.getType() == BufferedImage.TYPE_INT_RGB ) { destination = new BufferedImage( image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB ); } else { destination = new BufferedImage( image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB ); } ColorConvertOp colorConvert = new ColorConvertOp( ColorSpace.getInstance( ColorSpace.CS_GRAY ), null ); colorConvert.filter( image, destination ); return destination; } } /* ******************************************************************** Changes to this class. What the people have been up to: $Log$ Revision 1.18 2006/08/29 19:54:14 poth footer corrected Revision 1.17 2006/08/24 06:39:28 poth File header corrected Revision 1.16 2006/08/06 20:06:13 poth useless method removed Revision 1.15 2006/07/12 14:46:18 poth comment footer added ********************************************************************** */