001 /* 002 * ImageCreator 003 * 004 * Copyright (c) 2001, 2002, 2003 Marco Schmidt. 005 * All rights reserved. 006 */ 007 008 package net.sourceforge.jiu.gui.awt; 009 010 import net.sourceforge.jiu.data.BilevelImage; 011 import net.sourceforge.jiu.data.Gray16Image; 012 import net.sourceforge.jiu.data.Gray8Image; 013 import net.sourceforge.jiu.data.MemoryRGB24Image; 014 import net.sourceforge.jiu.data.Palette; 015 import net.sourceforge.jiu.data.Paletted8Image; 016 import net.sourceforge.jiu.data.PixelImage; 017 import net.sourceforge.jiu.data.RGB24Image; 018 import net.sourceforge.jiu.data.RGB48Image; 019 import net.sourceforge.jiu.data.RGBIndex; 020 import java.awt.Frame; 021 import java.awt.Image; 022 import java.awt.Toolkit; 023 import java.awt.image.ImageObserver; 024 import java.awt.image.MemoryImageSource; 025 import java.awt.image.PixelGrabber; 026 027 /** 028 * A class to create java.awt.Image objects from various JIU image data types 029 * and vice versa. 030 * java.awt.Image objects can be used with the AWT and Swing GUI environments. 031 * 032 * @author Marco Schmidt 033 */ 034 public class ImageCreator 035 { 036 /** 037 * The default transparency value to be used: full opacity. 038 */ 039 public static final int DEFAULT_ALPHA = 0xff000000; 040 private static Frame frame; 041 042 private ImageCreator() 043 { 044 } 045 046 /** 047 * Creates a {@link java.awt.Image} object from a pixel array. 048 * Internally, a {@link java.awt.Frame} object is used to call its 049 * {@link java.awt.Frame#createImage} method 050 * with a {@link java.awt.image.MemoryImageSource} object. 051 * 052 * @param pixels the image pixel data in the typical RGBA 32-bit format, one int per pixel 053 * @param width the horizontal resolution in pixels of the image to be created 054 * @param height the vertical resolution in pixels of the image to be created 055 */ 056 public static Image createImage(int[] pixels, int width, int height) 057 { 058 if (width < 1 || height < 1) 059 { 060 throw new IllegalArgumentException("Error -- width and height " + 061 "must both be larger than zero."); 062 } 063 if (pixels == null) 064 { 065 throw new IllegalArgumentException("Error -- the pixel array " + 066 "must be non-null."); 067 } 068 if (pixels.length < width * height) 069 { 070 throw new IllegalArgumentException("Error -- the pixel array " + 071 "must contain at least width times height items."); 072 } 073 if (frame == null) 074 { 075 frame = new Frame(); 076 } 077 return frame.createImage(new MemoryImageSource(width, height, pixels, 0, width)); 078 } 079 080 /** 081 * Creates an instance of {@link java.awt.Image} from an instance of 082 * {@link RGB24Image}. 083 * This will require <code>image.getWidth() * image.getHeight() * 4</code> 084 * bytes of free memory. 085 * This method checks the type of the argument image via instanceof 086 * and the calls the right convertToAwtImage method of this class. 087 * @param image the RGB24Image to be converted 088 * @return newly-created AWT image instance 089 */ 090 public static Image convertToAwtImage(PixelImage image, int alpha) 091 { 092 if (image == null) 093 { 094 return null; 095 } 096 if (image instanceof RGB24Image) 097 { 098 return convertToAwtImage((RGB24Image)image, alpha); 099 } 100 else 101 if (image instanceof RGB48Image) 102 { 103 return convertToAwtImage((RGB48Image)image, alpha); 104 } 105 else 106 if (image instanceof Gray8Image) 107 { 108 return convertToAwtImage((Gray8Image)image, alpha); 109 } 110 else 111 if (image instanceof Gray16Image) 112 { 113 return convertToAwtImage((Gray16Image)image, alpha); 114 } 115 else 116 if (image instanceof Paletted8Image) 117 { 118 return convertToAwtImage((Paletted8Image)image, alpha); 119 } 120 else 121 if (image instanceof BilevelImage) 122 { 123 return convertToAwtImage((BilevelImage)image, alpha); 124 } 125 else 126 { 127 return null; 128 } 129 } 130 131 /** 132 * Convert a BilevelImage object to an AWT image object. 133 * @param image the image to be converted 134 * @param alpha the transparency value to be written to each 135 * pixel in the resulting image 136 * @return newly-created AWT image 137 */ 138 public static Image convertToAwtImage(BilevelImage image, int alpha) 139 { 140 if (image == null) 141 { 142 return null; 143 } 144 Toolkit toolkit = Toolkit.getDefaultToolkit(); 145 if (toolkit == null) 146 { 147 return null; 148 } 149 int width = image.getWidth(); 150 int height = image.getHeight(); 151 if (width < 1 || height < 1) 152 { 153 return null; 154 } 155 int bytesPerRow = (width + 7) / 8; 156 int[] pixels = new int[width * height]; 157 byte[] row = new byte[bytesPerRow]; 158 int destOffset = 0; 159 for (int y = 0; y < height; y++) 160 { 161 image.getPackedBytes(0, y, width, row, 0, 0); 162 RGBA.convertFromPackedBilevel(row, 0, alpha, pixels, destOffset, width); 163 destOffset += width; 164 } 165 return toolkit.createImage(new MemoryImageSource(width, height, pixels, 0, width)); 166 } 167 168 /** 169 * Creates an AWT Image object from a Gray16Image object and an alpha value. 170 * This is done by allocating a new int array with image.getWidth() times 171 * image.getHeight() elements, copying the data to those ints (using transparency 172 * information from the top eight bits of the alpha argument) and calling 173 * Toolkit.createImage with a MemoryImageSource of those int[] pixels. 174 * @param image the grayscale image to be converted 175 * @param alpha the alpha value, bits must only be set in the top eight bits 176 * @return AWT image created from the argument input image 177 */ 178 public static Image convertToAwtImage(Gray16Image image, int alpha) 179 { 180 if (image == null) 181 { 182 return null; 183 } 184 Toolkit toolkit = Toolkit.getDefaultToolkit(); 185 if (toolkit == null) 186 { 187 return null; 188 } 189 int width = image.getWidth(); 190 int height = image.getHeight(); 191 if (width < 1 || height < 1) 192 { 193 return null; 194 } 195 int[] pixels = new int[width * height]; 196 short[] gray = new short[width]; 197 int destOffset = 0; 198 for (int y = 0; y < height; y++) 199 { 200 image.getShortSamples(0, 0, y, width, 1, gray, 0); 201 RGBA.convertFromGray16(gray, 0, alpha, pixels, destOffset, width); 202 destOffset += width; 203 } 204 return toolkit.createImage(new MemoryImageSource(width, height, pixels, 0, width)); 205 } 206 207 /** 208 * Creates an AWT Image object from a Gray8Image object and an alpha value. 209 * This is done by allocating a new int array with image.getWidth() times 210 * image.getHeight() elements, copying the data to those ints (using transparency 211 * information from the top eight bits of the alpha argument) and calling 212 * Toolkit.createImage with a MemoryImageSource of those int[] pixels. 213 * 214 * @param image the grayscale image to be converted 215 * @param alpha the alpha value, bits must only be set in the top eight bits 216 * @return AWT image created from the argument input image 217 */ 218 public static Image convertToAwtImage(Gray8Image image, int alpha) 219 { 220 if (image == null) 221 { 222 return null; 223 } 224 Toolkit toolkit = Toolkit.getDefaultToolkit(); 225 if (toolkit == null) 226 { 227 return null; 228 } 229 int width = image.getWidth(); 230 int height = image.getHeight(); 231 if (width < 1 || height < 1) 232 { 233 return null; 234 } 235 int[] pixels = new int[width * height]; 236 byte[] gray = new byte[width]; 237 int destOffset = 0; 238 for (int y = 0; y < height; y++) 239 { 240 image.getByteSamples(0, 0, y, width, 1, gray, 0); 241 RGBA.convertFromGray8(gray, 0, alpha, pixels, destOffset, width); 242 destOffset += width; 243 } 244 return toolkit.createImage(new MemoryImageSource(width, height, pixels, 0, width)); 245 } 246 247 public static Image convertToAwtImage(Paletted8Image image, int alpha) 248 { 249 if (image == null) 250 { 251 return null; 252 } 253 Toolkit toolkit = Toolkit.getDefaultToolkit(); 254 if (toolkit == null) 255 { 256 return null; 257 } 258 int width = image.getWidth(); 259 int height = image.getHeight(); 260 Palette palette = image.getPalette(); 261 if (width < 1 || height < 1 || palette == null) 262 { 263 return null; 264 } 265 int[] red = new int[palette.getNumEntries()]; 266 int[] green = new int[palette.getNumEntries()]; 267 int[] blue = new int[palette.getNumEntries()]; 268 for (int i = 0; i < palette.getNumEntries(); i++) 269 { 270 red[i] = palette.getSample(RGBIndex.INDEX_RED, i); 271 green[i] = palette.getSample(RGBIndex.INDEX_GREEN, i); 272 blue[i] = palette.getSample(RGBIndex.INDEX_BLUE, i); 273 } 274 int[] pixels = new int[width * height]; 275 byte[] data = new byte[width]; 276 int destOffset = 0; 277 for (int y = 0; y < height; y++) 278 { 279 image.getByteSamples(0, 0, y, width, 1, data, 0); 280 RGBA.convertFromPaletted8(data, 0, alpha, red, green, blue, pixels, destOffset, width); 281 destOffset += width; 282 } 283 return toolkit.createImage(new MemoryImageSource(width, height, pixels, 0, width)); 284 285 } 286 287 public static Image convertToAwtImage(RGB24Image image, int alpha) 288 { 289 if (image == null) 290 { 291 return null; 292 } 293 Toolkit toolkit = Toolkit.getDefaultToolkit(); 294 if (toolkit == null) 295 { 296 return null; 297 } 298 int width = image.getWidth(); 299 int height = image.getHeight(); 300 if (width < 1 || height < 1) 301 { 302 return null; 303 } 304 int[] pixels = new int[width * height]; 305 byte[] red = new byte[width]; 306 byte[] green = new byte[width]; 307 byte[] blue = new byte[width]; 308 int destOffset = 0; 309 for (int y = 0; y < height; y++) 310 { 311 image.getByteSamples(RGBIndex.INDEX_RED, 0, y, width, 1, red, 0); 312 image.getByteSamples(RGBIndex.INDEX_GREEN, 0, y, width, 1, green, 0); 313 image.getByteSamples(RGBIndex.INDEX_BLUE, 0, y, width, 1, blue, 0); 314 RGBA.convertFromRGB24(red, 0, green, 0, blue, 0, alpha, pixels, destOffset, width); 315 destOffset += width; 316 } 317 return toolkit.createImage(new MemoryImageSource(width, height, pixels, 0, width)); 318 319 } 320 321 public static Image convertToAwtImage(RGB48Image image, int alpha) 322 { 323 if (image == null) 324 { 325 return null; 326 } 327 Toolkit toolkit = Toolkit.getDefaultToolkit(); 328 if (toolkit == null) 329 { 330 return null; 331 } 332 int width = image.getWidth(); 333 int height = image.getHeight(); 334 if (width < 1 || height < 1) 335 { 336 return null; 337 } 338 int[] pixels = new int[width * height]; 339 short[] red = new short[width]; 340 short[] green = new short[width]; 341 short[] blue = new short[width]; 342 int destOffset = 0; 343 for (int y = 0; y < height; y++) 344 { 345 image.getShortSamples(RGBIndex.INDEX_RED, 0, y, width, 1, red, 0); 346 image.getShortSamples(RGBIndex.INDEX_GREEN, 0, y, width, 1, green, 0); 347 image.getShortSamples(RGBIndex.INDEX_BLUE, 0, y, width, 1, blue, 0); 348 RGBA.convertFromRGB48(red, 0, green, 0, blue, 0, alpha, pixels, destOffset, width); 349 destOffset += width; 350 } 351 return toolkit.createImage(new MemoryImageSource(width, height, pixels, 0, width)); 352 } 353 354 /** 355 * Creates an {@link RGB24Image} from the argument AWT image instance. 356 * @param image AWT image object to be converted to a {@link RGB24Image} 357 * @return a {@link RGB24Image} object holding the image data from the argument image 358 */ 359 public static RGB24Image convertImageToRGB24Image(Image image) 360 { 361 if (image == null) 362 { 363 return null; 364 } 365 int width = image.getWidth(null); 366 int height = image.getHeight(null); 367 if (width < 1 || height < 1) 368 { 369 return null; 370 } 371 int[] pixels = new int[width * height]; 372 PixelGrabber pg = new PixelGrabber(image, 0, 0, width, height, pixels, 0, width); 373 try 374 { 375 pg.grabPixels(); 376 } 377 catch (InterruptedException e) 378 { 379 return null; 380 } 381 if ((pg.getStatus() & ImageObserver.ABORT) != 0) 382 { 383 return null; 384 } 385 RGB24Image result = new MemoryRGB24Image(width, height); 386 int offset = 0; 387 for (int y = 0; y < height; y++) 388 { 389 for (int x = 0; x < width; x++) 390 { 391 int pixel = pixels[offset++] & 0xffffff; 392 // TODO: store alpha value; requires some sort of 393 // transparency channel data type yet to be implemented 394 result.putSample(RGBIndex.INDEX_RED, x, y, pixel >> 16); 395 result.putSample(RGBIndex.INDEX_GREEN, x, y, (pixel >> 8) & 0xff); 396 result.putSample(RGBIndex.INDEX_BLUE, x, y, pixel & 0xff); 397 } 398 } 399 return result; 400 } 401 }