Statistics
| Revision:

root / trunk / libraries / libCq CMS for java.old / src / org / cresques / io / EcwFile.java @ 8120

History | View | Annotate | Download (43.8 KB)

1 5990 luisw2
/*
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 6650 maquerol
import java.io.File;
32 5990 luisw2
33
import org.cresques.cts.ICoordTrans;
34
import org.cresques.cts.IProjection;
35
import org.cresques.px.Extent;
36
37 6650 maquerol
import com.ermapper.ecw.JNCSException;
38 5990 luisw2
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 6650 maquerol
86 5990 luisw2
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 6650 maquerol
99 6887 nacho
                if (!new File(fName).exists() && !fName.startsWith("ecwp:")){
100 6650 maquerol
                        System.err.println("No se puede abrir el archivo");
101
                        return;
102
                }
103
104 5990 luisw2
            file = new JNCSFile(fName, false);
105 6650 maquerol
                load();
106 5990 luisw2
            //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
        return this;
146
    }
147
148
    public void close() {
149
            if(file != null){
150
                    file.close(true);
151
                    file = null;
152
            }
153
    }
154
155
    /**
156
     * Devuelve el ancho de la imagen
157
     */
158
    public int getWidth() {
159
        return file.width;
160
    }
161
162
    /**
163
     * Devuelve el alto de la imagen
164
     */
165
    public int getHeight() {
166
        return file.height;
167
    }
168
169
    /**
170
     *
171
     */
172
    public void setMultifile(boolean mult) {
173
        this.multifile = mult;
174
    }
175
176
    public void setView(Extent e) {
177
            //Aplicamos la transformaci?n a la vista en caso de que haya un fichero .rmf
178
            /*
179
            if(file.cellIncrementY > 0)
180
                file.cellIncrementY = -file.cellIncrementY;
181
            if(minX < file.originX)
182
                    minX = file.originX;
183
            if(maxY > file.originY)
184
                    maxY = file.originY;
185
            if(maxX > (file.originX + ((double) (file.width - 1) * file.cellIncrementX)))
186
                    maxX = file.originX + ((double) (file.width - 1) * file.cellIncrementX);
187
            if(minY < file.originY + ((double) (file.height - 1) * file.cellIncrementY))
188
                    minY = file.originY + ((double) (file.height - 1) * file.cellIncrementY);
189

190
                Extent transformView = new Extent(        minX, minY, maxX, maxY );*/
191
        v = new Extent(e);
192
    }
193
194
    public Extent getView() {
195
        return v;
196
    }
197
198
    private void setFileView(int numBands, int [] bandList, ChunkFrame f)
199
            throws JNCSFileNotOpenException, JNCSInvalidSetViewException {
200
        file.setView(file.numBands, bandList, f.v.minX(), f.v.maxY(), f.v.maxX(), f.v.minY(), f.width, f.height);
201
    }
202
203
    /**
204
     * Obtiene un trozo de imagen (determinado por la vista y los par?metros.
205
     *
206
     * @param width
207
     * @param height
208
     */
