001    //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_testing/src/org/deegree/io/ecwapi/ECWReader.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2003 by:
006     IDgis bv, Holten, The Netherlands
007     http://www.idgis.nl
008    
009     This library is free software; you can redistribute it and/or
010     modify it under the terms of the GNU Lesser General Public
011     License as published by the Free Software Foundation; either
012     version 2.1 of the License, or (at your option) any later version.
013    
014     This library is distributed in the hope that it will be useful,
015     but WITHOUT ANY WARRANTY; without even the implied warranty of
016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
017     Lesser General Public License for more details.
018    
019     You should have received a copy of the GNU Lesser General Public
020     License along with this library; if not, write to the Free Software
021     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
022    
023     ---------------------------------------------------------------------------*/
024    package org.deegree.io.ecwapi;
025    
026    import java.awt.Graphics;
027    import java.awt.image.BufferedImage;
028    import java.io.File;
029    import java.net.URL;
030    
031    import org.deegree.framework.log.ILogger;
032    import org.deegree.framework.log.LoggerFactory;
033    import org.deegree.model.spatialschema.Envelope;
034    
035    import com.ermapper.ecw.JNCSException;
036    import com.ermapper.ecw.JNCSFile;
037    
038    /**
039     * ECWReader.java
040     * 
041     * @author Herman Assink
042     * @author last edited by: $Author: aschmitz $
043     * @version 1.0 2003-11-06
044     */
045    
046    public class ECWReader {
047    
048        private static final ILogger LOG = LoggerFactory.getLogger( ECWReader.class );
049    
050        private static boolean ECW_USE_CACHE = true;
051    
052        private boolean usedCacheOnOpen = true;
053    
054        private JNCSFile ecwFile;
055    
056        /**
057         * read part from ECW-file which falls within env and return this part dimenions width and height
058         * 
059         * @param fileName
060         *            full pathname of the ECW-file
061         * @throws JNCSException
062         */
063        public ECWReader( String fileName ) throws JNCSException {
064    
065            if ( fileName.toLowerCase().startsWith( "file:/" ) ) {
066                try {
067                    File f = new File( new URL( fileName ).getFile() );
068                    fileName = f.getAbsolutePath();
069                } catch ( Exception e ) {
070                    LOG.logDebug( "Stack trace of eaten exception: ", e );
071                    throw new JNCSException( fileName + " is not a valid URL" );
072                }
073            }
074            LOG.logDebug( "ECWReader: " + fileName );
075    
076            if ( ECW_USE_CACHE ) {
077                this.ecwFile = ECWFileCache.claimAccess( fileName );
078                usedCacheOnOpen = true;
079            } else {
080                this.ecwFile = new JNCSFile( fileName, false );
081                usedCacheOnOpen = false;
082            }
083        }
084    
085        /**
086         * Decide, if to use the cache.
087         * <p>
088         * Default is TRUE.
089         */
090        public static void useECWCache( boolean Use ) {
091            ECW_USE_CACHE = Use;
092        }
093    
094        /**
095         * Free the memory of the image cache
096         */
097        public void close() {
098            if ( usedCacheOnOpen ) {
099                ECWFileCache.releaseFile( ecwFile );
100            } else {
101                ecwFile.close( true );
102            }
103        }
104    
105        /**
106         * retuns the width of the entire image encapsulated in the ECW file
107         * 
108         * @return width of the image
109         */
110        public int getWidth() {
111            return ecwFile.width;
112        }
113    
114        /**
115         * retuns the height of the entire image encapsulated in the ECW file
116         * 
117         * @return height of the image
118         */
119        public int getHeight() {
120            return ecwFile.height;
121        }
122    
123        /**
124         * read part from ECW-file which falls within env and return this part as BufferedImage with dimenions width and
125         * height
126         * 
127         * @param env
128         *            bounding box in world coordinates of requested part
129         * @param width
130         *            width of the returned image
131         * @param height
132         *            height of the returned image
133         */
134        public BufferedImage getBufferedImage( Envelope env, int width, int height )
135                                throws JNCSException {
136    
137            int bandlist[];
138            int line, pRGBArray[] = null;
139    
140            // Setup the view parameters for the ecw file.
141            bandlist = new int[ecwFile.numBands];
142            for ( int i = 0; i < ecwFile.numBands; i++ ) {
143                bandlist[i] = i;
144            }
145    
146            // Check if the envelope is within the area of the ecw-image
147            double dWorldTLXRequest = env.getMin().getX();
148            double dWorldTLYRequest = env.getMax().getY();
149    
150            double dWorldTLX = dWorldTLXRequest;
151            double dWorldTLY = dWorldTLYRequest;
152    
153            LOG.logDebug( "tlx: " + dWorldTLX + " tly: " + dWorldTLY );
154    
155            if ( dWorldTLX < ecwFile.originX )
156                dWorldTLX = ecwFile.originX;
157            if ( dWorldTLY > ecwFile.originY )
158                dWorldTLY = ecwFile.originY;
159    
160            double dWorldBRXRequest = env.getMax().getX();
161            double dWorldBRYRequest = env.getMin().getY();
162    
163            double dWorldBRX = dWorldBRXRequest;
164            double dWorldBRY = dWorldBRYRequest;
165    
166            LOG.logDebug( "brx: " + dWorldBRX + " bry: " + dWorldBRY );
167    
168            if ( dWorldBRX > ( ecwFile.originX + ( ( ecwFile.width - 1 ) * ecwFile.cellIncrementX ) ) ) // Huh?
169                // ECW
170                // does
171                // not
172                // except
173                // the
174                // full
175                // width
176                dWorldBRX = ecwFile.originX + ( ( ecwFile.width - 1 ) * ecwFile.cellIncrementX );
177            if ( dWorldBRY < ( ecwFile.originY + ( ecwFile.height * ecwFile.cellIncrementY ) - ( ecwFile.cellIncrementY / 2 ) ) )
178                dWorldBRY = ecwFile.originY + ( ecwFile.height * ecwFile.cellIncrementY ) - ( ecwFile.cellIncrementY / 2 );
179    
180            // Work out the correct aspect for the setView call.
181            // double dEnvAspect = (dWorldBRX - dWorldTLX) / (dWorldTLY - dWorldBRY);
182            // double dImgAspect = (double) width / (double) height;
183    
184            LOG.logDebug( "tlx: " + dWorldTLX + " tly: " + dWorldTLY );
185            LOG.logDebug( "brx: " + dWorldBRX + " bry: " + dWorldBRY );
186            LOG.logDebug( "width: " + width + " height: " + height );
187    
188            int nDatasetTLX = (int) Math.round( ( dWorldTLX - ecwFile.originX ) / ecwFile.cellIncrementX );
189            int nDatasetTLY = (int) Math.round( ( dWorldTLY - ecwFile.originY ) / ecwFile.cellIncrementY );
190    
191            LOG.logDebug( "ptlx: " + nDatasetTLX + " ptly: " + nDatasetTLY );
192    
193            int nDatasetBRX = (int) Math.round( ( dWorldBRX - ecwFile.originX ) / ecwFile.cellIncrementX );
194            int nDatasetBRY = (int) Math.round( ( dWorldBRY - ecwFile.originY ) / ecwFile.cellIncrementY );
195    
196            LOG.logDebug( "pbrx: " + nDatasetBRX + " pbry: " + nDatasetBRY );
197    
198            if ( nDatasetBRX > ( ecwFile.width - 1 ) )
199                nDatasetBRX = ecwFile.width - 1;
200            if ( nDatasetBRY > ( ecwFile.height - 1 ) )
201                nDatasetBRY = ecwFile.height - 1;
202    
203            LOG.logDebug( "pbrx: " + nDatasetBRX + " pbry: " + nDatasetBRY );
204    
205            // Check for supersampling
206            int viewWidth = width;
207            int viewHeight = height;
208            if ( ( nDatasetBRX - nDatasetTLX ) < viewWidth || ( nDatasetBRY - nDatasetTLY ) < viewHeight ) {
209                viewWidth = nDatasetBRX - nDatasetTLX;
210                viewHeight = nDatasetBRY - nDatasetTLY;
211            }
212    
213            double requestWidth = dWorldBRXRequest - dWorldTLXRequest;
214            double worldWidth = dWorldBRX - dWorldTLX;
215            if ( requestWidth > worldWidth ) {
216                viewWidth *= worldWidth / requestWidth;
217            }
218    
219            double requestHeight = dWorldTLYRequest - dWorldBRYRequest;
220            double worldHeight = dWorldTLY - dWorldBRY;
221            if ( requestHeight > worldHeight ) {
222                viewHeight *= worldHeight / requestHeight;
223            }
224    
225            if ( viewWidth == 0 )
226                viewWidth = 1;
227            if ( viewHeight == 0 )
228                viewHeight = 1;
229    
230            LOG.logDebug( "Width: " + width + " Height: " + height );
231            LOG.logDebug( "viewWidth: " + viewWidth + " viewHeight: " + viewHeight );
232    
233            // Create an image of the ecw file.
234            BufferedImage ecwImage = new BufferedImage( viewWidth, viewHeight, BufferedImage.TYPE_INT_RGB );
235            pRGBArray = new int[width];
236    
237            // Set the view
238            ecwFile.setView( ecwFile.numBands, bandlist, nDatasetTLX, nDatasetTLY, nDatasetBRX, nDatasetBRY, viewWidth,
239                             viewHeight );
240    
241            // Read the scan lines
242            for ( line = 0; line < viewHeight; line++ ) {
243                ecwFile.readLineRGBA( pRGBArray );
244                ecwImage.setRGB( 0, line, viewWidth, 1, pRGBArray, 0, viewWidth );
245            }
246    
247            if ( width != viewWidth || height != viewHeight ) {
248                LOG.logDebug( "create larger image" );
249    
250                int destX = 0, destY = 0, destWidth = width, destHeight = height;
251    
252                if ( requestWidth > worldWidth ) {
253                    double pixWidth = requestWidth / width;
254    
255                    destX = (int) ( ( dWorldTLX - dWorldTLXRequest ) / pixWidth + 0.5 );
256                    destWidth = (int) ( ( dWorldBRX - dWorldTLXRequest ) / pixWidth + 0.5 );
257                }
258    
259                if ( requestHeight > worldHeight ) {
260                    double pixHeight = requestHeight / height;
261    
262                    destY = (int) ( ( dWorldTLYRequest - dWorldTLY ) / pixHeight + 0.5 );
263                    destHeight = (int) ( ( dWorldTLYRequest - dWorldBRY ) / pixHeight + 0.5 );
264                }
265    
266                BufferedImage enlargedImg = new BufferedImage( width, height, BufferedImage.TYPE_INT_RGB );
267                Graphics g = enlargedImg.getGraphics();
268                g.drawImage( ecwImage, destX, destY, destWidth, destHeight, 0, 0, viewWidth, viewHeight, null );
269                ecwImage = enlargedImg;
270                g.dispose();
271            }
272    
273            return ecwImage;
274    
275        }
276    }