Statistics
| Revision:

root / branches / CqCMSDvp / libraries / libCq CMS for java.old / src / org / cresques / io / EcwFile.java @ 2669

History | View | Annotate | Download (42.2 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 com.ermapper.ecw.JNCSFile;
27
import com.ermapper.ecw.JNCSFileNotOpenException;
28
import com.ermapper.ecw.JNCSProgressiveUpdate;
29

    
30
import com.ermapper.util.JNCSDatasetPoint;
31
import com.ermapper.util.JNCSWorldPoint;
32

    
33
import org.cresques.cts.ICoordTrans;
34
import org.cresques.cts.IProjection;
35

    
36
import org.cresques.px.Extent;
37

    
38
import java.awt.Dimension;
39
import java.awt.Image;
40
import java.awt.Point;
41
import java.awt.image.BufferedImage;
42
import java.awt.image.PixelGrabber;
43

    
44

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

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

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

    
95
        try {
96
            //System.err.println("Abriendo "+fName);
97
            file = new JNCSFile(fName, false);
98
            load();
99
            bandCount = file.numBands;
100

    
101
            /*if ( bandCount > 2) {
102
                    setBand(RED_BAND,   0);
103
                    setBand(GREEN_BAND, 1);
104
                    setBand(BLUE_BAND,  2);
105
            } else
106
                    setBand(RED_BAND|GREEN_BAND|BLUE_BAND, 0);*/
107
        } catch (Exception e) {
108
            bErrorOnOpen = true;
109
            errorMessage = e.getMessage();
110
            System.err.println(errorMessage);
111
            e.printStackTrace();
112
        }
113
    }
114

    
115
    public void setView(Extent e) {
116
        v = new Extent(e);
117
    }
118

    
119
    public Extent getView() {
120
        return v;
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
        /*System.out.println("ECW size = ("+file.width+","+file.height+")\n"+
135
                " inc=("+file.cellIncrementX+","+file.cellIncrementY+")\n"+
136
                " datum='"+file.datum+"', proyeccion='"+file.projection+"'");*/
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
        extent = new Extent(minX, minY, maxX, maxY);
144
        System.out.println(extent);
145

    
146
        return this;
147
    }
148

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

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

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

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

    
175
    /**
176
     * Obtiene un trozo de imagen (determinado por la vista y los par?metros.
177
     *
178
     * @param width
179
     * @param height
180
     */
