001: /*
002: * @(#)QtImage.java 1.7 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: package java.awt;
028:
029: import java.util.Hashtable;
030: import java.util.Vector;
031: import java.util.Enumeration;
032: import java.util.NoSuchElementException;
033:
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: Qt image implementation.
048: @version 1.50 05/28/02
049: */
050:
051: class QtImage extends java.awt.Image implements ImageConsumer,
052: sun.awt.image.BufferedImagePeer {
053:
054: static final int REDRAW_COUNT = 20;
055:
056: /** Qt PSD for this image */
057:
058: int psd;
059:
060: QtGraphicsConfiguration gc;
061:
062: int width, height;
063:
064: int status;
065: boolean empty;
066:
067: private Hashtable properties;
068: private Vector observers = new Vector();
069:
070: /** The producer actually used and returned by getProducer. This may be a scaled
071: image producer if the image was prepared with a specified width and height
072: or it may be the original image producer if -1 was used for the width and height
073: to prepareImage. */
074:
075: ImageProducer producer;
076: boolean started;
077:
078: private int scanlineCount;
079:
080: static native void pDrawImage(int psd, int psd_image, int x, int y,
081: Color bg);
082:
083: static private native void initIDs();
084:
085: static {
086:
087: Toolkit.getDefaultToolkit();
088:
089: initIDs();
090: }
091:
092: /** Creates an offscreen image of the specified width and height. This constructor exists
093: for the QtOffscreenImage class which is a sub class and should not be called directly. */
094:
095: QtImage(int width, int height, QtGraphicsConfiguration gc) {
096:
097: this .width = width;
098: this .height = height;
099: status = ImageObserver.ALLBITS | ImageObserver.WIDTH
100: | ImageObserver.HEIGHT;
101:
102: if (width > 0 && height > 0) {
103: this .gc = gc;
104: psd = gc.createCompatibleImagePSD(width, height);
105: } else
106: psd = -1;
107: }
108:
109: /** Creates an image from the supplied image producer. */
110:
111: QtImage(ImageProducer imageProd) {
112: this (imageProd, false);
113: }
114:
115: /* 5084018.
116: Take the parameter isEmpty, which indicates whether we've been
117: passed an obvioulsy bad image (like a non-existing file name).
118: If this flag is set, at prepareImage() where the actual image
119: loading starts, we take a shortcut and pretend that the image
120: loaded and errored immediately instead of actually starting
121: ImageProducer's image production.
122:
123: Even if the image production starts with a bad image, it will
124: error properly as the decoder won't be good. But we want
125: this shortcut for the performance reason, and also because
126: there can be a race condition in shutdown and production
127: if the app keeps on loading and flushing the errornous image
128: over and over again with pbp's simplified image pipeline model.
129: **/
130: QtImage(ImageProducer imageProd, boolean isEmpty) {
131:
132: width = -1;
133: height = -1;
134: producer = imageProd;
135: started = false;
136:
137: gc = (QtGraphicsConfiguration) GraphicsEnvironment
138: .getLocalGraphicsEnvironment().getDefaultScreenDevice()
139: .getDefaultConfiguration();
140: psd = -1;
141:
142: empty = isEmpty;
143: }
144:
145: /** Creates a new QtImage from an existing one.
146: This constructor only exists for QtSubImage class and should not be used for any other purpose. */
147:
148: QtImage(QtImage image) {
149: gc = image.gc;
150: psd = gc.pClonePSD(image.psd);
151: status = ImageObserver.ALLBITS | ImageObserver.WIDTH
152: | ImageObserver.HEIGHT;
153: width = image.width;
154: height = image.height;
155: }
156:
157: protected void finalize() throws Throwable {
158: dispose();
159: super .finalize();
160: }
161:
162: protected void dispose() {
163: if (psd > 0) {
164: psd = gc.pDisposePSD(psd);
165: }
166: }
167:
168: public Graphics getGraphics() {
169: throw new UnsupportedOperationException(
170: "Graphics can only be created for images created with Component.createImage(width, height)");
171: }
172:
173: public int getWidth() {
174: return width;
175: }
176:
177: public int getWidth(ImageObserver observer) {
178: if (width == -1) {
179: addObserver(observer);
180: startProduction();
181: }
182:
183: return width;
184: }
185:
186: public int getHeight() {
187: return height;
188: }
189:
190: public int getHeight(ImageObserver observer) {
191: if (height == -1) {
192: addObserver(observer);
193: startProduction();
194: }
195:
196: return height;
197: }
198:
199: public Object getProperty(String name) {
200: return getProperty(name, null);
201: }
202:
203: public Object getProperty(String name, ImageObserver observer) {
204: /* 467980
205: * getProperty checks if he properties hashtable exists.
206: * If so, the prop is assigned the value from properties
207: * that relates to the name specified. If no match is found,
208: * then the UndefinedProperty is returned.
209: *
210: * addObserver is called if prop is null and the observer is null.
211: *
212: */
213:
214: Object prop = null;
215:
216: if (properties != null) {
217: prop = properties.get(name);
218: if (prop == null) {
219: prop = UndefinedProperty;
220: }
221: }
222:
223: if ((prop == null) && (observer != null)) {
224: addObserver(observer);
225: }
226:
227: return prop;
228: }
229:
230: public String[] getPropertyNames() {
231: if (properties == null)
232: return null;
233:
234: Object[] names = properties.keySet().toArray();
235: String[] newNames = new String[names.length];
236:
237: System.arraycopy(names, 0, newNames, 0, newNames.length);
238:
239: return newNames;
240: }
241:
242: int getStatus(ImageObserver observer) {
243:
244: if (observer != null) {
245: if (observer.imageUpdate(this , status, 0, 0, width, height))
246: addObserver(observer);
247: }
248: return status;
249: }
250:
251: public BufferedImage getSubimage(int x, int y, int w, int h) {
252:
253: if (x < 0)
254: throw new RasterFormatException("x is outside image");
255: if (y < 0)
256: throw new RasterFormatException("y is outside image");
257: if (x + w > width)
258: throw new RasterFormatException(
259: "(x + width) is outside image");
260: if (y + h > height)
261: throw new RasterFormatException(
262: "(y + height) is outside image");
263:
264: QtSubimage qs = new QtSubimage(this , x, y, w, h);
265:
266: return gc.createBufferedImageObject(qs, qs.psd);
267:
268: }
269:
270: synchronized boolean prepareImage(int width, int height,
271: ImageObserver observer) {
272:
273: if (width == 0 || height == 0) {
274: if ((observer != null)
275: && observer.imageUpdate(this ,
276: ImageObserver.ALLBITS, 0, 0, 0, 0))
277: addObserver(observer);
278: return true;
279: }
280:
281: /* 5084018. We know the image is bad - error immediately */
282: if (empty) {
283: started = true;
284: status |= ImageObserver.ERROR;
285: }
286:
287: if (hasError()) {
288: if ((observer != null)
289: && observer.imageUpdate(this , ImageObserver.ERROR
290: | ImageObserver.ABORT, -1, -1, -1, -1))
291: addObserver(observer);
292: return false;
293: }
294:
295: if (started) {
296:
297: if ((observer != null)
298: && observer.imageUpdate(this , status, 0, 0, width,
299: height))
300: addObserver(observer);
301:
302: return ((status & ImageObserver.ALLBITS) != 0);
303: } else {
304: addObserver(observer);
305: startProduction();
306: }
307:
308: // Some producers deliver image data synchronously
309: return ((status & ImageObserver.ALLBITS) != 0);
310:
311: }
312:
313: synchronized void addObserver(ImageObserver observer) {
314:
315: if (isComplete()) {
316: if (observer != null) {
317: observer.imageUpdate(this , status, 0, 0, width, height);
318: }
319: return;
320: }
321:
322: if (observer != null && !isObserver(observer)) {
323: observers.addElement(observer);
324: }
325: }
326:
327: private boolean isObserver(ImageObserver observer) {
328: return (observer != null && observers.contains(observer));
329: }
330:
331: private synchronized void removeObserver(ImageObserver observer) {
332: if (observer != null) {
333: observers.removeElement(observer);
334: }
335: }
336:
337: private synchronized void notifyObservers(final Image img,
338: final int info,
339: final int x,
340: final int y,
341: final int w,
342: final int h)
343: {
344: Enumeration enum = observers.elements();
345: Vector uninterested = null;
346: while (enum.hasMoreElements()) {
347: ImageObserver observer;
348: try {
349: observer = (ImageObserver) enum.nextElement();
350: } catch (NoSuchElementException e) {
351: break;
352: }
353:
354: if (!observer.imageUpdate(img, info, x, y, w, h)) {
355: if (uninterested == null) {
356: uninterested = new Vector();
357: }
358: uninterested.addElement(observer);
359: }
360: }
361: if (uninterested != null) {
362: enum = uninterested.elements();
363: while (enum.hasMoreElements()) {
364: ImageObserver observer = (ImageObserver) enum.nextElement();
365: removeObserver(observer);
366: }
367: }
368: }
369:
370: synchronized void startProduction() {
371:
372: if (producer != null && !started) {
373:
374: if (!producer.isConsumer(this )) {
375: producer.addConsumer(this );
376: }
377: started = true;
378: producer.startProduction(this );
379: }
380: }
381:
382: public synchronized void flush() {
383:
384: dispose();
385:
386: started = true;
387:
388: // Begin of: PBP/PP [6262553]
389: // Take security fixes from J2SE SunToolkit.java into PBP/PP's SunToolkit.java.
390: // Image cache is now maintained at the SunToolkit.java via a sun.misc.SoftCache.
391:
392: // QtToolkit.clearCache(this);
393:
394: // End of: PBP/PP [6262553]
395:
396: width = -1;
397: height = -1;
398:
399: if (!empty) {
400: status = 0;
401: started = false;
402: }
403:
404: if (producer != null) {
405: producer.removeConsumer(this );
406:
407: if (producer instanceof sun.awt.image.InputStreamImageSource) {
408: ((sun.awt.image.InputStreamImageSource) producer)
409: .flush();
410: }
411: }
412: }
413:
414: public ImageProducer getSource() {
415: return producer;
416: }
417:
418: void drawImage(int psd, int x, int y, Color bg) {
419: pDrawImage(psd, this .psd, x, y, bg);
420: }
421:
422: private static native void pDrawImageScaled(int psd, int dx1,
423: int dy1, int dx2, int dy2, int imagePSD, int sx1, int sy1,
424: int sx2, int sy2, Color bg);
425:
426: void drawImage(int psd, int dx1, int dy1, int dx2, int dy2,
427: int sx1, int sy1, int sx2, int sy2, Color bg) {
428: pDrawImageScaled(psd, dx1, dy1, dx2, dy2, this .psd, sx1, sy1,
429: sx2, sy2, bg);
430: }
431:
432: boolean isComplete() {
433: return ((status & (ImageObserver.ALLBITS | ImageObserver.ERROR | ImageObserver.ABORT)) != 0);
434: }
435:
436: boolean hasError() {
437: return ((status & ImageObserver.ERROR) != 0);
438: }
439:
440: /***** --- Consumer Stuff --- *****/
441: private native static void imageCompleteLoadBuffer(int imagePSD,
442: boolean dispose);
443:
444: public void imageComplete(int stat) {
445:
446: switch (stat) {
447: case STATICIMAGEDONE:
448: status = ImageObserver.ALLBITS;
449: break;
450:
451: case SINGLEFRAMEDONE:
452: status = ImageObserver.FRAMEBITS;
453: break;
454:
455: case IMAGEERROR:
456: status = ImageObserver.ERROR;
457: break;
458:
459: case IMAGEABORTED:
460: status = ImageObserver.ABORT;
461: break;
462: }
463:
464: if (status != 0) {
465: imageCompleteLoadBuffer(psd,
466: (status == ImageObserver.ALLBITS));
467: notifyObservers(this , status, 0, 0, width, height);
468: }
469:
470: if (isComplete())
471: producer.removeConsumer(this );
472: }
473:
474: public void setColorModel(ColorModel cm) {
475: }
476:
477: public synchronized void setDimensions(int width, int height) {
478:
479: if ((width > 0) && (height > 0)) {
480: this .width = width;
481: this .height = height;
482:
483: dispose();
484:
485: psd = gc.createCompatibleImagePSD(width, height);
486:
487: status = ImageObserver.WIDTH | ImageObserver.HEIGHT;
488:
489: notifyObservers(this , status, 0, 0, width, height);
490: }
491: }
492:
493: public void setProperties(Hashtable props) {
494:
495: properties = props;
496: }
497:
498: public void setHints(int hints) {/*
499: System.out.println("ImageHints:");
500:
501: if((hints&RANDOMPIXELORDER) != 0)
502: System.out.println("Hints: random order");
503:
504: if((hints&TOPDOWNLEFTRIGHT) != 0)
505: System.out.println("Hints: top down");
506:
507: if((hints&COMPLETESCANLINES) != 0)
508: System.out.println("Hints: complete scan lines");
509:
510: if((hints&SINGLEPASS) != 0)
511: System.out.println("Hints: single pass");
512:
513: if((hints&SINGLEFRAME) != 0)
514: System.out.println("Hints: single frame");
515: */
516: }
517:
518: /** Unaccelerated native function for setting pixels in the image from any kind of ColorModel. */
519:
520: private static native void pSetColorModelBytePixels(int psd, int x,
521: int y, int w, int h, ColorModel cm, byte[] pixels,
522: int offset, int scansize);
523:
524: /** Unaccelerated native function for setting pixels in the image from any kind of ColorModel. */
525:
526: private static native void pSetColorModelIntPixels(int psd, int x,
527: int y, int w, int h, ColorModel cm, int[] pixels,
528: int offset, int scansize);
529:
530: /** Accelerated native function for setting pixels in the image when the ColorModel is an IndexColorModel. */
531:
532: private static native void pSetIndexColorModelBytePixels(int psd,
533: int x, int y, int w, int h, ColorModel cm, byte[] pixels,
534: int offset, int scansize);
535:
536: /** Accelerated native function for setting pixels in the image when the ColorModel is an IndexColorModel. */
537:
538: private static native void pSetIndexColorModelIntPixels(int psd,
539: int x, int y, int w, int h, ColorModel cm, int[] pixels,
540: int offset, int scansize);
541:
542: /** Accelerated native function for setting pixels in the image when the ColorModel is a DirectColorModel. */
543:
544: private static native void pSetDirectColorModelPixels(int psd,
545: int x, int y, int w, int h, ColorModel cm, int[] pixels,
546: int offset, int scansize, int totalMask);
547:
548: /** Gets the ARGB color value at the supplied location. */
549:
550: private static native int pGetRGB(int psd, int x, int y);
551:
552: /* Gets an area of ARGB values and stores them in the array. */
553:
554: private static native void pGetRGBArray(int psd, int x, int y,
555: int w, int h, int[] pixels, int off, int scansize);
556:
557: /* Sets the pixel at the supplied location to an ARGB value. */
558:
559: private static native void pSetRGB(int psd, int x, int y, int rgb);
560:
561: private static native void pSetRGBArray(int psd, int startX,
562: int startY, int w, int h, int[] rgbArray, int offset,
563: int scansize);
564:
565: public void setPixels(int x, int y, int w, int h, ColorModel cm,
566: byte[] pixels, int off, int scansize) {
567:
568: if (psd < 0)
569: return;
570:
571: /* 6199102 if ( pixels.length < h * scansize + off) */
572: if (pixels.length < (h - 1) * scansize + off + w)
573: throw new IllegalArgumentException(
574: "The pixel array is not big enough");
575:
576: // Use accelerated set pixels routine if possible
577:
578: if (cm instanceof IndexColorModel)
579: pSetIndexColorModelBytePixels(psd, x, y, w, h, cm, pixels,
580: off, scansize);
581:
582: else
583: pSetColorModelBytePixels(psd, x, y, w, h, cm, pixels, off,
584: scansize);
585:
586: scanlineCount++;
587:
588: status = ImageObserver.SOMEBITS;
589:
590: if (scanlineCount % REDRAW_COUNT == 0) {
591: notifyObservers(this , ImageObserver.SOMEBITS, x, y, w, h);
592: }
593:
594: // System.out.println("SetPixelsByte " + new Rectangle(x, y, w, h));
595:
596: }
597:
598: public void setPixels(int x, int y, int w, int h, ColorModel cm,
599: int[] pixels, int off, int scansize) {
600:
601: if (psd < 0)
602: return;
603:
604: /* 6199102 if ( pixels.length < h * scansize + off) */
605: if (pixels.length < (h - 1) * scansize + off + w)
606: throw new IllegalArgumentException(
607: "The pixel array is not big enough");
608:
609: // Use accelerated set pixels routine if possible
610: if (cm instanceof DirectColorModel) {
611: DirectColorModel dcm = (DirectColorModel) cm;
612: int totalMask = dcm.getAlphaMask() | dcm.getRedMask()
613: | dcm.getGreenMask() | dcm.getBlueMask();
614: pSetDirectColorModelPixels(psd, x, y, w, h, cm, pixels,
615: off, scansize, totalMask);
616: } else if (cm instanceof IndexColorModel)
617: pSetIndexColorModelIntPixels(psd, x, y, w, h, cm, pixels,
618: off, scansize);
619:
620: else
621: pSetColorModelIntPixels(psd, x, y, w, h, cm, pixels, off,
622: scansize);
623:
624: scanlineCount++;
625:
626: status = ImageObserver.SOMEBITS;
627:
628: if (scanlineCount % REDRAW_COUNT == 0) {
629: notifyObservers(this , ImageObserver.SOMEBITS, x, y, w, h);
630: }
631:
632: // System.out.println("SetPixelsInt " + new Rectangle(x, y, w, h));
633: }
634:
635: public int getType() {
636: return gc.getCompatibleImageType();
637: }
638:
639: public ColorModel getColorModel() {
640: return gc.getColorModel();
641: }
642:
643: public void setRGB(int x, int y, int rgb) {
644: if (x < 0 || y < 0 || x >= width || y >= height)
645: throw new java.lang.ArrayIndexOutOfBoundsException(x + y
646: * width);
647:
648: pSetRGB(psd, x, y, rgb);
649: };
650:
651: public void setRGB(int startX, int startY, int w, int h,
652: int[] rgbArray, int offset, int scansize) {
653:
654: if ((startX < 0) || (startY < 0) || (startX >= width)
655: || (startY >= height))
656: return;
657:
658: if (w > scansize)
659: return; // Overrun!!
660:
661: pSetRGBArray(psd, startX, startY, w, h, rgbArray, offset,
662: scansize);
663: }
664:
665: public int getRGB(int x, int y) {
666:
667: if (x < 0 || y < 0 || x >= width || y >= height)
668: throw new java.lang.ArrayIndexOutOfBoundsException(x + y
669: * width);
670:
671: // pGetPixel returns us an RGB color.
672: int r = pGetRGB(psd, x, y);
673: return r;
674: }
675:
676: public int[] getRGB(int startX, int startY, int w, int h,
677: int[] rgbArray, int offset, int scansize) {
678:
679: int yoff = offset;
680: int off;
681:
682: if ((startX < 0) || (startY < 0) || ((startX + w) > width)
683: || ((startY + h) > height))
684: throw new java.lang.ArrayIndexOutOfBoundsException(startX
685: + startY * width);
686:
687: // pGetPixelArray returns a RGB pixel
688:
689: if (rgbArray == null)
690: rgbArray = new int[offset + h * scansize];
691:
692: else if (rgbArray.length < offset + h * scansize)
693: throw new IllegalArgumentException(
694: "rgbArray is not large enough to store all the values");
695:
696: pGetRGBArray(psd, startX, startY, w, h, rgbArray, offset,
697: scansize);
698: return rgbArray;
699: }
700:
701: public String toString() {
702: return "[psd=" + psd + ",width=" + width + ",height=" + height
703: + ",status=" + status + "]";
704: }
705: }
|