0N/A/*
2362N/A * Copyright (c) 1997, 2000, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage java.awt.image;
0N/A
0N/Aimport java.util.Hashtable;
0N/Aimport java.awt.image.ImageConsumer;
0N/Aimport java.awt.image.ImageFilter;
0N/A
0N/A/**
0N/A * The <code>BufferedImageFilter</code> class subclasses an
0N/A * <code>ImageFilter</code> to provide a simple means of
0N/A * using a single-source/single-destination image operator
0N/A * ({@link BufferedImageOp}) to filter a <code>BufferedImage</code>
0N/A * in the Image Producer/Consumer/Observer
0N/A * paradigm. Examples of these image operators are: {@link ConvolveOp},
0N/A * {@link AffineTransformOp} and {@link LookupOp}.
0N/A *
0N/A * @see ImageFilter
0N/A * @see BufferedImage
0N/A * @see BufferedImageOp
0N/A */
0N/A
0N/Apublic class BufferedImageFilter extends ImageFilter implements Cloneable {
0N/A BufferedImageOp bufferedImageOp;
0N/A ColorModel model;
0N/A int width;
0N/A int height;
0N/A byte[] bytePixels;
0N/A int[] intPixels;
0N/A
0N/A /**
0N/A * Constructs a <code>BufferedImageFilter</code> with the
0N/A * specified single-source/single-destination operator.
0N/A * @param op the specified <code>BufferedImageOp</code> to
0N/A * use to filter a <code>BufferedImage</code>
0N/A * @throws NullPointerException if op is null
0N/A */
0N/A public BufferedImageFilter (BufferedImageOp op) {
0N/A super();
0N/A if (op == null) {
0N/A throw new NullPointerException("Operation cannot be null");
0N/A }
0N/A bufferedImageOp = op;
0N/A }
0N/A
0N/A /**
0N/A * Returns the <code>BufferedImageOp</code>.
0N/A * @return the operator of this <code>BufferedImageFilter</code>.
0N/A */
0N/A public BufferedImageOp getBufferedImageOp() {
0N/A return bufferedImageOp;
0N/A }
0N/A
0N/A /**
0N/A * Filters the information provided in the
0N/A * {@link ImageConsumer#setDimensions(int, int) setDimensions } method
0N/A * of the {@link ImageConsumer} interface.
0N/A * <p>
0N/A * Note: This method is intended to be called by the
0N/A * {@link ImageProducer} of the <code>Image</code> whose pixels are
0N/A * being filtered. Developers using this class to retrieve pixels from
0N/A * an image should avoid calling this method directly since that
0N/A * operation could result in problems with retrieving the requested
0N/A * pixels.
0N/A * <p>
0N/A * @param width the width to which to set the width of this
0N/A * <code>BufferedImageFilter</code>
0N/A * @param height the height to which to set the height of this
0N/A * <code>BufferedImageFilter</code>
0N/A * @see ImageConsumer#setDimensions
0N/A */
0N/A public void setDimensions(int width, int height) {
0N/A if (width <= 0 || height <= 0) {
0N/A imageComplete(STATICIMAGEDONE);
0N/A return;
0N/A }
0N/A this.width = width;
0N/A this.height = height;
0N/A }
0N/A
0N/A /**
0N/A * Filters the information provided in the
0N/A * {@link ImageConsumer#setColorModel(ColorModel) setColorModel} method
0N/A * of the <code>ImageConsumer</code> interface.
0N/A * <p>
0N/A * If <code>model</code> is <code>null</code>, this
0N/A * method clears the current <code>ColorModel</code> of this
0N/A * <code>BufferedImageFilter</code>.
0N/A * <p>
0N/A * Note: This method is intended to be called by the
0N/A * <code>ImageProducer</code> of the <code>Image</code>
0N/A * whose pixels are being filtered. Developers using this
0N/A * class to retrieve pixels from an image
0N/A * should avoid calling this method directly since that
0N/A * operation could result in problems with retrieving the
0N/A * requested pixels.
0N/A * @param model the {@link ColorModel} to which to set the
0N/A * <code>ColorModel</code> of this <code>BufferedImageFilter</code>
0N/A * @see ImageConsumer#setColorModel
0N/A */
0N/A public void setColorModel(ColorModel model) {
0N/A this.model = model;
0N/A }
0N/A
0N/A private void convertToRGB() {
0N/A int size = width * height;
0N/A int newpixels[] = new int[size];
0N/A if (bytePixels != null) {
0N/A for (int i = 0; i < size; i++) {
0N/A newpixels[i] = this.model.getRGB(bytePixels[i] & 0xff);
0N/A }
0N/A } else if (intPixels != null) {
0N/A for (int i = 0; i < size; i++) {
0N/A newpixels[i] = this.model.getRGB(intPixels[i]);
0N/A }
0N/A }
0N/A bytePixels = null;
0N/A intPixels = newpixels;
0N/A this.model = ColorModel.getRGBdefault();
0N/A }
0N/A
0N/A /**
0N/A * Filters the information provided in the <code>setPixels</code>
0N/A * method of the <code>ImageConsumer</code> interface which takes
0N/A * an array of bytes.
0N/A * <p>
0N/A * Note: This method is intended to be called by the
0N/A * <code>ImageProducer</code> of the <code>Image</code> whose pixels
0N/A * are being filtered. Developers using
0N/A * this class to retrieve pixels from an image should avoid calling
0N/A * this method directly since that operation could result in problems
0N/A * with retrieving the requested pixels.
0N/A * @throws IllegalArgumentException if width or height are less than
0N/A * zero.
0N/A * @see ImageConsumer#setPixels(int, int, int, int, ColorModel, byte[],
0N/A int, int)
0N/A */
0N/A public void setPixels(int x, int y, int w, int h,
0N/A ColorModel model, byte pixels[], int off,
0N/A int scansize) {
0N/A // Fix 4184230
0N/A if (w < 0 || h < 0) {
0N/A throw new IllegalArgumentException("Width ("+w+
0N/A ") and height ("+h+
0N/A ") must be > 0");
0N/A }
0N/A // Nothing to do
0N/A if (w == 0 || h == 0) {
0N/A return;
0N/A }
0N/A if (y < 0) {
0N/A int diff = -y;
0N/A if (diff >= h) {
0N/A return;
0N/A }
0N/A off += scansize * diff;
0N/A y += diff;
0N/A h -= diff;
0N/A }
0N/A if (y + h > height) {
0N/A h = height - y;
0N/A if (h <= 0) {
0N/A return;
0N/A }
0N/A }
0N/A if (x < 0) {
0N/A int diff = -x;
0N/A if (diff >= w) {
0N/A return;
0N/A }
0N/A off += diff;
0N/A x += diff;
0N/A w -= diff;
0N/A }
0N/A if (x + w > width) {
0N/A w = width - x;
0N/A if (w <= 0) {
0N/A return;
0N/A }
0N/A }
0N/A int dstPtr = y*width + x;
0N/A if (intPixels == null) {
0N/A if (bytePixels == null) {
0N/A bytePixels = new byte[width*height];
0N/A this.model = model;
0N/A } else if (this.model != model) {
0N/A convertToRGB();
0N/A }
0N/A if (bytePixels != null) {
0N/A for (int sh = h; sh > 0; sh--) {
0N/A System.arraycopy(pixels, off, bytePixels, dstPtr, w);
0N/A off += scansize;
0N/A dstPtr += width;
0N/A }
0N/A }
0N/A }
0N/A if (intPixels != null) {
0N/A int dstRem = width - w;
0N/A int srcRem = scansize - w;
0N/A for (int sh = h; sh > 0; sh--) {
0N/A for (int sw = w; sw > 0; sw--) {
0N/A intPixels[dstPtr++] = model.getRGB(pixels[off++]&0xff);
0N/A }
0N/A off += srcRem;
0N/A dstPtr += dstRem;
0N/A }
0N/A }
0N/A }
0N/A /**
0N/A * Filters the information provided in the <code>setPixels</code>
0N/A * method of the <code>ImageConsumer</code> interface which takes
0N/A * an array of integers.
0N/A * <p>
0N/A * Note: This method is intended to be called by the
0N/A * <code>ImageProducer</code> of the <code>Image</code> whose
0N/A * pixels are being filtered. Developers using this class to
0N/A * retrieve pixels from an image should avoid calling this method
0N/A * directly since that operation could result in problems
0N/A * with retrieving the requested pixels.
0N/A * @throws IllegalArgumentException if width or height are less than
0N/A * zero.
0N/A * @see ImageConsumer#setPixels(int, int, int, int, ColorModel, int[],
0N/A int, int)
0N/A */
0N/A public void setPixels(int x, int y, int w, int h,
0N/A ColorModel model, int pixels[], int off,
0N/A int scansize) {
0N/A // Fix 4184230
0N/A if (w < 0 || h < 0) {
0N/A throw new IllegalArgumentException("Width ("+w+
0N/A ") and height ("+h+
0N/A ") must be > 0");
0N/A }
0N/A // Nothing to do
0N/A if (w == 0 || h == 0) {
0N/A return;
0N/A }
0N/A if (y < 0) {
0N/A int diff = -y;
0N/A if (diff >= h) {
0N/A return;
0N/A }
0N/A off += scansize * diff;
0N/A y += diff;
0N/A h -= diff;
0N/A }
0N/A if (y + h > height) {
0N/A h = height - y;
0N/A if (h <= 0) {
0N/A return;
0N/A }
0N/A }
0N/A if (x < 0) {
0N/A int diff = -x;
0N/A if (diff >= w) {
0N/A return;
0N/A }
0N/A off += diff;
0N/A x += diff;
0N/A w -= diff;
0N/A }
0N/A if (x + w > width) {
0N/A w = width - x;
0N/A if (w <= 0) {
0N/A return;
0N/A }
0N/A }
0N/A
0N/A if (intPixels == null) {
0N/A if (bytePixels == null) {
0N/A intPixels = new int[width * height];
0N/A this.model = model;
0N/A } else {
0N/A convertToRGB();
0N/A }
0N/A }
0N/A int dstPtr = y*width + x;
0N/A if (this.model == model) {
0N/A for (int sh = h; sh > 0; sh--) {
0N/A System.arraycopy(pixels, off, intPixels, dstPtr, w);
0N/A off += scansize;
0N/A dstPtr += width;
0N/A }
0N/A } else {
0N/A if (this.model != ColorModel.getRGBdefault()) {
0N/A convertToRGB();
0N/A }
0N/A int dstRem = width - w;
0N/A int srcRem = scansize - w;
0N/A for (int sh = h; sh > 0; sh--) {
0N/A for (int sw = w; sw > 0; sw--) {
0N/A intPixels[dstPtr++] = model.getRGB(pixels[off++]);
0N/A }
0N/A off += srcRem;
0N/A dstPtr += dstRem;
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Filters the information provided in the <code>imageComplete</code>
0N/A * method of the <code>ImageConsumer</code> interface.
0N/A * <p>
0N/A * Note: This method is intended to be called by the
0N/A * <code>ImageProducer</code> of the <code>Image</code> whose pixels
0N/A * are being filtered. Developers using
0N/A * this class to retrieve pixels from an image should avoid calling
0N/A * this method directly since that operation could result in problems
0N/A * with retrieving the requested pixels.
0N/A * @param status the status of image loading
0N/A * @throws ImagingOpException if there was a problem calling the filter
0N/A * method of the <code>BufferedImageOp</code> associated with this
0N/A * instance.
0N/A * @see ImageConsumer#imageComplete
0N/A */
0N/A public void imageComplete(int status) {
0N/A WritableRaster wr;
0N/A switch(status) {
0N/A case IMAGEERROR:
0N/A case IMAGEABORTED:
0N/A // reinitialize the params
0N/A model = null;
0N/A width = -1;
0N/A height = -1;
0N/A intPixels = null;
0N/A bytePixels = null;
0N/A break;
0N/A
0N/A case SINGLEFRAMEDONE:
0N/A case STATICIMAGEDONE:
0N/A if (width <= 0 || height <= 0) break;
0N/A if (model instanceof DirectColorModel) {
0N/A if (intPixels == null) break;
0N/A wr = createDCMraster();
0N/A }
0N/A else if (model instanceof IndexColorModel) {
0N/A int[] bandOffsets = {0};
0N/A if (bytePixels == null) break;
0N/A DataBufferByte db = new DataBufferByte(bytePixels,
0N/A width*height);
0N/A wr = Raster.createInterleavedRaster(db, width, height, width,
0N/A 1, bandOffsets, null);
0N/A }
0N/A else {
0N/A convertToRGB();
0N/A if (intPixels == null) break;
0N/A wr = createDCMraster();
0N/A }
0N/A BufferedImage bi = new BufferedImage(model, wr,
0N/A model.isAlphaPremultiplied(),
0N/A null);
0N/A bi = bufferedImageOp.filter(bi, null);
0N/A WritableRaster r = bi.getRaster();
0N/A ColorModel cm = bi.getColorModel();
0N/A int w = r.getWidth();
0N/A int h = r.getHeight();
0N/A consumer.setDimensions(w, h);
0N/A consumer.setColorModel(cm);
0N/A if (cm instanceof DirectColorModel) {
0N/A DataBufferInt db = (DataBufferInt) r.getDataBuffer();
0N/A consumer.setPixels(0, 0, w, h,
0N/A cm, db.getData(), 0, w);
0N/A }
0N/A else if (cm instanceof IndexColorModel) {
0N/A DataBufferByte db = (DataBufferByte) r.getDataBuffer();
0N/A consumer.setPixels(0, 0, w, h,
0N/A cm, db.getData(), 0, w);
0N/A }
0N/A else {
0N/A throw new InternalError("Unknown color model "+cm);
0N/A }
0N/A break;
0N/A }
0N/A consumer.imageComplete(status);
0N/A }
0N/A
0N/A private final WritableRaster createDCMraster() {
0N/A WritableRaster wr;
0N/A DirectColorModel dcm = (DirectColorModel) model;
0N/A boolean hasAlpha = model.hasAlpha();
0N/A int[] bandMasks = new int[3+(hasAlpha ? 1 : 0)];
0N/A bandMasks[0] = dcm.getRedMask();
0N/A bandMasks[1] = dcm.getGreenMask();
0N/A bandMasks[2] = dcm.getBlueMask();
0N/A if (hasAlpha) {
0N/A bandMasks[3] = dcm.getAlphaMask();
0N/A }
0N/A DataBufferInt db = new DataBufferInt(intPixels, width*height);
0N/A wr = Raster.createPackedRaster(db, width, height, width,
0N/A bandMasks, null);
0N/A return wr;
0N/A }
0N/A
0N/A}