181
    public synchronized Image updateImage(int width, int height, ICoordTrans rp) {
182
        // TODO reproyectar para devolver el trozo de imagen pedida sobre ...
183
        // la proyecci?n de destino.
184
        int line = 0;
185
        boolean mustResize = false;
186
        Dimension fullSize = null;
187
        Image ecwImage = null;
188

    
189
        if (file == null) {
190
            return ecwImage;
191
        }
192

    
193
        try {
194
            double dFileAspect;
195
            double dWindowAspect;
196

    
197
            //double dWorldTLX, dWorldTLY, dWorldBRX, dWorldBRY;
198
            int[] bandlist;
199
            int[] bandListTriband;
200
            int[] pRGBArray = null;
201

    
202
            // Work out the correct aspect for the setView call.
203
            dFileAspect = (double) v.width() / (double) v.height();
204
            dWindowAspect = (double) width / (double) height;
205

    
206
            if (dFileAspect > dWindowAspect) {
207
                height = (int) ((double) width / dFileAspect);
208
            } else {
209
                width = (int) ((double) height * dFileAspect);
210
            }
211

    
212
            fullSize = new Dimension(width, height);
213

    
214
            //System.out.println("fullSize = ("+width+","+height+")");
215
            // Peta en los peque?os ... arreglar antes de meter del todo
216
            ChunkFrame[] frames = ChunkFrame.computeFrames(file, v, fullSize);
217

    
218
            /*for (int nChunk=0; nChunk<frames.length; nChunk++) {
219
                    System.out.println("chunck "+nChunk+"->"+frames[nChunk]);
220
            }*/
221
            if (frames.length == 1) {
222
                width = frames[0].width;
223
                height = frames[0].height;
224

    
225
                if (width <= 0) {
226
                    width = 1;
227
                }
228

    
229
                if (height <= 0) {
230
                    height = 1;
231
                }
232

    
233
                //System.out.println("frameSize = ("+width+","+height+")");
234
                //System.out.println("Cambio el ancho total a ("+width+","+height+")");
235
            }
236

    
237
            /*                        JNCSDatasetPoint ptMin = file.convertWorldToDataset(v.minX(), v.minY());
238
                                    JNCSDatasetPoint ptMax = file.convertWorldToDataset(v.maxX(), v.maxY());
239
                                    System.out.println("Dataset coords Width = "+(ptMax.x-ptMin.x)+", px width ="+width);
240
                                    // BEGIN Cambiando para soportar e < 1:1
241
                                    // TODO Mejorarlo para que los PAN con un zoom muy grande sean correctos
242
                                    if ((ptMax.x-ptMin.x)<width) {
243
                                            width = ptMax.x-ptMin.x;
244
                                            height = ptMin.y-ptMax.y;
245
                                            System.out.println("Size=("+width+","+height+")");
246
                                            mustResize = true;
247
                                    }*/
248

    
249
            // Create an image of the ecw file.
250
            if (doTransparency) {
251
                ecwImage = new BufferedImage(width, height,
252
                                             BufferedImage.TYPE_INT_ARGB);
253
            } else {
254
                ecwImage = new BufferedImage(width, height,
255
                                             BufferedImage.TYPE_INT_RGB);
256
            }
257

    
258
            pRGBArray = new int[width];
259

    
260
            // Setup the view parameters for the ecw file.
261
            bandlist = new int[bandCount];
262
            bandListTriband = new int[bandCount];
263

    
264
            if (bandCount > 2) {
265
                bandlist[0] = getBand(RED_BAND);
266
                bandlist[1] = getBand(GREEN_BAND);
267
                bandlist[2] = getBand(BLUE_BAND);
268

    
269
                if (bandCount > 3) {
270
                    for (int i = 3; i < bandCount; i++) {
271
                        bandlist[i] = 0;
272
                    }
273
                }
274
            } else {
275
                for (int i = 0; i < bandCount; i++) {
276
                    bandlist[i] = i;
277
                }
278
            }
279

    
280
            if (bandCount == 3) {
281
                bandListTriband[0] = 0;
282
                bandListTriband[1] = 1;
283
                bandListTriband[2] = 2;
284
            }
285

    
286
            for (int nChunk = 0; nChunk < frames.length; nChunk++) {
287
                ChunkFrame f = frames[nChunk];
288

    
289
                // Set the view                        
290
                if (bandCount != 3) {
291
                    file.setView(file.numBands, bandlist, f.v.minX(),
292
                                 f.v.maxY(), f.v.maxX(), f.v.minY(), f.width,
293
                                 f.height);
294
                } else {
295
                    file.setView(file.numBands, bandListTriband, f.v.minX(),
296
                                 f.v.maxY(), f.v.maxX(), f.v.minY(), f.width,
297
                                 f.height);
298
                }
299

    
300
                //System.out.println("f.Size = ("+f.width+","+f.height+")+CHUNK="+nChunk);
301

    
302
                /* Esta peli es porque el Ecw no intercambia las bandas con lo que me toca hacerlo
303
                 * a mano. Primero detectamos si se ha alterado el orden de las mismas. Si es as?
304
                 * calculamos mascaras y desplazamientos y hacemos una copia en pRGBArrayCopy
305
                 * con las bandas alteradas de orden
306
                 */
307
                int[] pRGBArrayCopy = null;
308
                int[] mascara = new int[3];
309
                int[] shl = new int[3];
310
                int[] shr = new int[3];
311
                boolean order = true;
312

    
313
                if (bandCount == 3) {
314
                    for (int i = 0; i < bandCount; i++)
315
                        if (bandlist[i] != i) {
316
                            order = false;
317
                        }
318

    
319
                    if (!order) {
320
                        for (int i = 0; i < bandCount; i++) {
321
                            switch (bandlist[i]) {
322
                            case 0:
323
                                mascara[i] = 0x00ff0000;
324

    
325
                                break;
326

    
327
                            case 1:
328
                                mascara[i] = 0x0000ff00;
329

    
330
                                break;
331

    
332
                            case 2:
333
                                mascara[i] = 0x000000ff;
334

    
335
                                break;
336
                            }
337

    
338
                            if ((i == 1) && (bandlist[i] == 0)) {
339
                                shr[i] = 8;
340
                            }
341

    
342
                            if ((i == 2) && (bandlist[i] == 0)) {
343
                                shr[i] = 16;
344
                            }
345

    
346
                            if ((i == 0) && (bandlist[i] == 1)) {
347
                                shl[i] = 8;
348
                            }
349

    
350
                            if ((i == 2) && (bandlist[i] == 1)) {
351
                                shr[i] = 8;
352
                            }
353

    
354
                            if ((i == 0) && (bandlist[i] == 2)) {
355
                                shl[i] = 16;
356
                            }
357

    
358
                            if ((i == 1) && (bandlist[i] == 2)) {
359
                                shl[i] = 8;
360
                            }
361
                        }
362
                    }
363
                }
364

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

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

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

    
379
                        pRGBArray = pRGBArrayCopy;
380
                    }
381

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

    
388
                        tFilter.filterLine(pRGBArray);
389
                        tFilter.debug = false;
390
                    }
391

    
392
                    //System.out.println("setRGB("+f.pos.x+","+f.pos.y+line+","+f.width+","+1+","+pRGBArray+","+0+","+f.width+")");
393
                    ((BufferedImage) ecwImage).setRGB(f.pos.x, f.pos.y + line,
394
                                                      f.width, 1, pRGBArray, 0,
395
                                                      f.width);
396
                }
