Imported Upstream version 3.6.0

Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
This commit is contained in:
Jo Shields
2014-08-13 10:39:27 +01:00
commit a575963da9
50588 changed files with 8155799 additions and 0 deletions

View File

@@ -0,0 +1,225 @@
/* Buffers.java --
Copyright (C) 2000, 2002, 2004 Free Software Foundation
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.java.awt;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferDouble;
import java.awt.image.DataBufferFloat;
import java.awt.image.DataBufferInt;
import java.awt.image.DataBufferShort;
import java.awt.image.DataBufferUShort;
/**
* Utility class for creating and accessing data buffers of arbitrary
* data types.
*/
public final class Buffers
{
/**
* Create a data buffer of a particular type.
*
* @param dataType the desired data type of the buffer.
* @param data an array containing data, or null
* @param size the size of the data buffer bank
*/
public static DataBuffer createBuffer(int dataType, Object data,
int size)
{
if (data == null) return createBuffer(dataType, size, 1);
return createBufferFromData(dataType, data, size);
}
/**
* Create a data buffer of a particular type.
*
* @param dataType the desired data type of the buffer.
* @param size the size of the data buffer bank
*/
public static DataBuffer createBuffer(int dataType, int size) {
return createBuffer(dataType, size, 1);
}
/**
* Create a data buffer of a particular type.
*
* @param dataType the desired data type of the buffer.
* @param size the size of the data buffer bank
* @param numBanks the number of banks the buffer should have
*/
public static DataBuffer createBuffer(int dataType, int size, int numBanks)
{
switch (dataType)
{
case DataBuffer.TYPE_BYTE:
return new DataBufferByte(size, numBanks);
case DataBuffer.TYPE_SHORT:
return new DataBufferShort(size, numBanks);
case DataBuffer.TYPE_USHORT:
return new DataBufferUShort(size, numBanks);
case DataBuffer.TYPE_INT:
return new DataBufferInt(size, numBanks);
case DataBuffer.TYPE_FLOAT:
return new DataBufferFloat(size, numBanks);
case DataBuffer.TYPE_DOUBLE:
return new DataBufferDouble(size, numBanks);
default:
throw new UnsupportedOperationException();
}
}
/**
* Create a data buffer of a particular type.
*
* @param dataType the desired data type of the buffer
* @param data an array containing the data
* @param size the size of the data buffer bank
*/
public static DataBuffer createBufferFromData(int dataType, Object data,
int size)
{
switch (dataType)
{
case DataBuffer.TYPE_BYTE:
return new DataBufferByte((byte[]) data, size);
case DataBuffer.TYPE_SHORT:
return new DataBufferShort((short[]) data, size);
case DataBuffer.TYPE_USHORT:
return new DataBufferUShort((short[]) data, size);
case DataBuffer.TYPE_INT:
return new DataBufferInt((int[]) data, size);
case DataBuffer.TYPE_FLOAT:
return new DataBufferFloat((float[]) data, size);
case DataBuffer.TYPE_DOUBLE:
return new DataBufferDouble((double[]) data, size);
default:
throw new UnsupportedOperationException();
}
}
/**
* Return the data array of a data buffer, regardless of the data
* type.
*
* @return an array of primitive values. The actual array type
* depends on the data type of the buffer.
*/
public static Object getData(DataBuffer buffer)
{
return getData(buffer, 0, null, 0, buffer.getSize());
}
/**
* Copy data from array contained in data buffer, much like
* System.arraycopy. Create a suitable destination array if the
* given destination array is null.
*/
public static Object getData(DataBuffer src, int srcOffset,
Object dest, int dstOffset,
int length)
{
Object from;
switch(src.getDataType())
{
case DataBuffer.TYPE_BYTE:
if (dest == null) dest = new byte[length+dstOffset];
for(int i = 0; i < length; i++)
((byte[])dest)[i + dstOffset] = (byte)src.getElem(i + srcOffset);
break;
case DataBuffer.TYPE_DOUBLE:
if (dest == null) dest = new double[length+dstOffset];
for(int i = 0; i < length; i++)
((double[])dest)[i + dstOffset] = src.getElemDouble(i + srcOffset);
break;
case DataBuffer.TYPE_FLOAT:
if (dest == null) dest = new float[length+dstOffset];
for(int i = 0; i < length; i++)
((float[])dest)[i + dstOffset] = src.getElemFloat(i + srcOffset);
break;
case DataBuffer.TYPE_INT:
if (dest == null) dest = new int[length+dstOffset];
for(int i = 0; i < length; i++)
((int[])dest)[i + dstOffset] = src.getElem(i + srcOffset);
break;
case DataBuffer.TYPE_SHORT:
case DataBuffer.TYPE_USHORT:
if (dest == null) dest = new short[length+dstOffset];
for(int i = 0; i < length; i++)
((short[])dest)[i + dstOffset] = (short)src.getElem(i + srcOffset);
break;
case DataBuffer.TYPE_UNDEFINED:
throw new ClassCastException("Unknown data buffer type");
}
return dest;
}
/**
* @param bits the width of a data element measured in bits
*
* @return the smallest data type that can store data elements of
* the given number of bits, without any truncation.
*/
public static int smallestAppropriateTransferType(int bits)
{
if (bits <= 8)
{
return DataBuffer.TYPE_BYTE;
}
else if (bits <= 16)
{
return DataBuffer.TYPE_USHORT;
}
else if (bits <= 32)
{
return DataBuffer.TYPE_INT;
}
else
{
return DataBuffer.TYPE_UNDEFINED;
}
}
}

View File

@@ -0,0 +1,73 @@
/* CieXyzConverter.java -- CieXyz conversion class
Copyright (C) 2004 Free Software Foundation
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.java.awt.color;
/**
* CieXyzConverter - converts to/from a D50-relative CIE XYZ color space.
*
* The sRGB<->CIE XYZ conversions in SrgbConverter are used.
*
* @author Sven de Marothy
*/
public class CieXyzConverter implements ColorSpaceConverter
{
public float[] toCIEXYZ(float[] in)
{
float[] out = new float[3];
System.arraycopy(in, 0, out, 0, 3);
return out;
}
public float[] fromCIEXYZ(float[] in)
{
float[] out = new float[3];
System.arraycopy(in, 0, out, 0, 3);
return out;
}
public float[] toRGB(float[] in)
{
return SrgbConverter.XYZtoRGB(in);
}
public float[] fromRGB(float[] in)
{
return SrgbConverter.RGBtoXYZ(in);
}
}

View File

