jnodeimage.java

来自「纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统」· Java 代码 · 共 495 行

JAVA
495
字号
/*
 * $Id: JNodeImage.java,v 1.1 2003/11/25 11:51:39 epr Exp $
 */
package org.jnode.awt.image;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.ColorModel;
import java.awt.image.ImageConsumer;
import java.awt.image.ImageObserver;
import java.awt.image.ImageProducer;
import java.awt.image.IndexColorModel;
import java.util.Hashtable;
import java.util.LinkedList;

import org.jnode.awt.util.AwtUtils;

/**
 * @author epr
 */
public class JNodeImage extends Image {

	int width;
	int height;
	int availableInfo;
	Hashtable properties = new Hashtable();
	Object pixels;
	ColorModel colorModel;
	private boolean productionStarted;
	private ImageProducer initProducer;

	/**
	 * Create an empty, transparent image
	 * @param width
	 * @param height
	 */
	public JNodeImage(int width, int height) {
		this(width, height, ColorModel.getRGBdefault());
	}

	/**
	 * Create an empty, transparent image
	 * @param width
	 * @param height
	 * @param colorModel
	 */
	public JNodeImage(int width, int height, ColorModel colorModel) {
		this.width = width;
		this.height = height;
		this.availableInfo = ImageObserver.ALLBITS | ImageObserver.HEIGHT | ImageObserver.WIDTH | ImageObserver.ALLBITS;
		this.colorModel = colorModel;
	}

	/**
	 * Create a new instance
	 * @param producer
	 */
	public JNodeImage(ImageProducer producer) {
		this.initProducer = producer;
		this.colorModel = ColorModel.getRGBdefault();
	}

	/**
	 * @see java.awt.Image#flush()
	 */
	public void flush() {
		// TODO Auto-generated method stub

	}

	/**
	 * @see java.awt.Image#getGraphics()
	 * @return The graphics
	 */
	public Graphics getGraphics() {
		// TODO Auto-generated method stub
		return null;
	}

	/**
	 * @param observer
	 * @see java.awt.Image#getHeight(java.awt.image.ImageObserver)
	 * @return the height
	 */
	public int getHeight(ImageObserver observer) {
		if ((availableInfo & ImageObserver.HEIGHT) == 0) {
			prepare(observer);
		}
		return height;
	}

	/**
	 * @param name
	 * @param observer
	 * @see java.awt.Image#getProperty(java.lang.String, java.awt.image.ImageObserver)
	 * @return the property
	 */
	public Object getProperty(String name, ImageObserver observer) {
		if ((availableInfo & ImageObserver.PROPERTIES) == 0) {
			prepare(observer);
		}
		return properties.get(name);
	}

	/**
	 * @see java.awt.Image#getSource()
	 * @return the source
	 */
	public ImageProducer getSource() {
		return new ForwardingProducer(null);
	}

	/**
	 * @param observer
	 * @see java.awt.Image#getWidth(java.awt.image.ImageObserver)
	 * @return the width
	 */
	public int getWidth(ImageObserver observer) {
		if ((availableInfo & ImageObserver.WIDTH) == 0) {
			prepare(observer);
		}
		return width;
	}

	/**
	 * Synchronizes the image loading.
	 * @since  PJA2.0
	 */
	public void sync() {
		loadInitImage(true, null);
	}

	protected boolean prepare(ImageObserver observer) {
		if (!productionStarted) {
			loadInitImage(false, observer);
		} else if ((availableInfo & ImageObserver.ERROR) != 0) {
			if (observer != null) {
				observer.imageUpdate(this, availableInfo, -1, -1, -1, -1);
			}
		} else {
			new ForwardingProducer(observer).startProduction(null);
		}

		return (availableInfo & ImageObserver.ALLBITS) != 0;
	}

	protected int getWidth() {
		return width;
	}

	protected int getHeight() {
		return height;
	}