397
            }
398

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

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

    
425
            //                        g.drawString(errorMessage, 0, 50);
426
            System.err.println(errorMessage);
427
            e.printStackTrace();
428
        }
429

    
430
        lastRefreshPercent = file.getPercentComplete();
431
        System.out.println("Leido al " + lastRefreshPercent + " %.");
432

    
433
        return ecwImage;
434
    }
435

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

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

    
455
        int[] pixels = new int[img.getWidth(null) * img.getHeight(null)];
456
        PixelGrabber pg = new PixelGrabber(img, 0, 0, img.getWidth(null),
457
                                           img.getHeight(null), pixels, 0,
458
                                           img.getWidth(null));
459

    
460
        try {
461
            pg.grabPixels();
462
        } catch (InterruptedException e) {
463
            e.printStackTrace();
464
        }
465

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

    
474
        return buffImg;
475
    }
476

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

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

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

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

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

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

    
529
            if (!order) {
530
                for (int i = 0; i < bandCount; i++) {
531
                    switch (bandList[i]) {
532
                    case 0:
533
                        mask[i] = 0x00ff0000;
534

    
535
                        break;
536

    
537
                    case 1:
538
                        mask[i] = 0x0000ff00;
539

    
540
                        break;
541

    
542
                    case 2:
543
                        mask[i] = 0x000000ff;
544

    
545
                        break;
546
                    }
547

    
548
                    if ((i == 1) && (bandList[i] == 0)) {
549
                        shr[i] = 8;
550
                    }
551

    
552
                    if ((i == 2) && (bandList[i] == 0)) {
553
                        shr[i] = 16;
554
                    }
555

    
556
                    if ((i == 0) && (bandList[i] == 1)) {
557
                        shl[i] = 8;
558
                    }
559

    
560
                    if ((i == 2) && (bandList[i] == 1)) {
561
                        shr[i] = 8;
562
                    }
563

    
564
                    if ((i == 0) && (bandList[i] == 2)) {
565
                        shl[i] = 16;
566
                    }
567

    
568
                    if ((i == 1) && (bandList[i] == 2)) {
569
                        shl[i] = 8;
570
                    }
571
                }
572
            }
573
        }
574

    
575
        return order;
576
    }
577

    
578
    /**
579
     * Intercambio de bandas para ecw manual. Se le pasa el array de bytes que se desea intercambiar
580
     * la mascara y desplazamientos previamente calculados con calcMaskAndShift
581
     * @param order        true si el orden de las bandas no est? alterado y false si lo est?
582
     * @param pRGBArray array de
583
     * @param mascara
584
     * @param shl desplazamiento a izquierda
585
     * @param shr desplazamiento a derecha
586
     * @return array con las bandas cambiadas
587
     */
588
    private int[] changeBands(boolean order, int[] pRGBArray, int[] mascara,
589
                              int[] shl, int[] shr) {
590
        if ((bandCount == 3) && !order) {
591
            int[] pRGBArrayCopy = new int[pRGBArray.length];
592

    
593
            for (int i = 0; i < pRGBArray.length; i++) {
594
                pRGBArrayCopy[i] = (pRGBArray[i] & 0xff000000) +
595
                                   (((pRGBArray[i] & mascara[2]) << shl[2]) >> shr[2]) +
596
                                   (((pRGBArray[i] & mascara[1]) << shl[1]) >> shr[1]) +
597
                                   (((pRGBArray[i] & mascara[0]) << shl[0]) >> shr[0]);
598
            }
599

    
600
            return pRGBArrayCopy;
601
        }
602

    
603
        return pRGBArray;
604
    }
