summaryrefslogtreecommitdiffstats
path: root/awt/org/apache/harmony/awt/gl/color/ColorScaler.java
diff options
context:
space:
mode:
Diffstat (limited to 'awt/org/apache/harmony/awt/gl/color/ColorScaler.java')
-rw-r--r--awt/org/apache/harmony/awt/gl/color/ColorScaler.java355
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