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

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: 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
« src/core/SkColorSpace.h ('K') | « 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(SkColorLUT colorLUT, const SkFloat3& gamma, const SkF loat3x3& toXYZD50,
107 const SkFloat3& toXYZOffset)
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"
164 175
165 #define SkColorSpacePrintf(...) 176 #define SkColorSpacePrintf(...)
166 177
167 #define return_if_false(pred, msg) \ 178 #define return_if_false(pred, msg) \
msarett 2016/04/27 18:56:44 I think maybe in a follow-up change I'll create a
scroggo 2016/04/27 20:18:46 Do you think this stuff will be used in other file
msarett 2016/04/27 21:17:58 sgtm
168 do { \ 179 do { \
169 if (!(pred)) { \ 180 if (!(pred)) { \
170 SkColorSpacePrintf("Invalid ICC Profile: %s.\n", (msg)); \ 181 SkColorSpacePrintf("Invalid ICC Profile: %s.\n", (msg)); \
171 return false; \ 182 return false; \
172 } \ 183 } \
173 } while (0) 184 } while (0)
174 185
175 #define return_null(msg) \ 186 #define return_null(msg) \
176 do { \ 187 do { \
177 SkColorSpacePrintf("Invalid ICC Profile: %s.\n", (msg)); \ 188 SkColorSpacePrintf("Invalid ICC Profile: %s.\n", (msg)); \
(...skipping 150 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.
msarett 2016/04/27 18:56:44 Next up, I will probably create a gamma struct, wh
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) {
msarett 2016/04/27 18:56:45 This function is mostly the same minus a few chang
366 return false; 376 for (uint32_t i = 0; i < numGammas; i++) {
msarett 2016/04/27 18:56:44 Added a loop so we can handle multiple gamma curve
367 } 377 if (len < 12) {
368 378 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len);
369 uint32_t type = read_big_endian_uint(src); 379 return false;
scroggo 2016/04/27 20:18:46 If the first gamma is valid, but the second is not
msarett 2016/04/27 21:17:58 I have no idea if we'd come across this error. I'
370 switch (type) { 380 }
371 case kTAG_CurveType: { 381
372 uint32_t count = read_big_endian_int(src + 8); 382 uint32_t type = read_big_endian_uint(src);
373 if (0 == count) { 383 size_t tagBytes;
msarett 2016/04/27 18:56:45 Now we need to count the number of bytes in the ta
scroggo 2016/04/27 20:18:46 Maybe these comments would be useful to have in th
msarett 2016/04/27 21:17:57 Done.
384 switch (type) {
385 case kTAG_CurveType: {
386 uint32_t count = read_big_endian_uint(src + 8);
387 tagBytes = 12 + count * 2;
388 if (0 == count) {
msarett 2016/04/27 18:56:44 count == 0 now means unit gamma.
389 // Some tags require a gamma curve, but the author doesn't a ctually want
390 // to transform the data. In this case, it is common to see a curve with
391 // a count of 0.
392 gammas[i] = 1.0f;
393 break;
394 } else if (len < 12 + 2 * count) {
395 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len) ;
396 return false;
397 }
398
399 const uint16_t* table = (const uint16_t*) (src + 12);
400 if (1 == count) {
401 // Table entry is the exponent (bias 256).
402 uint16_t value = read_big_endian_short((const uint8_t*) tabl e);
403 gammas[i] = value / 256.0f;
404 SkColorSpacePrintf("gamma %d %g\n", value, *gamma);
405 break;
406 }
407
408 // Print the interpolation table. For now, we ignore this and g uess 2.2f.
409 for (uint32_t i = 0; i < count; i++) {
410 SkColorSpacePrintf("curve[%d] %d\n", i,
411 read_big_endian_short((const uint8_t*) &table[i]));
412 }
413
414 gammas[i] = 2.2f;
415 break;
416 }
417 case kTAG_ParaCurveType:
418 // Guess 2.2f.
419 SkColorSpacePrintf("parametric curve\n");
420 gammas[i] = 2.2f;
421
422 switch(read_big_endian_short(src + 8)) {
msarett 2016/04/27 18:56:44 Added switch statement to determine how many bytes
423 case 0:
424 tagBytes = 12 + 4;
425 break;
426 case 1:
427 tagBytes = 12 + 12;
428 break;
429 case 2:
430 tagBytes = 12 + 16;
431 break;
432 case 3:
433 tagBytes = 12 + 20;
434 break;
435 case 4:
436 tagBytes = 12 + 28;
437 break;
438 default:
439 SkColorSpacePrintf("Invalid parametric curve type\n");
440 return false;
441 }
442 break;
443 default:
444 SkColorSpacePrintf("Unsupported gamma tag type %d\n", type);
445 return false;
446 }
447
448 // Adjust src and len if there is another gamma curve to load.
msarett 2016/04/27 18:56:45 The rest of this function is also new.
449 if (0 != numGammas) {
450 // Each curve will be padded to 4-byte alignment.
scroggo 2016/04/27 20:18:46 I found this sentence confusing - I thought you me
msarett 2016/04/27 21:17:57 Done.
451 tagBytes = SkAlign4(tagBytes);
452 if (len < tagBytes) {
374 return false; 453 return false;
375 } 454 }
376 455
377 const uint16_t* table = (const uint16_t*) (src + 12); 456 src += tagBytes;
378 if (1 == count) { 457 len -= tagBytes;
379 // Table entry is the exponent (bias 256). 458 }
380 uint16_t value = read_big_endian_short((const uint8_t*) table); 459 }
381 *gamma = value / 256.0f; 460
382 SkColorSpacePrintf("gamma %d %g\n", value, *gamma); 461 // If all of the gammas we encounter are 1.0f, indicate that we failed to lo ad gammas.
383 return true; 462 // There is no need to apply a gamma of 1.0f.
384 } 463 for (uint32_t i = 0; i < numGammas; i++) {
385 464 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; 465 return true;
400 } 466 }
401 case kTAG_ParaCurveType: 467 }
402 // Guess 2.2f. 468
403 SkColorSpacePrintf("parametric curve\n"); 469 return false;
404 *gamma = 2.2f; 470 }
405 return true; 471
472 static const uint32_t kTAG_AtoBType = SkSetFourByteTag('m', 'A', 'B', ' ');
473
474 bool load_color_lut(SkColorLUT* colorLUT, uint32_t inputChannels, uint32_t outpu tChannels,
475 const uint8_t* src, size_t len) {
476 if (len < 20) {
477 SkColorSpacePrintf("Color LUT tag is too small (%d bytes).", len);
478 return false;
479 }
480
481 colorLUT->fInputChannels = inputChannels;
482 colorLUT->fOutputChannels = outputChannels;
scroggo 2016/04/27 20:18:46 Should we SkASSERT(inputChannels <= kMaxChannels &
msarett 2016/04/27 21:17:57 Done.
483 uint32_t numEntries = 1;
484 for (uint32_t i = 0; i < inputChannels; i++) {
485 colorLUT->fGridPoints[i] = src[i];
486 numEntries *= src[i];
487 }
488 numEntries *= outputChannels;
489
490 // Space is provided for a maximum of the 16 input channels. Now we determi ne the precision
491 // of the table values.
492 uint8_t precision = src[16];
493 switch (precision) {
494 case 1: // 8-bit data
495 case 2: // 16-bit data
496 break;
406 default: 497 default:
407 SkColorSpacePrintf("Unsupported gamma tag type %d\n", type); 498 SkColorSpacePrintf("Color LUT precision must be 8-bit or 16-bit.\n", len);
408 return false; 499 return false;
409 } 500 }
501
502 if (len < 20 + numEntries * precision) {
503 SkColorSpacePrintf("Color LUT tag is too small (%d bytes).", len);
504 return false;
505 }
506
507 // Movable struct colorLUT has ownership of fTable.
508 colorLUT->fTable = std::unique_ptr<float[]>(new float[numEntries]);
509 const uint8_t* ptr = src + 20;
510 for (uint32_t i = 0; i < numEntries; i++, ptr += precision) {
511 if (1 == precision) {
512 colorLUT->fTable[i] = ((float) ptr[i]) / 255.0f;
513 } else {
514 colorLUT->fTable[i] = ((float) read_big_endian_short(ptr)) / 65535.0 f;
515 }
516 }
517
518 return true;
519 }
520
521 bool load_matrix(SkFloat3x3* toXYZ, SkFloat3* toXYZOffset, const uint8_t* src, s ize_t len) {
522 if (len < 48) {
523 SkColorSpacePrintf("Matrix tag is too small (%d bytes).", len);
524 return false;
525 }
526
527 toXYZ->fMat[0] = SkFixedToFloat(read_big_endian_int(src));
528 toXYZ->fMat[3] = SkFixedToFloat(read_big_endian_int(src + 4));
529 toXYZ->fMat[6] = SkFixedToFloat(read_big_endian_int(src + 8));
530 toXYZ->fMat[1] = SkFixedToFloat(read_big_endian_int(src + 12));
531 toXYZ->fMat[4] = SkFixedToFloat(read_big_endian_int(src + 16));
532 toXYZ->fMat[7] = SkFixedToFloat(read_big_endian_int(src + 20));
533 toXYZ->fMat[2] = SkFixedToFloat(read_big_endian_int(src + 24));
534 toXYZ->fMat[5] = SkFixedToFloat(read_big_endian_int(src + 28));
535 toXYZ->fMat[8] = SkFixedToFloat(read_big_endian_int(src + 32));
536 toXYZOffset->fVec[0] = SkFixedToFloat(read_big_endian_int(src + 36));
537 toXYZOffset->fVec[1] = SkFixedToFloat(read_big_endian_int(src + 40));
538 toXYZOffset->fVec[2] = SkFixedToFloat(read_big_endian_int(src + 44));
539 return true;
540 }
541
542 bool load_a2b0(SkColorLUT* colorLUT, SkFloat3* gamma, SkFloat3x3* toXYZ, SkFloat 3* toXYZOffset,
543 const uint8_t* src, size_t len) {
544 if (len < 32) {
545 SkColorSpacePrintf("A to B tag is too small (%d bytes).", len);
546 return false;
547 }
548
549 uint32_t type = read_big_endian_uint(src);
550 if (kTAG_AtoBType != type) {
551 // FIXME (msarett): Need to support lut8Type and lut16Type.
552 SkColorSpacePrintf("Unsupported A to B tag type.\n");
553 return false;
554 }
555
556 // Read the number of channels. The four bytes that we skipped are reserved and
557 // must be zero.
558 uint8_t inputChannels = src[8];
559 uint8_t outputChannels = src[9];
560 if (0 == inputChannels || inputChannels > SkColorLUT::kMaxChannels ||
561 0 < outputChannels || outputChannels > SkColorLUT::kMaxChannels) {
562 // The color LUT assumes that there are at most 16 input channels. For RGB
563 // profiles, output channels should be 3.
564 SkColorSpacePrintf("Too many input or output channels in A to B tag.\n") ;
565 return false;
566 }
567
568 // Skip two more reserved zero bytes before reading the offsets of each elem ent in
569 // the A to B tag. If the offset is non-zero it indicates that the element is present.
570 // We read these in the order that the elements should be applied, rather th an the
scroggo 2016/04/27 20:18:46 It might be clearer to move these to where they're
msarett 2016/04/27 21:17:57 sgtm. Yes, the B curve will be applied last, if w
571 // order in which the offsets are stored.
572 uint32_t offsetToACurves = read_big_endian_int(src + 28);
573 uint32_t offsetToColorLUT = read_big_endian_int(src + 24);
574 uint32_t offsetToMCurves = read_big_endian_int(src + 20);
575 uint32_t offsetToMatrix = read_big_endian_int(src + 16);
576 uint32_t offsetToBCurves = read_big_endian_int(src + 12);
577
578 bool hasACurves = (0 != offsetToACurves);
579 bool hasBCurves = (0 != offsetToBCurves);
580 if (hasACurves || hasBCurves) {
581 // FIXME (msarett): Handle A and B curves.
582 // Note that the A curve is technically required in order to have a colo r LUT.
583 // However, all the A curves I have seen so far have are just placeholde rs that
584 // don't actually transform the data.
585 SkColorSpacePrintf("Ignoring A and/or B curve. Output may be wrong.\n") ;
586 }
587
588 bool hasColorLUT = (0 != offsetToColorLUT && offsetToColorLUT < len);
589 if (hasColorLUT) {
590 if (!load_color_lut(colorLUT, inputChannels, outputChannels, src + offse tToColorLUT,
591 len - offsetToColorLUT)) {
592 hasColorLUT = false;
scroggo 2016/04/27 20:18:46 It looks like this is never used again. Do you nee
msarett 2016/04/27 21:17:58 Deleting them... At some point, we'll need to kno
593 SkColorSpacePrintf("Failed to read color LUT from A to B tag.\n");
594 }
595 }
596
597 bool hasMCurves = (0 != offsetToMCurves && offsetToMCurves < len);
598 if (hasMCurves) {
599 if (!load_gammas(gamma->fVec, outputChannels, src + offsetToMCurves, len - offsetToMCurves))
600 {
601 hasMCurves = false;
602 SkColorSpacePrintf("Failed to read M curves from A to B tag.\n");
603 }
604 }
605
606 bool hasMatrix = (0 != offsetToMatrix && offsetToMatrix < len);
607 if (hasMatrix) {
608 if (!load_matrix(toXYZ, toXYZOffset, src + offsetToMatrix, len - offsetT oMatrix)) {
609 hasMatrix = false;
610 SkColorSpacePrintf("Failed to read matrix from A to B tag.\n");
611 }
612 }
613
614 return true;
410 } 615 }
411 616
412 sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* base, size_t len) { 617 sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* base, size_t len) {
413 const uint8_t* ptr = (const uint8_t*) base; 618 const uint8_t* ptr = (const uint8_t*) base;
414 619
415 if (len < kICCHeaderSize) { 620 if (len < kICCHeaderSize) {
416 return_null("Data is not large enough to contain an ICC profile"); 621 return_null("Data is not large enough to contain an ICC profile");
417 } 622 }
418 623
419 // Read the ICC profile header and check to make sure that it is valid. 624 // 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); 650 ptr = tags[i].init(ptr);
446 SkColorSpacePrintf("[%d] %c%c%c%c %d %d\n", i, (tags[i].fSignature >> 24 ) & 0xFF, 651 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, 652 (tags[i].fSignature >> 16) & 0xFF, (tags[i].fSignature >> 8) & 0xFF,
448 (tags[i].fSignature >> 0) & 0xFF, tags[i].fOffset, tags[i].fLen gth); 653 (tags[i].fSignature >> 0) & 0xFF, tags[i].fOffset, tags[i].fLen gth);
449 654
450 if (!tags[i].valid(kICCHeaderSize + len)) { 655 if (!tags[i].valid(kICCHeaderSize + len)) {
451 return_null("Tag is too large to fit in ICC profile"); 656 return_null("Tag is too large to fit in ICC profile");
452 } 657 }
453 } 658 }
454 659
455 // Load our XYZ and gamma matrices.
456 SkFloat3x3 toXYZ;
457 SkFloat3 gamma {{ 1.0f, 1.0f, 1.0f }};
458 switch (header.fInputColorSpace) { 660 switch (header.fInputColorSpace) {
459 case kRGB_ColorSpace: { 661 case kRGB_ColorSpace: {
662 // Recognize the rXYZ, gXYZ, and bXYZ tags.
460 const ICCTag* r = ICCTag::Find(tags.get(), tagCount, kTAG_rXYZ); 663 const ICCTag* r = ICCTag::Find(tags.get(), tagCount, kTAG_rXYZ);
461 const ICCTag* g = ICCTag::Find(tags.get(), tagCount, kTAG_gXYZ); 664 const ICCTag* g = ICCTag::Find(tags.get(), tagCount, kTAG_gXYZ);
462 const ICCTag* b = ICCTag::Find(tags.get(), tagCount, kTAG_bXYZ); 665 const ICCTag* b = ICCTag::Find(tags.get(), tagCount, kTAG_bXYZ);
463 if (!r || !g || !b) { 666 if (r && g && b) {
msarett 2016/04/27 18:56:44 Moved a bunch of code into this block, but didn't
464 return_null("Need rgb tags for XYZ space"); 667 SkFloat3x3 toXYZ;
668 if (!load_xyz(&toXYZ.fMat[0], r->addr((const uint8_t*) base), r- >fLength) ||
669 !load_xyz(&toXYZ.fMat[3], g->addr((const uint8_t*) base), g- >fLength) ||
670 !load_xyz(&toXYZ.fMat[6], b->addr((const uint8_t*) base), b- >fLength))
671 {
672 return_null("Need valid rgb tags for XYZ space");
673 }
674
675 // It is not uncommon to see missing or empty gamma tags. This indicates
676 // that we should use unit gamma.
677 SkFloat3 gamma {{ 1.0f, 1.0f, 1.0f }};
678 r = ICCTag::Find(tags.get(), tagCount, kTAG_rTRC);
679 g = ICCTag::Find(tags.get(), tagCount, kTAG_gTRC);
680 b = ICCTag::Find(tags.get(), tagCount, kTAG_bTRC);
681 if (!r ||
682 !load_gammas(&gamma.fVec[0], 1, r->addr((const uint8_t*) bas e), r->fLength))
scroggo 2016/04/27 20:18:46 Previously we required the length to be at least 1
msarett 2016/04/27 21:17:58 Yes, it appears that a gamma chunk with count == 0
683 {
684 SkColorSpacePrintf("Failed to read R gamma tag.\n");
685 }
686 if (!g ||
687 !load_gammas(&gamma.fVec[1], 1, g->addr((const uint8_t*) bas e), g->fLength))
688 {
689 SkColorSpacePrintf("Failed to read G gamma tag.\n");
690 }
691 if (!b ||
692 !load_gammas(&gamma.fVec[2], 1, b->addr((const uint8_t*) bas e), b->fLength))
693 {
694 SkColorSpacePrintf("Failed to read B gamma tag.\n");
695 }
696 return SkColorSpace::NewRGB(toXYZ, gamma);
465 } 697 }
466 698
467 if (!load_xyz(&toXYZ.fMat[0], r->addr((const uint8_t*) base), r->fLe ngth) || 699 // Recognize color profile specified by A2B0 tag.
468 !load_xyz(&toXYZ.fMat[3], g->addr((const uint8_t*) base), g->fLe ngth) || 700 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)) 701 if (a2b0) {
470 { 702 SkColorLUT colorLUT;
471 return_null("Need valid rgb tags for XYZ space"); 703 SkFloat3 gamma;
704 SkFloat3x3 toXYZ;
705 SkFloat3 toXYZOffset;
706 if (!load_a2b0(&colorLUT, &gamma, &toXYZ, &toXYZOffset,
707 a2b0->addr((const uint8_t*) base), a2b0->fLength)) {
708 return_null("Failed to parse A2B0 tag");
709 }
710
711 return sk_sp<SkColorSpace>(new SkColorSpace(std::move(colorLUT), gamma, toXYZ,
712 toXYZOffset));
472 } 713 }
473 714
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 } 715 }
488 default: 716 default:
489 break; 717 break;
490 } 718 }
491 719
492 return_null("ICC profile contains unsupported colorspace"); 720 return_null("ICC profile contains unsupported colorspace");
493 } 721 }
494 722
495 //////////////////////////////////////////////////////////////////////////////// /////////////////// 723 //////////////////////////////////////////////////////////////////////////////// ///////////////////
496 724
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
572 } 800 }
573 801
574 // D65 white point of Rec. 709 [8] are: 802 // D65 white point of Rec. 709 [8] are:
575 // 803 //
576 // D65 white-point in unit luminance XYZ = 0.9505, 1.0000, 1.0890 804 // D65 white-point in unit luminance XYZ = 0.9505, 1.0000, 1.0890
577 // 805 //
578 // R G B white 806 // R G B white
579 // x 0.640 0.300 0.150 0.3127 807 // x 0.640 0.300 0.150 0.3127
580 // y 0.330 0.600 0.060 0.3290 808 // y 0.330 0.600 0.060 0.3290
581 // z 0.030 0.100 0.790 0.3582 809 // z 0.030 0.100 0.790 0.3582
OLDNEW
« src/core/SkColorSpace.h ('K') | « src/core/SkColorSpace.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698