605

    
606
    /**
607
     * Asigna al objeto Image los valores con los dato de la imagen contenidos en el
608
     * vector de enteros.
609
     * @param image        imagen con los datos actuales
610
     * @param startX        inicio de la posici?n en X dentro de la imagen
611
     * @param startY        inicio de la posici?n en X dentro de la imagen
612
     * @param w        Ancho de la imagen
613
     * @param h        Alto de la imagen
614
     * @param rgbArray        vector que contiene la banda que se va a sustituir
615
     * @param offset        desplazamiento
616
     * @param scansize        tama?o de imagen recorrida por cada p
617
     */
618
    protected void setRGBLine(BufferedImage image, int startX, int startY,
619
                              int w, int h, int[] rgbArray, int offset,
620
                              int scansize) {
621
        image.setRGB(startX, startY, w, h, rgbArray, offset, scansize);
622
    }
623

    
624
    /**
625
     * Asigna al objeto Image la mezcla entre los valores que ya tiene y los valores
626
     * con los dato de la imagen contenidos en el vector de enteros. De los valores RGB
627
     * que ya contiene se mantienen las bandas que no coinciden con el valor de flags. La
628
     * banda correspondiente a flags es sustituida por los datos del vector.
629
     * @param image        imagen con los datos actuales
630
     * @param startX        inicio de la posici?n en X dentro de la imagen
631
     * @param startY        inicio de la posici?n en X dentro de la imagen
632
     * @param w        Ancho de la imagen
633
     * @param h        Alto de la imagen
634
     * @param rgbArray        vector que contiene la banda que se va a sustituir
635
     * @param offset        desplazamiento
636
     * @param scansize        tama?o de imagen recorrida por cada paso
637
     * @param flags        banda que se va a sustituir (Ctes de GeoRasterFile)
638
     */
639
    protected void setRGBLine(BufferedImage image, int startX, int startY,
640
                              int w, int h, int[] rgbArray, int offset,
641
                              int scansize, int flags) {
642
        int[] line = new int[rgbArray.length];
643
        image.getRGB(startX, startY, w, h, line, offset, scansize);
644

    
645
        if (flags == GeoRasterFile.RED_BAND) {
646
            for (int i = 0; i < line.length; i++)
647
                line[i] = (line[i] & 0x0000ffff) | (rgbArray[i] & 0xffff0000);
648
        } else if (flags == GeoRasterFile.GREEN_BAND) {
649
            for (int i = 0; i < line.length; i++)
650
                line[i] = (line[i] & 0x00ff00ff) | (rgbArray[i] & 0xff00ff00);
651
        } else if (flags == GeoRasterFile.BLUE_BAND) {
652
            for (int i = 0; i < line.length; i++)
653
                line[i] = (line[i] & 0x00ffff00) | (rgbArray[i] & 0xff0000ff);
654
        }
655

    
656
        image.setRGB(startX, startY, w, h, line, offset, scansize);
657
    }
658

    
659
    /**
660
     * Asigna al objeto Image la mezcla entre los valores que ya tiene y los valores
661
     * con los dato de la imagen contenidos en el vector de enteros. De los valores RGB
662
     * que ya contiene se mantienen las bandas que no coinciden con el valor de flags. La
663
     * banda correspondiente a flags es sustituida por los datos del vector.
664
     * @param image        imagen con los datos actuales
665
     * @param startX        inicio de la posici?n en X dentro de la imagen
666
     * @param startY        inicio de la posici?n en X dentro de la imagen
667
     * @param w        Ancho de la imagen
668
     * @param h        Alto de la imagen
669
     * @param rgbArray        vector que contiene la banda que se va a sustituir
670
     * @param offset        desplazamiento
671
     * @param scansize        tama?o de imagen recorrida por cada paso
672
     * @param origBand        Banda origen del GeoRasterFile
673
     * @param destBandFlag        banda que se va a sustituir (Ctes de GeoRasterFile)
674
     */
