/* * @(#)MWImage.java 1.56 06/10/10 * * Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. * */ package java.awt; import java.util.Hashtable; import java.util.Vector; import java.util.Enumeration; import java.util.NoSuchElementException; import java.awt.image.ImageProducer; import java.awt.image.ImageObserver; import java.awt.image.ImageConsumer; import java.awt.image.ColorModel; import java.awt.image.IndexColorModel; import java.awt.image.DirectColorModel; import java.awt.image.RasterFormatException; import java.awt.image.BufferedImage; import java.awt.image.ReplicateScaleFilter; import java.awt.image.ImageFilter; import java.awt.image.FilteredImageSource; /** Microwindows image implementation. @version 1.51 08/19/02 */ class MWImage extends java.awt.Image implements ImageConsumer, sun.awt.image.BufferedImagePeer { static final int REDRAW_COUNT = 20; /** MicroWindows PSD for this image */ int psd; MWGraphicsConfiguration gc; int width, height; int status; private Hashtable properties; private Vector observers = new Vector(); /** The producer actually used and returned by getProducer. This may be a scaled image producer if the image was prepared with a specified width and height or it may be the original image producer if -1 was used for the width and height to prepareImage. */ ImageProducer producer; boolean started; private int scanlineCount; static native void pDrawImage(int psd, int psd_image, int x, int y, Color bg); static private native void initIDs(); static { Toolkit.getDefaultToolkit(); initIDs(); } /** Creates an offscreen image of the specified width and height. This constructor exists for the MWOffscreenImage class which is a sub class and should not be called directly. */ MWImage(int width, int height, MWGraphicsConfiguration gc) { this.width = width; this.height = height; status = ImageObserver.ALLBITS | ImageObserver.WIDTH | ImageObserver.HEIGHT; if (width > 0 && height > 0) { this.gc = gc; psd = gc.createCompatibleImagePSD(width, height); } } /** Creates an image from the supplied image producer. */ MWImage(ImageProducer imageProd) { width = -1; height = -1; producer = imageProd; started = false; gc = (MWGraphicsConfiguration) GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); } /** Creates a new MWImage from an existing one. This constructor only exists for MWSubImage class and should not be used for any other purpose. */ MWImage(MWImage image) { psd = MWGraphics.pClonePSD(image.psd); gc = image.gc; status = ImageObserver.ALLBITS | ImageObserver.WIDTH | ImageObserver.HEIGHT; width = image.width; height = image.height; } protected void finalize() { MWGraphics.pDisposePSD(psd); } public Graphics getGraphics() { throw new UnsupportedOperationException("Graphics can only be created for images created with Component.createImage(width, height)"); } public int getWidth() { return width; } public int getWidth(ImageObserver observer) { if (width == -1) { addObserver(observer); startProduction(); } return width; } public int getHeight() { return height; } public int getHeight(ImageObserver observer) { if (height == -1) { addObserver(observer); startProduction(); } return height; } public Object getProperty(String name) { return getProperty(name, null); } public Object getProperty(String name, ImageObserver observer) { /* 467980 * getProperty checks if he properties hashtable exists. * If so, the prop is assigned the value from properties * that relates to the name specified. If no match is found, * then the UndefinedProperty is returned. * * addObserver is called if prop is null and the observer is null. * */ Object prop = null; if (properties != null) { prop = properties.get(name); if (prop == null) { prop = UndefinedProperty; } } if ((prop == null) && (observer != null)) { addObserver(observer); } return prop; } public String[] getPropertyNames() { if (properties == null) return null; Object[] names = properties.keySet().toArray(); String[] newNames = new String[names.length]; System.arraycopy(names, 0, newNames, 0, newNames.length); return newNames; } int getStatus(ImageObserver observer) { if (observer != null) { if (observer.imageUpdate(this, status, 0, 0, width, height)) addObserver(observer); } return status; } public BufferedImage getSubimage(int x, int y, int w, int h) { if (x < 0) throw new RasterFormatException("x is outside image"); if (y < 0) throw new RasterFormatException("y is outside image"); if (x + w > width) throw new RasterFormatException("(x + width) is outside image"); if (y + h > height) throw new RasterFormatException("(y + height) is outside image"); return gc.createBufferedImageObject(new MWSubimage(this, x, y, w, h)); } synchronized boolean prepareImage(int width, int height, ImageObserver observer) { if (width == 0 || height == 0) { if ((observer != null) && observer.imageUpdate(this, ImageObserver.ALLBITS, 0, 0, 0, 0)) addObserver(observer); return true; } if (hasError()) { if ((observer != null) && observer.imageUpdate(this, ImageObserver.ERROR | ImageObserver.ABORT, -1, -1, -1, -1)) addObserver(observer); return false; } if (started) { if ((observer != null) && observer.imageUpdate(this, status, 0, 0, width, height)) addObserver(observer); return ((status & ImageObserver.ALLBITS) != 0); } else { addObserver(observer); startProduction(); } // Some producers deliver image data synchronously return ((status & ImageObserver.ALLBITS) != 0); } synchronized void addObserver(ImageObserver observer) { if (isComplete()) { if (observer != null) { observer.imageUpdate(this, status, 0, 0, width, height); } return; } if (observer != null && !isObserver(observer)) { observers.addElement(observer); } } private boolean isObserver(ImageObserver observer) { return (observer != null && observers.contains(observer)); } private synchronized void removeObserver(ImageObserver observer) { if (observer != null) { observers.removeElement(observer); } } private synchronized void notifyObservers(final Image img, final int info, final int x, final int y, final int w, final int h) { Enumeration enum = observers.elements(); Vector uninterested = null; while (enum.hasMoreElements()) { ImageObserver observer; try { observer = (ImageObserver) enum.nextElement(); } catch (NoSuchElementException e) { break; } if (!observer.imageUpdate(img, info, x, y, w, h)) { if (uninterested == null) { uninterested = new Vector(); } uninterested.addElement(observer); } } if (uninterested != null) { enum = uninterested.elements(); while (enum.hasMoreElements()) { ImageObserver observer = (ImageObserver) enum.nextElement(); removeObserver(observer); } } } synchronized void startProduction() { if (producer != null && !started) { if (!producer.isConsumer(this)) { producer.addConsumer(this); } started = true; producer.startProduction(this); } } public synchronized void flush() { status = 0; started = false; MWGraphics.pDisposePSD(psd); psd = 0; MWToolkit.clearCache(this); producer.removeConsumer(this); width = -1; height = -1; if (producer instanceof sun.awt.image.InputStreamImageSource) { ((sun.awt.image.InputStreamImageSource) producer).flush(); } } public ImageProducer getSource() { return producer; } void drawImage(int psd, int x, int y, Color bg) { pDrawImage(psd, this.psd, x, y, bg); } private static native void pDrawImageScaled(int psd, int dx1, int dy1, int dx2, int dy2, int imagePSD, int sx1, int sy1, int sx2, int sy2, Color bg); void drawImage(int psd, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bg) { pDrawImageScaled(psd, dx1, dy1, dx2, dy2, this.psd, sx1, sy1, sx2, sy2, bg); } boolean isComplete() { return ((status & (ImageObserver.ALLBITS | ImageObserver.ERROR | ImageObserver.ABORT)) != 0); } boolean hasError() { return ((status & ImageObserver.ERROR) != 0); } /***** --- Consumer Stuff --- *****/ public void imageComplete(int stat) { switch (stat) { case STATICIMAGEDONE: status = ImageObserver.ALLBITS; break; case SINGLEFRAMEDONE: status = ImageObserver.FRAMEBITS; break; case IMAGEERROR: status = ImageObserver.ERROR; break; case IMAGEABORTED: status = ImageObserver.ABORT; break; } if (status != 0) notifyObservers(this, status, 0, 0, width, height); if (isComplete()) producer.removeConsumer(this); } public void setColorModel(ColorModel cm) {} public synchronized void setDimensions(int width, int height) { if ((width > 0) && (height > 0)) { this.width = width; this.height = height; MWGraphics.pDisposePSD(psd); psd = gc.createCompatibleImagePSD(width, height); status = ImageObserver.WIDTH | ImageObserver.HEIGHT; notifyObservers(this, status, 0, 0, width, height); } } public void setProperties(Hashtable props) { properties = props; } public void setHints(int hints) {/* System.out.println("ImageHints:"); if((hints&RANDOMPIXELORDER) != 0) System.out.println("Hints: random order"); if((hints&TOPDOWNLEFTRIGHT) != 0) System.out.println("Hints: top down"); if((hints&COMPLETESCANLINES) != 0) System.out.println("Hints: complete scan lines"); if((hints&SINGLEPASS) != 0) System.out.println("Hints: single pass"); if((hints&SINGLEFRAME) != 0) System.out.println("Hints: single frame"); */} /** Unaccelerated native function for setting pixels in the image from any kind of ColorModel. */ private static native void pSetColorModelBytePixels(int psd, int x, int y, int w, int h, ColorModel cm, byte[] pixels, int offset, int scansize); /** Unaccelerated native function for setting pixels in the image from any kind of ColorModel. */ private static native void pSetColorModelIntPixels(int psd, int x, int y, int w, int h, ColorModel cm, int[] pixels, int offset, int scansize); /** Accelerated native function for setting pixels in the image when the ColorModel is an IndexColorModel. */ private static native void pSetIndexColorModelBytePixels(int psd, int x, int y, int w, int h, ColorModel cm, byte[] pixels, int offset, int scansize); /** Accelerated native function for setting pixels in the image when the ColorModel is an IndexColorModel. */ private static native void pSetIndexColorModelIntPixels(int psd, int x, int y, int w, int h, ColorModel cm, int[] pixels, int offset, int scansize); /** Accelerated native function for setting pixels in the image when the ColorModel is a DirectColorModel. */ private static native void pSetDirectColorModelPixels(int psd, int x, int y, int w, int h, ColorModel cm, int[] pixels, int offset, int scansize); /** Gets the ARGB color value at the supplied location. */ private static native int pGetRGB(int psd, int x, int y); /* Gets an area of ARGB values and stores them in the array. */ private native void pGetRGBArray(int psd, int x, int y, int w, int h, int[] pixels, int off, int scansize); /* Sets the pixel at the supplied location to an ARGB value. */ private static native void pSetRGB(int psd, int x, int y, int rgb); public void setPixels(int x, int y, int w, int h, ColorModel cm, byte[] pixels, int off, int scansize) { if ((h - 1) * scansize + (w - 1) + off >= pixels.length) throw new IllegalArgumentException("The pixel array is not big enough"); // Use accelerated set pixels routine if possible if (cm instanceof IndexColorModel) pSetIndexColorModelBytePixels(psd, x, y, w, h, cm, pixels, off, scansize); else pSetColorModelBytePixels(psd, x, y, w, h, cm, pixels, off, scansize); scanlineCount++; status = ImageObserver.SOMEBITS; if (scanlineCount % REDRAW_COUNT == 0) { notifyObservers(this, ImageObserver.SOMEBITS, x, y, w, h); } // System.out.println("SetPixelsByte " + new Rectangle(x, y, w, h)); } public void setPixels(int x, int y, int w, int h, ColorModel cm, int[] pixels, int off, int scansize) { if ((h - 1) * scansize + (w - 1) + off >= pixels.length) throw new IllegalArgumentException("The pixel array is not big enough"); // Use accelerated set pixels routine if possible if (cm instanceof DirectColorModel) pSetDirectColorModelPixels(psd, x, y, w, h, cm, pixels, off, scansize); else if (cm instanceof IndexColorModel) pSetIndexColorModelIntPixels(psd, x, y, w, h, cm, pixels, off, scansize); else pSetColorModelIntPixels(psd, x, y, w, h, cm, pixels, off, scansize); scanlineCount++; status = ImageObserver.SOMEBITS; if (scanlineCount % REDRAW_COUNT == 0) { notifyObservers(this, ImageObserver.SOMEBITS, x, y, w, h); } // System.out.println("SetPixelsInt " + new Rectangle(x, y, w, h)); } public int getType() { return gc.getCompatibleImageType(); } public ColorModel getColorModel() { return gc.getColorModel(); } public synchronized void setRGB(int x, int y, int rgb) { if (x < 0 || y < 0 || x >= width || y >= height) throw new java.lang.ArrayIndexOutOfBoundsException(x + y * width); pSetRGB(psd, x, y, rgb); }; public void setRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize) { pSetDirectColorModelPixels(psd, startX, startY, w, h, ColorModel.getRGBdefault(), rgbArray, offset, scansize); } public int getRGB(int x, int y) { if (x < 0 || y < 0 || x >= width || y >= height) throw new java.lang.ArrayIndexOutOfBoundsException(x + y * width); // pGetPixel returns us an RGB color. return pGetRGB(psd, x, y); } public int[] getRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize) { int yoff = offset; int off; if ((startX < 0) || (startY < 0) || ((startX + w) > width) || ((startY + h) > height)) throw new java.lang.ArrayIndexOutOfBoundsException(startX + startY * width); // pGetPixelArray returns a RGB pixel if (rgbArray == null) rgbArray = new int[offset + h * scansize]; else if (rgbArray.length < offset + h * scansize) throw new IllegalArgumentException("rgbArray is not large enough to store all the values"); pGetRGBArray(psd, startX, startY, w, h, rgbArray, offset, scansize); return rgbArray; } public String toString() { return "[psd=" + psd + ",width=" + width + ",height=" + height + ",status=" + status + "]"; } }