209
    public synchronized Image updateImage(int width, int height, ICoordTrans rp) {
210
        // TODO reproyectar para devolver el trozo de imagen pedida sobre ...
211
        // la proyecci?n de destino.
212
        int line = 0;
213
        boolean mustResize = false;
214
        Dimension fullSize = null;
215
        Image ecwImage = null;
216
217
        if (file == null) {
218
            return ecwImage;
219
        }
220
221
        try {
222
            int[] bandlist;
223
            int[] bandListTriband;
224
            int[] pRGBArray = null;
225
226
            if(mustVerifySize()){
227
            // Work out the correct aspect for the setView call.
228
                    double dFileAspect = (double) v.width() / (double) v.height();
229
                    double dWindowAspect = (double) width / (double) height;
230
231
                    if (dFileAspect > dWindowAspect) {
232
                        height = (int) ((double) width / dFileAspect);
233
                    } else {
234
                        width = (int) ((double) height * dFileAspect);
235
                    }
236
            }
237
            fullSize = new Dimension(width, height);
238
239
            //System.out.println("fullSize = ("+width+","+height+")");
240
            // Peta en los peque?os ... arreglar antes de meter del todo
241
            ChunkFrame[] frames = ChunkFrame.computeFrames(file, v, fullSize, extent);
242
243
            if (frames.length == 1) {
244
                width = frames[0].width;
245
                height = frames[0].height;
246
247
                if (width <= 0) {
248
                    width = 1;
249
                }
250
251
                if (height <= 0) {
252
                    height = 1;
253
                }
254
            }
255
256
            /*                        JNCSDatasetPoint ptMin = file.convertWorldToDataset(v.minX(), v.minY());
257
                                    JNCSDatasetPoint ptMax = file.convertWorldToDataset(v.maxX(), v.maxY());
258
                                    System.out.println("Dataset coords Width = "+(ptMax.x-ptMin.x)+", px width ="+width);
259
                                    // BEGIN Cambiando para soportar e < 1:1
260
                                    // TODO Mejorarlo para que los PAN con un zoom muy grande sean correctos
261
                                    if ((ptMax.x-ptMin.x)<width) {
262
                                            width = ptMax.x-ptMin.x;
263
                                            height = ptMin.y-ptMax.y;
264
                                            System.out.println("Size=("+width+","+height+")");
265
                                            mustResize = true;
266
                                    }*/
267
268
            // Create an image of the ecw file.
269
            if (doTransparency) {
270
                ecwImage = new BufferedImage(width, height,
271
                                             BufferedImage.TYPE_INT_ARGB);
272
            } else {
273
                ecwImage = new BufferedImage(width, height,
274
                                             BufferedImage.TYPE_INT_RGB);
275
            }
276
277
            pRGBArray = new int[width];
278
279
            // Setup the view parameters for the ecw file.
280
            bandlist = new int[bandCount];
281
            bandListTriband = new int[bandCount];
282
283
            if (bandCount > 2) {
284
                bandlist[0] = getBand(RED_BAND);
285
                bandlist[1] = getBand(GREEN_BAND);
286
                bandlist[2] = getBand(BLUE_BAND);
287
288
                if (bandCount > 3) {
289
                    for (int i = 3; i < bandCount; i++) {
290
                        bandlist[i] = 0;
291
                    }
292
                }
293
            } else {
294
                for (int i = 0; i < bandCount; i++) {
295
                    bandlist[i] = i;
296
                }
297
            }
298
299
            if (bandCount == 3) {
300
                bandListTriband[0] = 0;
301
                bandListTriband[1] = 1;
302
                bandListTriband[2] = 2;
303
            }
304
305
            for (int nChunk = 0; nChunk < frames.length; nChunk++) {
306
                ChunkFrame f = frames[nChunk];
307
308
                // Set the view
309
                if (bandCount != 3) {
310
                    setFileView(file.numBands, bandlist, f);
311
                } else {
312
                    setFileView(file.numBands, bandListTriband, f);
313
                }
314
315
                /*
316
                 * Esta peli es porque el Ecw no intercambia las bandas con lo que me toca hacerlo
317
                 * a mano. Primero detectamos si se ha alterado el orden de las mismas. Si es as?
318
                 * calculamos mascaras y desplazamientos y hacemos una copia en pRGBArrayCopy
319
                 * con las bandas alteradas de orden
320
                 */
321
                int[] pRGBArrayCopy = null;
322
                int[] mascara = new int[3];
323
                int[] shl = new int[3];
324
                int[] shr = new int[3];
325
                boolean order = true;
326
327
                if (bandCount == 3) {
328
                    for (int i = 0; i < bandCount; i++)
329
                        if (bandlist[i] != i) {
330
                            order = false;
331
                        }
332
333
                    if (!order) {
334
                        for (int i = 0; i < bandCount; i++) {
335
                            switch (bandlist[i]) {
336
                            case 0:
337
                                mascara[i] = 0x00ff0000;
338
                                break;
339
                            case 1:
340
                                mascara[i] = 0x0000ff00;
341
                                break;
342
                            case 2:
343
                                mascara[i] = 0x000000ff;
344
                                break;
345
                            }
346
                            if ((i == 1) && (bandlist[i] == 0))
347
                                shr[i] = 8;
348
                            if ((i == 2) && (bandlist[i] == 0))
349
                                shr[i] = 16;
350
                            if ((i == 0) && (bandlist[i] == 1))
351
                                shl[i] = 8;
352
                            if ((i == 2) && (bandlist[i] == 1))
353
                                shr[i] = 8;
354
                            if ((i == 0) && (bandlist[i] == 2))
355
                                shl[i] = 16;
356
                            if ((i == 1) && (bandlist[i] == 2))
357
                                shl[i] = 8;
358
                        }
359
                    }
360
                }
361
362
                // Read the scan lines
363
                for (line = 0; line < f.height; line++) {
364
                    file.readLineRGBA(pRGBArray);
365
366
                    if ((bandCount == 3) && !order) {
367
                        pRGBArrayCopy = new int[pRGBArray.length];
368
369
                        for (int i = 0; i < pRGBArray.length; i++) {
370
                            pRGBArrayCopy[i] = (pRGBArray[i] & 0xff000000) +
371
                                               (((pRGBArray[i] & mascara[2]) << shl[2]) >> shr[2]) +
372
                                               (((pRGBArray[i] & mascara[1]) << shl[1]) >> shr[1]) +
373
                                               (((pRGBArray[i] & mascara[0]) << shl[0]) >> shr[0]);
374
                        }
375
376
                        pRGBArray = pRGBArrayCopy;
377
                    }
378
379
                    // Prueba de sustituci?n de color transparente
380
                    if (doTransparency) {
381
                        if (line == 0) {
382
                            tFilter.debug = true;
383
                        }
384
385
                        tFilter.filterLine(pRGBArray);
386
                        tFilter.debug = false;
387
                    }
388
389
                    ((BufferedImage) ecwImage).setRGB(f.pos.x, f.pos.y + line,
390
                                                      f.width, 1, pRGBArray, 0,
391
                                                      f.width);
392
                }
393
            }
394
395
            if (frames[0].mustResize) {
396
                //System.out.println("resize "+fullSize);
397
                return resizeImage(fullSize, ecwImage);
398
            }
399
400
            /*
401
             * La excepci?n atrapada es la de 'zoom > 1:1 no valido'
402
            } catch (com.ermapper.ecw.JNCSInvalidSetViewException e) {
403
                    System.err.println(errorMessage);
404
                    e.printStackTrace(); */
405
        } catch (com.ermapper.ecw.JNCSException e) { //java.lang.ArrayIndexOutOfBoundsException:
406
            bErrorOnOpen = true;
407
            System.err.println("EcwFile JNCS Error en la l?nea " + line + "/" +
408
                               height);
409
            System.err.println(e.getMessage());
410
            e.printStackTrace();
411
        } catch (java.lang.ArrayIndexOutOfBoundsException e) { //:
412
            bErrorOnOpen = true;
413
            System.err.println("EcwFile ArrayIndex Error en la l?nea " + line +
414
                               "/" + height);
415
            System.err.println(e.getMessage());
416
            e.printStackTrace();
417
        } catch (Exception e) {
418
            bErrorOnOpen = true;
419
            errorMessage = e.getMessage();
420
421
            //                        g.drawString(errorMessage, 0, 50);
422
            System.err.println(errorMessage);
423
            e.printStackTrace();
424
        }
425
426
        lastRefreshPercent = file.getPercentComplete();
427
        System.out.println("Leido al " + lastRefreshPercent + " %.");
428
429
        return ecwImage;
430
    }