	/**
	 * Gets the array used to store the pixels of this image.
	 *
	 * @return an array of <code>int</code> or <code>null</code> if the array
	 *         contains <code>byte</code> or if the image was flushed.
	 */
	protected int[] getPixels() {
		Object pixelsArray = getPixelsArray();
		return pixelsArray instanceof int[] ? (int[]) pixelsArray : null;
	}

	/**
	 * Gets the array used to store the pixels of this image.
	 *
	 * @return an array of <code>int</code> or <code>byte</code>.
	 * @since  PJA2.3
	 */
	protected Object getPixelsArray() {
		if (pixels == null && width >= 0 && height >= 0 && (availableInfo & ImageObserver.ERROR) == 0) {
			// v2.3 : Added support for 8 bit color images
			if (colorModel == null || !(colorModel instanceof IndexColorModel))
				// Should take into account the size required to store each pixel with model.getPixelSize ()
				// but for the moment only default RGB model is used
				pixels = new int[width * height];
			else
				pixels = new byte[width * height];
		}

		return pixels;
	}

	/**
	 * Gets the color at the point <code>(x,y)</code>.
	 *
	 * @param  x     the point coordinates.
	 * @param  y 
	 * @return the color of the point in default RGB model.
	 * @since  PJA2.0
	 */
	protected int getPixelColor(int x, int y) {
		if ((availableInfo & ImageObserver.ERROR) != 0 || pixels == null || x < 0 || x >= width || y < 0 || y >= height)
			return 0;

		// v2.3 : Added support for 8 bit color images
		Object pixelsArray = getPixelsArray();
		if (pixelsArray instanceof int[])
			return ((int[]) pixelsArray)[x + y * width];
		else if (pixelsArray instanceof byte[])
			return colorModel.getRGB(((byte[]) pixelsArray)[x + y * width] & 0xFF);
		else
			return 0;
	}

	/**
	 * Sets the color at the point <code>(x,y)</code>.
	 *
	 * @param  x     the point coordinates.
	 * @param  y 
	 * @param  ARGB  the color of the point in default RGB model.
	 * @since  PJA2.0
	 */
	protected void setPixelColor(int x, int y, int ARGB) {
		if (x >= 0 && x < width && y >= 0 && y < height) {
			// v2.3 : Added support for 8 bit color images
			// Get the buffer with getPixelsArray () to ensure that pixels array is available
			Object pixelsArray = getPixelsArray();

			if (pixelsArray instanceof int[]) {
				((int[]) pixelsArray)[x + y * width] = ARGB;
			} else if (pixelsArray instanceof byte[]) {
				((byte[]) pixelsArray)[x + y * width] = (byte) AwtUtils.getClosestColorIndex((IndexColorModel) colorModel, ARGB);
			}
		}
	}

	private synchronized void loadInitImage(boolean wait, final ImageObserver observer) {
		if (!productionStarted) {
			final ImageProducer producer = initProducer;
			// Loads asynchronously initial image if not yet done
			new Thread() {
				public void run() {
					producer.startProduction(new JNodeConsumer(producer, observer));
				}
			}
			.start();

			productionStarted = true;
			// v1.2 : Moved wait () out of if (!productionStarted) block
			//        because loadInitImage () can called first with parameter wait == false (by prepareImage ())
			//        and then can be called again with parameter wait == true. In that case, 
			//        current thread must be stopped to complete image download.
		}

		try {
			// If image isn't downloaded yet
			if ((availableInfo & ImageObserver.ERROR) == 0 && (availableInfo & ImageObserver.ALLBITS) == 0) {
				// Wait the producer notifies us when image is ready
				if (wait) {
					wait();
				}
			}
		} catch (InterruptedException e) {
			availableInfo = ImageObserver.ABORT | ImageObserver.ERROR;
		}
	}

	/** ImageProducer implementation.
	 * This producer is used to forward data to ImageConsumer instances and
	 * to inform ImageObserver instances.
	 */
	private class ForwardingProducer implements ImageProducer {

