001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_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: mschneider $
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
058         * height
059         * 
060         * @param fileName
061         *            full pathname of the ECW-file
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                    new JNCSException( fileName + " is not a valid URL" );
071                }
072            }
073            LOG.logDebug( "ECWReader: " + fileName );
074    
075            if ( ECW_USE_CACHE ) {
076                this.ecwFile = ECWFileCache.claimAccess( fileName );
077                usedCacheOnOpen = true;
078            } else {
079                this.ecwFile = new JNCSFile( fileName, false );
080                usedCacheOnOpen = false;
081            }
082        }
083    
084        /**
085         * Decide, if to use the cache.
086         * <p>
087         * Default is TRUE.
088         */
089        public static void useECWCache( boolean Use ) {
090            ECW_USE_CACHE = Use;
091        }
092    
093        /**
094         * Free the memory of the image cache
095         */
096        public void close() {
097            if ( usedCacheOnOpen ) {
098                ECWFileCache.releaseFile( ecwFile );
099            } else {
100                ecwFile.close( true );
101            }
102        }
103    
104        /**
105         * retuns the width of the entire image encapsulated in the ECW file
106         * 
107         * @return width of the image
108         */
109        public int getWidth() {
110            return ecwFile.width;
111        }
112    
113        /**
114         * retuns the height of the entire image encapsulated in the ECW file
115         * 
116         * @return height of the image
117         */
118        public int getHeight() {
119            return ecwFile.height;
120        }
121    
122        /**
123         * read part from ECW-file which falls within env and return this part as BufferedImage with
124         * dimenions width and height
125         * 
126         * @param env
127         *            bounding box in world coordinates of requested part
128         * @param width
129         *            width of the returned image
130         * @param height
131         *            height of the returned image
132         */
133        public BufferedImage getBufferedImage( Envelope env, int width, int height )
134                                throws JNCSException {
135    
136            int bandlist[];
137            int line, pRGBArray[] = null;
138    
139            // Setup the view parameters for the ecw file.
140            bandlist = new int[ecwFile.numBands];
141            for ( int i = 0; i < ecwFile.numBands; i++ ) {
142                bandlist[i] = i;
143            }
144    
145            // Check if the envelope is within the area of the ecw-image
146            double dWorldTLXRequest = env.getMin().getX();
147            double dWorldTLYRequest = env.getMax().getY();
148            
149            double dWorldTLX = dWorldTLXRequest;
150            double dWorldTLY = dWorldTLYRequest;
151    
152            LOG.logDebug( "tlx: " + dWorldTLX + " tly: " + dWorldTLY );
153    
154            if ( dWorldTLX < ecwFile.originX )
155                dWorldTLX = ecwFile.originX;
156            if ( dWorldTLY > ecwFile.originY )
157                dWorldTLY = ecwFile.originY;
158            
159            double dWorldBRXRequest = env.getMax().getX();
160            double dWorldBRYRequest = env.getMin().getY();
161            
162            double dWorldBRX = dWorldBRXRequest;
163            double dWorldBRY = dWorldBRYRequest;
164    
165            LOG.logDebug( "brx: " + dWorldBRX + " bry: " + dWorldBRY );
166    
167            if ( dWorldBRX > ( ecwFile.originX + ( ( ecwFile.width - 1 ) * ecwFile.cellIncrementX ) ) ) // Huh?
168                // ECW
169                // does
170                // not
171                // except
172                // the
173                // full
174                // width
175                dWorldBRX = ecwFile.originX + ( ( ecwFile.width - 1 ) * ecwFile.cellIncrementX );
176            if ( dWorldBRY < ( ecwFile.originY + ( ecwFile.height * ecwFile.cellIncrementY ) - ( ecwFile.cellIncrementY / 2 ) ) )
177                dWorldBRY = ecwFile.originY + ( ecwFile.height * ecwFile.cellIncrementY ) - ( ecwFile.cellIncrementY / 2 );
178    
179            // Work out the correct aspect for the setView call.
180            // double dEnvAspect = (dWorldBRX - dWorldTLX) / (dWorldTLY - dWorldBRY);
181            // double dImgAspect = (double) width / (double) height;
182    
183            LOG.logDebug( "tlx: " + dWorldTLX + " tly: " + dWorldTLY );
184            LOG.logDebug( "brx: " + dWorldBRX + " bry: " + dWorldBRY );
185            LOG.logDebug( "width: " + width + " height: " + height );
186    
187            int nDatasetTLX = (int) Math.round( ( dWorldTLX - ecwFile.originX ) / ecwFile.cellIncrementX );
188            int nDatasetTLY = (int) Math.round( ( dWorldTLY - ecwFile.originY ) / ecwFile.cellIncrementY );
189    
190            LOG.logDebug( "ptlx: " + nDatasetTLX + " ptly: " + nDatasetTLY );
191    
192            int nDatasetBRX = (int) Math.round( ( dWorldBRX - ecwFile.originX ) / ecwFile.cellIncrementX );
193            int nDatasetBRY = (int) Math.round( ( dWorldBRY - ecwFile.originY ) / ecwFile.cellIncrementY );
194    
195            LOG.logDebug( "pbrx: " + nDatasetBRX + " pbry: " + nDatasetBRY );
196    
197            if ( nDatasetBRX > ( ecwFile.width - 1 ) )
198                nDatasetBRX = ecwFile.width - 1;
199            if ( nDatasetBRY > ( ecwFile.height - 1 ) )
200                nDatasetBRY = ecwFile.height - 1;
201    
202            LOG.logDebug( "pbrx: " + nDatasetBRX + " pbry: " + nDatasetBRY );
203    
204            // Check for supersampling
205            int viewWidth = width;
206            int viewHeight = height;
207            if ( ( nDatasetBRX - nDatasetTLX ) < viewWidth || ( nDatasetBRY - nDatasetTLY ) < viewHeight ) {
208                viewWidth = nDatasetBRX - nDatasetTLX;
209                viewHeight = nDatasetBRY - nDatasetTLY;
210            }
211            
212            double requestWidth = dWorldBRXRequest - dWorldTLXRequest;
213            double worldWidth = dWorldBRX - dWorldTLX;
214            if ( requestWidth > worldWidth) {
215                viewWidth *= worldWidth / requestWidth;            
216            }
217            
218            double requestHeight = dWorldTLYRequest - dWorldBRYRequest;
219            double worldHeight = dWorldTLY - dWorldBRY;
220            if ( requestHeight > worldHeight) {
221                viewHeight *= worldHeight / requestHeight;            
222            }
223            
224            if ( viewWidth == 0 )
225                viewWidth = 1;
226            if ( viewHeight == 0 )
227                viewHeight = 1;
228    
229            LOG.logDebug( "Width: " + width + " Height: " + height );
230            LOG.logDebug( "viewWidth: " + viewWidth + " viewHeight: " + viewHeight );
231    
232            // Create an image of the ecw file.
233            BufferedImage ecwImage = new BufferedImage( viewWidth, viewHeight, BufferedImage.TYPE_INT_RGB );
234            pRGBArray = new int[width];
235    
236            // Set the view
237            ecwFile.setView( ecwFile.numBands, bandlist, nDatasetTLX, nDatasetTLY, nDatasetBRX, nDatasetBRY, viewWidth,
238                             viewHeight );
239    
240            // Read the scan lines
241            for ( line = 0; line < viewHeight; line++ ) {
242                ecwFile.readLineRGBA( pRGBArray );
243                ecwImage.setRGB( 0, line, viewWidth, 1, pRGBArray, 0, viewWidth );
244            }
245    
246            if ( width != viewWidth || height != viewHeight ) {
247                LOG.logDebug( "create larger image" );
248                
249                int destX = 0,
250                    destY = 0,
251                    destWidth = width,
252                    destHeight = height;
253                
254                if ( requestWidth > worldWidth) {
255                    double pixWidth = requestWidth / width;
256                    
257                    destX = (int)( ( dWorldTLX - dWorldTLXRequest ) / pixWidth + 0.5 );
258                    destWidth = (int)( ( dWorldBRX - dWorldTLXRequest ) / pixWidth + 0.5 );
259                }
260    
261                
262                if ( requestHeight > worldHeight) {
263                    double pixHeight = requestHeight / height;
264                    
265                    destY = (int)( ( dWorldTLYRequest - dWorldTLY ) / pixHeight + 0.5 );
266                    destHeight = (int)( ( dWorldTLYRequest - dWorldBRY ) / pixHeight + 0.5 );
267                }
268                
269                BufferedImage enlargedImg = new BufferedImage( width, height, BufferedImage.TYPE_INT_RGB );
270                Graphics g = enlargedImg.getGraphics();
271                g.drawImage( ecwImage, destX, destY, destWidth, destHeight, 0, 0, viewWidth, viewHeight, null );
272                ecwImage = enlargedImg;
273                g.dispose();
274            }
275    
276            return ecwImage;
277    
278        }
279    }