svn-gvsig-desktop / branches / CqCMSDvp / libraries / libCq CMS for java.old / src / org / cresques / io / EcwFile.java @ 2185
History | View | Annotate | Download (29.8 KB)
1 |
/*
|
---|---|
2 |
* EcwFile.java
|
3 |
*/
|
4 |
package org.cresques.io; |
5 |
|
6 |
import java.awt.Dimension; |
7 |
import java.awt.Image; |
8 |
import java.awt.Point; |
9 |
import java.awt.image.BufferedImage; |
10 |
import java.awt.image.PixelGrabber; |
11 |
|
12 |
import com.ermapper.ecw.JNCSFile; |
13 |
import com.ermapper.ecw.JNCSFileNotOpenException; |
14 |
import com.ermapper.ecw.JNCSProgressiveUpdate; |
15 |
import com.ermapper.util.JNCSDatasetPoint; |
16 |
import com.ermapper.util.JNCSWorldPoint; |
17 |
import com.ermapper.ecw.JNCSException; |
18 |
|
19 |
import es.gva.cit.jmrsid.LTIMetadataRecord; |
20 |
import es.gva.cit.jmrsid.MrSIDException; |
21 |
|
22 |
import org.cresques.cts.ICoordTrans; |
23 |
import org.cresques.cts.IProjection; |
24 |
import org.cresques.px.*; |
25 |
|
26 |
|
27 |
/**
|
28 |
* Soporte para los ficheros .ecw de ErMapper.
|
29 |
* <br>
|
30 |
* NOTA: El SDK que ermapper ha puesto a disposici?n del p?blico en java
|
31 |
* es una versi?n 2.45, de 19/11/2001. Est? implementada usando JNI que
|
32 |
* se apoya en tres librer?as din?micas (dll), y presenta deficiencias
|
33 |
* muy graves a la hora de acceder a la informaci?n. Hasta el momento
|
34 |
* hemos detectado 3 de ellas:<BR>
|
35 |
* 1?.- No soporta ampliaciones superiores a 1:1. si se intenta acceder
|
36 |
* a un ecw con un zoom mayor da una excepci?n del tipo
|
37 |
* com.ermapper.ecw.JNCSInvalidSetViewException, que de no ser tenida encuenta
|
38 |
* acaba tirando abajo la m?quina virtual de java.<BR>
|
39 |
* 2?.- La longitud m?xima de l?nea que adminte el m?todo readLineRGBA es
|
40 |
* de unos 2500 pixeles, lo que hace el uso para la impresi?n en formatos
|
41 |
* superiorea a A4 a 300 ppp o m?s inviable.<BR>
|
42 |
* 3?.- La actualizaci?n progresiva usando el interface JNCSProgressiveUpdate
|
43 |
* con el JNCSFile hace que el equipo genere un error severo y se apague. Este
|
44 |
* error imposibilita esta t?cnica de acceso a ECW.<BR>
|
45 |
* <br>
|
46 |
* Para saltarnos la limitaci?n del bug#1 pedimos la ventana correspondiente al zoom 1:1 para
|
47 |
* el view que nos han puesto, y la resizeamos al tama?o que nos pide el usuario.<br>
|
48 |
* Como consecuencia del bug#2, para tama?os de ventana muy grandes (los necesarios
|
49 |
* para imprimir a m?s de A4 a 300DPI), hay que hacer varias llamadas al fichero con
|
50 |
* varios marcos contiguos, y los devolvemos 'pegados' en una sola imagen (esto se
|
51 |
* realiza de manera transparente para el usuario dentro de la llamada a updateImage.<br>
|
52 |
*
|
53 |
* @author "Luis W. Sevilla" <sevilla_lui@gva.es>
|
54 |
*/
|
55 |
|
56 |
public class EcwFile extends GeoRasterFile implements JNCSProgressiveUpdate { |
57 |
private JNCSFile file = null; |
58 |
private boolean bErrorOnOpen = false; |
59 |
private String errorMessage = null; |
60 |
|
61 |
private Extent v = null; |
62 |
|
63 |
// Ultimo porcentaje de refresco. Se carga en el update y se
|
64 |
// actualiza en el refreshUpdate
|
65 |
private int lastRefreshPercent = 0; |
66 |
|
67 |
public EcwFile(IProjection proj, String fName) { |
68 |
super(proj, null); |
69 |
fName = DataSource.normalize(fName);
|
70 |
super.setName(fName);
|
71 |
extent = new Extent();
|
72 |
try {
|
73 |
System.err.println("Abriendo "+fName); |
74 |
file = new JNCSFile(fName, false); |
75 |
//file = new JNCSFile(fName, true);
|
76 |
//file.addProgressiveUpdateListener(this);
|
77 |
load(); |
78 |
bandCount = file.numBands; |
79 |
/*if ( bandCount > 2) {
|
80 |
setBand(RED_BAND, 0);
|
81 |
setBand(GREEN_BAND, 1);
|
82 |
setBand(BLUE_BAND, 2);
|
83 |
} else
|
84 |
setBand(RED_BAND|GREEN_BAND|BLUE_BAND, 0);*/
|
85 |
} catch(Exception e) { |
86 |
bErrorOnOpen = true;
|
87 |
errorMessage = e.getMessage(); |
88 |
// g.drawString(errorMessage, 0, 50);
|
89 |
System.err.println(errorMessage);
|
90 |
e.printStackTrace(); |
91 |
} |
92 |
} |
93 |
|
94 |
public void setView(Extent e) { v = new Extent(e); } |
95 |
public Extent getView() { return v; } |
96 |
|
97 |
/**
|
98 |
* Carga un ECW.
|
99 |
*
|
100 |
* @param fname
|
101 |
*/
|
102 |
|
103 |
public GeoFile load() {
|
104 |
double minX, minY, maxX, maxY;
|
105 |
|
106 |
System.out.println("ECW size = ("+file.width+","+file.height+")\n"+ |
107 |
" inc=("+file.cellIncrementX+","+file.cellIncrementY+")\n"+ |
108 |
" datum='"+file.datum+"', proyeccion='"+file.projection+"'"); |
109 |
minX = file.originX; |
110 |
maxY = file.originY; |
111 |
maxX = file.originX + (double)(file.width-1)*file.cellIncrementX; |
112 |
minY = file.originY + (double)(file.height-1)*file.cellIncrementY; |
113 |
extent = new Extent(minX, minY, maxX, maxY);
|
114 |
System.out.println(extent);
|
115 |
|
116 |
return this; |
117 |
} |
118 |
|
119 |
public void close() { |
120 |
file.close(true);
|
121 |
file = null;
|
122 |
} |
123 |
|
124 |
public int getWidth() { return file.width; } |
125 |
public int getHeight() { return file.height; } |
126 |
|
127 |
/**
|
128 |
* Trozo de imagen (Chunk) en que se divide la consulta a la librer?a,
|
129 |
* para esquivar el bug#2.
|
130 |
*
|
131 |
* @author luisw
|
132 |
*/
|
133 |
static class ChunkFrame { |
134 |
// Ancho m?ximo (~2500 px)
|
135 |
final static int MAX_WIDTH = 1536; |
136 |
// Alto m?ximo (no hay l?mite)
|
137 |
final static int MAX_HEIGHT = 1536; |
138 |
Point pos;
|
139 |
Extent v; |
140 |
int width, height;
|
141 |
boolean mustResize = false; |
142 |
public ChunkFrame(Extent vista, int w, int h) { |
143 |
v = vista; |
144 |
width = w; |
145 |
height = h; |
146 |
} |
147 |
/**
|
148 |
* Calcula el array de chunks (trozos).
|
149 |
* @param file Fichero ecw que hay que trocear.
|
150 |
* @param v Extent total de la vista.
|
151 |
* @param sz Tama?o total de la vista.
|
152 |
* @return array de ChunkFrames.
|
153 |
* @throws JNCSFileNotOpenException
|
154 |
*/
|
155 |
public static ChunkFrame [] computeFrames(JNCSFile file, Extent v, Dimension sz) throws JNCSFileNotOpenException { |
156 |
ChunkFrame [] frames = null; |
157 |
ChunkFrame f = null;
|
158 |
|
159 |
// Calcula el n? de chunks (filas y columnas)
|
160 |
int numCol = (sz.width / MAX_WIDTH), numRow = (sz.height / MAX_HEIGHT);
|
161 |
if (sz.width -(numCol*MAX_WIDTH) > 0) numCol++; |
162 |
if (sz.height - (numRow*MAX_HEIGHT) > 0) numRow++; |
163 |
frames = new ChunkFrame[numCol*numRow];
|
164 |
|
165 |
// Coprobaci?n previa para resolver el bug#1
|
166 |
JNCSDatasetPoint ptMin = file.convertWorldToDataset(v.minX(), v.minY()); |
167 |
JNCSDatasetPoint ptMax = file.convertWorldToDataset(v.maxX(), v.maxY()); |
168 |
System.out.println("Dataset coords Width = "+(ptMax.x-ptMin.x)+", px width = "+sz.width+ |
169 |
" px heigh = "+sz.height);
|
170 |
// BEGIN Cambiando para soportar e < 1:1
|
171 |
// TODO Mejorarlo para que los PAN con un zoom muy grande sean correctos
|
172 |
System.out.println("MAXX MINX-"+ptMax.x+","+ptMin.x); |
173 |
if ((ptMax.x-ptMin.x)<sz.width) {
|
174 |
numCol = numRow = 1;
|
175 |
frames = new ChunkFrame[numCol*numRow];
|
176 |
f = frames[0] = new ChunkFrame(v, ptMax.x-ptMin.x, ptMin.y-ptMax.y); |
177 |
System.out.println("Size=("+f.width+","+f.height+")"); |
178 |
f.pos = new Point(0,0); |
179 |
f.mustResize = true;
|
180 |
f.v = new Extent(v);
|
181 |
} else {
|
182 |
// Calcula cada chunk
|
183 |
double stepx = ((double) ptMax.x-ptMin.x)/sz.getWidth(); |
184 |
double stepy = ((double) ptMax.y-ptMin.y)/sz.getHeight(); |
185 |
int h = sz.height;
|
186 |
for (int r=0; r<numRow; r++) { |
187 |
int w = sz.width;
|
188 |
for (int c = 0; c<numCol; c++) { |
189 |
f = new ChunkFrame(null, -1, -1); |
190 |
// Posici?n del chunk
|
191 |
f.pos = new Point(c*MAX_WIDTH, r*MAX_HEIGHT); |
192 |
// Tama?o del chunk
|
193 |
f.width = Math.min(MAX_WIDTH, w);
|
194 |
f.height = Math.min(MAX_HEIGHT, h);
|
195 |
// Extent del chunk
|
196 |
int x1 = ptMin.x+(int) (f.pos.x*stepx); |
197 |
int x2 = x1+(int)(f.width*stepx); |
198 |
int y1 = ptMax.y-(int) (f.pos.y*stepy); //ptMax.y; |
199 |
int y2 = y1-(int)(f.height*stepy);//ptMin.y; |
200 |
JNCSWorldPoint pt1 = file.convertDatasetToWorld(x1, y1); |
201 |
JNCSWorldPoint pt2 = file.convertDatasetToWorld(x2, y2); |
202 |
f.v = new Extent(pt1.x, pt1.y, pt2.x, pt2.y); // Hay que calcularlo |
203 |
System.out.println(" View DataSet = ("+x1+","+y1+","+x2+","+y2+")"); |
204 |
System.out.println(" View Extent = "+ v); |
205 |
System.out.println("Frame Extent = "+ f.v); |
206 |
|
207 |
frames[r*numCol+c] = f; |
208 |
w -= MAX_WIDTH; |
209 |
} |
210 |
h -= MAX_HEIGHT; |
211 |
} |
212 |
} |
213 |
System.out.println("Hay "+numRow+" filas y "+numCol+" columnas."); |
214 |
return frames;
|
215 |
} |
216 |
} |
217 |
|
218 |
/**
|
219 |
* Obtiene un trozo de imagen (determinado por la vista y los par?metros.
|
220 |
*
|
221 |
* @param width
|
222 |
* @param height
|
223 |
*/
|
224 |
|
225 |
public synchronized Image updateImage(int width, int height, ICoordTrans rp) { |
226 |
// TODO reproyectar para devolver el trozo de imagen pedida sobre ...
|
227 |
// la proyecci?n de destino.
|
228 |
int line = 0; |
229 |
boolean mustResize = false; |
230 |
Dimension fullSize = null; |
231 |
Image ecwImage = null; |
232 |
if (file == null) return ecwImage; |
233 |
try {
|
234 |
double dFileAspect, dWindowAspect;
|
235 |
//double dWorldTLX, dWorldTLY, dWorldBRX, dWorldBRY;
|
236 |
int bandlist[]; |
237 |
int bandListTriband[]; |
238 |
int pRGBArray[] = null; |
239 |
|
240 |
// Work out the correct aspect for the setView call.
|
241 |
dFileAspect = (double)v.width()/(double)v.height(); |
242 |
dWindowAspect = (double)width /(double)height; |
243 |
|
244 |
if (dFileAspect > dWindowAspect) {
|
245 |
height =(int)((double)width/dFileAspect); |
246 |
} else {
|
247 |
width = (int)((double)height*dFileAspect); |
248 |
} |
249 |
|
250 |
|
251 |
fullSize = new Dimension(width, height); |
252 |
System.out.println("fullSize = ("+width+","+height+")"); |
253 |
// Peta en los peque?os ... arreglar antes de meter del todo
|
254 |
ChunkFrame frames[] = ChunkFrame.computeFrames(file, v, fullSize);
|
255 |
for (int nChunk=0; nChunk<frames.length; nChunk++) { |
256 |
System.out.println("chunck "+nChunk+"->"+frames[nChunk]); |
257 |
} |
258 |
if (frames.length == 1) { |
259 |
width = frames[0].width;
|
260 |
height = frames[0].height;
|
261 |
if(width<=0)width=1; |
262 |
if(height<=0)height=1; |
263 |
System.out.println("frameSize = ("+width+","+height+")"); |
264 |
//System.out.println("Cambio el ancho total a ("+width+","+height+")");
|
265 |
} |
266 |
|
267 |
/* JNCSDatasetPoint ptMin = file.convertWorldToDataset(v.minX(), v.minY());
|
268 |
JNCSDatasetPoint ptMax = file.convertWorldToDataset(v.maxX(), v.maxY());
|
269 |
System.out.println("Dataset coords Width = "+(ptMax.x-ptMin.x)+", px width ="+width);
|
270 |
// BEGIN Cambiando para soportar e < 1:1
|
271 |
// TODO Mejorarlo para que los PAN con un zoom muy grande sean correctos
|
272 |
if ((ptMax.x-ptMin.x)<width) {
|
273 |
width = ptMax.x-ptMin.x;
|
274 |
height = ptMin.y-ptMax.y;
|
275 |
System.out.println("Size=("+width+","+height+")");
|
276 |
mustResize = true;
|
277 |
}*/
|
278 |
// Create an image of the ecw file.
|
279 |
if (doTransparency)
|
280 |
ecwImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB) ; |
281 |
else
|
282 |
ecwImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); |
283 |
|
284 |
pRGBArray = new int[width]; |
285 |
|
286 |
// Setup the view parameters for the ecw file.
|
287 |
bandlist = new int[bandCount]; |
288 |
bandListTriband = new int[bandCount]; |
289 |
if ( bandCount > 2) { |
290 |
bandlist[0] = getBand(RED_BAND);
|
291 |
bandlist[1] = getBand(GREEN_BAND);
|
292 |
bandlist[2] = getBand(BLUE_BAND);
|
293 |
if (bandCount > 3) |
294 |
for (int i=3; i< bandCount; i++) { |
295 |
bandlist[i] = 0;
|
296 |
} |
297 |
} else {
|
298 |
for (int i=0; i< bandCount; i++) { |
299 |
bandlist[i] = i; |
300 |
} |
301 |
} |
302 |
|
303 |
if(bandCount==3){ |
304 |
bandListTriband[0] = 0; |
305 |
bandListTriband[1] = 1; |
306 |
bandListTriband[2] = 2; |
307 |
} |
308 |
|
309 |
for (int nChunk=0; nChunk<frames.length; nChunk++) { |
310 |
ChunkFrame f = frames[nChunk]; |
311 |
|
312 |
// Set the view
|
313 |
if(bandCount!=3) |
314 |
file.setView(file.numBands, bandlist, f.v.minX(), f.v.maxY(), f.v.maxX(), f.v.minY(), f.width, f.height); |
315 |
else
|
316 |
file.setView(file.numBands, bandListTriband, f.v.minX(), f.v.maxY(), f.v.maxX(), f.v.minY(), f.width, f.height); |
317 |
|
318 |
System.out.println("f.Size = ("+f.width+","+f.height+")+CHUNK="+nChunk); |
319 |
|
320 |
/* Esta peli es porque el Ecw no intercambia las bandas con lo que me toca hacerlo
|
321 |
* a mano. Primero detectamos si se ha alterado el orden de las mismas. Si es as?
|
322 |
* calculamos mascaras y desplazamientos y hacemos una copia en pRGBArrayCopy
|
323 |
* con las bandas alteradas de orden
|
324 |
*/
|
325 |
|
326 |
int pRGBArrayCopy[] = null; |
327 |
int mascara[] = new int[3]; |
328 |
int shl[] = new int[3]; |
329 |
int shr[] = new int[3]; |
330 |
boolean order = true; |
331 |
|
332 |
if(bandCount==3){ |
333 |
for(int i=0;i<bandCount;i++) |
334 |
if(bandlist[i]!=i)order=false; |
335 |
if(!order){
|
336 |
for(int i=0;i<bandCount;i++){ |
337 |
switch(bandlist[i]){
|
338 |
case 0:mascara[i] = 0x00ff0000;break; |
339 |
case 1:mascara[i] = 0x0000ff00;break; |
340 |
case 2:mascara[i] = 0x000000ff;break; |
341 |
} |
342 |
if(i==1 && bandlist[i]==0)shr[i] = 8; |
343 |
if(i==2 && bandlist[i]==0)shr[i] = 16; |
344 |
if(i==0 && bandlist[i]==1)shl[i] = 8; |
345 |
if(i==2 && bandlist[i]==1)shr[i] = 8; |
346 |
if(i==0 && bandlist[i]==2)shl[i] = 16; |
347 |
if(i==1 && bandlist[i]==2)shl[i] = 8; |
348 |
} |
349 |
} |
350 |
} |
351 |
|
352 |
// Read the scan lines
|
353 |
for (line=0; line < f.height; line++) { |
354 |
file.readLineRGBA(pRGBArray); |
355 |
|
356 |
if(bandCount==3 && !order){ |
357 |
pRGBArrayCopy = new int[pRGBArray.length]; |
358 |
for(int i=0;i<pRGBArray.length;i++){ |
359 |
pRGBArrayCopy[i] = (pRGBArray[i] & 0xff000000) +
|
360 |
(((pRGBArray[i] & mascara[2]) << shl[2] ) >> shr[2]) + |
361 |
(((pRGBArray[i] & mascara[1]) << shl[1] ) >> shr[1]) + |
362 |
(((pRGBArray[i] & mascara[0]) << shl[0] ) >> shr[0]); |
363 |
} |
364 |
pRGBArray = pRGBArrayCopy; |
365 |
} |
366 |
|
367 |
// Prueba de sustituci?n de color transparente
|
368 |
if (doTransparency) {
|
369 |
if (line == 0) tFilter.debug = true; |
370 |
tFilter.filterLine(pRGBArray); |
371 |
tFilter.debug = false;
|
372 |
} |
373 |
//System.out.println("setRGB("+f.pos.x+","+f.pos.y+line+","+f.width+","+1+","+pRGBArray+","+0+","+f.width+")");
|
374 |
((BufferedImage)ecwImage).setRGB(f.pos.x, f.pos.y+line, f.width, 1, pRGBArray, 0, f.width); |
375 |
} |
376 |
} |
377 |
if (frames[0].mustResize) { |
378 |
//System.out.println("resize "+fullSize);
|
379 |
return resizeImage(fullSize, ecwImage);
|
380 |
} |
381 |
/*
|
382 |
* La excepci?n atrapada es la de 'zoom > 1:1 no valido'
|
383 |
} catch (com.ermapper.ecw.JNCSInvalidSetViewException e) {
|
384 |
System.err.println(errorMessage);
|
385 |
e.printStackTrace(); */
|
386 |
} catch(com.ermapper.ecw.JNCSException e) { //java.lang.ArrayIndexOutOfBoundsException: |
387 |
bErrorOnOpen = true;
|
388 |
System.err.println("EcwFile JNCS Error en la l?nea "+line+"/"+height); |
389 |
System.err.println(e.getMessage());
|
390 |
e.printStackTrace(); |
391 |
} catch(java.lang.ArrayIndexOutOfBoundsException e) { //: |
392 |
bErrorOnOpen = true;
|
393 |
System.err.println("EcwFile ArrayIndex Error en la l?nea "+line+"/"+height); |
394 |
System.err.println(e.getMessage());
|
395 |
e.printStackTrace(); |
396 |
} catch(Exception e) { |
397 |
bErrorOnOpen = true;
|
398 |
errorMessage = e.getMessage(); |
399 |
// g.drawString(errorMessage, 0, 50);
|
400 |
System.err.println(errorMessage);
|
401 |
e.printStackTrace(); |
402 |
} |
403 |
lastRefreshPercent = file.getPercentComplete(); |
404 |
System.out.println("Leido al "+lastRefreshPercent+" %."); |
405 |
return ecwImage;
|
406 |
} |
407 |
|
408 |
/**
|
409 |
* Redimensionado de imagen
|
410 |
* La funci?n getScaledInstance nos devuelve un tipo image que no sirve por lo que
|
411 |
* habr? que crear buffImg como BufferedImage y copiar los datos devueltos por esta
|
412 |
* funci?n a este que es el que ser? devuelto por la funci?n
|
413 |
* @param sz
|
414 |
* @param image Image de entrada
|
415 |
* @return Imagen reescalada
|
416 |
*/
|
417 |
private Image resizeImage(Dimension sz, Image image) { |
418 |
Image buffImg = null; |
419 |
Image img = image.getScaledInstance((int) sz.getWidth(), |
420 |
(int) sz.getHeight(), Image.SCALE_SMOOTH); |
421 |
|
422 |
//Todo este pollo es para copiar el tipo image devuelto a BufferedImage
|
423 |
|
424 |
buffImg = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB) ; |
425 |
|
426 |
int[] pixels = new int[img.getWidth(null) * img.getHeight(null)]; |
427 |
PixelGrabber pg = new PixelGrabber(img, 0, 0, img.getWidth(null), img.getHeight(null), pixels, 0, img.getWidth(null)); |
428 |
|
429 |
try {
|
430 |
pg.grabPixels(); |
431 |
} catch (InterruptedException e) { |
432 |
e.printStackTrace(); |
433 |
} |
434 |
|
435 |
for (int j = 0; j < buffImg.getHeight(null); j++) { |
436 |
for (int i = 0; i < buffImg.getWidth(null); i++) { |
437 |
((BufferedImage)buffImg).setRGB(i, j, pixels[j * buffImg.getWidth(null) + i]); |
438 |
} |
439 |
} |
440 |
|
441 |
return buffImg;
|
442 |
} |
443 |
|
444 |
/**
|
445 |
* Reproyecta el raster.
|
446 |
*/
|
447 |
public void reProject(ICoordTrans rp) { |
448 |
// TODO metodo reProject pendiente de implementar
|
449 |
} |
450 |
|
451 |
|
452 |
/**
|
453 |
* Soporte para actualizaci?n de la imagen
|
454 |
* @see com.ermapper.ecw.JNCSProgressiveUpdate#refreshUpdate(int, int, double, double, double, double)
|
455 |
*/
|
456 |
public void refreshUpdate(int nWidth, int nHeight, double dWorldTLX, double dWorldTLY, double dWorldBRX, double dWorldBRY) { |
457 |
int completado = file.getPercentComplete();
|
458 |
System.out.println("EcwFile: se actualiza 1: "+completado+" % completado"); |
459 |
if ((updatable != null) && (lastRefreshPercent < 100)) { |
460 |
if ((completado-lastRefreshPercent > 25) || completado == 100) { |
461 |
lastRefreshPercent = file.getPercentComplete(); |
462 |
updatable.repaint(); |
463 |
} |
464 |
} |
465 |
} |
466 |
|
467 |
public void refreshUpdate(int nWidth, int nHeight, int dDatasetTLX, int dDatasetTLY, int dDatasetBRX, int dDatasetBRY) { |
468 |
System.out.println("EcwFile: se actualiza 2"); |
469 |
} |
470 |
|
471 |
/**
|
472 |
* Esta funci?n es porque el Ecw no intercambia las bandas con lo que me toca hacerlo
|
473 |
* a mano. Primero detectamos si se ha alterado el orden de las mismas. Si es as?
|
474 |
* calculamos mascaras y desplazamientos y hacemos una copia en pRGBArrayCopy
|
475 |
* con las bandas alteradas de orden
|
476 |
* @param bandList lista de bandas
|
477 |
* @param mask mascara
|
478 |
* @param shl desplazamiento izquierda
|
479 |
* @param shr desplazamiento derecha
|
480 |
*/
|
481 |
private boolean calcMaskAndShift(int[] bandList, int[] mask, int[] shl, int[] shr){ |
482 |
boolean order = true; |
483 |
if(bandCount==3){ |
484 |
for(int i=0;i<bandCount;i++) |
485 |
if(bandList[i]!=i)order=false; |
486 |
if(!order){
|
487 |
for(int i=0;i<bandCount;i++){ |
488 |
switch(bandList[i]){
|
489 |
case 0:mask[i] = 0x00ff0000;break; |
490 |
case 1:mask[i] = 0x0000ff00;break; |
491 |
case 2:mask[i] = 0x000000ff;break; |
492 |
} |
493 |
if(i==1 && bandList[i]==0)shr[i] = 8; |
494 |
if(i==2 && bandList[i]==0)shr[i] = 16; |
495 |
if(i==0 && bandList[i]==1)shl[i] = 8; |
496 |
if(i==2 && bandList[i]==1)shr[i] = 8; |
497 |
if(i==0 && bandList[i]==2)shl[i] = 16; |
498 |
if(i==1 && bandList[i]==2)shl[i] = 8; |
499 |
} |
500 |
} |
501 |
} |
502 |
return order;
|
503 |
} |
504 |
|
505 |
/**
|
506 |
* Intercambio de bandas para ecw manual. Se le pasa el array de bytes que se desea intercambiar
|
507 |
* la mascara y desplazamientos previamente calculados con calcMaskAndShift
|
508 |
* @param order true si el orden de las bandas no est? alterado y false si lo est?
|
509 |
* @param pRGBArray array de
|
510 |
* @param mascara
|
511 |
* @param shl desplazamiento a izquierda
|
512 |
* @param shr desplazamiento a derecha
|
513 |
* @return array con las bandas cambiadas
|
514 |
*/
|
515 |
private int[] changeBands(boolean order, int[] pRGBArray, int[] mascara, int[] shl, int[] shr){ |
516 |
if(bandCount==3 && !order){ |
517 |
int[] pRGBArrayCopy = new int[pRGBArray.length]; |
518 |
for(int i=0;i<pRGBArray.length;i++){ |
519 |
pRGBArrayCopy[i] = (pRGBArray[i] & 0xff000000) +
|
520 |
(((pRGBArray[i] & mascara[2]) << shl[2] ) >> shr[2]) + |
521 |
(((pRGBArray[i] & mascara[1]) << shl[1] ) >> shr[1]) + |
522 |
(((pRGBArray[i] & mascara[0]) << shl[0] ) >> shr[0]); |
523 |
} |
524 |
return pRGBArrayCopy;
|
525 |
} |
526 |
return pRGBArray;
|
527 |
} |
528 |
|
529 |
/**
|
530 |
* Asigna al objeto Image los valores con los dato de la imagen contenidos en el
|
531 |
* vector de enteros.
|
532 |
* @param image imagen con los datos actuales
|
533 |
* @param startX inicio de la posici?n en X dentro de la imagen
|
534 |
* @param startY inicio de la posici?n en X dentro de la imagen
|
535 |
* @param w Ancho de la imagen
|
536 |
* @param h Alto de la imagen
|
537 |
* @param rgbArray vector que contiene la banda que se va a sustituir
|
538 |
* @param offset desplazamiento
|
539 |
* @param scansize tama?o de imagen recorrida por cada p
|
540 |
*/
|
541 |
protected void setRGBLine(BufferedImage image, int startX, int startY, int w, int h, int[] rgbArray, |
542 |
int offset, int scansize) { |
543 |
image.setRGB(startX, startY, w, h, rgbArray, offset, scansize); |
544 |
} |
545 |
|
546 |
/**
|
547 |
* Asigna al objeto Image la mezcla entre los valores que ya tiene y los valores
|
548 |
* con los dato de la imagen contenidos en el vector de enteros. De los valores RGB
|
549 |
* que ya contiene se mantienen las bandas que no coinciden con el valor de flags. La
|
550 |
* banda correspondiente a flags es sustituida por los datos del vector.
|
551 |
* @param image imagen con los datos actuales
|
552 |
* @param startX inicio de la posici?n en X dentro de la imagen
|
553 |
* @param startY inicio de la posici?n en X dentro de la imagen
|
554 |
* @param w Ancho de la imagen
|
555 |
* @param h Alto de la imagen
|
556 |
* @param rgbArray vector que contiene la banda que se va a sustituir
|
557 |
* @param offset desplazamiento
|
558 |
* @param scansize tama?o de imagen recorrida por cada paso
|
559 |
* @param flags banda que se va a sustituir (Ctes de GeoRasterFile)
|
560 |
*/
|
561 |
protected void setRGBLine(BufferedImage image, int startX, int startY, int w, int h, int[] rgbArray, |
562 |
int offset, int scansize, int flags) { |
563 |
int [] line = new int[rgbArray.length]; |
564 |
image.getRGB(startX, startY, w, h, line, offset, scansize); |
565 |
if (flags == GeoRasterFile.RED_BAND)
|
566 |
for (int i=0; i<line.length; i++) |
567 |
line[i] = (line[i] & 0x0000ffff) | (rgbArray[i] & 0xffff0000); |
568 |
else if (flags == GeoRasterFile.GREEN_BAND) |
569 |
for (int i=0; i<line.length; i++) |
570 |
line[i] = (line[i] & 0x00ff00ff) | (rgbArray[i] & 0xff00ff00); |
571 |
else if (flags == GeoRasterFile.BLUE_BAND) |
572 |
for (int i=0; i<line.length; i++) |
573 |
line[i] = (line[i] & 0x00ffff00) | (rgbArray[i] & 0xff0000ff); |
574 |
image.setRGB(startX, startY, w, h, line, offset, scansize); |
575 |
} |
576 |
|
577 |
/**
|
578 |
* Asigna al objeto Image la mezcla entre los valores que ya tiene y los valores
|
579 |
* con los dato de la imagen contenidos en el vector de enteros. De los valores RGB
|
580 |
* que ya contiene se mantienen las bandas que no coinciden con el valor de flags. La
|
581 |
* banda correspondiente a flags es sustituida por los datos del vector.
|
582 |
* @param image imagen con los datos actuales
|
583 |
* @param startX inicio de la posici?n en X dentro de la imagen
|
584 |
* @param startY inicio de la posici?n en X dentro de la imagen
|
585 |
* @param w Ancho de la imagen
|
586 |
* @param h Alto de la imagen
|
587 |
* @param rgbArray vector que contiene la banda que se va a sustituir
|
588 |
* @param offset desplazamiento
|
589 |
* @param scansize tama?o de imagen recorrida por cada paso
|
590 |
* @param origBand Banda origen del GeoRasterFile
|
591 |
* @param destBandFlag banda que se va a sustituir (Ctes de GeoRasterFile)
|
592 |
*/
|
593 |
protected void setRGBLine(BufferedImage image, int startX, int startY, int w, int h, int[] rgbArray, |
594 |
int offset, int scansize, int origBand, int destBandFlag) { |
595 |
int [] line = new int[rgbArray.length]; |
596 |
image.getRGB(startX, startY, w, h, line, offset, scansize); |
597 |
|
598 |
if (origBand == 0 && destBandFlag == GeoRasterFile.RED_BAND) |
599 |
for (int i=0; i<line.length; i++) |
600 |
line[i] = (line[i] & 0xff00ffff) | (rgbArray[i] & 0x00ff0000); |
601 |
else if (origBand == 1 && destBandFlag == GeoRasterFile.GREEN_BAND) |
602 |
for (int i=0; i<line.length; i++) |
603 |
line[i] = (line[i] & 0xffff00ff) | (rgbArray[i] & 0x0000ff00); |
604 |
else if (origBand == 2 && destBandFlag == GeoRasterFile.BLUE_BAND) |
605 |
for (int i=0; i<line.length; i++) |
606 |
line[i] = (line[i] & 0xffffff00) | (rgbArray[i] & 0x000000ff); |
607 |
|
608 |
else if (origBand == 0 && destBandFlag == GeoRasterFile.GREEN_BAND) |
609 |
for (int i=0; i<line.length; i++) |
610 |
line[i] = (line[i] & 0xffff00ff) | ((rgbArray[i] & 0x00ff0000) >> 8) ; |
611 |
else if (origBand == 0 && destBandFlag == GeoRasterFile.BLUE_BAND) |
612 |
for (int i=0; i<line.length; i++) |
613 |
line[i] = (line[i] & 0xffffff00) | ((rgbArray[i] & 0x00ff0000) >> 16); |
614 |
|
615 |
else if (origBand == 1 && destBandFlag == GeoRasterFile.RED_BAND) |
616 |
for (int i=0; i<line.length; i++) |
617 |
line[i] = (line[i] & 0xff00ffff) | ((rgbArray[i] & 0x0000ff00) << 8); |
618 |
else if (origBand == 1 && destBandFlag == GeoRasterFile.BLUE_BAND) |
619 |
for (int i=0; i<line.length; i++) |
620 |
line[i] = (line[i] & 0xffffff00) | ((rgbArray[i] & 0x0000ff00) >> 8); |
621 |
|
622 |
else if (origBand == 2 && destBandFlag == GeoRasterFile.RED_BAND) |
623 |
for (int i=0; i<line.length; i++) |
624 |
line[i] = (line[i] & 0xff00ffff) | ((rgbArray[i] & 0x000000ff) << 16); |
625 |
else if (origBand == 2 && destBandFlag == GeoRasterFile.GREEN_BAND) |
626 |
for (int i=0; i<line.length; i++) |
627 |
line[i] = (line[i] & 0xffff00ff) | ((rgbArray[i] & 0x000000ff) << 8); |
628 |
|
629 |
image.setRGB(startX, startY, w, h, line, offset, scansize); |
630 |
} |
631 |
|
632 |
/* (non-Javadoc)
|
633 |
* @see org.cresques.io.GeoRasterFile#updateImage(int, int, org.cresques.cts.ICoordTrans, java.awt.Image, int origBand, int destBand)
|
634 |
*/
|
635 |
public Image updateImage(int width, int height, ICoordTrans rp, Image img, int origBand, int destBandFlag) { |
636 |
//TODO reproyectar para devolver el trozo de imagen pedida sobre ...
|
637 |
// la proyecci?n de destino.
|
638 |
int line = 0; |
639 |
boolean mustResize = false; |
640 |
Dimension fullSize = null; |
641 |
|
642 |
if (file == null) return null; |
643 |
try {
|
644 |
double dFileAspect, dWindowAspect;
|
645 |
//double dWorldTLX, dWorldTLY, dWorldBRX, dWorldBRY;
|
646 |
int bandlist[]; |
647 |
int bandListTriband[]; |
648 |
int pRGBArray[] = null; |
649 |
|
650 |
// Work out the correct aspect for the setView call.
|
651 |
dFileAspect = (double)v.width()/(double)v.height(); |
652 |
dWindowAspect = (double)width /(double)height; |
653 |
|
654 |
if (dFileAspect > dWindowAspect) {
|
655 |
height =(int)((double)width/dFileAspect); |
656 |
} else {
|
657 |
width = (int)((double)height*dFileAspect); |
658 |
} |
659 |
|
660 |
fullSize = new Dimension(width, height); |
661 |
System.out.println("fullSize = ("+width+","+height+")"); |
662 |
// Peta en los peque?os ... arreglar antes de meter del todo
|
663 |
ChunkFrame frames[] = ChunkFrame.computeFrames(file, v, fullSize);
|
664 |
for (int nChunk=0; nChunk<frames.length; nChunk++) { |
665 |
System.out.println("chunck "+nChunk+"->"+frames[nChunk]); |
666 |
} |
667 |
if (frames.length == 1) { |
668 |
width = frames[0].width;
|
669 |
height = frames[0].height;
|
670 |
if(width<=0)width=1; |
671 |
if(height<=0)height=1; |
672 |
System.out.println("frameSize = ("+width+","+height+")"); |
673 |
//System.out.println("Cambio el ancho total a ("+width+","+height+")");
|
674 |
} |
675 |
|
676 |
// Create an image of the ecw file.
|
677 |
|
678 |
pRGBArray = new int[width]; |
679 |
|
680 |
// Setup the view parameters for the ecw file.
|
681 |
bandlist = new int[bandCount]; |
682 |
bandListTriband = new int[bandCount]; |
683 |
if ( bandCount > 2) { |
684 |
bandlist[0] = getBand(RED_BAND);
|
685 |
bandlist[1] = getBand(GREEN_BAND);
|
686 |
bandlist[2] = getBand(BLUE_BAND);
|
687 |
if (bandCount > 3) |
688 |
for (int i=3; i< bandCount; i++) { |
689 |
bandlist[i] = 0;
|
690 |
} |
691 |
} else {
|
692 |
for (int i=0; i< bandCount; i++) { |
693 |
bandlist[i] = i; |
694 |
} |
695 |
} |
696 |
|
697 |
if(bandCount==3){ |
698 |
bandListTriband[0] = 0; |
699 |
bandListTriband[1] = 1; |
700 |
bandListTriband[2] = 2; |
701 |
} |
702 |
|
703 |
int mascara[] = new int[3]; |
704 |
int shl[] = new int[3]; |
705 |
int shr[] = new int[3]; |
706 |
boolean order = true; |
707 |
|
708 |
if(img==null){ //Caso en el que se crea un Image |
709 |
Image ecwImage = null; |
710 |
for (int nChunk=0; nChunk<frames.length; nChunk++) { |
711 |
ChunkFrame f = frames[nChunk]; |
712 |
if(bandCount!=3) |
713 |
file.setView(file.numBands, bandlist, f.v.minX(), f.v.maxY(), f.v.maxX(), f.v.minY(), f.width, f.height); |
714 |
else
|
715 |
file.setView(file.numBands, bandListTriband, f.v.minX(), f.v.maxY(), f.v.maxX(), f.v.minY(), f.width, f.height); |
716 |
|
717 |
order = calcMaskAndShift(bandlist, mascara, shl, shr); |
718 |
|
719 |
ecwImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); |
720 |
|
721 |
for (line=0; line < f.height; line++) { |
722 |
file.readLineRGBA(pRGBArray); |
723 |
pRGBArray = changeBands(order, pRGBArray, mascara, shl, shr); |
724 |
setRGBLine((BufferedImage) ecwImage, f.pos.x, f.pos.y+line, f.width, 1, pRGBArray, 0, f.width); |
725 |
} |
726 |
|
727 |
}//Chuncks
|
728 |
applyAlpha(ecwImage); |
729 |
if (frames[0].mustResize) { |
730 |
return resizeImage(fullSize, ecwImage);
|
731 |
} |
732 |
lastRefreshPercent = file.getPercentComplete(); |
733 |
System.out.println("Leido al "+lastRefreshPercent+" %."); |
734 |
return ecwImage;
|
735 |
}else{ //Caso en el que se actualiza una banda del Image |
736 |
for (int nChunk=0; nChunk<frames.length; nChunk++) { |
737 |
ChunkFrame f = frames[nChunk]; |
738 |
if(bandCount!=3) |
739 |
file.setView(file.numBands, bandlist, f.v.minX(), f.v.maxY(), f.v.maxX(), f.v.minY(), f.width, f.height); |
740 |
else
|
741 |
file.setView(file.numBands, bandListTriband, f.v.minX(), f.v.maxY(), f.v.maxX(), f.v.minY(), f.width, f.height); |
742 |
order = calcMaskAndShift(bandlist, mascara, shl, shr); |
743 |
|
744 |
//System.out.println("ORIGEN="+origBand+" DESTINO="+destBandFlag);
|
745 |
for (line=0; line < f.height; line++) { |
746 |
file.readLineRGBA(pRGBArray); |
747 |
pRGBArray = changeBands(order, pRGBArray, mascara, shl, shr); |
748 |
setRGBLine((BufferedImage) img, f.pos.x, f.pos.y+line, f.width, 1, pRGBArray, 0, f.width, origBand, destBandFlag); |
749 |
} |
750 |
|
751 |
}//Chuncks
|
752 |
|
753 |
applyAlpha(img); |
754 |
|
755 |
if (frames[0].mustResize) { |
756 |
return resizeImage(fullSize, img);
|
757 |
} |
758 |
lastRefreshPercent = file.getPercentComplete(); |
759 |
System.out.println("Leido al "+lastRefreshPercent+" %."); |
760 |
return img;
|
761 |
} |
762 |
|
763 |
|
764 |
} catch(com.ermapper.ecw.JNCSException e) { //java.lang.ArrayIndexOutOfBoundsException: |
765 |
bErrorOnOpen = true;
|
766 |
System.err.println("EcwFile JNCS Error en la l?nea "+line+"/"+height); |
767 |
System.err.println(e.getMessage());
|
768 |
e.printStackTrace(); |
769 |
} catch(java.lang.ArrayIndexOutOfBoundsException e) { //: |
770 |
bErrorOnOpen = true;
|
771 |
System.err.println("EcwFile ArrayIndex Error en la l?nea "+line+"/"+height); |
772 |
System.err.println(e.getMessage());
|
773 |
e.printStackTrace(); |
774 |
} catch(Exception e) { |
775 |
bErrorOnOpen = true;
|
776 |
errorMessage = e.getMessage(); |
777 |
System.err.println(errorMessage);
|
778 |
e.printStackTrace(); |
779 |
} |
780 |
return img;
|
781 |
} |
782 |
|
783 |
private void applyAlpha(Image im) { |
784 |
BufferedImage img = (BufferedImage) im; |
785 |
int alpha = (getAlpha() & 0xff) << 24; |
786 |
int w = img.getWidth();
|
787 |
int [] line = new int[w]; |
788 |
for (int j=0; j<img.getHeight(); j++) { |
789 |
img.getRGB(0, j, w, 1, line, 0, w); |
790 |
for (int i=0; i<w; i++) |
791 |
line[i] = (alpha | line[i] & 0x00ffffff);
|
792 |
img.setRGB(0, j, w, 1, line, 0, w); |
793 |
} |
794 |
} |
795 |
|
796 |
/* (non-Javadoc)
|
797 |
* @see org.cresques.io.GeoRasterFile#getData(int, int)
|
798 |
*/
|
799 |
public Object getData(int x, int y, int band) { |
800 |
//file.readLineRGBA();
|
801 |
return null; |
802 |
} |
803 |
|
804 |
/**
|
805 |
* Devuelve los datos de una ventana solicitada
|
806 |
* @param ulX coordenada X superior izda.
|
807 |
* @param ulY coordenada Y superior derecha.
|
808 |
* @param sizeX tama?o en X de la ventana.
|
809 |
* @param sizeY tama?o en Y de la ventana.
|
810 |
* @param band Banda solicitada.
|
811 |
*/
|
812 |
|
813 |
public byte[] getWindow(int ulX, int ulY, int sizeX, int sizeY, int band){ |
814 |
//TODO Nacho: Implementar getWindow de EcwFile
|
815 |
return null; |
816 |
|
817 |
} |
818 |
|
819 |
/**
|
820 |
* Obtiene la zona (Norte / Sur)
|
821 |
* @return true si la zona es norte y false si es sur
|
822 |
*/
|
823 |
|
824 |
public boolean getZone(){ |
825 |
//TODO Nacho: Implementar getZone de EcwFile
|
826 |
return false; |
827 |
} |
828 |
|
829 |
/**
|
830 |
*Devuelve el n?mero de zona UTM
|
831 |
*@return N?mero de zona
|
832 |
*/
|
833 |
|
834 |
public int getUTM(){ |
835 |
// TODO Nacho: Implementar getUTM de EcwFile
|
836 |
return 0; |
837 |
} |
838 |
|
839 |
/**
|
840 |
* Obtiene el sistema de coordenadas geograficas
|
841 |
* @return Sistema de coordenadas geogr?ficas
|
842 |
*/
|
843 |
public String getGeogCS(){ |
844 |
//TODO Nacho: Implementar getGeogCS de EcwFile
|
845 |
return new String(""); |
846 |
} |
847 |
|
848 |
/**
|
849 |
* Devuelve el tama?o de bloque
|
850 |
* @return Tama?o de bloque
|
851 |
*/
|
852 |
public int getBlockSize(){ |
853 |
//TODO Nacho: Implementar getBlockSize de EcwFile
|
854 |
return 1; |
855 |
} |
856 |
|
857 |
} |