@@ -0,0 +1,152 @@
/* ClutProfileConverter.java -- Conversion routines for CLUT-Based profiles
Copyright (C) 2004 Free Software Foundation
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.java.awt.color;
import java.awt.color.ICC_Profile;
/**
* ClutProfileConverter - conversions through a CLUT-based profile
*
* @author Sven de Marothy
*/
public class ClutProfileConverter implements ColorSpaceConverter
{
private ColorLookUpTable toPCS;
private ColorLookUpTable fromPCS;
private int nChannels;
public ClutProfileConverter(ICC_Profile profile)
{
nChannels = profile.getNumComponents();
// Sun does not specifiy which rendering intent should be used,
// neither does the ICC v2 spec really.
// Try intent 0
try
{
toPCS = new ColorLookUpTable(profile, ICC_Profile.icSigAToB0Tag);
}
catch (Exception e)
{
toPCS = null;
}
try
{
fromPCS = new ColorLookUpTable(profile, ICC_Profile.icSigBToA0Tag);
}
catch (Exception e)
{
fromPCS = null;
}
if (toPCS != null || fromPCS != null)
return;
// If no intent 0 clut is available, look for a intent 1 clut.
try
{
toPCS = new ColorLookUpTable(profile, ICC_Profile.icSigAToB1Tag);
}
catch (Exception e)
{
toPCS = null;
}
try
{
fromPCS = new ColorLookUpTable(profile, ICC_Profile.icSigBToA1Tag);
}
catch (Exception e)
{
fromPCS = null;
}
if (toPCS != null || fromPCS != null)
return;
// Last shot.. intent 2 CLUT.
try
{
toPCS = new ColorLookUpTable(profile, ICC_Profile.icSigAToB2Tag);
}
catch (Exception e)
{
toPCS = null;
}
try
{
fromPCS = new ColorLookUpTable(profile, ICC_Profile.icSigBToA2Tag);
}
catch (Exception e)
{
fromPCS = null;
}
if (toPCS == null && fromPCS == null)
throw new IllegalArgumentException("No CLUTs in profile!");
}
public float[] toCIEXYZ(float[] in)
{
if (toPCS != null)
return toPCS.lookup(in);
else
return new float[3];
}
public float[] toRGB(float[] in)
{
return SrgbConverter.XYZtoRGB(toCIEXYZ(in));
}
public float[] fromCIEXYZ(float[] in)
{
if (fromPCS != null)
return fromPCS.lookup(in);
else
return new float[nChannels];
}
public float[] fromRGB(float[] in)
{
return fromCIEXYZ(SrgbConverter.RGBtoXYZ(in));
}
}

View File

