home *** CD-ROM | disk | FTP | other *** search
Java Source | 1998-03-20 | 15.0 KB | 417 lines |
- /*
- * @(#)ThresholdOp.java 1.30 98/03/18
- *
- * Copyright 1997, 1998 by Sun Microsystems, Inc.,
- * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
- * All rights reserved.
- *
- * This software is the confidential and proprietary information
- * of Sun Microsystems, Inc. ("Confidential Information"). You
- * shall not disclose such Confidential Information and shall use
- * it only in accordance with the terms of the license agreement
- * you entered into with Sun.
- */
-
- package java.awt.image;
-
- import java.awt.GraphicsEnvironment;
- import java.awt.geom.Rectangle2D;
- import java.awt.Rectangle;
- import java.awt.geom.Point2D;
-
- /**
- * This class performs thresholding on the source image by mapping
- * the value of each image component (for BufferedImages) or
- * channel element (for Rasters) that falls between a low and
- * a high value, to a constant.
- * <p>
- * For Rasters, the number of sets of threshold constants may be one, in which
- * case the same constants are applied to all bands, or it must equal
- * the number of Source Raster bands.
- * <p>
- * For BufferedImages, the number of low/high values may be
- * one, in which case the same range is applied to all color and
- * alpha components, or it must equal the number of
- * Source color components,
- * in which case no thresholding of the alpha component (if present) is
- * performed, or it must equal the number of Source color components plus
- * alpha components, in which case all color and alpha components are
- * thresholded.
- *
- * Image with an IndexColorModel cannot be thresholded.
- * <p>
- * The pseudo code for the thresholding operation is as follows:
- * <pre>
- *for each pixel from Source object {
- * for each channel/component of the pixel {
- * if (srcElement <= thresholdValue) {
- * destElement = lowValue;
- * }
- * else {
- * destElement = highValue;
- * }
- * }
- *}
- * </pre>
- * Note that in-place operation is allowed (i.e. the source and destination can
- * be the same object).
- * @version 10 Feb 1997
- */
- public class ThresholdOp implements BufferedImageOp, RasterOp {
- int[] threshold;
- int[] low;
- int[] high;
- int length;
-
-
- /**
- * Constructs a new ThresholdOp with the desired per channel/component
- * mappings. The number of sets of mapping constants is subject
- * to the restrictions given in the class comments above.
- */
- public ThresholdOp (int[] threshold, int[] low, int[] high) {
-
- if (threshold == null) {
- throw new IllegalArgumentException("Threshold value is null");
- }
-
- if (low == null) {
- throw new IllegalArgumentException("Low value is null.");
- }
- if (high == null) {
- throw new IllegalArgumentException("High value is null.");
- }
-
- // Figure out #elements
- length = (threshold.length > low.length
- ? low.length
- : threshold.length);
- length = (length > high.length ? high.length : length);
-
- this.threshold = new int[length];
- this.low = new int[length];
- this.high = new int[length];
- System.arraycopy(threshold, 0, this.threshold, 0, length);
- System.arraycopy(low, 0, this.low, 0, length);
- System.arraycopy(high, 0, this.high, 0, length);
- }
-
- /**
- * Constructs a new ThresholdOp with the desired mapping. The same set
- * of thresholding constants will be applied to all channels/components
- * of the Raster/BufferedImage.
- */
- public ThresholdOp (int threshold, int low, int high) {
- length = 1;
- this.threshold = new int[1];
- this.low = new int[1];
- this.high = new int[1];
-
- this.threshold[0] = threshold;
- this.low[0] = low;
- this.high[0] = high;
- }
-
- /**
- * Returns the threshold value.
- */
- final public int[] getThreshold() {
- return (int[]) threshold.clone();
- }
-
- /**
- * Returns the low value array.
- */
- final public int[] getLows() {
- return (int[]) low.clone();
- }
-
- /**
- * Returns the high value array.
- */
- final public int[] getHighs() {
- return (int[]) high.clone();
- }
-
- /**
- * Performs thresholding on the BufferedImage.
- * If the color model in the source image is not the same as that
- * in the destination image, the pixels will be converted
- * in the destination. If the destination image is null,
- * a BufferedImage will be created with the source ColorModel.
- * The number of sets of threshold constants in this object may be
- * one, in which case the same constants are applied to all color and
- * alpha components, or it must equal the number of Source color
- * components, in which case no thresholding of the alpha component
- * (if present) is performed, or it must equal the number of Source
- * color components plus alpha components, in which case all color
- * and alpha components are thresholded. Otherwise an
- * IllegalArgumentException will be thrown.
- */
- public BufferedImage filter (BufferedImage src, BufferedImage dst) {
- int length = this.length;
- ColorModel srcCM = src.getColorModel();
- int numBands = srcCM.getNumColorComponents();
- if (srcCM instanceof IndexColorModel) {
- throw new
- IllegalArgumentException("Thresholding cannot be performed "+
- "on an indexed image");
- }
-
- boolean needToConvert = false;
- if (length > 1 && length < numBands) {
- throw new IllegalArgumentException("Number of bands ("+numBands+
- ") must match number of "+
- " elements ("+length+
- ") in threshold array.");
- }
- // Include alpha
- if (length > numBands && srcCM.hasAlpha()) {
- length = numBands+1;
- }
-
- int width = src.getWidth();
- int height = src.getHeight();
-
- if (dst == null) {
- dst = createCompatibleDestImage(src, null);
- }
- else {
- if (width != dst.getWidth()) {
- throw new
- IllegalArgumentException("Src width ("+width+
- ") not equal to dst width ("+
- dst.getWidth()+")");
- }
- if (height != dst.getHeight()) {
- throw new
- IllegalArgumentException("Src height ("+height+
- ") not equal to dst height ("+
- dst.getHeight()+")");
- }
-
- ColorModel dstCM = dst.getColorModel();
- if (!srcCM.equals(dstCM)) {
- needToConvert = true;
- dst = createCompatibleDestImage(src, null);
- }
-
- }
-
- BufferedImage origDst = dst;
- GraphicsEnvironment ge =
- GraphicsEnvironment.getLocalGraphicsEnvironment();
- ImagingLib imlib = ge.getImagingLib();
-
-
- // See if there is an installed imaging library
- if (imlib.filter(this, src, dst) == null) {
-
- // REMIND: Use Byte or Short Lookup Table!
-
- if (srcCM instanceof ComponentColorModel) {
- filter(src.getRaster(), dst.getRaster());
- }
- else {
- // Do it the slow way
- WritableRaster srcRaster = src.getRaster();
- WritableRaster dstRaster = dst.getRaster();
- int[] data = null;
- Object obj = null;
- int[] components = null;
- int step;
- int tidx;
-
- step = (length > 1) ? 1 : 0;
-
- int sminX = src.getMinXCoord();
- int sX;
- int sY = src.getMinYCoord();
- int dminX = dst.getMinXCoord();
- int dX;
- int dY = dst.getMinYCoord();
- for (int y=0; y < height; y++, sY++, dY++) {
- dX = dminX;
- sX = sminX;
- for (int x = 0; x < width; x++, sX++, dX++) {
- data = srcRaster.getPixel(sX, sY, data);
- tidx=0;
- for (int c = 0; c < numBands; c++, tidx+=step) {
- data[c] = ((data[c] <= threshold[tidx])
- ? low[tidx]
- : high[tidx]);
- }
-
- dstRaster.setPixel(dX, dY, data);
- }
- }
- }
- }
-
- if (needToConvert) {
- // ColorModels are not the same
- ColorConvertOp ccop = new ColorConvertOp();
- ccop.filter(dst, origDst);
- }
-
- return origDst;
- }
-
- /**
- * Performs thresholding on the Raster.
- * If the destination Raster is null, a new Raster will be created.
- * The source and destination must have the same number of bands.
- * The number of sets of threshold constants in this object may be
- * one, in which case the same constants are applied to all bands,
- * or it must equal the number of Source Raster bands.
- * An IllegalArgumentException will be thrown if the number of bands
- * in the source does not match the destination, or if the above
- * restrictions on the number of sets of threshold constants are
- * not met.
- */
- public WritableRaster filter (Raster src, WritableRaster dst) {
- int numBands = src.getNumBands();
- int width = src.getWidth();
- int height = src.getHeight();
- int[] srcPix = null;
- int step = 0;
- int tIdx = 0;
-
- // Create a new destination Raster, if needed
- if (dst == null) {
- dst = createCompatibleDestRaster(src);
- }
- else if (height != dst.getHeight() || width != dst.getWidth()) {
- throw new
- IllegalArgumentException ("Width or height of Rasters do not "
- +"match");
- }
- else if (numBands != dst.getNumBands()) {
- // Make sure that the number of bands are equal
-
- throw new IllegalArgumentException("Number of bands in src "
- + numBands
- + " does not equal number of bands in dst "
- + dst.getNumBands());
- }
-
- // Make sure that the low/high/constant arrays match
- if (length != 1 && length < numBands) {
- throw new IllegalArgumentException("Number of bands ("+numBands+
- ") must match number of "+
- " elements ("+length+
- ") in threshold array.");
- }
-
- // REMIND: Use Byte or Short Lookup Table!
-
- if (length > 1) {
- step = 1;
- }
-
- int sminX = src.getMinX();
- int sY = src.getMinY();
- int dminX = dst.getMinX();
- int dY = dst.getMinY();
- int sX;
- int dX;
- for (int y=0; y < height; y++, sY++, dY++) {
- dX = dminX;
- sX = sminX;
- for (int x = 0; x < width; x++, sX++, dX++) {
- // Get data for all bands at this x,y position
- srcPix = src.getPixel(sX, sY, srcPix);
- tIdx = 0;
- for (int z=0; z < numBands; z++, tIdx += step) {
- srcPix[z] = ((srcPix[z] <= threshold[tIdx])
- ? low[tIdx]
- : high[tIdx]);
- }
-
- // Put it back for all bands
- dst.setPixel(dX, dY, srcPix);
- }
- }
-
- return dst;
- }
-
- /**
- * Returns the bounding box of the thresholded destination. Since
- * this is not a geometric operation, the bounding box does not
- * change. An IllegalArgumentException will be thrown if the
- * number of sets of threshold constants does not meet the restrictions
- * stated in the class comments above.
- */
- public Rectangle2D getDestBounds (BufferedImage src) {
- return getDestBounds(src.getRaster());
- }
-
- /**
- * Returns the bounding box of the thresholded destination. Since
- * this is not a geometric operation, the bounding box does not
- * change. An IllegalArgumentException will be thrown if the
- * number of sets of threshold constants does not meet the restrictions
- * stated in the class comments above.
- */
- public Rectangle2D getDestBounds (Raster src) {
- // return new Rectangle (src.getXOffset(), src.getYOffset(),
- // src.getWidth(), src.getHeight());
- return src.getBounds();
- }
-
- /**
- * Creates an empty destination image with the correct size and number of
- * bands. An IllegalArgumentException will be thrown if the
- * number of sets of threshold constants does not meet the restrictions
- * stated in the class comments above.
- * @param src Source image for the filter operation.
- * @param destCM ColorModel of the destination. If null, the
- * ColorModel of the source will be used.
- */
- public BufferedImage createCompatibleDestImage (BufferedImage src,
- ColorModel destCM) {
- BufferedImage image;
- if (destCM == null) {
- ColorModel cm = src.getColorModel();
- image = new BufferedImage(cm,
- src.getRaster().createCompatibleWritableRaster(),
- cm.isAlphaPremultiplied());
- }
- else {
- int w = src.getWidth();
- int h = src.getHeight();
- image = new BufferedImage (destCM,
- destCM.createCompatibleWritableRaster(w, h),
- destCM.isAlphaPremultiplied());
- }
-
- return image;
- }
-
- /**
- * Creates an empty destination Raster with the correct size and number
- * of bands.
- * An IllegalArgumentException will be thrown if the
- * number of sets of threshold constants does not meet the restrictions
- * stated in the class comments above.
- */
- public WritableRaster createCompatibleDestRaster (Raster src) {
- return src.createCompatibleWritableRaster(src.getWidth(), src.getHeight());
- }
-
- /**
- * Returns the location of the destination point given a
- * point in the source image. If dstPt is non-null, it will
- * be used to hold the return value. Since this is not a geometric
- * operation, the srcPt will equal the dstPt.
- */
- public Point2D getDestPoint (Point2D srcPt, Point2D dstPt) {
- if (dstPt == null) {
- dstPt = new Point2D.Float();
- }
- dstPt.setLocation(srcPt.getX(), srcPt.getY());
- return dstPt;
- }
- }
-