📄 rescaleop.java
字号:
/* * @(#)RescaleOp.java 1.42 03/01/23 * * Copyright 2003 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */package java.awt.image;import java.awt.color.ColorSpace;import java.awt.geom.Rectangle2D;import java.awt.Rectangle;import java.awt.geom.Point2D;import java.awt.RenderingHints;import sun.awt.image.ImagingLib;/** * This class performs a pixel-by-pixel rescaling of the data in the * source image by multiplying the sample values for each pixel by a scale * factor and then adding an offset. The scaled sample values are clipped * to the minimum/maximum representable in the destination image. * <p> * The pseudo code for the rescaling operation is as follows: * <pre> *for each pixel from Source object { * for each band/component of the pixel { * dstElement = (srcElement*scaleFactor) + offset * } *} * </pre> * <p> * For Rasters, rescaling operates on bands. The number of * sets of scaling 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, rescaling operates on color and alpha components. * The number of sets of scaling constants may be one, in which case the * same constants are applied to all color (but not alpha) components. * Otherwise, the number of sets of scaling constants may * equal the number of Source color components, in which case no * rescaling of the alpha component (if present) is performed. * If neither of these cases apply, the number of sets of scaling constants * must equal the number of Source color components plus alpha components, * in which case all color and alpha components are rescaled. * <p> * BufferedImage sources with premultiplied alpha data are treated in the same * manner as non-premultiplied images for purposes of rescaling. That is, * the rescaling is done per band on the raw data of the BufferedImage source * without regard to whether the data is premultiplied. If a color conversion * is required to the destination ColorModel, the premultiplied state of * both source and destination will be taken into account for this step. * <p> * Images with an IndexColorModel cannot be rescaled. * <p> * If a RenderingHints object is specified in the constructor, the * color rendering hint and the dithering hint may be used when color * conversion is required. * <p> * Note that in-place operation is allowed (i.e. the source and destination can * be the same object). * @version 10 Feb 1997 * @see java.awt.RenderingHints#KEY_COLOR_RENDERING * @see java.awt.RenderingHints#KEY_DITHERING */public class RescaleOp implements BufferedImageOp, RasterOp { float[] scaleFactors; float[] offsets; int length = 0; RenderingHints hints; private int srcNbits; private int dstNbits; /** * Constructs a new RescaleOp with the desired scale factors * and offsets. The length of the scaleFactor and offset arrays * must meet the restrictions stated in the class comments above. * The RenderingHints argument may be null. * @param scaleFactors the specified scale factors * @param offsets the specified offsets * @param hints the specified <code>RenderingHints</code>, or * <code>null</code> */ public RescaleOp (float[] scaleFactors, float[] offsets, RenderingHints hints) { length = scaleFactors.length; if (length > offsets.length) length = offsets.length; this.scaleFactors = new float[length]; this.offsets = new float[length]; for (int i=0; i < length; i++) { this.scaleFactors[i] = scaleFactors[i]; this.offsets[i] = offsets[i]; } this.hints = hints; } /** * Constructs a new RescaleOp with the desired scale factor * and offset. The scaleFactor and offset will be applied to * all bands in a source Raster and to all color (but not alpha) * components in a BufferedImage. * The RenderingHints argument may be null. * @param scaleFactor the specified scale factor * @param offset the specified offset * @param hints the specified <code>RenderingHints</code>, or * <code>null</code> */ public RescaleOp (float scaleFactor, float offset, RenderingHints hints) { length = 1; this.scaleFactors = new float[1]; this.offsets = new float[1]; this.scaleFactors[0] = scaleFactor; this.offsets[0] = offset; this.hints = hints; } /** * Returns the scale factors in the given array. The array is also * returned for convenience. If scaleFactors is null, a new array * will be allocated. * @param scaleFactors the array to contain the scale factors of * this <code>RescaleOp</code> * @return the scale factors of this <code>RescaleOp</code>. */ final public float[] getScaleFactors (float scaleFactors[]) { if (scaleFactors == null) { return (float[]) this.scaleFactors.clone(); } System.arraycopy (this.scaleFactors, 0, scaleFactors, 0, Math.min(this.scaleFactors.length, scaleFactors.length)); return scaleFactors; } /** * Returns the offsets in the given array. The array is also returned * for convenience. If offsets is null, a new array * will be allocated. * @param offsets the array to contain the offsets of * this <code>RescaleOp</code> * @return the offsets of this <code>RescaleOp</code>. */ final public float[] getOffsets(float offsets[]) { if (offsets == null) { return (float[]) this.offsets.clone(); } System.arraycopy (this.offsets, 0, offsets, 0, Math.min(this.offsets.length, offsets.length)); return offsets; } /** * Returns the number of scaling factors and offsets used in this * RescaleOp. * @return the number of scaling factors and offsets of this * <code>RescaleOp</code>. */ final public int getNumFactors() { return length; } /** * Creates a ByteLookupTable to implement the rescale. * The table may have either a SHORT or BYTE input. * @param nElems Number of elements the table is to have. * This will generally be 256 for byte and * 65536 for short. */ private ByteLookupTable createByteLut(float scale[], float off[], int nBands, int nElems) { byte[][] lutData = new byte[scale.length][nElems]; for (int band=0; band<scale.length; band++) { float bandScale = scale[band]; float bandOff = off[band]; byte[] bandLutData = lutData[band]; for (int i=0; i<nElems; i++) { int val = (int)(i*bandScale + bandOff); if ((val & 0xffffff00) != 0) { if (val < 0) { val = 0; } else { val = 255; } } bandLutData[i] = (byte)val; } } return new ByteLookupTable(0, lutData); } /** * Creates a ShortLookupTable to implement the rescale. * The table may have either a SHORT or BYTE input. * @param nElems Number of elements the table is to have. * This will generally be 256 for byte and * 65536 for short. */ private ShortLookupTable createShortLut(float scale[], float off[], int nBands, int nElems) { short[][] lutData = new short[scale.length][nElems]; for (int band=0; band<scale.length; band++) { float bandScale = scale[band]; float bandOff = off[band]; short[] bandLutData = lutData[band]; for (int i=0; i<nElems; i++) { int val = (int)(i*bandScale + bandOff); if ((val & 0xffff0000) != 0) { if (val < 0) { val = 0; } else { val = 65535; } } bandLutData[i] = (short)val; } } return new ShortLookupTable(0, lutData); } /** * Determines if the rescale can be performed as a lookup. * The dst must be a byte or short type. * The src must be less than 16 bits. * All source band sizes must be the same and all dst band sizes * must be the same. */ private boolean canUseLookup(Raster src, Raster dst) { // // Check that the src datatype is either a BYTE or SHORT // int datatype = src.getDataBuffer().getDataType(); if(datatype != DataBuffer.TYPE_BYTE && datatype != DataBuffer.TYPE_USHORT) { return false; } // // Check dst sample sizes. All must be 8 or 16 bits. // SampleModel dstSM = dst.getSampleModel(); dstNbits = dstSM.getSampleSize(0); if (!(dstNbits == 8 || dstNbits == 16)) { return false; } for (int i=1; i<src.getNumBands(); i++) { int bandSize = dstSM.getSampleSize(i); if (bandSize != dstNbits) { return false; } } // // Check src sample sizes. All must be the same size // SampleModel srcSM = src.getSampleModel(); srcNbits = srcSM.getSampleSize(0); if (srcNbits > 16) { return false; } for (int i=1; i<src.getNumBands(); i++) { int bandSize = srcSM.getSampleSize(i); if (bandSize != srcNbits) { return false; } } return true; } /** * Rescales the source 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. * An IllegalArgumentException may be thrown if the number of * scaling factors/offsets in this object does not meet the * restrictions stated in the class comments above, or if the * source image has an IndexColorModel. * @param src the <code>BufferedImage</code> to be filtered * @param dst the destination for the filtering operation * or <code>null</code> * @return the filtered <code>BufferedImage</code>. * @throws IllegalArgumentException if the <code>ColorModel</code> * of <code>src</code> is an <code>IndexColorModel</code>, * or if the number of scaling factors and offsets in this * <code>RescaleOp</code> do not meet the requirements * stated in the class comments. */ public final BufferedImage filter (BufferedImage src, BufferedImage dst) { ColorModel srcCM = src.getColorModel(); ColorModel dstCM; int numBands = srcCM.getNumColorComponents(); if (srcCM instanceof IndexColorModel) { throw new IllegalArgumentException("Rescaling cannot be "+ "performed on an indexed image"); } if (length != 1 && length != numBands && length != srcCM.getNumComponents()) { throw new IllegalArgumentException("Number of scaling constants "+ "does not equal the number of"+ " of color or color/alpha "+
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -