001: /*
002: * @(#)MWImage.java 1.56 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package java.awt;
029:
030: import java.util.Hashtable;
031: import java.util.Vector;
032: import java.util.Enumeration;
033: import java.util.NoSuchElementException;
034: import java.awt.image.ImageProducer;
035: import java.awt.image.ImageObserver;
036: import java.awt.image.ImageConsumer;
037: import java.awt.image.ColorModel;
038: import java.awt.image.IndexColorModel;
039: import java.awt.image.DirectColorModel;
040: import java.awt.image.RasterFormatException;
041: import java.awt.image.BufferedImage;
042: import java.awt.image.ReplicateScaleFilter;
043: import java.awt.image.ImageFilter;
044: import java.awt.image.FilteredImageSource;
045:
046: /**
047: Microwindows image implementation.
048: @version 1.51 08/19/02
049: */
050:
051: class MWImage extends java.awt.Image implements ImageConsumer,
052: sun.awt.image.BufferedImagePeer {
053: static final int REDRAW_COUNT = 20;
054: /** MicroWindows PSD for this image */
055:
056: int psd;
057: MWGraphicsConfiguration gc;
058: int width, height;
059: int status;
060: private Hashtable properties;
061: private Vector observers = new Vector();
062: /** The producer actually used and returned by getProducer. This may be a scaled
063: image producer if the image was prepared with a specified width and height
064: or it may be the original image producer if -1 was used for the width and height
065: to prepareImage. */
066:
067: ImageProducer producer;
068: boolean started;
069: private int scanlineCount;
070:
071: static native void pDrawImage(int psd, int psd_image, int x, int y,
072: Color bg);
073:
074: static private native void initIDs();
075:
076: static {
077: Toolkit.getDefaultToolkit();
078: initIDs();
079: }
080:
081: /** Creates an offscreen image of the specified width and height. This constructor exists
082: for the MWOffscreenImage class which is a sub class and should not be called directly. */
083:
084: MWImage(int width, int height, MWGraphicsConfiguration gc) {
085: this .width = width;
086: this .height = height;
087: status = ImageObserver.ALLBITS | ImageObserver.WIDTH
088: | ImageObserver.HEIGHT;
089: if (width > 0 && height > 0) {
090: this .gc = gc;
091: psd = gc.createCompatibleImagePSD(width, height);
092: }
093: }
094:
095: /** Creates an image from the supplied image producer. */
096:
097: MWImage(ImageProducer imageProd) {
098: width = -1;
099: height = -1;
100: producer = imageProd;
101: started = false;
102: gc = (MWGraphicsConfiguration) GraphicsEnvironment
103: .getLocalGraphicsEnvironment().getDefaultScreenDevice()
104: .getDefaultConfiguration();
105: }
106:
107: /** Creates a new MWImage from an existing one.
108: This constructor only exists for MWSubImage class and should not be used for any other purpose. */
109:
110: MWImage(MWImage image) {
111: psd = MWGraphics.pClonePSD(image.psd);
112: gc = image.gc;
113: status = ImageObserver.ALLBITS | ImageObserver.WIDTH
114: | ImageObserver.HEIGHT;
115: width = image.width;
116: height = image.height;
117: }
118:
119: protected void finalize() {
120: MWGraphics.pDisposePSD(psd);
121: }
122:
123: public Graphics getGraphics() {
124: throw new UnsupportedOperationException(
125: "Graphics can only be created for images created with Component.createImage(width, height)");
126: }
127:
128: public int getWidth() {
129: return width;
130: }
131:
132: public int getWidth(ImageObserver observer) {
133: if (width == -1) {
134: addObserver(observer);
135: startProduction();
136: }
137: return width;
138: }
139:
140: public int getHeight() {
141: return height;
142: }
143:
144: public int getHeight(ImageObserver observer) {
145: if (height == -1) {
146: addObserver(observer);
147: startProduction();
148: }
149: return height;
150: }
151:
152: public Object getProperty(String name) {
153: return getProperty(name, null);
154: }
155:
156: public Object getProperty(String name, ImageObserver observer) {
157: /* 467980
158: * getProperty checks if he properties hashtable exists.
159: * If so, the prop is assigned the value from properties
160: * that relates to the name specified. If no match is found,
161: * then the UndefinedProperty is returned.
162: *
163: * addObserver is called if prop is null and the observer is null.
164: *
165: */
166:
167: Object prop = null;
168: if (properties != null) {
169: prop = properties.get(name);
170: if (prop == null) {
171: prop = UndefinedProperty;
172: }
173: }
174: if ((prop == null) && (observer != null)) {
175: addObserver(observer);
176: }
177: return prop;
178: }
179:
180: public String[] getPropertyNames() {
181: if (properties == null)
182: return null;
183: Object[] names = properties.keySet().toArray();
184: String[] newNames = new String[names.length];
185: System.arraycopy(names, 0, newNames, 0, newNames.length);
186: return newNames;
187: }
188:
189: int getStatus(ImageObserver observer) {
190: if (observer != null) {
191: if (observer.imageUpdate(this , status, 0, 0, width, height))
192: addObserver(observer);
193: }
194: return status;
195: }
196:
197: public BufferedImage getSubimage(int x, int y, int w, int h) {
198: if (x < 0)
199: throw new RasterFormatException("x is outside image");
200: if (y < 0)
201: throw new RasterFormatException("y is outside image");
202: if (x + w > width)
203: throw new RasterFormatException(
204: "(x + width) is outside image");
205: if (y + h > height)
206: throw new RasterFormatException(
207: "(y + height) is outside image");
208: return gc.createBufferedImageObject(new MWSubimage(this , x, y,
209: w, h));
210: }
211:
212: synchronized boolean prepareImage(int width, int height,
213: ImageObserver observer) {
214: if (width == 0 || height == 0) {
215: if ((observer != null)
216: && observer.imageUpdate(this ,
217: ImageObserver.ALLBITS, 0, 0, 0, 0))
218: addObserver(observer);
219: return true;
220: }
221: if (hasError()) {
222: if ((observer != null)
223: && observer.imageUpdate(this , ImageObserver.ERROR
224: | ImageObserver.ABORT, -1, -1, -1, -1))
225: addObserver(observer);
226: return false;
227: }
228: if (started) {
229: if ((observer != null)
230: && observer.imageUpdate(this , status, 0, 0, width,
231: height))
232: addObserver(observer);
233: return ((status & ImageObserver.ALLBITS) != 0);
234: } else {
235: addObserver(observer);
236: startProduction();
237: }
238: // Some producers deliver image data synchronously
239: return ((status & ImageObserver.ALLBITS) != 0);
240: }
241:
242: synchronized void addObserver(ImageObserver observer) {
243: if (isComplete()) {
244: if (observer != null) {
245: observer.imageUpdate(this , status, 0, 0, width, height);
246: }
247: return;
248: }
249: if (observer != null && !isObserver(observer)) {
250: observers.addElement(observer);
251: }
252: }
253:
254: private boolean isObserver(ImageObserver observer) {
255: return (observer != null && observers.contains(observer));
256: }
257:
258: private synchronized void removeObserver(ImageObserver observer) {
259: if (observer != null) {
260: observers.removeElement(observer);
261: }
262: }
263:
264: private synchronized void notifyObservers(final Image img,
265: final int info,
266: final int x,
267: final int y,
268: final int w,
269: final int h) {
270: Enumeration enum = observers.elements();
271: Vector uninterested = null;
272: while (enum.hasMoreElements()) {
273: ImageObserver observer;
274: try {
275: observer = (ImageObserver) enum.nextElement();
276: } catch (NoSuchElementException e) {
277: break;
278: }
279: if (!observer.imageUpdate(img, info, x, y, w, h)) {
280: if (uninterested == null) {
281: uninterested = new Vector();
282: }
283: uninterested.addElement(observer);
284: }
285: }
286: if (uninterested != null) {
287: enum = uninterested.elements();
288: while (enum.hasMoreElements()) {
289: ImageObserver observer = (ImageObserver) enum.nextElement();
290: removeObserver(observer);
291: }
292: }
293: }
294:
295: synchronized void startProduction() {
296: if (producer != null && !started) {
297: if (!producer.isConsumer(this )) {
298: producer.addConsumer(this );
299: }
300: started = true;
301: producer.startProduction(this );
302: }
303: }
304:
305: public synchronized void flush() {
306: status = 0;
307: started = false;
308: MWGraphics.pDisposePSD(psd);
309: psd = 0;
310: MWToolkit.clearCache(this );
311: producer.removeConsumer(this );
312: width = -1;
313: height = -1;
314: if (producer instanceof sun.awt.image.InputStreamImageSource) {
315: ((sun.awt.image.InputStreamImageSource) producer).flush();
316: }
317: }
318:
319: public ImageProducer getSource() {
320: return producer;
321: }
322:
323: void drawImage(int psd, int x, int y, Color bg) {
324: pDrawImage(psd, this .psd, x, y, bg);
325: }
326:
327: private static native void pDrawImageScaled(int psd, int dx1,
328: int dy1, int dx2, int dy2, int imagePSD, int sx1, int sy1,
329: int sx2, int sy2, Color bg);
330:
331: void drawImage(int psd, int dx1, int dy1, int dx2, int dy2,
332: int sx1, int sy1, int sx2, int sy2, Color bg) {
333: pDrawImageScaled(psd, dx1, dy1, dx2, dy2, this .psd, sx1, sy1,
334: sx2, sy2, bg);
335: }
336:
337: boolean isComplete() {
338: return ((status & (ImageObserver.ALLBITS | ImageObserver.ERROR | ImageObserver.ABORT)) != 0);
339: }
340:
341: boolean hasError() {
342: return ((status & ImageObserver.ERROR) != 0);
343: }
344:
345: /***** --- Consumer Stuff --- *****/
346:
347: public void imageComplete(int stat) {
348: switch (stat) {
349: case STATICIMAGEDONE:
350: status = ImageObserver.ALLBITS;
351: break;
352:
353: case SINGLEFRAMEDONE:
354: status = ImageObserver.FRAMEBITS;
355: break;
356:
357: case IMAGEERROR:
358: status = ImageObserver.ERROR;
359: break;
360:
361: case IMAGEABORTED:
362: status = ImageObserver.ABORT;
363: break;
364: }
365: if (status != 0)
366: notifyObservers(this , status, 0, 0, width, height);
367: if (isComplete())
368: producer.removeConsumer(this );
369: }
370:
371: public void setColorModel(ColorModel cm) {
372: }
373:
374: public synchronized void setDimensions(int width, int height) {
375: if ((width > 0) && (height > 0)) {
376: this .width = width;
377: this .height = height;
378: MWGraphics.pDisposePSD(psd);
379: psd = gc.createCompatibleImagePSD(width, height);
380: status = ImageObserver.WIDTH | ImageObserver.HEIGHT;
381: notifyObservers(this , status, 0, 0, width, height);
382: }
383: }
384:
385: public void setProperties(Hashtable props) {
386: properties = props;
387: }
388:
389: public void setHints(int hints) {/*
390: System.out.println("ImageHints:");
391:
392: if((hints&RANDOMPIXELORDER) != 0)
393: System.out.println("Hints: random order");
394:
395: if((hints&TOPDOWNLEFTRIGHT) != 0)
396: System.out.println("Hints: top down");
397:
398: if((hints&COMPLETESCANLINES) != 0)
399: System.out.println("Hints: complete scan lines");
400:
401: if((hints&SINGLEPASS) != 0)
402: System.out.println("Hints: single pass");
403:
404: if((hints&SINGLEFRAME) != 0)
405: System.out.println("Hints: single frame");
406: */
407: }
408:
409: /** Unaccelerated native function for setting pixels in the image from any kind of ColorModel. */
410:
411: private static native void pSetColorModelBytePixels(int psd, int x,
412: int y, int w, int h, ColorModel cm, byte[] pixels,
413: int offset, int scansize);
414:
415: /** Unaccelerated native function for setting pixels in the image from any kind of ColorModel. */
416:
417: private static native void pSetColorModelIntPixels(int psd, int x,
418: int y, int w, int h, ColorModel cm, int[] pixels,
419: int offset, int scansize);
420:
421: /** Accelerated native function for setting pixels in the image when the ColorModel is an IndexColorModel. */
422:
423: private static native void pSetIndexColorModelBytePixels(int psd,
424: int x, int y, int w, int h, ColorModel cm, byte[] pixels,
425: int offset, int scansize);
426:
427: /** Accelerated native function for setting pixels in the image when the ColorModel is an IndexColorModel. */
428:
429: private static native void pSetIndexColorModelIntPixels(int psd,
430: int x, int y, int w, int h, ColorModel cm, int[] pixels,
431: int offset, int scansize);
432:
433: /** Accelerated native function for setting pixels in the image when the ColorModel is a DirectColorModel. */
434:
435: private static native void pSetDirectColorModelPixels(int psd,
436: int x, int y, int w, int h, ColorModel cm, int[] pixels,
437: int offset, int scansize);
438:
439: /** Gets the ARGB color value at the supplied location. */
440:
441: private static native int pGetRGB(int psd, int x, int y);
442:
443: /* Gets an area of ARGB values and stores them in the array. */
444:
445: private native void pGetRGBArray(int psd, int x, int y, int w,
446: int h, int[] pixels, int off, int scansize);
447:
448: /* Sets the pixel at the supplied location to an ARGB value. */
449:
450: private static native void pSetRGB(int psd, int x, int y, int rgb);
451:
452: public void setPixels(int x, int y, int w, int h, ColorModel cm,
453: byte[] pixels, int off, int scansize) {
454: if ((h - 1) * scansize + (w - 1) + off >= pixels.length)
455: throw new IllegalArgumentException(
456: "The pixel array is not big enough");
457: // Use accelerated set pixels routine if possible
458:
459: if (cm instanceof IndexColorModel)
460: pSetIndexColorModelBytePixels(psd, x, y, w, h, cm, pixels,
461: off, scansize);
462: else
463: pSetColorModelBytePixels(psd, x, y, w, h, cm, pixels, off,
464: scansize);
465: scanlineCount++;
466: status = ImageObserver.SOMEBITS;
467: if (scanlineCount % REDRAW_COUNT == 0) {
468: notifyObservers(this , ImageObserver.SOMEBITS, x, y, w, h);
469: }
470: // System.out.println("SetPixelsByte " + new Rectangle(x, y, w, h));
471:
472: }
473:
474: public void setPixels(int x, int y, int w, int h, ColorModel cm,
475: int[] pixels, int off, int scansize) {
476: if ((h - 1) * scansize + (w - 1) + off >= pixels.length)
477: throw new IllegalArgumentException(
478: "The pixel array is not big enough");
479: // Use accelerated set pixels routine if possible
480:
481: if (cm instanceof DirectColorModel)
482: pSetDirectColorModelPixels(psd, x, y, w, h, cm, pixels,
483: off, scansize);
484: else if (cm instanceof IndexColorModel)
485: pSetIndexColorModelIntPixels(psd, x, y, w, h, cm, pixels,
486: off, scansize);
487: else
488: pSetColorModelIntPixels(psd, x, y, w, h, cm, pixels, off,
489: scansize);
490: scanlineCount++;
491: status = ImageObserver.SOMEBITS;
492: if (scanlineCount % REDRAW_COUNT == 0) {
493: notifyObservers(this , ImageObserver.SOMEBITS, x, y, w, h);
494: }
495: // System.out.println("SetPixelsInt " + new Rectangle(x, y, w, h));
496: }
497:
498: public int getType() {
499: return gc.getCompatibleImageType();
500: }
501:
502: public ColorModel getColorModel() {
503: return gc.getColorModel();
504: }
505:
506: public synchronized void setRGB(int x, int y, int rgb) {
507: if (x < 0 || y < 0 || x >= width || y >= height)
508: throw new java.lang.ArrayIndexOutOfBoundsException(x + y
509: * width);
510: pSetRGB(psd, x, y, rgb);
511: };
512:
513: public void setRGB(int startX, int startY, int w, int h,
514: int[] rgbArray, int offset, int scansize) {
515: pSetDirectColorModelPixels(psd, startX, startY, w, h,
516: ColorModel.getRGBdefault(), rgbArray, offset, scansize);
517: }
518:
519: public int getRGB(int x, int y) {
520: if (x < 0 || y < 0 || x >= width || y >= height)
521: throw new java.lang.ArrayIndexOutOfBoundsException(x + y
522: * width);
523: // pGetPixel returns us an RGB color.
524:
525: return pGetRGB(psd, x, y);
526: }
527:
528: public int[] getRGB(int startX, int startY, int w, int h,
529: int[] rgbArray, int offset, int scansize) {
530: int yoff = offset;
531: int off;
532: if ((startX < 0) || (startY < 0) || ((startX + w) > width)
533: || ((startY + h) > height))
534: throw new java.lang.ArrayIndexOutOfBoundsException(startX
535: + startY * width);
536: // pGetPixelArray returns a RGB pixel
537:
538: if (rgbArray == null)
539: rgbArray = new int[offset + h * scansize];
540: else if (rgbArray.length < offset + h * scansize)
541: throw new IllegalArgumentException(
542: "rgbArray is not large enough to store all the values");
543: pGetRGBArray(psd, startX, startY, w, h, rgbArray, offset,
544: scansize);
545: return rgbArray;
546: }
547:
548: public String toString() {
549: return "[psd=" + psd + ",width=" + width + ",height=" + height
550: + ",status=" + status + "]";
551: }
552: }
|