@@ -0,0 +1,429 @@
/* ColorLookUpTable.java -- ICC v2 CLUT
Copyright (C) 2004 Free Software Foundation
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.java.awt.color;
import java.awt.color.ColorSpace;
import java.awt.color.ICC_Profile;
import java.nio.ByteBuffer;
/**
* ColorLookUpTable handles color lookups through a color lookup table,
* as defined in the ICC specification.
* Both 'mft2' and 'mft1' (8 and 16-bit) type CLUTs are handled.
*
* This will have to be updated later for ICC 4.0.0
*
* @author Sven de Marothy
*/
public class ColorLookUpTable
{
/**
* CIE 1931 D50 white point (in Lab coordinates)
*/
private static float[] D50 = { 0.96422f, 1.00f, 0.82521f };
/**
* Number of input/output channels
*/
int nIn;
/**
* Number of input/output channels
*/
int nOut;
int nInTableEntries; // Number of input table entries
int nOutTableEntries; // Number of output table entries
int gridpoints; // Number of gridpoints
int nClut; // This is nOut*(gridpoints**nIn)
double[][] inTable; // 1D input table ([channel][table])
short[][] outTable; // 1D input table ([channel][table])
double[] clut; // The color lookup table
float[][] inMatrix; // input matrix (XYZ only)
boolean useMatrix; // Whether to use the matrix or not.
int[] multiplier;
int[] offsets; // Hypercube offsets
boolean inputLab; // Set if the CLUT input CS is Lab
boolean outputLab; // Set if the CLUT output CS is Lab
/**
* Constructor
* Requires a profile file to get the CLUT from and the tag of the
* CLUT to create. (icSigXToYZTag where X,Y = [A | B], Z = [0,1,2])
*/
public ColorLookUpTable(ICC_Profile profile, int tag)
{
useMatrix = false;
switch (tag)
{
case ICC_Profile.icSigAToB0Tag:
case ICC_Profile.icSigAToB1Tag:
case ICC_Profile.icSigAToB2Tag:
if (profile.getColorSpaceType() == ColorSpace.TYPE_XYZ)
useMatrix = true;
inputLab = false;
outputLab = (profile.getPCSType() == ColorSpace.TYPE_Lab);
break;
case ICC_Profile.icSigBToA0Tag:
case ICC_Profile.icSigBToA1Tag:
case ICC_Profile.icSigBToA2Tag:
if (profile.getPCSType() == ColorSpace.TYPE_XYZ)
useMatrix = true;
inputLab = (profile.getPCSType() == ColorSpace.TYPE_Lab);
outputLab = false;
break;
default:
throw new IllegalArgumentException("Not a clut-type tag.");
}
byte[] data = profile.getData(tag);
if (data == null)
throw new IllegalArgumentException("Unsuitable profile, does not contain a CLUT.");
// check 'mft'
if (data[0] != 0x6d || data[1] != 0x66 || data[2] != 0x74)
throw new IllegalArgumentException("Unsuitable profile, invalid CLUT data.");
if (data[3] == 0x32)
readClut16(data);
else if (data[3] == 0x31)
readClut8(data);
else
throw new IllegalArgumentException("Unknown/invalid CLUT type.");
}
/**
* Loads a 16-bit CLUT into our data structures
*/
private void readClut16(byte[] data)
{
ByteBuffer buf = ByteBuffer.wrap(data);
nIn = data[8] & (0xFF);
nOut = data[9] & (0xFF);
nInTableEntries = buf.getShort(48);
nOutTableEntries = buf.getShort(50);
gridpoints = data[10] & (0xFF);
inMatrix = new float[3][3];
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
inMatrix[i][j] = ((float) (buf.getInt(12 + (i * 3 + j) * 4))) / 65536.0f;
inTable = new double[nIn][nInTableEntries];
for (int channel = 0; channel < nIn; channel++)
for (int i = 0; i < nInTableEntries; i++)
inTable[channel][i] = (double) ((int) buf.getShort(52
+ (channel * nInTableEntries
+ i) * 2)
& (0xFFFF)) / 65536.0;
nClut = nOut;
multiplier = new int[nIn];
multiplier[nIn - 1] = nOut;
for (int i = 0; i < nIn; i++)
{
nClut *= gridpoints;
if (i > 0)
multiplier[nIn - i - 1] = multiplier[nIn - i] * gridpoints;
}
int clutOffset = 52 + nIn * nInTableEntries * 2;
clut = new double[nClut];
for (int i = 0; i < nClut; i++)
clut[i] = (double) ((int) buf.getShort(clutOffset + i * 2) & (0xFFFF)) / 65536.0;
outTable = new short[nOut][nOutTableEntries];
for (int channel = 0; channel < nOut; channel++)
for (int i = 0; i < nOutTableEntries; i++)
outTable[channel][i] = buf.getShort(clutOffset
+ (nClut
+ channel * nOutTableEntries + i) * 2);
// calculate the hypercube corner offsets
offsets = new int[(1 << nIn)];
offsets[0] = 0;
for (int j = 0; j < nIn; j++)
{
int factor = 1 << j;
for (int i = 0; i < factor; i++)
offsets[factor + i] = offsets[i] + multiplier[j];
}
}
/**
* Loads a 8-bit CLUT into our data structures.
*/
private void readClut8(byte[] data)
{
ByteBuffer buf = ByteBuffer.wrap(data);
nIn = (data[8] & (0xFF));
nOut = (data[9] & (0xFF));
nInTableEntries = 256; // always 256
nOutTableEntries = 256; // always 256
gridpoints = (data[10] & (0xFF));
inMatrix = new float[3][3];
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
inMatrix[i][j] = ((float) (buf.getInt(12 + (i * 3 + j) * 4))) / 65536.0f;
inTable = new double[nIn][nInTableEntries];
for (int channel = 0; channel < nIn; channel++)
for (int i = 0; i < nInTableEntries; i++)
inTable[channel][i] = (double) ((int) buf.get(48
+ (channel * nInTableEntries
+ i)) & (0xFF)) / 255.0;
nClut = nOut;
multiplier = new int[nIn];
multiplier[nIn - 1] = nOut;
for (int i = 0; i < nIn; i++)
{
nClut *= gridpoints;
if (i > 0)
multiplier[nIn - i - 1] = multiplier[nIn - i] * gridpoints;
}
int clutOffset = 48 + nIn * nInTableEntries;
clut = new double[nClut];
for (int i = 0; i < nClut; i++)
clut[i] = (double) ((int) buf.get(clutOffset + i) & (0xFF)) / 255.0;
outTable = new short[nOut][nOutTableEntries];
for (int channel = 0; channel < nOut; channel++)
for (int i = 0; i < nOutTableEntries; i++)
outTable[channel][i] = (short) (buf.get(clutOffset + nClut
+ channel * nOutTableEntries
+ i) * 257);
// calculate the hypercube corner offsets
offsets = new int[(1 << nIn)];
offsets[0] = 0;
for (int j = 0; j < nIn; j++)
{
int factor = 1 << j;
for (int i = 0; i < factor; i++)
offsets[factor + i] = offsets[i] + multiplier[j];
}
}
/**
* Performs a lookup through the Color LookUp Table.
* If the CLUT tag type is AtoB the conversion will be from the device
* color space to the PCS, BtoA type goes in the opposite direction.
*
* For convenience, the PCS values for input or output will always be
* CIE XYZ (D50), if the actual PCS is Lab, the values will be converted.
*
* N-dimensional linear interpolation is used.
*/
float[] lookup(float[] in)
{
float[] in2 = new float[in.length];
if (useMatrix)
{
for (int i = 0; i < 3; i++)
in2[i] = in[0] * inMatrix[i][0] + in[1] * inMatrix[i][1]
+ in[2] * inMatrix[i][2];
}
else if (inputLab)
in2 = XYZtoLab(in);
else
System.arraycopy(in, 0, in2, 0, in.length);
// input table
for (int i = 0; i < nIn; i++)
{
int index = (int) Math.floor(in2[i] * (double) (nInTableEntries - 1)); // floor in
// clip values.
if (index >= nInTableEntries - 1)
in2[i] = (float) inTable[i][nInTableEntries - 1];
else if (index < 0)
in2[i] = (float) inTable[i][0];
else
{
// linear interpolation
double alpha = in2[i] * ((double) nInTableEntries - 1.0) - index;
in2[i] = (float) (inTable[i][index] * (1 - alpha)
+ inTable[i][index + 1] * alpha);
}
}
// CLUT lookup
double[] output2 = new double[nOut];
double[] weights = new double[(1 << nIn)];
double[] clutalpha = new double[nIn]; // interpolation values
int offset = 0; // = gp
for (int i = 0; i < nIn; i++)
{
int index = (int) Math.floor(in2[i] * ((double) gridpoints - 1.0));
double alpha = in2[i] * ((double) gridpoints - 1.0) - (double) index;
// clip values.
if (index >= gridpoints - 1)
{
index = gridpoints - 1;
alpha = 1.0;
}
else if (index < 0)
index = 0;
clutalpha[i] = alpha;
offset += index * multiplier[i];
}
// Calculate interpolation weights
weights[0] = 1.0;
for (int j = 0; j < nIn; j++)
{
int factor = 1 << j;
for (int i = 0; i < factor; i++)
{
weights[factor + i] = weights[i] * clutalpha[j];
weights[i] *= (1.0 - clutalpha[j]);
}
}
for (int i = 0; i < nOut; i++)
output2[i] = weights[0] * clut[offset + i];
for (int i = 1; i < (1 << nIn); i++)
{
int offset2 = offset + offsets[i];
for (int f = 0; f < nOut; f++)
output2[f] += weights[i] * clut[offset2 + f];
}
// output table
float[] output = new float[nOut];
for (int i = 0; i < nOut; i++)
{
int index = (int) Math.floor(output2[i] * ((double) nOutTableEntries
- 1.0));
// clip values.
if (index >= nOutTableEntries - 1)
output[i] = outTable[i][nOutTableEntries - 1];
else if (index < 0)
output[i] = outTable[i][0];
else
{
// linear interpolation
double a = output2[i] * ((double) nOutTableEntries - 1.0)
- (double) index;
output[i] = (float) ((double) ((int) outTable[i][index] & (0xFFFF)) * (1
- a)
+ (double) ((int) outTable[i][index + 1] & (0xFFFF)) * a) / 65536f;
}
}
if (outputLab)
return LabtoXYZ(output);
return output;
}
/**
* Converts CIE Lab coordinates to (D50) XYZ ones.
*/
private float[] LabtoXYZ(float[] in)
{
// Convert from byte-packed format to a
// more convenient one (actual Lab values)
// (See ICC spec for details)
// factor is 100 * 65536 / 65280
in[0] = (float) (100.392156862745 * in[0]);
in[1] = (in[1] * 256.0f) - 128.0f;
in[2] = (in[2] * 256.0f) - 128.0f;
float[] out = new float[3];
out[1] = (in[0] + 16.0f) / 116.0f;
out[0] = in[1] / 500.0f + out[1];
out[2] = out[1] - in[2] / 200.0f;
for (int i = 0; i < 3; i++)
{
double exp = out[i] * out[i] * out[i];
if (exp <= 0.008856)
out[i] = (out[i] - 16.0f / 116.0f) / 7.787f;
else
out[i] = (float) exp;
out[i] = D50[i] * out[i];
}
return out;
}
/**
* Converts CIE XYZ coordinates to Lab ones.
*/
private float[] XYZtoLab(float[] in)
{
float[] temp = new float[3];
for (int i = 0; i < 3; i++)
{
temp[i] = in[i] / D50[i];
if (temp[i] <= 0.008856f)
temp[i] = (7.7870689f * temp[i]) + (16f / 116.0f);
else
temp[i] = (float) Math.exp((1.0 / 3.0) * Math.log(temp[i]));
}
float[] out = new float[3];
out[0] = (116.0f * temp[1]) - 16f;
out[1] = 500.0f * (temp[0] - temp[1]);
out[2] = 200.0f * (temp[1] - temp[2]);
// Normalize to packed format
out[0] = (float) (out[0] / 100.392156862745);
out[1] = (out[1] + 128f) / 256f;
out[2] = (out[2] + 128f) / 256f;
for (int i = 0; i < 3; i++)
{
if (out[i] < 0f)
out[i] = 0f;
if (out[i] > 1f)
out[i] = 1f;
}
return out;
}
}

