001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/model/coverage/grid/ImageGridCoverage.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    package org.deegree.model.coverage.grid;
045    
046    import java.awt.Rectangle;
047    import java.awt.image.BufferedImage;
048    import java.awt.image.renderable.ParameterBlock;
049    import java.awt.image.renderable.RenderableImage;
050    
051    import javax.media.jai.Interpolation;
052    import javax.media.jai.InterpolationNearest;
053    import javax.media.jai.JAI;
054    import javax.media.jai.RenderableGraphics;
055    import javax.media.jai.RenderedOp;
056    
057    import org.deegree.model.crs.CoordinateSystem;
058    import org.deegree.model.spatialschema.Envelope;
059    import org.deegree.model.spatialschema.GeometryFactory;
060    import org.deegree.ogcwebservices.wcs.describecoverage.CoverageOffering;
061    import org.opengis.pt.PT_Envelope;
062    
063    /**
064     * GridCoverage implementation for holding grids stored in an <tt>BufferedImage</tt> or in a set
065     * of <tt>ImageGridCoverage</tt>s
066     * 
067     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
068     * @author last edited by: $Author: apoth $
069     * 
070     * @version $Revision: 9343 $, $Date: 2007-12-27 14:30:32 +0100 (Do, 27 Dez 2007) $
071     */
072    public class ImageGridCoverage extends AbstractGridCoverage {
073    
074        private static final long serialVersionUID = -531939507044569726L;
075    
076        private transient BufferedImage image = null;
077    
078        /**
079         * 
080         * @param coverageOffering
081         * @param envelope
082         * @param image
083         */
084        public ImageGridCoverage( CoverageOffering coverageOffering, Envelope envelope, BufferedImage image ) {
085            this( coverageOffering, envelope, false, image );
086        }
087    
088        /**
089         * 
090         * @param coverageOffering
091         * @param envelope
092         * @param isEditable
093         * @param image
094         */
095        public ImageGridCoverage( CoverageOffering coverageOffering, Envelope envelope, boolean isEditable,
096                                  BufferedImage image ) {
097            super( coverageOffering, envelope, isEditable );
098            this.image = image;
099        }
100    
101        /**
102         * 
103         * @param coverageOffering
104         * @param envelope
105         * @param crs
106         * @param isEditable
107         * @param image
108         */
109        public ImageGridCoverage( CoverageOffering coverageOffering, Envelope envelope, CoordinateSystem crs,
110                                  boolean isEditable, BufferedImage image ) {
111            super( coverageOffering, envelope, crs, isEditable );
112            this.image = image;
113        }
114    
115        /**
116         * 
117         * @param coverageOffering
118         * @param envelope
119         * @param sources
120         */
121        public ImageGridCoverage( CoverageOffering coverageOffering, Envelope envelope, ImageGridCoverage[] sources ) {
122            super( coverageOffering, envelope, sources );
123        }
124    
125        /**
126         * The number of sample dimensions in the coverage. For grid coverages, a sample dimension is a
127         * band.
128         * 
129         * @return The number of sample dimensions in the coverage.
130         */
131        public int getNumSampleDimensions() {
132            if ( image != null ) {
133                return image.getData().getNumBands();
134            }
135            return sources[0].getNumSampleDimensions();
136        }
137    
138        /**
139         * Returns 2D view of this coverage as a renderable image. This optional operation allows
140         * interoperability with <A HREF="http://java.sun.com/products/java-media/2D/">Java2D</A>. If
141         * this coverage is a {@link "org.opengis.coverage.grid.GridCoverage"} backed by a
142         * {@link java.awt.image.RenderedImage}, the underlying image can be obtained with:
143         * 
144         * <code>getRenderableImage(0,1).{@linkplain RenderableImage#createDefaultRendering()
145         * createDefaultRendering()}</code>
146         * 
147         * @param xAxis
148         *            Dimension to use for the <var>x</var> axis.
149         * @param yAxis
150         *            Dimension to use for the <var>y</var> axis.
151         * @return A 2D view of this coverage as a renderable image.
152         * @throws UnsupportedOperationException
153         *             if this optional operation is not supported.
154         * @throws IndexOutOfBoundsException
155         *             if <code>xAxis</code> or <code>yAxis</code> is out of bounds.
156         */
157        public RenderableImage getRenderableImage( int xAxis, int yAxis )
158                                throws UnsupportedOperationException, IndexOutOfBoundsException {
159            if ( image != null ) {
160                if ( xAxis > 0 && yAxis > 0 ) {
161                    Rectangle rect = new Rectangle( xAxis, yAxis );
162                    RenderableGraphics rg = new RenderableGraphics( rect );
163                    rg.drawImage( image, 0, 0, xAxis, yAxis, null );
164                    return rg;
165                }
166                Rectangle rect = new Rectangle( image.getWidth(), image.getHeight() );
167                RenderableGraphics rg = new RenderableGraphics( rect );
168                rg.drawImage( image, 0, 0, null );
169                return rg;
170            }
171            // TODO if multi images -> sources.length > 0
172            return null;
173        }
174    
175        /**
176         * this is a deegree convenience method which returns the source image of an
177         * <tt>ImageGridCoverage</tt>. In procipal the same can be done with the
178         * getRenderableImage(int xAxis, int yAxis) method. but creating a <tt>RenderableImage</tt>
179         * image is very slow. I xAxis or yAxis <= 0 then the size of the returned image will be
180         * calculated from the source images of the coverage.
181         * 
182         * @param xAxis
183         *            Dimension to use for the <var>x</var> axis.
184         * @param yAxis
185         *            Dimension to use for the <var>y</var> axis.
186         * @return the source image of an <tt>ImageGridCoverage</tt>.
187         */
188        public BufferedImage getAsImage( int xAxis, int yAxis ) {
189    
190            if ( xAxis <= 0 || yAxis <= 0 ) {
191                // get default size if passed target size is <= 0
192                Rectangle rect = calculateOriginalSize();
193                xAxis = rect.width;
194                yAxis = rect.height;
195            }
196            BufferedImage bi = null;
197            if ( image != null ) {
198                if ( xAxis == image.getWidth() && yAxis == image.getHeight() ) {
199                    bi = image;
200                } else {
201                    // it's a simple ImageGridCoverage just made up of one image
202                    ParameterBlock pb = new ParameterBlock();
203                    pb.addSource( image );
204                    pb.add( xAxis / (float) image.getWidth() ); // The xScale
205                    pb.add( yAxis / (float) image.getHeight() ); // The yScale
206                    pb.add( 0.0F ); // The x translation
207                    pb.add( 0.0F ); // The y translation
208                    Interpolation interpolation = new InterpolationNearest();
209                    pb.add( interpolation ); // The interpolation
210                    // Create the scale operation
211                    RenderedOp ro = JAI.create( "scale", pb, null );
212                    bi = ro.getAsBufferedImage();
213                }
214            } else {
215                String natFrm = coverageOffering.getSupportedFormats().getNativeFormat().getCode();
216                if ( "jpg".equalsIgnoreCase( natFrm ) || "jpeg".equalsIgnoreCase( natFrm )
217                     || "bmp".equalsIgnoreCase( natFrm ) ) {
218                    bi = new BufferedImage( xAxis, yAxis, BufferedImage.TYPE_INT_RGB );
219                } else {
220                    bi = new BufferedImage( xAxis, yAxis, BufferedImage.TYPE_INT_ARGB );
221                }
222                // it's a complex ImageGridCoverage made up of different
223                // source coverages
224                if ( sources == null || sources.length == 0 ) {
225                    return bi;
226                }
227    
228                for ( int i = 0; i < sources.length; i++ ) {
229                    PT_Envelope env = sources[i].getEnvelope();
230                    Envelope sourceEnv = GeometryFactory.createEnvelope( env.minCP.ord[0], env.minCP.ord[1],
231                                                                         env.maxCP.ord[0], env.maxCP.ord[1], null );
232                    env = this.getEnvelope();
233                    Envelope targetEnv = GeometryFactory.createEnvelope( env.minCP.ord[0], env.minCP.ord[1],
234                                                                         env.maxCP.ord[0], env.maxCP.ord[1], null );
235    
236                    BufferedImage sourceImg = ( (ImageGridCoverage) sources[i] ).getAsImage( -1, -1 );
237                    bi = paintImage( bi, targetEnv, sourceImg, sourceEnv );
238                }
239            }
240    
241            return bi;
242        }
243    
244        /**
245         * calculates the original size of a gridcoverage based on its resolution and the envelope(s) of
246         * its source(s).
247         * 
248         * @return
249         */
250        private Rectangle calculateOriginalSize() {
251            if ( image != null ) {
252                return new Rectangle( image.getWidth(), image.getHeight() );
253            }
254            BufferedImage bi = ( (ImageGridCoverage) sources[0] ).getAsImage( -1, -1 );
255            PT_Envelope env = sources[0].getEnvelope();
256            double dx = ( env.maxCP.ord[0] - env.minCP.ord[0] ) / bi.getWidth();
257            double dy = ( env.maxCP.ord[1] - env.minCP.ord[1] ) / bi.getHeight();
258            env = this.getEnvelope();
259            int w = (int) Math.round( ( env.maxCP.ord[0] - env.minCP.ord[0] ) / dx );
260            int h = (int) Math.round( ( env.maxCP.ord[1] - env.minCP.ord[1] ) / dy );
261            return new Rectangle( w, h );
262        }
263    
264    }