OLD | NEW |
| (Empty) |
1 diff --git a/third_party/qcms/src/iccread.c b/third_party/qcms/src/iccread.c | |
2 index 36b7011..0deab10 100644 | |
3 --- a/third_party/qcms/src/iccread.c | |
4 +++ b/third_party/qcms/src/iccread.c | |
5 @@ -266,7 +266,7 @@ qcms_bool qcms_profile_is_bogus(qcms_profile *profile) | |
6 if (profile->color_space != RGB_SIGNATURE) | |
7 return false; | |
8 | |
9 - if (profile->A2B0 || profile->B2A0) | |
10 + if (qcms_supports_iccv4 && (profile->A2B0 || profile->B2A0)) | |
11 return false; | |
12 | |
13 rX = s15Fixed16Number_to_float(profile->redColorant.X); | |
14 @@ -297,6 +297,11 @@ qcms_bool qcms_profile_is_bogus(qcms_profile *profile) | |
15 sum[1] = rY + gY + bY; | |
16 sum[2] = rZ + gZ + bZ; | |
17 | |
18 +#if defined (_MSC_VER) | |
19 +#pragma warning(push) | |
20 +/* Disable double to float truncation warning 4305 */ | |
21 +#pragma warning(disable:4305) | |
22 +#endif | |
23 // Build our target vector (see mozilla bug 460629) | |
24 target[0] = 0.96420; | |
25 target[1] = 1.00000; | |
26 @@ -310,6 +315,10 @@ qcms_bool qcms_profile_is_bogus(qcms_profile *profile) | |
27 tolerance[1] = 0.02; | |
28 tolerance[2] = 0.04; | |
29 | |
30 +#if defined (_MSC_VER) | |
31 +/* Restore warnings */ | |
32 +#pragma warning(pop) | |
33 +#endif | |
34 // Compare with our tolerance | |
35 for (i = 0; i < 3; ++i) { | |
36 if (!(((sum[i] - tolerance[i]) <= target[i]) && | |
37 @@ -331,6 +340,8 @@ qcms_bool qcms_profile_is_bogus(qcms_profile *profile) | |
38 #define TAG_A2B0 0x41324230 | |
39 #define TAG_B2A0 0x42324130 | |
40 #define TAG_CHAD 0x63686164 | |
41 +#define TAG_desc 0x64657363 | |
42 +#define TAG_vcgt 0x76636774 | |
43 | |
44 static struct tag *find_tag(struct tag_index index, uint32_t tag_id) | |
45 { | |
46 @@ -344,6 +355,215 @@ static struct tag *find_tag(struct tag_index index, uint32
_t tag_id) | |
47 return tag; | |
48 } | |
49 | |
50 +#define DESC_TYPE 0x64657363 // 'desc' | |
51 +#define MLUC_TYPE 0x6d6c7563 // 'mluc' | |
52 +#define MMOD_TYPE 0x6D6D6F64 // 'mmod' | |
53 +#define VCGT_TYPE 0x76636774 // 'vcgt' | |
54 + | |
55 +// Check unsigned short is uint16_t. | |
56 +typedef char assert_short_not_16b[(sizeof(unsigned short) == sizeof(uint16_t))
? 1 : -1]; | |
57 + | |
58 +qcms_bool read_tag_vcgtType(qcms_profile *profile, struct mem_source *src, stru
ct tag_index index) { | |
59 + size_t tag_offset = find_tag(index, TAG_vcgt)->offset; | |
60 + uint32_t tag_type = read_u32(src, tag_offset); | |
61 + uint32_t vcgt_type = read_u32(src, tag_offset + 8); | |
62 + uint16_t channels = read_u16(src, tag_offset + 12); | |
63 + uint16_t elements = read_u16(src, tag_offset + 14); | |
64 + uint16_t byte_depth = read_u16(src, tag_offset + 16); | |
65 + size_t table_offset = tag_offset + 18; | |
66 + uint32_t i; | |
67 + uint16_t *dest; | |
68 + | |
69 + if (!src->valid || tag_type != VCGT_TYPE) | |
70 + goto invalid_vcgt_tag; | |
71 + | |
72 + // Only support 3 channels. | |
73 + if (channels != 3) | |
74 + return true; | |
75 + // Only support single or double byte values. | |
76 + if (byte_depth != 1 && byte_depth != 2) | |
77 + return true; | |
78 + // Only support table data, not equation. | |
79 + if (vcgt_type != 0) | |
80 + return true; | |
81 + // Limit the table to a sensible size; 10-bit gamma is a reasonable | |
82 + // maximum for hardware correction. | |
83 + if (elements > 1024) | |
84 + return true; | |
85 + | |
86 + // Empty table is invalid. | |
87 + if (!elements) | |
88 + goto invalid_vcgt_tag; | |
89 + | |
90 + profile->vcgt.length = elements; | |
91 + profile->vcgt.data = malloc(3 * elements * sizeof(uint16_t)); | |
92 + if (!profile->vcgt.data) | |
93 + return false; | |
94 + | |
95 + dest = profile->vcgt.data; | |
96 + | |
97 + for (i = 0; i < 3 * elements; ++i) { | |
98 + if (byte_depth == 1) { | |
99 + *dest++ = read_u8(src, table_offset) * 256; | |
100 + } else { | |
101 + *dest++ = read_u16(src, table_offset); | |
102 + } | |
103 + | |
104 + table_offset += byte_depth; | |
105 + | |
106 + if (!src->valid) | |
107 + goto invalid_vcgt_tag; | |
108 + } | |
109 + | |
110 + return true; | |
111 + | |
112 +invalid_vcgt_tag: | |
113 + invalid_source(src, "invalid vcgt tag"); | |
114 + return false; | |
115 +} | |
116 + | |
117 +static bool read_tag_descType(qcms_profile *profile, struct mem_source *src, st
ruct tag_index index, uint32_t tag_id) | |
118 +{ | |
119 + struct tag *tag = find_tag(index, tag_id); | |
120 + if (tag) { | |
121 + const uint32_t limit = sizeof profile->description; | |
122 + uint32_t offset = tag->offset; | |
123 + uint32_t type = read_u32(src, offset); | |
124 + uint32_t length = read_u32(src, offset+8); | |
125 + uint32_t i, description_offset; | |
126 + bool mluc = false; | |
127 + if (length && type == MLUC_TYPE) { | |
128 + length = read_u32(src, offset+20); | |
129 + if (!length || (length & 1) || (read_u32(src, offset+12)
!= 12)) | |
130 + goto invalid_desc_tag; | |
131 + description_offset = offset + read_u32(src, offset+24); | |
132 + if (!src->valid) | |
133 + goto invalid_desc_tag; | |
134 + mluc = true; | |
135 + } else if (length && type == DESC_TYPE) { | |
136 + description_offset = offset + 12; | |
137 + } else { | |
138 + goto invalid_desc_tag; | |
139 + } | |
140 + if (length >= limit) | |
141 + length = limit - 1; | |
142 + for (i = 0; i < length; ++i) { | |
143 + uint8_t value = read_u8(src, description_offset + i); | |
144 + if (!src->valid) | |
145 + goto invalid_desc_tag; | |
146 + if (mluc && !value) | |
147 + value = '.'; | |
148 + profile->description[i] = value; | |
149 + } | |
150 + profile->description[length] = 0; | |
151 + } else { | |
152 + goto invalid_desc_tag; | |
153 + } | |
154 + | |
155 + if (src->valid) | |
156 + return true; | |
157 + | |
158 +invalid_desc_tag: | |
159 + invalid_source(src, "invalid description"); | |
160 + return false; | |
161 +} | |
162 + | |
163 +#if defined(__APPLE__) | |
164 + | |
165 +// Use the dscm tag to change profile description "Display" to its more specifi
c en-localized monitor name, if any. | |
166 + | |
167 +#define TAG_dscm 0x6473636D // 'dscm' | |
168 + | |
169 +static bool read_tag_dscmType(qcms_profile *profile, struct mem_source *src, st
ruct tag_index index, uint32_t tag_id) | |
170 +{ | |
171 + if (strcmp(profile->description, "Display") != 0) | |
172 + return true; | |
173 + | |
174 + struct tag *tag = find_tag(index, tag_id); | |
175 + if (tag) { | |
176 + uint32_t offset = tag->offset; | |
177 + uint32_t type = read_u32(src, offset); | |
178 + uint32_t records = read_u32(src, offset+8); | |
179 + | |
180 + if (!src->valid || !records || type != MLUC_TYPE) | |
181 + goto invalid_dscm_tag; | |
182 + if (read_u32(src, offset+12) != 12) // MLUC record size: bytes | |
183 + goto invalid_dscm_tag; | |
184 + | |
185 + for (uint32_t i = 0; i < records; ++i) { | |
186 + const uint32_t limit = sizeof profile->description; | |
187 + const uint16_t isoen = 0x656E; // ISO-3166-1 language 'e
n' | |
188 + | |
189 + uint16_t language = read_u16(src, offset + 16 + (i * 12)
+ 0); | |
190 + uint32_t length = read_u32(src, offset + 16 + (i * 12) +
4); | |
191 + uint32_t description_offset = read_u32(src, offset + 16
+ (i * 12) + 8); | |
192 + | |
193 + if (!src->valid || !length || (length & 1)) | |
194 + goto invalid_dscm_tag; | |
195 + if (language != isoen) | |
196 + continue; | |
197 + | |
198 + // Use a prefix to identify the display description sour
ce | |
199 + strcpy(profile->description, "dscm:"); | |
200 + length += 5; | |
201 + | |
202 + if (length >= limit) | |
203 + length = limit - 1; | |
204 + for (uint32_t j = 5; j < length; ++j) { | |
205 + uint8_t value = read_u8(src, offset + descriptio
n_offset + j - 5); | |
206 + if (!src->valid) | |
207 + goto invalid_dscm_tag; | |
208 + profile->description[j] = value ? value : '.'; | |
209 + } | |
210 + profile->description[length] = 0; | |
211 + break; | |
212 + } | |
213 + } | |
214 + | |
215 + if (src->valid) | |
216 + return true; | |
217 + | |
218 +invalid_dscm_tag: | |
219 + invalid_source(src, "invalid dscm tag"); | |
220 + return false; | |
221 +} | |
222 + | |
223 +// Use the mmod tag to change profile description "Display" to its specific mmo
d maker model data, if any. | |
224 + | |
225 +#define TAG_mmod 0x6D6D6F64 // 'mmod' | |
226 + | |
227 +static bool read_tag_mmodType(qcms_profile *profile, struct mem_source *src, st
ruct tag_index index, uint32_t tag_id) | |
228 +{ | |
229 + if (strcmp(profile->description, "Display") != 0) | |
230 + return true; | |
231 + | |
232 + struct tag *tag = find_tag(index, tag_id); | |
233 + if (tag) { | |
234 + const uint8_t length = 4 * 4; // Four 4-byte fields: 'mmod', 0,
maker, model. | |
235 + | |
236 + uint32_t offset = tag->offset; | |
237 + if (tag->size < 40 || read_u32(src, offset) != MMOD_TYPE) | |
238 + goto invalid_mmod_tag; | |
239 + | |
240 + for (uint8_t i = 0; i < length; ++i) { | |
241 + uint8_t value = read_u8(src, offset + i); | |
242 + if (!src->valid) | |
243 + goto invalid_mmod_tag; | |
244 + profile->description[i] = value ? value : '.'; | |
245 + } | |
246 + profile->description[length] = 0; | |
247 + } | |
248 + | |
249 + if (src->valid) | |
250 + return true; | |
251 + | |
252 +invalid_mmod_tag: | |
253 + invalid_source(src, "invalid mmod tag"); | |
254 + return false; | |
255 +} | |
256 + | |
257 +#endif // __APPLE__ | |
258 + | |
259 #define XYZ_TYPE 0x58595a20 // 'XYZ ' | |
260 #define CURVE_TYPE 0x63757276 // 'curv' | |
261 #define PARAMETRIC_CURVE_TYPE 0x70617261 // 'para' | |
262 @@ -402,7 +622,7 @@ static struct XYZNumber read_tag_XYZType(struct mem_source *
src, struct tag_inde | |
263 // present that are not part of the tag_index. | |
264 static struct curveType *read_curveType(struct mem_source *src, uint32_t offset
, uint32_t *len) | |
265 { | |
266 - static const size_t COUNT_TO_LENGTH[5] = {1, 3, 4, 5, 7}; | |
267 + static const uint32_t COUNT_TO_LENGTH[5] = {1, 3, 4, 5, 7}; | |
268 struct curveType *curve = NULL; | |
269 uint32_t type = read_u32(src, offset); | |
270 uint32_t count; | |
271 @@ -484,19 +704,23 @@ static void read_nested_curveType(struct mem_source *src,
struct curveType *(*cu | |
272 uint32_t channel_offset = 0; | |
273 int i; | |
274 for (i = 0; i < num_channels; i++) { | |
275 - uint32_t tag_len; | |
276 + uint32_t tag_len = ~0; | |
277 | |
278 (*curveArray)[i] = read_curveType(src, curve_offset + channel_of
fset, &tag_len); | |
279 if (!(*curveArray)[i]) { | |
280 invalid_source(src, "invalid nested curveType curve"); | |
281 } | |
282 | |
283 + if (tag_len == ~0) { | |
284 + invalid_source(src, "invalid nested curveType tag length
"); | |
285 + return; | |
286 + } | |
287 + | |
288 channel_offset += tag_len; | |
289 // 4 byte aligned | |
290 if ((tag_len % 4) != 0) | |
291 channel_offset += 4 - (tag_len % 4); | |
292 } | |
293 - | |
294 } | |
295 | |
296 static void mAB_release(struct lutmABType *lut) | |
297 @@ -540,7 +764,7 @@ static struct lutmABType *read_tag_lutmABType(struct mem_sou
rce *src, struct tag | |
298 // We require 3in/out channels since we only support RGB->XYZ (or RGB->L
AB) | |
299 // XXX: If we remove this restriction make sure that the number of chann
els | |
300 // is less or equal to the maximum number of mAB curves in qcmsint.
h | |
301 - // also check for clut_size overflow. | |
302 + // also check for clut_size overflow. Also make sure it's != 0 | |
303 if (num_in_channels != 3 || num_out_channels != 3) | |
304 return NULL; | |
305 | |
306 @@ -570,6 +794,9 @@ static struct lutmABType *read_tag_lutmABType(struct mem_sou
rce *src, struct tag | |
307 // clut_size can not overflow since lg(256^num_in_channels) = 24
bits. | |
308 for (i = 0; i < num_in_channels; i++) { | |
309 clut_size *= read_u8(src, clut_offset + i); | |
310 + if (clut_size == 0) { | |
311 + invalid_source(src, "bad clut_size"); | |
312 + } | |
313 } | |
314 } else { | |
315 clut_size = 0; | |
316 @@ -590,6 +817,9 @@ static struct lutmABType *read_tag_lutmABType(struct mem_sou
rce *src, struct tag | |
317 | |
318 for (i = 0; i < num_in_channels; i++) { | |
319 lut->num_grid_points[i] = read_u8(src, clut_offset + i); | |
320 + if (lut->num_grid_points[i] == 0) { | |
321 + invalid_source(src, "bad grid_points"); | |
322 + } | |
323 } | |
324 | |
325 // Reverse the processing of transformation elements for mBA type. | |
326 @@ -657,7 +887,7 @@ static struct lutType *read_tag_lutType(struct mem_source *s
rc, struct tag_index | |
327 uint16_t num_input_table_entries; | |
328 uint16_t num_output_table_entries; | |
329 uint8_t in_chan, grid_points, out_chan; | |
330 - uint32_t clut_offset, output_offset; | |
331 + size_t clut_offset, output_offset; | |
332 uint32_t clut_size; | |
333 size_t entry_size; | |
334 struct lutType *lut; | |
335 @@ -672,6 +902,10 @@ static struct lutType *read_tag_lutType(struct mem_source *
src, struct tag_index | |
336 } else if (type == LUT16_TYPE) { | |
337 num_input_table_entries = read_u16(src, offset + 48); | |
338 num_output_table_entries = read_u16(src, offset + 50); | |
339 + if (num_input_table_entries == 0 || num_output_table_entries ==
0) { | |
340 + invalid_source(src, "Bad channel count"); | |
341 + return NULL; | |
342 + } | |
343 entry_size = 2; | |
344 } else { | |
345 assert(0); // the caller checks that this doesn't happen | |
346 @@ -685,15 +919,18 @@ static struct lutType *read_tag_lutType(struct mem_source
*src, struct tag_index | |
347 | |
348 clut_size = pow(grid_points, in_chan); | |
349 if (clut_size > MAX_CLUT_SIZE) { | |
350 + invalid_source(src, "CLUT too large"); | |
351 return NULL; | |
352 } | |
353 | |
354 if (in_chan != 3 || out_chan != 3) { | |
355 + invalid_source(src, "CLUT only supports RGB"); | |
356 return NULL; | |
357 } | |
358 | |
359 lut = malloc(sizeof(struct lutType) + (num_input_table_entries * in_chan
+ clut_size*out_chan + num_output_table_entries * out_chan)*sizeof(float)); | |
360 if (!lut) { | |
361 + invalid_source(src, "CLUT too large"); | |
362 return NULL; | |
363 } | |
364 | |
365 @@ -704,9 +941,9 @@ static struct lutType *read_tag_lutType(struct mem_source *s
rc, struct tag_index | |
366 | |
367 lut->num_input_table_entries = num_input_table_entries; | |
368 lut->num_output_table_entries = num_output_table_entries; | |
369 - lut->num_input_channels = read_u8(src, offset + 8); | |
370 - lut->num_output_channels = read_u8(src, offset + 9); | |
371 - lut->num_clut_grid_points = read_u8(src, offset + 10); | |
372 + lut->num_input_channels = in_chan; | |
373 + lut->num_output_channels = out_chan; | |
374 + lut->num_clut_grid_points = grid_points; | |
375 lut->e00 = read_s15Fixed16Number(src, offset+12); | |
376 lut->e01 = read_s15Fixed16Number(src, offset+16); | |
377 lut->e02 = read_s15Fixed16Number(src, offset+20); | |
378 @@ -979,11 +1216,13 @@ qcms_profile* qcms_profile_sRGB(void) | |
379 return NO_MEM_PROFILE; | |
380 | |
381 profile = qcms_profile_create_rgb_with_table(D65, Rec709Primaries, table
, 1024); | |
382 + if (profile) | |
383 + strcpy(profile->description, "sRGB IEC61966-2.1"); | |
384 + | |
385 free(table); | |
386 return profile; | |
387 } | |
388 | |
389 - | |
390 /* qcms_profile_from_memory does not hold a reference to the memory passed in *
/ | |
391 qcms_profile* qcms_profile_from_memory(const void *mem, size_t size) | |
392 { | |
393 @@ -997,6 +1236,9 @@ qcms_profile* qcms_profile_from_memory(const void *mem, siz
e_t size) | |
394 source.size = size; | |
395 source.valid = true; | |
396 | |
397 + if (size < 4) | |
398 + return INVALID_PROFILE; | |
399 + | |
400 length = read_u32(src, 0); | |
401 if (length <= size) { | |
402 // shrink the area that we can read if appropriate | |
403 @@ -1028,12 +1270,26 @@ qcms_profile* qcms_profile_from_memory(const void *mem,
size_t size) | |
404 if (!src->valid || !index.tags) | |
405 goto invalid_tag_table; | |
406 | |
407 + if (!read_tag_descType(profile, src, index, TAG_desc)) | |
408 + goto invalid_tag_table; | |
409 +#if defined(__APPLE__) | |
410 + if (!read_tag_dscmType(profile, src, index, TAG_dscm)) | |
411 + goto invalid_tag_table; | |
412 + if (!read_tag_mmodType(profile, src, index, TAG_mmod)) | |
413 + goto invalid_tag_table; | |
414 +#endif // __APPLE__ | |
415 + | |
416 if (find_tag(index, TAG_CHAD)) { | |
417 profile->chromaticAdaption = read_tag_s15Fixed16ArrayType(src, i
ndex, TAG_CHAD); | |
418 } else { | |
419 profile->chromaticAdaption.invalid = true; //Signal the data is
not present | |
420 } | |
421 | |
422 + if (find_tag(index, TAG_vcgt)) { | |
423 + if (!read_tag_vcgtType(profile, src, index)) | |
424 + goto invalid_tag_table; | |
425 + } | |
426 + | |
427 if (profile->class == DISPLAY_DEVICE_PROFILE || profile->class == INPUT_
DEVICE_PROFILE || | |
428 profile->class == OUTPUT_DEVICE_PROFILE || profile->class == COLOR
_SPACE_PROFILE) { | |
429 if (profile->color_space == RGB_SIGNATURE) { | |
430 @@ -1098,6 +1354,16 @@ invalid_profile: | |
431 return INVALID_PROFILE; | |
432 } | |
433 | |
434 +qcms_bool qcms_profile_match(qcms_profile *p1, qcms_profile *p2) | |
435 +{ | |
436 + return memcmp(p1->description, p2->description, sizeof p1->description) ==
0; | |
437 +} | |
438 + | |
439 +const char* qcms_profile_get_description(qcms_profile *profile) | |
440 +{ | |
441 + return profile->description; | |
442 +} | |
443 + | |
444 qcms_intent qcms_profile_get_rendering_intent(qcms_profile *profile) | |
445 { | |
446 return profile->rendering_intent; | |
447 @@ -1114,6 +1380,18 @@ static void lut_release(struct lutType *lut) | |
448 free(lut); | |
449 } | |
450 | |
451 +size_t qcms_profile_get_vcgt_channel_length(qcms_profile *profile) { | |
452 + return profile->vcgt.length; | |
453 +} | |
454 + | |
455 +qcms_bool qcms_profile_get_vcgt_rgb_channels(qcms_profile *profile, unsigned sh
ort *data) { | |
456 + size_t vcgt_channel_bytes = qcms_profile_get_vcgt_channel_length(profile
) * sizeof(uint16_t); | |
457 + if (!vcgt_channel_bytes || !data) | |
458 + return false; | |
459 + memcpy(data, profile->vcgt.data, 3 * vcgt_channel_bytes); | |
460 + return true; | |
461 +} | |
462 + | |
463 void qcms_profile_release(qcms_profile *profile) | |
464 { | |
465 if (profile->output_table_r) | |
466 @@ -1133,6 +1411,9 @@ void qcms_profile_release(qcms_profile *profile) | |
467 if (profile->mBA) | |
468 mAB_release(profile->mBA); | |
469 | |
470 + if (profile->vcgt.data) | |
471 + free(profile->vcgt.data); | |
472 + | |
473 free(profile->redTRC); | |
474 free(profile->blueTRC); | |
475 free(profile->greenTRC); | |
476 diff --git a/third_party/qcms/src/qcms.h b/third_party/qcms/src/qcms.h | |
477 index 7d83623..be74717 100644 | |
478 --- a/third_party/qcms/src/qcms.h | |
479 +++ b/third_party/qcms/src/qcms.h | |
480 @@ -40,6 +40,12 @@ sale, use or other dealings in this Software without written | |
481 authorization from SunSoft Inc. | |
482 ******************************************************************/ | |
483 | |
484 +/* | |
485 + * QCMS, in general, is not threadsafe. However, it should be safe to create | |
486 + * profile and transformation objects on different threads, so long as you | |
487 + * don't use the same objects on different threads at the same time. | |
488 + */ | |
489 + | |
490 /* | |
491 * Color Space Signatures | |
492 * Note that only icSigXYZData and icSigLabData are valid | |
493 @@ -102,6 +108,12 @@ typedef enum { | |
494 QCMS_DATA_GRAYA_8 | |
495 } qcms_data_type; | |
496 | |
497 +/* Format of the output data for qcms_transform_data_type() */ | |
498 +typedef enum { | |
499 + QCMS_OUTPUT_RGBX, | |
500 + QCMS_OUTPUT_BGRX | |
501 +} qcms_output_type; | |
502 + | |
503 /* the names for the following two types are sort of ugly */ | |
504 typedef struct | |
505 { | |
506 @@ -136,16 +148,27 @@ qcms_bool qcms_profile_is_bogus(qcms_profile *profile); | |
507 qcms_intent qcms_profile_get_rendering_intent(qcms_profile *profile); | |
508 icColorSpaceSignature qcms_profile_get_color_space(qcms_profile *profile); | |
509 | |
510 +qcms_bool qcms_profile_match(qcms_profile *p1, qcms_profile *p2); | |
511 +const char* qcms_profile_get_description(qcms_profile *profile); | |
512 + | |
513 void qcms_profile_precache_output_transform(qcms_profile *profile); | |
514 | |
515 +size_t qcms_profile_get_vcgt_channel_length(qcms_profile *profile); | |
516 +qcms_bool qcms_profile_get_vcgt_rgb_channels(qcms_profile *profile, unsigned sh
ort *data); | |
517 + | |
518 qcms_transform* qcms_transform_create( | |
519 qcms_profile *in, qcms_data_type in_type, | |
520 qcms_profile* out, qcms_data_type out_type, | |
521 qcms_intent intent); | |
522 | |
523 -void qcms_transform_release(qcms_transform *); | |
524 +qcms_bool qcms_transform_create_LUT_zyx_bgra( | |
525 + qcms_profile *in, qcms_profile* out, qcms_intent intent, | |
526 + int samples, unsigned char* lut); | |
527 | |
528 void qcms_transform_data(qcms_transform *transform, void *src, void *dest, size
_t length); | |
529 +void qcms_transform_data_type(qcms_transform *transform, void *src, void *dest,
size_t length, qcms_output_type type); | |
530 + | |
531 +void qcms_transform_release(qcms_transform *); | |
532 | |
533 void qcms_enable_iccv4(); | |
534 | |
535 diff --git a/third_party/qcms/src/qcmsint.h b/third_party/qcms/src/qcmsint.h | |
536 index 53a3420..6b22c5a 100644 | |
537 --- a/third_party/qcms/src/qcmsint.h | |
538 +++ b/third_party/qcms/src/qcmsint.h | |
539 @@ -45,6 +45,11 @@ struct precache_output | |
540 #define ALIGN __attribute__(( aligned (16) )) | |
541 #endif | |
542 | |
543 +typedef struct _qcms_format_type { | |
544 + int r; | |
545 + int b; | |
546 +} qcms_format_type; | |
547 + | |
548 struct _qcms_transform { | |
549 float ALIGN matrix[3][4]; | |
550 float *input_gamma_table_r; | |
551 @@ -88,7 +93,7 @@ struct _qcms_transform { | |
552 struct precache_output *output_table_g; | |
553 struct precache_output *output_table_b; | |
554 | |
555 - void (*transform_fn)(struct _qcms_transform *transform, unsigned char *s
rc, unsigned char *dest, size_t length); | |
556 + void (*transform_fn)(struct _qcms_transform *transform, unsigned char *s
rc, unsigned char *dest, size_t length, struct _qcms_format_type output_format); | |
557 }; | |
558 | |
559 struct matrix { | |
560 @@ -200,6 +205,14 @@ struct lutType { // used by lut8Type/lut16Type (mft2) only | |
561 | |
562 float table_data[]; | |
563 }; | |
564 + | |
565 +struct vcgtType { | |
566 + /* data contains three gamma channels: R[length], then G[length], then | |
567 + * B[length]. */ | |
568 + uint16_t *data; | |
569 + size_t length; | |
570 +}; | |
571 + | |
572 #if 0 | |
573 /* this is from an intial idea of having the struct correspond to the data in | |
574 * the file. I decided that it wasn't a good idea. | |
575 @@ -225,6 +238,7 @@ struct tag_value { | |
576 #define LAB_SIGNATURE 0x4C616220 | |
577 | |
578 struct _qcms_profile { | |
579 + char description[64]; | |
580 uint32_t class; | |
581 uint32_t color_space; | |
582 uint32_t pcs; | |
583 @@ -241,6 +255,7 @@ struct _qcms_profile { | |
584 struct lutmABType *mAB; | |
585 struct lutmABType *mBA; | |
586 struct matrix chromaticAdaption; | |
587 + struct vcgtType vcgt; | |
588 | |
589 struct precache_output *output_table_r; | |
590 struct precache_output *output_table_g; | |
591 @@ -280,18 +295,40 @@ qcms_bool set_rgb_colorants(qcms_profile *profile, qcms_CI
E_xyY white_point, qcm | |
592 void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *transform, | |
593 unsigned char *src, | |
594 unsigned char *dest, | |
595 - size_t length); | |
596 + size_t length, | |
597 + qcms_format_type output_format); | |
598 void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *transform, | |
599 unsigned char *src, | |
600 unsigned char *dest, | |
601 - size_t length); | |
602 + size_t length, | |
603 + qcms_format_type output_format); | |
604 void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *transform, | |
605 unsigned char *src, | |
606 unsigned char *dest, | |
607 - size_t length); | |
608 + size_t length, | |
609 + qcms_format_type output_format); | |
610 void qcms_transform_data_rgba_out_lut_sse1(qcms_transform *transform, | |
611 unsigned char *src, | |
612 unsigned char *dest, | |
613 - size_t length); | |
614 + size_t length, | |
615 + qcms_format_type output_format); | |
616 | |
617 extern qcms_bool qcms_supports_iccv4; | |
618 + | |
619 + | |
620 +#ifdef _MSC_VER | |
621 + | |
622 +long __cdecl _InterlockedIncrement(long volatile *); | |
623 +long __cdecl _InterlockedDecrement(long volatile *); | |
624 +#pragma intrinsic(_InterlockedIncrement) | |
625 +#pragma intrinsic(_InterlockedDecrement) | |
626 + | |
627 +#define qcms_atomic_increment(x) _InterlockedIncrement((long volatile *)&x) | |
628 +#define qcms_atomic_decrement(x) _InterlockedDecrement((long volatile*)&x) | |
629 + | |
630 +#else | |
631 + | |
632 +#define qcms_atomic_increment(x) __sync_add_and_fetch(&x, 1) | |
633 +#define qcms_atomic_decrement(x) __sync_sub_and_fetch(&x, 1) | |
634 + | |
635 +#endif | |
636 diff --git a/third_party/qcms/src/qcmstypes.h b/third_party/qcms/src/qcmstypes.h | |
637 index 56d8de3..d58f691 100644 | |
638 --- a/third_party/qcms/src/qcmstypes.h | |
639 +++ b/third_party/qcms/src/qcmstypes.h | |
640 @@ -22,37 +22,6 @@ | |
641 #ifndef QCMS_TYPES_H | |
642 #define QCMS_TYPES_H | |
643 | |
644 -#ifdef MOZ_QCMS | |
645 - | |
646 -#include "prtypes.h" | |
647 - | |
648 -/* prtypes.h defines IS_LITTLE_ENDIAN and IS_BIG ENDIAN */ | |
649 - | |
650 -#if defined (__SVR4) && defined (__sun) | |
651 -/* int_types.h gets included somehow, so avoid redefining the types differently
*/ | |
652 -#include <sys/int_types.h> | |
653 -#elif defined (_AIX) | |
654 -#include <sys/types.h> | |
655 -#elif !defined(ANDROID) && !defined(__OpenBSD__) | |
656 -typedef PRInt8 int8_t; | |
657 -typedef PRUint8 uint8_t; | |
658 -typedef PRInt16 int16_t; | |
659 -typedef PRUint16 uint16_t; | |
660 -typedef PRInt32 int32_t; | |
661 -typedef PRUint32 uint32_t; | |
662 -typedef PRInt64 int64_t; | |
663 -typedef PRUint64 uint64_t; | |
664 - | |
665 -#ifdef __OS2__ | |
666 -/* OS/2's stdlib typdefs uintptr_t. So we'll just include that so we don't coll
ide */ | |
667 -#include <stdlib.h> | |
668 -#elif !defined(__intptr_t_defined) && !defined(_UINTPTR_T_DEFINED) | |
669 -typedef PRUptrdiff uintptr_t; | |
670 -#endif | |
671 -#endif | |
672 - | |
673 -#else // MOZ_QCMS | |
674 - | |
675 #if BYTE_ORDER == LITTLE_ENDIAN | |
676 #define IS_LITTLE_ENDIAN | |
677 #elif BYTE_ORDER == BIG_ENDIAN | |
678 @@ -75,7 +44,7 @@ typedef PRUptrdiff uintptr_t; | |
679 | |
680 #if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || defined (_sgi
) || defined (__sun) || defined (sun) || defined (__digital__) | |
681 # include <inttypes.h> | |
682 -#elif defined (_MSC_VER) | |
683 +#elif defined (_MSC_VER) && _MSC_VER < 1600 | |
684 typedef __int8 int8_t; | |
685 typedef unsigned __int8 uint8_t; | |
686 typedef __int16 int16_t; | |
687 @@ -87,7 +56,12 @@ typedef unsigned __int64 uint64_t; | |
688 #ifdef _WIN64 | |
689 typedef unsigned __int64 uintptr_t; | |
690 #else | |
691 +#pragma warning(push) | |
692 +/* Disable benign redefinition of type warning 4142 */ | |
693 +#pragma warning(disable:4142) | |
694 typedef unsigned long uintptr_t; | |
695 +/* Restore warnings */ | |
696 +#pragma warning(pop) | |
697 #endif | |
698 | |
699 #elif defined (_AIX) | |
700 @@ -96,8 +70,6 @@ typedef unsigned long uintptr_t; | |
701 # include <stdint.h> | |
702 #endif | |
703 | |
704 -#endif | |
705 - | |
706 typedef qcms_bool bool; | |
707 #define true 1 | |
708 #define false 0 | |
709 diff --git a/third_party/qcms/src/transform-sse1.c b/third_party/qcms/src/transf
orm-sse1.c | |
710 index 2f34db5..aaee1bf 100644 | |
711 --- a/third_party/qcms/src/transform-sse1.c | |
712 +++ b/third_party/qcms/src/transform-sse1.c | |
713 @@ -34,7 +34,8 @@ static const ALIGN float clampMaxValueX4[4] = | |
714 void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *transform, | |
715 unsigned char *src, | |
716 unsigned char *dest, | |
717 - size_t length) | |
718 + size_t length, | |
719 + qcms_format_type output_format) | |
720 { | |
721 unsigned int i; | |
722 float (*mat)[4] = transform->matrix; | |
723 @@ -70,6 +71,8 @@ void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *tran
sform, | |
724 | |
725 /* working variables */ | |
726 __m128 vec_r, vec_g, vec_b, result; | |
727 + const int r_out = output_format.r; | |
728 + const int b_out = output_format.b; | |
729 | |
730 /* CYA */ | |
731 if (!length) | |
732 @@ -116,9 +119,9 @@ void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *tr
ansform, | |
733 src += 3; | |
734 | |
735 /* use calc'd indices to output RGB values */ | |
736 - dest[0] = otdata_r[output[0]]; | |
737 - dest[1] = otdata_g[output[1]]; | |
738 - dest[2] = otdata_b[output[2]]; | |
739 + dest[r_out] = otdata_r[output[0]]; | |
740 + dest[1] = otdata_g[output[1]]; | |
741 + dest[b_out] = otdata_b[output[2]]; | |
742 dest += 3; | |
743 } | |
744 | |
745 @@ -141,9 +144,9 @@ void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *tr
ansform, | |
746 result = _mm_movehl_ps(result, result); | |
747 *((__m64 *)&output[2]) = _mm_cvtps_pi32(result); | |
748 | |
749 - dest[0] = otdata_r[output[0]]; | |
750 - dest[1] = otdata_g[output[1]]; | |
751 - dest[2] = otdata_b[output[2]]; | |
752 + dest[r_out] = otdata_r[output[0]]; | |
753 + dest[1] = otdata_g[output[1]]; | |
754 + dest[b_out] = otdata_b[output[2]]; | |
755 | |
756 _mm_empty(); | |
757 } | |
758 @@ -151,7 +154,8 @@ void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *tr
ansform, | |
759 void qcms_transform_data_rgba_out_lut_sse1(qcms_transform *transform, | |
760 unsigned char *src, | |
761 unsigned char *dest, | |
762 - size_t length) | |
763 + size_t length, | |
764 + qcms_format_type output_format) | |
765 { | |
766 unsigned int i; | |
767 float (*mat)[4] = transform->matrix; | |
768 @@ -187,6 +191,8 @@ void qcms_transform_data_rgba_out_lut_sse1(qcms_transform *t
ransform, | |
769 | |
770 /* working variables */ | |
771 __m128 vec_r, vec_g, vec_b, result; | |
772 + const int r_out = output_format.r; | |
773 + const int b_out = output_format.b; | |
774 unsigned char alpha; | |
775 | |
776 /* CYA */ | |
777 @@ -239,9 +245,9 @@ void qcms_transform_data_rgba_out_lut_sse1(qcms_transform *t
ransform, | |
778 src += 4; | |
779 | |
780 /* use calc'd indices to output RGB values */ | |
781 - dest[0] = otdata_r[output[0]]; | |
782 - dest[1] = otdata_g[output[1]]; | |
783 - dest[2] = otdata_b[output[2]]; | |
784 + dest[r_out] = otdata_r[output[0]]; | |
785 + dest[1] = otdata_g[output[1]]; | |
786 + dest[b_out] = otdata_b[output[2]]; | |
787 dest += 4; | |
788 } | |
789 | |
790 @@ -266,9 +272,9 @@ void qcms_transform_data_rgba_out_lut_sse1(qcms_transform *t
ransform, | |
791 result = _mm_movehl_ps(result, result); | |
792 *((__m64 *)&output[2]) = _mm_cvtps_pi32(result); | |
793 | |
794 - dest[0] = otdata_r[output[0]]; | |
795 - dest[1] = otdata_g[output[1]]; | |
796 - dest[2] = otdata_b[output[2]]; | |
797 + dest[r_out] = otdata_r[output[0]]; | |
798 + dest[1] = otdata_g[output[1]]; | |
799 + dest[b_out] = otdata_b[output[2]]; | |
800 | |
801 _mm_empty(); | |
802 } | |
803 diff --git a/third_party/qcms/src/transform-sse2.c b/third_party/qcms/src/transf
orm-sse2.c | |
804 index 6a5faf9..fa7f2d1 100644 | |
805 --- a/third_party/qcms/src/transform-sse2.c | |
806 +++ b/third_party/qcms/src/transform-sse2.c | |
807 @@ -34,7 +34,8 @@ static const ALIGN float clampMaxValueX4[4] = | |
808 void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *transform, | |
809 unsigned char *src, | |
810 unsigned char *dest, | |
811 - size_t length) | |
812 + size_t length, | |
813 + qcms_format_type output_format) | |
814 { | |
815 unsigned int i; | |
816 float (*mat)[4] = transform->matrix; | |
817 @@ -70,6 +71,8 @@ void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *tran
sform, | |
818 | |
819 /* working variables */ | |
820 __m128 vec_r, vec_g, vec_b, result; | |
821 + const int r_out = output_format.r; | |
822 + const int b_out = output_format.b; | |
823 | |
824 /* CYA */ | |
825 if (!length) | |
826 @@ -114,9 +117,9 @@ void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *tr
ansform, | |
827 src += 3; | |
828 | |
829 /* use calc'd indices to output RGB values */ | |
830 - dest[0] = otdata_r[output[0]]; | |
831 - dest[1] = otdata_g[output[1]]; | |
832 - dest[2] = otdata_b[output[2]]; | |
833 + dest[r_out] = otdata_r[output[0]]; | |
834 + dest[1] = otdata_g[output[1]]; | |
835 + dest[b_out] = otdata_b[output[2]]; | |
836 dest += 3; | |
837 } | |
838 | |
839 @@ -137,15 +140,16 @@ void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *
transform, | |
840 | |
841 _mm_store_si128((__m128i*)output, _mm_cvtps_epi32(result)); | |
842 | |
843 - dest[0] = otdata_r[output[0]]; | |
844 - dest[1] = otdata_g[output[1]]; | |
845 - dest[2] = otdata_b[output[2]]; | |
846 + dest[r_out] = otdata_r[output[0]]; | |
847 + dest[1] = otdata_g[output[1]]; | |
848 + dest[b_out] = otdata_b[output[2]]; | |
849 } | |
850 | |
851 void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *transform, | |
852 unsigned char *src, | |
853 unsigned char *dest, | |
854 - size_t length) | |
855 + size_t length, | |
856 + qcms_format_type output_format) | |
857 { | |
858 unsigned int i; | |
859 float (*mat)[4] = transform->matrix; | |
860 @@ -181,6 +185,8 @@ void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *t
ransform, | |
861 | |
862 /* working variables */ | |
863 __m128 vec_r, vec_g, vec_b, result; | |
864 + const int r_out = output_format.r; | |
865 + const int b_out = output_format.b; | |
866 unsigned char alpha; | |
867 | |
868 /* CYA */ | |
869 @@ -231,9 +237,9 @@ void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *t
ransform, | |
870 src += 4; | |
871 | |
872 /* use calc'd indices to output RGB values */ | |
873 - dest[0] = otdata_r[output[0]]; | |
874 - dest[1] = otdata_g[output[1]]; | |
875 - dest[2] = otdata_b[output[2]]; | |
876 + dest[r_out] = otdata_r[output[0]]; | |
877 + dest[1] = otdata_g[output[1]]; | |
878 + dest[b_out] = otdata_b[output[2]]; | |
879 dest += 4; | |
880 } | |
881 | |
882 @@ -256,7 +262,7 @@ void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *t
ransform, | |
883 | |
884 _mm_store_si128((__m128i*)output, _mm_cvtps_epi32(result)); | |
885 | |
886 - dest[0] = otdata_r[output[0]]; | |
887 - dest[1] = otdata_g[output[1]]; | |
888 - dest[2] = otdata_b[output[2]]; | |
889 + dest[r_out] = otdata_r[output[0]]; | |
890 + dest[1] = otdata_g[output[1]]; | |
891 + dest[b_out] = otdata_b[output[2]]; | |
892 } | |
893 diff --git a/third_party/qcms/src/transform.c b/third_party/qcms/src/transform.c | |
894 index 9a6562b..f669a6b 100644 | |
895 --- a/third_party/qcms/src/transform.c | |
896 +++ b/third_party/qcms/src/transform.c | |
897 @@ -181,11 +181,20 @@ compute_chromatic_adaption(struct CIE_XYZ source_white_poi
nt, | |
898 static struct matrix | |
899 adaption_matrix(struct CIE_XYZ source_illumination, struct CIE_XYZ target_illum
ination) | |
900 { | |
901 +#if defined (_MSC_VER) | |
902 +#pragma warning(push) | |
903 +/* Disable double to float truncation warning 4305 */ | |
904 +#pragma warning(disable:4305) | |
905 +#endif | |
906 struct matrix lam_rigg = {{ // Bradford matrix | |
907 { 0.8951, 0.2664, -0.1614 }, | |
908 { -0.7502, 1.7135, 0.0367 }, | |
909 { 0.0389, -0.0685, 1.0296 } | |
910 }}; | |
911 +#if defined (_MSC_VER) | |
912 +/* Restore warnings */ | |
913 +#pragma warning(pop) | |
914 +#endif | |
915 return compute_chromatic_adaption(source_illumination, target_illuminati
on, lam_rigg); | |
916 } | |
917 | |
918 @@ -230,8 +239,11 @@ qcms_bool set_rgb_colorants(qcms_profile *profile, qcms_CIE
_xyY white_point, qcm | |
919 } | |
920 | |
921 #if 0 | |
922 -static void qcms_transform_data_rgb_out_pow(qcms_transform *transform, unsigned
char *src, unsigned char *dest, size_t length) | |
923 +static void qcms_transform_data_rgb_out_pow(qcms_transform *transform, unsigned
char *src, unsigned char *dest, size_t length, qcms_format_type output_format) | |
924 { | |
925 + const int r_out = output_format.r; | |
926 + const int b_out = output_format.b; | |
927 + | |
928 int i; | |
929 float (*mat)[4] = transform->matrix; | |
930 for (i=0; i<length; i++) { | |
931 @@ -251,15 +263,19 @@ static void qcms_transform_data_rgb_out_pow(qcms_transform
*transform, unsigned | |
932 float out_device_g = pow(out_linear_g, transform->out_gamma_g); | |
933 float out_device_b = pow(out_linear_b, transform->out_gamma_b); | |
934 | |
935 - *dest++ = clamp_u8(255*out_device_r); | |
936 - *dest++ = clamp_u8(255*out_device_g); | |
937 - *dest++ = clamp_u8(255*out_device_b); | |
938 + dest[r_out] = clamp_u8(out_device_r*255); | |
939 + dest[1] = clamp_u8(out_device_g*255); | |
940 + dest[b_out] = clamp_u8(out_device_b*255); | |
941 + dest += 3; | |
942 } | |
943 } | |
944 #endif | |
945 | |
946 -static void qcms_transform_data_gray_out_lut(qcms_transform *transform, unsigne
d char *src, unsigned char *dest, size_t length) | |
947 +static void qcms_transform_data_gray_out_lut(qcms_transform *transform, unsigne
d char *src, unsigned char *dest, size_t length, qcms_format_type output_format) | |
948 { | |
949 + const int r_out = output_format.r; | |
950 + const int b_out = output_format.b; | |
951 + | |
952 unsigned int i; | |
953 for (i = 0; i < length; i++) { | |
954 float out_device_r, out_device_g, out_device_b; | |
955 @@ -267,13 +283,14 @@ static void qcms_transform_data_gray_out_lut(qcms_transfor
m *transform, unsigned | |
956 | |
957 float linear = transform->input_gamma_table_gray[device]; | |
958 | |
959 - out_device_r = lut_interp_linear(linear, transform->output_gamm
a_lut_r, transform->output_gamma_lut_r_length); | |
960 + out_device_r = lut_interp_linear(linear, transform->output_gamma
_lut_r, transform->output_gamma_lut_r_length); | |
961 out_device_g = lut_interp_linear(linear, transform->output_gamma
_lut_g, transform->output_gamma_lut_g_length); | |
962 out_device_b = lut_interp_linear(linear, transform->output_gamma
_lut_b, transform->output_gamma_lut_b_length); | |
963 | |
964 - *dest++ = clamp_u8(out_device_r*255); | |
965 - *dest++ = clamp_u8(out_device_g*255); | |
966 - *dest++ = clamp_u8(out_device_b*255); | |
967 + dest[r_out] = clamp_u8(out_device_r*255); | |
968 + dest[1] = clamp_u8(out_device_g*255); | |
969 + dest[b_out] = clamp_u8(out_device_b*255); | |
970 + dest += 3; | |
971 } | |
972 } | |
973 | |
974 @@ -283,8 +300,11 @@ static void qcms_transform_data_gray_out_lut(qcms_transform
*transform, unsigned | |
975 See: ftp://ftp.alvyray.com/Acrobat/17_Nonln.pdf | |
976 */ | |
977 | |
978 -static void qcms_transform_data_graya_out_lut(qcms_transform *transform, unsign
ed char *src, unsigned char *dest, size_t length) | |
979 +static void qcms_transform_data_graya_out_lut(qcms_transform *transform, unsign
ed char *src, unsigned char *dest, size_t length, qcms_format_type output_format
) | |
980 { | |
981 + const int r_out = output_format.r; | |
982 + const int b_out = output_format.b; | |
983 + | |
984 unsigned int i; | |
985 for (i = 0; i < length; i++) { | |
986 float out_device_r, out_device_g, out_device_b; | |
987 @@ -293,20 +313,24 @@ static void qcms_transform_data_graya_out_lut(qcms_transfo
rm *transform, unsigne | |
988 | |
989 float linear = transform->input_gamma_table_gray[device]; | |
990 | |
991 - out_device_r = lut_interp_linear(linear, transform->output_gamm
a_lut_r, transform->output_gamma_lut_r_length); | |
992 + out_device_r = lut_interp_linear(linear, transform->output_gamma
_lut_r, transform->output_gamma_lut_r_length); | |
993 out_device_g = lut_interp_linear(linear, transform->output_gamma
_lut_g, transform->output_gamma_lut_g_length); | |
994 out_device_b = lut_interp_linear(linear, transform->output_gamma
_lut_b, transform->output_gamma_lut_b_length); | |
995 | |
996 - *dest++ = clamp_u8(out_device_r*255); | |
997 - *dest++ = clamp_u8(out_device_g*255); | |
998 - *dest++ = clamp_u8(out_device_b*255); | |
999 - *dest++ = alpha; | |
1000 + dest[r_out] = clamp_u8(out_device_r*255); | |
1001 + dest[1] = clamp_u8(out_device_g*255); | |
1002 + dest[b_out] = clamp_u8(out_device_b*255); | |
1003 + dest[3] = alpha; | |
1004 + dest += 4; | |
1005 } | |
1006 } | |
1007 | |
1008 | |
1009 -static void qcms_transform_data_gray_out_precache(qcms_transform *transform, un
signed char *src, unsigned char *dest, size_t length) | |
1010 +static void qcms_transform_data_gray_out_precache(qcms_transform *transform, un
signed char *src, unsigned char *dest, size_t length, qcms_format_type output_fo
rmat) | |
1011 { | |
1012 + const int r_out = output_format.r; | |
1013 + const int b_out = output_format.b; | |
1014 + | |
1015 unsigned int i; | |
1016 for (i = 0; i < length; i++) { | |
1017 unsigned char device = *src++; | |
1018 @@ -317,14 +341,19 @@ static void qcms_transform_data_gray_out_precache(qcms_tra
nsform *transform, uns | |
1019 /* we could round here... */ | |
1020 gray = linear * PRECACHE_OUTPUT_MAX; | |
1021 | |
1022 - *dest++ = transform->output_table_r->data[gray]; | |
1023 - *dest++ = transform->output_table_g->data[gray]; | |
1024 - *dest++ = transform->output_table_b->data[gray]; | |
1025 + dest[r_out] = transform->output_table_r->data[gray]; | |
1026 + dest[1] = transform->output_table_g->data[gray]; | |
1027 + dest[b_out] = transform->output_table_b->data[gray]; | |
1028 + dest += 3; | |
1029 } | |
1030 } | |
1031 | |
1032 -static void qcms_transform_data_graya_out_precache(qcms_transform *transform, u
nsigned char *src, unsigned char *dest, size_t length) | |
1033 + | |
1034 +static void qcms_transform_data_graya_out_precache(qcms_transform *transform, u
nsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_f
ormat) | |
1035 { | |
1036 + const int r_out = output_format.r; | |
1037 + const int b_out = output_format.b; | |
1038 + | |
1039 unsigned int i; | |
1040 for (i = 0; i < length; i++) { | |
1041 unsigned char device = *src++; | |
1042 @@ -336,15 +365,19 @@ static void qcms_transform_data_graya_out_precache(qcms_tr
ansform *transform, un | |
1043 /* we could round here... */ | |
1044 gray = linear * PRECACHE_OUTPUT_MAX; | |
1045 | |
1046 - *dest++ = transform->output_table_r->data[gray]; | |
1047 - *dest++ = transform->output_table_g->data[gray]; | |
1048 - *dest++ = transform->output_table_b->data[gray]; | |
1049 - *dest++ = alpha; | |
1050 + dest[r_out] = transform->output_table_r->data[gray]; | |
1051 + dest[1] = transform->output_table_g->data[gray]; | |
1052 + dest[b_out] = transform->output_table_b->data[gray]; | |
1053 + dest[3] = alpha; | |
1054 + dest += 4; | |
1055 } | |
1056 } | |
1057 | |
1058 -static void qcms_transform_data_rgb_out_lut_precache(qcms_transform *transform,
unsigned char *src, unsigned char *dest, size_t length) | |
1059 +static void qcms_transform_data_rgb_out_lut_precache(qcms_transform *transform,
unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output
_format) | |
1060 { | |
1061 + const int r_out = output_format.r; | |
1062 + const int b_out = output_format.b; | |
1063 + | |
1064 unsigned int i; | |
1065 float (*mat)[4] = transform->matrix; | |
1066 for (i = 0; i < length; i++) { | |
1067 @@ -370,14 +403,18 @@ static void qcms_transform_data_rgb_out_lut_precache(qcms_
transform *transform, | |
1068 g = out_linear_g * PRECACHE_OUTPUT_MAX; | |
1069 b = out_linear_b * PRECACHE_OUTPUT_MAX; | |
1070 | |
1071 - *dest++ = transform->output_table_r->data[r]; | |
1072 - *dest++ = transform->output_table_g->data[g]; | |
1073 - *dest++ = transform->output_table_b->data[b]; | |
1074 + dest[r_out] = transform->output_table_r->data[r]; | |
1075 + dest[1] = transform->output_table_g->data[g]; | |
1076 + dest[b_out] = transform->output_table_b->data[b]; | |
1077 + dest += 3; | |
1078 } | |
1079 } | |
1080 | |
1081 -static void qcms_transform_data_rgba_out_lut_precache(qcms_transform *transform
, unsigned char *src, unsigned char *dest, size_t length) | |
1082 +static void qcms_transform_data_rgba_out_lut_precache(qcms_transform *transform
, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type outpu
t_format) | |
1083 { | |
1084 + const int r_out = output_format.r; | |
1085 + const int b_out = output_format.b; | |
1086 + | |
1087 unsigned int i; | |
1088 float (*mat)[4] = transform->matrix; | |
1089 for (i = 0; i < length; i++) { | |
1090 @@ -404,16 +441,21 @@ static void qcms_transform_data_rgba_out_lut_precache(qcms
_transform *transform, | |
1091 g = out_linear_g * PRECACHE_OUTPUT_MAX; | |
1092 b = out_linear_b * PRECACHE_OUTPUT_MAX; | |
1093 | |
1094 - *dest++ = transform->output_table_r->data[r]; | |
1095 - *dest++ = transform->output_table_g->data[g]; | |
1096 - *dest++ = transform->output_table_b->data[b]; | |
1097 - *dest++ = alpha; | |
1098 + dest[r_out] = transform->output_table_r->data[r]; | |
1099 + dest[1] = transform->output_table_g->data[g]; | |
1100 + dest[b_out] = transform->output_table_b->data[b]; | |
1101 + dest[3] = alpha; | |
1102 + dest += 4; | |
1103 } | |
1104 } | |
1105 | |
1106 // Not used | |
1107 /* | |
1108 -static void qcms_transform_data_clut(qcms_transform *transform, unsigned char *
src, unsigned char *dest, size_t length) { | |
1109 +static void qcms_transform_data_clut(qcms_transform *transform, unsigned char *
src, unsigned char *dest, size_t length, qcms_format_type output_format) | |
1110 +{ | |
1111 + const int r_out = output_format.r; | |
1112 + const int b_out = output_format.b; | |
1113 + | |
1114 unsigned int i; | |
1115 int xy_len = 1; | |
1116 int x_len = transform->grid_size; | |
1117 @@ -462,15 +504,20 @@ static void qcms_transform_data_clut(qcms_transform *trans
form, unsigned char *s | |
1118 float b_y2 = lerp(b_x3, b_x4, y_d); | |
1119 float clut_b = lerp(b_y1, b_y2, z_d); | |
1120 | |
1121 - *dest++ = clamp_u8(clut_r*255.0f); | |
1122 - *dest++ = clamp_u8(clut_g*255.0f); | |
1123 - *dest++ = clamp_u8(clut_b*255.0f); | |
1124 - } | |
1125 + dest[r_out] = clamp_u8(clut_r*255.0f); | |
1126 + dest[1] = clamp_u8(clut_g*255.0f); | |
1127 + dest[b_out] = clamp_u8(clut_b*255.0f); | |
1128 + dest += 3; | |
1129 + } | |
1130 } | |
1131 */ | |
1132 | |
1133 // Using lcms' tetra interpolation algorithm. | |
1134 -static void qcms_transform_data_tetra_clut_rgba(qcms_transform *transform, unsi
gned char *src, unsigned char *dest, size_t length) { | |
1135 +static void qcms_transform_data_tetra_clut_rgba(qcms_transform *transform, unsi
gned char *src, unsigned char *dest, size_t length, qcms_format_type output_form
at) | |
1136 +{ | |
1137 + const int r_out = output_format.r; | |
1138 + const int b_out = output_format.b; | |
1139 + | |
1140 unsigned int i; | |
1141 int xy_len = 1; | |
1142 int x_len = transform->grid_size; | |
1143 @@ -577,15 +624,20 @@ static void qcms_transform_data_tetra_clut_rgba(qcms_trans
form *transform, unsig | |
1144 clut_g = c0_g + c1_g*rx + c2_g*ry + c3_g*rz; | |
1145 clut_b = c0_b + c1_b*rx + c2_b*ry + c3_b*rz; | |
1146 | |
1147 - *dest++ = clamp_u8(clut_r*255.0f); | |
1148 - *dest++ = clamp_u8(clut_g*255.0f); | |
1149 - *dest++ = clamp_u8(clut_b*255.0f); | |
1150 - *dest++ = in_a; | |
1151 - } | |
1152 + dest[r_out] = clamp_u8(clut_r*255.0f); | |
1153 + dest[1] = clamp_u8(clut_g*255.0f); | |
1154 + dest[b_out] = clamp_u8(clut_b*255.0f); | |
1155 + dest[3] = in_a; | |
1156 + dest += 4; | |
1157 + } | |
1158 } | |
1159 | |
1160 // Using lcms' tetra interpolation code. | |
1161 -static void qcms_transform_data_tetra_clut(qcms_transform *transform, unsigned
char *src, unsigned char *dest, size_t length) { | |
1162 +static void qcms_transform_data_tetra_clut(qcms_transform *transform, unsigned
char *src, unsigned char *dest, size_t length, qcms_format_type output_format) | |
1163 +{ | |
1164 + const int r_out = output_format.r; | |
1165 + const int b_out = output_format.b; | |
1166 + | |
1167 unsigned int i; | |
1168 int xy_len = 1; | |
1169 int x_len = transform->grid_size; | |
1170 @@ -691,14 +743,18 @@ static void qcms_transform_data_tetra_clut(qcms_transform
*transform, unsigned c | |
1171 clut_g = c0_g + c1_g*rx + c2_g*ry + c3_g*rz; | |
1172 clut_b = c0_b + c1_b*rx + c2_b*ry + c3_b*rz; | |
1173 | |
1174 - *dest++ = clamp_u8(clut_r*255.0f); | |
1175 - *dest++ = clamp_u8(clut_g*255.0f); | |
1176 - *dest++ = clamp_u8(clut_b*255.0f); | |
1177 - } | |
1178 + dest[r_out] = clamp_u8(clut_r*255.0f); | |
1179 + dest[1] = clamp_u8(clut_g*255.0f); | |
1180 + dest[b_out] = clamp_u8(clut_b*255.0f); | |
1181 + dest += 3; | |
1182 + } | |
1183 } | |
1184 | |
1185 -static void qcms_transform_data_rgb_out_lut(qcms_transform *transform, unsigned
char *src, unsigned char *dest, size_t length) | |
1186 +static void qcms_transform_data_rgb_out_lut(qcms_transform *transform, unsigned
char *src, unsigned char *dest, size_t length, qcms_format_type output_format) | |
1187 { | |
1188 + const int r_out = output_format.r; | |
1189 + const int b_out = output_format.b; | |
1190 + | |
1191 unsigned int i; | |
1192 float (*mat)[4] = transform->matrix; | |
1193 for (i = 0; i < length; i++) { | |
1194 @@ -726,14 +782,18 @@ static void qcms_transform_data_rgb_out_lut(qcms_transform
*transform, unsigned | |
1195 out_device_b = lut_interp_linear(out_linear_b, | |
1196 transform->output_gamma_lut_b, transform->output
_gamma_lut_b_length); | |
1197 | |
1198 - *dest++ = clamp_u8(out_device_r*255); | |
1199 - *dest++ = clamp_u8(out_device_g*255); | |
1200 - *dest++ = clamp_u8(out_device_b*255); | |
1201 + dest[r_out] = clamp_u8(out_device_r*255); | |
1202 + dest[1] = clamp_u8(out_device_g*255); | |
1203 + dest[b_out] = clamp_u8(out_device_b*255); | |
1204 + dest += 3; | |
1205 } | |
1206 } | |
1207 | |
1208 -static void qcms_transform_data_rgba_out_lut(qcms_transform *transform, unsigne
d char *src, unsigned char *dest, size_t length) | |
1209 +static void qcms_transform_data_rgba_out_lut(qcms_transform *transform, unsigne
d char *src, unsigned char *dest, size_t length, qcms_format_type output_format) | |
1210 { | |
1211 + const int r_out = output_format.r; | |
1212 + const int b_out = output_format.b; | |
1213 + | |
1214 unsigned int i; | |
1215 float (*mat)[4] = transform->matrix; | |
1216 for (i = 0; i < length; i++) { | |
1217 @@ -762,16 +822,20 @@ static void qcms_transform_data_rgba_out_lut(qcms_transfor
m *transform, unsigned | |
1218 out_device_b = lut_interp_linear(out_linear_b, | |
1219 transform->output_gamma_lut_b, transform->output
_gamma_lut_b_length); | |
1220 | |
1221 - *dest++ = clamp_u8(out_device_r*255); | |
1222 - *dest++ = clamp_u8(out_device_g*255); | |
1223 - *dest++ = clamp_u8(out_device_b*255); | |
1224 - *dest++ = alpha; | |
1225 + dest[r_out] = clamp_u8(out_device_r*255); | |
1226 + dest[1] = clamp_u8(out_device_g*255); | |
1227 + dest[b_out] = clamp_u8(out_device_b*255); | |
1228 + dest[3] = alpha; | |
1229 + dest += 4; | |
1230 } | |
1231 } | |
1232 | |
1233 #if 0 | |
1234 -static void qcms_transform_data_rgb_out_linear(qcms_transform *transform, unsig
ned char *src, unsigned char *dest, size_t length) | |
1235 +static void qcms_transform_data_rgb_out_linear(qcms_transform *transform, unsig
ned char *src, unsigned char *dest, size_t length, qcms_format_type output_forma
t) | |
1236 { | |
1237 + const int r_out = output_format.r; | |
1238 + const int b_out = output_format.b; | |
1239 + | |
1240 int i; | |
1241 float (*mat)[4] = transform->matrix; | |
1242 for (i = 0; i < length; i++) { | |
1243 @@ -787,16 +851,25 @@ static void qcms_transform_data_rgb_out_linear(qcms_transf
orm *transform, unsign | |
1244 float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + m
at[2][1]*linear_b; | |
1245 float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + m
at[2][2]*linear_b; | |
1246 | |
1247 - *dest++ = clamp_u8(out_linear_r*255); | |
1248 - *dest++ = clamp_u8(out_linear_g*255); | |
1249 - *dest++ = clamp_u8(out_linear_b*255); | |
1250 + dest[r_out] = clamp_u8(out_linear_r*255); | |
1251 + dest[1] = clamp_u8(out_linear_g*255); | |
1252 + dest[b_out] = clamp_u8(out_linear_b*255); | |
1253 + dest += 3; | |
1254 } | |
1255 } | |
1256 #endif | |
1257 | |
1258 +/* | |
1259 + * If users create and destroy objects on different threads, even if the same | |
1260 + * objects aren't used on different threads at the same time, we can still run | |
1261 + * in to trouble with refcounts if they aren't atomic. | |
1262 + * | |
1263 + * This can lead to us prematurely deleting the precache if threads get unlucky | |
1264 + * and write the wrong value to the ref count. | |
1265 + */ | |
1266 static struct precache_output *precache_reference(struct precache_output *p) | |
1267 { | |
1268 - p->ref_count++; | |
1269 + qcms_atomic_increment(p->ref_count); | |
1270 return p; | |
1271 } | |
1272 | |
1273 @@ -810,12 +883,12 @@ static struct precache_output *precache_create() | |
1274 | |
1275 void precache_release(struct precache_output *p) | |
1276 { | |
1277 - if (--p->ref_count == 0) { | |
1278 + if (qcms_atomic_decrement(p->ref_count) == 0) { | |
1279 free(p); | |
1280 } | |
1281 } | |
1282 | |
1283 -#ifdef HAS_POSIX_MEMALIGN | |
1284 +#ifdef HAVE_POSIX_MEMALIGN | |
1285 static qcms_transform *transform_alloc(void) | |
1286 { | |
1287 qcms_transform *t; | |
1288 @@ -994,13 +1067,15 @@ void qcms_profile_precache_output_transform(qcms_profile
*profile) | |
1289 if (profile->color_space != RGB_SIGNATURE) | |
1290 return; | |
1291 | |
1292 - /* don't precache since we will use the B2A LUT */ | |
1293 - if (profile->B2A0) | |
1294 - return; | |
1295 + if (qcms_supports_iccv4) { | |
1296 + /* don't precache since we will use the B2A LUT */ | |
1297 + if (profile->B2A0) | |
1298 + return; | |
1299 | |
1300 - /* don't precache since we will use the mBA LUT */ | |
1301 - if (profile->mBA) | |
1302 - return; | |
1303 + /* don't precache since we will use the mBA LUT */ | |
1304 + if (profile->mBA) | |
1305 + return; | |
1306 + } | |
1307 | |
1308 /* don't precache if we do not have the TRC curves */ | |
1309 if (!profile->redTRC || !profile->greenTRC || !profile->blueTRC) | |
1310 @@ -1043,28 +1118,31 @@ qcms_transform* qcms_transform_precacheLUT_float(qcms_tr
ansform *transform, qcms | |
1311 float* src = NULL; | |
1312 float* dest = NULL; | |
1313 float* lut = NULL; | |
1314 + float inverse; | |
1315 | |
1316 src = malloc(lutSize*sizeof(float)); | |
1317 dest = malloc(lutSize*sizeof(float)); | |
1318 | |
1319 if (src && dest) { | |
1320 - /* Prepare a list of points we want to sample */ | |
1321 + /* Prepare a list of points we want to sample: x, y, z order */ | |
1322 l = 0; | |
1323 + inverse = 1 / (float)(samples-1); | |
1324 for (x = 0; x < samples; x++) { | |
1325 for (y = 0; y < samples; y++) { | |
1326 for (z = 0; z < samples; z++) { | |
1327 - src[l++] = x / (float)(samples-1); | |
1328 - src[l++] = y / (float)(samples-1); | |
1329 - src[l++] = z / (float)(samples-1); | |
1330 + src[l++] = x * inverse; // r | |
1331 + src[l++] = y * inverse; // g | |
1332 + src[l++] = z * inverse; // b | |
1333 } | |
1334 } | |
1335 } | |
1336 | |
1337 lut = qcms_chain_transform(in, out, src, dest, lutSize); | |
1338 + | |
1339 if (lut) { | |
1340 - transform->r_clut = &lut[0]; | |
1341 - transform->g_clut = &lut[1]; | |
1342 - transform->b_clut = &lut[2]; | |
1343 + transform->r_clut = &lut[0]; // r | |
1344 + transform->g_clut = &lut[1]; // g | |
1345 + transform->b_clut = &lut[2]; // b | |
1346 transform->grid_size = samples; | |
1347 if (in_type == QCMS_DATA_RGBA_8) { | |
1348 transform->transform_fn = qcms_transform_data_te
tra_clut_rgba; | |
1349 @@ -1074,11 +1152,12 @@ qcms_transform* qcms_transform_precacheLUT_float(qcms_tr
ansform *transform, qcms | |
1350 } | |
1351 } | |
1352 | |
1353 - | |
1354 - //XXX: qcms_modular_transform_data may return either the src or dest buf
fer. If so it must not be free-ed | |
1355 + // XXX: qcms_modular_transform_data may return the lut in either the src
or the | |
1356 + // dest buffer. If so, it must not be free-ed. | |
1357 if (src && lut != src) { | |
1358 free(src); | |
1359 - } else if (dest && lut != src) { | |
1360 + } | |
1361 + if (dest && lut != dest) { | |
1362 free(dest); | |
1363 } | |
1364 | |
1365 @@ -1088,6 +1167,71 @@ qcms_transform* qcms_transform_precacheLUT_float(qcms_tra
nsform *transform, qcms | |
1366 return transform; | |
1367 } | |
1368 | |
1369 +/* Create a transform LUT using the given number of sample points. The transfor
m LUT data is stored | |
1370 + in the output (cube) in bgra format in zyx sample order. */ | |
1371 +qcms_bool qcms_transform_create_LUT_zyx_bgra(qcms_profile *in, qcms_profile *ou
t, qcms_intent intent, | |
1372 + int samples, unsigned char* cube) | |
1373 +{ | |
1374 + uint16_t z,y,x; | |
1375 + uint32_t l,index; | |
1376 + uint32_t lutSize = 3 * samples * samples * samples; | |
1377 + | |
1378 + float* src = NULL; | |
1379 + float* dest = NULL; | |
1380 + float* lut = NULL; | |
1381 + float inverse; | |
1382 + | |
1383 + src = malloc(lutSize*sizeof(float)); | |
1384 + dest = malloc(lutSize*sizeof(float)); | |
1385 + | |
1386 + if (src && dest) { | |
1387 + /* Prepare a list of points we want to sample: z, y, x order */ | |
1388 + l = 0; | |
1389 + inverse = 1 / (float)(samples-1); | |
1390 + for (z = 0; z < samples; z++) { | |
1391 + for (y = 0; y < samples; y++) { | |
1392 + for (x = 0; x < samples; x++) { | |
1393 + src[l++] = x * inverse; // r | |
1394 + src[l++] = y * inverse; // g | |
1395 + src[l++] = z * inverse; // b | |
1396 + } | |
1397 + } | |
1398 + } | |
1399 + | |
1400 + lut = qcms_chain_transform(in, out, src, dest, lutSize); | |
1401 + | |
1402 + if (lut) { | |
1403 + index = l = 0; | |
1404 + for (z = 0; z < samples; z++) { | |
1405 + for (y = 0; y < samples; y++) { | |
1406 + for (x = 0; x < samples; x++) { | |
1407 + cube[index++] = (int)floorf(lut[
l + 2] * 255.0f + 0.5f); // b | |
1408 + cube[index++] = (int)floorf(lut[
l + 1] * 255.0f + 0.5f); // g | |
1409 + cube[index++] = (int)floorf(lut[
l + 0] * 255.0f + 0.5f); // r | |
1410 + cube[index++] = 255;
// a | |
1411 + l += 3; | |
1412 + } | |
1413 + } | |
1414 + } | |
1415 + } | |
1416 + } | |
1417 + | |
1418 + // XXX: qcms_modular_transform_data may return the lut data in either th
e src or | |
1419 + // dest buffer so free src, dest, and lut with care. | |
1420 + | |
1421 + if (src && lut != src) | |
1422 + free(src); | |
1423 + if (dest && lut != dest) | |
1424 + free(dest); | |
1425 + | |
1426 + if (lut) { | |
1427 + free(lut); | |
1428 + return true; | |
1429 + } | |
1430 + | |
1431 + return false; | |
1432 +} | |
1433 + | |
1434 #define NO_MEM_TRANSFORM NULL | |
1435 | |
1436 qcms_transform* qcms_transform_create( | |
1437 @@ -1157,14 +1301,14 @@ qcms_transform* qcms_transform_create( | |
1438 return NULL; | |
1439 } | |
1440 if (precache) { | |
1441 -#ifdef X86 | |
1442 +#if defined(SSE2_ENABLE) && defined(X86) | |
1443 if (sse_version_available() >= 2) { | |
1444 if (in_type == QCMS_DATA_RGB_8) | |
1445 transform->transform_fn = qcms_transform_dat
a_rgb_out_lut_sse2; | |
1446 else | |
1447 transform->transform_fn = qcms_transform_dat
a_rgba_out_lut_sse2; | |
1448 | |
1449 -#if !(defined(_MSC_VER) && defined(_M_AMD64)) | |
1450 +#if defined(SSE2_ENABLE) && !(defined(_MSC_VER) && defined(_M_AMD64)) | |
1451 /* Microsoft Compiler for x64 doesn't support MMX. | |
1452 * SSE code uses MMX so that we disable on x64 */ | |
1453 } else | |
1454 @@ -1256,13 +1400,34 @@ qcms_transform* qcms_transform_create( | |
1455 return transform; | |
1456 } | |
1457 | |
1458 -#if defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__) | |
1459 +/* __force_align_arg_pointer__ is an x86-only attribute, and gcc/clang warns on
unused | |
1460 + * attributes. Don't use this on ARM or AMD64. __has_attribute can detect the p
resence | |
1461 + * of the attribute but is currently only supported by clang */ | |
1462 +#if defined(__has_attribute) | |
1463 +#define HAS_FORCE_ALIGN_ARG_POINTER __has_attribute(__force_align_arg_pointer__
) | |
1464 +#elif defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__) && !defi
ned(__arm__) && !defined(__mips__) | |
1465 +#define HAS_FORCE_ALIGN_ARG_POINTER 1 | |
1466 +#else | |
1467 +#define HAS_FORCE_ALIGN_ARG_POINTER 0 | |
1468 +#endif | |
1469 + | |
1470 +#if HAS_FORCE_ALIGN_ARG_POINTER | |
1471 /* we need this to avoid crashes when gcc assumes the stack is 128bit aligned *
/ | |
1472 __attribute__((__force_align_arg_pointer__)) | |
1473 #endif | |
1474 void qcms_transform_data(qcms_transform *transform, void *src, void *dest, size
_t length) | |
1475 { | |
1476 - transform->transform_fn(transform, src, dest, length); | |
1477 + static const struct _qcms_format_type output_rgbx = { 0, 2 }; | |
1478 + | |
1479 + transform->transform_fn(transform, src, dest, length, output_rgbx); | |
1480 +} | |
1481 + | |
1482 +void qcms_transform_data_type(qcms_transform *transform, void *src, void *dest,
size_t length, qcms_output_type type) | |
1483 +{ | |
1484 + static const struct _qcms_format_type output_rgbx = { 0, 2 }; | |
1485 + static const struct _qcms_format_type output_bgrx = { 2, 0 }; | |
1486 + | |
1487 + transform->transform_fn(transform, src, dest, length, type == QCMS_OUTPU
T_BGRX ? output_bgrx : output_rgbx); | |
1488 } | |
1489 | |
1490 qcms_bool qcms_supports_iccv4; | |
1491 diff --git a/third_party/qcms/src/transform_util.c b/third_party/qcms/src/transf
orm_util.c | |
1492 index e8447e5..5eeafa2 100644 | |
1493 --- a/third_party/qcms/src/transform_util.c | |
1494 +++ b/third_party/qcms/src/transform_util.c | |
1495 @@ -36,7 +36,7 @@ | |
1496 | |
1497 /* value must be a value between 0 and 1 */ | |
1498 //XXX: is the above a good restriction to have? | |
1499 -float lut_interp_linear(double value, uint16_t *table, int length) | |
1500 +float lut_interp_linear(double value, uint16_t *table, size_t length) | |
1501 { | |
1502 int upper, lower; | |
1503 value = value * (length - 1); // scale to length of the array | |
1504 @@ -49,11 +49,11 @@ float lut_interp_linear(double value, uint16_t *table, int l
ength) | |
1505 } | |
1506 | |
1507 /* same as above but takes and returns a uint16_t value representing a range fr
om 0..1 */ | |
1508 -uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, int length) | |
1509 +uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, size_t leng
th) | |
1510 { | |
1511 /* Start scaling input_value to the length of the array: 65535*(length-1
). | |
1512 * We'll divide out the 65535 next */ | |
1513 - uint32_t value = (input_value * (length - 1)); | |
1514 + uintptr_t value = (input_value * (length - 1)); | |
1515 uint32_t upper = (value + 65534) / 65535; /* equivalent to ceil(value/65
535) */ | |
1516 uint32_t lower = value / 65535; /* equivalent to floor(value/6
5535) */ | |
1517 /* interp is the distance from upper to value scaled to 0..65535 */ | |
1518 @@ -67,11 +67,11 @@ uint16_t lut_interp_linear16(uint16_t input_value, uint16_t
*table, int length) | |
1519 /* same as above but takes an input_value from 0..PRECACHE_OUTPUT_MAX | |
1520 * and returns a uint8_t value representing a range from 0..1 */ | |
1521 static | |
1522 -uint8_t lut_interp_linear_precache_output(uint32_t input_value, uint16_t *table
, int length) | |
1523 +uint8_t lut_interp_linear_precache_output(uint32_t input_value, uint16_t *table
, size_t length) | |
1524 { | |
1525 /* Start scaling input_value to the length of the array: PRECACHE_OUTPUT
_MAX*(length-1). | |
1526 * We'll divide out the PRECACHE_OUTPUT_MAX next */ | |
1527 - uint32_t value = (input_value * (length - 1)); | |
1528 + uintptr_t value = (input_value * (length - 1)); | |
1529 | |
1530 /* equivalent to ceil(value/PRECACHE_OUTPUT_MAX) */ | |
1531 uint32_t upper = (value + PRECACHE_OUTPUT_MAX-1) / PRECACHE_OUTPUT_MAX; | |
1532 @@ -91,7 +91,7 @@ uint8_t lut_interp_linear_precache_output(uint32_t input_value
, uint16_t *table, | |
1533 | |
1534 /* value must be a value between 0 and 1 */ | |
1535 //XXX: is the above a good restriction to have? | |
1536 -float lut_interp_linear_float(float value, float *table, int length) | |
1537 +float lut_interp_linear_float(float value, float *table, size_t length) | |
1538 { | |
1539 int upper, lower; | |
1540 value = value * (length - 1); | |
1541 @@ -235,6 +235,21 @@ float u8Fixed8Number_to_float(uint16_t x) | |
1542 return x/256.; | |
1543 } | |
1544 | |
1545 +/* The SSE2 code uses min & max which let NaNs pass through. | |
1546 + We want to try to prevent that here by ensuring that | |
1547 + gamma table is within expected values. */ | |
1548 +void validate_gamma_table(float gamma_table[256]) | |
1549 +{ | |
1550 + int i; | |
1551 + for (i = 0; i < 256; i++) { | |
1552 + // Note: we check that the gamma is not in range | |
1553 + // instead of out of range so that we catch NaNs | |
1554 + if (!(gamma_table[i] >= 0.f && gamma_table[i] <= 1.f)) { | |
1555 + gamma_table[i] = 0.f; | |
1556 + } | |
1557 + } | |
1558 +} | |
1559 + | |
1560 float *build_input_gamma_table(struct curveType *TRC) | |
1561 { | |
1562 float *gamma_table; | |
1563 @@ -254,7 +269,10 @@ float *build_input_gamma_table(struct curveType *TRC) | |
1564 } | |
1565 } | |
1566 } | |
1567 - return gamma_table; | |
1568 + | |
1569 + validate_gamma_table(gamma_table); | |
1570 + | |
1571 + return gamma_table; | |
1572 } | |
1573 | |
1574 struct matrix build_colorant_matrix(qcms_profile *p) | |
1575 @@ -295,7 +313,7 @@ uint16_fract_t lut_inverse_interp16(uint16_t Value, uint16_t
LutTable[], int len | |
1576 | |
1577 NumZeroes = 0; | |
1578 while (LutTable[NumZeroes] == 0 && NumZeroes < length-1) | |
1579 - NumZeroes++; | |
1580 + NumZeroes++; | |
1581 | |
1582 // There are no zeros at the beginning and we are trying to find a zero
, so | |
1583 // return anything. It seems zero would be the less destructive choice | |
1584 @@ -305,26 +323,37 @@ uint16_fract_t lut_inverse_interp16(uint16_t Value, uint16
_t LutTable[], int len | |
1585 | |
1586 NumPoles = 0; | |
1587 while (LutTable[length-1- NumPoles] == 0xFFFF && NumPoles < length-1) | |
1588 - NumPoles++; | |
1589 + NumPoles++; | |
1590 | |
1591 // Does the curve belong to this case? | |
1592 if (NumZeroes > 1 || NumPoles > 1) | |
1593 - { | |
1594 - int a, b; | |
1595 + { | |
1596 + int a, b, sample; | |
1597 | |
1598 - // Identify if value fall downto 0 or FFFF zone | |
1599 + // Identify if value fall downto 0 or FFFF zone | |
1600 if (Value == 0) return 0; | |
1601 - // if (Value == 0xFFFF) return 0xFFFF; | |
1602 + // if (Value == 0xFFFF) return 0xFFFF; | |
1603 + sample = (length-1) * ((double) Value * (1./65535.)); | |
1604 + if (LutTable[sample] == 0) | |
1605 + return 0; | |
1606 + if (LutTable[sample] == 0xffff) | |
1607 + return 0xffff; | |
1608 | |
1609 // else restrict to valid zone | |
1610 | |
1611 - a = ((NumZeroes-1) * 0xFFFF) / (length-1); | |
1612 + a = ((NumZeroes-1) * 0xFFFF) / (length-1); | |
1613 b = ((length-1 - NumPoles) * 0xFFFF) / (length-1); | |
1614 - | |
1615 + | |
1616 l = a - 1; | |
1617 r = b + 1; | |
1618 - } | |
1619 | |
1620 + // Ensure a valid binary search range | |
1621 + | |
1622 + if (l < 1) | |
1623 + l = 1; | |
1624 + if (r > 0x10000) | |
1625 + r = 0x10000; | |
1626 + } | |
1627 | |
1628 // Seems not a degenerated case... apply binary search | |
1629 | |
1630 @@ -332,12 +361,12 @@ uint16_fract_t lut_inverse_interp16(uint16_t Value, uint16
_t LutTable[], int len | |
1631 | |
1632 x = (l + r) / 2; | |
1633 | |
1634 - res = (int) lut_interp_linear16((uint16_fract_t) (x-1), LutTable
, length); | |
1635 + res = (int) lut_interp_linear16((uint16_fract_t) (x-1), LutTabl
e, length); | |
1636 | |
1637 if (res == Value) { | |
1638 | |
1639 - // Found exact match. | |
1640 - | |
1641 + // Found exact match. | |
1642 + | |
1643 return (uint16_fract_t) (x - 1); | |
1644 } | |
1645 | |
1646 @@ -347,14 +376,14 @@ uint16_fract_t lut_inverse_interp16(uint16_t Value, uint16
_t LutTable[], int len | |
1647 | |
1648 // Not found, should we interpolate? | |
1649 | |
1650 - | |
1651 + | |
1652 // Get surrounding nodes | |
1653 - | |
1654 + | |
1655 val2 = (length-1) * ((double) (x - 1) / 65535.0); | |
1656 | |
1657 cell0 = (int) floor(val2); | |
1658 cell1 = (int) ceil(val2); | |
1659 - | |
1660 + | |
1661 if (cell0 == cell1) return (uint16_fract_t) x; | |
1662 | |
1663 y0 = LutTable[cell0] ; | |
1664 @@ -373,8 +402,7 @@ uint16_fract_t lut_inverse_interp16(uint16_t Value, uint16_t
LutTable[], int len | |
1665 if (f < 0.0) return (uint16_fract_t) 0; | |
1666 if (f >= 65535.0) return (uint16_fract_t) 0xFFFF; | |
1667 | |
1668 - return (uint16_fract_t) floor(f + 0.5); | |
1669 - | |
1670 + return (uint16_fract_t) floor(f + 0.5); | |
1671 } | |
1672 | |
1673 /* | |
1674 @@ -390,7 +418,7 @@ uint16_fract_t lut_inverse_interp16(uint16_t Value, uint16_t
LutTable[], int len | |
1675 which has an maximum error of about 9855 (pixel difference of ~38.346) | |
1676 | |
1677 For now, we punt the decision of output size to the caller. */ | |
1678 -static uint16_t *invert_lut(uint16_t *table, int length, int out_length) | |
1679 +static uint16_t *invert_lut(uint16_t *table, int length, size_t out_length) | |
1680 { | |
1681 int i; | |
1682 /* for now we invert the lut by creating a lut of size out_length | |
1683 diff --git a/third_party/qcms/src/transform_util.h b/third_party/qcms/src/transf
orm_util.h | |
1684 index 8f358a8..de465f4 100644 | |
1685 --- a/third_party/qcms/src/transform_util.h | |
1686 +++ b/third_party/qcms/src/transform_util.h | |
1687 @@ -31,9 +31,9 @@ | |
1688 //XXX: could use a bettername | |
1689 typedef uint16_t uint16_fract_t; | |
1690 | |
1691 -float lut_interp_linear(double value, uint16_t *table, int length); | |
1692 -float lut_interp_linear_float(float value, float *table, int length); | |
1693 -uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, int length)
; | |
1694 +float lut_interp_linear(double value, uint16_t *table, size_t length); | |
1695 +float lut_interp_linear_float(float value, float *table, size_t length); | |
1696 +uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, size_t leng
th); | |
1697 | |
1698 | |
1699 static inline float lerp(float a, float b, float t) | |
OLD | NEW |