View File

@@ -0,0 +1,69 @@
/* ColorSpaceConverter.java -- an interface for colorspace conversion
Copyright (C) 2004 Free Software Foundation
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.java.awt.color;
/**
* ColorSpaceConverter - used by java.awt.color.ICC_ColorSpace
*
* Color space conversion can occur in several ways:
*
* -Directly (for the built in spaces sRGB, linear RGB, gray, CIE XYZ and PYCC
* -ICC_ProfileRGB works through TRC curves and a matrix
* -ICC_ProfileGray works through a single TRC
* -Everything else is done through Color lookup tables.
*
* The different conversion methods are implemented through
* an interface. The built-in colorspaces are implemented directly
* with the relevant conversion equations.
*
* In this way, we hopefully will always use the fastest and most
* accurate method available.
*
* @author Sven de Marothy
*/
public interface ColorSpaceConverter
{
float[] toCIEXYZ(float[] in);
float[] fromCIEXYZ(float[] in);
float[] toRGB(float[] in);
float[] fromRGB(float[] in);
}

View File

@@ -0,0 +1,137 @@
/* GrayProfileConverter.java -- Gray profile conversion class
Copyright (C) 2004 Free Software Foundation
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.java.awt.color;
import java.awt.color.ICC_Profile;
import java.awt.color.ICC_ProfileGray;
import java.awt.color.ProfileDataException;
/**
* GrayProfileConverter - converts Grayscale profiles (ICC_ProfileGray)
*
* This type of profile contains a single tone reproduction curve (TRC).
* Conversion consists of simple TRC lookup.
*
* This implementation is very lazy and does everything applying the TRC and
* utilizing the built-in linear grayscale color space.
*
* @author Sven de Marothy
*/
public class GrayProfileConverter implements ColorSpaceConverter
{
private GrayScaleConverter gc;
private ToneReproductionCurve trc;
private ColorLookUpTable toPCS;
private ColorLookUpTable fromPCS;
/**
* Constructs the converter described by an ICC_ProfileGray object
*/
public GrayProfileConverter(ICC_ProfileGray profile)
{
try
{
trc = new ToneReproductionCurve(profile.getGamma());
}
catch (ProfileDataException e)
{
trc = new ToneReproductionCurve(profile.getTRC());
}
// linear grayscale converter
gc = new GrayScaleConverter();
// If a CLUT is available, it should be used, and the TRCs ignored.
// Note: A valid profile may only have CLUTs in one direction, and
// TRC:s without useful info, making reverse-transforms impossible.
// In this case the TRC will be used for the reverse-transform with
// unpredictable results. This is in line with the Java specification,
try
{
toPCS = new ColorLookUpTable(profile, ICC_Profile.icSigAToB0Tag);
}
catch (Exception e)
{
toPCS = null;
}
try
{
fromPCS = new ColorLookUpTable(profile, ICC_Profile.icSigBToA0Tag);
}
catch (Exception e)
{
fromPCS = null;
}
}
public float[] toCIEXYZ(float[] in)
{
if (toPCS != null)
return toPCS.lookup(in);
float[] gray = new float[1];
gray[0] = trc.lookup(in[0]);
return gc.toCIEXYZ(gray);
}
public float[] toRGB(float[] in)
{
float[] gray = new float[1];
gray[0] = trc.lookup(in[0]);
return gc.toRGB(gray);
}
public float[] fromRGB(float[] in)
{
// get linear grayscale value
float[] gray = gc.fromRGB(in);
gray[0] = trc.reverseLookup(gray[0]);
return gray;
}
public float[] fromCIEXYZ(float[] in)
{
if (fromPCS != null)
return fromPCS.lookup(in);
float[] gray = gc.fromCIEXYZ(in);
gray[0] = trc.reverseLookup(gray[0]);
return gray;
}
}

View File

@@ -0,0 +1,110 @@
/* GrayScaleConverter.java -- Linear grayscale conversion class
Copyright (C) 2004 Free Software Foundation
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.java.awt.color;
/**
* Linear Grayscale converter
*
* @author Sven de Marothy
*/
public class GrayScaleConverter implements ColorSpaceConverter
{
// intensity factors (ITU Rec. BT.709)
double[] coeff = { 0.2125f, 0.7154f, 0.0721f };
/**
* CIE 1931 D50 white point (in Lab coordinates)
*/
private static float[] D50 = { 0.96422f, 1.00f, 0.82521f };
public float[] toCIEXYZ(float[] in)
{
float g = in[0];
if (g < 0)
g = 1 + g;
float[] out = { g * D50[0], g * D50[1], g * D50[2] }; // White spot
return out;
}
public float[] toRGB(float[] in)
{
float[] out = new float[3];
if (in[0] <= 0.00304f)
out[0] = in[0] * 12.92f;
else
out[0] = 1.055f * ((float) Math.exp((1 / 2.4) * Math.log(in[0])))
- 0.055f;
out[1] = out[2] = out[0];
return out;
}
public float[] fromCIEXYZ(float[] in)
{
float[] temp = new float[3];
temp[0] = 3.1338f * in[0] - 1.6171f * in[1] - 0.4907f * in[2];
temp[1] = -0.9785f * in[0] + 1.9160f * in[1] + 0.0334f * in[2];
temp[2] = 0.0720f * in[0] - 0.2290f * in[1] + 1.4056f * in[2];
float[] out = new float[1];
for (int i = 0; i < 3; i++)
out[0] += (float) (temp[i] * coeff[i]);
return out;
}
public float[] fromRGB(float[] in)
{
float[] out = new float[1];
// Convert non-linear RGB coordinates to linear ones,
// numbers from the w3 spec.
out[0] = 0;
for (int i = 0; i < 3; i++)
{
float n = in[i];
if (n < 0)
n = 0f;
if (n > 1)
n = 1f;
if (n <= 0.03928f)
out[0] += (float) (coeff[i] * n / 12.92);
else
out[0] += (float) (coeff[i] * Math.exp(2.4 * Math.log((n + 0.055) / 1.055)));
}
return out;
}
}

View File

