Statistics
| Revision:

root / trunk / libraries / libRaster / src / org / gvsig / raster / grid / render / ImageDrawer.java @ 37962

History | View | Annotate | Download (13.8 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.GridTransparency;
27
import org.gvsig.raster.process.RasterTask;
28
import org.gvsig.raster.process.RasterTaskQueue;
29
import org.gvsig.raster.util.Cancellable;
30

    
31
/**
32
 * Objeto para la escritura de datos desde un buffer a un objeto Image. En este nivel de
33
 * renderizado no se gestiona extents, ni rotaciones ni coordenadas del mundo, solo la
34
 * escritura desde un buffer hasta otro de tama?o dado. Por medio de par?metros y de objetos
35
 * de estado varia el resultado de la escritura, selecci?n de bandas a escribir desde el buffer
36
 * a RGB, transparencias aplicadas o paletas.
37
 *
38
 * @author Nacho Brodin (nachobrodin@gmail.com)
39
 */
40
public class ImageDrawer {
41
        /**
42
         * Fuente de datos para el renderizado
43
         */
44
        private IBuffer   rasterBuf = null;
45
        private double[]  step      = null;
46
        /**
47
         * Ancho y alto del objeto image
48
         */
49
        private int       width     = 0;
50
        private int       height    = 0;
51
        private Rendering rendering = null;
52

    
53
        public ImageDrawer(Rendering rendering) {
54
                this.rendering = rendering;
55
        }
56

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

    
77
                BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
78

    
79
                // Dibujado de raster de 1 o 2 bandas.
80
                // adaptBufferToRender(replicateBand, renderBands);
81

    
82
                if (rasterBuf.getDataType() != IBuffer.TYPE_BYTE)
83
                        rasterBuf = convertToByte(rasterBuf);
84

    
85
                // Asigna la banda de transparencia si existe esta.
86
                // assignTransparencyBand(renderBands);
87

    
88
                byte[] data = new byte[rasterBuf.getBandCount()];
89
                GridTransparency transparency = rendering.getLastTransparency();
90
                if (transparency != null && transparency.isTransparencyActive()) {
91
                        if (transparency.existAlphaBand() &&
92
                                        transparency.getAlphaBand() != null &&
93
                                        (transparency.getAlphaBand().getDataType() != IBuffer.TYPE_BYTE))
94
                                transparency.setAlphaBand(convertToByte(transparency.getAlphaBand()));
95
                        drawWithTransparency(image, data, (step != null), cancel);
96
                } else
97
                        drawByte(image, data, (step != null), cancel);
98

    
99
                step = null;
100
                return image;
101
        }
102

    
103
        /**
104
         * Calcula los vectores de desplazamiento en pixels en X e Y cuando se supersamplea.
105
         * @param r Array de desplazamientos para las filas. Debe tener espacio reservado
106
         * @param c Array de desplazamientos para las columnas. Debe tener espacio reservado
107
         * cargados.
108
         */
109
        private void calcSupersamplingStepsArrays(int[] r, int[] c) {
110
                double pos = step[1];
111
                for(int row = 0; row < r.length; row ++) {
112
                        r[row] = (int)(pos / step[3]);
113
                        pos ++;
114
                }
115
                pos = step[0];
116
                for(int col = 0; col < c.length; col ++) {
117
                        c[col] = (int)(pos / step[2]);
118
                        pos ++;
119
                }
120
        }
121

    
122
        /**
123
         * Dibuja un raster sobre un BufferedImage
124
         * @param image BufferedImage sobre el que se dibuja
125
         * @param data buffer vacio. Se trata de un array de bytes donde cada elemento representa una banda.
126
         * @param supersampling true si se necesita supersamplear y false si no se necesita
127
         * @throws InterruptedException 
128
         */
129
        private void drawByte(BufferedImage image, byte[] data, boolean supersampling, Cancellable cancel) throws InterruptedException {
130
                RasterTask task = RasterTaskQueue.get(Thread.currentThread().toString());
131

    
132
                if (supersampling) {
133
                        int[] r = new int[height];
134
                        int[] c = new int[width];
135
                        calcSupersamplingStepsArrays(r, c);
136
                        for (int row = 0; row < height; row++) {
137
                                if (cancel.isCanceled())
138
                                        return;
139
                                for (int col = 0; col < width; col++) {
140
                                        try {
141
                                                rasterBuf.getElemByte(r[row], c[col], data);
142
                                                image.setRGB(col, row, (0xff000000 + ((data[0] & 0xff) << 16)
143
                                                                + ((data[1] & 0xff) << 8) + (data[2] & 0xff)));
144
                                        } catch (ArrayIndexOutOfBoundsException e) {
145
                                                System.err.println("== Size Image:" + image.getWidth() + " " + image.getHeight());
146
                                                System.err.println("== Position required:" + col + " " + row);
147
                                                break;
148
                                        }
149
                                }
150
                                if (task.getEvent() != null)
151
                                        task.manageEvent(task.getEvent());
152
                        }
153
                } else {
154
                        
155
                        for (int row = 0; row < rasterBuf.getHeight(); row++) {
156
                                if (row % 200 == 0)
157
                                        if (cancel.isCanceled())
158
                                                return;
159
                                
160
                                for (int col = 0; col < rasterBuf.getWidth(); col++) {
161
                                        try {
162
                                                rasterBuf.getElemByte(row, col, data);
163
                                                image.setRGB(col, row, (0xff000000 + ((data[0] & 0xff) << 16)
164
                                                                + ((data[1] & 0xff) << 8) + (data[2] & 0xff)));
165
                                        } catch (ArrayIndexOutOfBoundsException ex) {
166
                                                System.err.println("== Size Image:" + image.getWidth() + " " + image.getHeight());
167
                                                System.err.println("== Position required:" + col + " " + row);
168
                                                break;
169
                                        }
170
                                }
171
                                if (task.getEvent() != null)
172
                                        task.manageEvent(task.getEvent());
173
                        }
174
                }
175
        }
176

    
177
        /**
178
         * Dibuja un raster sobre un BufferedImage con las propiedades de paleta y transparencia
179
         * @param image BufferedImage sobre el que se dibuja
180
         * @param data buffer vacio. Se trata de un array de bytes donde cada elemento representa una banda.
181
         * @param supersampling true si se necesita supersamplear y false si no se necesita
182
         * @param cancel 
183
         * @throws InterruptedException 
184
         */
185
        private void drawWithTransparency(BufferedImage image, byte[] data, boolean supersampling, Cancellable cancel) throws InterruptedException {
186
                RasterTask task = RasterTaskQueue.get(Thread.currentThread().toString());
187
                int value = 0;
188
                GridTransparency transparency = rendering.getLastTransparency();
189
//                try {
190
                if (supersampling) {
191
                        int[] r = new int[height];
192
                        int[] c = new int[width];
193
                        calcSupersamplingStepsArrays(r, c);
194
                        for (int row = 0; row < height; row++) {
195
                                if (cancel.isCanceled())
196
                                        return;
197
                                
198
                                for (int col = 0; col < width; col++) {
199
                                        try {
200
                                                rasterBuf.getElemByte(r[row], c[col], data);
201
                                                value = transparency.processRGB(data[0] & 0xff, data[1] & 0xff, data[2] & 0xff, r[row], c[col]);
202
                                                image.setRGB(col, row, value);
203
                                        } catch (ArrayIndexOutOfBoundsException e) {
204
                                                System.err.println("== Size Image:" + image.getWidth() + " " + image.getHeight());
205
                                                System.err.println("== Position required:" + col + " " + row);
206
                                                break;
207
                                        }
208
                                }
209
                                if (task.getEvent() != null)
210
                                        task.manageEvent(task.getEvent());
211
                        }
212
                } else {
213
                        for (int row = 0; row < rasterBuf.getHeight(); row++) {
214
                                if (cancel.isCanceled())
215
                                        return;
216

    
217
                                for (int col = 0; col < rasterBuf.getWidth(); col++) {
218
                                        try {
219
                                                rasterBuf.getElemByte(row, col, data);
220
                                                value = transparency.processRGB(data[0] & 0xff, data[1] & 0xff, data[2] & 0xff, row, col);
221
                                                image.setRGB(col, row, value);
222
                                        } catch (ArrayIndexOutOfBoundsException e) {
223
                                                System.err.println("== Size Image:" + image.getWidth() + " " + image.getHeight());
224
                                                System.err.println("== Position required:" + col + " " + row);
225
                                                break;
226
                                        }
227
                                }
228
                                if (task.getEvent() != null)
229
                                        task.manageEvent(task.getEvent());
230
                        }
231
                }
232
//                } finally {
233
//                        Quitamos el uso del free para no invocar al garbage collector en numerosas
234
//                        iteraciones
235
//                        transparency.free();
236
//                }
237
        }
238
        /**
239
         * Intercala bandas en el buffer dependiendo de si hay que replicar o meter
240
         * bandas en negro. Esto tiene es valido para buffers con solo una banda ya que
241
         * el dibujado sobre Graphics debe ser R, G, B.
242
         *
243
         * @param replicateBand false si no se replican bandas y las que no existen
244
         * se ponen en negro y false si hay que dibujar la misma en R,G y B. Esto
245
         * tiene sentido si el raster tiene solo 1 o 2 bandas.
246
         * @param renderBands array con las posiciones de renderizado.
247
         *  A la hora de renderizar hay que tener en cuenta que solo se renderizan las
248
         * tres primeras bandas del buffer por lo que solo se tienen en cuenta los tres primeros
249
         * elementos. Por ejemplo, el array {1, 0, 3} dibujar? sobre el Graphics las bandas 1,0 y 3 de un
250
         * raster de al menos 4 bandas.La notaci?n con -1 en alguna posici?n del vector solo tiene sentido
251
         * en la visualizaci?n pero no se puede as?gnar una banda del buffer a null.
252
         * Algunos ejemplos:
253
         * <P>
254
         * {-1, 0, -1} Dibuja la banda 0 del raster en la G de la visualizaci?n.
255
         * Si replicateBand es true R = G = B sino R = B = 0
256
         * {1, 0, 3} La R = banda 1 del raster, G = 0 y B = 3
257
         * {0} La R = banda 0 del raster. Si replicateBand es true R = G = B sino G = B = 0
258
         * </P>
259
         */
260
        /*private void adaptBufferToRender(boolean replicateBand, int[] renderBands){
261
                byte[][] aux = null;
262
                if(rasterBuf.getBandCount() < 3){
263
                        for(int i = 0; i < renderBands.length; i++){
264
                                if( replicateBand && renderBands[i] == -1)
265
                                        rasterBuf.replicateBand(0, i);
266
                                if( !replicateBand && renderBands[i] == -1){
267
                                        if(aux == null)
268
                                                aux = rasterBuf.createByteBand(rasterBuf.getWidth(), rasterBuf.getHeight(), (byte)0);
269
                                        rasterBuf.addBandByte(i, aux);
270
                                }
271
                        }
272
                }
273
        }*/
274

    
275
        /**
276
         * Asigna al objeto GridTransparency la banda de transparencia si la tiene para
277
         * tenerla en cuenta en el renderizado.
278
         * @param renderBands Lista de bandas a renderizar
279
         * @param ts Objeto con las propiedades de transparencia del Grid.
280
         */
281
        /*private void assignTransparencyBand(int[] renderBands) {
282
                if(transparency != null){
283
                        for(int i = 0; i < transparency.getTransparencyBandNumberList().size(); i ++) {
284
                                for(int j = 0; j < renderBands.length; j ++) {
285
                                        if(renderBands[j] == ((Integer)transparency.getTransparencyBandNumberList().get(i)).intValue()){
286
                                                if(transparency.getBand() == null)
287
                                                        transparency.setBand(rasterBuf.getBandBuffer(renderBands[j]));
288
                                                else {
289
                                                        IBuffer outBuf = transparency.getBand().cloneBuffer();
290
                                                        transparency.mergeTransparencyBands(new IBuffer[]{transparency.getBand(), rasterBuf.getBandBuffer(renderBands[j])}, outBuf);
291
                                                }
292
                                        }
293
                                }
294
                        }
295
                }
296
        }*/
297

    
298
        private IBuffer convertToByte(IBuffer buf) throws InterruptedException {
299
                IBuffer b = RasterBuffer.getBuffer(IBuffer.TYPE_BYTE, buf.getWidth(), buf.getHeight(), buf.getBandCount(), true);
300
                if(buf.getDataType() == IBuffer.TYPE_SHORT) {
301
                        for (int nBand = 0; nBand < buf.getBandCount(); nBand++)
302
                                for (int row = 0; row < buf.getHeight(); row++)
303
                                        for (int col = 0; col < buf.getWidth(); col++)
304
                                                b.setElem(row, col, nBand, (byte)(buf.getElemShort(row, col, nBand) & 0xffff));
305
                }
306
                if(buf.getDataType() == IBuffer.TYPE_INT) {
307
                        for (int nBand = 0; nBand < buf.getBandCount(); nBand++)
308
                                for (int row = 0; row < buf.getHeight(); row++)
309
                                        for (int col = 0; col < buf.getWidth(); col++)
310
                                                b.setElem(row, col, nBand, (byte)(buf.getElemInt(row, col, nBand) & 0xffffffff));
311
                }
312
                if(buf.getDataType() == IBuffer.TYPE_FLOAT) {
313
                        for (int nBand = 0; nBand < buf.getBandCount(); nBand++)
314
                                for (int row = 0; row < buf.getHeight(); row++)
315
                                        for (int col = 0; col < buf.getWidth(); col++)
316
                                                b.setElem(row, col, nBand, (byte)(Math.round(buf.getElemFloat(row, col, nBand))));
317
                }
318
                if(buf.getDataType() == IBuffer.TYPE_DOUBLE) {
319
                        for (int nBand = 0; nBand < buf.getBandCount(); nBand++)
320
                                for (int row = 0; row < buf.getHeight(); row++)
321
                                        for (int col = 0; col < buf.getWidth(); col++)
322
                                                b.setElem(row, col, nBand, (byte)(Math.round(buf.getElemDouble(row, col, nBand))));
323
                }
324
                return b;
325
        }
326

    
327
        /**
328
         * Asigna el buffer a renderizar
329
         * @param b Buffer a renderizar
330
         */
331
        public void setBuffer(IBuffer b) {
332
                this.rasterBuf = b;
333
        }
334

    
335
        /**
336
         * Asigna la paleta asociada al grid
337
         * @param palette
338
         */
339
        /*public void setPalette(GridPalette palette) {
340
                this.palette = palette;
341
        }*/
342

    
343
        /**
344
         * Asigna el desplazamiento en pixeles desde la esquina superior izquierda. Si es null se considera que esta
345
         * funci?n la ha hecho el driver quedando desactivada en el renderizador. Si es as? no debe variar el resultado
346
         * en la visualizacion.
347
         * Si Supersamplea el renderizador se cargar? una matriz de datos 1:1 por lo que se podr? aplicar un filtro
348
         * a este buffer de datos leidos independientemente del zoom que tengamos.
349
         * @param step Desplazamiento
350
         */
351
        public void setStep(double[] step) {
352
                this.step = step;
353
        }
354

    
355
        /**
356
         * Asigna el ancho y el alto del BufferedImage. Esto es util para cuando hay supersampling
357
         * que el tama?o del objeto Image no coincide con el buffer con los datos raster.
358
         * @param w Ancho
359
         * @param h Alto
360
         */
361
        public void setBufferSize(int w, int h) {
362
                this.width = w;
363
                this.height = h;
364
        }
365

    
366
}