Frames | No Frames |
1: /* ToneReproductionCurve.java -- Representation of an ICC 'curv' type TRC 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., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 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: package gnu.java.awt.color; 39: 40: 41: /** 42: * ToneReproductionCurve - TRCs are used to describe RGB 43: * and Grayscale profiles. The TRC is essentially the gamma 44: * function of the color space. 45: * 46: * For example, Apple RGB has a gamma of 1.8, most monitors are ~2.2, 47: * sRGB is 2.4 with a small linear part near 0. 48: * Linear spaces are of course 1.0. 49: * (The exact function is implemented in SrgbConverter) 50: * 51: * The ICC specification allows the TRC to be described as a single 52: * Gamma value, where the function is thus out = in**gamma. 53: * Alternatively, the gamma function may be represented by a lookup table 54: * of values, in which case linear interpolation is used. 55: * 56: * @author Sven de Marothy 57: */ 58: public class ToneReproductionCurve 59: { 60: private float[] trc; 61: private float gamma; 62: private float[] reverseTrc; 63: 64: /** 65: * Constructs a TRC from a gamma values 66: */ 67: public ToneReproductionCurve(float gamma) 68: { 69: trc = null; 70: reverseTrc = null; 71: this.gamma = gamma; 72: } 73: 74: /** 75: * Constructs a TRC from a set of float values 76: */ 77: public ToneReproductionCurve(float[] trcValues) 78: { 79: trc = new float[trcValues.length]; 80: System.arraycopy(trcValues, 0, trc, 0, trcValues.length); 81: setupReverseTrc(); 82: } 83: 84: /** 85: * Constructs a TRC from a set of short values normalized to 86: * the 0-65535 range (as in the ICC profile file). 87: * (Note the values are treated as unsigned) 88: */ 89: public ToneReproductionCurve(short[] trcValues) 90: { 91: trc = new float[trcValues.length]; 92: for (int i = 0; i < trcValues.length; i++) 93: trc[i] = (float) ((int) trcValues[i] & (0xFFFF)) / 65535.0f; 94: setupReverseTrc(); 95: } 96: 97: /** 98: * Performs a TRC lookup 99: */ 100: public float lookup(float in) 101: { 102: float out; 103: 104: if (trc == null) 105: { 106: if (in == 0f) 107: return 0.0f; 108: return (float) Math.exp(gamma * Math.log(in)); 109: } 110: else 111: { 112: double alpha = in * (trc.length - 1); 113: int index = (int) Math.floor(alpha); 114: alpha = alpha - (double) index; 115: if (index >= trc.length - 1) 116: return trc[trc.length - 1]; 117: if (index <= 0) 118: return trc[0]; 119: out = (float) (trc[index] * (1.0 - alpha) + trc[index + 1] * alpha); 120: } 121: return out; 122: } 123: 124: /** 125: * Performs an reverse lookup 126: */ 127: public float reverseLookup(float in) 128: { 129: float out; 130: 131: if (trc == null) 132: { 133: if (in == 0f) 134: return 0.0f; 135: return (float) Math.exp((1.0 / gamma) * Math.log(in)); 136: } 137: else 138: { 139: double alpha = in * (reverseTrc.length - 1); 140: int index = (int) Math.floor(alpha); 141: alpha = alpha - (double) index; 142: if (index >= reverseTrc.length - 1) 143: return reverseTrc[reverseTrc.length - 1]; 144: if (index <= 0) 145: return reverseTrc[0]; 146: out = (float) (reverseTrc[index] * (1.0 - alpha) 147: + reverseTrc[index + 1] * alpha); 148: } 149: return out; 150: } 151: 152: /** 153: * Calculates a reverse-lookup table. 154: * We use a whopping 10,000 entries.. This is should be more than any 155: * real-life TRC table (typically around 256-1024) so we won't be losing 156: * any precision. 157: * 158: * This will of course generate completely invalid results if the curve 159: * is not monotonic and invertable. But what's the alternative? 160: */ 161: public void setupReverseTrc() 162: { 163: reverseTrc = new float[10000]; 164: int j = 0; 165: for (int i = 0; i < 10000; i++) 166: { 167: float n = ((float) i) / 10000f; 168: while (trc[j + 1] < n && j < trc.length - 2) 169: j++; 170: 171: if (j == trc.length - 2) 172: reverseTrc[i] = trc[trc.length - 1]; 173: else 174: reverseTrc[i] = (j + (n - trc[j]) / (trc[j + 1] - trc[j])) / ((float) trc.length); 175: } 176: } 177: }