root / trunk / libraries / libCq_CMS_praster / src / org / cresques / io / datastruct / Palette.java @ 8026
History | View | Annotate | Download (12.7 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.datastruct; |
25 |
|
26 |
import org.cresques.io.data.RasterBuf; |
27 |
import org.cresques.util.Utilities; |
28 |
|
29 |
import es.gva.cit.jgdal.GdalColorEntry; |
30 |
import es.gva.cit.jgdal.GdalColorTable; |
31 |
import es.gva.cit.jgdal.GdalException; |
32 |
|
33 |
/**
|
34 |
* Paleta para raster. Esta consta de los valores RGB de la paleta que son almacenados en un vector de
|
35 |
* enteros donde cada elemento entero contiene en su interior el RGB completo y del vector de rangos.
|
36 |
* Dependiendo de si el tipo de rango es entero o decimal este estar? almacenado en un vector de rangos
|
37 |
* entero (intRange) o enun vector de rangos double (doubleRange). El tipo de dato del rango quedar?
|
38 |
* almacenado en la variable type.
|
39 |
* @author Nacho Brodin (brodin_ign@gva.es)
|
40 |
*/
|
41 |
public class Palette{ |
42 |
/**
|
43 |
* Tipo de dato de la paleta
|
44 |
* <UL>
|
45 |
* <LI>TYPE_INT = Valido para byte, short e int</LI>
|
46 |
* <LI>TYPE_DOUBLE = Valido para float y double</LI>
|
47 |
* </UL>
|
48 |
*/
|
49 |
private int type = RasterBuf.TYPE_UNDEFINED; |
50 |
/**
|
51 |
* Lista de rangos para paletas enteras
|
52 |
*/
|
53 |
private int[] intRange = null; |
54 |
/**
|
55 |
* Lista de rangos para paletas decimales
|
56 |
*/
|
57 |
private double[] doubleRange = null; |
58 |
/**
|
59 |
* Lista de valores RGB
|
60 |
*/
|
61 |
private int[] palette = null; |
62 |
/**
|
63 |
* Heuristica para paletas enteras. Esta heuristica simple consiste en el valor
|
64 |
* intermedio de la tabla, de esta forma reduce la tabla a la mitad.
|
65 |
*/
|
66 |
private int intHeuristica = Integer.MAX_VALUE; |
67 |
/**
|
68 |
* Heuristica para paletas decimales. Esta heuristica simple consiste en el valor
|
69 |
* intermedio de la tabla, de esta forma reduce la tabla a la mitad.
|
70 |
*/
|
71 |
private double doubleHeuristica = Double.MAX_VALUE; |
72 |
/**
|
73 |
* Nombre de la clase asociada a la entrada
|
74 |
*/
|
75 |
private String[] nameClass = null; |
76 |
|
77 |
|
78 |
/**
|
79 |
* Obtiene el valor RGB interpolado para un clave entera pasada por par?metro
|
80 |
* @param value clave de la cual se quiere obtener el valor RGB de la paleta
|
81 |
* @return valor RGB
|
82 |
*/
|
83 |
public int getInterpolateRGB2(double value){ |
84 |
int maxGrad = 127; |
85 |
int init = 1; |
86 |
int color = 0; |
87 |
double beginValue = 0; |
88 |
double nextValue = 0; |
89 |
for(int i = init; i <= doubleRange.length; i++){ |
90 |
if(i < doubleRange.length){
|
91 |
if(value > doubleRange[i]){
|
92 |
color = palette[i - 1];
|
93 |
beginValue = doubleRange[i - 1];
|
94 |
nextValue = doubleRange[i]; |
95 |
break;
|
96 |
} |
97 |
}else{
|
98 |
color = palette[i - 1];
|
99 |
beginValue = doubleRange[i - 1];
|
100 |
nextValue = 0;
|
101 |
break;
|
102 |
} |
103 |
} |
104 |
int[] colorBegin = Utilities.getARGBFromIntToIntArray(color); |
105 |
|
106 |
int max = Math.max(Math.max(colorBegin[0], colorBegin[1]), colorBegin[2]); |
107 |
|
108 |
double distance = Math.abs(beginValue - nextValue); |
109 |
double absValue = Math.abs(value - nextValue); |
110 |
|
111 |
int newBand = 0; |
112 |
if(distance != 0) |
113 |
newBand = (int)Math.round((absValue * maxGrad) / distance); |
114 |
|
115 |
int[] res = new int[3]; |
116 |
|
117 |
if((max + maxGrad) > 255){ |
118 |
for(int i = 0; i < 3; i++) |
119 |
if(colorBegin[i] == max){
|
120 |
res[i] = max - newBand; |
121 |
break;
|
122 |
}else
|
123 |
res[i] = colorBegin[i]; |
124 |
}else{
|
125 |
for(int i = 0; i < 3; i++) |
126 |
if(colorBegin[i] == max){
|
127 |
res[i] = max + newBand; |
128 |
break;
|
129 |
}else
|
130 |
res[i] = colorBegin[i]; |
131 |
} |
132 |
|
133 |
return Utilities.getIntFromARGB(colorBegin[3], res[0], res[1], res[2]); |
134 |
} |
135 |
|
136 |
/**
|
137 |
* Obtiene el valor RGB interpolado para un clave entera pasada por par?metro
|
138 |
* @param value clave de la cual se quiere obtener el valor RGB de la paleta
|
139 |
* @return valor RGB
|
140 |
*/
|
141 |
public int getInterpolateRGB2(int value){ |
142 |
int maxGrad = 127; |
143 |
int init = 1; |
144 |
int color = 0; |
145 |
int beginValue = 0; |
146 |
int nextValue = 0; |
147 |
for(int i = init; i <= intRange.length; i++){ |
148 |
if(i < intRange.length){
|
149 |
if(value > intRange[i]){
|
150 |
color = palette[i - 1];
|
151 |
beginValue = intRange[i - 1];
|
152 |
nextValue = intRange[i]; |
153 |
break;
|
154 |
} |
155 |
}else{
|
156 |
color = palette[i - 1];
|
157 |
beginValue = intRange[i - 1];
|
158 |
nextValue = 0;
|
159 |
break;
|
160 |
} |
161 |
} |
162 |
int[] colorBegin = Utilities.getARGBFromIntToIntArray(color); |
163 |
|
164 |
int max = Math.max(Math.max(colorBegin[0], colorBegin[1]), colorBegin[2]); |
165 |
|
166 |
int distance = Math.abs(beginValue - nextValue); |
167 |
int absValue = Math.abs(value - nextValue); |
168 |
|
169 |
int newBand = 0; |
170 |
if(distance != 0) |
171 |
newBand = (absValue * maxGrad) / distance; |
172 |
|
173 |
int[] res = new int[3]; |
174 |
|
175 |
if((max + maxGrad) > 255){ |
176 |
for(int i = 0; i < 3; i++) |
177 |
if(colorBegin[i] == max){
|
178 |
res[i] = max - newBand; |
179 |
break;
|
180 |
}else
|
181 |
res[i] = colorBegin[i]; |
182 |
}else{
|
183 |
for(int i = 0; i < 3; i++) |
184 |
if(colorBegin[i] == max){
|
185 |
res[i] = max + newBand; |
186 |
break;
|
187 |
}else
|
188 |
res[i] = colorBegin[i]; |
189 |
} |
190 |
|
191 |
return Utilities.getIntFromARGB(colorBegin[3], res[0], res[1], res[2]); |
192 |
} |
193 |
|
194 |
|
195 |
/**
|
196 |
* Obtiene el valor RGB interpolado para un clave entera pasada por par?metro
|
197 |
* @param value clave de la cual se quiere obtener el valor RGB de la paleta
|
198 |
* @return valor RGB
|
199 |
*/
|
200 |
public int getInterpolateRGB(int value){ |
201 |
int init = 1; |
202 |
int color = 0; |
203 |
int beginValue = 0; |
204 |
int nextValue = 0; |
205 |
int nextColor = 0; |
206 |
for(int i = init; i <= intRange.length; i++){ |
207 |
if(i < intRange.length){
|
208 |
if(value > intRange[i]){
|
209 |
color = palette[i - 1];
|
210 |
beginValue = intRange[i - 1];
|
211 |
nextValue = intRange[i]; |
212 |
nextColor = palette[i]; |
213 |
break;
|
214 |
} |
215 |
}else{
|
216 |
color = palette[i - 1];
|
217 |
beginValue = intRange[i - 1];
|
218 |
nextValue = intRange[0];
|
219 |
nextColor = palette[0];
|
220 |
break;
|
221 |
} |
222 |
} |
223 |
int[] colorBegin = Utilities.getARGBFromIntToIntArray(color); |
224 |
int[] colorEnd = Utilities.getARGBFromIntToIntArray(nextColor); |
225 |
|
226 |
int dif = Math.abs(beginValue - nextValue); |
227 |
double difR = Math.abs(colorBegin[0] - colorEnd[0]) / (double)dif; |
228 |
double difG = Math.abs(colorBegin[1] - colorEnd[1]) / (double)dif; |
229 |
double difB = Math.abs(colorBegin[2] - colorEnd[2]) / (double)dif; |
230 |
|
231 |
int[] res = new int[3]; |
232 |
res[0] = (int)(colorBegin[0] + difR * (value - colorBegin[0])); |
233 |
res[1] = (int)(colorBegin[1] + difG * (value - colorBegin[1])); |
234 |
res[2] = (int)(colorBegin[2] + difB * (value - colorBegin[2])); |
235 |
|
236 |
return Utilities.getIntFromARGB(colorBegin[3], res[0], res[1], res[2]); |
237 |
} |
238 |
|
239 |
/**
|
240 |
* Obtiene el valor RGB para un clave entera pasada por par?metro
|
241 |
* @param value clave de la cual se quiere obtener el valor RGB de la paleta
|
242 |
* @return valor RGB
|
243 |
*/
|
244 |
public int getRGB(int value){ |
245 |
int init = 1; |
246 |
/*if(value > intHeuristica)
|
247 |
init = intRange.length >> 1;*/
|
248 |
for(int i = init; i <= intRange.length; i++) |
249 |
if(i < intRange.length){
|
250 |
if(value > intRange[i])
|
251 |
return palette[i - 1]; |
252 |
}else{
|
253 |
return palette[i - 1]; |
254 |
} |
255 |
return 0; |
256 |
} |
257 |
|
258 |
/**
|
259 |
* Obtiene el valor RGB para un clave decimal pasada por par?metro
|
260 |
* @param value clave de la cual se quiere obtener el valor RGB de la paleta
|
261 |
* @return valor RGB
|
262 |
*/
|
263 |
public int getRGB(double value){ |
264 |
int init = 1; |
265 |
/*if(value > doubleHeuristica)
|
266 |
init = doubleRange.length >> 1;*/
|
267 |
for(int i = init; i <= doubleRange.length; i++) |
268 |
if(i < doubleRange.length){
|
269 |
if(value > doubleRange[i])
|
270 |
return palette[i - 1]; |
271 |
}else{
|
272 |
return palette[i - 1]; |
273 |
} |
274 |
return 0; |
275 |
} |
276 |
|
277 |
/**
|
278 |
* Genera una paleta a partir de una tabla de entradas de la forma
|
279 |
* <UL>
|
280 |
* <LI>(String) Nombre de la clase</LI>
|
281 |
* <LI>(Integer) Rojo</LI>
|
282 |
* <LI>(Integer) Verde</LI>
|
283 |
* <LI>(Integer) Azul</LI>
|
284 |
* <LI>(Double) Valor</LI>
|
285 |
* </UL>
|
286 |
* @param entries
|
287 |
*/
|
288 |
public void createPaletteFromTable(Object[][] entries, int type){ |
289 |
this.type = type;
|
290 |
nameClass = new String[entries.length]; |
291 |
palette = new int[entries.length]; |
292 |
if(type <= RasterBuf.TYPE_INT){
|
293 |
intRange = new int[entries.length]; |
294 |
intHeuristica = (int)((Double)entries[(entries.length >> 1)][4]).doubleValue(); |
295 |
}else{
|
296 |
doubleRange = new double[entries.length]; |
297 |
doubleHeuristica = ((Double)entries[(entries.length >> 1)][4]).doubleValue(); |
298 |
} |
299 |
for(int entry = 0; entry < entries.length; entry++){ |
300 |
//palette[entry] = 0xff000000;
|
301 |
for(int value = 0; value < entries[entry].length; value++){ |
302 |
switch(value){
|
303 |
case 0: nameClass[entry] = (String)entries[entry][value]; |
304 |
break;
|
305 |
case 1: palette[entry] |= ((((Integer)entries[entry][value]).intValue() & 0x000000ff) << 16); |
306 |
break;
|
307 |
case 2: palette[entry] |= ((((Integer)entries[entry][value]).intValue() & 0x000000ff) << 8); |
308 |
break;
|
309 |
case 3: palette[entry] |= (((Integer)entries[entry][value]).intValue() & 0x000000ff); |
310 |
break;
|
311 |
case 4: if(type <= RasterBuf.TYPE_INT) |
312 |
intRange[entry] = ((Double)entries[entry][value]).intValue();
|
313 |
else
|
314 |
doubleRange[entry] = ((Double)entries[entry][value]).doubleValue();
|
315 |
break;
|
316 |
case 5: palette[entry] |= ((((Integer)entries[entry][value]).intValue() & 0x000000ff) << 24); |
317 |
break;
|
318 |
} |
319 |
} |
320 |
} |
321 |
} |
322 |
|
323 |
/**
|
324 |
* Crea una paleta a partir de un objeto GdalColorTable. Esto es necesario para los ficheros
|
325 |
* que tienen un paleta asignada, como los gif, y que son tratados por Gdal. Se pasa la tabla
|
326 |
* de color le?da desde gdal y se crea directamente un objeto Palette.
|
327 |
* @param table
|
328 |
*/
|
329 |
public void createPaletteFromGdalColorTable(GdalColorTable table){ |
330 |
try{
|
331 |
type = RasterBuf.TYPE_BYTE; |
332 |
nameClass = new String[table.getColorEntryCount()]; |
333 |
palette = new int[table.getColorEntryCount()]; |
334 |
intRange = new int[table.getColorEntryCount()]; |
335 |
|
336 |
int cont = table.getColorEntryCount() - 1; |
337 |
for(int iEntry = 0; iEntry < table.getColorEntryCount(); iEntry++){ |
338 |
GdalColorEntry entry = table.getColorEntryAsRGB(iEntry); |
339 |
nameClass[cont] = "";
|
340 |
palette[cont] = 0x00000000;
|
341 |
palette[cont] |= ((entry.c4 & 0x000000ff) << 24); |
342 |
palette[cont] |= ((entry.c1 & 0x000000ff) << 16); |
343 |
palette[cont] |= ((entry.c2 & 0x000000ff) << 8); |
344 |
palette[cont] |= (entry.c3 & 0x000000ff);
|
345 |
intRange[cont] = iEntry; |
346 |
cont --; |
347 |
} |
348 |
}catch(GdalException ex){
|
349 |
//No se crea la paleta
|
350 |
} |
351 |
} |
352 |
|
353 |
/**
|
354 |
* Carga una paleta desde un fichero XML
|
355 |
* @param file nombre del fichero
|
356 |
* @param palette Nombre de la paleta
|
357 |
*/
|
358 |
public void loadPaletteFromXML(String file, String palette){ |
359 |
//TODO: Implemetar cargar paleta desde el directorio gvSIG
|
360 |
} |
361 |
|
362 |
/**
|
363 |
* Carga una paleta desde el fichero .rmf asociado a la imagen
|
364 |
* @param file nombre del fichero de imagen
|
365 |
*/
|
366 |
public void loadPaletteFromRMF(String file){ |
367 |
//TODO: Implemetar cargar paleta desde .rmf
|
368 |
} |
369 |
|
370 |
/**
|
371 |
* Salva una paleta desde al fichero .rmf asociado a la imagen
|
372 |
* @param file nombre del fichero de imagen
|
373 |
*/
|
374 |
public void savePaletteToRMF(String file){ |
375 |
//TODO: Implemetar salvar paleta a .rmf
|
376 |
} |
377 |
|
378 |
/**
|
379 |
* Obtiene la paleta
|
380 |
* @return Paleta
|
381 |
*/
|
382 |
public int[] getPalette() { |
383 |
return palette;
|
384 |
} |
385 |
|
386 |
/**
|
387 |
* Asigna una paleta
|
388 |
* @param palette Paleta
|
389 |
*/
|
390 |
public void setPalette(int[] palette) { |
391 |
this.palette = palette;
|
392 |
} |
393 |
|
394 |
/**
|
395 |
* Obtiene el tipo del rango de la paleta que corresponde con los tipos de rasterBuf
|
396 |
* @return Tipo de rango, entero o double
|
397 |
*/
|
398 |
public int getType() { |
399 |
return type;
|
400 |
} |
401 |
|
402 |
/**
|
403 |
* Asigna el tipo del rango de la paleta que corresponde con los tipos de rasterBuf
|
404 |
* @param Tipo de rango, entero o double
|
405 |
*/
|
406 |
public void setType(int type) { |
407 |
this.type = type;
|
408 |
} |
409 |
|
410 |
/**
|
411 |
* Asigna los rangos si el tipo es decimal
|
412 |
* @param rangos
|
413 |
*/
|
414 |
public void setDoubleRange(double[] value) { |
415 |
doubleRange = value; |
416 |
} |
417 |
|
418 |
/**
|
419 |
* Asigna los rangos si el tipo es entero
|
420 |
* @param values
|
421 |
*/
|
422 |
public void setIntRange(int[] values) { |
423 |
intRange = values; |
424 |
} |
425 |
|
426 |
/**
|
427 |
* Obtiene los rangos si el tipo es decimal
|
428 |
* @return rangos
|
429 |
*/
|
430 |
public double[] getDoubleRange() { |
431 |
return doubleRange;
|
432 |
} |
433 |
|
434 |
/**
|
435 |
* Obtiene los rangos si el tipo es entero
|
436 |
* @return rangos
|
437 |
*/
|
438 |
public int[] getIntRange() { |
439 |
return intRange;
|
440 |
} |
441 |
|
442 |
|
443 |
/**
|
444 |
* Obtiene los nombres de las clases de la paleta
|
445 |
* @return Array de cadenas. Cada una corresponde con un nombre de clase
|
446 |
* que corresponde a cada rango de tipos.
|
447 |
*/
|
448 |
public String[] getNameClass() { |
449 |
return nameClass;
|
450 |
} |
451 |
|
452 |
/**
|
453 |
* Asigna los nombres de las clases de la paleta
|
454 |
* @param names Array de cadenas. Cada una corresponde con un nombre de clase
|
455 |
* que corresponde a cada rango de tipos.
|
456 |
*/
|
457 |
public void setNameClass(String[] names) { |
458 |
nameClass = names; |
459 |
} |
460 |
|
461 |
|
462 |
} |