OSDN Git Service

0482b3fe6690164ef459a756f8daa64973c412cf
[pf3gnuchains/gcc-fork.git] / libjava / gnu / java / awt / color / RgbProfileConverter.java
1 /* RgbProfileConverter.java -- RGB Profile conversion class
2    Copyright (C) 2004 Free Software Foundation
3
4    This file is part of GNU Classpath.
5
6    GNU Classpath is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2, or (at your option)
9    any later version.
10
11    GNU Classpath is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with GNU Classpath; see the file COPYING.  If not, write to the
18    Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.
20
21    Linking this library statically or dynamically with other modules is
22    making a combined work based on this library.  Thus, the terms and
23    conditions of the GNU General Public License cover the whole
24    combination.
25
26    As a special exception, the copyright holders of this library give you
27    permission to link this library with independent modules to produce an
28    executable, regardless of the license terms of these independent
29    modules, and to copy and distribute the resulting executable under
30    terms of your choice, provided that you also meet, for each linked
31    independent module, the terms and conditions of the license of that
32    module.  An independent module is a module which is not derived from
33    or based on this library.  If you modify this library, you may extend
34    this exception to your version of the library, but you are not
35    obligated to do so.  If you do not wish to do so, delete this
36    exception statement from your version.
37 */
38
39 package gnu.java.awt.color;
40
41 import java.awt.color.ProfileDataException;
42 import java.awt.color.ICC_Profile;
43 import java.awt.color.ICC_ProfileRGB;
44
45
46 /**
47  * RgbProfileConverter - converts RGB profiles (ICC_ProfileRGB)
48  *
49  * This type of profile contains a matrix and three
50  * tone reproduction curves (TRCs).
51  *
52  * Device RGB --> CIE XYZ is done through first multiplying with
53  * a matrix, then each component is looked-up against it's TRC.
54  *
55  * The opposite transform is done using the inverse of the matrix,
56  * and TRC:s.
57  *
58  * @author Sven de Marothy
59  */
60 public class RgbProfileConverter implements ColorSpaceConverter
61 {
62   private float[][] matrix;
63   private float[][] inv_matrix;
64   private ToneReproductionCurve rTRC;
65   private ToneReproductionCurve gTRC;
66   private ToneReproductionCurve bTRC;
67   private ColorLookUpTable toPCS;
68   private ColorLookUpTable fromPCS;
69
70   /**
71    * CIE 1931 D50 white point (in Lab coordinates)
72    */
73   private static float[] D50 = { 0.96422f, 1.00f, 0.82521f };
74
75   /**
76    * Constructs an RgbProfileConverter from a given ICC_ProfileRGB
77    */
78   public RgbProfileConverter(ICC_ProfileRGB profile)
79   {
80     toPCS = fromPCS = null;
81     matrix = profile.getMatrix();
82
83     // get TRCs
84     try
85       {
86         rTRC = new ToneReproductionCurve(profile.getGamma(ICC_ProfileRGB.REDCOMPONENT));
87       }
88     catch (ProfileDataException e)
89       {
90         rTRC = new ToneReproductionCurve(profile.getTRC(ICC_ProfileRGB.REDCOMPONENT));
91       }
92     try
93       {
94         gTRC = new ToneReproductionCurve(profile.getGamma(ICC_ProfileRGB.GREENCOMPONENT));
95       }
96     catch (ProfileDataException e)
97       {
98         gTRC = new ToneReproductionCurve(profile.getTRC(ICC_ProfileRGB.GREENCOMPONENT));
99       }
100     try
101       {
102         bTRC = new ToneReproductionCurve(profile.getGamma(ICC_ProfileRGB.BLUECOMPONENT));
103       }
104     catch (ProfileDataException e)
105       {
106         bTRC = new ToneReproductionCurve(profile.getTRC(ICC_ProfileRGB.BLUECOMPONENT));
107       }
108
109     // If a CLUT is available, it should be used, and the TRCs ignored.
110     // Note: A valid profile may only have CLUTs in one direction, and
111     // TRC:s without useful info, making reverse-transforms impossible.
112     // In this case the TRC will be used for the reverse-transform with
113     // unpredictable results. This is in line with the Java specification,
114     try
115       {
116         toPCS = new ColorLookUpTable(profile, ICC_Profile.icSigAToB0Tag);
117       }
118     catch (Exception e)
119       {
120         toPCS = null;
121       }
122
123     try
124       {
125         fromPCS = new ColorLookUpTable(profile, ICC_Profile.icSigBToA0Tag);
126       }
127     catch (Exception e)
128       {
129         fromPCS = null;
130       }
131
132     // Calculate the inverse matrix if no reverse CLUT is available
133     if(fromPCS == null)
134         inv_matrix = invertMatrix(matrix);
135     else 
136       {
137         // otherwise just set it to an identity matrix
138         inv_matrix = new float[3][3];
139         inv_matrix[0][0] = inv_matrix[1][1] = inv_matrix[2][2] = 1.0f;
140       }
141   }
142
143   public float[] toCIEXYZ(float[] in)
144   {
145     // CLUT takes precedence
146     if (toPCS != null)
147       return toPCS.lookup(in);
148
149     float[] temp = new float[3];
150     float[] out = new float[3];
151
152     // device space --> linear gamma
153     temp[0] = rTRC.lookup(in[0]);
154     temp[1] = gTRC.lookup(in[1]);
155     temp[2] = bTRC.lookup(in[2]);
156
157     // matrix multiplication
158     out[0] = matrix[0][0] * temp[0] + matrix[0][1] * temp[1]
159              + matrix[0][2] * temp[2];
160     out[1] = matrix[1][0] * temp[0] + matrix[1][1] * temp[1]
161              + matrix[1][2] * temp[2];
162     out[2] = matrix[2][0] * temp[0] + matrix[2][1] * temp[1]
163              + matrix[2][2] * temp[2];
164
165     return out;
166   }
167
168   public float[] toRGB(float[] in)
169   {
170     return SrgbConverter.XYZtoRGB(toCIEXYZ(in));
171   }
172
173   public float[] fromCIEXYZ(float[] in)
174   {
175     if (fromPCS != null)
176       return fromPCS.lookup(in);
177
178     float[] temp = new float[3];
179     float[] out = new float[3];
180
181     // matrix multiplication
182     temp[0] = inv_matrix[0][0] * in[0] + inv_matrix[0][1] * in[1]
183               + inv_matrix[0][2] * in[2];
184     temp[1] = inv_matrix[1][0] * in[0] + inv_matrix[1][1] * in[1]
185               + inv_matrix[1][2] * in[2];
186     temp[2] = inv_matrix[2][0] * in[0] + inv_matrix[2][1] * in[1]
187               + inv_matrix[2][2] * in[2];
188
189     // device space --> linear gamma
190     out[0] = rTRC.reverseLookup(temp[0]);
191     out[1] = gTRC.reverseLookup(temp[1]);
192     out[2] = bTRC.reverseLookup(temp[2]);
193
194     // FIXME: Sun appears to clip the return values to [0,1]
195     // I don't believe that is a Good Thing, 
196     // (some colorspaces may allow values outside that range.)
197     // So we return the actual values here.
198     return out;
199   }
200
201   public float[] fromRGB(float[] in)
202   {
203     return fromCIEXYZ(SrgbConverter.RGBtoXYZ(in));
204   }
205
206   /**
207    * Inverts a 3x3 matrix, returns the inverse,
208    * throws an IllegalArgumentException if the matrix is not
209    * invertible (this shouldn't happen for a valid profile)
210    */
211   private float[][] invertMatrix(float[][] matrix)
212   {
213     float[][] out = new float[3][3];
214     double determinant = matrix[0][0] * (matrix[1][1] * matrix[2][2]
215                          - matrix[2][1] * matrix[1][2])
216                          - matrix[0][1] * (matrix[1][0] * matrix[2][2]
217                          - matrix[2][0] * matrix[1][2])
218                          + matrix[0][2] * (matrix[1][0] * matrix[2][1]
219                          - matrix[2][0] * matrix[1][1]);
220
221     if (determinant == 0.0)
222       throw new IllegalArgumentException("Can't invert conversion matrix.");
223     float invdet = (float) (1.0 / determinant);
224
225     out[0][0] = invdet * (matrix[1][1] * matrix[2][2]
226                 - matrix[1][2] * matrix[2][1]);
227     out[0][1] = invdet * (matrix[0][2] * matrix[2][1]
228                 - matrix[0][1] * matrix[2][2]);
229     out[0][2] = invdet * (matrix[0][1] * matrix[1][2]
230                 - matrix[0][2] * matrix[1][1]);
231     out[1][0] = invdet * (matrix[1][2] * matrix[2][0]
232                 - matrix[1][0] * matrix[2][2]);
233     out[1][1] = invdet * (matrix[0][0] * matrix[2][2]
234                 - matrix[0][2] * matrix[2][0]);
235     out[1][2] = invdet * (matrix[0][2] * matrix[1][0]
236                 - matrix[0][0] * matrix[1][2]);
237     out[2][0] = invdet * (matrix[1][0] * matrix[2][1]
238                 - matrix[1][1] * matrix[2][0]);
239     out[2][1] = invdet * (matrix[0][1] * matrix[2][0]
240                 - matrix[0][0] * matrix[2][1]);
241     out[2][2] = invdet * (matrix[0][0] * matrix[1][1]
242                 - matrix[0][1] * matrix[1][0]);
243     return out;
244   }
245 }