Statistics
| Revision:

svn-gvsig-desktop / tags / v1_0_2_Build_910 / libraries / libCq CMS for java.old / src / org / cresques / io / EcwFile.java @ 11275

History | View | Annotate | Download (43.8 KB)

1
/*
2
 * Cresques Mapping Suite. Graphic Library for constructing mapping applications.
3
 *
4
 * Copyright (C) 2004-5.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
19
 *
20
 * For more information, contact:
21
 *
22
 * cresques@gmail.com
23
 */
24
package org.cresques.io;
25

    
26
import java.awt.Dimension;
27
import java.awt.Image;
28
import java.awt.Point;
29
import java.awt.image.BufferedImage;
30
import java.awt.image.PixelGrabber;
31
import java.io.File;
32

    
33
import org.cresques.cts.ICoordTrans;
34
import org.cresques.cts.IProjection;
35
import org.cresques.px.Extent;
36

    
37
import com.ermapper.ecw.JNCSException;
38
import com.ermapper.ecw.JNCSFile;
39
import com.ermapper.ecw.JNCSFileNotOpenException;
40
import com.ermapper.ecw.JNCSInvalidSetViewException;
41
import com.ermapper.ecw.JNCSProgressiveUpdate;
42
import com.ermapper.util.JNCSDatasetPoint;
43
import com.ermapper.util.JNCSWorldPoint;
44

    
45

    
46
/**
47
 * Soporte para los ficheros .ecw de ErMapper.
48
 * <br>
49
 * NOTA: El SDK que ermapper ha puesto a disposici?n del p?blico en java
50
 * es una versi?n 2.45, de 19/11/2001. Est? implementada usando JNI que
51
 * se apoya en tres librer?as din?micas (dll), y presenta deficiencias
52
 * muy graves a la hora de acceder a la informaci?n. Hasta el momento
53
 * hemos detectado 3 de ellas:<BR>
54
 *     1?.- No soporta ampliaciones superiores a 1:1. si se intenta acceder
55
 * a un ecw con un zoom mayor da una excepci?n del tipo
56
 * com.ermapper.ecw.JNCSInvalidSetViewException, que de no ser tenida encuenta
57
 * acaba tirando abajo la m?quina virtual de java.<BR>
58
 *     2?.- La longitud m?xima de l?nea que adminte el m?todo readLineRGBA es
59
 * de unos 2500 pixeles, lo que hace el uso para la impresi?n en formatos
60
 * superiorea a A4 a 300 ppp o m?s inviable.<BR>
61
 *     3?.- La actualizaci?n progresiva usando el interface JNCSProgressiveUpdate
62
 * con el JNCSFile hace que el equipo genere un error severo y se apague. Este
63
 * error imposibilita esta t?cnica de acceso a ECW.<BR>
64
 * <br>
65
 * Para saltarnos la limitaci?n del bug#1 pedimos la ventana correspondiente al zoom 1:1 para
66
 * el view que nos han puesto, y la resizeamos al tama?o que nos pide el usuario.<br>
67
 * Como consecuencia del bug#2, para tama?os de ventana muy grandes (los necesarios
68
 * para imprimir a m?s de A4 a 300DPI), hay que hacer varias llamadas al fichero con
69
 * varios marcos contiguos, y los devolvemos 'pegados' en una sola imagen (esto se
70
 * realiza de manera transparente para el usuario dentro de la llamada a updateImage.<br>
71
 *
72
 * @author "Luis W. Sevilla" <sevilla_lui@gva.es>
73
 */
