Statistics
| Revision:

svn-gvsig-desktop / trunk / libraries / libRaster / src / org / gvsig / raster / grid / render / ImageDrawer.java @ 12035

History | View | Annotate | Download (14.2 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2006 IVER T.I. and Generalitat Valenciana.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 */
19
package org.gvsig.raster.grid.render;
20

    
21
import java.awt.Image;
22
import java.awt.image.BufferedImage;
23

    
24
import org.gvsig.raster.buffer.RasterBuffer;
25
import org.gvsig.raster.dataset.IBuffer;
26
import org.gvsig.raster.grid.GridPalette;
27
import org.gvsig.raster.grid.GridTransparency;
28
/**
29
 * Objeto para la escritura de datos desde un buffer a un objeto Image. En este nivel de 
30
 * renderizado no se gestiona extents, ni rotaciones ni coordenadas del mundo, solo la
31
 * escritura desde un buffer hasta otro de tama?o dado. Por medio de par?metros y de objetos
32
 * de estado varia el resultado de la escritura, selecci?n de bandas a escribir desde el buffer
33
 * a RGB, transparencias aplicadas o paletas.
34
 * 
35
 * @author Nacho Brodin (nachobrodin@gmail.com)
36
 */
37
public class ImageDrawer {
38
        /**
39
         * Fuente de datos para el renderizado
40
         */
41
        private IBuffer                                rasterBuf = null;
42
        private GridTransparency        transparency = null;
43
        private GridPalette                        palette = null;
44
        private int[]                                step = null;
45
        /**
46
         * Ancho y alto del objeto image
47
         */
48
        private int                                 width = 0;
49
        private int                                 height = 0;
50
        /**
51
         * Ancho y alto en pixeles del ?ltimo buffer asignado
52
         */
53
        private double                                         nWidth = 0;
54
        private double                                         nHeight = 0;
55

    
56
        /**
57
         * Dibuja el buffer sobre un objeto Image de java.awt y devuelve el resultado.
58
         * 
59
         * @param replicateBand Flag de comportamiento del renderizado. Al renderizar el buffer
60
         * este obtiene la primera banda del buffer y la asigna al R, la segunda al G y la tercera
61
         * al B. Este flag no es tomado en cuenta en caso de que existan 3 bandas en el buffer.
62
         * Si no hay tres bandas, por ejemplo una y el flag es true esta ser? replicada 
63
         * en R, G y B, en caso de ser false la banda ser? dibujada en su posici?n (R, G o B)
64
         * y en las otras bandas se rellenar? con 0.
65
         *  
66
         * @param transparentBand. Si es true la banda 4 es alpha y si es false no lo es. 
67
         *  
68
         * @return java.awt.Image con el buffer dibujado.
69
         */
70
        public Image drawBufferOverImageObject(boolean replicateBand, int[] renderBands){
71
                if(rasterBuf == null)
72
                        return null;
73

    
74
                BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
75

    
76
                //Dibujado de raster de 1 o 2 bandas.
77
                //adaptBufferToRender(replicateBand, renderBands);
78

    
79
                if(rasterBuf.getDataType() != IBuffer.TYPE_BYTE)
80
                        rasterBuf = convertToByte(rasterBuf);
81

    
82
                //Asigna la banda de transparencia si existe esta.
83
                assignTransparencyBand(renderBands);
84

    
85
                byte[] data = new byte[rasterBuf.getBandCount()];
86
                if(transparency != null && transparency.isTransparencyActive())
87
                        drawWithTransparency(image, data, (step != null));
88
                else if(palette != null && palette.isPaletteActive())
89
                        drawWithPalette(image, data, (step != null));
90
                else
91
                        drawByte(image, data, (step != null));
92

    
93
                step = null;
94
                return image;
95
        }
96

    
97
        /**
98
         * Calcula los vectores de desplazamiento en pixels en X e Y cuando se supersamplea. 
99
         * @param r Array de desplazamientos para las filas. Debe tener espacio reservado
100
         * @param c Array de desplazamientos para las columnas. Debe tener espacio reservado 
101
         * @param rel relaci?n entre el ancho o alto del objeto Image y el ancho o alto del buffer con los pixels
102
         * cargados.
103
         */
104
        private void calcSupersamplingStepsArrays(int[] r, int[] c, double rel) {
105
                for(int row = 0; row < r.length; row ++)
106
                        r[row] = (int)((row + step[1]) / rel);
107

    
108
                for(int col = 0; col < c.length; col ++)
109
                        c[col] = (int)((col + step[0]) / rel);
110
        }
111

    
112
        /**
113
         * Dibuja un raster sobre un BufferedImage
114
         * @param image BufferedImage sobre el que se dibuja
115
         * @param data buffer vacio. Se trata de un array de bytes donde cada elemento representa una banda.
116
         * @param supersampling true si se necesita supersamplear y false si no se necesita
117
         */
118
        private void drawByte(BufferedImage image, byte[] data, boolean supersampling) {
119
                if(supersampling) {
120
                        //double relHeight = (double)height/ nHeight;
121
                        int[] r = new int[height];
122
                        int[] c = new int[width];
123
                        calcSupersamplingStepsArrays(r, c, (double)((double)height / nHeight));
124
                        for(int row = 0; row < height; row ++) {
125
                                //int r = (int)((row + step[1]) / relHeight);
126
                                for(int col = 0; col < width; col ++) {
127
                                        try {
128
                                                //rasterBuf.getElemByte(r, (int)((col + step[0]) / relHeight), data);
129
                                                rasterBuf.getElemByte(r[row], c[col], data);
130
                                                image.setRGB(col, row, (0xff000000 + ((data[0] & 0xff) << 16) + ((data[1] & 0xff) << 8) + (data[2] & 0xff)));
131
                                        } catch(ArrayIndexOutOfBoundsException e){}
132
                                }
133
                        }
134
                } else {
135
                        for(int row = 0; row < rasterBuf.getHeight(); row ++) {
136
                                for(int col = 0; col < rasterBuf.getWidth(); col ++) {
137
                                        rasterBuf.getElemByte(row, col, data);
138
                                        image.setRGB(col, row, (0xff000000 + ((data[0] & 0xff) << 16) + ((data[1] & 0xff) << 8) + (data[2] & 0xff)));
139
                                }
140
                        }
141
                }
142
        }
143

    
144
        /**
145
         * Dibuja un raster sobre un BufferedImage con las propiedades de paleta.
146
         * @param image BufferedImage sobre el que se dibuja
147
         * @param data buffer vacio. Se trata de un array de bytes donde cada elemento representa una banda.
148
         * @param supersampling true si se necesita supersamplear y false si no se necesita
149
         */
150
        private void drawWithPalette(BufferedImage image, byte[] data, boolean supersampling) {
151
                int value = 0;
152
                if(supersampling) {
153
                        int[] r = new int[height];
154
                        int[] c = new int[width];
155
                        calcSupersamplingStepsArrays(r, c, (double)((double)height/ nHeight));
156
                        for(int row = 0; row < height; row ++) {
157
                                for(int col = 0; col < width; col ++) {
158
                                        try {
159
                                                rasterBuf.getElemByte(r[row], c[col], data);
160
                                                value = palette.getRGB(data[0]);
161
                                                image.setRGB(col, row, value);
162
                                        } catch(ArrayIndexOutOfBoundsException e){}
163
                                }
164
                        }
165
                } else {
166
                        for(int row = 0; row < rasterBuf.getHeight(); row ++) {
167
                                for(int col = 0; col < rasterBuf.getWidth(); col ++) {
168
                                        rasterBuf.getElemByte(row, col, data);
169
                                        value = palette.getRGB(data[0]);
170
                                        image.setRGB(col, row, value);
171
                                }
172
                        }
173
                }
174
        }
175

    
176
        /**
177
         * Dibuja un raster sobre un BufferedImage con las propiedades de paleta y transparencia
178
         * @param image BufferedImage sobre el que se dibuja
179
         * @param data buffer vacio. Se trata de un array de bytes donde cada elemento representa una banda.
180
         * @param supersampling true si se necesita supersamplear y false si no se necesita
181
         */
182
        private void drawWithTransparency(BufferedImage image, byte[] data, boolean supersampling) {
183
                int value = 0;
184
                if(supersampling) {
185
                        int[] r = new int[height];
186
                        int[] c = new int[width];
187
                        calcSupersamplingStepsArrays(r, c, (double)((double)height/ nHeight));
188
                        for(int row = 0; row < height; row ++) {
189
                                for(int col = 0; col < width; col ++) {
190
                                        try{
191
                                                rasterBuf.getElemByte(r[row], c[col], data);
192
                                                if(palette != null) {
193
                                                        value = palette.getRGB(data[0] & 0xff);
194
                                                        value = transparency.processRGB(value, row, col);
195
                                                } else 
196
                                                        value = transparency.processRGB(0xff000000 + ((data[0] & 0xff) << 16) + ((data[1] & 0xff) << 8) + (data[2] & 0xff), row, col);
197
                                                /*value = transparency.processRGB(0xff000000 + ((data[0] & 0xff) << 16) + ((data[1] & 0xff) << 8) + (data[2] & 0xff), row, col);
198
                                                if(palette != null)
199
                                                        value = palette.getRGB(value);*/
200
                                                image.setRGB(col, row, value);
201
                                        } catch(ArrayIndexOutOfBoundsException e){}
202
                                }
203
                        }
204
                } else {
205
                        for(int row = 0; row < rasterBuf.getHeight(); row ++) {
206
                                for(int col = 0; col < rasterBuf.getWidth(); col ++) {
207
                                        rasterBuf.getElemByte(row, col, data);
208
                                        if(palette != null) {
209
                                                value = palette.getRGB(data[0] & 0xff);
210
                                                value = transparency.processRGB(value, row, col);
211
                                        } else 
212
                                                value = transparency.processRGB(0xff000000 + ((data[0] & 0xff) << 16) + ((data[1] & 0xff) << 8) + (data[2] & 0xff), row, col);
213
                                        image.setRGB(col, row, value);
214
                                }
215
                        }
216
                }
217
        }
218
        /**
219
         * Intercala bandas en el buffer dependiendo de si hay que replicar o meter
220
         * bandas en negro. Esto tiene es valido para buffers con solo una banda ya que
221
         * el dibujado sobre Graphics debe ser R, G, B.
222
         * 
223
         * @param replicateBand false si no se replican bandas y las que no existen 
224
         * se ponen en negro y false si hay que dibujar la misma en R,G y B. Esto 
225
         * tiene sentido si el raster tiene solo 1 o 2 bandas.
226
         * @param renderBands array con las posiciones de renderizado. 
227
         *  A la hora de renderizar hay que tener en cuenta que solo se renderizan las 
228
         * tres primeras bandas del buffer por lo que solo se tienen en cuenta los tres primeros
229
         * elementos. Por ejemplo, el array {1, 0, 3} dibujar? sobre el Graphics las bandas 1,0 y 3 de un
230
         * raster de al menos 4 bandas.La notaci?n con -1 en alguna posici?n del vector solo tiene sentido
231
         * en la visualizaci?n pero no se puede as?gnar una banda del buffer a null.
232
         * Algunos ejemplos:
233
         * <P> 
234
         * {-1, 0, -1} Dibuja la banda 0 del raster en la G de la visualizaci?n.
235
         * Si replicateBand es true R = G = B sino R = B = 0
236
         * {1, 0, 3} La R = banda 1 del raster, G = 0 y B = 3
237
         * {0} La R = banda 0 del raster. Si replicateBand es true R = G = B sino G = B = 0
238
         * </P>
239
         */
240
        /*private void adaptBufferToRender(boolean replicateBand, int[] renderBands){
241
                byte[][] aux = null;
242
                if(rasterBuf.getBandCount() < 3){
243
                        for(int i = 0; i < renderBands.length; i++){
244
                                if( replicateBand && renderBands[i] == -1)
245
                                        rasterBuf.replicateBand(0, i);
246
                                if( !replicateBand && renderBands[i] == -1){
247
                                        if(aux == null)
248
                                                aux = rasterBuf.createByteBand(rasterBuf.getWidth(), rasterBuf.getHeight(), (byte)0);
249
                                        rasterBuf.addBandByte(i, aux);
250
                                }
251
                        }
252
                }
253
        }*/
254

    
255
        /**
256
         * Asigna al objeto GridTransparency la banda de transparencia si la tiene para
257
         * tenerla en cuenta en el renderizado.
258
         * @param renderBands Lista de bandas a renderizar
259
         * @param ts Objeto con las propiedades de transparencia del Grid.
260
         */
261
        private void assignTransparencyBand(int[] renderBands) {
262
                if(transparency != null){
263
                        for(int i = 0; i < transparency.getTransparencyBandNumberList().size(); i ++) {
264
                                for(int j = 0; j < renderBands.length; j ++) {
265
                                        if(renderBands[j] == ((Integer)transparency.getTransparencyBandNumberList().get(i)).intValue()){
266
                                                if(transparency.getBand() == null)
267
                                                        transparency.setBand(rasterBuf.getBandBuffer(renderBands[j]));
268
                                                else {
269
                                                        IBuffer outBuf = transparency.getBand().cloneBuffer();
270
                                                        transparency.mergeTransparencyBands(new IBuffer[]{transparency.getBand(), rasterBuf.getBandBuffer(renderBands[j])}, outBuf);
271
                                                }
272
                                        }
273
                                }
274
                        }
275
                }
276
        }
277

    
278
        private IBuffer convertToByte(IBuffer buf) {
279
                IBuffer b = RasterBuffer.getBuffer(IBuffer.TYPE_BYTE, buf.getWidth(), buf.getHeight(), buf.getBandCount(), true);
280
                if(buf.getDataType() == IBuffer.TYPE_SHORT) {
281
                        for (int nBand = 0; nBand < buf.getBandCount(); nBand++)
282
                                for (int row = 0; row < buf.getHeight(); row++)
283
                                        for (int col = 0; col < buf.getWidth(); col++)
284
                                                b.setElem(row, col, nBand, (byte)(buf.getElemShort(row, col, nBand) & 0xffff));
285
                }
286
                if(buf.getDataType() == IBuffer.TYPE_INT) {
287
                        for (int nBand = 0; nBand < buf.getBandCount(); nBand++)
288
                                for (int row = 0; row < buf.getHeight(); row++)
289
                                        for (int col = 0; col < buf.getWidth(); col++)
290
                                                b.setElem(row, col, nBand, (byte)(buf.getElemInt(row, col, nBand) & 0xffffffff));
291
                }
292
                if(buf.getDataType() == IBuffer.TYPE_FLOAT) {
293
                        for (int nBand = 0; nBand < buf.getBandCount(); nBand++)
294
                                for (int row = 0; row < buf.getHeight(); row++)
295
                                        for (int col = 0; col < buf.getWidth(); col++)
296
                                                b.setElem(row, col, nBand, (byte)(Math.round(buf.getElemFloat(row, col, nBand))));
297
                }
298
                if(buf.getDataType() == IBuffer.TYPE_DOUBLE) {
299
                        for (int nBand = 0; nBand < buf.getBandCount(); nBand++)
300
                                for (int row = 0; row < buf.getHeight(); row++)
301
                                        for (int col = 0; col < buf.getWidth(); col++)
302
                                                b.setElem(row, col, nBand, (byte)(Math.round(buf.getElemDouble(row, col, nBand))));
303
                }
304
                return b;
305
        }
306

    
307
        /**
308
         * Asigna el buffer a renderizar
309
         * @param b Buffer a renderizar
310
         */
311
        public void setBuffer(IBuffer b) {
312
                this.rasterBuf = b;
313
        }
314

    
315
        /**
316
         * Asigna la paleta asociada al grid
317
         * @param palette 
318
         */
319
        public void setPalette(GridPalette palette) {
320
                this.palette = palette;
321
        }
322

    
323
        /**
324
         * Asigna el objeto que contiene el estado de transparencia del grid
325
         * @param transparency
326
         */
327
        public void setTransparency(GridTransparency transparency) {
328
                this.transparency = transparency;
329
        }
330

    
331
        /**
332
         * Asigna el desplazamiento en pixeles desde la esquina superior izquierda. Si es null se considera que esta
333
         * funci?n la ha hecho el driver quedando desactivada en el renderizador. Si es as? no debe variar el resultado
334
         * en la visualizacion. 
335
         * Si Supersamplea el renderizador se cargar? una matriz de datos 1:1 por lo que se podr? aplicar un filtro 
336
         * a este buffer de datos leidos independientemente del zoom que tengamos.
337
         * @param step Desplazamiento
338
         */
339
        public void setStep(int[] step) {
340
                this.step = step;
341
        }
342

    
343
        /**
344
         * Asigna el ancho y el alto del BufferedImage. Esto es util para cuando hay supersampling
345
         * que el tama?o del objeto Image no coincide con el buffer con los datos raster.  
346
         * @param w Ancho
347
         * @param h Alto
348
         */
349
        public void setBufferSize(int w, int h) {
350
                this.width = w;
351
                this.height = h;
352
        }
353

    
354
        /**
355
         * Asigna el ancho y el alto en pixeles a dibujar. Esto es util para cuando hay supersampling
356
         * ya que necesitamos saber la relaci?n entre el ancho o alto del objeto image y en ancho o alto en pixels
357
         * del buffer. No vale la informaci?n contenida en rasterBuf (ni rasterBuf.getWidth ni rasterBuf.getHeight) 
358
         * ya que esta es entera y necesitamos el valor en double para mantener la precisi?n del calculo.  
359
         * @param w Ancho
360
         * @param h Alto
361
         */
362
        public void setPixelsToDrawSize(double w, double h) {
363
                this.nWidth = w;
364
                this.nHeight = h;
365
        }
366

    
367
}