diff options
Diffstat (limited to 'awt/org/apache/harmony/awt/gl/color/ColorScaler.java')
-rw-r--r-- | awt/org/apache/harmony/awt/gl/color/ColorScaler.java | 355 |
1 files changed, 355 insertions, 0 deletions
diff --git a/awt/org/apache/harmony/awt/gl/color/ColorScaler.java b/awt/org/apache/harmony/awt/gl/color/ColorScaler.java new file mode 100644 index 0000000..a1cc169 --- /dev/null +++ b/awt/org/apache/harmony/awt/gl/color/ColorScaler.java @@ -0,0 +1,355 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ +package org.apache.harmony.awt.gl.color; + +import java.awt.color.ColorSpace; +import java.awt.color.ICC_Profile; +import java.awt.image.DataBuffer; +import java.awt.image.Raster; +import java.awt.image.SampleModel; +import java.awt.image.WritableRaster; + +/** + * This class provides functionality for scaling color data when + * ranges of the source and destination color values differs. + */ +public class ColorScaler { + private static final float MAX_SHORT = 0xFFFF; + private static final float MAX_SIGNED_SHORT = 0x7FFF; + + private static final float MAX_XYZ = 1f + (32767f/32768f); + + // Cached values for scaling color data + private float[] channelMinValues = null; + private float[] channelMulipliers = null; // for scale + private float[] invChannelMulipliers = null; // for unscale + + int nColorChannels = 0; + + // For scaling rasters, false if transfer type is double or float + boolean isTTypeIntegral = false; + + /** + * Loads scaling data for raster. Note, if profile pf is null, + * for non-integral data types multipliers are not initialized. + * @param r - raster + * @param pf - profile which helps to determine the ranges of the color data + */ + public void loadScalingData(Raster r, ICC_Profile pf) { + boolean isSrcTTypeIntegral = + r.getTransferType() != DataBuffer.TYPE_FLOAT && + r.getTransferType() != DataBuffer.TYPE_DOUBLE; + if (isSrcTTypeIntegral) + loadScalingData(r.getSampleModel()); + else if (pf != null) + loadScalingData(pf); + } + + /** + * Use this method only for integral transfer types. + * Extracts min/max values from the sample model + * @param sm - sample model + */ + public void loadScalingData(SampleModel sm) { + // Supposing integral transfer type + isTTypeIntegral = true; + + nColorChannels = sm.getNumBands(); + + channelMinValues = new float[nColorChannels]; + channelMulipliers = new float[nColorChannels]; + invChannelMulipliers = new float[nColorChannels]; + + boolean isSignedShort = + (sm.getTransferType() == DataBuffer.TYPE_SHORT); + + float maxVal; + for (int i=0; i<nColorChannels; i++) { + channelMinValues[i] = 0; + if (isSignedShort) { + channelMulipliers[i] = MAX_SHORT / MAX_SIGNED_SHORT; + invChannelMulipliers[i] = MAX_SIGNED_SHORT / MAX_SHORT; + } else { + maxVal = ((1 << sm.getSampleSize(i)) - 1); + channelMulipliers[i] = MAX_SHORT / maxVal; + invChannelMulipliers[i] = maxVal / MAX_SHORT; + } + } + } + + /** + * Use this method only for double of float transfer types. + * Extracts scaling data from the color space signature + * and other tags, stored in the profile + * @param pf - ICC profile + */ + public void loadScalingData(ICC_Profile pf) { + // Supposing double or float transfer type + isTTypeIntegral = false; + + nColorChannels = pf.getNumComponents(); + + // Get min/max values directly from the profile + // Very much like fillMinMaxValues in ICC_ColorSpace + float maxValues[] = new float[nColorChannels]; + float minValues[] = new float[nColorChannels]; + + switch (pf.getColorSpaceType()) { + case ColorSpace.TYPE_XYZ: + minValues[0] = 0; + minValues[1] = 0; + minValues[2] = 0; + maxValues[0] = MAX_XYZ; + maxValues[1] = MAX_XYZ; + maxValues[2] = MAX_XYZ; + break; + case ColorSpace.TYPE_Lab: + minValues[0] = 0; + minValues[1] = -128; + minValues[2] = -128; + maxValues[0] = 100; + maxValues[1] = 127; + maxValues[2] = 127; + break; + default: + for (int i=0; i<nColorChannels; i++) { + minValues[i] = 0; + maxValues[i] = 1; + } + } + + channelMinValues = minValues; + channelMulipliers = new float[nColorChannels]; + invChannelMulipliers = new float[nColorChannels]; + + for (int i = 0; i < nColorChannels; i++) { + channelMulipliers[i] = + MAX_SHORT / (maxValues[i] - channelMinValues[i]); + + invChannelMulipliers[i] = + (maxValues[i] - channelMinValues[i]) / MAX_SHORT; + } + } + + /** + * Extracts scaling data from the color space + * @param cs - color space + */ + public void loadScalingData(ColorSpace cs) { + nColorChannels = cs.getNumComponents(); + + channelMinValues = new float[nColorChannels]; + channelMulipliers = new float[nColorChannels]; + invChannelMulipliers = new float[nColorChannels]; + + for (int i = 0; i < nColorChannels; i++) { + channelMinValues[i] = cs.getMinValue(i); + + channelMulipliers[i] = + MAX_SHORT / (cs.getMaxValue(i) - channelMinValues[i]); + + invChannelMulipliers[i] = + (cs.getMaxValue(i) - channelMinValues[i]) / MAX_SHORT; + } + } + + /** + * Scales and normalizes the whole raster and returns the result + * in the float array + * @param r - source raster + * @return scaled and normalized raster data + */ + public float[][] scaleNormalize(Raster r) { + int width = r.getWidth(); + int height = r.getHeight(); + float result[][] = new float[width*height][nColorChannels]; + float normMultipliers[] = new float[nColorChannels]; + + int pos = 0; + if (isTTypeIntegral) { + // Change max value from MAX_SHORT to 1f + for (int i=0; i<nColorChannels; i++) { + normMultipliers[i] = channelMulipliers[i] / MAX_SHORT; + } + + int sample; + for (int row=r.getMinX(); row<width; row++) { + for (int col=r.getMinY(); col<height; col++) { + for (int chan = 0; chan < nColorChannels; chan++) { + sample = r.getSample(row, col, chan); + result[pos][chan] = (sample * normMultipliers[chan]); + } + pos++; + } + } + } else { // Just get the samples... + for (int row=r.getMinX(); row<width; row++) { + for (int col=r.getMinY(); col<height; col++) { + for (int chan = 0; chan < nColorChannels; chan++) { + result[pos][chan] = r.getSampleFloat(row, col, chan); + } + pos++; + } + } + } + return result; + } + + /** + * Unscale the whole float array and put the result + * in the raster + * @param r - destination raster + * @param data - input pixels + */ + public void unscaleNormalized(WritableRaster r, float data[][]) { + int width = r.getWidth(); + int height = r.getHeight(); + float normMultipliers[] = new float[nColorChannels]; + + int pos = 0; + if (isTTypeIntegral) { + // Change max value from MAX_SHORT to 1f + for (int i=0; i<nColorChannels; i++) { + normMultipliers[i] = invChannelMulipliers[i] * MAX_SHORT; + } + + int sample; + for (int row=r.getMinX(); row<width; row++) { + for (int col=r.getMinY(); col<height; col++) { + for (int chan = 0; chan < nColorChannels; chan++) { + sample = (int) (data[pos][chan] * normMultipliers[chan] + 0.5f); + r.setSample(row, col, chan, sample); + } + pos++; + } + } + } else { // Just set the samples... + for (int row=r.getMinX(); row<width; row++) { + for (int col=r.getMinY(); col<height; col++) { + for (int chan = 0; chan < nColorChannels; chan++) { + r.setSample(row, col, chan, data[pos][chan]); + } + pos++; + } + } + } + } + + /** + * Scales the whole raster to short and returns the result + * in the array + * @param r - source raster + * @return scaled and normalized raster data + */ + public short[] scale(Raster r) { + int width = r.getWidth(); + int height = r.getHeight(); + short result[] = new short[width*height*nColorChannels]; + + int pos = 0; + if (isTTypeIntegral) { + int sample; + for (int row=r.getMinX(); row<width; row++) { + for (int col=r.getMinY(); col<height; col++) { + for (int chan = 0; chan < nColorChannels; chan++) { + sample = r.getSample(row, col, chan); + result[pos++] = + (short) (sample * channelMulipliers[chan] + 0.5f); + } + } + } + } else { + float sample; + for (int row=r.getMinX(); row<width; row++) { + for (int col=r.getMinY(); col<height; col++) { + for (int chan = 0; chan < nColorChannels; chan++) { + sample = r.getSampleFloat(row, col, chan); + result[pos++] = (short) ((sample - channelMinValues[chan]) + * channelMulipliers[chan] + 0.5f); + } + } + } + } + return result; + } + + /** + * Unscales the whole data array and puts obtained values to the raster + * @param data - input data + * @param wr - destination raster + */ + public void unscale(short[] data, WritableRaster wr) { + int width = wr.getWidth(); + int height = wr.getHeight(); + + int pos = 0; + if (isTTypeIntegral) { + int sample; + for (int row=wr.getMinX(); row<width; row++) { + for (int col=wr.getMinY(); col<height; col++) { + for (int chan = 0; chan < nColorChannels; chan++) { + sample = (int) ((data[pos++] & 0xFFFF) * + invChannelMulipliers[chan] + 0.5f); + wr.setSample(row, col, chan, sample); + } + } + } + } else { + float sample; + for (int row=wr.getMinX(); row<width; row++) { + for (int col=wr.getMinY(); col<height; col++) { + for (int chan = 0; chan < nColorChannels; chan++) { + sample = (data[pos++] & 0xFFFF) * + invChannelMulipliers[chan] + channelMinValues[chan]; + wr.setSample(row, col, chan, sample); + } + } + } + } + } + + /** + * Scales one pixel and puts obtained values to the chanData + * @param pixelData - input pixel + * @param chanData - output buffer + * @param chanDataOffset - output buffer offset + */ + public void scale(float[] pixelData, short[] chanData, int chanDataOffset) { + for (int chan = 0; chan < nColorChannels; chan++) { + chanData[chanDataOffset + chan] = + (short) ((pixelData[chan] - channelMinValues[chan]) * + channelMulipliers[chan] + 0.5f); + } + } + + /** + * Unscales one pixel and puts obtained values to the pixelData + * @param pixelData - output pixel + * @param chanData - input buffer + * @param chanDataOffset - input buffer offset + */ + public void unscale(float[] pixelData, short[] chanData, int chanDataOffset) { + for (int chan = 0; chan < nColorChannels; chan++) { + pixelData[chan] = (chanData[chanDataOffset + chan] & 0xFFFF) + * invChannelMulipliers[chan] + channelMinValues[chan]; + } + } +}
\ No newline at end of file |