431
432
    /**
433
     * Redimensionado de imagen
434
     * La funci?n getScaledInstance nos devuelve un tipo image que no sirve por lo que
435
     * habr? que crear  buffImg como BufferedImage y copiar los datos devueltos por esta
436
     * funci?n a este que es el que ser? devuelto por la funci?n
437
     * @param sz
438
     * @param image        Image de entrada
439
     * @return        Imagen reescalada
440
     */
441
    private Image resizeImage(Dimension sz, Image image) {
442
        Image buffImg = null;
443
        Image img = image.getScaledInstance((int) sz.getWidth(),
444
                                            (int) sz.getHeight(),
445
                                            Image.SCALE_SMOOTH);
446
447
        //Todo este pollo es para copiar el tipo image devuelto a BufferedImage
448
        buffImg = new BufferedImage(img.getWidth(null), img.getHeight(null),
449
                                    BufferedImage.TYPE_INT_ARGB);
450
451
        int[] pixels = new int[img.getWidth(null) * img.getHeight(null)];
452
        PixelGrabber pg = new PixelGrabber(img, 0, 0, img.getWidth(null),
453
                                           img.getHeight(null), pixels, 0,
454
                                           img.getWidth(null));
455
456
        try {
457
            pg.grabPixels();
458
        } catch (InterruptedException e) {
459
            e.printStackTrace();
460
        }
461
462
        for (int j = 0; j < buffImg.getHeight(null); j++) {
463
            for (int i = 0; i < buffImg.getWidth(null); i++) {
464
                ((BufferedImage) buffImg).setRGB(i, j,
465
                                                 pixels[(j * buffImg.getWidth(null)) +
466
                                                 i]);
467
            }
468
        }
469
470
        return buffImg;
471
    }
472
473
    /**
474
     * Reproyecta el raster.
475
     */
476
    public void reProject(ICoordTrans rp) {
477
        // TODO metodo reProject pendiente de implementar
478
    }
479
480
    /**
481
     * Soporte para actualizaci?n de la imagen
482
     * @see com.ermapper.ecw.JNCSProgressiveUpdate#refreshUpdate(int, int, double, double, double, double)
483
     */
484
    public void refreshUpdate(int nWidth, int nHeight, double dWorldTLX,
485
                              double dWorldTLY, double dWorldBRX,
486
                              double dWorldBRY) {
487
        int completado = file.getPercentComplete();
488
        System.out.println("EcwFile: se actualiza 1: " + completado +
489
                           " % completado");
490
491
        if ((updatable != null) && (lastRefreshPercent < 100)) {
492
            if (((completado - lastRefreshPercent) > 25) ||
493
                    (completado == 100)) {
494
                lastRefreshPercent = file.getPercentComplete();
495
                updatable.repaint();
496
            }
497
        }
498
    }
499
500
    public void refreshUpdate(int nWidth, int nHeight, int dDatasetTLX,
501
                              int dDatasetTLY, int dDatasetBRX, int dDatasetBRY) {
502
        System.out.println("EcwFile: se actualiza 2");
503
    }
504
505
    /**
506
     *  Esta funci?n es porque el Ecw no intercambia las bandas con lo que me toca hacerlo
507
     * a mano. Primero detectamos si se ha alterado el orden de las mismas. Si es as?
508
     * calculamos mascaras y desplazamientos y hacemos una copia en pRGBArrayCopy
509
     * con las bandas alteradas de orden
510
     * @param bandList        lista de bandas
511
     * @param mask mascara
512
     * @param shl desplazamiento izquierda
513
     * @param shr desplazamiento derecha
514
     */