675
    protected void setRGBLine(BufferedImage image, int startX, int startY,
676
                              int w, int h, int[] rgbArray, int offset,
677
                              int scansize, int origBand, int destBandFlag) {
678
        int[] line = new int[rgbArray.length];
679
        image.getRGB(startX, startY, w, h, line, offset, scansize);
680

    
681
        if ((origBand == 0) && (destBandFlag == GeoRasterFile.RED_BAND)) {
682
            for (int i = 0; i < line.length; i++)
683
                line[i] = (line[i] & 0xff00ffff) | (rgbArray[i] & 0x00ff0000);
684
        } else if ((origBand == 1) &&
685
                       (destBandFlag == GeoRasterFile.GREEN_BAND)) {
686
            for (int i = 0; i < line.length; i++)
687
                line[i] = (line[i] & 0xffff00ff) | (rgbArray[i] & 0x0000ff00);
688
        } else if ((origBand == 2) &&
689
                       (destBandFlag == GeoRasterFile.BLUE_BAND)) {
690
            for (int i = 0; i < line.length; i++)
691
                line[i] = (line[i] & 0xffffff00) | (rgbArray[i] & 0x000000ff);
692
        }
693
        else if ((origBand == 0) && (destBandFlag == GeoRasterFile.GREEN_BAND)) {
694
            for (int i = 0; i < line.length; i++)
695
                line[i] = (line[i] & 0xffff00ff) |
696
                          ((rgbArray[i] & 0x00ff0000) >> 8);
697
        } else if ((origBand == 0) &&
698
                       (destBandFlag == GeoRasterFile.BLUE_BAND)) {
699
            for (int i = 0; i < line.length; i++)
700
                line[i] = (line[i] & 0xffffff00) |
701
                          ((rgbArray[i] & 0x00ff0000) >> 16);
702
        }
703
        else if ((origBand == 1) && (destBandFlag == GeoRasterFile.RED_BAND)) {
704
            for (int i = 0; i < line.length; i++)
705
                line[i] = (line[i] & 0xff00ffff) |
706
                          ((rgbArray[i] & 0x0000ff00) << 8);
707
        } else if ((origBand == 1) &&
708
                       (destBandFlag == GeoRasterFile.BLUE_BAND)) {
709
            for (int i = 0; i < line.length; i++)
710
                line[i] = (line[i] & 0xffffff00) |
711
                          ((rgbArray[i] & 0x0000ff00) >> 8);
712
        }
713
        else if ((origBand == 2) && (destBandFlag == GeoRasterFile.RED_BAND)) {
714
            for (int i = 0; i < line.length; i++)
715
                line[i] = (line[i] & 0xff00ffff) |
716
                          ((rgbArray[i] & 0x000000ff) << 16);
717
        } else if ((origBand == 2) &&
718
                       (destBandFlag == GeoRasterFile.GREEN_BAND)) {
719
            for (int i = 0; i < line.length; i++)
720
                line[i] = (line[i] & 0xffff00ff) |
721
                          ((rgbArray[i] & 0x000000ff) << 8);
722
        }
723

    
724
        image.setRGB(startX, startY, w, h, line, offset, scansize);
725
    }
726

    
727
    /* (non-Javadoc)
728
     * @see org.cresques.io.GeoRasterFile#updateImage(int, int, org.cresques.cts.ICoordTrans, java.awt.Image, int origBand, int destBand)
729
     */
