1 /* ImageConverter.java -- Loads images asynchronously 2 Copyright (C) 2008 Free Software Foundation, Inc. 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 02110-1301 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 39 package gnu.java.awt.image; 40 41 import gnu.java.awt.image.AsyncImage; 42 43 import java.awt.GraphicsEnvironment; 44 import java.awt.Image; 45 import java.awt.Transparency; 46 import java.awt.image.BufferedImage; 47 import java.awt.image.ColorModel; 48 import java.awt.image.DataBuffer; 49 import java.awt.image.ImageConsumer; 50 import java.awt.image.IndexColorModel; 51 import java.awt.image.ImageObserver; 52 import java.awt.image.SinglePixelPackedSampleModel; 53 import java.awt.image.WritableRaster; 54 import java.util.Hashtable; 55 56 /** 57 * Convert an Image to a BufferedImage. 58 * 59 * @author Roman Kennke (kennke@aicas.com) 60 */ 61 public class ImageConverter implements ImageConsumer 62 { 63 64 public static final String IMAGE_TRANSPARENCY_PROPERTY = 65 "gnu.awt.image.transparency"; 66 67 public static final String IMAGE_PROPERTIES_PROPERTY = 68 "gnu.awt.image.properties"; 69 70 private AsyncImage image; 71 private BufferedImage bImage; 72 private Hashtable imageProperties; 73 private int width, height; 74 private ColorModel colorModel; 75 private ColorModel targetColorModel; 76 ImageConverter()77 public ImageConverter() 78 { 79 width = 0; 80 height = 0; 81 image = new AsyncImage(); 82 } 83 setDimensions(int w, int h)84 public void setDimensions(int w, int h) 85 { 86 width = w; 87 height = h; 88 } 89 setProperties(Hashtable props)90 public void setProperties(Hashtable props) 91 { 92 // Ignore for now. 93 } 94 setColorModel(ColorModel model)95 public void setColorModel(ColorModel model) 96 { 97 colorModel = model; 98 } 99 setHints(int flags)100 public void setHints(int flags) 101 { 102 // Ignore for now. 103 } 104 setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int offset, int scansize)105 public void setPixels(int x, int y, int w, int h, ColorModel model, 106 byte[] pixels, int offset, int scansize) 107 { 108 model = setupColorModel(model); 109 110 if (bImage == null) 111 { 112 createImage(); 113 } 114 115 Integer t = (Integer) imageProperties.get("gnu.awt.image.transparency"); 116 int transparency = t.intValue(); 117 118 if(targetColorModel.equals(model)) 119 { 120 transparency = transferPixels(x, y, w, h, model, pixels, offset, 121 scansize, transparency); 122 } 123 else if (model instanceof IndexColorModel 124 && targetColorModel.equals(ColorModel.getRGBdefault())) 125 { 126 transparency = convertIndexColorModelToSRGB(x, y, w, h, 127 (IndexColorModel) model, 128 pixels, offset, scansize, 129 transparency); 130 } 131 else 132 { 133 transparency = convertPixels(x, y, w, h, model, pixels, offset, 134 scansize, transparency); 135 } 136 137 imageProperties.put("gnu.awt.image.transparency", 138 Integer.valueOf(transparency)); 139 } 140 setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int offset, int scansize)141 public void setPixels(int x, int y, int w, int h, ColorModel model, 142 int[] pixels, int offset, int scansize) 143 { 144 model = setupColorModel(model); 145 if (bImage == null) 146 { 147 createImage(); 148 } 149 150 Integer t = (Integer) imageProperties.get(IMAGE_TRANSPARENCY_PROPERTY); 151 int transparency= t.intValue(); 152 153 if (targetColorModel.equals(model)) 154 { 155 transparency = transferPixels(x, y, w, h, model, pixels, offset, 156 scansize, transparency); 157 } 158 else if (model instanceof IndexColorModel 159 && targetColorModel.equals(ColorModel.getRGBdefault())) 160 { 161 transparency = convertIndexColorModelToSRGB(x, y, w, h, 162 (IndexColorModel) model, 163 pixels, offset, scansize, 164 transparency); 165 } 166 else 167 { 168 transparency = convertPixels(x, y, w, h, model, pixels, offset, 169 scansize, transparency); 170 } 171 172 imageProperties.put(IMAGE_TRANSPARENCY_PROPERTY, 173 Integer.valueOf(transparency)); 174 175 } 176 177 /** 178 * Initialize the color model for this setPixels run: <br/> 179 * 1. if no color model was given use the hinted color model <br/> 180 * 2. if no color model was given and non was hinted use the default sRGB color model. <br/> 181 * Also:<br/> 182 * If no target color model was set use the color model of the given pixels. 183 * @param model 184 * @return 185 */ setupColorModel(ColorModel model)186 private ColorModel setupColorModel(ColorModel model) 187 { 188 // If the given color model is null use the previously hinted color model. 189 if (model == null) 190 model = colorModel; 191 192 // If no color model was given or hinted use default sRGB. 193 if (model == null) 194 model = ColorModel.getRGBdefault(); 195 196 // If no specific color model was requested for the target use the current 197 // pixels model. 198 if (targetColorModel == null) 199 targetColorModel = model; 200 targetColorModel = ColorModel.getRGBdefault(); 201 return model; 202 } 203 204 /** 205 * Creates the image instance into which the pixel data is converted. 206 */ createImage()207 private void createImage() 208 { 209 if (imageProperties == null) 210 { 211 imageProperties = new Hashtable(); 212 } 213 214 imageProperties.put(IMAGE_TRANSPARENCY_PROPERTY, 215 Integer.valueOf(Transparency.OPAQUE)); 216 imageProperties.put(IMAGE_PROPERTIES_PROPERTY, imageProperties); 217 218 // For the sRGB case let the GraphicsEnvironment create an image for us. 219 if (ColorModel.getRGBdefault().equals(targetColorModel)) 220 { 221 bImage = GraphicsEnvironment.getLocalGraphicsEnvironment() 222 .getDefaultScreenDevice() 223 .getDefaultConfiguration() 224 .createCompatibleImage(width, height, Transparency.TRANSLUCENT); 225 } 226 else 227 { 228 WritableRaster raster = 229 targetColorModel.createCompatibleWritableRaster(width, height); 230 bImage = new BufferedImage(targetColorModel, raster, false, 231 imageProperties); 232 } 233 image.setRealImage(bImage); 234 return; 235 } 236 237 /** 238 * Transfers pixels into a raster of the same color model. 239 * 240 * @param x the X coordinate of the source pixel rectangle 241 * @param y the Y coordinate of the source pixel rectangle 242 * @param w the width of the source pixel rectangle 243 * @param h the height of the source pixel rectangle 244 * @param model the color model of the source pixels 245 * @param pixels the pixel data 246 * @param offset the offset in the pixel array 247 * @param scansize the scanline size 248 * @param transparency the assumed transparency 249 * 250 * @return the determined transparency 251 */ transferPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int offset, int scansize, int transparency)252 private int transferPixels(int x, int y, int w, int h, ColorModel model, 253 byte[] pixels, int offset, int scansize, 254 int transparency) 255 { 256 // If we have the same color model, then we can simply drop 257 // the pixel value into the target raster. 258 bImage.getRaster().setDataElements(x, y, w, h, pixels); 259 260 for (int yy = 0; yy < h; yy++) 261 { 262 for (int xx = 0; xx < w; xx++) 263 { 264 int pixel = 0xFF & pixels[yy * scansize + xx + offset]; 265 int alpha = model.getAlpha(pixel); 266 transparency = updateTransparency(alpha, transparency); 267 } 268 } 269 return transparency; 270 } 271 272 /** 273 * Transfers pixels into a raster of the same color model. 274 * 275 * @param x the X coordinate of the source pixel rectangle 276 * @param y the Y coordinate of the source pixel rectangle 277 * @param w the width of the source pixel rectangle 278 * @param h the height of the source pixel rectangle 279 * @param model the color model of the source pixels 280 * @param pixels the pixel data 281 * @param offset the offset in the pixel array 282 * @param scansize the scanline size 283 * @param transparency the assumed transparency 284 * 285 * @return the determined transparency 286 */ transferPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int offset, int scansize, int transparency)287 private int transferPixels(int x, int y, int w, int h, ColorModel model, 288 int[] pixels, int offset, int scansize, 289 int transparency) 290 { 291 // If we have the same color model, then we can simply drop 292 // the pixel value into the target raster. 293 bImage.getRaster().setDataElements(x, y, w, h, pixels); 294 295 for (int yy = 0; yy < h; yy++) 296 { 297 for (int xx = 0; xx < w; xx++) 298 { 299 int pixel = pixels[yy * scansize + xx + offset]; 300 int alpha = model.getAlpha(pixel); 301 transparency = updateTransparency(alpha, transparency); 302 } 303 } 304 return transparency; 305 } 306 307 /** 308 * Converts pixel from one color model to another, and stores them in the 309 * target image. 310 * 311 * @param x the X coordinate of the source pixel rectangle 312 * @param y the Y coordinate of the source pixel rectangle 313 * @param w the width of the source pixel rectangle 314 * @param h the height of the source pixel rectangle 315 * @param model the color model of the source pixels 316 * @param pixels the pixel data 317 * @param offset the offset in the pixel array 318 * @param scansize the scanline size 319 * @param transparency the assumed transparency 320 * 321 * @return the determined transparency 322 */ convertPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int offset, int scansize, int transparency)323 private int convertPixels(int x, int y, int w, int h, ColorModel model, 324 byte[] pixels, int offset, int scansize, 325 int transparency) 326 { 327 // If the color models are not the same, we must convert the 328 // pixel values from one model to the other. 329 Object dataEl = null; 330 // Convert pixels to the destination color model. 331 for (int yy = 0; yy < h; yy++) 332 { 333 for (int xx = 0; xx < w; xx++) 334 { 335 int pixel = 0xFF & pixels[yy * scansize + xx + offset]; 336 int rgb = model.getRGB(pixel); 337 int alpha = model.getAlpha(pixel); 338 transparency = updateTransparency(alpha, transparency); 339 dataEl = targetColorModel.getDataElements(rgb, dataEl); 340 bImage.getRaster().setDataElements(x + xx, y + yy, dataEl); 341 } 342 } 343 return transparency; 344 } 345 346 /** 347 * Converts pixel from one color model to another, and stores them in the 348 * target image. 349 * 350 * @param x the X coordinate of the source pixel rectangle 351 * @param y the Y coordinate of the source pixel rectangle 352 * @param w the width of the source pixel rectangle 353 * @param h the height of the source pixel rectangle 354 * @param model the color model of the source pixels 355 * @param pixels the pixel data 356 * @param offset the offset in the pixel array 357 * @param scansize the scanline size 358 * @param transparency the assumed transparency 359 * 360 * @return the determined transparency 361 */ convertPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int offset, int scansize, int transparency)362 private int convertPixels(int x, int y, int w, int h, ColorModel model, 363 int[] pixels, int offset, int scansize, 364 int transparency) 365 { 366 // If the color models are not the same, we must convert the 367 // pixel values from one model to the other. 368 Object dataEl = null; 369 // Convert pixels to the destination color model. 370 for (int yy = 0; yy < h; yy++) 371 { 372 for (int xx = 0; xx < w; xx++) 373 { 374 int pixel = pixels[yy * scansize + xx + offset]; 375 int rgb = model.getRGB(pixel); 376 int alpha = model.getAlpha(pixel); 377 transparency = updateTransparency(alpha, transparency); 378 dataEl = targetColorModel.getDataElements(rgb, dataEl); 379 bImage.getRaster().setDataElements(x + xx, y + yy, dataEl); 380 } 381 } 382 return transparency; 383 } 384 385 /** 386 * Converts pixels from an index color model to the target image. 387 * 388 * @param x the X coordinate of the source pixel rectangle 389 * @param y the Y coordinate of the source pixel rectangle 390 * @param w the width of the source pixel rectangle 391 * @param h the height of the source pixel rectangle 392 * @param model the color model of the source pixels 393 * @param pixels the pixel data 394 * @param offset the offset in the pixel array 395 * @param scansize the scanline size 396 * @param transparency the assumed transparency 397 * 398 * @return the determined transparency 399 */ convertIndexColorModelToSRGB(int x, int y, int w, int h, IndexColorModel model, byte[] pixels, int offset, int scansize, int transparency)400 private int convertIndexColorModelToSRGB(int x, int y, int w, int h, 401 IndexColorModel model, 402 byte[] pixels, int offset, 403 int scansize, int transparency) 404 { 405 406 int mapSize = model.getMapSize(); 407 int[] colorMap = new int[mapSize]; 408 for(int i=0; i < mapSize; i++) 409 { 410 colorMap[i] = model.getRGB(i); 411 } 412 413 WritableRaster raster = bImage.getRaster(); 414 SinglePixelPackedSampleModel sampleMode = 415 (SinglePixelPackedSampleModel) raster.getSampleModel(); 416 DataBuffer dataBuffer = (DataBuffer) raster.getDataBuffer(); 417 418 int rasterOffset = sampleMode.getOffset(x,y)+dataBuffer.getOffset(); 419 int rasterScanline = sampleMode.getScanlineStride(); 420 421 for (int yy = 0; yy < h; yy++) 422 { 423 int xoffset = offset; 424 for (int xx = 0; xx < w; xx++) 425 { 426 int argb = colorMap[(pixels[xoffset++] & 0xFF)]; 427 dataBuffer.setElem(rasterOffset+xx, argb); 428 int alpha = (argb >>> 24); 429 transparency = updateTransparency(alpha, transparency); 430 } 431 offset += scansize; 432 rasterOffset += rasterScanline; 433 } 434 435 return transparency; 436 } 437 438 /** 439 * Converts pixels from an index color model to the target image. 440 * 441 * @param x the X coordinate of the source pixel rectangle 442 * @param y the Y coordinate of the source pixel rectangle 443 * @param w the width of the source pixel rectangle 444 * @param h the height of the source pixel rectangle 445 * @param model the color model of the source pixels 446 * @param pixels the pixel data 447 * @param offset the offset in the pixel array 448 * @param scansize the scanline size 449 * @param transparency the assumed transparency 450 * 451 * @return the determined transparency 452 */ convertIndexColorModelToSRGB(int x, int y, int w, int h, IndexColorModel model, int[] pixels, int offset, int scansize, int transparency)453 private int convertIndexColorModelToSRGB(int x, int y, int w, int h, 454 IndexColorModel model, int[] pixels, 455 int offset, int scansize, 456 int transparency) 457 { 458 int mapSize = model.getMapSize(); 459 int[] colorMap = new int[mapSize]; 460 for(int i=0; i < mapSize; i++) 461 { 462 colorMap[i] = model.getRGB(i); 463 } 464 465 WritableRaster raster = bImage.getRaster(); 466 SinglePixelPackedSampleModel sampleMode = 467 (SinglePixelPackedSampleModel) raster.getSampleModel(); 468 DataBuffer dataBuffer = (DataBuffer)raster.getDataBuffer(); 469 470 int rasterOffset = sampleMode.getOffset(x, y) + dataBuffer.getOffset(); 471 int rasterScanline = sampleMode.getScanlineStride(); 472 473 for (int yy = 0; yy < h; yy++) 474 { 475 int xoffset = offset; 476 for (int xx = 0; xx < w; xx++) 477 { 478 int argb = colorMap[pixels[xoffset++]]; 479 dataBuffer.setElem(rasterOffset + xx, argb); 480 int alpha = (argb >>> 24); 481 transparency = updateTransparency(alpha, transparency); 482 } 483 offset += scansize; 484 rasterOffset += rasterScanline; 485 } 486 487 return transparency; 488 } 489 490 /** 491 * Updates the transparency information according to the alpha pixel value. 492 * 493 * @param alpha the alpha pixel value 494 * @param transparency the old transparency 495 * 496 * @return the updated transparency 497 */ updateTransparency(int alpha, int transparency)498 private int updateTransparency(int alpha, int transparency) 499 { 500 if (alpha != 0xFF) 501 { 502 if (alpha == 0x00 && transparency <= Transparency.BITMASK) 503 { 504 transparency = Transparency.BITMASK; 505 } 506 else if (transparency < Transparency.TRANSLUCENT) 507 { 508 transparency = Transparency.TRANSLUCENT; 509 } 510 } 511 return transparency; 512 } 513 imageComplete(int status)514 public void imageComplete(int status) 515 { 516 image.notifyObservers(ImageObserver.ALLBITS, 0, 0, width, height); 517 } 518 setTargetColorModel(ColorModel model)519 public void setTargetColorModel(ColorModel model) 520 { 521 targetColorModel = model; 522 } 523 getImage()524 public Image getImage() 525 { 526 return image; 527 } 528 } 529