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

Side by Side Diff: third_party/qcms/iccread.c

Issue 4855001: Add qcms library for applying ICC color profile transforms to images. This... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/qcms/README.chromium ('k') | third_party/qcms/qcms.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // qcms
2 // Copyright (C) 2009 Mozilla Foundation
3 // Copyright (C) 1998-2007 Marti Maria
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining
6 // a copy of this software and associated documentation files (the "Software"),
7 // to deal in the Software without restriction, including without limitation
8 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 // and/or sell copies of the Software, and to permit persons to whom the Softwar e
10 // is furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
17 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23 #include <math.h>
24 #include <assert.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include "qcmsint.h"
28
29 typedef uint32_t be32;
30 typedef uint16_t be16;
31
32 #if 0
33 not used yet
34 /* __builtin_bswap isn't available in older gccs
35 * so open code it for now */
36 static be32 cpu_to_be32(int32_t v)
37 {
38 #ifdef IS_LITTLE_ENDIAN
39 return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) | ((v & 0xff000000) >> 24);
40 //return __builtin_bswap32(v);
41 return v;
42 #endif
43 }
44 #endif
45
46 static uint32_t be32_to_cpu(be32 v)
47 {
48 #ifdef IS_LITTLE_ENDIAN
49 return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) | ((v & 0xff000000) >> 24);
50 //return __builtin_bswap32(v);
51 #else
52 return v;
53 #endif
54 }
55
56 static uint16_t be16_to_cpu(be16 v)
57 {
58 #ifdef IS_LITTLE_ENDIAN
59 return ((v & 0xff) << 8) | ((v & 0xff00) >> 8);
60 #else
61 return v;
62 #endif
63 }
64
65 /* a wrapper around the memory that we are going to parse
66 * into a qcms_profile */
67 struct mem_source
68 {
69 const unsigned char *buf;
70 size_t size;
71 qcms_bool valid;
72 const char *invalid_reason;
73 };
74
75 static void invalid_source(struct mem_source *mem, const char *reason)
76 {
77 mem->valid = false;
78 mem->invalid_reason = reason;
79 }
80
81 static uint32_t read_u32(struct mem_source *mem, size_t offset)
82 {
83 /* Subtract from mem->size instead of the more intuitive adding to offse t.
84 * This avoids overflowing offset. The subtraction is safe because
85 * mem->size is guaranteed to be > 4 */
86 if (offset > mem->size - 4) {
87 invalid_source(mem, "Invalid offset");
88 return 0;
89 } else {
90 be32 k;
91 memcpy(&k, mem->buf + offset, sizeof(k));
92 return be32_to_cpu(k);
93 }
94 }
95
96 static uint16_t read_u16(struct mem_source *mem, size_t offset)
97 {
98 if (offset > mem->size - 2) {
99 invalid_source(mem, "Invalid offset");
100 return 0;
101 } else {
102 be16 k;
103 memcpy(&k, mem->buf + offset, sizeof(k));
104 return be16_to_cpu(k);
105 }
106 }
107
108 static uint8_t read_u8(struct mem_source *mem, size_t offset)
109 {
110 if (offset > mem->size - 1) {
111 invalid_source(mem, "Invalid offset");
112 return 0;
113 } else {
114 return *(uint8_t*)(mem->buf + offset);
115 }
116 }
117
118 static s15Fixed16Number read_s15Fixed16Number(struct mem_source *mem, size_t off set)
119 {
120 return read_u32(mem, offset);
121 }
122
123 #if 0
124 static uInt16Number read_uInt16Number(struct mem_source *mem, size_t offset)
125 {
126 return read_u16(mem, offset);
127 }
128 #endif
129
130 #define BAD_VALUE_PROFILE NULL
131 #define INVALID_PROFILE NULL
132 #define NO_MEM_PROFILE NULL
133
134 /* An arbitrary 4MB limit on profile size */
135 #define MAX_PROFILE_SIZE 1024*1024*4
136 #define MAX_TAG_COUNT 1024
137
138 static void check_CMM_type_signature(struct mem_source *src)
139 {
140 //uint32_t CMM_type_signature = read_u32(src, 4);
141 //TODO: do the check?
142
143 }
144
145 static void check_profile_version(struct mem_source *src)
146 {
147 uint8_t major_revision = read_u8(src, 8 + 0);
148 uint8_t minor_revision = read_u8(src, 8 + 1);
149 uint8_t reserved1 = read_u8(src, 8 + 2);
150 uint8_t reserved2 = read_u8(src, 8 + 3);
151 if (major_revision != 0x4) {
152 if (major_revision > 0x2)
153 invalid_source(src, "Unsupported major revision");
154 if (minor_revision > 0x40)
155 invalid_source(src, "Unsupported minor revision");
156 }
157 if (reserved1 != 0 || reserved2 != 0)
158 invalid_source(src, "Invalid reserved bytes");
159 }
160
161 #define INPUT_DEVICE_PROFILE 0x73636e72 // 'scnr'
162 #define DISPLAY_DEVICE_PROFILE 0x6d6e7472 // 'mntr'
163 #define OUTPUT_DEVICE_PROFILE 0x70727472 // 'prtr'
164 #define DEVICE_LINK_PROFILE 0x6c696e6b // 'link'
165 #define COLOR_SPACE_PROFILE 0x73706163 // 'spac'
166 #define ABSTRACT_PROFILE 0x61627374 // 'abst'
167 #define NAMED_COLOR_PROFILE 0x6e6d636c // 'nmcl'
168
169 static void read_class_signature(qcms_profile *profile, struct mem_source *mem)
170 {
171 profile->class = read_u32(mem, 12);
172 switch (profile->class) {
173 case DISPLAY_DEVICE_PROFILE:
174 case INPUT_DEVICE_PROFILE:
175 break;
176 case OUTPUT_DEVICE_PROFILE:
177 default:
178 invalid_source(mem, "Invalid Profile/Device Class signa ture");
179 }
180 }
181
182 static void read_color_space(qcms_profile *profile, struct mem_source *mem)
183 {
184 profile->color_space = read_u32(mem, 16);
185 switch (profile->color_space) {
186 case RGB_SIGNATURE:
187 case GRAY_SIGNATURE:
188 break;
189 default:
190 invalid_source(mem, "Unsupported colorspace");
191 }
192 }
193
194 struct tag
195 {
196 uint32_t signature;
197 uint32_t offset;
198 uint32_t size;
199 };
200
201 struct tag_index {
202 uint32_t count;
203 struct tag *tags;
204 };
205
206 static struct tag_index read_tag_table(qcms_profile *profile, struct mem_source *mem)
207 {
208 struct tag_index index = {0, NULL};
209 unsigned int i;
210
211 index.count = read_u32(mem, 128);
212 if (index.count > MAX_TAG_COUNT) {
213 invalid_source(mem, "max number of tags exceeded");
214 return index;
215 }
216
217 index.tags = malloc(sizeof(struct tag)*index.count);
218 if (index.tags) {
219 for (i = 0; i < index.count; i++) {
220 index.tags[i].signature = read_u32(mem, 128 + 4 + 4*i*3) ;
221 index.tags[i].offset = read_u32(mem, 128 + 4 + 4*i*3 + 4);
222 index.tags[i].size = read_u32(mem, 128 + 4 + 4*i*3 + 8);
223 }
224 }
225
226 return index;
227 }
228
229 // Checks a profile for obvious inconsistencies and returns
230 // true if the profile looks bogus and should probably be
231 // ignored.
232 qcms_bool qcms_profile_is_bogus(qcms_profile *profile)
233 {
234 float sum[3], target[3], tolerance[3];
235 float rX, rY, rZ, gX, gY, gZ, bX, bY, bZ;
236 bool negative;
237 unsigned i;
238
239 // We currently only check the bogosity of RGB profiles
240 if (profile->color_space != RGB_SIGNATURE)
241 return false;
242
243 rX = s15Fixed16Number_to_float(profile->redColorant.X);
244 rY = s15Fixed16Number_to_float(profile->redColorant.Y);
245 rZ = s15Fixed16Number_to_float(profile->redColorant.Z);
246
247 gX = s15Fixed16Number_to_float(profile->greenColorant.X);
248 gY = s15Fixed16Number_to_float(profile->greenColorant.Y);
249 gZ = s15Fixed16Number_to_float(profile->greenColorant.Z);
250
251 bX = s15Fixed16Number_to_float(profile->blueColorant.X);
252 bY = s15Fixed16Number_to_float(profile->blueColorant.Y);
253 bZ = s15Fixed16Number_to_float(profile->blueColorant.Z);
254
255 // Check if any of the XYZ values are negative (see mozilla bug 498245)
256 // CIEXYZ tristimulus values cannot be negative according to the spec.
257 negative =
258 (rX < 0) || (rY < 0) || (rZ < 0) ||
259 (gX < 0) || (gY < 0) || (gZ < 0) ||
260 (bX < 0) || (bY < 0) || (bZ < 0);
261
262 if (negative)
263 return true;
264
265
266 // Sum the values; they should add up to something close to white
267 sum[0] = rX + gX + bX;
268 sum[1] = rY + gY + bY;
269 sum[2] = rZ + gZ + bZ;
270
271 // Build our target vector (see mozilla bug 460629)
272 target[0] = 0.96420;
273 target[1] = 1.00000;
274 target[2] = 0.82491;
275
276 // Our tolerance vector - Recommended by Chris Murphy based on
277 // conversion from the LAB space criterion of no more than 3 in any one
278 // channel. This is similar to, but slightly more tolerant than Adobe's
279 // criterion.
280 tolerance[0] = 0.02;
281 tolerance[1] = 0.02;
282 tolerance[2] = 0.04;
283
284 // Compare with our tolerance
285 for (i = 0; i < 3; ++i) {
286 if (!(((sum[i] - tolerance[i]) <= target[i]) &&
287 ((sum[i] + tolerance[i]) >= target[i])))
288 return true;
289 }
290
291 // All Good
292 return false;
293 }
294
295 #define TAG_bXYZ 0x6258595a
296 #define TAG_gXYZ 0x6758595a
297 #define TAG_rXYZ 0x7258595a
298 #define TAG_rTRC 0x72545243
299 #define TAG_bTRC 0x62545243
300 #define TAG_gTRC 0x67545243
301 #define TAG_kTRC 0x6b545243
302 #define TAG_A2B0 0x41324230
303
304 static struct tag *find_tag(struct tag_index index, uint32_t tag_id)
305 {
306 unsigned int i;
307 struct tag *tag = NULL;
308 for (i = 0; i < index.count; i++) {
309 if (index.tags[i].signature == tag_id) {
310 return &index.tags[i];
311 }
312 }
313 return tag;
314 }
315
316 #define XYZ_TYPE 0x58595a20 // 'XYZ '
317 #define CURVE_TYPE 0x63757276 // 'curv'
318 #define LUT16_TYPE 0x6d667432 // 'mft2'
319 #define LUT8_TYPE 0x6d667431 // 'mft1'
320
321 static struct XYZNumber read_tag_XYZType(struct mem_source *src, struct tag_inde x index, uint32_t tag_id)
322 {
323 struct XYZNumber num = {0, 0, 0};
324 struct tag *tag = find_tag(index, tag_id);
325 if (tag) {
326 uint32_t offset = tag->offset;
327
328 uint32_t type = read_u32(src, offset);
329 if (type != XYZ_TYPE)
330 invalid_source(src, "unexpected type, expected XYZ");
331 num.X = read_s15Fixed16Number(src, offset+8);
332 num.Y = read_s15Fixed16Number(src, offset+12);
333 num.Z = read_s15Fixed16Number(src, offset+16);
334 } else {
335 invalid_source(src, "missing xyztag");
336 }
337 return num;
338 }
339
340 static struct curveType *read_tag_curveType(struct mem_source *src, struct tag_i ndex index, uint32_t tag_id)
341 {
342 struct tag *tag = find_tag(index, tag_id);
343 struct curveType *curve = NULL;
344 if (tag) {
345 uint32_t offset = tag->offset;
346 uint32_t type = read_u32(src, offset);
347 uint32_t count = read_u32(src, offset+8);
348 unsigned int i;
349
350 if (type != CURVE_TYPE) {
351 invalid_source(src, "unexpected type, expected CURV");
352 return NULL;
353 }
354
355 #define MAX_CURVE_ENTRIES 40000 //arbitrary
356 if (count > MAX_CURVE_ENTRIES) {
357 invalid_source(src, "curve size too large");
358 return NULL;
359 }
360 curve = malloc(sizeof(struct curveType) + sizeof(uInt16Number)*c ount);
361 if (!curve)
362 return NULL;
363
364 curve->count = count;
365 for (i=0; i<count; i++) {
366 curve->data[i] = read_u16(src, offset + 12 + i *2);
367 }
368 } else {
369 invalid_source(src, "missing curvetag");
370 }
371
372 return curve;
373 }
374
375 /* This function's not done yet */
376 static struct lutType *read_tag_lutType(struct mem_source *src, struct tag_index index, uint32_t tag_id)
377 {
378 struct tag *tag = find_tag(index, tag_id);
379 uint32_t offset = tag->offset;
380 uint32_t type = read_u32(src, offset);
381 uint16_t num_input_table_entries;
382 uint16_t num_output_table_entries;
383 uint8_t in_chan, grid_points, out_chan;
384 uint32_t clut_size;
385 struct lutType *lut;
386 int i;
387
388 num_input_table_entries = read_u16(src, offset + 48);
389 num_output_table_entries = read_u16(src, offset + 50);
390
391 in_chan = read_u8(src, offset + 8);
392 out_chan = read_u8(src, offset + 9);
393 grid_points = read_u8(src, offset + 10);
394
395 if (!src->valid)
396 return NULL;
397
398 clut_size = in_chan * grid_points * out_chan;
399 #define MAX_CLUT_SIZE 10000 // arbitrary
400 if (clut_size > MAX_CLUT_SIZE) {
401 return NULL;
402 }
403
404 if (type != LUT16_TYPE && type != LUT8_TYPE)
405 return NULL;
406
407 lut = malloc(sizeof(struct lutType) + (clut_size + num_input_table_entri es + num_output_table_entries)*sizeof(uint8_t));
408 if (!lut)
409 return NULL;
410 lut->num_input_channels = read_u8(src, offset + 8);
411 lut->num_output_channels = read_u8(src, offset + 9);
412 lut->num_clut_grid_points = read_u8(src, offset + 10);
413 lut->e00 = read_s15Fixed16Number(src, offset+12);
414 lut->e01 = read_s15Fixed16Number(src, offset+16);
415 lut->e02 = read_s15Fixed16Number(src, offset+20);
416 lut->e10 = read_s15Fixed16Number(src, offset+24);
417 lut->e11 = read_s15Fixed16Number(src, offset+28);
418 lut->e12 = read_s15Fixed16Number(src, offset+32);
419 lut->e20 = read_s15Fixed16Number(src, offset+36);
420 lut->e21 = read_s15Fixed16Number(src, offset+40);
421 lut->e22 = read_s15Fixed16Number(src, offset+44);
422
423 //TODO: finish up
424 return lut;
425 }
426
427 static void read_rendering_intent(qcms_profile *profile, struct mem_source *src)
428 {
429 profile->rendering_intent = read_u32(src, 64);
430 switch (profile->rendering_intent) {
431 case QCMS_INTENT_PERCEPTUAL:
432 case QCMS_INTENT_SATURATION:
433 case QCMS_INTENT_RELATIVE_COLORIMETRIC:
434 case QCMS_INTENT_ABSOLUTE_COLORIMETRIC:
435 break;
436 default:
437 invalid_source(src, "unknown rendering intent");
438 }
439 }
440
441 qcms_profile *qcms_profile_create(void)
442 {
443 return calloc(sizeof(qcms_profile), 1);
444 }
445
446 /* build sRGB gamma table */
447 /* based on cmsBuildParametricGamma() */
448 static uint16_t *build_sRGB_gamma_table(int num_entries)
449 {
450 int i;
451 /* taken from lcms: Build_sRGBGamma() */
452 double gamma = 2.4;
453 double a = 1./1.055;
454 double b = 0.055/1.055;
455 double c = 1./12.92;
456 double d = 0.04045;
457
458 uint16_t *table = malloc(sizeof(uint16_t) * num_entries);
459 if (!table)
460 return NULL;
461
462 for (i=0; i<num_entries; i++) {
463 double x = (double)i / (num_entries-1);
464 double y, output;
465 // IEC 61966-2.1 (sRGB)
466 // Y = (aX + b)^Gamma | X >= d
467 // Y = cX | X < d
468 if (x >= d) {
469 double e = (a*x + b);
470 if (e > 0)
471 y = pow(e, gamma);
472 else
473 y = 0;
474 } else {
475 y = c*x;
476 }
477
478 // Saturate -- this could likely move to a separate function
479 output = y * 65535. + .5;
480 if (output > 65535.)
481 output = 65535;
482 if (output < 0)
483 output = 0;
484 table[i] = (uint16_t)floor(output);
485 }
486 return table;
487 }
488
489 static struct curveType *curve_from_table(uint16_t *table, int num_entries)
490 {
491 struct curveType *curve;
492 int i;
493 curve = malloc(sizeof(struct curveType) + sizeof(uInt16Number)*num_entri es);
494 if (!curve)
495 return NULL;
496 curve->count = num_entries;
497 for (i = 0; i < num_entries; i++) {
498 curve->data[i] = table[i];
499 }
500 return curve;
501 }
502
503 static uint16_t float_to_u8Fixed8Number(float a)
504 {
505 if (a > (255. + 255./256))
506 return 0xffff;
507 else if (a < 0.)
508 return 0;
509 else
510 return floor(a*256. + .5);
511 }
512
513 static struct curveType *curve_from_gamma(float gamma)
514 {
515 struct curveType *curve;
516 int num_entries = 1;
517 curve = malloc(sizeof(struct curveType) + sizeof(uInt16Number)*num_entri es);
518 if (!curve)
519 return NULL;
520 curve->count = num_entries;
521 curve->data[0] = float_to_u8Fixed8Number(gamma);
522 return curve;
523 }
524
525 static void qcms_profile_fini(qcms_profile *profile)
526 {
527 free(profile->redTRC);
528 free(profile->blueTRC);
529 free(profile->greenTRC);
530 free(profile->grayTRC);
531 free(profile);
532 }
533
534 //XXX: it would be nice if we had a way of ensuring
535 // everything in a profile was initialized regardless of how it was created
536
537 //XXX: should this also be taking a black_point?
538 /* similar to CGColorSpaceCreateCalibratedRGB */
539 qcms_profile* qcms_profile_create_rgb_with_gamma(
540 qcms_CIE_xyY white_point,
541 qcms_CIE_xyYTRIPLE primaries,
542 float gamma)
543 {
544 qcms_profile* profile = qcms_profile_create();
545 if (!profile)
546 return NO_MEM_PROFILE;
547
548 //XXX: should store the whitepoint
549 if (!set_rgb_colorants(profile, white_point, primaries)) {
550 qcms_profile_fini(profile);
551 return INVALID_PROFILE;
552 }
553
554 profile->redTRC = curve_from_gamma(gamma);
555 profile->blueTRC = curve_from_gamma(gamma);
556 profile->greenTRC = curve_from_gamma(gamma);
557
558 if (!profile->redTRC || !profile->blueTRC || !profile->greenTRC) {
559 qcms_profile_fini(profile);
560 return NO_MEM_PROFILE;
561 }
562 profile->class = DISPLAY_DEVICE_PROFILE;
563 profile->rendering_intent = QCMS_INTENT_PERCEPTUAL;
564 profile->color_space = RGB_SIGNATURE;
565 return profile;
566 }
567
568 qcms_profile* qcms_profile_create_rgb_with_table(
569 qcms_CIE_xyY white_point,
570 qcms_CIE_xyYTRIPLE primaries,
571 uint16_t *table, int num_entries)
572 {
573 qcms_profile* profile = qcms_profile_create();
574 if (!profile)
575 return NO_MEM_PROFILE;
576
577 //XXX: should store the whitepoint
578 if (!set_rgb_colorants(profile, white_point, primaries)) {
579 qcms_profile_fini(profile);
580 return INVALID_PROFILE;
581 }
582
583 profile->redTRC = curve_from_table(table, num_entries);
584 profile->blueTRC = curve_from_table(table, num_entries);
585 profile->greenTRC = curve_from_table(table, num_entries);
586
587 if (!profile->redTRC || !profile->blueTRC || !profile->greenTRC) {
588 qcms_profile_fini(profile);
589 return NO_MEM_PROFILE;
590 }
591 profile->class = DISPLAY_DEVICE_PROFILE;
592 profile->rendering_intent = QCMS_INTENT_PERCEPTUAL;
593 profile->color_space = RGB_SIGNATURE;
594 return profile;
595 }
596
597 /* from lcms: cmsWhitePointFromTemp */
598 /* tempK must be >= 4000. and <= 25000.
599 * similar to argyll: icx_DTEMP2XYZ() */
600 static qcms_CIE_xyY white_point_from_temp(int temp_K)
601 {
602 qcms_CIE_xyY white_point;
603 double x, y;
604 double T, T2, T3;
605 // double M1, M2;
606
607 // No optimization provided.
608 T = temp_K;
609 T2 = T*T; // Square
610 T3 = T2*T; // Cube
611
612 // For correlated color temperature (T) between 4000K and 7000K:
613 if (T >= 4000. && T <= 7000.) {
614 x = -4.6070*(1E9/T3) + 2.9678*(1E6/T2) + 0.09911*(1E3/T) + 0.244 063;
615 } else {
616 // or for correlated color temperature (T) between 7000K and 250 00K:
617 if (T > 7000.0 && T <= 25000.0) {
618 x = -2.0064*(1E9/T3) + 1.9018*(1E6/T2) + 0.24748*(1E3/T) + 0.237040;
619 } else {
620 assert(0 && "invalid temp");
621 }
622 }
623
624 // Obtain y(x)
625
626 y = -3.000*(x*x) + 2.870*x - 0.275;
627
628 // wave factors (not used, but here for futures extensions)
629
630 // M1 = (-1.3515 - 1.7703*x + 5.9114 *y)/(0.0241 + 0.2562*x - 0.7341*y);
631 // M2 = (0.0300 - 31.4424*x + 30.0717*y)/(0.0241 + 0.2562*x - 0.7341*y);
632
633 // Fill white_point struct
634 white_point.x = x;
635 white_point.y = y;
636 white_point.Y = 1.0;
637
638 return white_point;
639 }
640
641 qcms_profile* qcms_profile_sRGB(void)
642 {
643 qcms_profile *profile;
644 uint16_t *table;
645
646 qcms_CIE_xyYTRIPLE Rec709Primaries = {
647 {0.6400, 0.3300, 1.0},
648 {0.3000, 0.6000, 1.0},
649 {0.1500, 0.0600, 1.0}
650 };
651 qcms_CIE_xyY D65;
652
653 D65 = white_point_from_temp(6504);
654
655 table = build_sRGB_gamma_table(1024);
656
657 if (!table)
658 return NO_MEM_PROFILE;
659
660 profile = qcms_profile_create_rgb_with_table(D65, Rec709Primaries, table , 1024);
661 free(table);
662 return profile;
663 }
664
665
666 /* qcms_profile_from_memory does not hold a reference to the memory passed in */
667 qcms_profile* qcms_profile_from_memory(const void *mem, size_t size)
668 {
669 uint32_t length;
670 struct mem_source source;
671 struct mem_source *src = &source;
672 struct tag_index index;
673 qcms_profile *profile;
674
675 source.buf = mem;
676 source.size = size;
677 source.valid = true;
678
679 length = read_u32(src, 0);
680 if (length <= size) {
681 // shrink the area that we can read if appropriate
682 source.size = length;
683 } else {
684 return INVALID_PROFILE;
685 }
686
687 /* ensure that the profile size is sane so it's easier to reason about * /
688 if (source.size <= 64 || source.size >= MAX_PROFILE_SIZE)
689 return INVALID_PROFILE;
690
691 profile = qcms_profile_create();
692 if (!profile)
693 return NO_MEM_PROFILE;
694
695 check_CMM_type_signature(src);
696 check_profile_version(src);
697 read_class_signature(profile, src);
698 read_rendering_intent(profile, src);
699 read_color_space(profile, src);
700 //TODO read rest of profile stuff
701
702 if (!src->valid)
703 goto invalid_profile;
704
705 index = read_tag_table(profile, src);
706 if (!src->valid || !index.tags)
707 goto invalid_tag_table;
708
709 if (profile->class == DISPLAY_DEVICE_PROFILE || profile->class == INPUT_ DEVICE_PROFILE) {
710 if (profile->color_space == RGB_SIGNATURE) {
711
712 profile->redColorant = read_tag_XYZType(src, index, TAG_ rXYZ);
713 profile->blueColorant = read_tag_XYZType(src, index, TAG _bXYZ);
714 profile->greenColorant = read_tag_XYZType(src, index, TA G_gXYZ);
715
716 if (!src->valid)
717 goto invalid_tag_table;
718
719 profile->redTRC = read_tag_curveType(src, index, TAG_rTR C);
720 profile->blueTRC = read_tag_curveType(src, index, TAG_bT RC);
721 profile->greenTRC = read_tag_curveType(src, index, TAG_g TRC);
722
723 if (!profile->redTRC || !profile->blueTRC || !profile->g reenTRC)
724 goto invalid_tag_table;
725
726 } else if (profile->color_space == GRAY_SIGNATURE) {
727
728 profile->grayTRC = read_tag_curveType(src, index, TAG_kT RC);
729 if (!profile->grayTRC)
730 goto invalid_tag_table;
731
732 } else {
733 goto invalid_tag_table;
734 }
735 } else if (0 && profile->class == OUTPUT_DEVICE_PROFILE) {
736 profile->A2B0 = read_tag_lutType(src, index, TAG_A2B0);
737 } else {
738 goto invalid_tag_table;
739 }
740
741 if (!src->valid)
742 goto invalid_tag_table;
743
744 free(index.tags);
745
746 return profile;
747
748 invalid_tag_table:
749 free(index.tags);
750 invalid_profile:
751 qcms_profile_fini(profile);
752 return INVALID_PROFILE;
753 }
754
755 qcms_intent qcms_profile_get_rendering_intent(qcms_profile *profile)
756 {
757 return profile->rendering_intent;
758 }
759
760 icColorSpaceSignature
761 qcms_profile_get_color_space(qcms_profile *profile)
762 {
763 return profile->color_space;
764 }
765
766 void qcms_profile_release(qcms_profile *profile)
767 {
768 if (profile->output_table_r)
769 precache_release(profile->output_table_r);
770 if (profile->output_table_g)
771 precache_release(profile->output_table_g);
772 if (profile->output_table_b)
773 precache_release(profile->output_table_b);
774
775 qcms_profile_fini(profile);
776 }
777
778 #include <stdio.h>
779 qcms_profile* qcms_profile_from_file(FILE *file)
780 {
781 uint32_t length, remaining_length;
782 qcms_profile *profile;
783 size_t read_length;
784 be32 length_be;
785 void *data;
786
787 fread(&length_be, sizeof(length), 1, file);
788 length = be32_to_cpu(length_be);
789 if (length > MAX_PROFILE_SIZE)
790 return BAD_VALUE_PROFILE;
791
792 /* allocate room for the entire profile */
793 data = malloc(length);
794 if (!data)
795 return NO_MEM_PROFILE;
796
797 /* copy in length to the front so that the buffer will contain the entir e profile */
798 *((be32*)data) = length_be;
799 remaining_length = length - sizeof(length_be);
800
801 /* read the rest profile */
802 read_length = fread((unsigned char*)data + sizeof(length_be), 1, remaini ng_length, file);
803 if (read_length != remaining_length) {
804 free(data);
805 return INVALID_PROFILE;
806 }
807
808 profile = qcms_profile_from_memory(data, length);
809 free(data);
810 return profile;
811 }
812
813 qcms_profile* qcms_profile_from_path(const char *path)
814 {
815 qcms_profile *profile = NULL;
816 FILE *file = fopen(path, "rb");
817 if (file) {
818 profile = qcms_profile_from_file(file);
819 fclose(file);
820 }
821 return profile;
822 }
OLDNEW
« no previous file with comments | « third_party/qcms/README.chromium ('k') | third_party/qcms/qcms.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698