94 * // Send the new data to the interested ImageConsumers 95 * source.newPixels(x, y, w, h); 96 * } 97 * } 98 * 99 * }</pre> 100 * 101 * @see ImageProducer 102 * 103 * @author Jim Graham 104 * @author Animation capabilities inspired by the 105 * MemoryAnimationSource class written by Garth Dickie 106 */ 107 public class MemoryImageSource implements ImageProducer { 108 int width; 109 int height; 110 ColorModel model; 111 Object pixels; 112 int pixeloffset; 113 int pixelscan; 114 Hashtable properties; 115 Vector theConsumers = new Vector(); 116 boolean animating; 117 boolean fullbuffers; 118 119 /** 120 * Constructs an ImageProducer object which uses an array of bytes 121 * to produce data for an Image object. 122 * @param w the width of the rectangle of pixels 123 * @param h the height of the rectangle of pixels 124 * @param cm the specified <code>ColorModel</code> 125 * @param pix an array of pixels 126 * @param off the offset into the array of where to store the 127 * first pixel 128 * @param scan the distance from one row of pixels to the next in 129 * the array 130 * @see java.awt.Component#createImage 131 */ 132 public MemoryImageSource(int w, int h, ColorModel cm, 133 byte[] pix, int off, int scan) { 134 initialize(w, h, cm, (Object) pix, off, scan, null); 135 } 180 * @param w the width of the rectangle of pixels 181 * @param h the height of the rectangle of pixels 182 * @param cm the specified <code>ColorModel</code> 183 * @param pix an array of pixels 184 * @param off the offset into the array of where to store the 185 * first pixel 186 * @param scan the distance from one row of pixels to the next in 187 * the array 188 * @param props a list of properties that the <code>ImageProducer</code> 189 * uses to process an image 190 * @see java.awt.Component#createImage 191 */ 192 public MemoryImageSource(int w, int h, ColorModel cm, 193 int[] pix, int off, int scan, 194 Hashtable<?,?> props) 195 { 196 initialize(w, h, cm, (Object) pix, off, scan, props); 197 } 198 199 private void initialize(int w, int h, ColorModel cm, 200 Object pix, int off, int scan, Hashtable props) { 201 width = w; 202 height = h; 203 model = cm; 204 pixels = pix; 205 pixeloffset = off; 206 pixelscan = scan; 207 if (props == null) { 208 props = new Hashtable(); 209 } 210 properties = props; 211 } 212 213 /** 214 * Constructs an ImageProducer object which uses an array of integers 215 * in the default RGB ColorModel to produce data for an Image object. 216 * @param w the width of the rectangle of pixels 217 * @param h the height of the rectangle of pixels 218 * @param pix an array of pixels 219 * @param off the offset into the array of where to store the 220 * first pixel 221 * @param scan the distance from one row of pixels to the next in 222 * the array 223 * @see java.awt.Component#createImage 224 * @see ColorModel#getRGBdefault 225 */ 226 public MemoryImageSource(int w, int h, int pix[], int off, int scan) { 227 initialize(w, h, ColorModel.getRGBdefault(), 228 (Object) pix, off, scan, null); 326 // Ignored. The data is either single frame and already in TDLR 327 // format or it is multi-frame and TDLR resends aren't critical. 328 } 329 330 /** 331 * Changes this memory image into a multi-frame animation or a 332 * single-frame static image depending on the animated parameter. 333 * <p>This method should be called immediately after the 334 * MemoryImageSource is constructed and before an image is 335 * created with it to ensure that all ImageConsumers will 336 * receive the correct multi-frame data. If an ImageConsumer 337 * is added to this ImageProducer before this flag is set then 338 * that ImageConsumer will see only a snapshot of the pixel 339 * data that was available when it connected. 340 * @param animated <code>true</code> if the image is a 341 * multi-frame animation 342 */ 343 public synchronized void setAnimated(boolean animated) { 344 this.animating = animated; 345 if (!animating) { 346 Enumeration enum_ = theConsumers.elements(); 347 while (enum_.hasMoreElements()) { 348 ImageConsumer ic = (ImageConsumer) enum_.nextElement(); 349 ic.imageComplete(ImageConsumer.STATICIMAGEDONE); 350 if (isConsumer(ic)) { 351 ic.imageComplete(ImageConsumer.IMAGEERROR); 352 } 353 } 354 theConsumers.removeAllElements(); 355 } 356 } 357 358 /** 359 * Specifies whether this animated memory image should always be 360 * updated by sending the complete buffer of pixels whenever 361 * there is a change. 362 * This flag is ignored if the animation flag is not turned on 363 * through the setAnimated() method. 364 * <p>This method should be called immediately after the 365 * MemoryImageSource is constructed and before an image is 366 * created with it to ensure that all ImageConsumers will 367 * receive the correct pixel delivery hints. 368 * @param fullbuffers <code>true</code> if the complete pixel 369 * buffer should always 370 * be sent 371 * @see #setAnimated 372 */ 373 public synchronized void setFullBufferUpdates(boolean fullbuffers) { 374 if (this.fullbuffers == fullbuffers) { 375 return; 376 } 377 this.fullbuffers = fullbuffers; 378 if (animating) { 379 Enumeration enum_ = theConsumers.elements(); 380 while (enum_.hasMoreElements()) { 381 ImageConsumer ic = (ImageConsumer) enum_.nextElement(); 382 ic.setHints(fullbuffers 383 ? (ImageConsumer.TOPDOWNLEFTRIGHT | 384 ImageConsumer.COMPLETESCANLINES) 385 : ImageConsumer.RANDOMPIXELORDER); 386 } 387 } 388 } 389 390 /** 391 * Sends a whole new buffer of pixels to any ImageConsumers that 392 * are currently interested in the data for this image and notify 393 * them that an animation frame is complete. 394 * This method only has effect if the animation flag has been 395 * turned on through the setAnimated() method. 396 * @see #newPixels(int, int, int, int, boolean) 397 * @see ImageConsumer 398 * @see #setAnimated 399 */ 400 public void newPixels() { 401 newPixels(0, 0, width, height, true); 457 h = height; 458 } else { 459 if (x < 0) { 460 w += x; 461 x = 0; 462 } 463 if (x + w > width) { 464 w = width - x; 465 } 466 if (y < 0) { 467 h += y; 468 y = 0; 469 } 470 if (y + h > height) { 471 h = height - y; 472 } 473 } 474 if ((w <= 0 || h <= 0) && !framenotify) { 475 return; 476 } 477 Enumeration enum_ = theConsumers.elements(); 478 while (enum_.hasMoreElements()) { 479 ImageConsumer ic = (ImageConsumer) enum_.nextElement(); 480 if (w > 0 && h > 0) { 481 sendPixels(ic, x, y, w, h); 482 } 483 if (framenotify && isConsumer(ic)) { 484 ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE); 485 } 486 } 487 } 488 } 489 490 /** 491 * Changes to a new byte array to hold the pixels for this image. 492 * If the animation flag has been turned on through the setAnimated() 493 * method, then the new pixels will be immediately delivered to any 494 * ImageConsumers that are currently interested in the data for 495 * this image. 496 * @param newpix the new pixel array 497 * @param newmodel the specified <code>ColorModel</code> 498 * @param offset the offset into the array 499 * @param scansize the distance from one row of pixels to the next in | 94 * // Send the new data to the interested ImageConsumers 95 * source.newPixels(x, y, w, h); 96 * } 97 * } 98 * 99 * }</pre> 100 * 101 * @see ImageProducer 102 * 103 * @author Jim Graham 104 * @author Animation capabilities inspired by the 105 * MemoryAnimationSource class written by Garth Dickie 106 */ 107 public class MemoryImageSource implements ImageProducer { 108 int width; 109 int height; 110 ColorModel model; 111 Object pixels; 112 int pixeloffset; 113 int pixelscan; 114 Hashtable<?, ?> properties; 115 Vector<ImageConsumer> theConsumers = new Vector<>(); 116 boolean animating; 117 boolean fullbuffers; 118 119 /** 120 * Constructs an ImageProducer object which uses an array of bytes 121 * to produce data for an Image object. 122 * @param w the width of the rectangle of pixels 123 * @param h the height of the rectangle of pixels 124 * @param cm the specified <code>ColorModel</code> 125 * @param pix an array of pixels 126 * @param off the offset into the array of where to store the 127 * first pixel 128 * @param scan the distance from one row of pixels to the next in 129 * the array 130 * @see java.awt.Component#createImage 131 */ 132 public MemoryImageSource(int w, int h, ColorModel cm, 133 byte[] pix, int off, int scan) { 134 initialize(w, h, cm, (Object) pix, off, scan, null); 135 } 180 * @param w the width of the rectangle of pixels 181 * @param h the height of the rectangle of pixels 182 * @param cm the specified <code>ColorModel</code> 183 * @param pix an array of pixels 184 * @param off the offset into the array of where to store the 185 * first pixel 186 * @param scan the distance from one row of pixels to the next in 187 * the array 188 * @param props a list of properties that the <code>ImageProducer</code> 189 * uses to process an image 190 * @see java.awt.Component#createImage 191 */ 192 public MemoryImageSource(int w, int h, ColorModel cm, 193 int[] pix, int off, int scan, 194 Hashtable<?,?> props) 195 { 196 initialize(w, h, cm, (Object) pix, off, scan, props); 197 } 198 199 private void initialize(int w, int h, ColorModel cm, 200 Object pix, int off, int scan, Hashtable<?, ?> props) { 201 width = w; 202 height = h; 203 model = cm; 204 pixels = pix; 205 pixeloffset = off; 206 pixelscan = scan; 207 if (props == null) { 208 props = new Hashtable<>(); 209 } 210 properties = props; 211 } 212 213 /** 214 * Constructs an ImageProducer object which uses an array of integers 215 * in the default RGB ColorModel to produce data for an Image object. 216 * @param w the width of the rectangle of pixels 217 * @param h the height of the rectangle of pixels 218 * @param pix an array of pixels 219 * @param off the offset into the array of where to store the 220 * first pixel 221 * @param scan the distance from one row of pixels to the next in 222 * the array 223 * @see java.awt.Component#createImage 224 * @see ColorModel#getRGBdefault 225 */ 226 public MemoryImageSource(int w, int h, int pix[], int off, int scan) { 227 initialize(w, h, ColorModel.getRGBdefault(), 228 (Object) pix, off, scan, null); 326 // Ignored. The data is either single frame and already in TDLR 327 // format or it is multi-frame and TDLR resends aren't critical. 328 } 329 330 /** 331 * Changes this memory image into a multi-frame animation or a 332 * single-frame static image depending on the animated parameter. 333 * <p>This method should be called immediately after the 334 * MemoryImageSource is constructed and before an image is 335 * created with it to ensure that all ImageConsumers will 336 * receive the correct multi-frame data. If an ImageConsumer 337 * is added to this ImageProducer before this flag is set then 338 * that ImageConsumer will see only a snapshot of the pixel 339 * data that was available when it connected. 340 * @param animated <code>true</code> if the image is a 341 * multi-frame animation 342 */ 343 public synchronized void setAnimated(boolean animated) { 344 this.animating = animated; 345 if (!animating) { 346 Enumeration<ImageConsumer> enum_ = theConsumers.elements(); 347 while (enum_.hasMoreElements()) { 348 ImageConsumer ic = enum_.nextElement(); 349 ic.imageComplete(ImageConsumer.STATICIMAGEDONE); 350 if (isConsumer(ic)) { 351 ic.imageComplete(ImageConsumer.IMAGEERROR); 352 } 353 } 354 theConsumers.removeAllElements(); 355 } 356 } 357 358 /** 359 * Specifies whether this animated memory image should always be 360 * updated by sending the complete buffer of pixels whenever 361 * there is a change. 362 * This flag is ignored if the animation flag is not turned on 363 * through the setAnimated() method. 364 * <p>This method should be called immediately after the 365 * MemoryImageSource is constructed and before an image is 366 * created with it to ensure that all ImageConsumers will 367 * receive the correct pixel delivery hints. 368 * @param fullbuffers <code>true</code> if the complete pixel 369 * buffer should always 370 * be sent 371 * @see #setAnimated 372 */ 373 public synchronized void setFullBufferUpdates(boolean fullbuffers) { 374 if (this.fullbuffers == fullbuffers) { 375 return; 376 } 377 this.fullbuffers = fullbuffers; 378 if (animating) { 379 Enumeration<ImageConsumer> enum_ = theConsumers.elements(); 380 while (enum_.hasMoreElements()) { 381 ImageConsumer ic = enum_.nextElement(); 382 ic.setHints(fullbuffers 383 ? (ImageConsumer.TOPDOWNLEFTRIGHT | 384 ImageConsumer.COMPLETESCANLINES) 385 : ImageConsumer.RANDOMPIXELORDER); 386 } 387 } 388 } 389 390 /** 391 * Sends a whole new buffer of pixels to any ImageConsumers that 392 * are currently interested in the data for this image and notify 393 * them that an animation frame is complete. 394 * This method only has effect if the animation flag has been 395 * turned on through the setAnimated() method. 396 * @see #newPixels(int, int, int, int, boolean) 397 * @see ImageConsumer 398 * @see #setAnimated 399 */ 400 public void newPixels() { 401 newPixels(0, 0, width, height, true); 457 h = height; 458 } else { 459 if (x < 0) { 460 w += x; 461 x = 0; 462 } 463 if (x + w > width) { 464 w = width - x; 465 } 466 if (y < 0) { 467 h += y; 468 y = 0; 469 } 470 if (y + h > height) { 471 h = height - y; 472 } 473 } 474 if ((w <= 0 || h <= 0) && !framenotify) { 475 return; 476 } 477 Enumeration<ImageConsumer> enum_ = theConsumers.elements(); 478 while (enum_.hasMoreElements()) { 479 ImageConsumer ic = enum_.nextElement(); 480 if (w > 0 && h > 0) { 481 sendPixels(ic, x, y, w, h); 482 } 483 if (framenotify && isConsumer(ic)) { 484 ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE); 485 } 486 } 487 } 488 } 489 490 /** 491 * Changes to a new byte array to hold the pixels for this image. 492 * If the animation flag has been turned on through the setAnimated() 493 * method, then the new pixels will be immediately delivered to any 494 * ImageConsumers that are currently interested in the data for 495 * this image. 496 * @param newpix the new pixel array 497 * @param newmodel the specified <code>ColorModel</code> 498 * @param offset the offset into the array 499 * @param scansize the distance from one row of pixels to the next in |