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

Side by Side Diff: src/core/SkColorSpace.cpp

Issue 1925753002: Parse A2B0 tag on ICC profiles (Closed) Base URL: https://skia.googlesource.com/skia.git@sanity-icc-parse
Patch Set: Explicit move constructor for MSVS 2013 Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/core/SkColorSpace.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2016 Google Inc. 2 * Copyright 2016 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkAtomics.h" 8 #include "SkAtomics.h"
9 #include "SkColorSpace.h" 9 #include "SkColorSpace.h"
10 10
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
81 SkDebugf("[%7.4f %7.4f %7.4f] [%7.4f %7.4f %7.4f] [%7.4f %7.4f %7.4f]\n", 81 SkDebugf("[%7.4f %7.4f %7.4f] [%7.4f %7.4f %7.4f] [%7.4f %7.4f %7.4f]\n",
82 fMat[0], fMat[1], fMat[2], 82 fMat[0], fMat[1], fMat[2],
83 fMat[3], fMat[4], fMat[5], 83 fMat[3], fMat[4], fMat[5],
84 fMat[6], fMat[7], fMat[8]); 84 fMat[6], fMat[7], fMat[8]);
85 } 85 }
86 86
87 //////////////////////////////////////////////////////////////////////////////// ////////////////// 87 //////////////////////////////////////////////////////////////////////////////// //////////////////
88 88
89 static int32_t gUniqueColorSpaceID; 89 static int32_t gUniqueColorSpaceID;
90 90
91 SkColorSpace::SkColorSpace(const SkFloat3x3& toXYZD50, const SkFloat3& gamma, Na med named) 91 SkColorSpace::SkColorSpace(const SkFloat3& gamma, const SkFloat3x3& toXYZD50, Na med named)
92 : fToXYZD50(toXYZD50) 92 : fGamma(gamma)
93 , fGamma(gamma) 93 , fToXYZD50(toXYZD50)
94 , fToXYZOffset({{ 0.0f, 0.0f, 0.0f }})
94 , fUniqueID(sk_atomic_inc(&gUniqueColorSpaceID)) 95 , fUniqueID(sk_atomic_inc(&gUniqueColorSpaceID))
95 , fNamed(named) 96 , fNamed(named)
96 { 97 {
97 for (int i = 0; i < 3; ++i) { 98 for (int i = 0; i < 3; ++i) {
98 SkASSERT(SkFloatIsFinite(gamma.fVec[i])); 99 SkASSERT(SkFloatIsFinite(gamma.fVec[i]));
99 for (int j = 0; j < 3; ++j) { 100 for (int j = 0; j < 3; ++j) {
100 SkASSERT(SkFloatIsFinite(toXYZD50.fMat[3*i + j])); 101 SkASSERT(SkFloatIsFinite(toXYZD50.fMat[3*i + j]));
101 } 102 }
102 } 103 }
103 } 104 }
104 105
106 SkColorSpace::SkColorSpace(SkColorLookUpTable colorLUT, const SkFloat3& gamma,
107 const SkFloat3x3& toXYZD50, const SkFloat3& toXYZOffs et)
108 : fColorLUT(std::move(colorLUT))
109 , fGamma(gamma)
110 , fToXYZD50(toXYZD50)
111 , fToXYZOffset(toXYZOffset)
112 , fUniqueID(sk_atomic_inc(&gUniqueColorSpaceID))
113 , fNamed(kUnknown_Named)
114 {}
115
105 sk_sp<SkColorSpace> SkColorSpace::NewRGB(const SkFloat3x3& toXYZD50, const SkFlo at3& gamma) { 116 sk_sp<SkColorSpace> SkColorSpace::NewRGB(const SkFloat3x3& toXYZD50, const SkFlo at3& gamma) {
106 for (int i = 0; i < 3; ++i) { 117 for (int i = 0; i < 3; ++i) {
107 if (!SkFloatIsFinite(gamma.fVec[i]) || gamma.fVec[i] < 0) { 118 if (!SkFloatIsFinite(gamma.fVec[i]) || gamma.fVec[i] < 0) {
108 return nullptr; 119 return nullptr;
109 } 120 }
110 for (int j = 0; j < 3; ++j) { 121 for (int j = 0; j < 3; ++j) {
111 if (!SkFloatIsFinite(toXYZD50.fMat[3*i + j])) { 122 if (!SkFloatIsFinite(toXYZD50.fMat[3*i + j])) {
112 return nullptr; 123 return nullptr;
113 } 124 }
114 } 125 }
115 } 126 }
116 127
117 // check the matrix for invertibility 128 // check the matrix for invertibility
118 float d = det(toXYZD50); 129 float d = det(toXYZD50);
119 if (!SkFloatIsFinite(d) || !SkFloatIsFinite(1 / d)) { 130 if (!SkFloatIsFinite(d) || !SkFloatIsFinite(1 / d)) {
120 return nullptr; 131 return nullptr;
121 } 132 }
122 133
123 return sk_sp<SkColorSpace>(new SkColorSpace(toXYZD50, gamma, kUnknown_Named) ); 134 return sk_sp<SkColorSpace>(new SkColorSpace(gamma, toXYZD50, kUnknown_Named) );
124 } 135 }
125 136
126 void SkColorSpace::dump() const { 137 void SkColorSpace::dump() const {
127 fToXYZD50.dump(); 138 fToXYZD50.dump();
128 fGamma.dump(); 139 fGamma.dump();
129 } 140 }
130 141
131 //////////////////////////////////////////////////////////////////////////////// ////////////////// 142 //////////////////////////////////////////////////////////////////////////////// //////////////////
132 143
133 const SkFloat3 gDevice_gamma {{ 0, 0, 0 }}; 144 const SkFloat3 gDevice_gamma {{ 0, 0, 0 }};
134 const SkFloat3x3 gDevice_toXYZD50 {{ 145 const SkFloat3x3 gDevice_toXYZD50 {{
135 1, 0, 0, 146 1, 0, 0,
136 0, 1, 0, 147 0, 1, 0,
137 0, 0, 1 148 0, 0, 1
138 }}; 149 }};
139 150
140 const SkFloat3 gSRGB_gamma {{ 2.2f, 2.2f, 2.2f }}; 151 const SkFloat3 gSRGB_gamma {{ 2.2f, 2.2f, 2.2f }};
141 const SkFloat3x3 gSRGB_toXYZD50 {{ 152 const SkFloat3x3 gSRGB_toXYZD50 {{
142 0.4358f, 0.2224f, 0.0139f, // * R 153 0.4358f, 0.2224f, 0.0139f, // * R
143 0.3853f, 0.7170f, 0.0971f, // * G 154 0.3853f, 0.7170f, 0.0971f, // * G
144 0.1430f, 0.0606f, 0.7139f, // * B 155 0.1430f, 0.0606f, 0.7139f, // * B
145 }}; 156 }};
146 157
147 sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) { 158 sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) {
148 switch (named) { 159 switch (named) {
149 case kDevice_Named: 160 case kDevice_Named:
150 return sk_sp<SkColorSpace>(new SkColorSpace(gDevice_toXYZD50, gDevic e_gamma, 161 return sk_sp<SkColorSpace>(new SkColorSpace(gDevice_gamma, gDevice_t oXYZD50,
151 kDevice_Named)); 162 kDevice_Named));
152 case kSRGB_Named: 163 case kSRGB_Named:
153 return sk_sp<SkColorSpace>(new SkColorSpace(gSRGB_toXYZD50, gSRGB_ga mma, kSRGB_Named)); 164 return sk_sp<SkColorSpace>(new SkColorSpace(gSRGB_gamma, gSRGB_toXYZ D50, kSRGB_Named));
154 default: 165 default:
155 break; 166 break;
156 } 167 }
157 return nullptr; 168 return nullptr;
158 } 169 }
159 170
160 //////////////////////////////////////////////////////////////////////////////// /////////////////// 171 //////////////////////////////////////////////////////////////////////////////// ///////////////////
161 172
162 #include "SkFixed.h" 173 #include "SkFixed.h"
163 #include "SkTemplates.h" 174 #include "SkTemplates.h"
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
328 static const ICCTag* Find(const ICCTag tags[], int count, uint32_t signature ) { 339 static const ICCTag* Find(const ICCTag tags[], int count, uint32_t signature ) {
329 for (int i = 0; i < count; ++i) { 340 for (int i = 0; i < count; ++i) {
330 if (tags[i].fSignature == signature) { 341 if (tags[i].fSignature == signature) {
331 return &tags[i]; 342 return &tags[i];
332 } 343 }
333 } 344 }
334 return nullptr; 345 return nullptr;
335 } 346 }
336 }; 347 };
337 348
338 // TODO (msarett):
339 // Should we recognize more tags?
340 static const uint32_t kTAG_rXYZ = SkSetFourByteTag('r', 'X', 'Y', 'Z'); 349 static const uint32_t kTAG_rXYZ = SkSetFourByteTag('r', 'X', 'Y', 'Z');
341 static const uint32_t kTAG_gXYZ = SkSetFourByteTag('g', 'X', 'Y', 'Z'); 350 static const uint32_t kTAG_gXYZ = SkSetFourByteTag('g', 'X', 'Y', 'Z');
342 static const uint32_t kTAG_bXYZ = SkSetFourByteTag('b', 'X', 'Y', 'Z'); 351 static const uint32_t kTAG_bXYZ = SkSetFourByteTag('b', 'X', 'Y', 'Z');
343 static const uint32_t kTAG_rTRC = SkSetFourByteTag('r', 'T', 'R', 'C'); 352 static const uint32_t kTAG_rTRC = SkSetFourByteTag('r', 'T', 'R', 'C');
344 static const uint32_t kTAG_gTRC = SkSetFourByteTag('g', 'T', 'R', 'C'); 353 static const uint32_t kTAG_gTRC = SkSetFourByteTag('g', 'T', 'R', 'C');
345 static const uint32_t kTAG_bTRC = SkSetFourByteTag('b', 'T', 'R', 'C'); 354 static const uint32_t kTAG_bTRC = SkSetFourByteTag('b', 'T', 'R', 'C');
355 static const uint32_t kTAG_A2B0 = SkSetFourByteTag('A', '2', 'B', '0');
346 356
347 bool load_xyz(float dst[3], const uint8_t* src, size_t len) { 357 bool load_xyz(float dst[3], const uint8_t* src, size_t len) {
348 if (len < 20) { 358 if (len < 20) {
349 SkColorSpacePrintf("XYZ tag is too small (%d bytes)", len); 359 SkColorSpacePrintf("XYZ tag is too small (%d bytes)", len);
350 return false; 360 return false;
351 } 361 }
352 362
353 dst[0] = SkFixedToFloat(read_big_endian_int(src + 8)); 363 dst[0] = SkFixedToFloat(read_big_endian_int(src + 8));
354 dst[1] = SkFixedToFloat(read_big_endian_int(src + 12)); 364 dst[1] = SkFixedToFloat(read_big_endian_int(src + 12));
355 dst[2] = SkFixedToFloat(read_big_endian_int(src + 16)); 365 dst[2] = SkFixedToFloat(read_big_endian_int(src + 16));
356 SkColorSpacePrintf("XYZ %g %g %g\n", dst[0], dst[1], dst[2]); 366 SkColorSpacePrintf("XYZ %g %g %g\n", dst[0], dst[1], dst[2]);
357 return true; 367 return true;
358 } 368 }
359 369
360 static const uint32_t kTAG_CurveType = SkSetFourByteTag('c', 'u', 'r', 'v'); 370 static const uint32_t kTAG_CurveType = SkSetFourByteTag('c', 'u', 'r', 'v');
361 static const uint32_t kTAG_ParaCurveType = SkSetFourByteTag('p', 'a', 'r', 'a'); 371 static const uint32_t kTAG_ParaCurveType = SkSetFourByteTag('p', 'a', 'r', 'a');
362 372
363 static bool load_gamma(float* gamma, const uint8_t* src, size_t len) { 373 // FIXME (msarett):
364 if (len < 14) { 374 // We need to handle the possibility that the gamma curve does not correspond to 2.2f.
365 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); 375 static bool load_gammas(float* gammas, uint32_t numGammas, const uint8_t* src, s ize_t len) {
366 return false; 376 for (uint32_t i = 0; i < numGammas; i++) {
367 } 377 if (len < 12) {
368 378 // FIXME (msarett):
369 uint32_t type = read_big_endian_uint(src); 379 // We could potentially return false here after correctly parsing *s ome* of the
370 switch (type) { 380 // gammas correctly. Should we somehow try to indicate a partial su ccess?
371 case kTAG_CurveType: { 381 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len);
372 uint32_t count = read_big_endian_int(src + 8); 382 return false;
373 if (0 == count) { 383 }
384
385 // We need to count the number of bytes in the tag, so we are able to mo ve to the
386 // next tag on the next loop iteration.
387 size_t tagBytes;
388
389 uint32_t type = read_big_endian_uint(src);
390 switch (type) {
391 case kTAG_CurveType: {
392 uint32_t count = read_big_endian_uint(src + 8);
393 tagBytes = 12 + count * 2;
394 if (0 == count) {
395 // Some tags require a gamma curve, but the author doesn't a ctually want
396 // to transform the data. In this case, it is common to see a curve with
397 // a count of 0.
398 gammas[i] = 1.0f;
399 break;
400 } else if (len < 12 + 2 * count) {
401 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len) ;
402 return false;
403 }
404
405 const uint16_t* table = (const uint16_t*) (src + 12);
406 if (1 == count) {
407 // Table entry is the exponent (bias 256).
408 uint16_t value = read_big_endian_short((const uint8_t*) tabl e);
409 gammas[i] = value / 256.0f;
410 SkColorSpacePrintf("gamma %d %g\n", value, *gamma);
411 break;
412 }
413
414 // Print the interpolation table. For now, we ignore this and g uess 2.2f.
415 for (uint32_t j = 0; j < count; j++) {
416 SkColorSpacePrintf("curve[%d] %d\n", j,
417 read_big_endian_short((const uint8_t*) &table[j]));
418 }
419
420 gammas[i] = 2.2f;
421 break;
422 }
423 case kTAG_ParaCurveType:
424 // Guess 2.2f.
425 SkColorSpacePrintf("parametric curve\n");
426 gammas[i] = 2.2f;
427
428 switch(read_big_endian_short(src + 8)) {
429 case 0:
430 tagBytes = 12 + 4;
431 break;
432 case 1:
433 tagBytes = 12 + 12;
434 break;
435 case 2:
436 tagBytes = 12 + 16;
437 break;
438 case 3:
439 tagBytes = 12 + 20;
440 break;
441 case 4:
442 tagBytes = 12 + 28;
443 break;
444 default:
445 SkColorSpacePrintf("Invalid parametric curve type\n");
446 return false;
447 }
448 break;
449 default:
450 SkColorSpacePrintf("Unsupported gamma tag type %d\n", type);
451 return false;
452 }
453
454 // Adjust src and len if there is another gamma curve to load.
455 if (0 != numGammas) {
456 // Each curve is padded to 4-byte alignment.
457 tagBytes = SkAlign4(tagBytes);
458 if (len < tagBytes) {
374 return false; 459 return false;
375 } 460 }
376 461
377 const uint16_t* table = (const uint16_t*) (src + 12); 462 src += tagBytes;
378 if (1 == count) { 463 len -= tagBytes;
379 // Table entry is the exponent (bias 256). 464 }
380 uint16_t value = read_big_endian_short((const uint8_t*) table); 465 }
381 *gamma = value / 256.0f; 466
382 SkColorSpacePrintf("gamma %d %g\n", value, *gamma); 467 // If all of the gammas we encounter are 1.0f, indicate that we failed to lo ad gammas.
383 return true; 468 // There is no need to apply a gamma of 1.0f.
384 } 469 for (uint32_t i = 0; i < numGammas; i++) {
385 470 if (1.0f != gammas[i]) {
386 // Check length again if we have a table.
387 if (len < 12 + 2 * count) {
388 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len);
389 return false;
390 }
391
392 // Print the interpolation table. For now, we ignore this and guess 2.2f.
393 for (uint32_t i = 0; i < count; i++) {
394 SkColorSpacePrintf("curve[%d] %d\n", i,
395 read_big_endian_short((const uint8_t*) &table[i]));
396 }
397
398 *gamma = 2.2f;
399 return true; 471 return true;
400 } 472 }
401 case kTAG_ParaCurveType: 473 }
402 // Guess 2.2f. 474
403 SkColorSpacePrintf("parametric curve\n"); 475 return false;
404 *gamma = 2.2f; 476 }
405 return true; 477
478 static const uint32_t kTAG_AtoBType = SkSetFourByteTag('m', 'A', 'B', ' ');
479
480 bool load_color_lut(SkColorLookUpTable* colorLUT, uint32_t inputChannels, uint32 _t outputChannels,
481 const uint8_t* src, size_t len) {
482 if (len < 20) {
483 SkColorSpacePrintf("Color LUT tag is too small (%d bytes).", len);
484 return false;
485 }
486
487 SkASSERT(inputChannels <= SkColorLookUpTable::kMaxChannels &&
488 outputChannels <= SkColorLookUpTable::kMaxChannels);
489 colorLUT->fInputChannels = inputChannels;
490 colorLUT->fOutputChannels = outputChannels;
491 uint32_t numEntries = 1;
492 for (uint32_t i = 0; i < inputChannels; i++) {
493 colorLUT->fGridPoints[i] = src[i];
494 numEntries *= src[i];
495 }
496 numEntries *= outputChannels;
497
498 // Space is provided for a maximum of the 16 input channels. Now we determi ne the precision
499 // of the table values.
500 uint8_t precision = src[16];
501 switch (precision) {
502 case 1: // 8-bit data
503 case 2: // 16-bit data
504 break;
406 default: 505 default:
407 SkColorSpacePrintf("Unsupported gamma tag type %d\n", type); 506 SkColorSpacePrintf("Color LUT precision must be 8-bit or 16-bit.\n", len);
408 return false; 507 return false;
409 } 508 }
509
510 if (len < 20 + numEntries * precision) {
511 SkColorSpacePrintf("Color LUT tag is too small (%d bytes).", len);
512 return false;
513 }
514
515 // Movable struct colorLUT has ownership of fTable.
516 colorLUT->fTable = std::unique_ptr<float[]>(new float[numEntries]);
517 const uint8_t* ptr = src + 20;
518 for (uint32_t i = 0; i < numEntries; i++, ptr += precision) {
519 if (1 == precision) {
520 colorLUT->fTable[i] = ((float) ptr[i]) / 255.0f;
521 } else {
522 colorLUT->fTable[i] = ((float) read_big_endian_short(ptr)) / 65535.0 f;
523 }
524 }
525
526 return true;
527 }
528
529 bool load_matrix(SkFloat3x3* toXYZ, SkFloat3* toXYZOffset, const uint8_t* src, s ize_t len) {
530 if (len < 48) {
531 SkColorSpacePrintf("Matrix tag is too small (%d bytes).", len);
532 return false;
533 }
534
535 toXYZ->fMat[0] = SkFixedToFloat(read_big_endian_int(src));
536 toXYZ->fMat[3] = SkFixedToFloat(read_big_endian_int(src + 4));
537 toXYZ->fMat[6] = SkFixedToFloat(read_big_endian_int(src + 8));
538 toXYZ->fMat[1] = SkFixedToFloat(read_big_endian_int(src + 12));
539 toXYZ->fMat[4] = SkFixedToFloat(read_big_endian_int(src + 16));
540 toXYZ->fMat[7] = SkFixedToFloat(read_big_endian_int(src + 20));
541 toXYZ->fMat[2] = SkFixedToFloat(read_big_endian_int(src + 24));
542 toXYZ->fMat[5] = SkFixedToFloat(read_big_endian_int(src + 28));
543 toXYZ->fMat[8] = SkFixedToFloat(read_big_endian_int(src + 32));
544 toXYZOffset->fVec[0] = SkFixedToFloat(read_big_endian_int(src + 36));
545 toXYZOffset->fVec[1] = SkFixedToFloat(read_big_endian_int(src + 40));
546 toXYZOffset->fVec[2] = SkFixedToFloat(read_big_endian_int(src + 44));
547 return true;
548 }
549
550 bool load_a2b0(SkColorLookUpTable* colorLUT, SkFloat3* gamma, SkFloat3x3* toXYZ,
551 SkFloat3* toXYZOffset, const uint8_t* src, size_t len) {
552 if (len < 32) {
553 SkColorSpacePrintf("A to B tag is too small (%d bytes).", len);
554 return false;
555 }
556
557 uint32_t type = read_big_endian_uint(src);
558 if (kTAG_AtoBType != type) {
559 // FIXME (msarett): Need to support lut8Type and lut16Type.
560 SkColorSpacePrintf("Unsupported A to B tag type.\n");
561 return false;
562 }
563
564 // Read the number of channels. The four bytes that we skipped are reserved and
565 // must be zero.
566 uint8_t inputChannels = src[8];
567 uint8_t outputChannels = src[9];
568 if (0 == inputChannels || inputChannels > SkColorLookUpTable::kMaxChannels | |
569 0 < outputChannels || outputChannels > SkColorLookUpTable::kMaxChann els) {
570 // The color LUT assumes that there are at most 16 input channels. For RGB
571 // profiles, output channels should be 3.
572 SkColorSpacePrintf("Too many input or output channels in A to B tag.\n") ;
573 return false;
574 }
575
576 // Read the offsets of each element in the A to B tag. With the exception o f A curves and
577 // B curves (which we do not yet support), we will handle these elements in the order in
578 // which they should be applied (rather than the order in which they occur i n the tag).
579 // If the offset is non-zero it indicates that the element is present.
580 uint32_t offsetToACurves = read_big_endian_int(src + 28);
581 uint32_t offsetToBCurves = read_big_endian_int(src + 12);
582 if ((0 != offsetToACurves) || (0 != offsetToBCurves)) {
583 // FIXME (msarett): Handle A and B curves.
584 // Note that the A curve is technically required in order to have a colo r LUT.
585 // However, all the A curves I have seen so far have are just placeholde rs that
586 // don't actually transform the data.
587 SkColorSpacePrintf("Ignoring A and/or B curve. Output may be wrong.\n") ;
588 }
589
590 uint32_t offsetToColorLUT = read_big_endian_int(src + 24);
591 if (0 != offsetToColorLUT && offsetToColorLUT < len) {
592 if (!load_color_lut(colorLUT, inputChannels, outputChannels, src + offse tToColorLUT,
593 len - offsetToColorLUT)) {
594 SkColorSpacePrintf("Failed to read color LUT from A to B tag.\n");
595 }
596 }
597
598 uint32_t offsetToMCurves = read_big_endian_int(src + 20);
599 if (0 != offsetToMCurves && offsetToMCurves < len) {
600 if (!load_gammas(gamma->fVec, outputChannels, src + offsetToMCurves, len - offsetToMCurves))
601 {
602 SkColorSpacePrintf("Failed to read M curves from A to B tag.\n");
603 }
604 }
605
606 uint32_t offsetToMatrix = read_big_endian_int(src + 16);
607 if (0 != offsetToMatrix && offsetToMatrix < len) {
608 if (!load_matrix(toXYZ, toXYZOffset, src + offsetToMatrix, len - offsetT oMatrix)) {
609 SkColorSpacePrintf("Failed to read matrix from A to B tag.\n");
610 }
611 }
612
613 return true;
410 } 614 }
411 615
412 sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* base, size_t len) { 616 sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* base, size_t len) {
413 const uint8_t* ptr = (const uint8_t*) base; 617 const uint8_t* ptr = (const uint8_t*) base;
414 618
415 if (len < kICCHeaderSize) { 619 if (len < kICCHeaderSize) {
416 return_null("Data is not large enough to contain an ICC profile"); 620 return_null("Data is not large enough to contain an ICC profile");
417 } 621 }
418 622
419 // Read the ICC profile header and check to make sure that it is valid. 623 // Read the ICC profile header and check to make sure that it is valid.
(...skipping 25 matching lines...) Expand all
445 ptr = tags[i].init(ptr); 649 ptr = tags[i].init(ptr);
446 SkColorSpacePrintf("[%d] %c%c%c%c %d %d\n", i, (tags[i].fSignature >> 24 ) & 0xFF, 650 SkColorSpacePrintf("[%d] %c%c%c%c %d %d\n", i, (tags[i].fSignature >> 24 ) & 0xFF,
447 (tags[i].fSignature >> 16) & 0xFF, (tags[i].fSignature >> 8) & 0xFF, 651 (tags[i].fSignature >> 16) & 0xFF, (tags[i].fSignature >> 8) & 0xFF,
448 (tags[i].fSignature >> 0) & 0xFF, tags[i].fOffset, tags[i].fLen gth); 652 (tags[i].fSignature >> 0) & 0xFF, tags[i].fOffset, tags[i].fLen gth);
449 653
450 if (!tags[i].valid(kICCHeaderSize + len)) { 654 if (!tags[i].valid(kICCHeaderSize + len)) {
451 return_null("Tag is too large to fit in ICC profile"); 655 return_null("Tag is too large to fit in ICC profile");
452 } 656 }
453 } 657 }
454 658
455 // Load our XYZ and gamma matrices.
456 SkFloat3x3 toXYZ;
457 SkFloat3 gamma {{ 1.0f, 1.0f, 1.0f }};
458 switch (header.fInputColorSpace) { 659 switch (header.fInputColorSpace) {
459 case kRGB_ColorSpace: { 660 case kRGB_ColorSpace: {
661 // Recognize the rXYZ, gXYZ, and bXYZ tags.
460 const ICCTag* r = ICCTag::Find(tags.get(), tagCount, kTAG_rXYZ); 662 const ICCTag* r = ICCTag::Find(tags.get(), tagCount, kTAG_rXYZ);
461 const ICCTag* g = ICCTag::Find(tags.get(), tagCount, kTAG_gXYZ); 663 const ICCTag* g = ICCTag::Find(tags.get(), tagCount, kTAG_gXYZ);
462 const ICCTag* b = ICCTag::Find(tags.get(), tagCount, kTAG_bXYZ); 664 const ICCTag* b = ICCTag::Find(tags.get(), tagCount, kTAG_bXYZ);
463 if (!r || !g || !b) { 665 if (r && g && b) {
464 return_null("Need rgb tags for XYZ space"); 666 SkFloat3x3 toXYZ;
667 if (!load_xyz(&toXYZ.fMat[0], r->addr((const uint8_t*) base), r- >fLength) ||
668 !load_xyz(&toXYZ.fMat[3], g->addr((const uint8_t*) base), g- >fLength) ||
669 !load_xyz(&toXYZ.fMat[6], b->addr((const uint8_t*) base), b- >fLength))
670 {
671 return_null("Need valid rgb tags for XYZ space");
672 }
673
674 // It is not uncommon to see missing or empty gamma tags. This indicates
675 // that we should use unit gamma.
676 SkFloat3 gamma {{ 1.0f, 1.0f, 1.0f }};
677 r = ICCTag::Find(tags.get(), tagCount, kTAG_rTRC);
678 g = ICCTag::Find(tags.get(), tagCount, kTAG_gTRC);
679 b = ICCTag::Find(tags.get(), tagCount, kTAG_bTRC);
680 if (!r ||
681 !load_gammas(&gamma.fVec[0], 1, r->addr((const uint8_t*) bas e), r->fLength))
682 {
683 SkColorSpacePrintf("Failed to read R gamma tag.\n");
684 }
685 if (!g ||
686 !load_gammas(&gamma.fVec[1], 1, g->addr((const uint8_t*) bas e), g->fLength))
687 {
688 SkColorSpacePrintf("Failed to read G gamma tag.\n");
689 }
690 if (!b ||
691 !load_gammas(&gamma.fVec[2], 1, b->addr((const uint8_t*) bas e), b->fLength))
692 {
693 SkColorSpacePrintf("Failed to read B gamma tag.\n");
694 }
695 return SkColorSpace::NewRGB(toXYZ, gamma);
465 } 696 }
466 697
467 if (!load_xyz(&toXYZ.fMat[0], r->addr((const uint8_t*) base), r->fLe ngth) || 698 // Recognize color profile specified by A2B0 tag.
468 !load_xyz(&toXYZ.fMat[3], g->addr((const uint8_t*) base), g->fLe ngth) || 699 const ICCTag* a2b0 = ICCTag::Find(tags.get(), tagCount, kTAG_A2B0);
469 !load_xyz(&toXYZ.fMat[6], b->addr((const uint8_t*) base), b->fLe ngth)) 700 if (a2b0) {
470 { 701 SkColorLookUpTable colorLUT;
471 return_null("Need valid rgb tags for XYZ space"); 702 SkFloat3 gamma;
703 SkFloat3x3 toXYZ;
704 SkFloat3 toXYZOffset;
705 if (!load_a2b0(&colorLUT, &gamma, &toXYZ, &toXYZOffset,
706 a2b0->addr((const uint8_t*) base), a2b0->fLength)) {
707 return_null("Failed to parse A2B0 tag");
708 }
709
710 return sk_sp<SkColorSpace>(new SkColorSpace(std::move(colorLUT), gamma, toXYZ,
711 toXYZOffset));
472 } 712 }
473 713
474 r = ICCTag::Find(tags.get(), tagCount, kTAG_rTRC);
475 g = ICCTag::Find(tags.get(), tagCount, kTAG_gTRC);
476 b = ICCTag::Find(tags.get(), tagCount, kTAG_bTRC);
477 if (!r || !load_gamma(&gamma.fVec[0], r->addr((const uint8_t*) base) , r->fLength)) {
478 SkColorSpacePrintf("Failed to read R gamma tag.\n");
479 }
480 if (!g || !load_gamma(&gamma.fVec[1], g->addr((const uint8_t*) base) , g->fLength)) {
481 SkColorSpacePrintf("Failed to read G gamma tag.\n");
482 }
483 if (!b || !load_gamma(&gamma.fVec[2], b->addr((const uint8_t*) base) , b->fLength)) {
484 SkColorSpacePrintf("Failed to read B gamma tag.\n");
485 }
486 return SkColorSpace::NewRGB(toXYZ, gamma);
487 } 714 }
488 default: 715 default:
489 break; 716 break;
490 } 717 }
491 718
492 return_null("ICC profile contains unsupported colorspace"); 719 return_null("ICC profile contains unsupported colorspace");
493 } 720 }
494 721
495 //////////////////////////////////////////////////////////////////////////////// /////////////////// 722 //////////////////////////////////////////////////////////////////////////////// ///////////////////
496 723
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
572 } 799 }
573 800
574 // D65 white point of Rec. 709 [8] are: 801 // D65 white point of Rec. 709 [8] are:
575 // 802 //
576 // D65 white-point in unit luminance XYZ = 0.9505, 1.0000, 1.0890 803 // D65 white-point in unit luminance XYZ = 0.9505, 1.0000, 1.0890
577 // 804 //
578 // R G B white 805 // R G B white
579 // x 0.640 0.300 0.150 0.3127 806 // x 0.640 0.300 0.150 0.3127
580 // y 0.330 0.600 0.060 0.3290 807 // y 0.330 0.600 0.060 0.3290
581 // z 0.030 0.100 0.790 0.3582 808 // z 0.030 0.100 0.790 0.3582
OLDNEW
« no previous file with comments | « src/core/SkColorSpace.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698