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

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

Issue 2117773002: Refactor parsing and storage of SkGammas (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Read fixed 0.16 properly Created 4 years, 5 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_Base.h ('k') | tests/ColorSpaceXformTest.cpp » ('j') | 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 "SkColorSpace.h" 8 #include "SkColorSpace.h"
9 #include "SkColorSpace_Base.h" 9 #include "SkColorSpace_Base.h"
10 #include "SkColorSpacePriv.h" 10 #include "SkColorSpacePriv.h"
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 dst[0] = SkFixedToFloat(read_big_endian_int(src + 8)); 231 dst[0] = SkFixedToFloat(read_big_endian_int(src + 8));
232 dst[1] = SkFixedToFloat(read_big_endian_int(src + 12)); 232 dst[1] = SkFixedToFloat(read_big_endian_int(src + 12));
233 dst[2] = SkFixedToFloat(read_big_endian_int(src + 16)); 233 dst[2] = SkFixedToFloat(read_big_endian_int(src + 16));
234 SkColorSpacePrintf("XYZ %g %g %g\n", dst[0], dst[1], dst[2]); 234 SkColorSpacePrintf("XYZ %g %g %g\n", dst[0], dst[1], dst[2]);
235 return true; 235 return true;
236 } 236 }
237 237
238 static constexpr uint32_t kTAG_CurveType = SkSetFourByteTag('c', 'u', 'r', ' v'); 238 static constexpr uint32_t kTAG_CurveType = SkSetFourByteTag('c', 'u', 'r', ' v');
239 static constexpr uint32_t kTAG_ParaCurveType = SkSetFourByteTag('p', 'a', 'r', ' a'); 239 static constexpr uint32_t kTAG_ParaCurveType = SkSetFourByteTag('p', 'a', 'r', ' a');
240 240
241 static bool load_gammas(SkGammaCurve* gammas, uint32_t numGammas, const uint8_t* src, size_t len) { 241 static SkGammas::Type set_gamma_value(SkGammas::Data* data, float value) {
242 for (uint32_t i = 0; i < numGammas; i++) { 242 if (color_space_almost_equal(2.2f, value)) {
243 if (len < 12) { 243 data->fNamed = SkColorSpace::k2Dot2Curve_GammaNamed;
244 // FIXME (msarett): 244 return SkGammas::Type::kNamed_Type;
245 // We could potentially return false here after correctly parsing *s ome* of the 245 }
246 // gammas correctly. Should we somehow try to indicate a partial su ccess? 246
247 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); 247 if (color_space_almost_equal(1.0f, value)) {
248 return false; 248 data->fNamed = SkColorSpace::kLinear_GammaNamed;
249 return SkGammas::Type::kNamed_Type;
250 }
251
252 if (color_space_almost_equal(0.0f, value)) {
253 return SkGammas::Type::kNone_Type;
254 }
255
256 data->fValue = value;
257 return SkGammas::Type::kValue_Type;
258 }
259
260 static float read_big_endian_16_dot_16(const uint8_t buf[4]) {
261 // It just so happens that SkFixed is also 16.16!
262 return SkFixedToFloat(read_big_endian_int(buf));
263 }
264
265 /**
266 * @param outData Set to the appropriate value on success. If we have tabl e or
267 * parametric gamma, it is the responsibility of the caller to set
268 * fOffset.
269 * @param outParams If this is a parametric gamma, this is set to the appropr iate
270 * parameters on success.
271 * @param outTagBytes Will be set to the length of the tag on success.
272 * @src Pointer to tag data.
273 * @len Length of tag data in bytes.
274 *
275 * @return kNone_Type on failure, otherwise the type of the gamma ta g.
276 */
277 static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkGammas::Params* out Params,
278 size_t* outTagBytes, const uint8_t* src, s ize_t len) {
279 if (len < 12) {
280 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len);
281 return SkGammas::Type::kNone_Type;
282 }
283
284 // In the case of consecutive gamma tags, we need to count the number of byt es in the
285 // tag, so that we can move on to the next tag.
286 size_t tagBytes;
287
288 uint32_t type = read_big_endian_uint(src);
289 // Bytes 4-7 are reserved and should be set to zero.
290 switch (type) {
291 case kTAG_CurveType: {
292 uint32_t count = read_big_endian_uint(src + 8);
293
294 // tagBytes = 12 + 2 * count
295 // We need to do safe addition here to avoid integer overflow.
296 if (!safe_add(count, count, &tagBytes) ||
297 !safe_add((size_t) 12, tagBytes, &tagBytes))
298 {
299 SkColorSpacePrintf("Invalid gamma count");
300 return SkGammas::Type::kNone_Type;
301 }
302
303 if (len < tagBytes) {
304 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len);
305 return SkGammas::Type::kNone_Type;
306 }
307 *outTagBytes = tagBytes;
308
309 if (0 == count) {
310 // Some tags require a gamma curve, but the author doesn't actua lly want
311 // to transform the data. In this case, it is common to see a c urve with
312 // a count of 0.
313 outData->fNamed = SkColorSpace::kLinear_GammaNamed;
314 return SkGammas::Type::kNamed_Type;
315 }
316
317 const uint16_t* table = (const uint16_t*) (src + 12);
318 if (1 == count) {
319 // The table entry is the gamma (with a bias of 256).
320 float value = (read_big_endian_short((const uint8_t*) table)) / 256.0f;
321 SkColorSpacePrintf("gamma %g\n", value);
322
323 return set_gamma_value(outData, value);
324 }
325
326 // Check for frequently occurring sRGB curves.
327 // We do this by sampling a few values and see if they match our exp ectation.
328 // A more robust solution would be to compare each value in this cur ve against
329 // an sRGB curve to see if we remain below an error threshold. At t his time,
330 // we haven't seen any images in the wild that make this kind of
331 // calculation necessary. We encounter identical gamma curves over and
332 // over again, but relatively few variations.
333 if (1024 == count) {
334 // The magic values were chosen because they match both the very common
335 // HP sRGB gamma table and the less common Canon sRGB gamma tabl e (which use
336 // different rounding rules).
337 if (0 == read_big_endian_short((const uint8_t*) &table[0]) &&
338 3366 == read_big_endian_short((const uint8_t*) &table[25 7]) &&
339 14116 == read_big_endian_short((const uint8_t*) &table[5 13]) &&
340 34318 == read_big_endian_short((const uint8_t*) &table[7 68]) &&
341 65535 == read_big_endian_short((const uint8_t*) &table[1 023])) {
342 outData->fNamed = SkColorSpace::kSRGB_GammaNamed;
343 return SkGammas::Type::kNamed_Type;
344 }
345 }
346
347 if (26 == count) {
348 // The magic values were chosen because they match a very common LCMS sRGB
349 // gamma table.
350 if (0 == read_big_endian_short((const uint8_t*) &table[0]) &&
351 3062 == read_big_endian_short((const uint8_t*) &table[6] ) &&
352 12824 == read_big_endian_short((const uint8_t*) &table[1 2]) &&
353 31237 == read_big_endian_short((const uint8_t*) &table[1 8]) &&
354 65535 == read_big_endian_short((const uint8_t*) &table[2 5])) {
355 outData->fNamed = SkColorSpace::kSRGB_GammaNamed;
356 return SkGammas::Type::kNamed_Type;
357 }
358 }
359
360 if (4096 == count) {
361 // The magic values were chosen because they match Nikon, Epson, and
362 // LCMS sRGB gamma tables (all of which use different rounding r ules).
363 if (0 == read_big_endian_short((const uint8_t*) &table[0]) &&
364 950 == read_big_endian_short((const uint8_t*) &table[515 ]) &&
365 3342 == read_big_endian_short((const uint8_t*) &table[10 25]) &&
366 14079 == read_big_endian_short((const uint8_t*) &table[2 051]) &&
367 65535 == read_big_endian_short((const uint8_t*) &table[4 095])) {
368 outData->fNamed = SkColorSpace::kSRGB_GammaNamed;
369 return SkGammas::Type::kNamed_Type;
370 }
371 }
372
373 // Otherwise, we will represent gamma with a table.
374 outData->fTable.fSize = count;
375 return SkGammas::Type::kTable_Type;
249 } 376 }
250 377 case kTAG_ParaCurveType: {
251 // We need to count the number of bytes in the tag, so we are able to mo ve to the 378 enum ParaCurveType {
252 // next tag on the next loop iteration. 379 kExponential_ParaCurveType = 0,
253 size_t tagBytes; 380 kGAB_ParaCurveType = 1,
254 381 kGABC_ParaCurveType = 2,
255 uint32_t type = read_big_endian_uint(src); 382 kGABDE_ParaCurveType = 3,
256 switch (type) { 383 kGABCDEF_ParaCurveType = 4,
257 case kTAG_CurveType: { 384 };
258 uint32_t count = read_big_endian_uint(src + 8); 385
259 386 // Determine the format of the parametric curve tag.
260 // tagBytes = 12 + 2 * count 387 uint16_t format = read_big_endian_short(src + 8);
261 // We need to do safe addition here to avoid integer overflow. 388 if (format > kGABCDEF_ParaCurveType) {
262 if (!safe_add(count, count, &tagBytes) || 389 SkColorSpacePrintf("Unsupported gamma tag type %d\n", type);
263 !safe_add((size_t) 12, tagBytes, &tagBytes)) 390 return SkGammas::Type::kNone_Type;
264 { 391 }
265 SkColorSpacePrintf("Invalid gamma count"); 392
266 return false; 393 if (kExponential_ParaCurveType == format) {
267 } 394 tagBytes = 12 + 4;
268 395 if (len < tagBytes) {
269 if (0 == count) { 396 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len) ;
270 // Some tags require a gamma curve, but the author doesn't a ctually want 397 return SkGammas::Type::kNone_Type;
271 // to transform the data. In this case, it is common to see a curve with 398 }
272 // a count of 0. 399
273 gammas[i].fNamed = SkColorSpace::kLinear_GammaNamed; 400 // Y = X^g
401 float g = read_big_endian_16_dot_16(src + 12);
402
403 *outTagBytes = tagBytes;
404 return set_gamma_value(outData, g);
405 }
406
407 // Here's where the real parametric gammas start. There are many
408 // permutations of the same equations.
409 //
410 // Y = (aX + b)^g + c for X >= d
411 // Y = eX + f otherwise
412 //
413 // We will fill in with zeros as necessary to always match the above form.
414 if (len < 24) {
415 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len);
416 return SkGammas::Type::kNone_Type;
417 }
418 float g = read_big_endian_16_dot_16(src + 12);
419 float a = read_big_endian_16_dot_16(src + 16);
420 float b = read_big_endian_16_dot_16(src + 20);
421 float c = 0.0f, d = 0.0f, e = 0.0f, f = 0.0f;
422 switch(format) {
423 case kGAB_ParaCurveType:
424 tagBytes = 12 + 12;
425
426 // Y = (aX + b)^g for X >= -b/a
427 // Y = 0 otherwise
428 d = -b / a;
274 break; 429 break;
275 } else if (len < tagBytes) { 430 case kGABC_ParaCurveType:
276 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len) ; 431 tagBytes = 12 + 16;
277 return false;
278 }
279
280 const uint16_t* table = (const uint16_t*) (src + 12);
281 if (1 == count) {
282 // The table entry is the gamma (with a bias of 256).
283 float value = (read_big_endian_short((const uint8_t*) table) ) / 256.0f;
284 set_gamma_value(&gammas[i], value);
285 SkColorSpacePrintf("gamma %g\n", value);
286 break;
287 }
288
289 // Check for frequently occurring sRGB curves.
290 // We do this by sampling a few values and see if they match our expectation.
291 // A more robust solution would be to compare each value in this curve against
292 // an sRGB curve to see if we remain below an error threshold. At this time,
293 // we haven't seen any images in the wild that make this kind of
294 // calculation necessary. We encounter identical gamma curves o ver and
295 // over again, but relatively few variations.
296 if (1024 == count) {
297 // The magic values were chosen because they match a very co mmon sRGB
298 // gamma table and the less common Canon sRGB gamma table (w hich use
299 // different rounding rules).
300 if (0 == read_big_endian_short((const uint8_t*) &table[0]) & &
301 3366 == read_big_endian_short((const uint8_t*) &tabl e[257]) &&
302 14116 == read_big_endian_short((const uint8_t*) &tab le[513]) &&
303 34318 == read_big_endian_short((const uint8_t*) &tab le[768]) &&
304 65535 == read_big_endian_short((const uint8_t*) &tab le[1023])) {
305 gammas[i].fNamed = SkColorSpace::kSRGB_GammaNamed;
306 break;
307 }
308 } else if (26 == count) {
309 // The magic values were chosen because they match a very co mmon sRGB
310 // gamma table.
311 if (0 == read_big_endian_short((const uint8_t*) &table[0]) & &
312 3062 == read_big_endian_short((const uint8_t*) &tabl e[6]) &&
313 12824 == read_big_endian_short((const uint8_t*) &tab le[12]) &&
314 31237 == read_big_endian_short((const uint8_t*) &tab le[18]) &&
315 65535 == read_big_endian_short((const uint8_t*) &tab le[25])) {
316 gammas[i].fNamed = SkColorSpace::kSRGB_GammaNamed;
317 break;
318 }
319 } else if (4096 == count) {
320 // The magic values were chosen because they match Nikon, Ep son, and
321 // LCMS sRGB gamma tables (all of which use different roundi ng rules).
322 if (0 == read_big_endian_short((const uint8_t*) &table[0]) & &
323 950 == read_big_endian_short((const uint8_t*) &table [515]) &&
324 3342 == read_big_endian_short((const uint8_t*) &tabl e[1025]) &&
325 14079 == read_big_endian_short((const uint8_t*) &tab le[2051]) &&
326 65535 == read_big_endian_short((const uint8_t*) &tab le[4095])) {
327 gammas[i].fNamed = SkColorSpace::kSRGB_GammaNamed;
328 break;
329 }
330 }
331
332 // Otherwise, fill in the interpolation table.
333 gammas[i].fTableSize = count;
334 gammas[i].fTable = std::unique_ptr<float[]>(new float[count]);
335 for (uint32_t j = 0; j < count; j++) {
336 gammas[i].fTable[j] =
337 (read_big_endian_short((const uint8_t*) &table[j])) / 65535.0f;
338 }
339 break;
340 }
341 case kTAG_ParaCurveType: {
342 enum ParaCurveType {
343 kExponential_ParaCurveType = 0,
344 kGAB_ParaCurveType = 1,
345 kGABC_ParaCurveType = 2,
346 kGABDE_ParaCurveType = 3,
347 kGABCDEF_ParaCurveType = 4,
348 };
349
350 // Determine the format of the parametric curve tag.
351 uint16_t format = read_big_endian_short(src + 8);
352 if (kExponential_ParaCurveType == format) {
353 tagBytes = 12 + 4;
354 if (len < tagBytes) { 432 if (len < tagBytes) {
355 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); 433 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len);
356 return false; 434 return SkGammas::Type::kNone_Type;
357 } 435 }
358 436
359 // Y = X^g 437 // Y = (aX + b)^g + c for X >= -b/a
360 int32_t g = read_big_endian_int(src + 12); 438 // Y = c otherwise
361 set_gamma_value(&gammas[i], SkFixedToFloat(g)); 439 c = read_big_endian_16_dot_16(src + 24);
362 } else { 440 d = -b / a;
363 // Here's where the real parametric gammas start. There are many 441 f = c;
364 // permutations of the same equations. 442 break;
365 // 443 case kGABDE_ParaCurveType:
444 tagBytes = 12 + 20;
445 if (len < tagBytes) {
446 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len);
447 return SkGammas::Type::kNone_Type;
448 }
449
450 // Y = (aX + b)^g for X >= d
451 // Y = eX otherwise
452 d = read_big_endian_16_dot_16(src + 28);
453
454 // Not a bug! We define |e| to always be the coefficient on X in the
455 // second equation. The spec calls this |c| in this particu lar equation.
456 // We don't follow their convention because then |c| would h ave a
457 // different meaning in each of our cases.
458 e = read_big_endian_16_dot_16(src + 24);
459 break;
460 case kGABCDEF_ParaCurveType:
461 tagBytes = 12 + 28;
462 if (len < tagBytes) {
463 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len);
464 return SkGammas::Type::kNone_Type;
465 }
466
366 // Y = (aX + b)^g + c for X >= d 467 // Y = (aX + b)^g + c for X >= d
367 // Y = eX + f otherwise 468 // Y = eX + f otherwise
368 // 469 // NOTE: The ICC spec writes "cX" in place of "eX" but I thi nk
369 // We will fill in with zeros as necessary to always match t he above form. 470 // it's a typo.
370 float g = 0.0f, a = 0.0f, b = 0.0f, c = 0.0f, d = 0.0f, e = 0.0f, f = 0.0f; 471 c = read_big_endian_16_dot_16(src + 24);
371 switch(format) { 472 d = read_big_endian_16_dot_16(src + 28);
372 case kGAB_ParaCurveType: { 473 e = read_big_endian_16_dot_16(src + 32);
373 tagBytes = 12 + 12; 474 f = read_big_endian_16_dot_16(src + 36);
374 if (len < tagBytes) { 475 break;
375 SkColorSpacePrintf("gamma tag is too small (%d b ytes)", len); 476 default:
376 return false; 477 SkASSERT(false);
377 } 478 return SkGammas::Type::kNone_Type;
378 479 }
379 // Y = (aX + b)^g for X >= -b/a 480
380 // Y = 0 otherwise 481 // Recognize and simplify a very common parametric representation of sRGB gamma.
381 g = SkFixedToFloat(read_big_endian_int(src + 12)); 482 if (color_space_almost_equal(0.9479f, a) &&
382 a = SkFixedToFloat(read_big_endian_int(src + 16)); 483 color_space_almost_equal(0.0521f, b) &&
383 if (0.0f == a) { 484 color_space_almost_equal(0.0000f, c) &&
384 return false; 485 color_space_almost_equal(0.0405f, d) &&
385 } 486 color_space_almost_equal(0.0774f, e) &&
386 487 color_space_almost_equal(0.0000f, f) &&
387 b = SkFixedToFloat(read_big_endian_int(src + 20)); 488 color_space_almost_equal(2.4000f, g)) {
388 d = -b / a; 489 outData->fNamed = SkColorSpace::kSRGB_GammaNamed;
389 break; 490 return SkGammas::Type::kNamed_Type;
390 } 491 }
391 case kGABC_ParaCurveType: 492
392 tagBytes = 12 + 16; 493 // Fail on invalid gammas.
393 if (len < tagBytes) { 494 if (SkScalarIsNaN(d)) {
394 SkColorSpacePrintf("gamma tag is too small (%d b ytes)", len); 495 return SkGammas::Type::kNone_Type;
395 return false; 496 }
396 } 497
397 498 if (d <= 0.0f) {
398 // Y = (aX + b)^g + c for X >= -b/a 499 // Y = (aX + b)^g + c for always
399 // Y = c otherwise 500 if (0.0f == a || 0.0f == g) {
400 g = SkFixedToFloat(read_big_endian_int(src + 12)); 501 SkColorSpacePrintf("A or G is zero, constant gamma function "
401 a = SkFixedToFloat(read_big_endian_int(src + 16)); 502 "is nonsense");
402 if (0.0f == a) { 503 return SkGammas::Type::kNone_Type;
403 return false; 504 }
404 } 505 }
405 506
406 b = SkFixedToFloat(read_big_endian_int(src + 20)); 507 if (d >= 1.0f) {
407 c = SkFixedToFloat(read_big_endian_int(src + 24)); 508 // Y = eX + f for always
408 d = -b / a; 509 if (0.0f == e) {
409 f = c; 510 SkColorSpacePrintf("E is zero, constant gamma function is "
410 break; 511 "nonsense");
411 case kGABDE_ParaCurveType: 512 return SkGammas::Type::kNone_Type;
412 tagBytes = 12 + 20; 513 }
413 if (len < tagBytes) { 514 }
414 SkColorSpacePrintf("gamma tag is too small (%d b ytes)", len); 515
415 return false; 516 if ((0.0f == a || 0.0f == g) && 0.0f == e) {
416 } 517 SkColorSpacePrintf("A or G, and E are zero, constant gamma funct ion "
417 518 "is nonsense");
418 // Y = (aX + b)^g for X >= d 519 return SkGammas::Type::kNone_Type;
419 // Y = cX otherwise 520 }
420 g = SkFixedToFloat(read_big_endian_int(src + 12)); 521
421 a = SkFixedToFloat(read_big_endian_int(src + 16)); 522 *outTagBytes = tagBytes;
422 b = SkFixedToFloat(read_big_endian_int(src + 20)); 523
423 d = SkFixedToFloat(read_big_endian_int(src + 28)); 524 outParams->fG = g;
424 e = SkFixedToFloat(read_big_endian_int(src + 24)); 525 outParams->fA = a;
425 break; 526 outParams->fB = b;
426 case kGABCDEF_ParaCurveType: 527 outParams->fC = c;
427 tagBytes = 12 + 28; 528 outParams->fD = d;
428 if (len < tagBytes) { 529 outParams->fE = e;
429 SkColorSpacePrintf("gamma tag is too small (%d b ytes)", len); 530 outParams->fF = f;
430 return false; 531 return SkGammas::Type::kParam_Type;
431 }
432
433 // Y = (aX + b)^g + c for X >= d
434 // Y = eX + f otherwise
435 // NOTE: The ICC spec writes "cX" in place of "eX" b ut I think
436 // it's a typo.
437 g = SkFixedToFloat(read_big_endian_int(src + 12));
438 a = SkFixedToFloat(read_big_endian_int(src + 16));
439 b = SkFixedToFloat(read_big_endian_int(src + 20));
440 c = SkFixedToFloat(read_big_endian_int(src + 24));
441 d = SkFixedToFloat(read_big_endian_int(src + 28));
442 e = SkFixedToFloat(read_big_endian_int(src + 32));
443 f = SkFixedToFloat(read_big_endian_int(src + 36));
444 break;
445 default:
446 SkColorSpacePrintf("Invalid parametric curve type\n" );
447 return false;
448 }
449
450 // Recognize and simplify a very common parametric represent ation of sRGB gamma.
451 if (color_space_almost_equal(0.9479f, a) &&
452 color_space_almost_equal(0.0521f, b) &&
453 color_space_almost_equal(0.0000f, c) &&
454 color_space_almost_equal(0.0405f, d) &&
455 color_space_almost_equal(0.0774f, e) &&
456 color_space_almost_equal(0.0000f, f) &&
457 color_space_almost_equal(2.4000f, g)) {
458 gammas[i].fNamed = SkColorSpace::kSRGB_GammaNamed;
459 } else {
460 // Fail on invalid gammas.
461 if (d <= 0.0f) {
462 // Y = (aX + b)^g + c for always
463 if (0.0f == a || 0.0f == g) {
464 SkColorSpacePrintf("A or G is zero, constant gam ma function "
465 "is nonsense");
466 return false;
467 }
468 } else if (d >= 1.0f) {
469 // Y = eX + f for always
470 if (0.0f == e) {
471 SkColorSpacePrintf("E is zero, constant gamma fu nction is "
472 "nonsense");
473 return false;
474 }
475 } else if ((0.0f == a || 0.0f == g) && 0.0f == e) {
476 SkColorSpacePrintf("A or G, and E are zero, constant gamma function "
477 "is nonsense");
478 return false;
479 }
480
481 gammas[i].fG = g;
482 gammas[i].fA = a;
483 gammas[i].fB = b;
484 gammas[i].fC = c;
485 gammas[i].fD = d;
486 gammas[i].fE = e;
487 gammas[i].fF = f;
488 }
489 }
490
491 break;
492 }
493 default:
494 SkColorSpacePrintf("Unsupported gamma tag type %d\n", type);
495 return false;
496 } 532 }
497 533 default:
498 // Ensure that we have successfully read a gamma representation. 534 SkColorSpacePrintf("Unsupported gamma tag type %d\n", type);
499 SkASSERT(gammas[i].isNamed() || gammas[i].isValue() || gammas[i].isTable () || 535 return SkGammas::Type::kNone_Type;
500 gammas[i].isParametric()); 536 }
501 537 }
502 // Adjust src and len if there is another gamma curve to load. 538
503 if (i != numGammas - 1) { 539 /**
504 // Each curve is padded to 4-byte alignment. 540 * Returns the additional size in bytes needed to store the gamma tag.
505 tagBytes = SkAlign4(tagBytes); 541 */
506 if (len < tagBytes) { 542 static size_t gamma_alloc_size(SkGammas::Type type, const SkGammas::Data& data) {
507 return false; 543 switch (type) {
508 } 544 case SkGammas::Type::kNamed_Type:
509 545 case SkGammas::Type::kValue_Type:
510 src += tagBytes; 546 return 0;
511 len -= tagBytes; 547 case SkGammas::Type::kTable_Type:
548 return sizeof(float) * data.fTable.fSize;
549 case SkGammas::Type::kParam_Type:
550 return sizeof(SkGammas::Params);
551 default:
552 SkASSERT(false);
553 return 0;
554 }
555 }
556
557 /**
558 * Sets invalid gamma to the default value.
559 */
560 static void handle_invalid_gamma(SkGammas::Type* type, SkGammas::Data* data) {
561 if (SkGammas::Type::kNone_Type == *type) {
562 *type = SkGammas::Type::kNamed_Type;
563 data->fNamed = SkColorSpace::kSRGB_GammaNamed;
564 }
565 }
566
567 /**
568 * Finish loading the gammas, now that we have allocated memory for the SkGamma s struct.
569 *
570 * There's nothing to do for the simple cases, but for table gammas we need to actually
571 * read the table into heap memory. And for parametric gammas, we need to copy over the
572 * parameter values.
573 *
574 * @param memory Pointer to start of the SkGammas memory block
575 * @param offset Bytes of memory (after the SkGammas struct) that are already i n use.
576 * @param data In-out variable. Will fill in the offset to the table or para meters
577 * if necessary.
578 * @param params Parameters for gamma curve. Only initialized/used when we hav e a
579 * parametric gamma.
580 * @param src Pointer to start of the gamma tag.
581 *
582 * @return Additional bytes of memory that are being used by this gamma c urve.
583 */
584 static size_t load_gammas(void* memory, size_t offset, SkGammas::Type type,
585 SkGammas::Data* data, const SkGammas::Params& params,
586 const uint8_t* src) {
587 void* storage = SkTAddOffset<void>(memory, offset + sizeof(SkGammas));
588
589 switch (type) {
590 case SkGammas::Type::kNamed_Type:
591 case SkGammas::Type::kValue_Type:
592 // Nothing to do here.
593 return 0;
594 case SkGammas::Type::kTable_Type: {
595 data->fTable.fOffset = offset;
596
597 float* outTable = (float*) storage;
598 const uint16_t* inTable = (const uint16_t*) (src + 12);
599 for (int i = 0; i < data->fTable.fSize; i++) {
600 outTable[i] = (read_big_endian_short((const uint8_t*) &inTable[i ])) / 65535.0f;
601 }
602
603 return sizeof(float) * data->fTable.fSize;
512 } 604 }
513 } 605 case SkGammas::Type::kParam_Type:
514 606 data->fTable.fOffset = offset;
515 return true; 607 memcpy(storage, &params, sizeof(SkGammas::Params));
608 return sizeof(SkGammas::Params);
609 default:
610 SkASSERT(false);
611 return 0;
612 }
516 } 613 }
517 614
518 static constexpr uint32_t kTAG_AtoBType = SkSetFourByteTag('m', 'A', 'B', ' '); 615 static constexpr uint32_t kTAG_AtoBType = SkSetFourByteTag('m', 'A', 'B', ' ');
519 616
520 bool load_color_lut(SkColorLookUpTable* colorLUT, uint32_t inputChannels, uint32 _t outputChannels, 617 static bool load_color_lut(SkColorLookUpTable* colorLUT, uint32_t inputChannels,
521 const uint8_t* src, size_t len) { 618 uint32_t outputChannels, const uint8_t* src, size_t l en) {
522 // 16 bytes reserved for grid points, 2 for precision, 2 for padding. 619 // 16 bytes reserved for grid points, 2 for precision, 2 for padding.
523 // The color LUT data follows after this header. 620 // The color LUT data follows after this header.
524 static constexpr uint32_t kColorLUTHeaderSize = 20; 621 static constexpr uint32_t kColorLUTHeaderSize = 20;
525 if (len < kColorLUTHeaderSize) { 622 if (len < kColorLUTHeaderSize) {
526 SkColorSpacePrintf("Color LUT tag is too small (%d bytes).", len); 623 SkColorSpacePrintf("Color LUT tag is too small (%d bytes).", len);
527 return false; 624 return false;
528 } 625 }
529 size_t dataLen = len - kColorLUTHeaderSize; 626 size_t dataLen = len - kColorLUTHeaderSize;
530 627
531 SkASSERT(3 == inputChannels && 3 == outputChannels); 628 SkASSERT(3 == inputChannels && 3 == outputChannels);
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
580 if (1 == precision) { 677 if (1 == precision) {
581 colorLUT->fTable[i] = ((float) ptr[i]) / 255.0f; 678 colorLUT->fTable[i] = ((float) ptr[i]) / 255.0f;
582 } else { 679 } else {
583 colorLUT->fTable[i] = ((float) read_big_endian_short(ptr)) / 65535.0 f; 680 colorLUT->fTable[i] = ((float) read_big_endian_short(ptr)) / 65535.0 f;
584 } 681 }
585 } 682 }
586 683
587 return true; 684 return true;
588 } 685 }
589 686
590 bool load_matrix(SkMatrix44* toXYZ, const uint8_t* src, size_t len) { 687 static bool load_matrix(SkMatrix44* toXYZ, const uint8_t* src, size_t len) {
591 if (len < 48) { 688 if (len < 48) {
592 SkColorSpacePrintf("Matrix tag is too small (%d bytes).", len); 689 SkColorSpacePrintf("Matrix tag is too small (%d bytes).", len);
593 return false; 690 return false;
594 } 691 }
595 692
596 // For this matrix to behave like our "to XYZ D50" matrices, it needs to be scaled. 693 // For this matrix to behave like our "to XYZ D50" matrices, it needs to be scaled.
597 constexpr float scale = 65535.0 / 32768.0; 694 constexpr float scale = 65535.0 / 32768.0;
598 float array[16]; 695 float array[16];
599 array[ 0] = scale * SkFixedToFloat(read_big_endian_int(src)); 696 array[ 0] = scale * SkFixedToFloat(read_big_endian_int(src));
600 array[ 1] = scale * SkFixedToFloat(read_big_endian_int(src + 4)); 697 array[ 1] = scale * SkFixedToFloat(read_big_endian_int(src + 4));
601 array[ 2] = scale * SkFixedToFloat(read_big_endian_int(src + 8)); 698 array[ 2] = scale * SkFixedToFloat(read_big_endian_int(src + 8));
602 array[ 3] = scale * SkFixedToFloat(read_big_endian_int(src + 36)); // transl ate R 699 array[ 3] = scale * SkFixedToFloat(read_big_endian_int(src + 36)); // transl ate R
603 array[ 4] = scale * SkFixedToFloat(read_big_endian_int(src + 12)); 700 array[ 4] = scale * SkFixedToFloat(read_big_endian_int(src + 12));
604 array[ 5] = scale * SkFixedToFloat(read_big_endian_int(src + 16)); 701 array[ 5] = scale * SkFixedToFloat(read_big_endian_int(src + 16));
605 array[ 6] = scale * SkFixedToFloat(read_big_endian_int(src + 20)); 702 array[ 6] = scale * SkFixedToFloat(read_big_endian_int(src + 20));
606 array[ 7] = scale * SkFixedToFloat(read_big_endian_int(src + 40)); // transl ate G 703 array[ 7] = scale * SkFixedToFloat(read_big_endian_int(src + 40)); // transl ate G
607 array[ 8] = scale * SkFixedToFloat(read_big_endian_int(src + 24)); 704 array[ 8] = scale * SkFixedToFloat(read_big_endian_int(src + 24));
608 array[ 9] = scale * SkFixedToFloat(read_big_endian_int(src + 28)); 705 array[ 9] = scale * SkFixedToFloat(read_big_endian_int(src + 28));
609 array[10] = scale * SkFixedToFloat(read_big_endian_int(src + 32)); 706 array[10] = scale * SkFixedToFloat(read_big_endian_int(src + 32));
610 array[11] = scale * SkFixedToFloat(read_big_endian_int(src + 44)); // transl ate B 707 array[11] = scale * SkFixedToFloat(read_big_endian_int(src + 44)); // transl ate B
611 array[12] = 0.0f; 708 array[12] = 0.0f;
612 array[13] = 0.0f; 709 array[13] = 0.0f;
613 array[14] = 0.0f; 710 array[14] = 0.0f;
614 array[15] = 1.0f; 711 array[15] = 1.0f;
615 toXYZ->setColMajorf(array); 712 toXYZ->setColMajorf(array);
616 return true; 713 return true;
617 } 714 }
618 715
619 bool load_a2b0(SkColorLookUpTable* colorLUT, SkGammaCurve* gammas, SkMatrix44* t oXYZ, 716 static bool load_a2b0(SkColorLookUpTable* colorLUT, SkColorSpace::GammaNamed* ga mmaNamed,
620 const uint8_t* src, size_t len) { 717 sk_sp<SkGammas>* gammas, SkMatrix44* toXYZ, const uint8_t* src, size_t len) {
621 if (len < 32) { 718 if (len < 32) {
622 SkColorSpacePrintf("A to B tag is too small (%d bytes).", len); 719 SkColorSpacePrintf("A to B tag is too small (%d bytes).", len);
623 return false; 720 return false;
624 } 721 }
625 722
626 uint32_t type = read_big_endian_uint(src); 723 uint32_t type = read_big_endian_uint(src);
627 if (kTAG_AtoBType != type) { 724 if (kTAG_AtoBType != type) {
628 // FIXME (msarett): Need to support lut8Type and lut16Type. 725 // FIXME (msarett): Need to support lut8Type and lut16Type.
629 SkColorSpacePrintf("Unsupported A to B tag type.\n"); 726 SkColorSpacePrintf("Unsupported A to B tag type.\n");
630 return false; 727 return false;
(...skipping 27 matching lines...) Expand all
658 uint32_t offsetToColorLUT = read_big_endian_int(src + 24); 755 uint32_t offsetToColorLUT = read_big_endian_int(src + 24);
659 if (0 != offsetToColorLUT && offsetToColorLUT < len) { 756 if (0 != offsetToColorLUT && offsetToColorLUT < len) {
660 if (!load_color_lut(colorLUT, inputChannels, outputChannels, src + offse tToColorLUT, 757 if (!load_color_lut(colorLUT, inputChannels, outputChannels, src + offse tToColorLUT,
661 len - offsetToColorLUT)) { 758 len - offsetToColorLUT)) {
662 SkColorSpacePrintf("Failed to read color LUT from A to B tag.\n"); 759 SkColorSpacePrintf("Failed to read color LUT from A to B tag.\n");
663 } 760 }
664 } 761 }
665 762
666 uint32_t offsetToMCurves = read_big_endian_int(src + 20); 763 uint32_t offsetToMCurves = read_big_endian_int(src + 20);
667 if (0 != offsetToMCurves && offsetToMCurves < len) { 764 if (0 != offsetToMCurves && offsetToMCurves < len) {
668 if (!load_gammas(gammas, outputChannels, src + offsetToMCurves, len - of fsetToMCurves)) { 765 const uint8_t* rTagPtr = src + offsetToMCurves;
669 SkColorSpacePrintf("Failed to read M curves from A to B tag. Using linear gamma.\n"); 766 size_t tagLen = len - offsetToMCurves;
670 gammas[0].fNamed = SkColorSpace::kLinear_GammaNamed; 767
671 gammas[1].fNamed = SkColorSpace::kLinear_GammaNamed; 768 SkGammas::Data rData;
672 gammas[2].fNamed = SkColorSpace::kLinear_GammaNamed; 769 SkGammas::Params rParams;
770
771 // On an invalid first gamma, tagBytes remains set as zero. This causes the two
772 // subsequent to be treated as identical (which is what we want).
773 size_t tagBytes = 0;
774 SkGammas::Type rType = parse_gamma(&rData, &rParams, &tagBytes, rTagPtr, tagLen);
775 handle_invalid_gamma(&rType, &rData);
776 size_t alignedTagBytes = SkAlign4(tagBytes);
777
778 if ((3 * alignedTagBytes <= tagLen) &&
779 !memcmp(rTagPtr, rTagPtr + 1 * alignedTagBytes, tagBytes) &&
780 !memcmp(rTagPtr, rTagPtr + 2 * alignedTagBytes, tagBytes))
781 {
782 if (SkGammas::Type::kNamed_Type == rType) {
783 *gammaNamed = rData.fNamed;
784 } else {
785 size_t allocSize = sizeof(SkGammas) + gamma_alloc_size(rType, rD ata);
786 void* memory = sk_malloc_throw(allocSize);
787 *gammas = sk_sp<SkGammas>(new (memory) SkGammas());
788 load_gammas(memory, 0, rType, &rData, rParams, rTagPtr);
789
790 (*gammas)->fRedType = rType;
791 (*gammas)->fGreenType = rType;
792 (*gammas)->fBlueType = rType;
793
794 (*gammas)->fRedData = rData;
795 (*gammas)->fGreenData = rData;
796 (*gammas)->fBlueData = rData;
797 }
798 } else {
799 const uint8_t* gTagPtr = rTagPtr + alignedTagBytes;
800 tagLen = tagLen > alignedTagBytes ? tagLen - alignedTagBytes : 0;
801 SkGammas::Data gData;
802 SkGammas::Params gParams;
803 tagBytes = 0;
804 SkGammas::Type gType = parse_gamma(&gData, &gParams, &tagBytes, gTag Ptr,
805 tagLen);
806 handle_invalid_gamma(&gType, &gData);
807
808 alignedTagBytes = SkAlign4(tagBytes);
809 const uint8_t* bTagPtr = gTagPtr + alignedTagBytes;
810 tagLen = tagLen > alignedTagBytes ? tagLen - alignedTagBytes : 0;
811 SkGammas::Data bData;
812 SkGammas::Params bParams;
813 SkGammas::Type bType = parse_gamma(&bData, &bParams, &tagBytes, bTag Ptr,
814 tagLen);
815 handle_invalid_gamma(&bType, &bData);
816
817 size_t allocSize = sizeof(SkGammas) + gamma_alloc_size(rType, rData)
818 + gamma_alloc_size(gType, gData)
819 + gamma_alloc_size(bType, bData) ;
820 void* memory = sk_malloc_throw(allocSize);
821 *gammas = sk_sp<SkGammas>(new (memory) SkGammas());
822
823 uint32_t offset = 0;
824 (*gammas)->fRedType = rType;
825 offset += load_gammas(memory, offset, rType, &rData, rParams, rTagPt r);
826
827 (*gammas)->fGreenType = gType;
828 offset += load_gammas(memory, offset, gType, &gData, gParams, gTagPt r);
829
830 (*gammas)->fBlueType = bType;
831 load_gammas(memory, offset, bType, &bData, bParams, bTagPtr);
832
833 (*gammas)->fRedData = rData;
834 (*gammas)->fGreenData = gData;
835 (*gammas)->fBlueData = bData;
673 } 836 }
674 } 837 }
675 838
676 uint32_t offsetToMatrix = read_big_endian_int(src + 16); 839 uint32_t offsetToMatrix = read_big_endian_int(src + 16);
677 if (0 != offsetToMatrix && offsetToMatrix < len) { 840 if (0 != offsetToMatrix && offsetToMatrix < len) {
678 if (!load_matrix(toXYZ, src + offsetToMatrix, len - offsetToMatrix)) { 841 if (!load_matrix(toXYZ, src + offsetToMatrix, len - offsetToMatrix)) {
679 SkColorSpacePrintf("Failed to read matrix from A to B tag.\n"); 842 SkColorSpacePrintf("Failed to read matrix from A to B tag.\n");
680 toXYZ->setIdentity(); 843 toXYZ->setIdentity();
681 } 844 }
682 } 845 }
683 846
684 return true; 847 return true;
685 } 848 }
686 849
850 static bool tag_equals(const ICCTag* a, const ICCTag* b, const uint8_t* base) {
851 if (!a || !b) {
852 return a == b;
853 }
854
855 if (a->fLength != b->fLength) {
856 return false;
857 }
858
859 if (a->fOffset == b->fOffset) {
860 return true;
861 }
862
863 return !memcmp(a->addr(base), b->addr(base), a->fLength);
864 }
865
687 sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* input, size_t len) { 866 sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* input, size_t len) {
688 if (!input || len < kICCHeaderSize) { 867 if (!input || len < kICCHeaderSize) {
689 return_null("Data is null or not large enough to contain an ICC profile" ); 868 return_null("Data is null or not large enough to contain an ICC profile" );
690 } 869 }
691 870
692 // Create our own copy of the input. 871 // Create our own copy of the input.
693 void* memory = sk_malloc_throw(len); 872 void* memory = sk_malloc_throw(len);
694 memcpy(memory, input, len); 873 memcpy(memory, input, len);
695 sk_sp<SkData> data = SkData::MakeFromMalloc(memory, len); 874 sk_sp<SkData> data = SkData::MakeFromMalloc(memory, len);
696 const void* base = data->data(); 875 const uint8_t* base = data->bytes();
697 const uint8_t* ptr = (const uint8_t*) base; 876 const uint8_t* ptr = base;
698 877
699 // Read the ICC profile header and check to make sure that it is valid. 878 // Read the ICC profile header and check to make sure that it is valid.
700 ICCProfileHeader header; 879 ICCProfileHeader header;
701 header.init(ptr, len); 880 header.init(ptr, len);
702 if (!header.valid()) { 881 if (!header.valid()) {
703 return nullptr; 882 return nullptr;
704 } 883 }
705 884
706 // Adjust ptr and len before reading the tags. 885 // Adjust ptr and len before reading the tags.
707 if (len < header.fSize) { 886 if (len < header.fSize) {
(...skipping 25 matching lines...) Expand all
733 } 912 }
734 913
735 switch (header.fInputColorSpace) { 914 switch (header.fInputColorSpace) {
736 case kRGB_ColorSpace: { 915 case kRGB_ColorSpace: {
737 // Recognize the rXYZ, gXYZ, and bXYZ tags. 916 // Recognize the rXYZ, gXYZ, and bXYZ tags.
738 const ICCTag* r = ICCTag::Find(tags.get(), tagCount, kTAG_rXYZ); 917 const ICCTag* r = ICCTag::Find(tags.get(), tagCount, kTAG_rXYZ);
739 const ICCTag* g = ICCTag::Find(tags.get(), tagCount, kTAG_gXYZ); 918 const ICCTag* g = ICCTag::Find(tags.get(), tagCount, kTAG_gXYZ);
740 const ICCTag* b = ICCTag::Find(tags.get(), tagCount, kTAG_bXYZ); 919 const ICCTag* b = ICCTag::Find(tags.get(), tagCount, kTAG_bXYZ);
741 if (r && g && b) { 920 if (r && g && b) {
742 float toXYZ[9]; 921 float toXYZ[9];
743 if (!load_xyz(&toXYZ[0], r->addr((const uint8_t*) base), r->fLen gth) || 922 if (!load_xyz(&toXYZ[0], r->addr(base), r->fLength) ||
744 !load_xyz(&toXYZ[3], g->addr((const uint8_t*) base), g->fLen gth) || 923 !load_xyz(&toXYZ[3], g->addr(base), g->fLength) ||
745 !load_xyz(&toXYZ[6], b->addr((const uint8_t*) base), b->fLen gth)) 924 !load_xyz(&toXYZ[6], b->addr(base), b->fLength))
746 { 925 {
747 return_null("Need valid rgb tags for XYZ space"); 926 return_null("Need valid rgb tags for XYZ space");
748 } 927 }
749 SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor); 928 SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor);
750 mat.set3x3RowMajorf(toXYZ); 929 mat.set3x3RowMajorf(toXYZ);
751 930
752 // It is not uncommon to see missing or empty gamma tags. This indicates
753 // that we should use unit gamma.
754 SkGammaCurve curves[3];
755 r = ICCTag::Find(tags.get(), tagCount, kTAG_rTRC); 931 r = ICCTag::Find(tags.get(), tagCount, kTAG_rTRC);
756 g = ICCTag::Find(tags.get(), tagCount, kTAG_gTRC); 932 g = ICCTag::Find(tags.get(), tagCount, kTAG_gTRC);
757 b = ICCTag::Find(tags.get(), tagCount, kTAG_bTRC); 933 b = ICCTag::Find(tags.get(), tagCount, kTAG_bTRC);
758 if (!r || !load_gammas(&curves[0], 1, r->addr((const uint8_t*) b ase), r->fLength)) 934
759 { 935 // If some, but not all, of the gamma tags are missing, assume t hat all
760 SkColorSpacePrintf("Failed to read R gamma tag.\n"); 936 // gammas are meant to be the same. This behavior is an arbitra ry guess,
761 curves[0].fNamed = SkColorSpace::kLinear_GammaNamed; 937 // but it simplifies the code below.
762 } 938 if ((!r || !g || !b) && (r || g || b)) {
763 if (!g || !load_gammas(&curves[1], 1, g->addr((const uint8_t*) b ase), g->fLength)) 939 if (!r) {
764 { 940 r = g ? g : b;
765 SkColorSpacePrintf("Failed to read G gamma tag.\n"); 941 }
766 curves[1].fNamed = SkColorSpace::kLinear_GammaNamed; 942
767 } 943 if (!g) {
768 if (!b || !load_gammas(&curves[2], 1, b->addr((const uint8_t*) b ase), b->fLength)) 944 g = r ? r : b;
769 { 945 }
770 SkColorSpacePrintf("Failed to read B gamma tag.\n"); 946
771 curves[2].fNamed = SkColorSpace::kLinear_GammaNamed; 947 if (!b) {
948 b = r ? r : g;
949 }
772 } 950 }
773 951
774 GammaNamed gammaNamed = SkGammas::Named(curves); 952 GammaNamed gammaNamed = kNonStandard_GammaNamed;
953 sk_sp<SkGammas> gammas = nullptr;
954 size_t tagBytes;
955 if (r && g && b) {
956 if (tag_equals(r, g, base) && tag_equals(g, b, base)) {
957 SkGammas::Data data;
958 SkGammas::Params params;
959 SkGammas::Type Type =
960 parse_gamma(&data, &params, &tagBytes, r->addr(b ase), r->fLength);
961 handle_invalid_gamma(&Type, &data);
962
963 if (SkGammas::Type::kNamed_Type == Type) {
964 gammaNamed = data.fNamed;
965 } else {
966 size_t allocSize = sizeof(SkGammas) + gamma_alloc_si ze(Type, data);
967 void* memory = sk_malloc_throw(allocSize);
968 gammas = sk_sp<SkGammas>(new (memory) SkGammas());
969 load_gammas(memory, 0, Type, &data, params, r->addr( base));
970
971 gammas->fRedType = Type;
972 gammas->fGreenType = Type;
973 gammas->fBlueType = Type;
974
975 gammas->fRedData = data;
976 gammas->fGreenData = data;
977 gammas->fBlueData = data;
978 }
979 } else {
980 SkGammas::Data rData;
981 SkGammas::Params rParams;
982 SkGammas::Type rType =
983 parse_gamma(&rData, &rParams, &tagBytes, r->addr (base), r->fLength);
984 handle_invalid_gamma(&rType, &rData);
985
986 SkGammas::Data gData;
987 SkGammas::Params gParams;
988 SkGammas::Type gType =
989 parse_gamma(&gData, &gParams, &tagBytes, g->addr (base), g->fLength);
990 handle_invalid_gamma(&gType, &gData);
991
992 SkGammas::Data bData;
993 SkGammas::Params bParams;
994 SkGammas::Type bType =
995 parse_gamma(&bData, &bParams, &tagBytes, b->addr (base), b->fLength);
996 handle_invalid_gamma(&bType, &bData);
997
998 size_t allocSize = sizeof(SkGammas) + gamma_alloc_size(r Type, rData)
999 + gamma_alloc_size(g Type, gData)
1000 + gamma_alloc_size(b Type, bData);
1001 void* memory = sk_malloc_throw(allocSize);
1002 gammas = sk_sp<SkGammas>(new (memory) SkGammas());
1003
1004 uint32_t offset = 0;
1005 gammas->fRedType = rType;
1006 offset += load_gammas(memory, offset, rType, &rData, rPa rams,
1007 r->addr(base));
1008
1009 gammas->fGreenType = gType;
1010 offset += load_gammas(memory, offset, gType, &gData, gPa rams,
1011 g->addr(base));
1012
1013 gammas->fBlueType = bType;
1014 load_gammas(memory, offset, bType, &bData, bParams, b->a ddr(base));
1015
1016 gammas->fRedData = rData;
1017 gammas->fGreenData = gData;
1018 gammas->fBlueData = bData;
1019 }
1020 } else {
1021 gammaNamed = kLinear_GammaNamed;
1022 }
1023
775 if (kNonStandard_GammaNamed == gammaNamed) { 1024 if (kNonStandard_GammaNamed == gammaNamed) {
776 sk_sp<SkGammas> gammas = sk_make_sp<SkGammas>(std::move(curv es[0]), 1025 return sk_sp<SkColorSpace>(new SkColorSpace_Base(nullptr, ga mmaNamed,
777 std::move(curv es[1]), 1026 std::move(g ammas), mat,
778 std::move(curv es[2])); 1027 std::move(d ata)));
779 return sk_sp<SkColorSpace>(new SkColorSpace_Base(nullptr, st d::move(gammas),
780 mat, std::m ove(data)));
781 } else { 1028 } else {
782 return SkColorSpace_Base::NewRGB(gammaNamed, mat); 1029 return SkColorSpace_Base::NewRGB(gammaNamed, mat);
783 } 1030 }
784 } 1031 }
785 1032
786 // Recognize color profile specified by A2B0 tag. 1033 // Recognize color profile specified by A2B0 tag.
787 const ICCTag* a2b0 = ICCTag::Find(tags.get(), tagCount, kTAG_A2B0); 1034 const ICCTag* a2b0 = ICCTag::Find(tags.get(), tagCount, kTAG_A2B0);
788 if (a2b0) { 1035 if (a2b0) {
1036 GammaNamed gammaNamed = kNonStandard_GammaNamed;
1037 sk_sp<SkGammas> gammas = nullptr;
789 sk_sp<SkColorLookUpTable> colorLUT = sk_make_sp<SkColorLookUpTab le>(); 1038 sk_sp<SkColorLookUpTable> colorLUT = sk_make_sp<SkColorLookUpTab le>();
790 SkGammaCurve curves[3];
791 SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor); 1039 SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor);
792 if (!load_a2b0(colorLUT.get(), curves, &toXYZ, a2b0->addr((const uint8_t*) base), 1040 if (!load_a2b0(colorLUT.get(), &gammaNamed, &gammas, &toXYZ, a2b 0->addr(base),
793 a2b0->fLength)) { 1041 a2b0->fLength)) {
794 return_null("Failed to parse A2B0 tag"); 1042 return_null("Failed to parse A2B0 tag");
795 } 1043 }
796 1044
797 GammaNamed gammaNamed = SkGammas::Named(curves);
798 colorLUT = colorLUT->fTable ? colorLUT : nullptr; 1045 colorLUT = colorLUT->fTable ? colorLUT : nullptr;
799 if (colorLUT || kNonStandard_GammaNamed == gammaNamed) { 1046 if (colorLUT || kNonStandard_GammaNamed == gammaNamed) {
800 sk_sp<SkGammas> gammas = sk_make_sp<SkGammas>(std::move(curv es[0]),
801 std::move(curv es[1]),
802 std::move(curv es[2]));
803
804 return sk_sp<SkColorSpace>(new SkColorSpace_Base(std::move(c olorLUT), 1047 return sk_sp<SkColorSpace>(new SkColorSpace_Base(std::move(c olorLUT),
805 std::move(g ammas), toXYZ, 1048 gammaNamed, std::move(gammas),
806 std::move(d ata))); 1049 toXYZ, std: :move(data)));
807 } else { 1050 } else {
808 return SkColorSpace_Base::NewRGB(gammaNamed, toXYZ); 1051 return SkColorSpace_Base::NewRGB(gammaNamed, toXYZ);
809 } 1052 }
810 } 1053 }
811 } 1054 }
812 default: 1055 default:
813 break; 1056 break;
814 } 1057 }
815 1058
816 return_null("ICC profile contains unsupported colorspace"); 1059 return_null("ICC profile contains unsupported colorspace");
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
938 ptr[2] = SkEndian_SwapBE32(1); 1181 ptr[2] = SkEndian_SwapBE32(1);
939 1182
940 // Convert gamma to 16-bit fixed point. 1183 // Convert gamma to 16-bit fixed point.
941 uint16_t* ptr16 = (uint16_t*) (ptr + 3); 1184 uint16_t* ptr16 = (uint16_t*) (ptr + 3);
942 ptr16[0] = SkEndian_SwapBE16((uint16_t) (value * 256.0f)); 1185 ptr16[0] = SkEndian_SwapBE16((uint16_t) (value * 256.0f));
943 1186
944 // Pad tag with zero. 1187 // Pad tag with zero.
945 ptr16[1] = 0; 1188 ptr16[1] = 0;
946 } 1189 }
947 1190
948 static float get_gamma_value(const SkGammaCurve* curve) {
949 switch (curve->fNamed) {
950 case SkColorSpace::kSRGB_GammaNamed:
951 // FIXME (msarett):
952 // kSRGB cannot be represented by a value. Here we fall through to 2.2f,
953 // which is a close guess. To be more accurate, we need to represen t sRGB
954 // gamma with a parametric curve.
955 case SkColorSpace::k2Dot2Curve_GammaNamed:
956 return 2.2f;
957 case SkColorSpace::kLinear_GammaNamed:
958 return 1.0f;
959 default:
960 SkASSERT(curve->isValue());
961 return curve->fValue;
962 }
963 }
964
965 sk_sp<SkData> SkColorSpace_Base::writeToICC() const { 1191 sk_sp<SkData> SkColorSpace_Base::writeToICC() const {
966 // Return if this object was created from a profile, or if we have already s erialized 1192 // Return if this object was created from a profile, or if we have already s erialized
967 // the profile. 1193 // the profile.
968 if (fProfileData) { 1194 if (fProfileData) {
969 return fProfileData; 1195 return fProfileData;
970 } 1196 }
971 1197
972 // The client may create an SkColorSpace using an SkMatrix44, but currently we only 1198 // The client may create an SkColorSpace using an SkMatrix44, but currently we only
973 // support writing profiles with 3x3 matrices. 1199 // support writing profiles with 3x3 matrices.
974 // TODO (msarett): Fix this! 1200 // TODO (msarett): Fix this!
(...skipping 23 matching lines...) Expand all
998 write_xyz_tag((uint32_t*) ptr, fToXYZD50, 0); 1224 write_xyz_tag((uint32_t*) ptr, fToXYZD50, 0);
999 ptr += kTAG_XYZ_Bytes; 1225 ptr += kTAG_XYZ_Bytes;
1000 write_xyz_tag((uint32_t*) ptr, fToXYZD50, 1); 1226 write_xyz_tag((uint32_t*) ptr, fToXYZD50, 1);
1001 ptr += kTAG_XYZ_Bytes; 1227 ptr += kTAG_XYZ_Bytes;
1002 write_xyz_tag((uint32_t*) ptr, fToXYZD50, 2); 1228 write_xyz_tag((uint32_t*) ptr, fToXYZD50, 2);
1003 ptr += kTAG_XYZ_Bytes; 1229 ptr += kTAG_XYZ_Bytes;
1004 1230
1005 // Write TRC tags 1231 // Write TRC tags
1006 GammaNamed gammaNamed = this->gammaNamed(); 1232 GammaNamed gammaNamed = this->gammaNamed();
1007 if (kNonStandard_GammaNamed == gammaNamed) { 1233 if (kNonStandard_GammaNamed == gammaNamed) {
1008 write_trc_tag((uint32_t*) ptr, get_gamma_value(&as_CSB(this)->fGammas->f Red)); 1234 // FIXME (msarett):
1235 // Write the correct gamma representation rather than 2.2f.
1236 write_trc_tag((uint32_t*) ptr, 2.2f);
1009 ptr += SkAlign4(kTAG_TRC_Bytes); 1237 ptr += SkAlign4(kTAG_TRC_Bytes);
1010 write_trc_tag((uint32_t*) ptr, get_gamma_value(&as_CSB(this)->fGammas->f Green)); 1238 write_trc_tag((uint32_t*) ptr, 2.2f);
1011 ptr += SkAlign4(kTAG_TRC_Bytes); 1239 ptr += SkAlign4(kTAG_TRC_Bytes);
1012 write_trc_tag((uint32_t*) ptr, get_gamma_value(&as_CSB(this)->fGammas->f Blue)); 1240 write_trc_tag((uint32_t*) ptr, 2.2f);
1013 ptr += SkAlign4(kTAG_TRC_Bytes); 1241 ptr += SkAlign4(kTAG_TRC_Bytes);
1014 } else { 1242 } else {
1015 switch (gammaNamed) { 1243 switch (gammaNamed) {
1016 case SkColorSpace::kSRGB_GammaNamed: 1244 case SkColorSpace::kSRGB_GammaNamed:
1017 // FIXME (msarett): 1245 // FIXME (msarett):
1018 // kSRGB cannot be represented by a value. Here we fall through to 2.2f, 1246 // kSRGB cannot be represented by a value. Here we fall through to 2.2f,
1019 // which is a close guess. To be more accurate, we need to repr esent sRGB 1247 // which is a close guess. To be more accurate, we need to repr esent sRGB
1020 // gamma with a parametric curve. 1248 // gamma with a parametric curve.
1021 case SkColorSpace::k2Dot2Curve_GammaNamed: 1249 case SkColorSpace::k2Dot2Curve_GammaNamed:
1022 write_trc_tag((uint32_t*) ptr, 2.2f); 1250 write_trc_tag((uint32_t*) ptr, 2.2f);
(...skipping 28 matching lines...) Expand all
1051 ptr32[4] = SkEndian_SwapBE32(0x000116cc); 1279 ptr32[4] = SkEndian_SwapBE32(0x000116cc);
1052 ptr += kTAG_XYZ_Bytes; 1280 ptr += kTAG_XYZ_Bytes;
1053 1281
1054 // Write copyright tag 1282 // Write copyright tag
1055 memcpy(ptr, gEmptyTextTag, sizeof(gEmptyTextTag)); 1283 memcpy(ptr, gEmptyTextTag, sizeof(gEmptyTextTag));
1056 1284
1057 // TODO (msarett): Should we try to hold onto the data so we can return imme diately if 1285 // TODO (msarett): Should we try to hold onto the data so we can return imme diately if
1058 // the client calls again? 1286 // the client calls again?
1059 return SkData::MakeFromMalloc(profile.release(), kICCProfileSize); 1287 return SkData::MakeFromMalloc(profile.release(), kICCProfileSize);
1060 } 1288 }
OLDNEW
« no previous file with comments | « src/core/SkColorSpace_Base.h ('k') | tests/ColorSpaceXformTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698