730
    public Image updateImage(int width, int height, ICoordTrans rp, Image img,
731
                             int origBand, int destBandFlag) {
732
        //TODO reproyectar para devolver el trozo de imagen pedida sobre ...
733
        // la proyecci?n de destino.
734
        int line = 0;
735
        boolean mustResize = false;
736
        Dimension fullSize = null;
737

    
738
        if (file == null) {
739
            return null;
740
        }
741

    
742
        try {
743
            double dFileAspect;
744
            double dWindowAspect;
745

    
746
            //double dWorldTLX, dWorldTLY, dWorldBRX, dWorldBRY;
747
            int[] bandlist;
748
            int[] bandListTriband;
749
            int[] pRGBArray = null;
750

    
751
            // Work out the correct aspect for the setView call.
752
            dFileAspect = (double) v.width() / (double) v.height();
753
            dWindowAspect = (double) width / (double) height;
754

    
755
            if (dFileAspect > dWindowAspect) {
756
                height = (int) ((double) width / dFileAspect);
757
            } else {
758
                width = (int) ((double) height * dFileAspect);
759
            }
760

    
761
            fullSize = new Dimension(width, height);
762

    
763
            //System.out.println("fullSize = ("+width+","+height+")");
764
            // Peta en los peque?os ... arreglar antes de meter del todo
765
            ChunkFrame[] frames = ChunkFrame.computeFrames(file, v, fullSize);
766

    
767
            /*for (int nChunk=0; nChunk<frames.length; nChunk++) {
768
                    System.out.println("chunck "+nChunk+"->"+frames[nChunk]);
769
            }*/
770
            if (frames.length == 1) {
771
                width = frames[0].width;
772
                height = frames[0].height;
773

    
774
                if (width <= 0) {
775
                    width = 1;
776
                }
777

    
778
                if (height <= 0) {
779
                    height = 1;
780
                }
781

    
782
                //System.out.println("frameSize = ("+width+","+height+")");
783
                //System.out.println("Cambio el ancho total a ("+width+","+height+")");
784
            }
785

    
786
            // Create an image of the ecw file.
787
            pRGBArray = new int[width];
788

    
789
            // Setup the view parameters for the ecw file.
790
            bandlist = new int[bandCount];
791
            bandListTriband = new int[bandCount];
792

    
793
            if (bandCount > 2) {
794
                bandlist[0] = getBand(RED_BAND);
795
                bandlist[1] = getBand(GREEN_BAND);
796
                bandlist[2] = getBand(BLUE_BAND);
797

    
798
                if (bandCount > 3) {
799
                    for (int i = 3; i < bandCount; i++) {
800
                        bandlist[i] = 0;
801
                    }
802
                }
803
            } else {
804
                for (int i = 0; i < bandCount; i++) {
805
                    bandlist[i] = i;
806
                }
807
            }
808

    
809
            if (bandCount == 3) {
810
                bandListTriband[0] = 0;
811
                bandListTriband[1] = 1;
812
                bandListTriband[2] = 2;
813
            }
814

    
815
            int[] mascara = new int[3];
816
            int[] shl = new int[3];
817
            int[] shr = new int[3];
818
            boolean order = true;
819

    
820
            if (img == null) { //Caso en el que se crea un Image
821
                EcwFile.nUpdate = 1;
822

    
823
                Image ecwImage = new BufferedImage(width, height,
824
                                                   BufferedImage.TYPE_INT_ARGB);
825

    
826
                for (int nChunk = 0; nChunk < frames.length; nChunk++) {
827
                    ChunkFrame f = frames[nChunk];
828

    
829
                    if (bandCount != 3) {
830
                        file.setView(file.numBands, bandlist, f.v.minX(),
831
                                     f.v.maxY(), f.v.maxX(), f.v.minY(),
832
                                     f.width, f.height);
833
                    } else {
834
                        file.setView(file.numBands, bandListTriband,
835
                                     f.v.minX(), f.v.maxY(), f.v.maxX(),
836
                                     f.v.minY(), f.width, f.height);
837
                    }
838

    
839
                    order = calcMaskAndShift(bandlist, mascara, shl, shr);
840

    
841
                    for (line = 0; line < f.height; line++) {
842
                        file.readLineRGBA(pRGBArray);
843
                        pRGBArray = changeBands(order, pRGBArray, mascara, shl,
844
                                                shr);
845
                        setRGBLine((BufferedImage) ecwImage, f.pos.x,
846
                                   f.pos.y + line, f.width, 1, pRGBArray, 0,
847
                                   f.width);
848
                    }
849
                } //Chuncks
850

    
851
                applyAlpha(ecwImage);
852

    
853
                if (frames[0].mustResize && !this.multifile) {
854
                    return resizeImage(fullSize, ecwImage);
855
                }
856

    
857
                lastRefreshPercent = file.getPercentComplete();
858

    
859
                //System.out.println("Leido al "+lastRefreshPercent+" %.");
860
                return ecwImage;
861
            } else { //Caso en el que se actualiza una banda del Image
862
                EcwFile.nUpdate++;
863

    
864
                for (int nChunk = 0; nChunk < frames.length; nChunk++) {
865
                    ChunkFrame f = frames[nChunk];
866

    
867
                    if (bandCount != 3) {
868
                        file.setView(file.numBands, bandlist, f.v.minX(),
869
                                     f.v.maxY(), f.v.maxX(), f.v.minY(),
870
                                     f.width, f.height);
871
                    } else {
872
                        file.setView(file.numBands, bandListTriband,
873
                                     f.v.minX(), f.v.maxY(), f.v.maxX(),
874
                                     f.v.minY(), f.width, f.height);
875
                    }
876

    
877
                    order = calcMaskAndShift(bandlist, mascara, shl, shr);
878

    
879
                    //System.out.println("ORIGEN="+origBand+" DESTINO="+destBandFlag);
880
                    for (line = 0; line < f.height; line++) {
881
                        file.readLineRGBA(pRGBArray);
882
                        pRGBArray = changeBands(order, pRGBArray, mascara, shl,
883
                                                shr);
884
                        setRGBLine((BufferedImage) img, f.pos.x,
885
                                   f.pos.y + line, f.width, 1, pRGBArray, 0,
886
                                   f.width, origBand, destBandFlag);
887
                    }
888
                } //Chuncks
889

    
890
                applyAlpha(img);
891

    
892
                if (frames[0].mustResize && (nUpdate == 3) && this.multifile) {
893
                    return resizeImage(fullSize, img);
894
                }
895

    
896
                lastRefreshPercent = file.getPercentComplete();
897

    
898
                //System.out.println("Leido al "+lastRefreshPercent+" %.");
899
                return img;
900
            }
901
        } catch (com.ermapper.ecw.JNCSException e) { //java.lang.ArrayIndexOutOfBoundsException:
902
            bErrorOnOpen = true;
903
            System.err.println("EcwFile JNCS Error en la l?nea " + line + "/" +
904
                               height);
905
            System.err.println(e.getMessage());
906
            e.printStackTrace();
907
        } catch (java.lang.ArrayIndexOutOfBoundsException e) { //:
908
            bErrorOnOpen = true;
909
            System.err.println("EcwFile ArrayIndex Error en la l?nea " + line +
910
                               "/" + height);
911
            System.err.println(e.getMessage());
912
            e.printStackTrace();
913
        } catch (Exception e) {
914
            bErrorOnOpen = true;
915
            errorMessage = e.getMessage();
916
            System.err.println(errorMessage);
917
            e.printStackTrace();
918
        }
919

    
920
        return img;
921
    }