74
public class EcwFile extends GeoRasterFile implements JNCSProgressiveUpdate {
75
    //Lleva la cuenta del n?mero de actualizaciones que se hace de una imagen que corresponde con el 
76
    //n?mero de bandas que tiene. Esto es necesario ya que si una imagen tiene el mustResize a
77
    //true solo debe llamar a la funci?n resizeImage al actualizar la ?ltima banda, sino al hacer
78
    //un zoom menor que 1:1 se veria mal
79
    private static int nUpdate = 0;
80
    private JNCSFile file = null;
81
    private boolean bErrorOnOpen = false;
82
    private String errorMessage = null;
83
    private boolean multifile = false;
84
    private Extent v = null;
85
   
86

    
87
    // Ultimo porcentaje de refresco. Se carga en el update y se
88
    // actualiza en el refreshUpdate
89
    private int lastRefreshPercent = 0;
90

    
91
    public EcwFile(IProjection proj, String fName) {
92
        super(proj, null);
93
        fName = DataSource.normalize(fName);
94
        super.setName(fName);
95
        extent = new Extent();
96

    
97
        try {
98
                
99
                if (!new File(fName).exists() && !fName.startsWith("ecwp:")){
100
                        System.err.println("No se puede abrir el archivo");
101
                        return;
102
                }
103
                
104
            file = new JNCSFile(fName, false);
105
                load();
106
            //readGeoInfo(fName);
107
            bandCount = file.numBands;
108

    
109
            if ( bandCount > 2) {
110
                    setBand(RED_BAND,   0);
111
                    setBand(GREEN_BAND, 1);
112
                    setBand(BLUE_BAND,  2);
113
            } else
114
                    setBand(RED_BAND|GREEN_BAND|BLUE_BAND, 0);
115
        } catch (Exception e) {
116
            bErrorOnOpen = true;
117
            errorMessage = e.getMessage();
118
            System.err.println(errorMessage);
119
            e.printStackTrace();
120
        }
121
    }
122

    
123
    /**
124
     * Carga un ECW.
125
     *
126
     * @param fname
127
     */
128
    public GeoFile load() {
129
        double minX;
130
        double minY;
131
        double maxX;
132
        double maxY;
133

    
134
        if(file.cellIncrementY > 0)
135
                file.cellIncrementY = -file.cellIncrementY;
136
        
137
        minX = file.originX;
138
        maxY = file.originY;
139
        maxX = file.originX +
140
               ((double) (file.width - 1) * file.cellIncrementX);
141
        minY = file.originY +
142
               ((double) (file.height - 1) * file.cellIncrementY);
143
        
144
        extent = new Extent(minX, minY, maxX, maxY);
145
        requestExtent = extent;
146
        return this;
147
    }
148

    
149
    public void close() {
150
            if(file != null){
151
                    file.close(true);
152
                    file = null;
153
            }
154
    }
155

    
156
    /**
157
     * Devuelve el ancho de la imagen
158
     */
159
    public int getWidth() {
160
        return file.width;
161
    }
162

    
163
    /**
164
     * Devuelve el alto de la imagen
165
     */
166
    public int getHeight() {
167
        return file.height;
168
    }
169

    
170
    /**
171
     *
172
     */
173
    public void setMultifile(boolean mult) {
174
        this.multifile = mult;
175
    }
176

    
177
    public void setView(Extent e) {
178
            //Aplicamos la transformaci?n a la vista en caso de que haya un fichero .rmf 
179
            /*                     
180
            if(file.cellIncrementY > 0)
181
                file.cellIncrementY = -file.cellIncrementY;
182
            if(minX < file.originX)
183
                    minX = file.originX;
184
            if(maxY > file.originY)
185
                    maxY = file.originY;
186
            if(maxX > (file.originX + ((double) (file.width - 1) * file.cellIncrementX)))
187
                    maxX = file.originX + ((double) (file.width - 1) * file.cellIncrementX);
188
            if(minY < file.originY + ((double) (file.height - 1) * file.cellIncrementY))
189
                    minY = file.originY + ((double) (file.height - 1) * file.cellIncrementY);
190
            
191
                Extent transformView = new Extent(        minX, minY, maxX, maxY );*/
192
        v = new Extent(e);
193
    }
194

    
195
    public Extent getView() {
196
        return v;
197
    }
198
    
199
    private void setFileView(int numBands, int [] bandList, ChunkFrame f)
200
            throws JNCSFileNotOpenException, JNCSInvalidSetViewException {
201
        file.setView(file.numBands, bandList, f.v.minX(), f.v.maxY(), f.v.maxX(), f.v.minY(), f.width, f.height);
202
    }
203

    
204
    /**
205
     * Obtiene un trozo de imagen (determinado por la vista y los par?metros.
206
     *
207
     * @param width
208
     * @param height
209
     */
210
    public synchronized Image updateImage(int width, int height, ICoordTrans rp) {
211
        // TODO reproyectar para devolver el trozo de imagen pedida sobre ...
212
        // la proyecci?n de destino.
213
        int line = 0;
214
        boolean mustResize = false;
215
        Dimension fullSize = null;
216
        Image ecwImage = null;
217

    
218
        if (file == null) {
219
            return ecwImage;
220
        }
221

    
222
        try {
223
            int[] bandlist;
224
            int[] bandListTriband;
225
            int[] pRGBArray = null;
226

    
227
            if(mustVerifySize()){
228
            // Work out the correct aspect for the setView call.
229
                    double dFileAspect = (double) v.width() / (double) v.height();
230
                    double dWindowAspect = (double) width / (double) height;
231
        
232
                    if (dFileAspect > dWindowAspect) {
233
                        height = (int) ((double) width / dFileAspect);
234
                    } else {
235
                        width = (int) ((double) height * dFileAspect);
236
                    }
237
            }
238
            fullSize = new Dimension(width, height);
239

    
240
            //System.out.println("fullSize = ("+width+","+height+")");
241
            // Peta en los peque?os ... arreglar antes de meter del todo
242
            ChunkFrame[] frames = ChunkFrame.computeFrames(file, v, fullSize, extent);
243

    
244
            if (frames.length == 1) {
245
                width = frames[0].width;
246
                height = frames[0].height;
247

    
248
                if (width <= 0) {
249
                    width = 1;
250
                }
251

    
252
                if (height <= 0) {
253
                    height = 1;
254
                }
255
            }
256

    
257
            /*                        JNCSDatasetPoint ptMin = file.convertWorldToDataset(v.minX(), v.minY());
258
                                    JNCSDatasetPoint ptMax = file.convertWorldToDataset(v.maxX(), v.maxY());
259
                                    System.out.println("Dataset coords Width = "+(ptMax.x-ptMin.x)+", px width ="+width);
260
                                    // BEGIN Cambiando para soportar e < 1:1
261
                                    // TODO Mejorarlo para que los PAN con un zoom muy grande sean correctos
262
                                    if ((ptMax.x-ptMin.x)<width) {
263
                                            width = ptMax.x-ptMin.x;
264
                                            height = ptMin.y-ptMax.y;
265
                                            System.out.println("Size=("+width+","+height+")");
266
                                            mustResize = true;
267
                                    }*/
268

    
269
            // Create an image of the ecw file.
270
            if (doTransparency) {
271
                ecwImage = new BufferedImage(width, height,
272
                                             BufferedImage.TYPE_INT_ARGB);
273
            } else {
274
                ecwImage = new BufferedImage(width, height,
275
                                             BufferedImage.TYPE_INT_RGB);
276
            }
277

    
278
            pRGBArray = new int[width];
279

    
280
            // Setup the view parameters for the ecw file.
281
            bandlist = new int[bandCount];
282
            bandListTriband = new int[bandCount];
283

    
284
            if (bandCount > 2) {
285
                bandlist[0] = getBand(RED_BAND);
286
                bandlist[1] = getBand(GREEN_BAND);
287
                bandlist[2] = getBand(BLUE_BAND);
288

    
289
                if (bandCount > 3) {
290
                    for (int i = 3; i < bandCount; i++) {
291
                        bandlist[i] = 0;
292
                    }
293
                }
294
            } else {
295
                for (int i = 0; i < bandCount; i++) {
296
                    bandlist[i] = i;
297
                }
298
            }
299

    
300
            if (bandCount == 3) {
301
                bandListTriband[0] = 0;
302
                bandListTriband[1] = 1;
303
                bandListTriband[2] = 2;
304
            }
305

    
306
            for (int nChunk = 0; nChunk < frames.length; nChunk++) {
307
                ChunkFrame f = frames[nChunk];
308

    
309
                // Set the view                        
310
                if (bandCount != 3) {
311
                    setFileView(file.numBands, bandlist, f);
312
                } else {
313
                    setFileView(file.numBands, bandListTriband, f);
314
                }
315

    
316
                /* 
317
                 * Esta peli es porque el Ecw no intercambia las bandas con lo que me toca hacerlo
318
                 * a mano. Primero detectamos si se ha alterado el orden de las mismas. Si es as?
319
                 * calculamos mascaras y desplazamientos y hacemos una copia en pRGBArrayCopy
320
                 * con las bandas alteradas de orden
321
                 */
322
                int[] pRGBArrayCopy = null;
323
                int[] mascara = new int[3];
324
                int[] shl = new int[3];
325
                int[] shr = new int[3];
326
                boolean order = true;
327

    
328
                if (bandCount == 3) {
329
                    for (int i = 0; i < bandCount; i++)
330
                        if (bandlist[i] != i) {
331
                            order = false;
332
                        }
333

    
334
                    if (!order) {
335
                        for (int i = 0; i < bandCount; i++) {
336
                            switch (bandlist[i]) {
337
                            case 0:
338
                                mascara[i] = 0x00ff0000;
339
                                break;
340
                            case 1:
341
                                mascara[i] = 0x0000ff00;
342
                                break;
343
                            case 2:
344
                                mascara[i] = 0x000000ff;
345
                                break;
346
                            }
347
                            if ((i == 1) && (bandlist[i] == 0)) 
348
                                shr[i] = 8;
349
                            if ((i == 2) && (bandlist[i] == 0)) 
350
                                shr[i] = 16;
351
                            if ((i == 0) && (bandlist[i] == 1)) 
352
                                shl[i] = 8;
353
                            if ((i == 2) && (bandlist[i] == 1))
354
                                shr[i] = 8;
355
                            if ((i == 0) && (bandlist[i] == 2)) 
356
                                shl[i] = 16;
357
                            if ((i == 1) && (bandlist[i] == 2))
358
                                shl[i] = 8;
359
                        }
360
                    }
361
                }
362

    
363
                // Read the scan lines
364
                for (line = 0; line < f.height; line++) {
365
                    file.readLineRGBA(pRGBArray);
366

    
367
                    if ((bandCount == 3) && !order) {
368
                        pRGBArrayCopy = new int[pRGBArray.length];
369

    
370
                        for (int i = 0; i < pRGBArray.length; i++) {
371
                            pRGBArrayCopy[i] = (pRGBArray[i] & 0xff000000) +
372
                                               (((pRGBArray[i] & mascara[2]) << shl[2]) >> shr[2]) +
373
                                               (((pRGBArray[i] & mascara[1]) << shl[1]) >> shr[1]) +
374
                                               (((pRGBArray[i] & mascara[0]) << shl[0]) >> shr[0]);
375
                        }
376

    
377
                        pRGBArray = pRGBArrayCopy;
378
                    }
379

    
380
                    // Prueba de sustituci?n de color transparente
381
                    if (doTransparency) {
382
                        if (line == 0) {
383
                            tFilter.debug = true;
384
                        }
385

    
386
                        tFilter.filterLine(pRGBArray);
387
                        tFilter.debug = false;
388
                    }
389

    
390
                    ((BufferedImage) ecwImage).setRGB(f.pos.x, f.pos.y + line,
391
                                                      f.width, 1, pRGBArray, 0,
392
                                                      f.width);
393
                }
394
            }
395

    
396
            if (frames[0].mustResize) {
397
                //System.out.println("resize "+fullSize);
398
                return resizeImage(fullSize, ecwImage);
399
            }
400

    
401
            /*
402
             * La excepci?n atrapada es la de 'zoom > 1:1 no valido'
403
            } catch (com.ermapper.ecw.JNCSInvalidSetViewException e) {
404
                    System.err.println(errorMessage);
405
                    e.printStackTrace(); */
406
        } catch (com.ermapper.ecw.JNCSException e) { //java.lang.ArrayIndexOutOfBoundsException:
407
            bErrorOnOpen = true;
408
            System.err.println("EcwFile JNCS Error en la l?nea " + line + "/" +
409
                               height);
410
            System.err.println(e.getMessage());
411
            e.printStackTrace();
412
        } catch (java.lang.ArrayIndexOutOfBoundsException e) { //:
413
            bErrorOnOpen = true;
414
            System.err.println("EcwFile ArrayIndex Error en la l?nea " + line +
415
                               "/" + height);
416
            System.err.println(e.getMessage());
417
            e.printStackTrace();
418
        } catch (Exception e) {
419
            bErrorOnOpen = true;
420
            errorMessage = e.getMessage();
421

    
422
            //                        g.drawString(errorMessage, 0, 50);
423
            System.err.println(errorMessage);
424
            e.printStackTrace();
425
        }
426

    
427
        lastRefreshPercent = file.getPercentComplete();
428
        System.out.println("Leido al " + lastRefreshPercent + " %.");
429

    
430
        return ecwImage;
431
    }
432

    
433
    /**
434
     * Redimensionado de imagen
435
     * La funci?n getScaledInstance nos devuelve un tipo image que no sirve por lo que
436
     * habr? que crear  buffImg como BufferedImage y copiar los datos devueltos por esta
437
     * funci?n a este que es el que ser? devuelto por la funci?n
438
     * @param sz
439
     * @param image        Image de entrada
440
     * @return        Imagen reescalada
441
     */
442
    private Image resizeImage(Dimension sz, Image image) {
443
        Image buffImg = null;
444
        Image img = image.getScaledInstance((int) sz.getWidth(),
445
                                            (int) sz.getHeight(),
446
                                            Image.SCALE_SMOOTH);
447

    
448
        //Todo este pollo es para copiar el tipo image devuelto a BufferedImage
449
        buffImg = new BufferedImage(img.getWidth(null), img.getHeight(null),
450
                                    BufferedImage.TYPE_INT_ARGB);
451

    
452
        int[] pixels = new int[img.getWidth(null) * img.getHeight(null)];
453
        PixelGrabber pg = new PixelGrabber(img, 0, 0, img.getWidth(null),
454
                                           img.getHeight(null), pixels, 0,
455
                                           img.getWidth(null));
456

    
457
        try {
458
            pg.grabPixels();
459
        } catch (InterruptedException e) {
460
            e.printStackTrace();
461
        }
462

    
463
        for (int j = 0; j < buffImg.getHeight(null); j++) {
464
            for (int i = 0; i < buffImg.getWidth(null); i++) {
465
                ((BufferedImage) buffImg).setRGB(i, j,
466
                                                 pixels[(j * buffImg.getWidth(null)) +
467
                                                 i]);
468
            }
469
        }
470

    
471
        return buffImg;
472
    }
473

    
474
    /**
475
     * Reproyecta el raster.
476
     */
477
    public void reProject(ICoordTrans rp) {
478
        // TODO metodo reProject pendiente de implementar
479
    }
480

    
481
    /**
482
     * Soporte para actualizaci?n de la imagen
483
     * @see com.ermapper.ecw.JNCSProgressiveUpdate#refreshUpdate(int, int, double, double, double, double)
484
     */
485
    public void refreshUpdate(int nWidth, int nHeight, double dWorldTLX,
486
                              double dWorldTLY, double dWorldBRX,
487
                              double dWorldBRY) {
488
        int completado = file.getPercentComplete();
489
        System.out.println("EcwFile: se actualiza 1: " + completado +
490
                           " % completado");
491

    
492
        if ((updatable != null) && (lastRefreshPercent < 100)) {
493
            if (((completado - lastRefreshPercent) > 25) ||
494
                    (completado == 100)) {
495
                lastRefreshPercent = file.getPercentComplete();
496
                updatable.repaint();
497
            }
498
        }
499
    }
500

    
501
    public void refreshUpdate(int nWidth, int nHeight, int dDatasetTLX,
502
                              int dDatasetTLY, int dDatasetBRX, int dDatasetBRY) {
503
        System.out.println("EcwFile: se actualiza 2");
504
    }
505

    
506
    /**
507
     *  Esta funci?n es porque el Ecw no intercambia las bandas con lo que me toca hacerlo
508
     * a mano. Primero detectamos si se ha alterado el orden de las mismas. Si es as?
509
     * calculamos mascaras y desplazamientos y hacemos una copia en pRGBArrayCopy
510
     * con las bandas alteradas de orden
511
     * @param bandList        lista de bandas
512
     * @param mask mascara
513
     * @param shl desplazamiento izquierda
514
     * @param shr desplazamiento derecha
515
     */
516
    private boolean calcMaskAndShift(int[] bandList, int[] mask, int[] shl,
517
                                     int[] shr) {
518
        boolean order = true;
519

    
520
        if (bandCount == 3) {
521
            for (int i = 0; i < bandCount; i++)
522
                if (bandList[i] != i) {
523
                    order = false;
524
                }
525

    
526
            if (!order) {
527
                for (int i = 0; i < bandCount; i++) {
528
                    switch (bandList[i]) {
529
                    case 0:
530
                        mask[i] = 0x00ff0000;
531
                        break;
532
                    case 1:
533
                        mask[i] = 0x0000ff00;
534
                        break;
535
                    case 2:
536
                        mask[i] = 0x000000ff;
537
                        break;
538
                    }
539
                    
540
                    if ((i == 1) && (bandList[i] == 0))
541
                        shr[i] = 8;
542
                    if ((i == 2) && (bandList[i] == 0)) 
543
                        shr[i] = 16;
544
                    if ((i == 0) && (bandList[i] == 1))
545
                        shl[i] = 8;
546
                    if ((i == 2) && (bandList[i] == 1))
547
                        shr[i] = 8;
548
                    if ((i == 0) && (bandList[i] == 2))
549
                        shl[i] = 16;
550
                    if ((i == 1) && (bandList[i] == 2))
551
                        shl[i] = 8;
552
                }
553
            }
554
        }
555

    
556
        return order;
557
    }
558

    
559
    /**
560
     * Intercambio de bandas para ecw manual. Se le pasa el array de bytes que se desea intercambiar
561
     * la mascara y desplazamientos previamente calculados con calcMaskAndShift
562
     * @param order        true si el orden de las bandas no est? alterado y false si lo est?
563
     * @param pRGBArray array de
564
     * @param mascara
565
     * @param shl desplazamiento a izquierda
566
     * @param shr desplazamiento a derecha
567
     * @return array con las bandas cambiadas
568
     */
569
    private int[] changeBands(boolean order, int[] pRGBArray, int[] mascara,
570
                              int[] shl, int[] shr) {
571
        if ((bandCount == 3) && !order) {
572
            int[] pRGBArrayCopy = new int[pRGBArray.length];
573

    
574
            for (int i = 0; i < pRGBArray.length; i++) {
575
                pRGBArrayCopy[i] = (pRGBArray[i] & 0xff000000) +
576
                                   (((pRGBArray[i] & mascara[2]) << shl[2]) >> shr[2]) +
577
                                   (((pRGBArray[i] & mascara[1]) << shl[1]) >> shr[1]) +
578
                                   (((pRGBArray[i] & mascara[0]) << shl[0]) >> shr[0]);
579
            }
580

    
581
            return pRGBArrayCopy;
582
        }
583

    
584
        return pRGBArray;
585
    }
586

    
587
    /**
588
     * Asigna al objeto Image los valores con los dato de la imagen contenidos en el
589
     * vector de enteros.
590
     * @param image        imagen con los datos actuales
591
     * @param startX        inicio de la posici?n en X dentro de la imagen
592
     * @param startY        inicio de la posici?n en X dentro de la imagen
593
     * @param w        Ancho de la imagen
594
     * @param h        Alto de la imagen
595
     * @param rgbArray        vector que contiene la banda que se va a sustituir
596
     * @param offset        desplazamiento
597
     * @param scansize        tama?o de imagen recorrida por cada p
598
     */
599
    protected void setRGBLine(BufferedImage image, int startX, int startY,
600
                              int w, int h, int[] rgbArray, int offset,
601
                              int scansize) {
602
        image.setRGB(startX, startY, w, h, rgbArray, offset, scansize);
603
    }
604

    
605
    /**
606
     * Asigna al objeto Image la mezcla entre los valores que ya tiene y los valores
607
     * con los dato de la imagen contenidos en el vector de enteros. De los valores RGB
608
     * que ya contiene se mantienen las bandas que no coinciden con el valor de flags. La
609
     * banda correspondiente a flags es sustituida por los datos del vector.
610
     * @param image        imagen con los datos actuales
611
     * @param startX        inicio de la posici?n en X dentro de la imagen
612
     * @param startY        inicio de la posici?n en X dentro de la imagen
613
     * @param w        Ancho de la imagen
614
     * @param h        Alto de la imagen
615
     * @param rgbArray        vector que contiene la banda que se va a sustituir
616
     * @param offset        desplazamiento
617
     * @param scansize        tama?o de imagen recorrida por cada paso
618
     * @param flags        banda que se va a sustituir (Ctes de GeoRasterFile)
619
     */
620
    protected void setRGBLine(BufferedImage image, int startX, int startY,
621
                              int w, int h, int[] rgbArray, int offset,
622
                              int scansize, int flags) {
623
        int[] line = new int[rgbArray.length];
624
        image.getRGB(startX, startY, w, h, line, offset, scansize);
625

    
626
        if (flags == GeoRasterFile.RED_BAND) {
627
            for (int i = 0; i < line.length; i++)
628
                line[i] = (line[i] & 0x0000ffff) | (rgbArray[i] & 0xffff0000);
629
        } else if (flags == GeoRasterFile.GREEN_BAND) {
630
            for (int i = 0; i < line.length; i++)
631
                line[i] = (line[i] & 0x00ff00ff) | (rgbArray[i] & 0xff00ff00);
632
        } else if (flags == GeoRasterFile.BLUE_BAND) {
633
            for (int i = 0; i < line.length; i++)
634
                line[i] = (line[i] & 0x00ffff00) | (rgbArray[i] & 0xff0000ff);
635
        }
636

    
637
        image.setRGB(startX, startY, w, h, line, offset, scansize);
638
    }
639

    
640
    /**
641
     * Asigna al objeto Image la mezcla entre los valores que ya tiene y los valores
642
     * con los dato de la imagen contenidos en el vector de enteros. De los valores RGB
643
     * que ya contiene se mantienen las bandas que no coinciden con el valor de flags. La
644
     * banda correspondiente a flags es sustituida por los datos del vector.
645
     * @param image        imagen con los datos actuales
646
     * @param startX        inicio de la posici?n en X dentro de la imagen
647
     * @param startY        inicio de la posici?n en X dentro de la imagen
648
     * @param w        Ancho de la imagen
649
     * @param h        Alto de la imagen
650
     * @param rgbArray        vector que contiene la banda que se va a sustituir
651
     * @param offset        desplazamiento
652
     * @param scansize        tama?o de imagen recorrida por cada paso
653
     * @param origBand        Banda origen del GeoRasterFile
654
     * @param destBandFlag        banda que se va a sustituir (Ctes de GeoRasterFile)
655
     */
656
    protected void setRGBLine(BufferedImage image, int startX, int startY,
657
                              int w, int h, int[] rgbArray, int offset,
658
                              int scansize, int origBand, int destBandFlag) {
659
        int[] line = new int[rgbArray.length];
660
        image.getRGB(startX, startY, w, h, line, offset, scansize);
661

    
662
        if ((origBand == 0) && (destBandFlag == GeoRasterFile.RED_BAND)) {
663
            for (int i = 0; i < line.length; i++)
664
                line[i] = (line[i] & 0xff00ffff) | (rgbArray[i] & 0x00ff0000);
665
        } else if ((origBand == 1) &&
666
                       (destBandFlag == GeoRasterFile.GREEN_BAND)) {
667
            for (int i = 0; i < line.length; i++)
668
                line[i] = (line[i] & 0xffff00ff) | (rgbArray[i] & 0x0000ff00);
669
        } else if ((origBand == 2) &&
670
                       (destBandFlag == GeoRasterFile.BLUE_BAND)) {
671
            for (int i = 0; i < line.length; i++)
672
                line[i] = (line[i] & 0xffffff00) | (rgbArray[i] & 0x000000ff);
673
        }
674
        else if ((origBand == 0) && (destBandFlag == GeoRasterFile.GREEN_BAND)) {
675
            for (int i = 0; i < line.length; i++)
676
                line[i] = (line[i] & 0xffff00ff) |
677
                          ((rgbArray[i] & 0x00ff0000) >> 8);
678
        } else if ((origBand == 0) &&
679
                       (destBandFlag == GeoRasterFile.BLUE_BAND)) {
680
            for (int i = 0; i < line.length; i++)
681
                line[i] = (line[i] & 0xffffff00) |
682
                          ((rgbArray[i] & 0x00ff0000) >> 16);
683
        }
684
        else if ((origBand == 1) && (destBandFlag == GeoRasterFile.RED_BAND)) {
685
            for (int i = 0; i < line.length; i++)
686
                line[i] = (line[i] & 0xff00ffff) |
687
                          ((rgbArray[i] & 0x0000ff00) << 8);
688
        } else if ((origBand == 1) &&
689
                       (destBandFlag == GeoRasterFile.BLUE_BAND)) {
690
            for (int i = 0; i < line.length; i++)
691
                line[i] = (line[i] & 0xffffff00) |
692
                          ((rgbArray[i] & 0x0000ff00) >> 8);
693
        }
694
        else if ((origBand == 2) && (destBandFlag == GeoRasterFile.RED_BAND)) {
695
            for (int i = 0; i < line.length; i++)
696
                line[i] = (line[i] & 0xff00ffff) |
697
                          ((rgbArray[i] & 0x000000ff) << 16);
698
        } else if ((origBand == 2) &&
699
                       (destBandFlag == GeoRasterFile.GREEN_BAND)) {
700
            for (int i = 0; i < line.length; i++)
701
                line[i] = (line[i] & 0xffff00ff) |
702
                          ((rgbArray[i] & 0x000000ff) << 8);
703
        }
704

    
705
        image.setRGB(startX, startY, w, h, line, offset, scansize);
706
    }
707
    
708
    
709
    /* (non-Javadoc)
710
     * @see org.cresques.io.GeoRasterFile#updateImage(int, int, org.cresques.cts.ICoordTrans, java.awt.Image, int origBand, int destBand)
711
     */
712
    public Image updateImage(int width, int height, ICoordTrans rp, Image img,
713
                             int origBand, int destBandFlag) throws SupersamplingNotSupportedException{
714
        //TODO reproyectar para devolver el trozo de imagen pedida sobre ...
715
        // la proyecci?n de destino.
716
        int line = 0;
717
        boolean mustResize = false;
718
        Dimension fullSize = null;
719
        boolean trySupersampling = false;
720

    
721
        if (file == null) {
722
            return null;
723
        }
724

    
725
        try {
726
            int[] bandlist;
727
            int[] bandListTriband;
728
            int[] pRGBArray = null;
729

    
730
            if(mustVerifySize()){
731
                    // Work out the correct aspect for the setView call.
732
                    double dFileAspect = (double) v.width() / (double) v.height();
733
                    double dWindowAspect = (double) width / (double) height;
734
        
735
                    if (dFileAspect > dWindowAspect) {
736
                        height = (int) ((double) width / dFileAspect);
737
                    } else {
738
                        width = (int) ((double) height * dFileAspect);
739
                    }
740
            }
741

    
742
            fullSize = new Dimension(width, height);
743
            
744
            ChunkFrame[] frames = ChunkFrame.computeFrames(file, v, fullSize, extent);
745
                    
746
            if (frames.length == 1) {
747
                width = frames[0].width;
748
                height = frames[0].height;
749

    
750
                if (width <= 0)
751
                    width = 1;
752
             
753
                if (height <= 0)
754
                    height = 1;
755
            }
756
                        
757
            // Create an image of the ecw file.
758
            pRGBArray = new int[width];
759

    
760
            // Setup the view parameters for the ecw file.
761
            bandlist = new int[bandCount];
762
            bandListTriband = new int[bandCount];
763

    
764
            if (bandCount > 2) {
765
                bandlist[0] = getBand(RED_BAND);
766
                bandlist[1] = getBand(GREEN_BAND);
767
                bandlist[2] = getBand(BLUE_BAND);
768

    
769
                if (bandCount > 3) {
770
                    for (int i = 3; i < bandCount; i++) {
771
                        bandlist[i] = 0;
772
                    }
773
                }
774
            } else {
775
                for (int i = 0; i < bandCount; i++)
776
                    bandlist[i] = i;
777
            }
778

    
779
            if (bandCount == 3) {
780
                bandListTriband[0] = 0;
781
                bandListTriband[1] = 1;
782
                bandListTriband[2] = 2;
783
            }
784

    
785
            int[] mascara = new int[3];
786
            int[] shl = new int[3];
787
            int[] shr = new int[3];
788
            boolean order = true;
789
            
790
            if (img == null) { //Caso en el que se crea un Image
791
                EcwFile.nUpdate = 1;
792

    
793
                Image ecwImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
794

    
795
                for (int nChunk = 0; nChunk < frames.length; nChunk++) {
796
                    ChunkFrame f = frames[nChunk];
797
                    
798
                    try{
799
                            if (bandCount != 3) {
800
                                setFileView(file.numBands, bandlist, f);
801
                            } else {
802
                                setFileView(file.numBands, bandListTriband, f);
803
                            }
804
                    }catch(JNCSInvalidSetViewException exc){
805
                            trySupersampling = true;
806
                    }
807

    
808
                    order = calcMaskAndShift(bandlist, mascara, shl, shr);
809

    
810
                    for (line = 0; line < f.height; line++) {
811
                        file.readLineRGBA(pRGBArray);
812
                        pRGBArray = changeBands(order, pRGBArray, mascara, shl, shr);
813
                        setRGBLine((BufferedImage) ecwImage, f.pos.x, f.pos.y + line, f.width, 1, pRGBArray, 0, f.width);
814
                    }
815
                } //Chuncks
816

    
817
                applyAlpha(ecwImage);
818

    
819
                if (frames[0].mustResize && !this.multifile)
820
                    return resizeImageII(fullSize, ecwImage);
821
                
822
                lastRefreshPercent = file.getPercentComplete();
823

    
824
                //System.out.println("Leido al "+lastRefreshPercent+" %.");
825
                return ecwImage;
826
            } else { //Caso en el que se actualiza una banda del Image
827
                EcwFile.nUpdate++;
828

    
829
                for (int nChunk = 0; nChunk < frames.length; nChunk++) {
830
                    ChunkFrame f = frames[nChunk];
831

    
832
                    if (bandCount != 3) {
833
                        setFileView(file.numBands, bandlist, f);
834
                    } else {
835
                        setFileView(file.numBands, bandListTriband, f);
836
                    }
837

    
838
                    order = calcMaskAndShift(bandlist, mascara, shl, shr);
839
                    
840
                    for (line = 0; line < f.height; line++) {
841
                        file.readLineRGBA(pRGBArray);
842
                        pRGBArray = changeBands(order, pRGBArray, mascara, shl, shr);
843
                        setRGBLine((BufferedImage) img, f.pos.x, f.pos.y + line, f.width, 1, pRGBArray, 0, f.width, origBand, destBandFlag);
844
                    }
845
                } //Chuncks
846

    
847
                applyAlpha(img);
848

    
849
                if (frames[0].mustResize && (nUpdate == 3) && this.multifile) {
850
                    return resizeImageII(fullSize, img);
851
                }
852

    
853
                lastRefreshPercent = file.getPercentComplete();
854

    
855
                //System.out.println("Leido al "+lastRefreshPercent+" %.");
856
                return img;
857
            }
858
        } catch (com.ermapper.ecw.JNCSException e) { //java.lang.ArrayIndexOutOfBoundsException:
859
            bErrorOnOpen = true;
860
            System.err.println("EcwFile JNCS Error en la l?nea " + line + "/" +
861
                               height);
862
            System.err.println(e.getMessage());
863
        } catch (java.lang.ArrayIndexOutOfBoundsException e) { //:
864
            bErrorOnOpen = true;
865
            System.err.println("EcwFile ArrayIndex Error en la l?nea " + line +"/" + height);
866
            System.err.println(e.getMessage());
867
        } catch (Exception e) {
868
            bErrorOnOpen = true;
869
            errorMessage = e.getMessage();
870
            System.err.println(errorMessage);
871
            if(trySupersampling)
872
                    throw new SupersamplingNotSupportedException();
873
        }
874

    
875
        return img;
876
    }
877

    
878
    private Image resizeImageII(Dimension sz, Image image) {
879
        int w = (int)sz.getWidth();
880
        int h = (int)sz.getHeight();
881
            Image buffImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
882
            
883
        //Desplazamiento para la X y la Y leidas. Estas tienen efecto cuando un pixel no empieza a visualizarse
884
        //justo en su esquina superior izquierda y tiene que ser cortado en la visualizaci?n.
885
       
886
        double currentViewX = (((double) file.width)/(Math.abs(extent.getMax().getX() - extent.getMin().getX())))*(v.minX()-file.originX);
887
                double currentViewY = (((double) file.height)/(Math.abs(extent.getMax().getY() - extent.getMin().getY())))*(file.originY - v.minY());
888
        double offsetX = Math.abs(currentViewX - ((int)currentViewX));
889
        double offsetY = Math.abs(currentViewY - ((int)currentViewY));
890
        
891
        int xSrc, ySrc;
892
        int decr = 2;
893

    
894
        if(v.minX() == extent.minX() || v.maxX() == extent.maxX() || v.minY() == extent.minY() || v.maxY() == extent.maxY()){
895
                decr = 0;
896
                offsetX = offsetY = 0;
897
        }
898

    
899
        double scaleW = (double)((double)(image.getWidth(null) - decr) / (double)w);
900
        double scaleH = (double)((double)(image.getHeight(null) - decr) / (double)h);
901
        for (int y1 = 0; y1 < h; y1++){
902
        ySrc = (int) ((y1 * scaleH) + offsetY);
903
                for (int x1 = 0; x1 < w; x1++){
904
                        xSrc = (int) ((x1 * scaleW) + offsetX);
905
                        try {
906
                                ((BufferedImage) buffImg).setRGB(x1, y1, ((BufferedImage)image).getRGB(xSrc, ySrc));
907
                        } catch (java.lang.ArrayIndexOutOfBoundsException e) {
908
                        }
909
                }
910
        }
911
        
912
        return buffImg;
913
    }
914

    
915
    
916
    private void applyAlpha(Image im) {
917
        BufferedImage img = (BufferedImage) im;
918
        int alpha = (getAlpha() & 0xff) << 24;
919
        int w = img.getWidth();
920
        int[] line = new int[w];
921

    
922
        for (int j = 0; j < img.getHeight(); j++) {
923
            img.getRGB(0, j, w, 1, line, 0, w);
924

    
925
            for (int i = 0; i < w; i++)
926
                line[i] = (alpha | (line[i] & 0x00ffffff));
927

    
928
            img.setRGB(0, j, w, 1, line, 0, w);
929
        }
930
    }
931

    
932
    /* (non-Javadoc)
933
     * @see org.cresques.io.GeoRasterFile#getData(int, int)
934
     */
935
    public Object getData(int x, int y, int band) {
936
        //file.readLineRGBA();
937
        return null;
938
    }
939

    
940
    /**
941
     * Devuelve los datos de una ventana solicitada
942
     * @param ulX        coordenada X superior izda.
943
     * @param ulY        coordenada Y superior derecha.
944
     * @param sizeX        tama?o en X de la ventana.
945
     * @param sizeY tama?o en Y de la ventana.
946
     * @param band        Banda solicitada.
947
     */
948
    public byte[] getWindow(int ulX, int ulY, int sizeX, int sizeY, int band) {
949
        //TODO Nacho: Implementar getWindow de EcwFile
950
        return null;
951
    }
952

    
953
    /**
954
     * Obtiene la zona (Norte / Sur)
955
     * @return true si la zona es norte y false si es sur
956
     */
957
    public boolean getZone() {
958
        //TODO Nacho: Implementar getZone de EcwFile
959
        return false;
960
    }
961

    
962
    /**
963
     *Devuelve el n?mero de zona UTM
964
     *@return N?mero de zona
965
     */
966
    public int getUTM() {
967
        //                TODO Nacho: Implementar getUTM de EcwFile
968
        return 0;
969
    }
970

    
971
    /**
972
     * Obtiene el sistema de coordenadas geograficas
973
     * @return Sistema de coordenadas geogr?ficas
974
     */
975
    public String getGeogCS() {
976
        //TODO Nacho: Implementar getGeogCS de EcwFile
977
        return new String("");
978
    }
979

    
980
    /**
981
     * Devuelve el tama?o de bloque
982
     * @return Tama?o de bloque
983
     */
984
    public int getBlockSize() {
985
        //TODO Nacho: Implementar getBlockSize de EcwFile        
986
        return 1;
987
    }
988
    
989
    /**
990
         * Calcula la transformaci?n que se produce sobre la vista cuando la imagen tiene un fichero .rmf
991
         * asociado. En Ecw el origen de coordenadas en Y es el valor m?ximo y decrece hasta el m?nimo.
992
         * @param originX Origen de la imagen en la coordenada X
993
         * @param originY Origen de la imagen en la coordenada Y
994
         */
995
    public void setExtentTransform(double originX, double originY, double psX, double psY) {
996
                
997
        }
998

    
999
    /**
1000
     * Trozo de imagen (Chunk) en que se divide la consulta a la librer?a,
1001
     * para esquivar el bug#2.
1002
     *
1003
     * @author luisw
1004
     */
1005
    static class ChunkFrame {
1006
        // Ancho m?ximo (~2500 px)
1007
        final static int MAX_WIDTH = 1536;
1008

    
1009
        // Alto m?ximo (no hay l?mite)
1010
        final static int MAX_HEIGHT = 1536;
1011
        Point pos;
1012
        Extent v;
1013
        int width;
1014
        int height;
1015
        boolean mustResize = false;
1016

    
1017
        public ChunkFrame(Extent vista, int w, int h) {
1018
            v = vista;
1019
            width = w;
1020
            height = h;
1021
        }
1022

    
1023
        /**
1024
         * Calcula el array de chunks (trozos).
1025
         * @param file        Fichero ecw que hay que trocear.
1026
         * @param v Extent total de la vista.
1027
         * @param sz        Tama?o total de la vista.
1028
         * @return array de ChunkFrames.
1029
         * @throws JNCSFileNotOpenException
1030
         */
1031
        public static ChunkFrame[] computeFrames(JNCSFile file, Extent v,
1032
                                                 Dimension sz, Extent extent)
1033
                                          throws JNCSFileNotOpenException {
1034
            ChunkFrame[] frames = null;
1035
            ChunkFrame f = null;
1036

    
1037
            // Calcula el n? de chunks (filas y columnas)
1038
            int numCol = (sz.width / MAX_WIDTH);
1039

    
1040
            // Calcula el n? de chunks (filas y columnas)
1041
            int numRow = (sz.height / MAX_HEIGHT);
1042

    
1043
            if ((sz.width - (numCol * MAX_WIDTH)) > 0) {
1044
                numCol++;
1045
            }
1046

    
1047
            if ((sz.height - (numRow * MAX_HEIGHT)) > 0) {
1048
                numRow++;
1049
            }
1050

    
1051
            frames = new ChunkFrame[numCol * numRow];
1052

    
1053
            JNCSDatasetPoint ptMin = file.convertWorldToDataset(v.minX(), v.minY());
1054
            JNCSDatasetPoint ptMax = file.convertWorldToDataset(v.maxX(), v.maxY());
1055

    
1056
            //No utilizamos JNCSDatasetPoint porque siempre hace un redondeo por abajo con lo que perdemos precisi?n. En su lugar
1057
            //utilizamos currentViewM... calculado manualmente y que nos proporciona todos los decimales 
1058
            double currentViewMinX = (((double) file.width)/(Math.abs(extent.getMax().getX() - extent.getMin().getX())))*(v.minX()-file.originX);
1059
            double currentViewMaxX = (((double) file.width)/(Math.abs(extent.getMax().getX() - extent.getMin().getX())))*(v.maxX()-file.originX);
1060
                    double currentViewMinY = (((double) file.height)/(Math.abs(extent.getMax().getY() - extent.getMin().getY())))*(file.originY - v.minY());
1061
                    double currentViewMaxY = (((double) file.height)/(Math.abs(extent.getMax().getY() - extent.getMin().getY())))*(file.originY - v.maxY());
1062
                      
1063
            if ((ptMax.x - ptMin.x) < sz.width) {
1064
                numCol = numRow = 1;
1065
                frames = new ChunkFrame[numCol * numRow];
1066
                int nPixelsX = (int)Math.ceil(Math.abs(currentViewMaxX - currentViewMinX));
1067
                int nPixelsY = (int)Math.ceil(Math.abs(currentViewMaxY - currentViewMinY));
1068
                
1069
                if(v.minX() == extent.minX() || v.maxX() == extent.maxX() || v.minY() == extent.minY() || v.maxY() == extent.maxY()){
1070
                        f = frames[0] = new ChunkFrame(v, nPixelsX, nPixelsY);
1071
                        f.v = new Extent(v);
1072
                }else{
1073
                        f = frames[0] = new ChunkFrame(v, nPixelsX + 1, nPixelsY + 1);
1074
                        double pointEndWcX = v.minX() + (((nPixelsX + 1) * Math.abs(v.maxX() - v.minX())) / nPixelsX);
1075
                        double pointEndWcY = v.maxY() - (((nPixelsY + 1) * Math.abs(v.maxY() - v.minY())) / nPixelsY);
1076
                        f.v = new Extent(v.minX(), v.maxY(), pointEndWcX, pointEndWcY);
1077
                }
1078
                
1079
                f.pos = new Point(0, 0);
1080
                f.mustResize = true;
1081
            } else {
1082
                // Calcula cada chunk
1083
                double stepx = ((double) ptMax.x - ptMin.x) / sz.getWidth();
1084
                double stepy = ((double) ptMax.y - ptMin.y) / sz.getHeight();
1085
                int h = sz.height;
1086

    
1087
                for (int r = 0; r < numRow; r++) {
1088
                    int w = sz.width;
1089

    
1090
                    for (int c = 0; c < numCol; c++) {
1091
                        f = new ChunkFrame(null, -1, -1);
1092

    
1093
                        // Posici?n del chunk
1094
                        f.pos = new Point(c * MAX_WIDTH, r * MAX_HEIGHT);
1095

    
1096
                        // Tama?o del chunk
1097
                        f.width = Math.min(MAX_WIDTH, w);
1098
                        f.height = Math.min(MAX_HEIGHT, h);
1099

    
1100
                        // Extent del chunk
1101
                        int x1 = ptMin.x + (int) (f.pos.x * stepx);
1102
                        int x2 = x1 + (int) (f.width * stepx);
1103
                        int y1 = ptMax.y - (int) (f.pos.y * stepy); 
1104
                        int y2 = y1 - (int) (f.height * stepy); //ptMin.y;
1105
                        JNCSWorldPoint pt1 = file.convertDatasetToWorld(x1, y1);
1106
                        JNCSWorldPoint pt2 = file.convertDatasetToWorld(x2, y2);
1107
                        
1108
                        f.v = new Extent(pt1.x, pt1.y, pt2.x, pt2.y); // Hay que calcularlo
1109
                        frames[(r * numCol) + c] = f;
1110
                        w -= MAX_WIDTH;
1111
                    }
1112

    
1113
                    h -= MAX_HEIGHT;
1114
                }
1115
            }
1116

    
1117
            //System.out.println("Hay "+numRow+" filas y "+numCol+" columnas.");
1118
            return frames;
1119
        }
1120
    }
1121
}