Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(397)

Side by Side Diff: third_party/qcms/src/chain.c

Issue 2014023003: Add exact version of qcms used by Chrome for testing and comparison (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/qcms/src/chain.h ('k') | third_party/qcms/src/empty.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /* vim: set ts=8 sw=8 noexpandtab: */
2 // qcms
3 // Copyright (C) 2009 Mozilla Corporation
4 // Copyright (C) 1998-2007 Marti Maria
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining
7 // a copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the Softwar e
11 // is furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
18 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24 #include <stdlib.h>
25 #include <math.h>
26 #include <assert.h>
27 #include <string.h> //memcpy
28 #include "qcmsint.h"
29 #include "transform_util.h"
30 #include "matrix.h"
31
32 static struct matrix build_lut_matrix(struct lutType *lut)
33 {
34 struct matrix result;
35 if (lut) {
36 result.m[0][0] = s15Fixed16Number_to_float(lut->e00);
37 result.m[0][1] = s15Fixed16Number_to_float(lut->e01);
38 result.m[0][2] = s15Fixed16Number_to_float(lut->e02);
39 result.m[1][0] = s15Fixed16Number_to_float(lut->e10);
40 result.m[1][1] = s15Fixed16Number_to_float(lut->e11);
41 result.m[1][2] = s15Fixed16Number_to_float(lut->e12);
42 result.m[2][0] = s15Fixed16Number_to_float(lut->e20);
43 result.m[2][1] = s15Fixed16Number_to_float(lut->e21);
44 result.m[2][2] = s15Fixed16Number_to_float(lut->e22);
45 result.invalid = false;
46 } else {
47 memset(&result, 0, sizeof(struct matrix));
48 result.invalid = true;
49 }
50 return result;
51 }
52
53 static struct matrix build_mAB_matrix(struct lutmABType *lut)
54 {
55 struct matrix result;
56 if (lut) {
57 result.m[0][0] = s15Fixed16Number_to_float(lut->e00);
58 result.m[0][1] = s15Fixed16Number_to_float(lut->e01);
59 result.m[0][2] = s15Fixed16Number_to_float(lut->e02);
60 result.m[1][0] = s15Fixed16Number_to_float(lut->e10);
61 result.m[1][1] = s15Fixed16Number_to_float(lut->e11);
62 result.m[1][2] = s15Fixed16Number_to_float(lut->e12);
63 result.m[2][0] = s15Fixed16Number_to_float(lut->e20);
64 result.m[2][1] = s15Fixed16Number_to_float(lut->e21);
65 result.m[2][2] = s15Fixed16Number_to_float(lut->e22);
66 result.invalid = false;
67 } else {
68 memset(&result, 0, sizeof(struct matrix));
69 result.invalid = true;
70 }
71 return result;
72 }
73
74 //Based on lcms cmsLab2XYZ
75 #define f(t) (t <= (24.0f/116.0f)*(24.0f/116.0f)*(24.0f/116.0f)) ? ((841.0/108.0 ) * t + (16.0/116.0)) : pow(t,1.0/3.0)
76 #define f_1(t) (t <= (24.0f/116.0f)) ? ((108.0/841.0) * (t - (16.0/116.0))) : (t * t * t)
77 static void qcms_transform_module_LAB_to_XYZ(struct qcms_modular_transform *tran sform, float *src, float *dest, size_t length)
78 {
79 size_t i;
80 // lcms: D50 XYZ values
81 float WhitePointX = 0.9642f;
82 float WhitePointY = 1.0f;
83 float WhitePointZ = 0.8249f;
84 for (i = 0; i < length; i++) {
85 float device_L = *src++ * 100.0f;
86 float device_a = *src++ * 255.0f - 128.0f;
87 float device_b = *src++ * 255.0f - 128.0f;
88 float y = (device_L + 16.0f) / 116.0f;
89
90 float X = f_1((y + 0.002f * device_a)) * WhitePointX;
91 float Y = f_1(y) * WhitePointY;
92 float Z = f_1((y - 0.005f * device_b)) * WhitePointZ;
93 *dest++ = X / (1.0 + 32767.0/32768.0);
94 *dest++ = Y / (1.0 + 32767.0/32768.0);
95 *dest++ = Z / (1.0 + 32767.0/32768.0);
96 }
97 }
98
99 //Based on lcms cmsXYZ2Lab
100 static void qcms_transform_module_XYZ_to_LAB(struct qcms_modular_transform *tran sform, float *src, float *dest, size_t length)
101 {
102 size_t i;
103 // lcms: D50 XYZ values
104 float WhitePointX = 0.9642f;
105 float WhitePointY = 1.0f;
106 float WhitePointZ = 0.8249f;
107 for (i = 0; i < length; i++) {
108 float device_x = *src++ * (1.0 + 32767.0/32768.0) / WhitePointX;
109 float device_y = *src++ * (1.0 + 32767.0/32768.0) / WhitePointY;
110 float device_z = *src++ * (1.0 + 32767.0/32768.0) / WhitePointZ;
111
112 float fx = f(device_x);
113 float fy = f(device_y);
114 float fz = f(device_z);
115
116 float L = 116.0f*fy - 16.0f;
117 float a = 500.0f*(fx - fy);
118 float b = 200.0f*(fy - fz);
119 *dest++ = L / 100.0f;
120 *dest++ = (a+128.0f) / 255.0f;
121 *dest++ = (b+128.0f) / 255.0f;
122 }
123
124 }
125
126 static void qcms_transform_module_clut_only(struct qcms_modular_transform *trans form, float *src, float *dest, size_t length)
127 {
128 size_t i;
129 int xy_len = 1;
130 int x_len = transform->grid_size;
131 int len = x_len * x_len;
132 float* r_table = transform->r_clut;
133 float* g_table = transform->g_clut;
134 float* b_table = transform->b_clut;
135
136 assert(transform->grid_size >= 1);
137
138 for (i = 0; i < length; i++) {
139 float linear_r = *src++;
140 float linear_g = *src++;
141 float linear_b = *src++;
142
143 int x = floor(linear_r * (transform->grid_size-1));
144 int y = floor(linear_g * (transform->grid_size-1));
145 int z = floor(linear_b * (transform->grid_size-1));
146 int x_n = ceil(linear_r * (transform->grid_size-1));
147 int y_n = ceil(linear_g * (transform->grid_size-1));
148 int z_n = ceil(linear_b * (transform->grid_size-1));
149 float x_d = linear_r * (transform->grid_size-1) - x;
150 float y_d = linear_g * (transform->grid_size-1) - y;
151 float z_d = linear_b * (transform->grid_size-1) - z;
152
153 float r_x1 = lerp(CLU(r_table,x,y,z), CLU(r_table,x_n,y,z), x_d) ;
154 float r_x2 = lerp(CLU(r_table,x,y_n,z), CLU(r_table,x_n,y_n,z), x_d);
155 float r_y1 = lerp(r_x1, r_x2, y_d);
156 float r_x3 = lerp(CLU(r_table,x,y,z_n), CLU(r_table,x_n,y,z_n), x_d);
157 float r_x4 = lerp(CLU(r_table,x,y_n,z_n), CLU(r_table,x_n,y_n,z_ n), x_d);
158 float r_y2 = lerp(r_x3, r_x4, y_d);
159 float clut_r = lerp(r_y1, r_y2, z_d);
160
161 float g_x1 = lerp(CLU(g_table,x,y,z), CLU(g_table,x_n,y,z), x_d) ;
162 float g_x2 = lerp(CLU(g_table,x,y_n,z), CLU(g_table,x_n,y_n,z), x_d);
163 float g_y1 = lerp(g_x1, g_x2, y_d);
164 float g_x3 = lerp(CLU(g_table,x,y,z_n), CLU(g_table,x_n,y,z_n), x_d);
165 float g_x4 = lerp(CLU(g_table,x,y_n,z_n), CLU(g_table,x_n,y_n,z_ n), x_d);
166 float g_y2 = lerp(g_x3, g_x4, y_d);
167 float clut_g = lerp(g_y1, g_y2, z_d);
168
169 float b_x1 = lerp(CLU(b_table,x,y,z), CLU(b_table,x_n,y,z), x_d) ;
170 float b_x2 = lerp(CLU(b_table,x,y_n,z), CLU(b_table,x_n,y_n,z), x_d);
171 float b_y1 = lerp(b_x1, b_x2, y_d);
172 float b_x3 = lerp(CLU(b_table,x,y,z_n), CLU(b_table,x_n,y,z_n), x_d);
173 float b_x4 = lerp(CLU(b_table,x,y_n,z_n), CLU(b_table,x_n,y_n,z_ n), x_d);
174 float b_y2 = lerp(b_x3, b_x4, y_d);
175 float clut_b = lerp(b_y1, b_y2, z_d);
176
177 *dest++ = clamp_float(clut_r);
178 *dest++ = clamp_float(clut_g);
179 *dest++ = clamp_float(clut_b);
180 }
181 }
182
183 static void qcms_transform_module_clut(struct qcms_modular_transform *transform, float *src, float *dest, size_t length)
184 {
185 size_t i;
186 int xy_len = 1;
187 int x_len = transform->grid_size;
188 int len = x_len * x_len;
189 float* r_table = transform->r_clut;
190 float* g_table = transform->g_clut;
191 float* b_table = transform->b_clut;
192
193 assert(transform->grid_size >= 1);
194
195 for (i = 0; i < length; i++) {
196 float device_r = *src++;
197 float device_g = *src++;
198 float device_b = *src++;
199 float linear_r = lut_interp_linear_float(device_r,
200 transform->input_clut_table_r, transform->input_ clut_table_length);
201 float linear_g = lut_interp_linear_float(device_g,
202 transform->input_clut_table_g, transform->input_ clut_table_length);
203 float linear_b = lut_interp_linear_float(device_b,
204 transform->input_clut_table_b, transform->input_ clut_table_length);
205
206 int x = floor(linear_r * (transform->grid_size-1));
207 int y = floor(linear_g * (transform->grid_size-1));
208 int z = floor(linear_b * (transform->grid_size-1));
209 int x_n = ceil(linear_r * (transform->grid_size-1));
210 int y_n = ceil(linear_g * (transform->grid_size-1));
211 int z_n = ceil(linear_b * (transform->grid_size-1));
212 float x_d = linear_r * (transform->grid_size-1) - x;
213 float y_d = linear_g * (transform->grid_size-1) - y;
214 float z_d = linear_b * (transform->grid_size-1) - z;
215
216 float r_x1 = lerp(CLU(r_table,x,y,z), CLU(r_table,x_n,y,z), x_d) ;
217 float r_x2 = lerp(CLU(r_table,x,y_n,z), CLU(r_table,x_n,y_n,z), x_d);
218 float r_y1 = lerp(r_x1, r_x2, y_d);
219 float r_x3 = lerp(CLU(r_table,x,y,z_n), CLU(r_table,x_n,y,z_n), x_d);
220 float r_x4 = lerp(CLU(r_table,x,y_n,z_n), CLU(r_table,x_n,y_n,z_ n), x_d);
221 float r_y2 = lerp(r_x3, r_x4, y_d);
222 float clut_r = lerp(r_y1, r_y2, z_d);
223
224 float g_x1 = lerp(CLU(g_table,x,y,z), CLU(g_table,x_n,y,z), x_d) ;
225 float g_x2 = lerp(CLU(g_table,x,y_n,z), CLU(g_table,x_n,y_n,z), x_d);
226 float g_y1 = lerp(g_x1, g_x2, y_d);
227 float g_x3 = lerp(CLU(g_table,x,y,z_n), CLU(g_table,x_n,y,z_n), x_d);
228 float g_x4 = lerp(CLU(g_table,x,y_n,z_n), CLU(g_table,x_n,y_n,z_ n), x_d);
229 float g_y2 = lerp(g_x3, g_x4, y_d);
230 float clut_g = lerp(g_y1, g_y2, z_d);
231
232 float b_x1 = lerp(CLU(b_table,x,y,z), CLU(b_table,x_n,y,z), x_d) ;
233 float b_x2 = lerp(CLU(b_table,x,y_n,z), CLU(b_table,x_n,y_n,z), x_d);
234 float b_y1 = lerp(b_x1, b_x2, y_d);
235 float b_x3 = lerp(CLU(b_table,x,y,z_n), CLU(b_table,x_n,y,z_n), x_d);
236 float b_x4 = lerp(CLU(b_table,x,y_n,z_n), CLU(b_table,x_n,y_n,z_ n), x_d);
237 float b_y2 = lerp(b_x3, b_x4, y_d);
238 float clut_b = lerp(b_y1, b_y2, z_d);
239
240 float pcs_r = lut_interp_linear_float(clut_r,
241 transform->output_clut_table_r, transform->outpu t_clut_table_length);
242 float pcs_g = lut_interp_linear_float(clut_g,
243 transform->output_clut_table_g, transform->outpu t_clut_table_length);
244 float pcs_b = lut_interp_linear_float(clut_b,
245 transform->output_clut_table_b, transform->outpu t_clut_table_length);
246
247 *dest++ = clamp_float(pcs_r);
248 *dest++ = clamp_float(pcs_g);
249 *dest++ = clamp_float(pcs_b);
250 }
251 }
252
253 /* NOT USED
254 static void qcms_transform_module_tetra_clut(struct qcms_modular_transform *tran sform, float *src, float *dest, size_t length)
255 {
256 size_t i;
257 int xy_len = 1;
258 int x_len = transform->grid_size;
259 int len = x_len * x_len;
260 float* r_table = transform->r_clut;
261 float* g_table = transform->g_clut;
262 float* b_table = transform->b_clut;
263 float c0_r, c1_r, c2_r, c3_r;
264 float c0_g, c1_g, c2_g, c3_g;
265 float c0_b, c1_b, c2_b, c3_b;
266 float clut_r, clut_g, clut_b;
267 float pcs_r, pcs_g, pcs_b;
268 for (i = 0; i < length; i++) {
269 float device_r = *src++;
270 float device_g = *src++;
271 float device_b = *src++;
272 float linear_r = lut_interp_linear_float(device_r,
273 transform->input_clut_table_r, transform->input_ clut_table_length);
274 float linear_g = lut_interp_linear_float(device_g,
275 transform->input_clut_table_g, transform->input_ clut_table_length);
276 float linear_b = lut_interp_linear_float(device_b,
277 transform->input_clut_table_b, transform->input_ clut_table_length);
278
279 int x = floor(linear_r * (transform->grid_size-1));
280 int y = floor(linear_g * (transform->grid_size-1));
281 int z = floor(linear_b * (transform->grid_size-1));
282 int x_n = ceil(linear_r * (transform->grid_size-1));
283 int y_n = ceil(linear_g * (transform->grid_size-1));
284 int z_n = ceil(linear_b * (transform->grid_size-1));
285 float rx = linear_r * (transform->grid_size-1) - x;
286 float ry = linear_g * (transform->grid_size-1) - y;
287 float rz = linear_b * (transform->grid_size-1) - z;
288
289 c0_r = CLU(r_table, x, y, z);
290 c0_g = CLU(g_table, x, y, z);
291 c0_b = CLU(b_table, x, y, z);
292 if( rx >= ry ) {
293 if (ry >= rz) { //rx >= ry && ry >= rz
294 c1_r = CLU(r_table, x_n, y, z) - c0_r;
295 c2_r = CLU(r_table, x_n, y_n, z) - CLU(r_table, x_n, y, z);
296 c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table , x_n, y_n, z);
297 c1_g = CLU(g_table, x_n, y, z) - c0_g;
298 c2_g = CLU(g_table, x_n, y_n, z) - CLU(g_table, x_n, y, z);
299 c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table , x_n, y_n, z);
300 c1_b = CLU(b_table, x_n, y, z) - c0_b;
301 c2_b = CLU(b_table, x_n, y_n, z) - CLU(b_table, x_n, y, z);
302 c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table , x_n, y_n, z);
303 } else {
304 if (rx >= rz) { //rx >= rz && rz >= ry
305 c1_r = CLU(r_table, x_n, y, z) - c0_r;
306 c2_r = CLU(r_table, x_n, y_n, z_n) - CLU (r_table, x_n, y, z_n);
307 c3_r = CLU(r_table, x_n, y, z_n) - CLU(r _table, x_n, y, z);
308 c1_g = CLU(g_table, x_n, y, z) - c0_g;
309 c2_g = CLU(g_table, x_n, y_n, z_n) - CLU (g_table, x_n, y, z_n);
310 c3_g = CLU(g_table, x_n, y, z_n) - CLU(g _table, x_n, y, z);
311 c1_b = CLU(b_table, x_n, y, z) - c0_b;
312 c2_b = CLU(b_table, x_n, y_n, z_n) - CLU (b_table, x_n, y, z_n);
313 c3_b = CLU(b_table, x_n, y, z_n) - CLU(b _table, x_n, y, z);
314 } else { //rz > rx && rx >= ry
315 c1_r = CLU(r_table, x_n, y, z_n) - CLU(r _table, x, y, z_n);
316 c2_r = CLU(r_table, x_n, y_n, z_n) - CLU (r_table, x_n, y, z_n);
317 c3_r = CLU(r_table, x, y, z_n) - c0_r;
318 c1_g = CLU(g_table, x_n, y, z_n) - CLU(g _table, x, y, z_n);
319 c2_g = CLU(g_table, x_n, y_n, z_n) - CLU (g_table, x_n, y, z_n);
320 c3_g = CLU(g_table, x, y, z_n) - c0_g;
321 c1_b = CLU(b_table, x_n, y, z_n) - CLU(b _table, x, y, z_n);
322 c2_b = CLU(b_table, x_n, y_n, z_n) - CLU (b_table, x_n, y, z_n);
323 c3_b = CLU(b_table, x, y, z_n) - c0_b;
324 }
325 }
326 } else {
327 if (rx >= rz) { //ry > rx && rx >= rz
328 c1_r = CLU(r_table, x_n, y_n, z) - CLU(r_table, x, y_n, z);
329 c2_r = CLU(r_table, x_n, y_n, z) - c0_r;
330 c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table , x_n, y_n, z);
331 c1_g = CLU(g_table, x_n, y_n, z) - CLU(g_table, x, y_n, z);
332 c2_g = CLU(g_table, x_n, y_n, z) - c0_g;
333 c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table , x_n, y_n, z);
334 c1_b = CLU(b_table, x_n, y_n, z) - CLU(b_table, x, y_n, z);
335 c2_b = CLU(b_table, x_n, y_n, z) - c0_b;
336 c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table , x_n, y_n, z);
337 } else {
338 if (ry >= rz) { //ry >= rz && rz > rx
339 c1_r = CLU(r_table, x_n, y_n, z_n) - CLU (r_table, x, y_n, z_n);
340 c2_r = CLU(r_table, x, y_n, z) - c0_r;
341 c3_r = CLU(r_table, x, y_n, z_n) - CLU(r _table, x, y_n, z);
342 c1_g = CLU(g_table, x_n, y_n, z_n) - CLU (g_table, x, y_n, z_n);
343 c2_g = CLU(g_table, x, y_n, z) - c0_g;
344 c3_g = CLU(g_table, x, y_n, z_n) - CLU(g _table, x, y_n, z);
345 c1_b = CLU(b_table, x_n, y_n, z_n) - CLU (b_table, x, y_n, z_n);
346 c2_b = CLU(b_table, x, y_n, z) - c0_b;
347 c3_b = CLU(b_table, x, y_n, z_n) - CLU(b _table, x, y_n, z);
348 } else { //rz > ry && ry > rx
349 c1_r = CLU(r_table, x_n, y_n, z_n) - CLU (r_table, x, y_n, z_n);
350 c2_r = CLU(r_table, x, y_n, z) - c0_r;
351 c3_r = CLU(r_table, x_n, y_n, z_n) - CLU (r_table, x_n, y_n, z);
352 c1_g = CLU(g_table, x_n, y_n, z_n) - CLU (g_table, x, y_n, z_n);
353 c2_g = CLU(g_table, x, y_n, z) - c0_g;
354 c3_g = CLU(g_table, x_n, y_n, z_n) - CLU (g_table, x_n, y_n, z);
355 c1_b = CLU(b_table, x_n, y_n, z_n) - CLU (b_table, x, y_n, z_n);
356 c2_b = CLU(b_table, x, y_n, z) - c0_b;
357 c3_b = CLU(b_table, x_n, y_n, z_n) - CLU (b_table, x_n, y_n, z);
358 }
359 }
360 }
361
362 clut_r = c0_r + c1_r*rx + c2_r*ry + c3_r*rz;
363 clut_g = c0_g + c1_g*rx + c2_g*ry + c3_g*rz;
364 clut_b = c0_b + c1_b*rx + c2_b*ry + c3_b*rz;
365
366 pcs_r = lut_interp_linear_float(clut_r,
367 transform->output_clut_table_r, transform->outpu t_clut_table_length);
368 pcs_g = lut_interp_linear_float(clut_g,
369 transform->output_clut_table_g, transform->outpu t_clut_table_length);
370 pcs_b = lut_interp_linear_float(clut_b,
371 transform->output_clut_table_b, transform->outpu t_clut_table_length);
372 *dest++ = clamp_float(pcs_r);
373 *dest++ = clamp_float(pcs_g);
374 *dest++ = clamp_float(pcs_b);
375 }
376 }
377 */
378
379 static void qcms_transform_module_gamma_table(struct qcms_modular_transform *tra nsform, float *src, float *dest, size_t length)
380 {
381 size_t i;
382 float out_r, out_g, out_b;
383 for (i = 0; i < length; i++) {
384 float in_r = *src++;
385 float in_g = *src++;
386 float in_b = *src++;
387
388 out_r = lut_interp_linear_float(in_r, transform->input_clut_tabl e_r, 256);
389 out_g = lut_interp_linear_float(in_g, transform->input_clut_tabl e_g, 256);
390 out_b = lut_interp_linear_float(in_b, transform->input_clut_tabl e_b, 256);
391
392 *dest++ = clamp_float(out_r);
393 *dest++ = clamp_float(out_g);
394 *dest++ = clamp_float(out_b);
395 }
396 }
397
398 static void qcms_transform_module_gamma_lut(struct qcms_modular_transform *trans form, float *src, float *dest, size_t length)
399 {
400 size_t i;
401 float out_r, out_g, out_b;
402 for (i = 0; i < length; i++) {
403 float in_r = *src++;
404 float in_g = *src++;
405 float in_b = *src++;
406
407 out_r = lut_interp_linear(in_r,
408 transform->output_gamma_lut_r, transform->output _gamma_lut_r_length);
409 out_g = lut_interp_linear(in_g,
410 transform->output_gamma_lut_g, transform->output _gamma_lut_g_length);
411 out_b = lut_interp_linear(in_b,
412 transform->output_gamma_lut_b, transform->output _gamma_lut_b_length);
413
414 *dest++ = clamp_float(out_r);
415 *dest++ = clamp_float(out_g);
416 *dest++ = clamp_float(out_b);
417 }
418 }
419
420 static void qcms_transform_module_matrix_translate(struct qcms_modular_transform *transform, float *src, float *dest, size_t length)
421 {
422 size_t i;
423 struct matrix mat;
424
425 /* store the results in column major mode
426 * this makes doing the multiplication with sse easier */
427 mat.m[0][0] = transform->matrix.m[0][0];
428 mat.m[1][0] = transform->matrix.m[0][1];
429 mat.m[2][0] = transform->matrix.m[0][2];
430 mat.m[0][1] = transform->matrix.m[1][0];
431 mat.m[1][1] = transform->matrix.m[1][1];
432 mat.m[2][1] = transform->matrix.m[1][2];
433 mat.m[0][2] = transform->matrix.m[2][0];
434 mat.m[1][2] = transform->matrix.m[2][1];
435 mat.m[2][2] = transform->matrix.m[2][2];
436
437 for (i = 0; i < length; i++) {
438 float in_r = *src++;
439 float in_g = *src++;
440 float in_b = *src++;
441
442 float out_r = mat.m[0][0]*in_r + mat.m[1][0]*in_g + mat.m[2][0]* in_b + transform->tx;
443 float out_g = mat.m[0][1]*in_r + mat.m[1][1]*in_g + mat.m[2][1]* in_b + transform->ty;
444 float out_b = mat.m[0][2]*in_r + mat.m[1][2]*in_g + mat.m[2][2]* in_b + transform->tz;
445
446 *dest++ = clamp_float(out_r);
447 *dest++ = clamp_float(out_g);
448 *dest++ = clamp_float(out_b);
449 }
450 }
451
452 static void qcms_transform_module_matrix(struct qcms_modular_transform *transfor m, float *src, float *dest, size_t length)
453 {
454 size_t i;
455 struct matrix mat;
456
457 /* store the results in column major mode
458 * this makes doing the multiplication with sse easier */
459 mat.m[0][0] = transform->matrix.m[0][0];
460 mat.m[1][0] = transform->matrix.m[0][1];
461 mat.m[2][0] = transform->matrix.m[0][2];
462 mat.m[0][1] = transform->matrix.m[1][0];
463 mat.m[1][1] = transform->matrix.m[1][1];
464 mat.m[2][1] = transform->matrix.m[1][2];
465 mat.m[0][2] = transform->matrix.m[2][0];
466 mat.m[1][2] = transform->matrix.m[2][1];
467 mat.m[2][2] = transform->matrix.m[2][2];
468
469 for (i = 0; i < length; i++) {
470 float in_r = *src++;
471 float in_g = *src++;
472 float in_b = *src++;
473
474 float out_r = mat.m[0][0]*in_r + mat.m[1][0]*in_g + mat.m[2][0]* in_b;
475 float out_g = mat.m[0][1]*in_r + mat.m[1][1]*in_g + mat.m[2][1]* in_b;
476 float out_b = mat.m[0][2]*in_r + mat.m[1][2]*in_g + mat.m[2][2]* in_b;
477
478 *dest++ = clamp_float(out_r);
479 *dest++ = clamp_float(out_g);
480 *dest++ = clamp_float(out_b);
481 }
482 }
483
484 static struct qcms_modular_transform* qcms_modular_transform_alloc() {
485 return calloc(1, sizeof(struct qcms_modular_transform));
486 }
487
488 static void qcms_modular_transform_release(struct qcms_modular_transform *transf orm)
489 {
490 struct qcms_modular_transform *next_transform;
491 while (transform != NULL) {
492 next_transform = transform->next_transform;
493 // clut may use a single block of memory.
494 // Perhaps we should remove this to simply the code.
495 if (transform->input_clut_table_r + transform->input_clut_table_ length == transform->input_clut_table_g && transform->input_clut_table_g + trans form->input_clut_table_length == transform->input_clut_table_b) {
496 if (transform->input_clut_table_r) free(transform->input _clut_table_r);
497 } else {
498 if (transform->input_clut_table_r) free(transform->input _clut_table_r);
499 if (transform->input_clut_table_g) free(transform->input _clut_table_g);
500 if (transform->input_clut_table_b) free(transform->input _clut_table_b);
501 }
502 if (transform->r_clut + 1 == transform->g_clut && transform->g_c lut + 1 == transform->b_clut) {
503 if (transform->r_clut) free(transform->r_clut);
504 } else {
505 if (transform->r_clut) free(transform->r_clut);
506 if (transform->g_clut) free(transform->g_clut);
507 if (transform->b_clut) free(transform->b_clut);
508 }
509 if (transform->output_clut_table_r + transform->output_clut_tabl e_length == transform->output_clut_table_g && transform->output_clut_table_g+ tr ansform->output_clut_table_length == transform->output_clut_table_b) {
510 if (transform->output_clut_table_r) free(transform->outp ut_clut_table_r);
511 } else {
512 if (transform->output_clut_table_r) free(transform->outp ut_clut_table_r);
513 if (transform->output_clut_table_g) free(transform->outp ut_clut_table_g);
514 if (transform->output_clut_table_b) free(transform->outp ut_clut_table_b);
515 }
516 if (transform->output_gamma_lut_r) free(transform->output_gamma_ lut_r);
517 if (transform->output_gamma_lut_g) free(transform->output_gamma_ lut_g);
518 if (transform->output_gamma_lut_b) free(transform->output_gamma_ lut_b);
519 free(transform);
520 transform = next_transform;
521 }
522 }
523
524 /* Set transform to be the next element in the linked list. */
525 static void append_transform(struct qcms_modular_transform *transform, struct qc ms_modular_transform ***next_transform)
526 {
527 **next_transform = transform;
528 while (transform) {
529 *next_transform = &(transform->next_transform);
530 transform = transform->next_transform;
531 }
532 }
533
534 /* reverse the transformation list (used by mBA) */
535 static struct qcms_modular_transform* reverse_transform(struct qcms_modular_tran sform *transform)
536 {
537 struct qcms_modular_transform *prev_transform = NULL;
538 while (transform != NULL) {
539 struct qcms_modular_transform *next_transform = transform->next_ transform;
540 transform->next_transform = prev_transform;
541 prev_transform = transform;
542 transform = next_transform;
543 }
544
545 return prev_transform;
546 }
547
548 #define EMPTY_TRANSFORM_LIST NULL
549 static struct qcms_modular_transform* qcms_modular_transform_create_mAB(struct l utmABType *lut)
550 {
551 struct qcms_modular_transform *first_transform = NULL;
552 struct qcms_modular_transform **next_transform = &first_transform;
553 struct qcms_modular_transform *transform = NULL;
554
555 if (lut->a_curves[0] != NULL) {
556 size_t clut_length;
557 float *clut;
558
559 // If the A curve is present this also implies the
560 // presence of a CLUT.
561 if (!lut->clut_table)
562 goto fail;
563
564 // Prepare A curve.
565 transform = qcms_modular_transform_alloc();
566 if (!transform)
567 goto fail;
568 append_transform(transform, &next_transform);
569 transform->input_clut_table_r = build_input_gamma_table(lut->a_c urves[0]);
570 transform->input_clut_table_g = build_input_gamma_table(lut->a_c urves[1]);
571 transform->input_clut_table_b = build_input_gamma_table(lut->a_c urves[2]);
572 transform->transform_module_fn = qcms_transform_module_gamma_tab le;
573 if (lut->num_grid_points[0] != lut->num_grid_points[1] ||
574 lut->num_grid_points[1] != lut->num_grid_points[2] ) {
575 //XXX: We don't currently support clut that are not squa red!
576 goto fail;
577 }
578
579 // Prepare CLUT
580 transform = qcms_modular_transform_alloc();
581 if (!transform)
582 goto fail;
583 append_transform(transform, &next_transform);
584 clut_length = sizeof(float)*pow(lut->num_grid_points[0], 3)*3;
585 clut = malloc(clut_length);
586 if (!clut)
587 goto fail;
588 memcpy(clut, lut->clut_table, clut_length);
589 transform->r_clut = clut + 0;
590 transform->g_clut = clut + 1;
591 transform->b_clut = clut + 2;
592 transform->grid_size = lut->num_grid_points[0];
593 transform->transform_module_fn = qcms_transform_module_clut_only ;
594 }
595 if (lut->m_curves[0] != NULL) {
596 // M curve imples the presence of a Matrix
597
598 // Prepare M curve
599 transform = qcms_modular_transform_alloc();
600 if (!transform)
601 goto fail;
602 append_transform(transform, &next_transform);
603 transform->input_clut_table_r = build_input_gamma_table(lut->m_c urves[0]);
604 transform->input_clut_table_g = build_input_gamma_table(lut->m_c urves[1]);
605 transform->input_clut_table_b = build_input_gamma_table(lut->m_c urves[2]);
606 transform->transform_module_fn = qcms_transform_module_gamma_tab le;
607
608 // Prepare Matrix
609 transform = qcms_modular_transform_alloc();
610 if (!transform)
611 goto fail;
612 append_transform(transform, &next_transform);
613 transform->matrix = build_mAB_matrix(lut);
614 if (transform->matrix.invalid)
615 goto fail;
616 transform->tx = s15Fixed16Number_to_float(lut->e03);
617 transform->ty = s15Fixed16Number_to_float(lut->e13);
618 transform->tz = s15Fixed16Number_to_float(lut->e23);
619 transform->transform_module_fn = qcms_transform_module_matrix_tr anslate;
620 }
621 if (lut->b_curves[0] != NULL) {
622 // Prepare B curve
623 transform = qcms_modular_transform_alloc();
624 if (!transform)
625 goto fail;
626 append_transform(transform, &next_transform);
627 transform->input_clut_table_r = build_input_gamma_table(lut->b_c urves[0]);
628 transform->input_clut_table_g = build_input_gamma_table(lut->b_c urves[1]);
629 transform->input_clut_table_b = build_input_gamma_table(lut->b_c urves[2]);
630 transform->transform_module_fn = qcms_transform_module_gamma_tab le;
631 } else {
632 // B curve is mandatory
633 goto fail;
634 }
635
636 if (lut->reversed) {
637 // mBA are identical to mAB except that the transformation order
638 // is reversed
639 first_transform = reverse_transform(first_transform);
640 }
641
642 return first_transform;
643 fail:
644 qcms_modular_transform_release(first_transform);
645 return NULL;
646 }
647
648 static struct qcms_modular_transform* qcms_modular_transform_create_lut(struct l utType *lut)
649 {
650 struct qcms_modular_transform *first_transform = NULL;
651 struct qcms_modular_transform **next_transform = &first_transform;
652 struct qcms_modular_transform *transform = NULL;
653
654 size_t in_curve_len, clut_length, out_curve_len;
655 float *in_curves, *clut, *out_curves;
656
657 // Prepare Matrix
658 transform = qcms_modular_transform_alloc();
659 if (!transform)
660 goto fail;
661 append_transform(transform, &next_transform);
662 transform->matrix = build_lut_matrix(lut);
663 if (transform->matrix.invalid)
664 goto fail;
665 transform->transform_module_fn = qcms_transform_module_matrix;
666
667 // Prepare input curves
668 transform = qcms_modular_transform_alloc();
669 if (!transform)
670 goto fail;
671 append_transform(transform, &next_transform);
672 in_curve_len = sizeof(float)*lut->num_input_table_entries * 3;
673 in_curves = malloc(in_curve_len);
674 if (!in_curves)
675 goto fail;
676 memcpy(in_curves, lut->input_table, in_curve_len);
677 transform->input_clut_table_r = in_curves + lut->num_input_table_entries * 0;
678 transform->input_clut_table_g = in_curves + lut->num_input_table_entries * 1;
679 transform->input_clut_table_b = in_curves + lut->num_input_table_entries * 2;
680 transform->input_clut_table_length = lut->num_input_table_entries;
681
682 // Prepare table
683 clut_length = sizeof(float)*pow(lut->num_clut_grid_points, 3)*3;
684 clut = malloc(clut_length);
685 if (!clut)
686 goto fail;
687 memcpy(clut, lut->clut_table, clut_length);
688 transform->r_clut = clut + 0;
689 transform->g_clut = clut + 1;
690 transform->b_clut = clut + 2;
691 transform->grid_size = lut->num_clut_grid_points;
692
693 // Prepare output curves
694 out_curve_len = sizeof(float) * lut->num_output_table_entries * 3;
695 out_curves = malloc(out_curve_len);
696 if (!out_curves)
697 goto fail;
698 memcpy(out_curves, lut->output_table, out_curve_len);
699 transform->output_clut_table_r = out_curves + lut->num_output_table_entr ies * 0;
700 transform->output_clut_table_g = out_curves + lut->num_output_table_entr ies * 1;
701 transform->output_clut_table_b = out_curves + lut->num_output_table_entr ies * 2;
702 transform->output_clut_table_length = lut->num_output_table_entries;
703 transform->transform_module_fn = qcms_transform_module_clut;
704
705 return first_transform;
706 fail:
707 qcms_modular_transform_release(first_transform);
708 return NULL;
709 }
710
711 struct qcms_modular_transform* qcms_modular_transform_create_input(qcms_profile *in)
712 {
713 struct qcms_modular_transform *first_transform = NULL;
714 struct qcms_modular_transform **next_transform = &first_transform;
715
716 if (in->A2B0) {
717 struct qcms_modular_transform *lut_transform;
718 lut_transform = qcms_modular_transform_create_lut(in->A2B0);
719 if (!lut_transform)
720 goto fail;
721 append_transform(lut_transform, &next_transform);
722 } else if (in->mAB && in->mAB->num_in_channels == 3 && in->mAB->num_out_ channels == 3) {
723 struct qcms_modular_transform *mAB_transform;
724 mAB_transform = qcms_modular_transform_create_mAB(in->mAB);
725 if (!mAB_transform)
726 goto fail;
727 append_transform(mAB_transform, &next_transform);
728
729 } else {
730 struct qcms_modular_transform *transform;
731
732 transform = qcms_modular_transform_alloc();
733 if (!transform)
734 goto fail;
735 append_transform(transform, &next_transform);
736 transform->input_clut_table_r = build_input_gamma_table(in->redT RC);
737 transform->input_clut_table_g = build_input_gamma_table(in->gree nTRC);
738 transform->input_clut_table_b = build_input_gamma_table(in->blue TRC);
739 transform->transform_module_fn = qcms_transform_module_gamma_tab le;
740 if (!transform->input_clut_table_r || !transform->input_clut_tab le_g ||
741 !transform->input_clut_table_b) {
742 goto fail;
743 }
744
745 transform = qcms_modular_transform_alloc();
746 if (!transform)
747 goto fail;
748 append_transform(transform, &next_transform);
749 transform->matrix.m[0][0] = 1/1.999969482421875f;
750 transform->matrix.m[0][1] = 0.f;
751 transform->matrix.m[0][2] = 0.f;
752 transform->matrix.m[1][0] = 0.f;
753 transform->matrix.m[1][1] = 1/1.999969482421875f;
754 transform->matrix.m[1][2] = 0.f;
755 transform->matrix.m[2][0] = 0.f;
756 transform->matrix.m[2][1] = 0.f;
757 transform->matrix.m[2][2] = 1/1.999969482421875f;
758 transform->matrix.invalid = false;
759 transform->transform_module_fn = qcms_transform_module_matrix;
760
761 transform = qcms_modular_transform_alloc();
762 if (!transform)
763 goto fail;
764 append_transform(transform, &next_transform);
765 transform->matrix = build_colorant_matrix(in);
766 transform->transform_module_fn = qcms_transform_module_matrix;
767 }
768
769 return first_transform;
770 fail:
771 qcms_modular_transform_release(first_transform);
772 return EMPTY_TRANSFORM_LIST;
773 }
774 static struct qcms_modular_transform* qcms_modular_transform_create_output(qcms_ profile *out)
775 {
776 struct qcms_modular_transform *first_transform = NULL;
777 struct qcms_modular_transform **next_transform = &first_transform;
778
779 if (out->B2A0) {
780 struct qcms_modular_transform *lut_transform;
781 lut_transform = qcms_modular_transform_create_lut(out->B2A0);
782 if (!lut_transform)
783 goto fail;
784 append_transform(lut_transform, &next_transform);
785 } else if (out->mBA && out->mBA->num_in_channels == 3 && out->mBA->num_o ut_channels == 3) {
786 struct qcms_modular_transform *lut_transform;
787 lut_transform = qcms_modular_transform_create_mAB(out->mBA);
788 if (!lut_transform)
789 goto fail;
790 append_transform(lut_transform, &next_transform);
791 } else if (out->redTRC && out->greenTRC && out->blueTRC) {
792 struct qcms_modular_transform *transform;
793
794 transform = qcms_modular_transform_alloc();
795 if (!transform)
796 goto fail;
797 append_transform(transform, &next_transform);
798 transform->matrix = matrix_invert(build_colorant_matrix(out));
799 transform->transform_module_fn = qcms_transform_module_matrix;
800
801 transform = qcms_modular_transform_alloc();
802 if (!transform)
803 goto fail;
804 append_transform(transform, &next_transform);
805 transform->matrix.m[0][0] = 1.999969482421875f;
806 transform->matrix.m[0][1] = 0.f;
807 transform->matrix.m[0][2] = 0.f;
808 transform->matrix.m[1][0] = 0.f;
809 transform->matrix.m[1][1] = 1.999969482421875f;
810 transform->matrix.m[1][2] = 0.f;
811 transform->matrix.m[2][0] = 0.f;
812 transform->matrix.m[2][1] = 0.f;
813 transform->matrix.m[2][2] = 1.999969482421875f;
814 transform->matrix.invalid = false;
815 transform->transform_module_fn = qcms_transform_module_matrix;
816
817 transform = qcms_modular_transform_alloc();
818 if (!transform)
819 goto fail;
820 append_transform(transform, &next_transform);
821 build_output_lut(out->redTRC, &transform->output_gamma_lut_r,
822 &transform->output_gamma_lut_r_length);
823 build_output_lut(out->greenTRC, &transform->output_gamma_lut_g,
824 &transform->output_gamma_lut_g_length);
825 build_output_lut(out->blueTRC, &transform->output_gamma_lut_b,
826 &transform->output_gamma_lut_b_length);
827 transform->transform_module_fn = qcms_transform_module_gamma_lut ;
828
829 if (!transform->output_gamma_lut_r || !transform->output_gamma_l ut_g ||
830 !transform->output_gamma_lut_b) {
831 goto fail;
832 }
833 } else {
834 assert(0 && "Unsupported output profile workflow.");
835 return NULL;
836 }
837
838 return first_transform;
839 fail:
840 qcms_modular_transform_release(first_transform);
841 return EMPTY_TRANSFORM_LIST;
842 }
843
844 /* Not Completed
845 // Simplify the transformation chain to an equivalent transformation chain
846 static struct qcms_modular_transform* qcms_modular_transform_reduce(struct qcms_ modular_transform *transform)
847 {
848 struct qcms_modular_transform *first_transform = NULL;
849 struct qcms_modular_transform *curr_trans = transform;
850 struct qcms_modular_transform *prev_trans = NULL;
851 while (curr_trans) {
852 struct qcms_modular_transform *next_trans = curr_trans->next_tra nsform;
853 if (curr_trans->transform_module_fn == qcms_transform_module_mat rix) {
854 if (next_trans && next_trans->transform_module_fn == qcm s_transform_module_matrix) {
855 curr_trans->matrix = matrix_multiply(curr_trans- >matrix, next_trans->matrix);
856 goto remove_next;
857 }
858 }
859 if (curr_trans->transform_module_fn == qcms_transform_module_gam ma_table) {
860 bool isLinear = true;
861 uint16_t i;
862 for (i = 0; isLinear && i < 256; i++) {
863 isLinear &= (int)(curr_trans->input_clut_table_r [i] * 255) == i;
864 isLinear &= (int)(curr_trans->input_clut_table_g [i] * 255) == i;
865 isLinear &= (int)(curr_trans->input_clut_table_b [i] * 255) == i;
866 }
867 goto remove_current;
868 }
869
870 next_transform:
871 if (!next_trans) break;
872 prev_trans = curr_trans;
873 curr_trans = next_trans;
874 continue;
875 remove_current:
876 if (curr_trans == transform) {
877 //Update head
878 transform = next_trans;
879 } else {
880 prev_trans->next_transform = next_trans;
881 }
882 curr_trans->next_transform = NULL;
883 qcms_modular_transform_release(curr_trans);
884 //return transform;
885 return qcms_modular_transform_reduce(transform);
886 remove_next:
887 curr_trans->next_transform = next_trans->next_transform;
888 next_trans->next_transform = NULL;
889 qcms_modular_transform_release(next_trans);
890 continue;
891 }
892 return transform;
893 }
894 */
895
896 static struct qcms_modular_transform* qcms_modular_transform_create(qcms_profile *in, qcms_profile *out)
897 {
898 struct qcms_modular_transform *first_transform = NULL;
899 struct qcms_modular_transform **next_transform = &first_transform;
900 qcms_bool transform_to_pcs_xyz_only = (out == NULL);
901
902 if (in->color_space == RGB_SIGNATURE) {
903 struct qcms_modular_transform* rgb_to_pcs;
904 rgb_to_pcs = qcms_modular_transform_create_input(in);
905 if (!rgb_to_pcs)
906 goto fail;
907 append_transform(rgb_to_pcs, &next_transform);
908 } else {
909 assert(0 && "input color space not supported");
910 goto fail;
911 }
912
913 if (in->pcs == LAB_SIGNATURE && (transform_to_pcs_xyz_only || out->pcs = = XYZ_SIGNATURE)) {
914 struct qcms_modular_transform* lab_to_pcs;
915 lab_to_pcs = qcms_modular_transform_alloc();
916 if (!lab_to_pcs)
917 goto fail;
918 append_transform(lab_to_pcs, &next_transform);
919 lab_to_pcs->transform_module_fn = qcms_transform_module_LAB_to_X YZ;
920 }
921
922 if (transform_to_pcs_xyz_only)
923 return first_transform;
924
925 // This does not improve accuracy in practice, something is wrong here.
926 //if (in->chromaticAdaption.invalid == false) {
927 // struct qcms_modular_transform* chromaticAdaption;
928 // chromaticAdaption = qcms_modular_transform_alloc();
929 // if (!chromaticAdaption)
930 // goto fail;
931 // append_transform(chromaticAdaption, &next_transform);
932 // chromaticAdaption->matrix = matrix_invert(in->chromaticAdaption) ;
933 // chromaticAdaption->transform_module_fn = qcms_transform_module_m atrix;
934 //}
935
936 if (in->pcs == XYZ_SIGNATURE && out->pcs == LAB_SIGNATURE) {
937 struct qcms_modular_transform* pcs_to_lab;
938 pcs_to_lab = qcms_modular_transform_alloc();
939 if (!pcs_to_lab)
940 goto fail;
941 append_transform(pcs_to_lab, &next_transform);
942 pcs_to_lab->transform_module_fn = qcms_transform_module_XYZ_to_L AB;
943 }
944
945 if (out->color_space == RGB_SIGNATURE) {
946 struct qcms_modular_transform* pcs_to_rgb;
947 pcs_to_rgb = qcms_modular_transform_create_output(out);
948 if (!pcs_to_rgb)
949 goto fail;
950 append_transform(pcs_to_rgb, &next_transform);
951 } else {
952 assert(0 && "output color space not supported");
953 goto fail;
954 }
955 // Not Completed
956 //return qcms_modular_transform_reduce(first_transform);
957 return first_transform;
958 fail:
959 qcms_modular_transform_release(first_transform);
960 return EMPTY_TRANSFORM_LIST;
961 }
962
963 static float* qcms_modular_transform_data(struct qcms_modular_transform *transfo rm, float *src, float *dest, size_t len)
964 {
965 while (transform != NULL) {
966 // Keep swaping src/dest when performing a transform to use less memory.
967 float *new_src = dest;
968 const transform_module_fn_t transform_fn = transform->transform_ module_fn;
969 if (transform_fn != qcms_transform_module_gamma_table &&
970 transform_fn != qcms_transform_module_gamma_lut &&
971 transform_fn != qcms_transform_module_clut &&
972 transform_fn != qcms_transform_module_clut_only &&
973 transform_fn != qcms_transform_module_matrix &&
974 transform_fn != qcms_transform_module_matrix_translate &&
975 transform_fn != qcms_transform_module_LAB_to_XYZ &&
976 transform_fn != qcms_transform_module_XYZ_to_LAB) {
977 assert(0 && "Unsupported transform module");
978 return NULL;
979 }
980 transform->transform_module_fn(transform,src,dest,len);
981 dest = src;
982 src = new_src;
983 transform = transform->next_transform;
984 }
985 // The results end up in the src buffer because of the switching
986 return src;
987 }
988
989 float* qcms_chain_transform(qcms_profile *in, qcms_profile *out, float *src, flo at *dest, size_t lutSize)
990 {
991 struct qcms_modular_transform *transform_list = qcms_modular_transform_c reate(in, out);
992 if (transform_list != NULL) {
993 float *lut = qcms_modular_transform_data(transform_list, src, de st, lutSize/3);
994 qcms_modular_transform_release(transform_list);
995 return lut;
996 }
997 return NULL;
998 }
999
1000 qcms_bool qcms_profile_white_transform(qcms_profile *profile, float XYZ[3])
1001 {
1002 const float inverse_internal_scale = 1.999969482421875f;
1003
1004 // Set the output profile to NULL to request a color transform to PCS XY Z only.
1005 struct qcms_modular_transform *transform_list = qcms_modular_transform_c reate(profile, NULL);
1006
1007 // Now calculate how the profile transforms white input color to PCS XYZ space.
1008 if (transform_list != NULL) {
1009 XYZ[0] = XYZ[1] = XYZ[2] = 1.0f; // white input
1010 qcms_modular_transform_data(transform_list, XYZ, XYZ, 1);
1011 // qcms_modular_transform_create internally scales input by 1/1. 999969482421875f
1012 // but no qcms changelog describes why / how that number was cho osen. junov@ "it
1013 // might be related to the epsilon of the fixed-point type 2*(1- 1/(2^16)), but
1014 // there is no explanation, which is disconcerting." Meanwhile, undo the internal
1015 // scaling so we return a normalized CIEXYZ value viz., where Y is scaled to 1.0.
1016 // A properly created color profile should produce Y=~1.0 in PCS XYZ with white
1017 // input (the D50 test). If it does not, then the profile is lik ely bogus.
1018 XYZ[0] *= inverse_internal_scale;
1019 XYZ[1] *= inverse_internal_scale;
1020 XYZ[2] *= inverse_internal_scale;
1021 qcms_modular_transform_release(transform_list);
1022 return true;
1023 }
1024
1025 return false;
1026 }
OLDNEW
« no previous file with comments | « third_party/qcms/src/chain.h ('k') | third_party/qcms/src/empty.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698