		/** All consumers */
		private final LinkedList consumers = new LinkedList();
		/** The observer, can be null */
		private final ImageObserver observer;

		public ForwardingProducer(ImageObserver observer) {
			this.observer = observer;
		}

		public synchronized void addConsumer(final ImageConsumer ic) {
			if (ic != null && isConsumer(ic)) {
				return;
			}

			if ((availableInfo & ImageObserver.ERROR) == 0) {
				// v1.1 : forgot to check ic
				if (ic != null) {
					consumers.add(ic);
				}

				// Complete image production before drawing in it
				sync();
			}

			synchronized (JNodeImage.this) {
				if ((availableInfo & ImageObserver.ERROR) != 0) {
					if (ic != null) {
						ic.imageComplete(ImageConsumer.IMAGEERROR);
					}
					if (observer != null) {
						observer.imageUpdate(JNodeImage.this, availableInfo, -1, -1, -1, -1);
					}
				} else {
					if (ic != null) {
						ic.setDimensions(width, height);
						ic.setHints(ImageConsumer.SINGLEPASS | ImageConsumer.SINGLEFRAME | ImageConsumer.TOPDOWNLEFTRIGHT);
						ic.setProperties(properties);
						if (colorModel != null) {
							ic.setColorModel(colorModel);
						}
						if (pixels instanceof int[]) {
							ic.setPixels(0, 0, width, height, colorModel, (int[]) pixels, 0, width);
						} else {
							ic.setPixels(0, 0, width, height, colorModel, (byte[]) pixels, 0, width);
						}
						ic.imageComplete(ImageConsumer.STATICIMAGEDONE);
					}

					if (observer != null) {
						observer.imageUpdate(JNodeImage.this, availableInfo, 0, 0, width, height);
					}
				}
			}
		}

		public synchronized void removeConsumer(ImageConsumer ic) {
			consumers.remove(ic);
		}

		public synchronized boolean isConsumer(ImageConsumer ic) {
			return consumers.contains(ic);
		}

		public void startProduction(ImageConsumer ic) {
			addConsumer(ic);
		}

		public void requestTopDownLeftRightResend(ImageConsumer ic) {
			// Useless, already sent in that order
		}
	}

	/** 
	 * ImageConsumer implementation
	 */
	private class JNodeConsumer implements ImageConsumer {
		private final ImageProducer producer;
		private final ImageObserver observer;

		public JNodeConsumer(ImageProducer producer, ImageObserver observer) {
			this.producer = producer;
			this.observer = observer;
		}

		public void setDimensions(int width, int height) {
			JNodeImage.this.width = width;
			JNodeImage.this.height = height;
			JNodeImage.this.availableInfo |= ImageObserver.WIDTH | ImageObserver.HEIGHT;
			if (observer != null) {
				observer.imageUpdate(JNodeImage.this, availableInfo, 0, 0, width, height);
			}
		}

		public void setHints(int hints) {
		}

		public void setProperties(Hashtable props) {
			JNodeImage.this.properties = props;
			JNodeImage.this.availableInfo |= ImageObserver.PROPERTIES;
			if (observer != null) {
				observer.imageUpdate(JNodeImage.this, availableInfo, 0, 0, width, height);
			}
		}

		public void setColorModel(ColorModel model) {
			//System.out.println("setColorModel " + model);
			JNodeImage.this.colorModel = model;
		}