515
    private boolean calcMaskAndShift(int[] bandList, int[] mask, int[] shl,
516
                                     int[] shr) {
517
        boolean order = true;
518
519
        if (bandCount == 3) {
520
            for (int i = 0; i < bandCount; i++)
521
                if (bandList[i] != i) {
522
                    order = false;
523
                }
524
525
            if (!order) {
526
                for (int i = 0; i < bandCount; i++) {
527
                    switch (bandList[i]) {
528
                    case 0:
529
                        mask[i] = 0x00ff0000;
530
                        break;
531
                    case 1:
532
                        mask[i] = 0x0000ff00;
533
                        break;
534
                    case 2:
535
                        mask[i] = 0x000000ff;
536
                        break;
537
                    }
538
539
                    if ((i == 1) && (bandList[i] == 0))
540
                        shr[i] = 8;
541
                    if ((i == 2) && (bandList[i] == 0))
542
                        shr[i] = 16;
543
                    if ((i == 0) && (bandList[i] == 1))
544
                        shl[i] = 8;
545
                    if ((i == 2) && (bandList[i] == 1))
546
                        shr[i] = 8;
547
                    if ((i == 0) && (bandList[i] == 2))
548
                        shl[i] = 16;
549
                    if ((i == 1) && (bandList[i] == 2))
550
                        shl[i] = 8;
551
                }
552
            }
553
        }
554
555
        return order;
556
    }
557
558
    /**
559
     * Intercambio de bandas para ecw manual. Se le pasa el array de bytes que se desea intercambiar
560
     * la mascara y desplazamientos previamente calculados con calcMaskAndShift
561
     * @param order        true si el orden de las bandas no est? alterado y false si lo est?
562
     * @param pRGBArray array de
563
     * @param mascara
564
     * @param shl desplazamiento a izquierda
565
     * @param shr desplazamiento a derecha
566
     * @return array con las bandas cambiadas
567
     */
568
    private int[] changeBands(boolean order, int[] pRGBArray, int[] mascara,
569
                              int[] shl, int[] shr) {
570
        if ((bandCount == 3) && !order) {
571
            int[] pRGBArrayCopy = new int[pRGBArray.length];
572
573
            for (int i = 0; i < pRGBArray.length; i++) {
574
                pRGBArrayCopy[i] = (pRGBArray[i] & 0xff000000) +
575
                                   (((pRGBArray[i] & mascara[2]) << shl[2]) >> shr[2]) +
576
                                   (((pRGBArray[i] & mascara[1]) << shl[1]) >> shr[1]) +
577
                                   (((pRGBArray[i] & mascara[0]) << shl[0]) >> shr[0]);
578
            }
579
580
            return pRGBArrayCopy;
581
        }
582
583
        return pRGBArray;
584
    }
585
586
    /**
587
     * Asigna al objeto Image los valores con los dato de la imagen contenidos en el
588
     * vector de enteros.
589
     * @param image        imagen con los datos actuales
590
     * @param startX        inicio de la posici?n en X dentro de la imagen
591
     * @param startY        inicio de la posici?n en X dentro de la imagen
592
     * @param w        Ancho de la imagen
593
     * @param h        Alto de la imagen
594
     * @param rgbArray        vector que contiene la banda que se va a sustituir
595
     * @param offset        desplazamiento
596
     * @param scansize        tama?o de imagen recorrida por cada p
597
     */
598
    protected void setRGBLine(BufferedImage image, int startX, int startY,
599
                              int w, int h, int[] rgbArray, int offset,
600
                              int scansize) {
601
        image.setRGB(startX, startY, w, h, rgbArray, offset, scansize);
602
    }
603
604
    /**
605
     * Asigna al objeto Image la mezcla entre los valores que ya tiene y los valores
606
     * con los dato de la imagen contenidos en el vector de enteros. De los valores RGB
607
     * que ya contiene se mantienen las bandas que no coinciden con el valor de flags. La
608
     * banda correspondiente a flags es sustituida por los datos del vector.
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 paso
617
     * @param flags        banda que se va a sustituir (Ctes de GeoRasterFile)
618
     */
619
    protected void setRGBLine(BufferedImage image, int startX, int startY,
620
                              int w, int h, int[] rgbArray, int offset,
621
                              int scansize, int flags) {
622
        int[] line = new int[rgbArray.length];
623
        image.getRGB(startX, startY, w, h, line, offset, scansize);
624
625
        if (flags == GeoRasterFile.RED_BAND) {
626
            for (int i = 0; i < line.length; i++)
627
                line[i] = (line[i] & 0x0000ffff) | (rgbArray[i] & 0xffff0000);
628
        } else if (flags == GeoRasterFile.GREEN_BAND) {
629
            for (int i = 0; i < line.length; i++)
630
                line[i] = (line[i] & 0x00ff00ff) | (rgbArray[i] & 0xff00ff00);
631
        } else if (flags == GeoRasterFile.BLUE_BAND) {
632
            for (int i = 0; i < line.length; i++)
633
                line[i] = (line[i] & 0x00ffff00) | (rgbArray[i] & 0xff0000ff);
634
        }
635
636
        image.setRGB(startX, startY, w, h, line, offset, scansize);
637
    }
638
639
    /**
640
     * Asigna al objeto Image la mezcla entre los valores que ya tiene y los valores
641
     * con los dato de la imagen contenidos en el vector de enteros. De los valores RGB
642
     * que ya contiene se mantienen las bandas que no coinciden con el valor de flags. La
643
     * banda correspondiente a flags es sustituida por los datos del vector.
644
     * @param image        imagen con los datos actuales
645
     * @param startX        inicio de la posici?n en X dentro de la imagen
646
     * @param startY        inicio de la posici?n en X dentro de la imagen
647
     * @param w        Ancho de la imagen
648
     * @param h        Alto de la imagen
649
     * @param rgbArray        vector que contiene la banda que se va a sustituir
650
     * @param offset        desplazamiento
651
     * @param scansize        tama?o de imagen recorrida por cada paso
652
     * @param origBand        Banda origen del GeoRasterFile
653
     * @param destBandFlag        banda que se va a sustituir (Ctes de GeoRasterFile)
654
     */
