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

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

Issue 2409383002: Add SkColorSpaceTransferFn to SkColorSpace (Closed)
Patch Set: Add more comments Created 4 years, 2 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/ColorSpaceTest.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 256 matching lines...) Expand 10 before | Expand all | Expand 10 after
267 * parametric gamma, it is the responsibility of the caller to set 267 * parametric gamma, it is the responsibility of the caller to set
268 * fOffset. 268 * fOffset.
269 * @param outParams If this is a parametric gamma, this is set to the appropr iate 269 * @param outParams If this is a parametric gamma, this is set to the appropr iate
270 * parameters on success. 270 * parameters on success.
271 * @param outTagBytes Will be set to the length of the tag on success. 271 * @param outTagBytes Will be set to the length of the tag on success.
272 * @src Pointer to tag data. 272 * @src Pointer to tag data.
273 * @len Length of tag data in bytes. 273 * @len Length of tag data in bytes.
274 * 274 *
275 * @return kNone_Type on failure, otherwise the type of the gamma ta g. 275 * @return kNone_Type on failure, otherwise the type of the gamma ta g.
276 */ 276 */
277 static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkGammas::Params* out Params, 277 static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkColorSpaceTransferF n* outParams,
278 size_t* outTagBytes, const uint8_t* src, s ize_t len) { 278 size_t* outTagBytes, const uint8_t* src, size_ t len) {
279 if (len < 12) { 279 if (len < 12) {
280 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); 280 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len);
281 return SkGammas::Type::kNone_Type; 281 return SkGammas::Type::kNone_Type;
282 } 282 }
283 283
284 // In the case of consecutive gamma tags, we need to count the number of byt es in the 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. 285 // tag, so that we can move on to the next tag.
286 size_t tagBytes; 286 size_t tagBytes;
287 287
288 uint32_t type = read_big_endian_u32(src); 288 uint32_t type = read_big_endian_u32(src);
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
471 c = read_big_endian_16_dot_16(src + 24); 471 c = read_big_endian_16_dot_16(src + 24);
472 d = read_big_endian_16_dot_16(src + 28); 472 d = read_big_endian_16_dot_16(src + 28);
473 e = read_big_endian_16_dot_16(src + 32); 473 e = read_big_endian_16_dot_16(src + 32);
474 f = read_big_endian_16_dot_16(src + 36); 474 f = read_big_endian_16_dot_16(src + 36);
475 break; 475 break;
476 default: 476 default:
477 SkASSERT(false); 477 SkASSERT(false);
478 return SkGammas::Type::kNone_Type; 478 return SkGammas::Type::kNone_Type;
479 } 479 }
480 480
481 // Recognize and simplify a very common parametric representation of sRGB gamma.
482 if (color_space_almost_equal(0.9479f, a) &&
483 color_space_almost_equal(0.0521f, b) &&
484 color_space_almost_equal(0.0000f, c) &&
485 color_space_almost_equal(0.0405f, d) &&
486 color_space_almost_equal(0.0774f, e) &&
487 color_space_almost_equal(0.0000f, f) &&
488 color_space_almost_equal(2.4000f, g)) {
489 outData->fNamed = kSRGB_SkGammaNamed;
490 return SkGammas::Type::kNamed_Type;
491 }
492
493 // Fail on invalid gammas.
494 if (SkScalarIsNaN(d)) {
495 return SkGammas::Type::kNone_Type;
496 }
497
498 if (d <= 0.0f) {
499 // Y = (aX + b)^g + c for always
500 if (0.0f == a || 0.0f == g) {
501 SkColorSpacePrintf("A or G is zero, constant gamma function "
502 "is nonsense");
503 return SkGammas::Type::kNone_Type;
504 }
505 }
506
507 if (d >= 1.0f) {
508 // Y = eX + f for always
509 if (0.0f == e) {
510 SkColorSpacePrintf("E is zero, constant gamma function is "
511 "nonsense");
512 return SkGammas::Type::kNone_Type;
513 }
514 }
515
516 if ((0.0f == a || 0.0f == g) && 0.0f == e) {
517 SkColorSpacePrintf("A or G, and E are zero, constant gamma funct ion "
518 "is nonsense");
519 return SkGammas::Type::kNone_Type;
520 }
521
522 *outTagBytes = tagBytes;
523
524 outParams->fG = g; 481 outParams->fG = g;
525 outParams->fA = a; 482 outParams->fA = a;
526 outParams->fB = b; 483 outParams->fB = b;
527 outParams->fC = c; 484 outParams->fC = c;
528 outParams->fD = d; 485 outParams->fD = d;
529 outParams->fE = e; 486 outParams->fE = e;
530 outParams->fF = f; 487 outParams->fF = f;
488
489 if (!is_valid_transfer_fn(*outParams)) {
490 return SkGammas::Type::kNone_Type;
491 }
492
493 if (is_almost_srgb(*outParams)) {
494 outData->fNamed = kSRGB_SkGammaNamed;
495 return SkGammas::Type::kNamed_Type;
496 }
497
498 if (is_almost_2dot2(*outParams)) {
499 outData->fNamed = k2Dot2Curve_SkGammaNamed;
500 return SkGammas::Type::kNamed_Type;
501 }
502
503 *outTagBytes = tagBytes;
531 return SkGammas::Type::kParam_Type; 504 return SkGammas::Type::kParam_Type;
532 } 505 }
533 default: 506 default:
534 SkColorSpacePrintf("Unsupported gamma tag type %d\n", type); 507 SkColorSpacePrintf("Unsupported gamma tag type %d\n", type);
535 return SkGammas::Type::kNone_Type; 508 return SkGammas::Type::kNone_Type;
536 } 509 }
537 } 510 }
538 511
539 /** 512 /**
540 * Returns the additional size in bytes needed to store the gamma tag. 513 * Returns the additional size in bytes needed to store the gamma tag.
541 */ 514 */
542 static size_t gamma_alloc_size(SkGammas::Type type, const SkGammas::Data& data) { 515 static size_t gamma_alloc_size(SkGammas::Type type, const SkGammas::Data& data) {
543 switch (type) { 516 switch (type) {
544 case SkGammas::Type::kNamed_Type: 517 case SkGammas::Type::kNamed_Type:
545 case SkGammas::Type::kValue_Type: 518 case SkGammas::Type::kValue_Type:
546 return 0; 519 return 0;
547 case SkGammas::Type::kTable_Type: 520 case SkGammas::Type::kTable_Type:
548 return sizeof(float) * data.fTable.fSize; 521 return sizeof(float) * data.fTable.fSize;
549 case SkGammas::Type::kParam_Type: 522 case SkGammas::Type::kParam_Type:
550 return sizeof(SkGammas::Params); 523 return sizeof(SkColorSpaceTransferFn);
551 default: 524 default:
552 SkASSERT(false); 525 SkASSERT(false);
553 return 0; 526 return 0;
554 } 527 }
555 } 528 }
556 529
557 /** 530 /**
558 * Sets invalid gamma to the default value. 531 * Sets invalid gamma to the default value.
559 */ 532 */
560 static void handle_invalid_gamma(SkGammas::Type* type, SkGammas::Data* data) { 533 static void handle_invalid_gamma(SkGammas::Type* type, SkGammas::Data* data) {
(...skipping 16 matching lines...) Expand all
577 * @param offset Bytes of memory (after the SkGammas struct) that are already i n use. 550 * @param offset Bytes of memory (after the SkGammas struct) that are already i n use.
578 * @param data In-out variable. Will fill in the offset to the table or para meters 551 * @param data In-out variable. Will fill in the offset to the table or para meters
579 * if necessary. 552 * if necessary.
580 * @param params Parameters for gamma curve. Only initialized/used when we hav e a 553 * @param params Parameters for gamma curve. Only initialized/used when we hav e a
581 * parametric gamma. 554 * parametric gamma.
582 * @param src Pointer to start of the gamma tag. 555 * @param src Pointer to start of the gamma tag.
583 * 556 *
584 * @return Additional bytes of memory that are being used by this gamma c urve. 557 * @return Additional bytes of memory that are being used by this gamma c urve.
585 */ 558 */
586 static size_t load_gammas(void* memory, size_t offset, SkGammas::Type type, 559 static size_t load_gammas(void* memory, size_t offset, SkGammas::Type type,
587 SkGammas::Data* data, const SkGammas::Params& params, 560 SkGammas::Data* data, const SkColorSpaceTransferFn& para ms,
588 const uint8_t* src) { 561 const uint8_t* src) {
589 void* storage = SkTAddOffset<void>(memory, offset + sizeof(SkGammas)); 562 void* storage = SkTAddOffset<void>(memory, offset + sizeof(SkGammas));
590 563
591 switch (type) { 564 switch (type) {
592 case SkGammas::Type::kNamed_Type: 565 case SkGammas::Type::kNamed_Type:
593 case SkGammas::Type::kValue_Type: 566 case SkGammas::Type::kValue_Type:
594 // Nothing to do here. 567 // Nothing to do here.
595 return 0; 568 return 0;
596 case SkGammas::Type::kTable_Type: { 569 case SkGammas::Type::kTable_Type: {
597 data->fTable.fOffset = offset; 570 data->fTable.fOffset = offset;
598 571
599 float* outTable = (float*) storage; 572 float* outTable = (float*) storage;
600 const uint16_t* inTable = (const uint16_t*) (src + 12); 573 const uint16_t* inTable = (const uint16_t*) (src + 12);
601 for (int i = 0; i < data->fTable.fSize; i++) { 574 for (int i = 0; i < data->fTable.fSize; i++) {
602 outTable[i] = (read_big_endian_u16((const uint8_t*) &inTable[i]) ) / 65535.0f; 575 outTable[i] = (read_big_endian_u16((const uint8_t*) &inTable[i]) ) / 65535.0f;
603 } 576 }
604 577
605 return sizeof(float) * data->fTable.fSize; 578 return sizeof(float) * data->fTable.fSize;
606 } 579 }
607 case SkGammas::Type::kParam_Type: 580 case SkGammas::Type::kParam_Type:
608 data->fTable.fOffset = offset; 581 data->fTable.fOffset = offset;
609 memcpy(storage, &params, sizeof(SkGammas::Params)); 582 memcpy(storage, &params, sizeof(SkColorSpaceTransferFn));
610 return sizeof(SkGammas::Params); 583 return sizeof(SkColorSpaceTransferFn);
611 default: 584 default:
612 SkASSERT(false); 585 SkASSERT(false);
613 return 0; 586 return 0;
614 } 587 }
615 } 588 }
616 589
617 static constexpr uint32_t kTAG_AtoBType = SkSetFourByteTag('m', 'A', 'B', ' '); 590 static constexpr uint32_t kTAG_AtoBType = SkSetFourByteTag('m', 'A', 'B', ' ');
618 591
619 static bool load_color_lut(sk_sp<SkColorLookUpTable>* colorLUT, uint32_t inputCh annels, 592 static bool load_color_lut(sk_sp<SkColorLookUpTable>* colorLUT, uint32_t inputCh annels,
620 const uint8_t* src, size_t len) { 593 const uint8_t* src, size_t len) {
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
778 SkColorSpacePrintf("Failed to read color LUT from A to B tag.\n"); 751 SkColorSpacePrintf("Failed to read color LUT from A to B tag.\n");
779 } 752 }
780 } 753 }
781 754
782 uint32_t offsetToMCurves = read_big_endian_i32(src + 20); 755 uint32_t offsetToMCurves = read_big_endian_i32(src + 20);
783 if (0 != offsetToMCurves && offsetToMCurves < len) { 756 if (0 != offsetToMCurves && offsetToMCurves < len) {
784 const uint8_t* rTagPtr = src + offsetToMCurves; 757 const uint8_t* rTagPtr = src + offsetToMCurves;
785 size_t tagLen = len - offsetToMCurves; 758 size_t tagLen = len - offsetToMCurves;
786 759
787 SkGammas::Data rData; 760 SkGammas::Data rData;
788 SkGammas::Params rParams; 761 SkColorSpaceTransferFn rParams;
789 762
790 // On an invalid first gamma, tagBytes remains set as zero. This causes the two 763 // On an invalid first gamma, tagBytes remains set as zero. This causes the two
791 // subsequent to be treated as identical (which is what we want). 764 // subsequent to be treated as identical (which is what we want).
792 size_t tagBytes = 0; 765 size_t tagBytes = 0;
793 SkGammas::Type rType = parse_gamma(&rData, &rParams, &tagBytes, rTagPtr, tagLen); 766 SkGammas::Type rType = parse_gamma(&rData, &rParams, &tagBytes, rTagPtr, tagLen);
794 handle_invalid_gamma(&rType, &rData); 767 handle_invalid_gamma(&rType, &rData);
795 size_t alignedTagBytes = SkAlign4(tagBytes); 768 size_t alignedTagBytes = SkAlign4(tagBytes);
796 769
797 if ((3 * alignedTagBytes <= tagLen) && 770 if ((3 * alignedTagBytes <= tagLen) &&
798 !memcmp(rTagPtr, rTagPtr + 1 * alignedTagBytes, tagBytes) && 771 !memcmp(rTagPtr, rTagPtr + 1 * alignedTagBytes, tagBytes) &&
(...skipping 14 matching lines...) Expand all
813 (*gammas)->fBlueType = rType; 786 (*gammas)->fBlueType = rType;
814 787
815 (*gammas)->fRedData = rData; 788 (*gammas)->fRedData = rData;
816 (*gammas)->fGreenData = rData; 789 (*gammas)->fGreenData = rData;
817 (*gammas)->fBlueData = rData; 790 (*gammas)->fBlueData = rData;
818 } 791 }
819 } else { 792 } else {
820 const uint8_t* gTagPtr = rTagPtr + alignedTagBytes; 793 const uint8_t* gTagPtr = rTagPtr + alignedTagBytes;
821 tagLen = tagLen > alignedTagBytes ? tagLen - alignedTagBytes : 0; 794 tagLen = tagLen > alignedTagBytes ? tagLen - alignedTagBytes : 0;
822 SkGammas::Data gData; 795 SkGammas::Data gData;
823 SkGammas::Params gParams; 796 SkColorSpaceTransferFn gParams;
824 tagBytes = 0; 797 tagBytes = 0;
825 SkGammas::Type gType = parse_gamma(&gData, &gParams, &tagBytes, gTag Ptr, 798 SkGammas::Type gType = parse_gamma(&gData, &gParams, &tagBytes, gTag Ptr,
826 tagLen); 799 tagLen);
827 handle_invalid_gamma(&gType, &gData); 800 handle_invalid_gamma(&gType, &gData);
828 801
829 alignedTagBytes = SkAlign4(tagBytes); 802 alignedTagBytes = SkAlign4(tagBytes);
830 const uint8_t* bTagPtr = gTagPtr + alignedTagBytes; 803 const uint8_t* bTagPtr = gTagPtr + alignedTagBytes;
831 tagLen = tagLen > alignedTagBytes ? tagLen - alignedTagBytes : 0; 804 tagLen = tagLen > alignedTagBytes ? tagLen - alignedTagBytes : 0;
832 SkGammas::Data bData; 805 SkGammas::Data bData;
833 SkGammas::Params bParams; 806 SkColorSpaceTransferFn bParams;
834 SkGammas::Type bType = parse_gamma(&bData, &bParams, &tagBytes, bTag Ptr, 807 SkGammas::Type bType = parse_gamma(&bData, &bParams, &tagBytes, bTag Ptr,
835 tagLen); 808 tagLen);
836 handle_invalid_gamma(&bType, &bData); 809 handle_invalid_gamma(&bType, &bData);
837 810
838 size_t allocSize = sizeof(SkGammas); 811 size_t allocSize = sizeof(SkGammas);
839 return_if_false(safe_add(allocSize, gamma_alloc_size(rType, rData), &allocSize), 812 return_if_false(safe_add(allocSize, gamma_alloc_size(rType, rData), &allocSize),
840 "SkGammas struct is too large to allocate"); 813 "SkGammas struct is too large to allocate");
841 return_if_false(safe_add(allocSize, gamma_alloc_size(gType, gData), &allocSize), 814 return_if_false(safe_add(allocSize, gamma_alloc_size(gType, gData), &allocSize),
842 "SkGammas struct is too large to allocate"); 815 "SkGammas struct is too large to allocate");
843 return_if_false(safe_add(allocSize, gamma_alloc_size(bType, bData), &allocSize), 816 return_if_false(safe_add(allocSize, gamma_alloc_size(bType, bData), &allocSize),
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
986 b = r ? r : g; 959 b = r ? r : g;
987 } 960 }
988 } 961 }
989 962
990 SkGammaNamed gammaNamed = kNonStandard_SkGammaNamed; 963 SkGammaNamed gammaNamed = kNonStandard_SkGammaNamed;
991 sk_sp<SkGammas> gammas = nullptr; 964 sk_sp<SkGammas> gammas = nullptr;
992 size_t tagBytes; 965 size_t tagBytes;
993 if (r && g && b) { 966 if (r && g && b) {
994 if (tag_equals(r, g, base) && tag_equals(g, b, base)) { 967 if (tag_equals(r, g, base) && tag_equals(g, b, base)) {
995 SkGammas::Data data; 968 SkGammas::Data data;
996 SkGammas::Params params; 969 SkColorSpaceTransferFn params;
997 SkGammas::Type type = 970 SkGammas::Type type =
998 parse_gamma(&data, &params, &tagBytes, r->addr(b ase), r->fLength); 971 parse_gamma(&data, &params, &tagBytes, r->addr(b ase), r->fLength);
999 handle_invalid_gamma(&type, &data); 972 handle_invalid_gamma(&type, &data);
1000 973
1001 if (SkGammas::Type::kNamed_Type == type) { 974 if (SkGammas::Type::kNamed_Type == type) {
1002 gammaNamed = data.fNamed; 975 gammaNamed = data.fNamed;
1003 } else { 976 } else {
1004 size_t allocSize = sizeof(SkGammas); 977 size_t allocSize = sizeof(SkGammas);
1005 if (!safe_add(allocSize, gamma_alloc_size(type, data ), &allocSize)) { 978 if (!safe_add(allocSize, gamma_alloc_size(type, data ), &allocSize)) {
1006 return_null("SkGammas struct is too large to all ocate"); 979 return_null("SkGammas struct is too large to all ocate");
1007 } 980 }
1008 void* memory = sk_malloc_throw(allocSize); 981 void* memory = sk_malloc_throw(allocSize);
1009 gammas = sk_sp<SkGammas>(new (memory) SkGammas()); 982 gammas = sk_sp<SkGammas>(new (memory) SkGammas());
1010 load_gammas(memory, 0, type, &data, params, r->addr( base)); 983 load_gammas(memory, 0, type, &data, params, r->addr( base));
1011 984
1012 gammas->fRedType = type; 985 gammas->fRedType = type;
1013 gammas->fGreenType = type; 986 gammas->fGreenType = type;
1014 gammas->fBlueType = type; 987 gammas->fBlueType = type;
1015 988
1016 gammas->fRedData = data; 989 gammas->fRedData = data;
1017 gammas->fGreenData = data; 990 gammas->fGreenData = data;
1018 gammas->fBlueData = data; 991 gammas->fBlueData = data;
1019 } 992 }
1020 } else { 993 } else {
1021 SkGammas::Data rData; 994 SkGammas::Data rData;
1022 SkGammas::Params rParams; 995 SkColorSpaceTransferFn rParams;
1023 SkGammas::Type rType = 996 SkGammas::Type rType =
1024 parse_gamma(&rData, &rParams, &tagBytes, r->addr (base), r->fLength); 997 parse_gamma(&rData, &rParams, &tagBytes, r->addr (base), r->fLength);
1025 handle_invalid_gamma(&rType, &rData); 998 handle_invalid_gamma(&rType, &rData);
1026 999
1027 SkGammas::Data gData; 1000 SkGammas::Data gData;
1028 SkGammas::Params gParams; 1001 SkColorSpaceTransferFn gParams;
1029 SkGammas::Type gType = 1002 SkGammas::Type gType =
1030 parse_gamma(&gData, &gParams, &tagBytes, g->addr (base), g->fLength); 1003 parse_gamma(&gData, &gParams, &tagBytes, g->addr (base), g->fLength);
1031 handle_invalid_gamma(&gType, &gData); 1004 handle_invalid_gamma(&gType, &gData);
1032 1005
1033 SkGammas::Data bData; 1006 SkGammas::Data bData;
1034 SkGammas::Params bParams; 1007 SkColorSpaceTransferFn bParams;
1035 SkGammas::Type bType = 1008 SkGammas::Type bType =
1036 parse_gamma(&bData, &bParams, &tagBytes, b->addr (base), b->fLength); 1009 parse_gamma(&bData, &bParams, &tagBytes, b->addr (base), b->fLength);
1037 handle_invalid_gamma(&bType, &bData); 1010 handle_invalid_gamma(&bType, &bData);
1038 1011
1039 size_t allocSize = sizeof(SkGammas); 1012 size_t allocSize = sizeof(SkGammas);
1040 if (!safe_add(allocSize, gamma_alloc_size(rType, rData), &allocSize) || 1013 if (!safe_add(allocSize, gamma_alloc_size(rType, rData), &allocSize) ||
1041 !safe_add(allocSize, gamma_alloc_size(gType, gData), &allocSize) || 1014 !safe_add(allocSize, gamma_alloc_size(gType, gData), &allocSize) ||
1042 !safe_add(allocSize, gamma_alloc_size(bType, bData), &allocSize)) 1015 !safe_add(allocSize, gamma_alloc_size(bType, bData), &allocSize))
1043 { 1016 {
1044 return_null("SkGammas struct is too large to allocat e"); 1017 return_null("SkGammas struct is too large to allocat e");
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after
1329 ptr32[4] = SkEndian_SwapBE32(0x000116cc); 1302 ptr32[4] = SkEndian_SwapBE32(0x000116cc);
1330 ptr += kTAG_XYZ_Bytes; 1303 ptr += kTAG_XYZ_Bytes;
1331 1304
1332 // Write copyright tag 1305 // Write copyright tag
1333 memcpy(ptr, gEmptyTextTag, sizeof(gEmptyTextTag)); 1306 memcpy(ptr, gEmptyTextTag, sizeof(gEmptyTextTag));
1334 1307
1335 // TODO (msarett): Should we try to hold onto the data so we can return imme diately if 1308 // TODO (msarett): Should we try to hold onto the data so we can return imme diately if
1336 // the client calls again? 1309 // the client calls again?
1337 return SkData::MakeFromMalloc(profile.release(), kICCProfileSize); 1310 return SkData::MakeFromMalloc(profile.release(), kICCProfileSize);
1338 } 1311 }
OLDNEW
« no previous file with comments | « src/core/SkColorSpace_Base.h ('k') | tests/ColorSpaceTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698