922

    
923
    private void applyAlpha(Image im) {
924
        BufferedImage img = (BufferedImage) im;
925
        int alpha = (getAlpha() & 0xff) << 24;
926
        int w = img.getWidth();
927
        int[] line = new int[w];
928

    
929
        for (int j = 0; j < img.getHeight(); j++) {
930
            img.getRGB(0, j, w, 1, line, 0, w);
931

    
932
            for (int i = 0; i < w; i++)
933
                line[i] = (alpha | (line[i] & 0x00ffffff));
934

    
935
            img.setRGB(0, j, w, 1, line, 0, w);
936
        }
937
    }
938

    
939
    /* (non-Javadoc)
940
     * @see org.cresques.io.GeoRasterFile#getData(int, int)
941
     */
942
    public Object getData(int x, int y, int band) {
943
        //file.readLineRGBA();
944
        return null;
945
    }
946

    
947
    /**
948
     * Devuelve los datos de una ventana solicitada
949
     * @param ulX        coordenada X superior izda.
950
     * @param ulY        coordenada Y superior derecha.
951
     * @param sizeX        tama?o en X de la ventana.
952
     * @param sizeY tama?o en Y de la ventana.
953
     * @param band        Banda solicitada.
954
     */
955
    public byte[] getWindow(int ulX, int ulY, int sizeX, int sizeY, int band) {
956
        //TODO Nacho: Implementar getWindow de EcwFile
957
        return null;
958
    }
959

    
960
    /**
961
     * Obtiene la zona (Norte / Sur)
962
     * @return true si la zona es norte y false si es sur
963
     */
964
    public boolean getZone() {
965
        //TODO Nacho: Implementar getZone de EcwFile
966
        return false;
967
    }
968

    
969
    /**
970
     *Devuelve el n?mero de zona UTM
971
     *@return N?mero de zona
972
     */
973
    public int getUTM() {
974
        //                TODO Nacho: Implementar getUTM de EcwFile
975
        return 0;
976
    }
977

    
978
    /**
979
     * Obtiene el sistema de coordenadas geograficas
980
     * @return Sistema de coordenadas geogr?ficas
981
     */
982
    public String getGeogCS() {
983
        //TODO Nacho: Implementar getGeogCS de EcwFile
984
        return new String("");
985
    }
986

    
987
    /**
988
     * Devuelve el tama?o de bloque
989
     * @return Tama?o de bloque
990
     */
991
    public int getBlockSize() {
992
        //TODO Nacho: Implementar getBlockSize de EcwFile        
993
        return 1;
994
    }