655
    protected void setRGBLine(BufferedImage image, int startX, int startY,
656
                              int w, int h, int[] rgbArray, int offset,
657
                              int scansize, int origBand, int destBandFlag) {
658
        int[] line = new int[rgbArray.length];
659
        image.getRGB(startX, startY, w, h, line, offset, scansize);
660
661
        if ((origBand == 0) && (destBandFlag == GeoRasterFile.RED_BAND)) {
662
            for (int i = 0; i < line.length; i++)
663
                line[i] = (line[i] & 0xff00ffff) | (rgbArray[i] & 0x00ff0000);
664
        } else if ((origBand == 1) &&
665
                       (destBandFlag == GeoRasterFile.GREEN_BAND)) {
666
            for (int i = 0; i < line.length; i++)
667
                line[i] = (line[i] & 0xffff00ff) | (rgbArray[i] & 0x0000ff00);
668
        } else if ((origBand == 2) &&
669
                       (destBandFlag == GeoRasterFile.BLUE_BAND)) {
670
            for (int i = 0; i < line.length; i++)
671
                line[i] = (line[i] & 0xffffff00) | (rgbArray[i] & 0x000000ff);
672
        }
673
        else if ((origBand == 0) && (destBandFlag == GeoRasterFile.GREEN_BAND)) {
674
            for (int i = 0; i < line.length; i++)
675
                line[i] = (line[i] & 0xffff00ff) |
676
                          ((rgbArray[i] & 0x00ff0000) >> 8);
677
        } else if ((origBand == 0) &&
678
                       (destBandFlag == GeoRasterFile.BLUE_BAND)) {
679
            for (int i = 0; i < line.length; i++)
680
                line[i] = (line[i] & 0xffffff00) |
681
                          ((rgbArray[i] & 0x00ff0000) >> 16);
682
        }
683
        else if ((origBand == 1) && (destBandFlag == GeoRasterFile.RED_BAND)) {
684
            for (int i = 0; i < line.length; i++)
685
                line[i] = (line[i] & 0xff00ffff) |
686
                          ((rgbArray[i] & 0x0000ff00) << 8);
687
        } else if ((origBand == 1) &&
688
                       (destBandFlag == GeoRasterFile.BLUE_BAND)) {
689
            for (int i = 0; i < line.length; i++)
690
                line[i] = (line[i] & 0xffffff00) |
691
                          ((rgbArray[i] & 0x0000ff00) >> 8);
692
        }
693
        else if ((origBand == 2) && (destBandFlag == GeoRasterFile.RED_BAND)) {
694
            for (int i = 0; i < line.length; i++)
695
                line[i] = (line[i] & 0xff00ffff) |
696
                          ((rgbArray[i] & 0x000000ff) << 16);
697
        } else if ((origBand == 2) &&
698
                       (destBandFlag == GeoRasterFile.GREEN_BAND)) {
699
            for (int i = 0; i < line.length; i++)
700
                line[i] = (line[i] & 0xffff00ff) |
701
                          ((rgbArray[i] & 0x000000ff) << 8);
702
        }
703
704
        image.setRGB(startX, startY, w, h, line, offset, scansize);
705
    }
706
707
708
    /* (non-Javadoc)
709
     * @see org.cresques.io.GeoRasterFile#updateImage(int, int, org.cresques.cts.ICoordTrans, java.awt.Image, int origBand, int destBand)
710
     */