		public void setPixels(int x, int y, int width, int height, ColorModel model, byte pixels[], int offset, int scansize) {
			synchronized (JNodeImage.this) {
				// v1.1 : check if image not flushed
				if ((availableInfo & ImageObserver.ERROR) == 0) {
					final Object pixelsArray = getPixelsArray();
					final int[] intPixels;
					final byte[] bytePixels;
					int lastARGB = 0;
					byte lastIndex = (byte) - 1;

					if (pixelsArray instanceof int[]) {
						intPixels = (int[]) pixelsArray;
						bytePixels = null;
					} else {
						bytePixels = (byte[]) pixelsArray;
						intPixels = null;
					}

					for (int row = 0, destRow = y * JNodeImage.this.width; row < height; row++, destRow += JNodeImage.this.width) {
						final int rowOff = offset + row * scansize;
						for (int col = 0; col < width; col++)
							// v2.3 : Added support for 8 bit color images
							if (intPixels != null) {
								// v1.2 : Added & 0xFF to disable sign bit
								intPixels[destRow + x + col] = model.getRGB(pixels[rowOff + col] & 0xFF);
							} else if (colorModel == model) {
								bytePixels[destRow + x + col] = pixels[rowOff + col];
							} else {
								final int ARGB = model.getRGB(pixels[rowOff + col] & 0xFF);
								if (lastIndex == -1 || lastARGB != ARGB) {
									// Keep track of the last color
									lastARGB = ARGB;
									lastIndex = (byte) AwtUtils.getClosestColorIndex((IndexColorModel) colorModel, lastARGB);
								}
								bytePixels[destRow + x + col] = lastIndex;
							}
					}
					JNodeImage.this.availableInfo |= ImageObserver.SOMEBITS;
				}
			}
		}

		public void setPixels(int x, int y, int width, int height, ColorModel model, int pixels[], int offset, int scansize) {
			synchronized (JNodeImage.this) {
				// v1.1 : check if image not flushed
				if ((availableInfo & ImageObserver.ERROR) == 0) {
					final Object pixelsArray = getPixelsArray();
					final int[] intPixels;
					final byte[] bytePixels;
					int lastARGB = 0;
					byte lastIndex = (byte) - 1;

					if (pixelsArray instanceof int[]) {
						intPixels = (int[]) pixelsArray;
						bytePixels = null;
					} else {
						bytePixels = (byte[]) pixelsArray;
						intPixels = null;
					}

					for (int row = 0, destRow = y * JNodeImage.this.width; row < height; row++, destRow += JNodeImage.this.width) {
						final int rowOff = offset + row * scansize;
						for (int col = 0; col < width; col++) {
							int ARGB = model == null ? pixels[rowOff + col] : model.getRGB(pixels[rowOff + col]);
							// v2.3 : Added support for 8 bit color images
							if (intPixels != null)
								// If model == null, consider it's the default RGB model
								intPixels[destRow + x + col] = ARGB;
							else {
								if (lastIndex == -1 || lastARGB != ARGB) {
									// Keep track of the last color
									lastARGB = ARGB;
									lastIndex = (byte) AwtUtils.getClosestColorIndex((IndexColorModel) colorModel, lastARGB);
								}
								bytePixels[destRow + x + col] = lastIndex;

							}
						}
					}
					availableInfo |= ImageObserver.SOMEBITS;
				}
			}
		}

		public void imageComplete(int status) {
			synchronized (JNodeImage.this) {
				if (status == IMAGEERROR) {
					availableInfo = ImageObserver.ERROR;
				} else if (status == IMAGEABORTED) {
					availableInfo = ImageObserver.ABORT | ImageObserver.ERROR;
				} else {
					availableInfo &= ~ImageObserver.SOMEBITS;
					if (status == STATICIMAGEDONE) {
						availableInfo |= ImageObserver.ALLBITS;
					} else if (status == SINGLEFRAMEDONE) {
						// This implementation manages only one frame
						availableInfo |= ImageObserver.ALLBITS /*ImageObserver.FRAMEBITS*/;
					}
				}

				if (status == IMAGEERROR || status == IMAGEABORTED) {
					pixels = null;
				}

				producer.removeConsumer(this);
				if (observer != null) {
					if ((availableInfo & ImageObserver.ERROR) != 0) {
						observer.imageUpdate(JNodeImage.this, availableInfo, -1, -1, -1, -1);
					} else {
						observer.imageUpdate(JNodeImage.this, availableInfo, 0, 0, width, height);
					}
				}

				// v1.2 : Moved synchronized to method start
				JNodeImage.this.notifyAll();
			}
		}
	}
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?