Line data Source code
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 Software
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 0 : static struct matrix build_lut_matrix(struct lutType *lut)
33 : {
34 : struct matrix result;
35 0 : if (lut) {
36 0 : result.m[0][0] = s15Fixed16Number_to_float(lut->e00);
37 0 : result.m[0][1] = s15Fixed16Number_to_float(lut->e01);
38 0 : result.m[0][2] = s15Fixed16Number_to_float(lut->e02);
39 0 : result.m[1][0] = s15Fixed16Number_to_float(lut->e10);
40 0 : result.m[1][1] = s15Fixed16Number_to_float(lut->e11);
41 0 : result.m[1][2] = s15Fixed16Number_to_float(lut->e12);
42 0 : result.m[2][0] = s15Fixed16Number_to_float(lut->e20);
43 0 : result.m[2][1] = s15Fixed16Number_to_float(lut->e21);
44 0 : result.m[2][2] = s15Fixed16Number_to_float(lut->e22);
45 0 : result.invalid = false;
46 : } else {
47 0 : memset(&result, 0, sizeof(struct matrix));
48 0 : result.invalid = true;
49 : }
50 0 : return result;
51 : }
52 :
53 0 : static struct matrix build_mAB_matrix(struct lutmABType *lut)
54 : {
55 : struct matrix result;
56 0 : if (lut) {
57 0 : result.m[0][0] = s15Fixed16Number_to_float(lut->e00);
58 0 : result.m[0][1] = s15Fixed16Number_to_float(lut->e01);
59 0 : result.m[0][2] = s15Fixed16Number_to_float(lut->e02);
60 0 : result.m[1][0] = s15Fixed16Number_to_float(lut->e10);
61 0 : result.m[1][1] = s15Fixed16Number_to_float(lut->e11);
62 0 : result.m[1][2] = s15Fixed16Number_to_float(lut->e12);
63 0 : result.m[2][0] = s15Fixed16Number_to_float(lut->e20);
64 0 : result.m[2][1] = s15Fixed16Number_to_float(lut->e21);
65 0 : result.m[2][2] = s15Fixed16Number_to_float(lut->e22);
66 0 : result.invalid = false;
67 : } else {
68 0 : memset(&result, 0, sizeof(struct matrix));
69 0 : result.invalid = true;
70 : }
71 0 : 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 0 : static void qcms_transform_module_LAB_to_XYZ(struct qcms_modular_transform *transform, float *src, float *dest, size_t length)
78 : {
79 : size_t i;
80 : // lcms: D50 XYZ values
81 0 : float WhitePointX = 0.9642f;
82 0 : float WhitePointY = 1.0f;
83 0 : float WhitePointZ = 0.8249f;
84 0 : for (i = 0; i < length; i++) {
85 0 : float device_L = *src++ * 100.0f;
86 0 : float device_a = *src++ * 255.0f - 128.0f;
87 0 : float device_b = *src++ * 255.0f - 128.0f;
88 0 : float y = (device_L + 16.0f) / 116.0f;
89 :
90 0 : float X = f_1((y + 0.002f * device_a)) * WhitePointX;
91 0 : float Y = f_1(y) * WhitePointY;
92 0 : float Z = f_1((y - 0.005f * device_b)) * WhitePointZ;
93 0 : *dest++ = X / (1.0 + 32767.0/32768.0);
94 0 : *dest++ = Y / (1.0 + 32767.0/32768.0);
95 0 : *dest++ = Z / (1.0 + 32767.0/32768.0);
96 : }
97 0 : }
98 :
99 : //Based on lcms cmsXYZ2Lab
100 0 : static void qcms_transform_module_XYZ_to_LAB(struct qcms_modular_transform *transform, float *src, float *dest, size_t length)
101 : {
102 : size_t i;
103 : // lcms: D50 XYZ values
104 0 : float WhitePointX = 0.9642f;
105 0 : float WhitePointY = 1.0f;
106 0 : float WhitePointZ = 0.8249f;
107 0 : for (i = 0; i < length; i++) {
108 0 : float device_x = *src++ * (1.0 + 32767.0/32768.0) / WhitePointX;
109 0 : float device_y = *src++ * (1.0 + 32767.0/32768.0) / WhitePointY;
110 0 : float device_z = *src++ * (1.0 + 32767.0/32768.0) / WhitePointZ;
111 :
112 0 : float fx = f(device_x);
113 0 : float fy = f(device_y);
114 0 : float fz = f(device_z);
115 :
116 0 : float L = 116.0f*fy - 16.0f;
117 0 : float a = 500.0f*(fx - fy);
118 0 : float b = 200.0f*(fy - fz);
119 0 : *dest++ = L / 100.0f;
120 0 : *dest++ = (a+128.0f) / 255.0f;
121 0 : *dest++ = (b+128.0f) / 255.0f;
122 : }
123 :
124 0 : }
125 :
126 0 : static void qcms_transform_module_clut_only(struct qcms_modular_transform *transform, float *src, float *dest, size_t length)
127 : {
128 : size_t i;
129 0 : int xy_len = 1;
130 0 : int x_len = transform->grid_size;
131 0 : int len = x_len * x_len;
132 0 : float* r_table = transform->r_clut;
133 0 : float* g_table = transform->g_clut;
134 0 : float* b_table = transform->b_clut;
135 :
136 0 : for (i = 0; i < length; i++) {
137 0 : assert(transform->grid_size >= 1);
138 :
139 0 : float linear_r = *src++;
140 0 : float linear_g = *src++;
141 0 : float linear_b = *src++;
142 :
143 0 : int x = floorf(linear_r * (transform->grid_size-1));
144 0 : int y = floorf(linear_g * (transform->grid_size-1));
145 0 : int z = floorf(linear_b * (transform->grid_size-1));
146 0 : int x_n = ceilf(linear_r * (transform->grid_size-1));
147 0 : int y_n = ceilf(linear_g * (transform->grid_size-1));
148 0 : int z_n = ceilf(linear_b * (transform->grid_size-1));
149 0 : float x_d = linear_r * (transform->grid_size-1) - x;
150 0 : float y_d = linear_g * (transform->grid_size-1) - y;
151 0 : float z_d = linear_b * (transform->grid_size-1) - z;
152 :
153 0 : float r_x1 = lerp(CLU(r_table,x,y,z), CLU(r_table,x_n,y,z), x_d);
154 0 : float r_x2 = lerp(CLU(r_table,x,y_n,z), CLU(r_table,x_n,y_n,z), x_d);
155 0 : float r_y1 = lerp(r_x1, r_x2, y_d);
156 0 : float r_x3 = lerp(CLU(r_table,x,y,z_n), CLU(r_table,x_n,y,z_n), x_d);
157 0 : float r_x4 = lerp(CLU(r_table,x,y_n,z_n), CLU(r_table,x_n,y_n,z_n), x_d);
158 0 : float r_y2 = lerp(r_x3, r_x4, y_d);
159 0 : float clut_r = lerp(r_y1, r_y2, z_d);
160 :
161 0 : float g_x1 = lerp(CLU(g_table,x,y,z), CLU(g_table,x_n,y,z), x_d);
162 0 : float g_x2 = lerp(CLU(g_table,x,y_n,z), CLU(g_table,x_n,y_n,z), x_d);
163 0 : float g_y1 = lerp(g_x1, g_x2, y_d);
164 0 : float g_x3 = lerp(CLU(g_table,x,y,z_n), CLU(g_table,x_n,y,z_n), x_d);
165 0 : float g_x4 = lerp(CLU(g_table,x,y_n,z_n), CLU(g_table,x_n,y_n,z_n), x_d);
166 0 : float g_y2 = lerp(g_x3, g_x4, y_d);
167 0 : float clut_g = lerp(g_y1, g_y2, z_d);
168 :
169 0 : float b_x1 = lerp(CLU(b_table,x,y,z), CLU(b_table,x_n,y,z), x_d);
170 0 : float b_x2 = lerp(CLU(b_table,x,y_n,z), CLU(b_table,x_n,y_n,z), x_d);
171 0 : float b_y1 = lerp(b_x1, b_x2, y_d);
172 0 : float b_x3 = lerp(CLU(b_table,x,y,z_n), CLU(b_table,x_n,y,z_n), x_d);
173 0 : float b_x4 = lerp(CLU(b_table,x,y_n,z_n), CLU(b_table,x_n,y_n,z_n), x_d);
174 0 : float b_y2 = lerp(b_x3, b_x4, y_d);
175 0 : float clut_b = lerp(b_y1, b_y2, z_d);
176 :
177 0 : *dest++ = clamp_float(clut_r);
178 0 : *dest++ = clamp_float(clut_g);
179 0 : *dest++ = clamp_float(clut_b);
180 : }
181 0 : }
182 :
183 0 : static void qcms_transform_module_clut(struct qcms_modular_transform *transform, float *src, float *dest, size_t length)
184 : {
185 : size_t i;
186 0 : int xy_len = 1;
187 0 : int x_len = transform->grid_size;
188 0 : int len = x_len * x_len;
189 0 : float* r_table = transform->r_clut;
190 0 : float* g_table = transform->g_clut;
191 0 : float* b_table = transform->b_clut;
192 0 : for (i = 0; i < length; i++) {
193 0 : assert(transform->grid_size >= 1);
194 :
195 0 : float device_r = *src++;
196 0 : float device_g = *src++;
197 0 : float device_b = *src++;
198 0 : float linear_r = lut_interp_linear_float(device_r,
199 0 : transform->input_clut_table_r, transform->input_clut_table_length);
200 0 : float linear_g = lut_interp_linear_float(device_g,
201 0 : transform->input_clut_table_g, transform->input_clut_table_length);
202 0 : float linear_b = lut_interp_linear_float(device_b,
203 0 : transform->input_clut_table_b, transform->input_clut_table_length);
204 :
205 0 : int x = floorf(linear_r * (transform->grid_size-1));
206 0 : int y = floorf(linear_g * (transform->grid_size-1));
207 0 : int z = floorf(linear_b * (transform->grid_size-1));
208 0 : int x_n = ceilf(linear_r * (transform->grid_size-1));
209 0 : int y_n = ceilf(linear_g * (transform->grid_size-1));
210 0 : int z_n = ceilf(linear_b * (transform->grid_size-1));
211 0 : float x_d = linear_r * (transform->grid_size-1) - x;
212 0 : float y_d = linear_g * (transform->grid_size-1) - y;
213 0 : float z_d = linear_b * (transform->grid_size-1) - z;
214 :
215 0 : float r_x1 = lerp(CLU(r_table,x,y,z), CLU(r_table,x_n,y,z), x_d);
216 0 : float r_x2 = lerp(CLU(r_table,x,y_n,z), CLU(r_table,x_n,y_n,z), x_d);
217 0 : float r_y1 = lerp(r_x1, r_x2, y_d);
218 0 : float r_x3 = lerp(CLU(r_table,x,y,z_n), CLU(r_table,x_n,y,z_n), x_d);
219 0 : float r_x4 = lerp(CLU(r_table,x,y_n,z_n), CLU(r_table,x_n,y_n,z_n), x_d);
220 0 : float r_y2 = lerp(r_x3, r_x4, y_d);
221 0 : float clut_r = lerp(r_y1, r_y2, z_d);
222 :
223 0 : float g_x1 = lerp(CLU(g_table,x,y,z), CLU(g_table,x_n,y,z), x_d);
224 0 : float g_x2 = lerp(CLU(g_table,x,y_n,z), CLU(g_table,x_n,y_n,z), x_d);
225 0 : float g_y1 = lerp(g_x1, g_x2, y_d);
226 0 : float g_x3 = lerp(CLU(g_table,x,y,z_n), CLU(g_table,x_n,y,z_n), x_d);
227 0 : float g_x4 = lerp(CLU(g_table,x,y_n,z_n), CLU(g_table,x_n,y_n,z_n), x_d);
228 0 : float g_y2 = lerp(g_x3, g_x4, y_d);
229 0 : float clut_g = lerp(g_y1, g_y2, z_d);
230 :
231 0 : float b_x1 = lerp(CLU(b_table,x,y,z), CLU(b_table,x_n,y,z), x_d);
232 0 : float b_x2 = lerp(CLU(b_table,x,y_n,z), CLU(b_table,x_n,y_n,z), x_d);
233 0 : float b_y1 = lerp(b_x1, b_x2, y_d);
234 0 : float b_x3 = lerp(CLU(b_table,x,y,z_n), CLU(b_table,x_n,y,z_n), x_d);
235 0 : float b_x4 = lerp(CLU(b_table,x,y_n,z_n), CLU(b_table,x_n,y_n,z_n), x_d);
236 0 : float b_y2 = lerp(b_x3, b_x4, y_d);
237 0 : float clut_b = lerp(b_y1, b_y2, z_d);
238 :
239 0 : float pcs_r = lut_interp_linear_float(clut_r,
240 0 : transform->output_clut_table_r, transform->output_clut_table_length);
241 0 : float pcs_g = lut_interp_linear_float(clut_g,
242 0 : transform->output_clut_table_g, transform->output_clut_table_length);
243 0 : float pcs_b = lut_interp_linear_float(clut_b,
244 0 : transform->output_clut_table_b, transform->output_clut_table_length);
245 :
246 0 : *dest++ = clamp_float(pcs_r);
247 0 : *dest++ = clamp_float(pcs_g);
248 0 : *dest++ = clamp_float(pcs_b);
249 : }
250 0 : }
251 :
252 : /* NOT USED
253 : static void qcms_transform_module_tetra_clut(struct qcms_modular_transform *transform, float *src, float *dest, size_t length)
254 : {
255 : size_t i;
256 : int xy_len = 1;
257 : int x_len = transform->grid_size;
258 : int len = x_len * x_len;
259 : float* r_table = transform->r_clut;
260 : float* g_table = transform->g_clut;
261 : float* b_table = transform->b_clut;
262 : float c0_r, c1_r, c2_r, c3_r;
263 : float c0_g, c1_g, c2_g, c3_g;
264 : float c0_b, c1_b, c2_b, c3_b;
265 : float clut_r, clut_g, clut_b;
266 : float pcs_r, pcs_g, pcs_b;
267 : for (i = 0; i < length; i++) {
268 : float device_r = *src++;
269 : float device_g = *src++;
270 : float device_b = *src++;
271 : float linear_r = lut_interp_linear_float(device_r,
272 : transform->input_clut_table_r, transform->input_clut_table_length);
273 : float linear_g = lut_interp_linear_float(device_g,
274 : transform->input_clut_table_g, transform->input_clut_table_length);
275 : float linear_b = lut_interp_linear_float(device_b,
276 : transform->input_clut_table_b, transform->input_clut_table_length);
277 :
278 : int x = floorf(linear_r * (transform->grid_size-1));
279 : int y = floorf(linear_g * (transform->grid_size-1));
280 : int z = floorf(linear_b * (transform->grid_size-1));
281 : int x_n = ceilf(linear_r * (transform->grid_size-1));
282 : int y_n = ceilf(linear_g * (transform->grid_size-1));
283 : int z_n = ceilf(linear_b * (transform->grid_size-1));
284 : float rx = linear_r * (transform->grid_size-1) - x;
285 : float ry = linear_g * (transform->grid_size-1) - y;
286 : float rz = linear_b * (transform->grid_size-1) - z;
287 :
288 : c0_r = CLU(r_table, x, y, z);
289 : c0_g = CLU(g_table, x, y, z);
290 : c0_b = CLU(b_table, x, y, z);
291 : if( rx >= ry ) {
292 : if (ry >= rz) { //rx >= ry && ry >= rz
293 : c1_r = CLU(r_table, x_n, y, z) - c0_r;
294 : c2_r = CLU(r_table, x_n, y_n, z) - CLU(r_table, x_n, y, z);
295 : c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y_n, z);
296 : c1_g = CLU(g_table, x_n, y, z) - c0_g;
297 : c2_g = CLU(g_table, x_n, y_n, z) - CLU(g_table, x_n, y, z);
298 : c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y_n, z);
299 : c1_b = CLU(b_table, x_n, y, z) - c0_b;
300 : c2_b = CLU(b_table, x_n, y_n, z) - CLU(b_table, x_n, y, z);
301 : c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y_n, z);
302 : } else {
303 : if (rx >= rz) { //rx >= rz && rz >= ry
304 : c1_r = CLU(r_table, x_n, y, z) - c0_r;
305 : c2_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y, z_n);
306 : c3_r = CLU(r_table, x_n, y, z_n) - CLU(r_table, x_n, y, z);
307 : c1_g = CLU(g_table, x_n, y, z) - c0_g;
308 : c2_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y, z_n);
309 : c3_g = CLU(g_table, x_n, y, z_n) - CLU(g_table, x_n, y, z);
310 : c1_b = CLU(b_table, x_n, y, z) - c0_b;
311 : c2_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y, z_n);
312 : c3_b = CLU(b_table, x_n, y, z_n) - CLU(b_table, x_n, y, z);
313 : } else { //rz > rx && rx >= ry
314 : c1_r = CLU(r_table, x_n, y, z_n) - CLU(r_table, x, y, z_n);
315 : c2_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y, z_n);
316 : c3_r = CLU(r_table, x, y, z_n) - c0_r;
317 : c1_g = CLU(g_table, x_n, y, z_n) - CLU(g_table, x, y, z_n);
318 : c2_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y, z_n);
319 : c3_g = CLU(g_table, x, y, z_n) - c0_g;
320 : c1_b = CLU(b_table, x_n, y, z_n) - CLU(b_table, x, y, z_n);
321 : c2_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y, z_n);
322 : c3_b = CLU(b_table, x, y, z_n) - c0_b;
323 : }
324 : }
325 : } else {
326 : if (rx >= rz) { //ry > rx && rx >= rz
327 : c1_r = CLU(r_table, x_n, y_n, z) - CLU(r_table, x, y_n, z);
328 : c2_r = CLU(r_table, x_n, y_n, z) - c0_r;
329 : c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y_n, z);
330 : c1_g = CLU(g_table, x_n, y_n, z) - CLU(g_table, x, y_n, z);
331 : c2_g = CLU(g_table, x_n, y_n, z) - c0_g;
332 : c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y_n, z);
333 : c1_b = CLU(b_table, x_n, y_n, z) - CLU(b_table, x, y_n, z);
334 : c2_b = CLU(b_table, x_n, y_n, z) - c0_b;
335 : c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y_n, z);
336 : } else {
337 : if (ry >= rz) { //ry >= rz && rz > rx
338 : c1_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x, y_n, z_n);
339 : c2_r = CLU(r_table, x, y_n, z) - c0_r;
340 : c3_r = CLU(r_table, x, y_n, z_n) - CLU(r_table, x, y_n, z);
341 : c1_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x, y_n, z_n);
342 : c2_g = CLU(g_table, x, y_n, z) - c0_g;
343 : c3_g = CLU(g_table, x, y_n, z_n) - CLU(g_table, x, y_n, z);
344 : c1_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x, y_n, z_n);
345 : c2_b = CLU(b_table, x, y_n, z) - c0_b;
346 : c3_b = CLU(b_table, x, y_n, z_n) - CLU(b_table, x, y_n, z);
347 : } else { //rz > ry && ry > rx
348 : c1_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x, y_n, z_n);
349 : c2_r = CLU(r_table, x, y_n, z) - c0_r;
350 : c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y_n, z);
351 : c1_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x, y_n, z_n);
352 : c2_g = CLU(g_table, x, y_n, z) - c0_g;
353 : c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y_n, z);
354 : c1_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x, y_n, z_n);
355 : c2_b = CLU(b_table, x, y_n, z) - c0_b;
356 : c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y_n, z);
357 : }
358 : }
359 : }
360 :
361 : clut_r = c0_r + c1_r*rx + c2_r*ry + c3_r*rz;
362 : clut_g = c0_g + c1_g*rx + c2_g*ry + c3_g*rz;
363 : clut_b = c0_b + c1_b*rx + c2_b*ry + c3_b*rz;
364 :
365 : pcs_r = lut_interp_linear_float(clut_r,
366 : transform->output_clut_table_r, transform->output_clut_table_length);
367 : pcs_g = lut_interp_linear_float(clut_g,
368 : transform->output_clut_table_g, transform->output_clut_table_length);
369 : pcs_b = lut_interp_linear_float(clut_b,
370 : transform->output_clut_table_b, transform->output_clut_table_length);
371 : *dest++ = clamp_float(pcs_r);
372 : *dest++ = clamp_float(pcs_g);
373 : *dest++ = clamp_float(pcs_b);
374 : }
375 : }
376 : */
377 :
378 0 : static void qcms_transform_module_gamma_table(struct qcms_modular_transform *transform, float *src, float *dest, size_t length)
379 : {
380 : size_t i;
381 : float out_r, out_g, out_b;
382 0 : for (i = 0; i < length; i++) {
383 0 : float in_r = *src++;
384 0 : float in_g = *src++;
385 0 : float in_b = *src++;
386 :
387 0 : out_r = lut_interp_linear_float(in_r, transform->input_clut_table_r, 256);
388 0 : out_g = lut_interp_linear_float(in_g, transform->input_clut_table_g, 256);
389 0 : out_b = lut_interp_linear_float(in_b, transform->input_clut_table_b, 256);
390 :
391 0 : *dest++ = clamp_float(out_r);
392 0 : *dest++ = clamp_float(out_g);
393 0 : *dest++ = clamp_float(out_b);
394 : }
395 0 : }
396 :
397 0 : static void qcms_transform_module_gamma_lut(struct qcms_modular_transform *transform, float *src, float *dest, size_t length)
398 : {
399 : size_t i;
400 : float out_r, out_g, out_b;
401 0 : for (i = 0; i < length; i++) {
402 0 : float in_r = *src++;
403 0 : float in_g = *src++;
404 0 : float in_b = *src++;
405 :
406 0 : out_r = lut_interp_linear(in_r,
407 0 : transform->output_gamma_lut_r, transform->output_gamma_lut_r_length);
408 0 : out_g = lut_interp_linear(in_g,
409 0 : transform->output_gamma_lut_g, transform->output_gamma_lut_g_length);
410 0 : out_b = lut_interp_linear(in_b,
411 0 : transform->output_gamma_lut_b, transform->output_gamma_lut_b_length);
412 :
413 0 : *dest++ = clamp_float(out_r);
414 0 : *dest++ = clamp_float(out_g);
415 0 : *dest++ = clamp_float(out_b);
416 : }
417 0 : }
418 :
419 0 : static void qcms_transform_module_matrix_translate(struct qcms_modular_transform *transform, float *src, float *dest, size_t length)
420 : {
421 : size_t i;
422 : struct matrix mat;
423 :
424 : /* store the results in column major mode
425 : * this makes doing the multiplication with sse easier */
426 0 : mat.m[0][0] = transform->matrix.m[0][0];
427 0 : mat.m[1][0] = transform->matrix.m[0][1];
428 0 : mat.m[2][0] = transform->matrix.m[0][2];
429 0 : mat.m[0][1] = transform->matrix.m[1][0];
430 0 : mat.m[1][1] = transform->matrix.m[1][1];
431 0 : mat.m[2][1] = transform->matrix.m[1][2];
432 0 : mat.m[0][2] = transform->matrix.m[2][0];
433 0 : mat.m[1][2] = transform->matrix.m[2][1];
434 0 : mat.m[2][2] = transform->matrix.m[2][2];
435 :
436 0 : for (i = 0; i < length; i++) {
437 0 : float in_r = *src++;
438 0 : float in_g = *src++;
439 0 : float in_b = *src++;
440 :
441 0 : float out_r = mat.m[0][0]*in_r + mat.m[1][0]*in_g + mat.m[2][0]*in_b + transform->tx;
442 0 : float out_g = mat.m[0][1]*in_r + mat.m[1][1]*in_g + mat.m[2][1]*in_b + transform->ty;
443 0 : float out_b = mat.m[0][2]*in_r + mat.m[1][2]*in_g + mat.m[2][2]*in_b + transform->tz;
444 :
445 0 : *dest++ = clamp_float(out_r);
446 0 : *dest++ = clamp_float(out_g);
447 0 : *dest++ = clamp_float(out_b);
448 : }
449 0 : }
450 :
451 0 : static void qcms_transform_module_matrix(struct qcms_modular_transform *transform, float *src, float *dest, size_t length)
452 : {
453 : size_t i;
454 : struct matrix mat;
455 :
456 : /* store the results in column major mode
457 : * this makes doing the multiplication with sse easier */
458 0 : mat.m[0][0] = transform->matrix.m[0][0];
459 0 : mat.m[1][0] = transform->matrix.m[0][1];
460 0 : mat.m[2][0] = transform->matrix.m[0][2];
461 0 : mat.m[0][1] = transform->matrix.m[1][0];
462 0 : mat.m[1][1] = transform->matrix.m[1][1];
463 0 : mat.m[2][1] = transform->matrix.m[1][2];
464 0 : mat.m[0][2] = transform->matrix.m[2][0];
465 0 : mat.m[1][2] = transform->matrix.m[2][1];
466 0 : mat.m[2][2] = transform->matrix.m[2][2];
467 :
468 0 : for (i = 0; i < length; i++) {
469 0 : float in_r = *src++;
470 0 : float in_g = *src++;
471 0 : float in_b = *src++;
472 :
473 0 : float out_r = mat.m[0][0]*in_r + mat.m[1][0]*in_g + mat.m[2][0]*in_b;
474 0 : float out_g = mat.m[0][1]*in_r + mat.m[1][1]*in_g + mat.m[2][1]*in_b;
475 0 : float out_b = mat.m[0][2]*in_r + mat.m[1][2]*in_g + mat.m[2][2]*in_b;
476 :
477 0 : *dest++ = clamp_float(out_r);
478 0 : *dest++ = clamp_float(out_g);
479 0 : *dest++ = clamp_float(out_b);
480 : }
481 0 : }
482 :
483 0 : static struct qcms_modular_transform* qcms_modular_transform_alloc() {
484 0 : return calloc(1, sizeof(struct qcms_modular_transform));
485 : }
486 :
487 0 : static void qcms_modular_transform_release(struct qcms_modular_transform *transform)
488 : {
489 : struct qcms_modular_transform *next_transform;
490 0 : while (transform != NULL) {
491 0 : next_transform = transform->next_transform;
492 : // clut may use a single block of memory.
493 : // Perhaps we should remove this to simply the code.
494 0 : if (transform->input_clut_table_r + transform->input_clut_table_length == transform->input_clut_table_g && transform->input_clut_table_g + transform->input_clut_table_length == transform->input_clut_table_b) {
495 0 : if (transform->input_clut_table_r) free(transform->input_clut_table_r);
496 : } else {
497 0 : if (transform->input_clut_table_r) free(transform->input_clut_table_r);
498 0 : if (transform->input_clut_table_g) free(transform->input_clut_table_g);
499 0 : if (transform->input_clut_table_b) free(transform->input_clut_table_b);
500 : }
501 0 : if (transform->r_clut + 1 == transform->g_clut && transform->g_clut + 1 == transform->b_clut) {
502 0 : if (transform->r_clut) free(transform->r_clut);
503 : } else {
504 0 : if (transform->r_clut) free(transform->r_clut);
505 0 : if (transform->g_clut) free(transform->g_clut);
506 0 : if (transform->b_clut) free(transform->b_clut);
507 : }
508 0 : if (transform->output_clut_table_r + transform->output_clut_table_length == transform->output_clut_table_g && transform->output_clut_table_g+ transform->output_clut_table_length == transform->output_clut_table_b) {
509 0 : if (transform->output_clut_table_r) free(transform->output_clut_table_r);
510 : } else {
511 0 : if (transform->output_clut_table_r) free(transform->output_clut_table_r);
512 0 : if (transform->output_clut_table_g) free(transform->output_clut_table_g);
513 0 : if (transform->output_clut_table_b) free(transform->output_clut_table_b);
514 : }
515 0 : if (transform->output_gamma_lut_r) free(transform->output_gamma_lut_r);
516 0 : if (transform->output_gamma_lut_g) free(transform->output_gamma_lut_g);
517 0 : if (transform->output_gamma_lut_b) free(transform->output_gamma_lut_b);
518 0 : free(transform);
519 0 : transform = next_transform;
520 : }
521 0 : }
522 :
523 : /* Set transform to be the next element in the linked list. */
524 0 : static void append_transform(struct qcms_modular_transform *transform, struct qcms_modular_transform ***next_transform)
525 : {
526 0 : **next_transform = transform;
527 0 : while (transform) {
528 0 : *next_transform = &(transform->next_transform);
529 0 : transform = transform->next_transform;
530 : }
531 0 : }
532 :
533 : /* reverse the transformation list (used by mBA) */
534 0 : static struct qcms_modular_transform* reverse_transform(struct qcms_modular_transform *transform)
535 : {
536 0 : struct qcms_modular_transform *prev_transform = NULL;
537 0 : while (transform != NULL) {
538 0 : struct qcms_modular_transform *next_transform = transform->next_transform;
539 0 : transform->next_transform = prev_transform;
540 0 : prev_transform = transform;
541 0 : transform = next_transform;
542 : }
543 :
544 0 : return prev_transform;
545 : }
546 :
547 : #define EMPTY_TRANSFORM_LIST NULL
548 0 : static struct qcms_modular_transform* qcms_modular_transform_create_mAB(struct lutmABType *lut)
549 : {
550 0 : struct qcms_modular_transform *first_transform = NULL;
551 0 : struct qcms_modular_transform **next_transform = &first_transform;
552 0 : struct qcms_modular_transform *transform = NULL;
553 :
554 0 : if (lut->a_curves[0] != NULL) {
555 : size_t clut_length;
556 : float *clut;
557 :
558 : // If the A curve is present this also implies the
559 : // presence of a CLUT.
560 0 : if (!lut->clut_table)
561 0 : goto fail;
562 :
563 : // Prepare A curve.
564 0 : transform = qcms_modular_transform_alloc();
565 0 : if (!transform)
566 0 : goto fail;
567 0 : append_transform(transform, &next_transform);
568 0 : transform->input_clut_table_r = build_input_gamma_table(lut->a_curves[0]);
569 0 : transform->input_clut_table_g = build_input_gamma_table(lut->a_curves[1]);
570 0 : transform->input_clut_table_b = build_input_gamma_table(lut->a_curves[2]);
571 0 : transform->transform_module_fn = qcms_transform_module_gamma_table;
572 0 : if (lut->num_grid_points[0] != lut->num_grid_points[1] ||
573 0 : lut->num_grid_points[1] != lut->num_grid_points[2] ) {
574 : //XXX: We don't currently support clut that are not squared!
575 : goto fail;
576 : }
577 :
578 : // Prepare CLUT
579 0 : transform = qcms_modular_transform_alloc();
580 0 : if (!transform)
581 0 : goto fail;
582 0 : append_transform(transform, &next_transform);
583 0 : clut_length = sizeof(float)*pow(lut->num_grid_points[0], 3)*3;
584 0 : clut = malloc(clut_length);
585 0 : if (!clut)
586 0 : goto fail;
587 0 : memcpy(clut, lut->clut_table, clut_length);
588 0 : transform->r_clut = clut + 0;
589 0 : transform->g_clut = clut + 1;
590 0 : transform->b_clut = clut + 2;
591 0 : transform->grid_size = lut->num_grid_points[0];
592 0 : transform->transform_module_fn = qcms_transform_module_clut_only;
593 : }
594 0 : if (lut->m_curves[0] != NULL) {
595 : // M curve imples the presence of a Matrix
596 :
597 : // Prepare M curve
598 0 : transform = qcms_modular_transform_alloc();
599 0 : if (!transform)
600 0 : goto fail;
601 0 : append_transform(transform, &next_transform);
602 0 : transform->input_clut_table_r = build_input_gamma_table(lut->m_curves[0]);
603 0 : transform->input_clut_table_g = build_input_gamma_table(lut->m_curves[1]);
604 0 : transform->input_clut_table_b = build_input_gamma_table(lut->m_curves[2]);
605 0 : transform->transform_module_fn = qcms_transform_module_gamma_table;
606 :
607 : // Prepare Matrix
608 0 : transform = qcms_modular_transform_alloc();
609 0 : if (!transform)
610 0 : goto fail;
611 0 : append_transform(transform, &next_transform);
612 0 : transform->matrix = build_mAB_matrix(lut);
613 0 : if (transform->matrix.invalid)
614 0 : goto fail;
615 0 : transform->tx = s15Fixed16Number_to_float(lut->e03);
616 0 : transform->ty = s15Fixed16Number_to_float(lut->e13);
617 0 : transform->tz = s15Fixed16Number_to_float(lut->e23);
618 0 : transform->transform_module_fn = qcms_transform_module_matrix_translate;
619 : }
620 0 : if (lut->b_curves[0] != NULL) {
621 : // Prepare B curve
622 0 : transform = qcms_modular_transform_alloc();
623 0 : if (!transform)
624 0 : goto fail;
625 0 : append_transform(transform, &next_transform);
626 0 : transform->input_clut_table_r = build_input_gamma_table(lut->b_curves[0]);
627 0 : transform->input_clut_table_g = build_input_gamma_table(lut->b_curves[1]);
628 0 : transform->input_clut_table_b = build_input_gamma_table(lut->b_curves[2]);
629 0 : transform->transform_module_fn = qcms_transform_module_gamma_table;
630 : } else {
631 : // B curve is mandatory
632 0 : goto fail;
633 : }
634 :
635 0 : if (lut->reversed) {
636 : // mBA are identical to mAB except that the transformation order
637 : // is reversed
638 0 : first_transform = reverse_transform(first_transform);
639 : }
640 :
641 0 : return first_transform;
642 : fail:
643 0 : qcms_modular_transform_release(first_transform);
644 0 : return NULL;
645 : }
646 :
647 0 : static struct qcms_modular_transform* qcms_modular_transform_create_lut(struct lutType *lut)
648 : {
649 0 : struct qcms_modular_transform *first_transform = NULL;
650 0 : struct qcms_modular_transform **next_transform = &first_transform;
651 0 : struct qcms_modular_transform *transform = NULL;
652 :
653 : size_t in_curve_len, clut_length, out_curve_len;
654 : float *in_curves, *clut, *out_curves;
655 :
656 : // Prepare Matrix
657 0 : transform = qcms_modular_transform_alloc();
658 0 : if (!transform)
659 0 : goto fail;
660 0 : append_transform(transform, &next_transform);
661 0 : transform->matrix = build_lut_matrix(lut);
662 0 : if (transform->matrix.invalid)
663 0 : goto fail;
664 0 : transform->transform_module_fn = qcms_transform_module_matrix;
665 :
666 : // Prepare input curves
667 0 : transform = qcms_modular_transform_alloc();
668 0 : if (!transform)
669 0 : goto fail;
670 0 : append_transform(transform, &next_transform);
671 0 : in_curve_len = sizeof(float)*lut->num_input_table_entries * 3;
672 0 : in_curves = malloc(in_curve_len);
673 0 : if (!in_curves)
674 0 : goto fail;
675 0 : memcpy(in_curves, lut->input_table, in_curve_len);
676 0 : transform->input_clut_table_r = in_curves + lut->num_input_table_entries * 0;
677 0 : transform->input_clut_table_g = in_curves + lut->num_input_table_entries * 1;
678 0 : transform->input_clut_table_b = in_curves + lut->num_input_table_entries * 2;
679 0 : transform->input_clut_table_length = lut->num_input_table_entries;
680 :
681 : // Prepare table
682 0 : clut_length = sizeof(float)*pow(lut->num_clut_grid_points, 3)*3;
683 0 : clut = malloc(clut_length);
684 0 : if (!clut)
685 0 : goto fail;
686 0 : memcpy(clut, lut->clut_table, clut_length);
687 0 : transform->r_clut = clut + 0;
688 0 : transform->g_clut = clut + 1;
689 0 : transform->b_clut = clut + 2;
690 0 : transform->grid_size = lut->num_clut_grid_points;
691 :
692 : // Prepare output curves
693 0 : out_curve_len = sizeof(float) * lut->num_output_table_entries * 3;
694 0 : out_curves = malloc(out_curve_len);
695 0 : if (!out_curves)
696 0 : goto fail;
697 0 : memcpy(out_curves, lut->output_table, out_curve_len);
698 0 : transform->output_clut_table_r = out_curves + lut->num_output_table_entries * 0;
699 0 : transform->output_clut_table_g = out_curves + lut->num_output_table_entries * 1;
700 0 : transform->output_clut_table_b = out_curves + lut->num_output_table_entries * 2;
701 0 : transform->output_clut_table_length = lut->num_output_table_entries;
702 0 : transform->transform_module_fn = qcms_transform_module_clut;
703 :
704 0 : return first_transform;
705 : fail:
706 0 : qcms_modular_transform_release(first_transform);
707 0 : return NULL;
708 : }
709 :
710 0 : struct qcms_modular_transform* qcms_modular_transform_create_input(qcms_profile *in)
711 : {
712 0 : struct qcms_modular_transform *first_transform = NULL;
713 0 : struct qcms_modular_transform **next_transform = &first_transform;
714 :
715 0 : if (in->A2B0) {
716 : struct qcms_modular_transform *lut_transform;
717 0 : lut_transform = qcms_modular_transform_create_lut(in->A2B0);
718 0 : if (!lut_transform)
719 0 : goto fail;
720 0 : append_transform(lut_transform, &next_transform);
721 0 : } else if (in->mAB && in->mAB->num_in_channels == 3 && in->mAB->num_out_channels == 3) {
722 : struct qcms_modular_transform *mAB_transform;
723 0 : mAB_transform = qcms_modular_transform_create_mAB(in->mAB);
724 0 : if (!mAB_transform)
725 0 : goto fail;
726 0 : append_transform(mAB_transform, &next_transform);
727 :
728 : } else {
729 : struct qcms_modular_transform *transform;
730 :
731 0 : transform = qcms_modular_transform_alloc();
732 0 : if (!transform)
733 0 : goto fail;
734 0 : append_transform(transform, &next_transform);
735 0 : transform->input_clut_table_r = build_input_gamma_table(in->redTRC);
736 0 : transform->input_clut_table_g = build_input_gamma_table(in->greenTRC);
737 0 : transform->input_clut_table_b = build_input_gamma_table(in->blueTRC);
738 0 : transform->transform_module_fn = qcms_transform_module_gamma_table;
739 0 : if (!transform->input_clut_table_r || !transform->input_clut_table_g ||
740 0 : !transform->input_clut_table_b) {
741 : goto fail;
742 : }
743 :
744 0 : transform = qcms_modular_transform_alloc();
745 0 : if (!transform)
746 0 : goto fail;
747 0 : append_transform(transform, &next_transform);
748 0 : transform->matrix.m[0][0] = 1/1.999969482421875f;
749 0 : transform->matrix.m[0][1] = 0.f;
750 0 : transform->matrix.m[0][2] = 0.f;
751 0 : transform->matrix.m[1][0] = 0.f;
752 0 : transform->matrix.m[1][1] = 1/1.999969482421875f;
753 0 : transform->matrix.m[1][2] = 0.f;
754 0 : transform->matrix.m[2][0] = 0.f;
755 0 : transform->matrix.m[2][1] = 0.f;
756 0 : transform->matrix.m[2][2] = 1/1.999969482421875f;
757 0 : transform->matrix.invalid = false;
758 0 : transform->transform_module_fn = qcms_transform_module_matrix;
759 :
760 0 : transform = qcms_modular_transform_alloc();
761 0 : if (!transform)
762 0 : goto fail;
763 0 : append_transform(transform, &next_transform);
764 0 : transform->matrix = build_colorant_matrix(in);
765 0 : transform->transform_module_fn = qcms_transform_module_matrix;
766 : }
767 :
768 0 : return first_transform;
769 : fail:
770 0 : qcms_modular_transform_release(first_transform);
771 0 : return EMPTY_TRANSFORM_LIST;
772 : }
773 0 : static struct qcms_modular_transform* qcms_modular_transform_create_output(qcms_profile *out)
774 : {
775 0 : struct qcms_modular_transform *first_transform = NULL;
776 0 : struct qcms_modular_transform **next_transform = &first_transform;
777 :
778 0 : if (out->B2A0) {
779 : struct qcms_modular_transform *lut_transform;
780 0 : lut_transform = qcms_modular_transform_create_lut(out->B2A0);
781 0 : if (!lut_transform)
782 0 : goto fail;
783 0 : append_transform(lut_transform, &next_transform);
784 0 : } else if (out->mBA && out->mBA->num_in_channels == 3 && out->mBA->num_out_channels == 3) {
785 : struct qcms_modular_transform *lut_transform;
786 0 : lut_transform = qcms_modular_transform_create_mAB(out->mBA);
787 0 : if (!lut_transform)
788 0 : goto fail;
789 0 : append_transform(lut_transform, &next_transform);
790 0 : } else if (out->redTRC && out->greenTRC && out->blueTRC) {
791 : struct qcms_modular_transform *transform;
792 :
793 0 : transform = qcms_modular_transform_alloc();
794 0 : if (!transform)
795 0 : goto fail;
796 0 : append_transform(transform, &next_transform);
797 0 : transform->matrix = matrix_invert(build_colorant_matrix(out));
798 0 : transform->transform_module_fn = qcms_transform_module_matrix;
799 :
800 0 : transform = qcms_modular_transform_alloc();
801 0 : if (!transform)
802 0 : goto fail;
803 0 : append_transform(transform, &next_transform);
804 0 : transform->matrix.m[0][0] = 1.999969482421875f;
805 0 : transform->matrix.m[0][1] = 0.f;
806 0 : transform->matrix.m[0][2] = 0.f;
807 0 : transform->matrix.m[1][0] = 0.f;
808 0 : transform->matrix.m[1][1] = 1.999969482421875f;
809 0 : transform->matrix.m[1][2] = 0.f;
810 0 : transform->matrix.m[2][0] = 0.f;
811 0 : transform->matrix.m[2][1] = 0.f;
812 0 : transform->matrix.m[2][2] = 1.999969482421875f;
813 0 : transform->matrix.invalid = false;
814 0 : transform->transform_module_fn = qcms_transform_module_matrix;
815 :
816 0 : transform = qcms_modular_transform_alloc();
817 0 : if (!transform)
818 0 : goto fail;
819 0 : append_transform(transform, &next_transform);
820 0 : build_output_lut(out->redTRC, &transform->output_gamma_lut_r,
821 : &transform->output_gamma_lut_r_length);
822 0 : build_output_lut(out->greenTRC, &transform->output_gamma_lut_g,
823 : &transform->output_gamma_lut_g_length);
824 0 : build_output_lut(out->blueTRC, &transform->output_gamma_lut_b,
825 : &transform->output_gamma_lut_b_length);
826 0 : transform->transform_module_fn = qcms_transform_module_gamma_lut;
827 :
828 0 : if (!transform->output_gamma_lut_r || !transform->output_gamma_lut_g ||
829 0 : !transform->output_gamma_lut_b) {
830 : goto fail;
831 : }
832 : } else {
833 0 : assert(0 && "Unsupported output profile workflow.");
834 : return NULL;
835 : }
836 :
837 0 : return first_transform;
838 : fail:
839 0 : qcms_modular_transform_release(first_transform);
840 0 : return EMPTY_TRANSFORM_LIST;
841 : }
842 :
843 : /* Not Completed
844 : // Simplify the transformation chain to an equivalent transformation chain
845 : static struct qcms_modular_transform* qcms_modular_transform_reduce(struct qcms_modular_transform *transform)
846 : {
847 : struct qcms_modular_transform *first_transform = NULL;
848 : struct qcms_modular_transform *curr_trans = transform;
849 : struct qcms_modular_transform *prev_trans = NULL;
850 : while (curr_trans) {
851 : struct qcms_modular_transform *next_trans = curr_trans->next_transform;
852 : if (curr_trans->transform_module_fn == qcms_transform_module_matrix) {
853 : if (next_trans && next_trans->transform_module_fn == qcms_transform_module_matrix) {
854 : curr_trans->matrix = matrix_multiply(curr_trans->matrix, next_trans->matrix);
855 : goto remove_next;
856 : }
857 : }
858 : if (curr_trans->transform_module_fn == qcms_transform_module_gamma_table) {
859 : bool isLinear = true;
860 : uint16_t i;
861 : for (i = 0; isLinear && i < 256; i++) {
862 : isLinear &= (int)(curr_trans->input_clut_table_r[i] * 255) == i;
863 : isLinear &= (int)(curr_trans->input_clut_table_g[i] * 255) == i;
864 : isLinear &= (int)(curr_trans->input_clut_table_b[i] * 255) == i;
865 : }
866 : goto remove_current;
867 : }
868 :
869 : next_transform:
870 : if (!next_trans) break;
871 : prev_trans = curr_trans;
872 : curr_trans = next_trans;
873 : continue;
874 : remove_current:
875 : if (curr_trans == transform) {
876 : //Update head
877 : transform = next_trans;
878 : } else {
879 : prev_trans->next_transform = next_trans;
880 : }
881 : curr_trans->next_transform = NULL;
882 : qcms_modular_transform_release(curr_trans);
883 : //return transform;
884 : return qcms_modular_transform_reduce(transform);
885 : remove_next:
886 : curr_trans->next_transform = next_trans->next_transform;
887 : next_trans->next_transform = NULL;
888 : qcms_modular_transform_release(next_trans);
889 : continue;
890 : }
891 : return transform;
892 : }
893 : */
894 :
895 0 : static struct qcms_modular_transform* qcms_modular_transform_create(qcms_profile *in, qcms_profile *out)
896 : {
897 0 : struct qcms_modular_transform *first_transform = NULL;
898 0 : struct qcms_modular_transform **next_transform = &first_transform;
899 :
900 0 : if (in->color_space == RGB_SIGNATURE) {
901 : struct qcms_modular_transform* rgb_to_pcs;
902 0 : rgb_to_pcs = qcms_modular_transform_create_input(in);
903 0 : if (!rgb_to_pcs)
904 0 : goto fail;
905 0 : append_transform(rgb_to_pcs, &next_transform);
906 : } else {
907 0 : assert(0 && "input color space not supported");
908 : goto fail;
909 : }
910 :
911 0 : if (in->pcs == LAB_SIGNATURE && out->pcs == XYZ_SIGNATURE) {
912 : struct qcms_modular_transform* lab_to_pcs;
913 0 : lab_to_pcs = qcms_modular_transform_alloc();
914 0 : if (!lab_to_pcs)
915 0 : goto fail;
916 0 : append_transform(lab_to_pcs, &next_transform);
917 0 : lab_to_pcs->transform_module_fn = qcms_transform_module_LAB_to_XYZ;
918 : }
919 :
920 : // This does not improve accuracy in practice, something is wrong here.
921 : //if (in->chromaticAdaption.invalid == false) {
922 : // struct qcms_modular_transform* chromaticAdaption;
923 : // chromaticAdaption = qcms_modular_transform_alloc();
924 : // if (!chromaticAdaption)
925 : // goto fail;
926 : // append_transform(chromaticAdaption, &next_transform);
927 : // chromaticAdaption->matrix = matrix_invert(in->chromaticAdaption);
928 : // chromaticAdaption->transform_module_fn = qcms_transform_module_matrix;
929 : //}
930 :
931 0 : if (in->pcs == XYZ_SIGNATURE && out->pcs == LAB_SIGNATURE) {
932 : struct qcms_modular_transform* pcs_to_lab;
933 0 : pcs_to_lab = qcms_modular_transform_alloc();
934 0 : if (!pcs_to_lab)
935 0 : goto fail;
936 0 : append_transform(pcs_to_lab, &next_transform);
937 0 : pcs_to_lab->transform_module_fn = qcms_transform_module_XYZ_to_LAB;
938 : }
939 :
940 0 : if (out->color_space == RGB_SIGNATURE) {
941 : struct qcms_modular_transform* pcs_to_rgb;
942 0 : pcs_to_rgb = qcms_modular_transform_create_output(out);
943 0 : if (!pcs_to_rgb)
944 0 : goto fail;
945 0 : append_transform(pcs_to_rgb, &next_transform);
946 : } else {
947 0 : assert(0 && "output color space not supported");
948 : goto fail;
949 : }
950 : // Not Completed
951 : //return qcms_modular_transform_reduce(first_transform);
952 0 : return first_transform;
953 : fail:
954 0 : qcms_modular_transform_release(first_transform);
955 0 : return EMPTY_TRANSFORM_LIST;
956 : }
957 :
958 0 : static float* qcms_modular_transform_data(struct qcms_modular_transform *transform, float *src, float *dest, size_t len)
959 : {
960 0 : while (transform != NULL) {
961 : // Keep swaping src/dest when performing a transform to use less memory.
962 0 : float *new_src = dest;
963 0 : const transform_module_fn_t transform_fn = transform->transform_module_fn;
964 0 : if (transform_fn != qcms_transform_module_gamma_table &&
965 0 : transform_fn != qcms_transform_module_gamma_lut &&
966 0 : transform_fn != qcms_transform_module_clut &&
967 0 : transform_fn != qcms_transform_module_clut_only &&
968 0 : transform_fn != qcms_transform_module_matrix &&
969 0 : transform_fn != qcms_transform_module_matrix_translate &&
970 0 : transform_fn != qcms_transform_module_LAB_to_XYZ &&
971 : transform_fn != qcms_transform_module_XYZ_to_LAB) {
972 0 : assert(0 && "Unsupported transform module");
973 : return NULL;
974 : }
975 0 : transform->transform_module_fn(transform,src,dest,len);
976 0 : dest = src;
977 0 : src = new_src;
978 0 : transform = transform->next_transform;
979 : }
980 : // The results end up in the src buffer because of the switching
981 0 : return src;
982 : }
983 :
984 0 : float* qcms_chain_transform(qcms_profile *in, qcms_profile *out, float *src, float *dest, size_t lutSize)
985 : {
986 0 : struct qcms_modular_transform *transform_list = qcms_modular_transform_create(in, out);
987 0 : if (transform_list != NULL) {
988 0 : float *lut = qcms_modular_transform_data(transform_list, src, dest, lutSize/3);
989 0 : qcms_modular_transform_release(transform_list);
990 0 : return lut;
991 : }
992 0 : return NULL;
993 : }
|