711
    public Image updateImage(int width, int height, ICoordTrans rp, Image img,
712
                             int origBand, int destBandFlag) throws SupersamplingNotSupportedException{
713
        //TODO reproyectar para devolver el trozo de imagen pedida sobre ...
714
        // la proyecci?n de destino.
715
        int line = 0;
716
        boolean mustResize = false;
717
        Dimension fullSize = null;
718
        boolean trySupersampling = false;
719
720
        if (file == null) {
721
            return null;
722
        }
723
724
        try {
725
            int[] bandlist;
726
            int[] bandListTriband;
727
            int[] pRGBArray = null;
728
729
            if(mustVerifySize()){
730
                    // Work out the correct aspect for the setView call.
731
                    double dFileAspect = (double) v.width() / (double) v.height();
732
                    double dWindowAspect = (double) width / (double) height;
733
734
                    if (dFileAspect > dWindowAspect) {
735
                        height = (int) ((double) width / dFileAspect);
736
                    } else {
737
                        width = (int) ((double) height * dFileAspect);
738
                    }
739
            }
740
741
            fullSize = new Dimension(width, height);
742
743
            ChunkFrame[] frames = ChunkFrame.computeFrames(file, v, fullSize, extent);
744
745
            if (frames.length == 1) {
746
                width = frames[0].width;
747
                height = frames[0].height;
748
749
                if (width <= 0)
750
                    width = 1;
751
752
                if (height <= 0)
753
                    height = 1;
754
            }
755
756
            // Create an image of the ecw file.
757
            pRGBArray = new int[width];
758
759
            // Setup the view parameters for the ecw file.
760
            bandlist = new int[bandCount];
761
            bandListTriband = new int[bandCount];
762
763
            if (bandCount > 2) {
764
                bandlist[0] = getBand(RED_BAND);
765
                bandlist[1] = getBand(GREEN_BAND);
766
                bandlist[2] = getBand(BLUE_BAND);
767
768
                if (bandCount > 3) {
769
                    for (int i = 3; i < bandCount; i++) {
770
                        bandlist[i] = 0;
771
                    }
772
                }
773
            } else {
774
                for (int i = 0; i < bandCount; i++)
775
                    bandlist[i] = i;
776
            }
777
778
            if (bandCount == 3) {
779
                bandListTriband[0] = 0;
780
                bandListTriband[1] = 1;
781
                bandListTriband[2] = 2;
782
            }
783
784
            int[] mascara = new int[3];
785
            int[] shl = new int[3];
786
            int[] shr = new int[3];
787
            boolean order = true;
788
789
            if (img == null) { //Caso en el que se crea un Image
790
                EcwFile.nUpdate = 1;
791
792
                Image ecwImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
793
794
                for (int nChunk = 0; nChunk < frames.length; nChunk++) {
795
                    ChunkFrame f = frames[nChunk];
796
797
                    try{
798
                            if (bandCount != 3) {
799
                                setFileView(file.numBands, bandlist, f);
800
                            } else {
801
                                setFileView(file.numBands, bandListTriband, f);
802
                            }
803
                    }catch(JNCSInvalidSetViewException exc){
804
                            trySupersampling = true;
805
                    }
806
807
                    order = calcMaskAndShift(bandlist, mascara, shl, shr);
808
809
                    for (line = 0; line < f.height; line++) {
810
                        file.readLineRGBA(pRGBArray);
811
                        pRGBArray = changeBands(order, pRGBArray, mascara, shl, shr);
812
                        setRGBLine((BufferedImage) ecwImage, f.pos.x, f.pos.y + line, f.width, 1, pRGBArray, 0, f.width);
813
                    }
814
                } //Chuncks
815
816
                applyAlpha(ecwImage);
817
818
                if (frames[0].mustResize && !this.multifile)
819
                    return resizeImageII(fullSize, ecwImage);
820
821
                lastRefreshPercent = file.getPercentComplete();
822
823
                //System.out.println("Leido al "+lastRefreshPercent+" %.");
824
                return ecwImage;
825
            } else { //Caso en el que se actualiza una banda del Image
826
                EcwFile.nUpdate++;
827
828
                for (int nChunk = 0; nChunk < frames.length; nChunk++) {
829
                    ChunkFrame f = frames[nChunk];
830
831
                    if (bandCount != 3) {
832
                        setFileView(file.numBands, bandlist, f);
833
                    } else {
834
                        setFileView(file.numBands, bandListTriband, f);
835
                    }
836
837
                    order = calcMaskAndShift(bandlist, mascara, shl, shr);
838
839
                    for (line = 0; line < f.height; line++) {
840
                        file.readLineRGBA(pRGBArray);
841
                        pRGBArray = changeBands(order, pRGBArray, mascara, shl, shr);
842
                        setRGBLine((BufferedImage) img, f.pos.x, f.pos.y + line, f.width, 1, pRGBArray, 0, f.width, origBand, destBandFlag);
843
                    }
844
                } //Chuncks
845
846
                applyAlpha(img);
847
848
                if (frames[0].mustResize && (nUpdate == 3) && this.multifile) {
849
                    return resizeImageII(fullSize, img);
850
                }
851
852
                lastRefreshPercent = file.getPercentComplete();
853
854
                //System.out.println("Leido al "+lastRefreshPercent+" %.");
855
                return img;
856
            }
857
        } catch (com.ermapper.ecw.JNCSException e) { //java.lang.ArrayIndexOutOfBoundsException:
858
            bErrorOnOpen = true;
859
            System.err.println("EcwFile JNCS Error en la l?nea " + line + "/" +
860
                               height);
861
            System.err.println(e.getMessage());
862
        } catch (java.lang.ArrayIndexOutOfBoundsException e) { //:
863
            bErrorOnOpen = true;
864
            System.err.println("EcwFile ArrayIndex Error en la l?nea " + line +"/" + height);
865
            System.err.println(e.getMessage());
866
        } catch (Exception e) {
867
            bErrorOnOpen = true;
868
            errorMessage = e.getMessage();
869
            System.err.println(errorMessage);
870
            if(trySupersampling)
871
                    throw new SupersamplingNotSupportedException();
872
        }
873
874
        return img;
875
    }
