Source for gnu.java.awt.image.ImageConverter

   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: 
  77:   public ImageConverter()
  78:   {
  79:     width = 0;
  80:     height = 0;
  81:     image = new AsyncImage();
  82:   }
  83: 
  84:   public void setDimensions(int w, int h)
  85:   {
  86:     width = w;
  87:     height = h;
  88:   }
  89: 
  90:   public void setProperties(Hashtable props)
  91:   {
  92:     // Ignore for now.
  93:   }
  94: 
  95:   public void setColorModel(ColorModel model)
  96:   {
  97:     colorModel = model;
  98:   }
  99: 
 100:   public void setHints(int flags)
 101:   {
 102:     // Ignore for now.
 103:   }
 104: 
 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: 
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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: 
 514:   public void imageComplete(int status)
 515:   {
 516:     image.notifyObservers(ImageObserver.ALLBITS, 0, 0, width, height);
 517:   }
 518: 
 519:   public void setTargetColorModel(ColorModel model)
 520:   {
 521:     targetColorModel = model;
 522:   }
 523: 
 524:   public Image getImage()
 525:   {
 526:     return image;
 527:   }
 528: }