@@ -0,0 +1,398 @@
/* ProfileHeader.java -- Encapsules ICC Profile header data
Copyright (C) 2004 Free Software Foundation
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.java.awt.color;
import java.awt.color.ColorSpace;
import java.awt.color.ICC_Profile;
import java.nio.ByteBuffer;
/**
* Header, abstracts and validates the header data.
*
* @author Sven de Marothy
*/
public class ProfileHeader
{
/**
* Magic identifier (ASCII 'acsp')
*/
private static final int icMagicNumber = 0x61637370;
/**
* Mapping from ICC Profile signatures to ColorSpace types
*/
private static final int[] csTypeMap =
{
ICC_Profile.icSigXYZData,
ColorSpace.TYPE_XYZ,
ICC_Profile.icSigLabData,
ColorSpace.TYPE_Lab,
ICC_Profile.icSigLuvData,
ColorSpace.TYPE_Luv,
ICC_Profile.icSigYCbCrData,
ColorSpace.TYPE_YCbCr,
ICC_Profile.icSigYxyData,
ColorSpace.TYPE_Yxy,
ICC_Profile.icSigRgbData,
ColorSpace.TYPE_RGB,
ICC_Profile.icSigGrayData,
ColorSpace.TYPE_GRAY,
ICC_Profile.icSigHsvData,
ColorSpace.TYPE_HSV,
ICC_Profile.icSigHlsData,
ColorSpace.TYPE_HLS,
ICC_Profile.icSigCmykData,
ColorSpace.TYPE_CMYK,
ICC_Profile.icSigCmyData,
ColorSpace.TYPE_CMY,
ICC_Profile.icSigSpace2CLR,
ColorSpace.TYPE_2CLR,
ICC_Profile.icSigSpace3CLR,
ColorSpace.TYPE_3CLR,
ICC_Profile.icSigSpace4CLR,
ColorSpace.TYPE_4CLR,
ICC_Profile.icSigSpace5CLR,
ColorSpace.TYPE_5CLR,
ICC_Profile.icSigSpace6CLR,
ColorSpace.TYPE_6CLR,
ICC_Profile.icSigSpace7CLR,
ColorSpace.TYPE_7CLR,
ICC_Profile.icSigSpace8CLR,
ColorSpace.TYPE_8CLR,
ICC_Profile.icSigSpace9CLR,
ColorSpace.TYPE_9CLR,
ICC_Profile.icSigSpaceACLR,
ColorSpace.TYPE_ACLR,
ICC_Profile.icSigSpaceBCLR,
ColorSpace.TYPE_BCLR,
ICC_Profile.icSigSpaceCCLR,
ColorSpace.TYPE_CCLR,
ICC_Profile.icSigSpaceDCLR,
ColorSpace.TYPE_DCLR,
ICC_Profile.icSigSpaceECLR,
ColorSpace.TYPE_ECLR,
ICC_Profile.icSigSpaceFCLR,
ColorSpace.TYPE_FCLR
};
/**
* Size of an ICC header (128 bytes)
*/
public static final int HEADERSIZE = 128;
/**
* Mapping of ICC class signatures to profile class constants
*/
private static final int[] classMap =
{
ICC_Profile.icSigInputClass,
ICC_Profile.CLASS_INPUT,
ICC_Profile.icSigDisplayClass,
ICC_Profile.CLASS_DISPLAY,
ICC_Profile.icSigOutputClass,
ICC_Profile.CLASS_OUTPUT,
ICC_Profile.icSigLinkClass,
ICC_Profile.CLASS_DEVICELINK,
ICC_Profile.icSigColorSpaceClass,
ICC_Profile.CLASS_COLORSPACECONVERSION,
ICC_Profile.icSigAbstractClass,
ICC_Profile.CLASS_ABSTRACT,
ICC_Profile.icSigNamedColorClass,
ICC_Profile.CLASS_NAMEDCOLOR
};
private int size;
private int cmmId;
// Major/Minor version, The ICC-1998 spec is major v2
private int majorVersion;
// Major/Minor version, The ICC-1998 spec is major v2
private int minorVersion;
private int profileClass; // profile device class
private int colorSpace; // data color space type
private int profileColorSpace; // profile connection space (PCS) type
private byte[] timestamp; // original creation timestamp
private int platform; // platform signature
private int flags; // flags
private int magic; // magic number.
private int manufacturerSig; // manufacturer sig
private int modelSig; // model sig
private byte[] attributes; // Attributes
private int intent; // rendering intent
private byte[] illuminant; // illuminant info (Coordinates of D50 in the PCS)
private int creatorSig; // Creator sig (same type as manufacturer)
/**
* Creates a 'default' header for use with our predefined profiles.
* Note the device and profile color spaces are not set.
*/
public ProfileHeader()
{
creatorSig = 0;
intent = 0;
modelSig = manufacturerSig = (int) 0x6E6f6E65; // 'none'
magic = icMagicNumber;
cmmId = 0;
platform = 0; // no preferred platform
timestamp = new byte[8];
majorVersion = 2;
minorVersion = 0x10;
flags = 0;
// D50 in XYZ format (encoded)
illuminant = new byte[]
{
(byte) 0x00, (byte) 0x00, (byte) 0xf6, (byte) 0xd6,
(byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0xd3, (byte) 0x2d
};
attributes = new byte[8];
profileClass = ICC_Profile.CLASS_DISPLAY;
}
/**
* Creates a header from profile data. Only the header portion (128 bytes)
* is read, so the array passed need not be the full profile.
*/
public ProfileHeader(byte[] data)
{
ByteBuffer buf = ByteBuffer.wrap(data);
// Get size (the sign bit shouldn't matter.
// A valid profile can never be +2Gb)
size = buf.getInt(ICC_Profile.icHdrSize);
// CMM ID
cmmId = buf.getInt(ICC_Profile.icHdrCmmId);
// Version number
majorVersion = (int) (data[ICC_Profile.icHdrVersion]);
minorVersion = (int) (data[ICC_Profile.icHdrVersion + 1]);
// Profile/Device class
int classSig = buf.getInt(ICC_Profile.icHdrDeviceClass);
profileClass = -1;
for (int i = 0; i < classMap.length; i += 2)
if (classMap[i] == classSig)
{
profileClass = classMap[i + 1];
break;
}
// get the data color space
int csSig = buf.getInt(ICC_Profile.icHdrColorSpace);
colorSpace = -1;
for (int i = 0; i < csTypeMap.length; i += 2)
if (csTypeMap[i] == csSig)
{
colorSpace = csTypeMap[i + 1];
break;
}
// get the profile color space (PCS), must be xyz or lab except
// for device-link-class profiles
int pcsSig = buf.getInt(ICC_Profile.icHdrPcs);
profileColorSpace = -1;
if (profileClass != ICC_Profile.CLASS_DEVICELINK)
{
if (pcsSig == ICC_Profile.icSigXYZData)
profileColorSpace = ColorSpace.TYPE_XYZ;
if (pcsSig == ICC_Profile.icSigLabData)
profileColorSpace = ColorSpace.TYPE_Lab;
}
else
{
for (int i = 0; i < csTypeMap.length; i += 2)
if (csTypeMap[i] == pcsSig)
{
profileColorSpace = csTypeMap[i + 1];
break;
}
}
// creation timestamp
timestamp = new byte[8];
System.arraycopy(data, ICC_Profile.icHdrDate, timestamp, 0, 8);
// magic number
magic = buf.getInt(ICC_Profile.icHdrMagic);
// platform info
platform = buf.getInt(ICC_Profile.icHdrPlatform);
// get flags
flags = buf.getInt(ICC_Profile.icHdrFlags);
// get manufacturer sign
manufacturerSig = buf.getInt(ICC_Profile.icHdrManufacturer);
// get header model
modelSig = buf.getInt(ICC_Profile.icHdrModel);
// attributes
attributes = new byte[8];
System.arraycopy(data, ICC_Profile.icHdrAttributes, attributes, 0, 8);
// rendering intent
intent = buf.getInt(ICC_Profile.icHdrRenderingIntent);
// illuminant info
illuminant = new byte[12];
System.arraycopy(data, ICC_Profile.icHdrIlluminant, illuminant, 0, 12);
// Creator signature
creatorSig = buf.getInt(ICC_Profile.icHdrCreator);
// The rest of the header (Total size: 128 bytes) is unused..
}
/**
* Verify that the header is valid
* @param size equals the file size if it is to be verified, -1 otherwise
* @throws IllegalArgumentException if the header is found to be invalid.
*/
public void verifyHeader(int size) throws IllegalArgumentException
{
// verify size
if (size != -1 && this.size != size)
throw new IllegalArgumentException("Invalid profile length:" + size);
// Check version number
if (majorVersion != 2)
throw new IllegalArgumentException("Wrong major version number:"
+ majorVersion);
// Profile/Device class
if (profileClass == -1)
throw new IllegalArgumentException("Invalid profile/device class");
// get the data color space
if (colorSpace == -1)
throw new IllegalArgumentException("Invalid colorspace");
// profile color space
if (profileColorSpace == -1)
throw new IllegalArgumentException("Invalid PCS.");
// check magic number
if (magic != icMagicNumber)
throw new IllegalArgumentException("Invalid magic number!");
}
/**
* Creates a header, setting the header file size at the same time.
* @param size the profile file size.
*/
public byte[] getData(int size)
{
byte[] data = new byte[HEADERSIZE];
ByteBuffer buf = ByteBuffer.wrap(data);
buf.putInt(ICC_Profile.icHdrSize, size);
buf.putInt(ICC_Profile.icHdrCmmId, cmmId);
buf.putShort(ICC_Profile.icHdrVersion,
(short) (majorVersion << 8 | minorVersion));
for (int i = 1; i < classMap.length; i += 2)
if (profileClass == classMap[i])
buf.putInt(ICC_Profile.icHdrDeviceClass, classMap[i - 1]);
for (int i = 1; i < csTypeMap.length; i += 2)
if (csTypeMap[i] == colorSpace)
buf.putInt(ICC_Profile.icHdrColorSpace, csTypeMap[i - 1]);
for (int i = 1; i < csTypeMap.length; i += 2)
if (csTypeMap[i] == profileColorSpace)
buf.putInt(ICC_Profile.icHdrPcs, csTypeMap[i - 1]);
System.arraycopy(timestamp, 0, data, ICC_Profile.icHdrDate,
timestamp.length);
buf.putInt(ICC_Profile.icHdrMagic, icMagicNumber);
buf.putInt(ICC_Profile.icHdrPlatform, platform);
buf.putInt(ICC_Profile.icHdrFlags, flags);
buf.putInt(ICC_Profile.icHdrManufacturer, manufacturerSig);
buf.putInt(ICC_Profile.icHdrModel, modelSig);
System.arraycopy(attributes, 0, data, ICC_Profile.icHdrAttributes,
attributes.length);
buf.putInt(ICC_Profile.icHdrRenderingIntent, intent);
System.arraycopy(illuminant, 0, data, ICC_Profile.icHdrIlluminant,
illuminant.length);
buf.putInt(ICC_Profile.icHdrCreator, creatorSig);
return buf.array();
}
public int getSize()
{
return size;
}
public void setSize(int s)
{
size = s;
}
public int getMajorVersion()
{
return majorVersion;
}
public int getMinorVersion()
{
return minorVersion;
}
public int getProfileClass()
{
return profileClass;
}
public void setProfileClass(int pc)
{
profileClass = pc;
}
public int getColorSpace()
{
return colorSpace;
}
public int getProfileColorSpace()
{
return profileColorSpace;
}
public void setColorSpace(int cs)
{
colorSpace = cs;
}
public void setProfileColorSpace(int pcs)
{
profileColorSpace = pcs;
}
}

View File

@@ -0,0 +1,244 @@
/* RgbProfileConverter.java -- RGB Profile conversion class
Copyright (C) 2004 Free Software Foundation
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.java.awt.color;
import java.awt.color.ICC_Profile;
import java.awt.color.ICC_ProfileRGB;
import java.awt.color.ProfileDataException;
/**
* RgbProfileConverter - converts RGB profiles (ICC_ProfileRGB)
*
* This type of profile contains a matrix and three
* tone reproduction curves (TRCs).
*
* Device RGB --&gt; CIE XYZ is done through first multiplying with
* a matrix, then each component is looked-up against it's TRC.
*
* The opposite transform is done using the inverse of the matrix,
* and TRC:s.
*
* @author Sven de Marothy
*/
public class RgbProfileConverter implements ColorSpaceConverter
{
private float[][] matrix;
private float[][] inv_matrix;
private ToneReproductionCurve rTRC;
private ToneReproductionCurve gTRC;
private ToneReproductionCurve bTRC;
private ColorLookUpTable toPCS;
private ColorLookUpTable fromPCS;
/**
* CIE 1931 D50 white point (in Lab coordinates)
*/
private static float[] D50 = { 0.96422f, 1.00f, 0.82521f };
/**
* Constructs an RgbProfileConverter from a given ICC_ProfileRGB
*/
public RgbProfileConverter(ICC_ProfileRGB profile)
{
toPCS = fromPCS = null;
matrix = profile.getMatrix();
// get TRCs
try
{
rTRC = new ToneReproductionCurve(profile.getGamma(ICC_ProfileRGB.REDCOMPONENT));
}
catch (ProfileDataException e)
{
rTRC = new ToneReproductionCurve(profile.getTRC(ICC_ProfileRGB.REDCOMPONENT));
}
try
{
gTRC = new ToneReproductionCurve(profile.getGamma(ICC_ProfileRGB.GREENCOMPONENT));
}
catch (ProfileDataException e)
{
gTRC = new ToneReproductionCurve(profile.getTRC(ICC_ProfileRGB.GREENCOMPONENT));
}
try
{
bTRC = new ToneReproductionCurve(profile.getGamma(ICC_ProfileRGB.BLUECOMPONENT));
}
catch (ProfileDataException e)
{
bTRC = new ToneReproductionCurve(profile.getTRC(ICC_ProfileRGB.BLUECOMPONENT));
}
// If a CLUT is available, it should be used, and the TRCs ignored.
// Note: A valid profile may only have CLUTs in one direction, and
// TRC:s without useful info, making reverse-transforms impossible.
// In this case the TRC will be used for the reverse-transform with
// unpredictable results. This is in line with the Java specification,
try
{
toPCS = new ColorLookUpTable(profile, ICC_Profile.icSigAToB0Tag);
}
catch (Exception e)
{
toPCS = null;
}
try
{
fromPCS = new ColorLookUpTable(profile, ICC_Profile.icSigBToA0Tag);
}
catch (Exception e)
{
fromPCS = null;
}
// Calculate the inverse matrix if no reverse CLUT is available
if(fromPCS == null)
inv_matrix = invertMatrix(matrix);
else
{
// otherwise just set it to an identity matrix
inv_matrix = new float[3][3];
inv_matrix[0][0] = inv_matrix[1][1] = inv_matrix[2][2] = 1.0f;
}
}
public float[] toCIEXYZ(float[] in)
{
// CLUT takes precedence
if (toPCS != null)
return toPCS.lookup(in);
float[] temp = new float[3];
float[] out = new float[3];
// device space --> linear gamma
temp[0] = rTRC.lookup(in[0]);
temp[1] = gTRC.lookup(in[1]);
temp[2] = bTRC.lookup(in[2]);
// matrix multiplication
out[0] = matrix[0][0] * temp[0] + matrix[0][1] * temp[1]
+ matrix[0][2] * temp[2];
out[1] = matrix[1][0] * temp[0] + matrix[1][1] * temp[1]
+ matrix[1][2] * temp[2];
out[2] = matrix[2][0] * temp[0] + matrix[2][1] * temp[1]
+ matrix[2][2] * temp[2];
return out;
}
public float[] toRGB(float[] in)
{
return SrgbConverter.XYZtoRGB(toCIEXYZ(in));
}
public float[] fromCIEXYZ(float[] in)
{
if (fromPCS != null)
return fromPCS.lookup(in);
float[] temp = new float[3];
float[] out = new float[3];
// matrix multiplication
temp[0] = inv_matrix[0][0] * in[0] + inv_matrix[0][1] * in[1]
+ inv_matrix[0][2] * in[2];
temp[1] = inv_matrix[1][0] * in[0] + inv_matrix[1][1] * in[1]
+ inv_matrix[1][2] * in[2];
temp[2] = inv_matrix[2][0] * in[0] + inv_matrix[2][1] * in[1]
+ inv_matrix[2][2] * in[2];
// device space --> linear gamma
out[0] = rTRC.reverseLookup(temp[0]);
out[1] = gTRC.reverseLookup(temp[1]);
out[2] = bTRC.reverseLookup(temp[2]);
// FIXME: Sun appears to clip the return values to [0,1]
// I don't believe that is a Good Thing,
// (some colorspaces may allow values outside that range.)
// So we return the actual values here.
return out;
}
public float[] fromRGB(float[] in)
{
return fromCIEXYZ(SrgbConverter.RGBtoXYZ(in));
}
/**
* Inverts a 3x3 matrix, returns the inverse,
* throws an IllegalArgumentException if the matrix is not
* invertible (this shouldn't happen for a valid profile)
*/
private float[][] invertMatrix(float[][] matrix)
{
float[][] out = new float[3][3];
double determinant = matrix[0][0] * (matrix[1][1] * matrix[2][2]
- matrix[2][1] * matrix[1][2])
- matrix[0][1] * (matrix[1][0] * matrix[2][2]
- matrix[2][0] * matrix[1][2])
+ matrix[0][2] * (matrix[1][0] * matrix[2][1]
- matrix[2][0] * matrix[1][1]);
if (determinant == 0.0)
throw new IllegalArgumentException("Can't invert conversion matrix.");
float invdet = (float) (1.0 / determinant);
out[0][0] = invdet * (matrix[1][1] * matrix[2][2]
- matrix[1][2] * matrix[2][1]);
out[0][1] = invdet * (matrix[0][2] * matrix[2][1]
- matrix[0][1] * matrix[2][2]);
out[0][2] = invdet * (matrix[0][1] * matrix[1][2]
- matrix[0][2] * matrix[1][1]);
out[1][0] = invdet * (matrix[1][2] * matrix[2][0]
- matrix[1][0] * matrix[2][2]);
out[1][1] = invdet * (matrix[0][0] * matrix[2][2]
- matrix[0][2] * matrix[2][0]);
out[1][2] = invdet * (matrix[0][2] * matrix[1][0]
- matrix[0][0] * matrix[1][2]);
out[2][0] = invdet * (matrix[1][0] * matrix[2][1]
- matrix[1][1] * matrix[2][0]);
out[2][1] = invdet * (matrix[0][1] * matrix[2][0]
- matrix[0][0] * matrix[2][1]);
out[2][2] = invdet * (matrix[0][0] * matrix[1][1]
- matrix[0][1] * matrix[1][0]);
return out;
}
}

View File

@@ -0,0 +1,152 @@
/* SrgbConverter.java -- sRGB conversion class
Copyright (C) 2004 Free Software Foundation
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.java.awt.color;
/**
* SrgbConverter - conversion routines for the sRGB colorspace
* sRGB is a standard for RGB colorspaces, adopted by the w3c.
*
* The specification is available at:
* http://www.w3.org/Graphics/Color/sRGB.html
*
* @author Sven de Marothy
*/
/**
*
* Note the matrix numbers used here are NOT identical to those in the
* w3 spec, as those numbers are CIE XYZ relative a D65 white point.
* The CIE XYZ we use is relative a D50 white point, so therefore a
* linear Bradford transform matrix for D65->D50 mapping has been applied.
* (The ICC documents describe this transform)
*
* Linearized Bradford transform:
* 0.8951 0.2664 -0.1614
* -0.7502 1.7135 0.0367
* 0.0389 -0.0685 1.0296
*
* Inverse:
* 0.9870 -0.1471 0.1600
* 0.4323 0.5184 0.0493
* -0.00853 0.0400 0.9685
*/
public class SrgbConverter implements ColorSpaceConverter
{
public float[] fromCIEXYZ(float[] in)
{
return XYZtoRGB(in);
}
public float[] toCIEXYZ(float[] in)
{
return RGBtoXYZ(in);
}
public float[] toRGB(float[] in)
{
float[] out = new float[3];
System.arraycopy(in, 0, out, 0, 3);
return out;
}
public float[] fromRGB(float[] in)
{
float[] out = new float[3];
System.arraycopy(in, 0, out, 0, 3);
return out;
}
/**
* CIE XYZ (D50 relative) --> sRGB
*
* Static as it's used by other ColorSpaceConverters to
* convert to sRGB if the color space is defined in XYZ.
*/
public static float[] XYZtoRGB(float[] in)
{
float[] temp = new float[3];
temp[0] = 3.1338f * in[0] - 1.6171f * in[1] - 0.4907f * in[2];
temp[1] = -0.9785f * in[0] + 1.9160f * in[1] + 0.0334f * in[2];
temp[2] = 0.0720f * in[0] - 0.2290f * in[1] + 1.4056f * in[2];
float[] out = new float[3];
for (int i = 0; i < 3; i++)
{
if (temp[i] < 0)
temp[i] = 0.0f;
if (temp[i] > 1)
temp[i] = 1.0f;
if (temp[i] <= 0.00304f)
out[i] = temp[i] * 12.92f;
else
out[i] = 1.055f * ((float) Math.exp((1 / 2.4) * Math.log(temp[i])))
- 0.055f;
}
return out;
}
/**
* sRGB --> CIE XYZ (D50 relative)
*
* Static as it's used by other ColorSpaceConverters to
* convert to XYZ if the color space is defined in RGB.
*/
public static float[] RGBtoXYZ(float[] in)
{
float[] temp = new float[3];
float[] out = new float[3];
for (int i = 0; i < 3; i++)
if (in[i] <= 0.03928f)
temp[i] = in[i] / 12.92f;
else
temp[i] = (float) Math.exp(2.4 * Math.log((in[i] + 0.055) / 1.055));
/*
* Note: The numbers which were used to calculate this only had four
* digits of accuracy. So don't be fooled by the number of digits here.
* If someone has more accurate source, feel free to update this.
*/
out[0] = (float) (0.436063750222 * temp[0] + 0.385149601465 * temp[1]
+ 0.143086418888 * temp[2]);
out[1] = (float) (0.222450894035 * temp[0] + 0.71692584775 * temp[1]
+ 0.060624511256 * temp[2]);
out[2] = (float) (0.0138985186 * temp[0] + 0.097079690112 * temp[1]
+ 0.713996045725 * temp[2]);
return out;
}
}

View File

@@ -0,0 +1,121 @@
/* TagEntry.java -- A utility class used for storing the tags in ICC_Profile
Copyright (C) 2004 Free Software Foundation
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.java.awt.color;
/**
* TagEntry - stores a profile tag.
* These are conveniently stored in a hashtable with the tag signature
* as a key. A legal profile can only have one tag with a given sig,
* so we can conveniently ignore collisions.
*
* @author Sven de Marothy
*/
public class TagEntry
{
// tag table entry size
public static final int entrySize = 12;
private int signature;
private int size;
private int offset;
private byte[] data;
public TagEntry(int sig, int offset, int size, byte[] data)
{
this.signature = sig;
this.offset = offset;
this.size = size;
this.data = new byte[size];
System.arraycopy(data, offset, this.data, 0, size);
}
public TagEntry(int sig, byte[] data)
{
this.signature = sig;
this.size = data.length;
this.data = new byte[size];
System.arraycopy(data, offset, this.data, 0, size);
}
public byte[] getData()
{
byte[] d = new byte[size];
System.arraycopy(this.data, 0, d, 0, size);
return d;
}
public String hashKey()
{
return tagHashKey(signature);
}
public String toString()
{
String s = "";
s = s + (char) ((byte) ((signature >> 24) & 0xFF));
s = s + (char) ((byte) ((signature >> 16) & 0xFF));
s = s + (char) ((byte) ((signature >> 8) & 0xFF));
s = s + (char) ((byte) (signature & 0xFF));
return s;
}
public int getSignature()
{
return signature;
}
public int getSize()
{
return size;
}
public int getOffset()
{
return offset;
}
public void setOffset(int offset)
{
this.offset = offset;
}
public static String tagHashKey(int sig)
{
return "" + sig;
}
}

View File

@@ -0,0 +1,177 @@
/* ToneReproductionCurve.java -- Representation of an ICC 'curv' type TRC
Copyright (C) 2004 Free Software Foundation
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.java.awt.color;
/**
* ToneReproductionCurve - TRCs are used to describe RGB
* and Grayscale profiles. The TRC is essentially the gamma
* function of the color space.
*
* For example, Apple RGB has a gamma of 1.8, most monitors are ~2.2,
* sRGB is 2.4 with a small linear part near 0.
* Linear spaces are of course 1.0.
* (The exact function is implemented in SrgbConverter)
*
* The ICC specification allows the TRC to be described as a single
* Gamma value, where the function is thus out = in**gamma.
* Alternatively, the gamma function may be represented by a lookup table
* of values, in which case linear interpolation is used.
*
* @author Sven de Marothy
*/
public class ToneReproductionCurve
{
private float[] trc;
private float gamma;
private float[] reverseTrc;
/**
* Constructs a TRC from a gamma values
*/
public ToneReproductionCurve(float gamma)
{
trc = null;
reverseTrc = null;
this.gamma = gamma;
}
/**
* Constructs a TRC from a set of float values
*/
public ToneReproductionCurve(float[] trcValues)
{
trc = new float[trcValues.length];
System.arraycopy(trcValues, 0, trc, 0, trcValues.length);
setupReverseTrc();
}
/**
* Constructs a TRC from a set of short values normalized to
* the 0-65535 range (as in the ICC profile file).
* (Note the values are treated as unsigned)
*/
public ToneReproductionCurve(short[] trcValues)
{
trc = new float[trcValues.length];
for (int i = 0; i < trcValues.length; i++)
trc[i] = (float) ((int) trcValues[i] & (0xFFFF)) / 65535.0f;
setupReverseTrc();
}
/**
* Performs a TRC lookup
*/
public float lookup(float in)
{
float out;
if (trc == null)
{
if (in == 0f)
return 0.0f;
return (float) Math.exp(gamma * Math.log(in));
}
else
{
double alpha = in * (trc.length - 1);
int index = (int) Math.floor(alpha);
alpha = alpha - (double) index;
if (index >= trc.length - 1)
return trc[trc.length - 1];
if (index <= 0)
return trc[0];
out = (float) (trc[index] * (1.0 - alpha) + trc[index + 1] * alpha);
}
return out;
}
/**
* Performs an reverse lookup
*/
public float reverseLookup(float in)
{
float out;
if (trc == null)
{
if (in == 0f)
return 0.0f;
return (float) Math.exp((1.0 / gamma) * Math.log(in));
}
else
{
double alpha = in * (reverseTrc.length - 1);
int index = (int) Math.floor(alpha);
alpha = alpha - (double) index;
if (index >= reverseTrc.length - 1)
return reverseTrc[reverseTrc.length - 1];
if (index <= 0)
return reverseTrc[0];
out = (float) (reverseTrc[index] * (1.0 - alpha)
+ reverseTrc[index + 1] * alpha);
}
return out;
}
/**
* Calculates a reverse-lookup table.
* We use a whopping 10,000 entries.. This is should be more than any
* real-life TRC table (typically around 256-1024) so we won't be losing
* any precision.
*
* This will of course generate completely invalid results if the curve
* is not monotonic and invertable. But what's the alternative?
*/
public void setupReverseTrc()
{
reverseTrc = new float[10000];
int j = 0;
for (int i = 0; i < 10000; i++)
{
float n = ((float) i) / 10000f;
while (trc[j + 1] < n && j < trc.length - 2)
j++;
if (j == trc.length - 2)
reverseTrc[i] = trc[trc.length - 1];
else
reverseTrc[i] = (j + (n - trc[j]) / (trc[j + 1] - trc[j])) / ((float) trc.length);
}
}
}