876
877
    private Image resizeImageII(Dimension sz, Image image) {
878
        int w = (int)sz.getWidth();
879
        int h = (int)sz.getHeight();
880
            Image buffImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
881
882
        //Desplazamiento para la X y la Y leidas. Estas tienen efecto cuando un pixel no empieza a visualizarse
883
        //justo en su esquina superior izquierda y tiene que ser cortado en la visualizaci?n.
884
885
        double currentViewX = (((double) file.width)/(Math.abs(extent.getMax().getX() - extent.getMin().getX())))*(v.minX()-file.originX);
886
                double currentViewY = (((double) file.height)/(Math.abs(extent.getMax().getY() - extent.getMin().getY())))*(file.originY - v.minY());
887
        double offsetX = Math.abs(currentViewX - ((int)currentViewX));
888
        double offsetY = Math.abs(currentViewY - ((int)currentViewY));
889
890
        int xSrc, ySrc;
891
        int decr = 2;
892
893
        if(v.minX() == extent.minX() || v.maxX() == extent.maxX() || v.minY() == extent.minY() || v.maxY() == extent.maxY()){
894
                decr = 0;
895
                offsetX = offsetY = 0;
896
        }
897
898
        double scaleW = (double)((double)(image.getWidth(null) - decr) / (double)w);
899
        double scaleH = (double)((double)(image.getHeight(null) - decr) / (double)h);
900
        for (int y1 = 0; y1 < h; y1++){
901
        ySrc = (int) ((y1 * scaleH) + offsetY);
902
                for (int x1 = 0; x1 < w; x1++){
903
                        xSrc = (int) ((x1 * scaleW) + offsetX);
904
                        try {
905
                                ((BufferedImage) buffImg).setRGB(x1, y1, ((BufferedImage)image).getRGB(xSrc, ySrc));
906
                        } catch (java.lang.ArrayIndexOutOfBoundsException e) {
907
                        }
908
                }
909
        }
910
911
        return buffImg;
912
    }
913
914
915
    private void applyAlpha(Image im) {
916
        BufferedImage img = (BufferedImage) im;
917
        int alpha = (getAlpha() & 0xff) << 24;
918
        int w = img.getWidth();
919
        int[] line = new int[w];
920
921
        for (int j = 0; j < img.getHeight(); j++) {
922
            img.getRGB(0, j, w, 1, line, 0, w);
923
924
            for (int i = 0; i < w; i++)
925
                line[i] = (alpha | (line[i] & 0x00ffffff));
926
927
            img.setRGB(0, j, w, 1, line, 0, w);
928
        }
929
    }
930
931
    /* (non-Javadoc)
932
     * @see org.cresques.io.GeoRasterFile#getData(int, int)
933
     */
934
    public Object getData(int x, int y, int band) {
935
        //file.readLineRGBA();
936
        return null;
937
    }
938
939
    /**
940
     * Devuelve los datos de una ventana solicitada
941
     * @param ulX        coordenada X superior izda.
942
     * @param ulY        coordenada Y superior derecha.
943
     * @param sizeX        tama?o en X de la ventana.
944
     * @param sizeY tama?o en Y de la ventana.
945
     * @param band        Banda solicitada.
946
     */
947
    public byte[] getWindow(int ulX, int ulY, int sizeX, int sizeY, int band) {
948
        //TODO Nacho: Implementar getWindow de EcwFile
949
        return null;
950
    }
951
952
    /**
953
     * Obtiene la zona (Norte / Sur)
954
     * @return true si la zona es norte y false si es sur
955
     */
956
    public boolean getZone() {
957
        //TODO Nacho: Implementar getZone de EcwFile
958
        return false;
959
    }
960
961
    /**
962
     *Devuelve el n?mero de zona UTM
963
     *@return N?mero de zona
964
     */
965
    public int getUTM() {
966
        //                TODO Nacho: Implementar getUTM de EcwFile
967
        return 0;
968
    }
969
970
    /**
971
     * Obtiene el sistema de coordenadas geograficas
972
     * @return Sistema de coordenadas geogr?ficas
973
     */
974
    public String getGeogCS() {
975
        //TODO Nacho: Implementar getGeogCS de EcwFile
976
        return new String("");
977
    }
978
979
    /**
980
     * Devuelve el tama?o de bloque
981
     * @return Tama?o de bloque
982
     */
983
    public int getBlockSize() {
984
        //TODO Nacho: Implementar getBlockSize de EcwFile
985
        return 1;
986
    }
987
988
    /**
989
         * Calcula la transformaci?n que se produce sobre la vista cuando la imagen tiene un fichero .rmf
990
         * asociado. En Ecw el origen de coordenadas en Y es el valor m?ximo y decrece hasta el m?nimo.
991
         * @param originX Origen de la imagen en la coordenada X
992
         * @param originY Origen de la imagen en la coordenada Y
993
         */
994
    public void setExtentTransform(double originX, double originY, double w, double h, double psX, double psY) {
995
996
        }
997
998
    /**
999
     * Trozo de imagen (Chunk) en que se divide la consulta a la librer?a,
1000
     * para esquivar el bug#2.
1001
     *
1002
     * @author luisw
1003
     */