995

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

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

    
1014
        public ChunkFrame(Extent vista, int w, int h) {
1015
            v = vista;
1016
            width = w;
1017
            height = h;
1018
        }
1019

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

    
1034
            // Calcula el n? de chunks (filas y columnas)
1035
            int numCol = (sz.width / MAX_WIDTH);
1036

    
1037
            // Calcula el n? de chunks (filas y columnas)
1038
            int numRow = (sz.height / MAX_HEIGHT);
1039

    
1040
            if ((sz.width - (numCol * MAX_WIDTH)) > 0) {
1041
                numCol++;
1042
            }
1043

    
1044
            if ((sz.height - (numRow * MAX_HEIGHT)) > 0) {
1045
                numRow++;
1046
            }
1047

    
1048
            frames = new ChunkFrame[numCol * numRow];
1049

    
1050
            // Coprobaci?n previa para resolver el bug#1
1051
            JNCSDatasetPoint ptMin = file.convertWorldToDataset(v.minX(),
1052
                                                                v.minY());
1053
            JNCSDatasetPoint ptMax = file.convertWorldToDataset(v.maxX(),
1054
                                                                v.maxY());
1055

    
1056
            /*System.out.println("Dataset coords Width = "+(ptMax.x-ptMin.x)+", px width = "+sz.width+
1057
                            " px heigh = "+sz.height);*/
1058

    
1059
            // BEGIN Cambiando para soportar e < 1:1
1060
            // TODO Mejorarlo para que los PAN con un zoom muy grande sean correctos
1061
            //System.out.println("MAXX MINX-"+ptMax.x+","+ptMin.x);
1062
            if ((ptMax.x - ptMin.x) < sz.width) {
1063
                numCol = numRow = 1;
1064
                frames = new ChunkFrame[numCol * numRow];
1065
                f = frames[0] = new ChunkFrame(v, ptMax.x - ptMin.x,
1066
                                               ptMin.y - ptMax.y);
1067

    
1068
                //System.out.println("Size=("+f.width+","+f.height+")");
1069
                f.pos = new Point(0, 0);
1070
                f.mustResize = true;
1071
                f.v = new Extent(v);
1072
            } else {
1073
                // Calcula cada chunk
1074
                double stepx = ((double) ptMax.x - ptMin.x) / sz.getWidth();
1075
                double stepy = ((double) ptMax.y - ptMin.y) / sz.getHeight();
1076
                int h = sz.height;
1077

    
1078
                for (int r = 0; r < numRow; r++) {
1079
                    int w = sz.width;
1080

    
1081
                    for (int c = 0; c < numCol; c++) {
1082
                        f = new ChunkFrame(null, -1, -1);
1083

    
1084
                        // Posici?n del chunk
1085
                        f.pos = new Point(c * MAX_WIDTH, r * MAX_HEIGHT);
1086

    
1087
                        // Tama?o del chunk
1088
                        f.width = Math.min(MAX_WIDTH, w);
1089
                        f.height = Math.min(MAX_HEIGHT, h);
1090

    
1091
                        // Extent del chunk
1092
                        int x1 = ptMin.x + (int) (f.pos.x * stepx);
1093
                        int x2 = x1 + (int) (f.width * stepx);
1094
                        int y1 = ptMax.y - (int) (f.pos.y * stepy); //ptMax.y;
1095
                        int y2 = y1 - (int) (f.height * stepy); //ptMin.y;
1096
                        JNCSWorldPoint pt1 = file.convertDatasetToWorld(x1, y1);
1097
                        JNCSWorldPoint pt2 = file.convertDatasetToWorld(x2, y2);
1098
                        f.v = new Extent(pt1.x, pt1.y, pt2.x, pt2.y); // Hay que calcularlo
1099

    
1100
                        /*System.out.println(" View DataSet = ("+x1+","+y1+","+x2+","+y2+")");
1101
                        System.out.println(" View Extent  = "+ v);
1102
                        System.out.println("Frame Extent  = "+ f.v);*/
1103
                        frames[(r * numCol) + c] = f;
1104
                        w -= MAX_WIDTH;
1105
                    }
1106

    
1107
                    h -= MAX_HEIGHT;
1108
                }
1109
            }
1110

    
1111
            //System.out.println("Hay "+numRow+" filas y "+numCol+" columnas.");
1112
            return frames;
1113
        }
1114
    }
1115
}