1004
    static class ChunkFrame {
1005
        // Ancho m?ximo (~2500 px)
1006
        final static int MAX_WIDTH = 1536;
1007
1008
        // Alto m?ximo (no hay l?mite)
1009
        final static int MAX_HEIGHT = 1536;
1010
        Point pos;
1011
        Extent v;
1012
        int width;
1013
        int height;
1014
        boolean mustResize = false;
1015
1016
        public ChunkFrame(Extent vista, int w, int h) {
1017
            v = vista;
1018
            width = w;
1019
            height = h;
1020
        }
1021
1022
        /**
1023
         * Calcula el array de chunks (trozos).
1024
         * @param file        Fichero ecw que hay que trocear.
1025
         * @param v Extent total de la vista.
1026
         * @param sz        Tama?o total de la vista.
1027
         * @return array de ChunkFrames.
1028
         * @throws JNCSFileNotOpenException
1029
         */
1030
        public static ChunkFrame[] computeFrames(JNCSFile file, Extent v,
1031
                                                 Dimension sz, Extent extent)
1032
                                          throws JNCSFileNotOpenException {
1033
            ChunkFrame[] frames = null;
1034
            ChunkFrame f = null;
1035
1036
            // Calcula el n? de chunks (filas y columnas)
1037
            int numCol = (sz.width / MAX_WIDTH);
1038
1039
            // Calcula el n? de chunks (filas y columnas)
1040
            int numRow = (sz.height / MAX_HEIGHT);
1041
1042
            if ((sz.width - (numCol * MAX_WIDTH)) > 0) {
1043
                numCol++;
1044
            }
1045
1046
            if ((sz.height - (numRow * MAX_HEIGHT)) > 0) {
1047
                numRow++;
1048
            }
1049
1050
            frames = new ChunkFrame[numCol * numRow];
1051
1052
            JNCSDatasetPoint ptMin = file.convertWorldToDataset(v.minX(), v.minY());
1053
            JNCSDatasetPoint ptMax = file.convertWorldToDataset(v.maxX(), v.maxY());
1054
1055
            //No utilizamos JNCSDatasetPoint porque siempre hace un redondeo por abajo con lo que perdemos precisi?n. En su lugar
1056
            //utilizamos currentViewM... calculado manualmente y que nos proporciona todos los decimales
1057
            double currentViewMinX = (((double) file.width)/(Math.abs(extent.getMax().getX() - extent.getMin().getX())))*(v.minX()-file.originX);
1058
            double currentViewMaxX = (((double) file.width)/(Math.abs(extent.getMax().getX() - extent.getMin().getX())))*(v.maxX()-file.originX);
1059
                    double currentViewMinY = (((double) file.height)/(Math.abs(extent.getMax().getY() - extent.getMin().getY())))*(file.originY - v.minY());
1060
                    double currentViewMaxY = (((double) file.height)/(Math.abs(extent.getMax().getY() - extent.getMin().getY())))*(file.originY - v.maxY());
1061
1062
            if ((ptMax.x - ptMin.x) < sz.width) {
1063
                numCol = numRow = 1;
1064
                frames = new ChunkFrame[numCol * numRow];
1065
                int nPixelsX = (int)Math.ceil(Math.abs(currentViewMaxX - currentViewMinX));
1066
                int nPixelsY = (int)Math.ceil(Math.abs(currentViewMaxY - currentViewMinY));
1067
1068
                if(v.minX() == extent.minX() || v.maxX() == extent.maxX() || v.minY() == extent.minY() || v.maxY() == extent.maxY()){
1069
                        f = frames[0] = new ChunkFrame(v, nPixelsX, nPixelsY);
1070
                        f.v = new Extent(v);
1071
                }else{
1072
                        f = frames[0] = new ChunkFrame(v, nPixelsX + 1, nPixelsY + 1);
1073
                        double pointEndWcX = v.minX() + (((nPixelsX + 1) * Math.abs(v.maxX() - v.minX())) / nPixelsX);
1074
                        double pointEndWcY = v.maxY() - (((nPixelsY + 1) * Math.abs(v.maxY() - v.minY())) / nPixelsY);
1075
                        f.v = new Extent(v.minX(), v.maxY(), pointEndWcX, pointEndWcY);
1076
                }
1077
1078
                f.pos = new Point(0, 0);
1079
                f.mustResize = true;
1080
            } else {
1081
                // Calcula cada chunk
1082
                double stepx = ((double) ptMax.x - ptMin.x) / sz.getWidth();
1083
                double stepy = ((double) ptMax.y - ptMin.y) / sz.getHeight();
1084
                int h = sz.height;
1085
1086
                for (int r = 0; r < numRow; r++) {
1087
                    int w = sz.width;
1088
1089
                    for (int c = 0; c < numCol; c++) {
1090
                        f = new ChunkFrame(null, -1, -1);
1091
1092
                        // Posici?n del chunk
1093
                        f.pos = new Point(c * MAX_WIDTH, r * MAX_HEIGHT);
1094
1095
                        // Tama?o del chunk
1096
                        f.width = Math.min(MAX_WIDTH, w);
1097
                        f.height = Math.min(MAX_HEIGHT, h);
1098
1099
                        // Extent del chunk
1100
                        int x1 = ptMin.x + (int) (f.pos.x * stepx);
1101
                        int x2 = x1 + (int) (f.width * stepx);
1102
                        int y1 = ptMax.y - (int) (f.pos.y * stepy);
1103
                        int y2 = y1 - (int) (f.height * stepy); //ptMin.y;
1104
                        JNCSWorldPoint pt1 = file.convertDatasetToWorld(x1, y1);
1105
                        JNCSWorldPoint pt2 = file.convertDatasetToWorld(x2, y2);
1106
1107
                        f.v = new Extent(pt1.x, pt1.y, pt2.x, pt2.y); // Hay que calcularlo
1108
                        frames[(r * numCol) + c] = f;
1109
                        w -= MAX_WIDTH;
1110
                    }
1111
1112
                    h -= MAX_HEIGHT;
1113
                }
1114
            }
1115
1116
            //System.out.println("Hay "+numRow+" filas y "+numCol+" columnas.");
1117
            return frames;
1118
        }
1119
    }
1120
}