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

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

Issue 2389983002: Refactored SkColorSpace and added in a Lab PCS GM (Closed)
Patch Set: migrated call from SkColorSpace_Base::makeLinearGamma() to SkColorSpace_XYZ::makeLinearGamma() 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') | src/core/SkColorSpace_XYZ.h » ('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_A2B.h"
9 #include "SkColorSpace_Base.h" 10 #include "SkColorSpace_Base.h"
11 #include "SkColorSpace_XYZ.h"
10 #include "SkColorSpacePriv.h" 12 #include "SkColorSpacePriv.h"
11 #include "SkEndian.h" 13 #include "SkEndian.h"
12 #include "SkFixed.h" 14 #include "SkFixed.h"
13 #include "SkTemplates.h" 15 #include "SkTemplates.h"
14 16
15 #define return_if_false(pred, msg) \ 17 #define return_if_false(pred, msg) \
16 do { \ 18 do { \
17 if (!(pred)) { \ 19 if (!(pred)) { \
18 SkColorSpacePrintf("Invalid ICC Profile: %s.\n", (msg)); \ 20 SkColorSpacePrintf("Invalid ICC Profile: %s.\n", (msg)); \
19 return false; \ 21 return false; \
(...skipping 25 matching lines...) Expand all
45 47
46 // Contains a signature (4), offset (4), and size (4). 48 // Contains a signature (4), offset (4), and size (4).
47 static constexpr size_t kICCTagTableEntrySize = 12; 49 static constexpr size_t kICCTagTableEntrySize = 12;
48 50
49 static constexpr uint32_t kRGB_ColorSpace = SkSetFourByteTag('R', 'G', 'B', ' '); 51 static constexpr uint32_t kRGB_ColorSpace = SkSetFourByteTag('R', 'G', 'B', ' ');
50 static constexpr uint32_t kDisplay_Profile = SkSetFourByteTag('m', 'n', 't', 'r'); 52 static constexpr uint32_t kDisplay_Profile = SkSetFourByteTag('m', 'n', 't', 'r');
51 static constexpr uint32_t kInput_Profile = SkSetFourByteTag('s', 'c', 'n', 'r'); 53 static constexpr uint32_t kInput_Profile = SkSetFourByteTag('s', 'c', 'n', 'r');
52 static constexpr uint32_t kOutput_Profile = SkSetFourByteTag('p', 'r', 't', 'r'); 54 static constexpr uint32_t kOutput_Profile = SkSetFourByteTag('p', 'r', 't', 'r');
53 static constexpr uint32_t kColorSpace_Profile = SkSetFourByteTag('s', 'p', 'a', 'c'); 55 static constexpr uint32_t kColorSpace_Profile = SkSetFourByteTag('s', 'p', 'a', 'c');
54 static constexpr uint32_t kXYZ_PCSSpace = SkSetFourByteTag('X', 'Y', 'Z', ' '); 56 static constexpr uint32_t kXYZ_PCSSpace = SkSetFourByteTag('X', 'Y', 'Z', ' ');
57 static constexpr uint32_t kLAB_PCSSpace = SkSetFourByteTag('L', 'a', 'b', ' ');
55 static constexpr uint32_t kACSP_Signature = SkSetFourByteTag('a', 'c', 's', 'p'); 58 static constexpr uint32_t kACSP_Signature = SkSetFourByteTag('a', 'c', 's', 'p');
56 59
57 struct ICCProfileHeader { 60 struct ICCProfileHeader {
58 uint32_t fSize; 61 uint32_t fSize;
59 62
60 // No reason to care about the preferred color management module (ex: Adobe, Apple, etc.). 63 // No reason to care about the preferred color management module (ex: Adobe, Apple, etc.).
61 // We're always going to use this one. 64 // We're always going to use this one.
62 uint32_t fCMMType_ignored; 65 uint32_t fCMMType_ignored;
63 66
64 uint32_t fVersion; 67 uint32_t fVersion;
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
123 fProfileClass == kOutput_Profile || 126 fProfileClass == kOutput_Profile ||
124 fProfileClass == kColorSpace_Profile, 127 fProfileClass == kColorSpace_Profile,
125 "Unsupported profile"); 128 "Unsupported profile");
126 129
127 // TODO (msarett): 130 // TODO (msarett):
128 // All the profiles we've tested so far use RGB as the input color space . 131 // All the profiles we've tested so far use RGB as the input color space .
129 return_if_false(fInputColorSpace == kRGB_ColorSpace, "Unsupported color space"); 132 return_if_false(fInputColorSpace == kRGB_ColorSpace, "Unsupported color space");
130 133
131 // TODO (msarett): 134 // TODO (msarett):
132 // All the profiles we've tested so far use XYZ as the profile connectio n space. 135 // All the profiles we've tested so far use XYZ as the profile connectio n space.
133 return_if_false(fPCS == kXYZ_PCSSpace, "Unsupported PCS space"); 136 return_if_false(fPCS == kXYZ_PCSSpace || fPCS == kLAB_PCSSpace, "Unsuppo rted PCS space");
134 137
135 return_if_false(fSignature == kACSP_Signature, "Bad signature"); 138 return_if_false(fSignature == kACSP_Signature, "Bad signature");
136 139
137 // TODO (msarett): 140 // TODO (msarett):
138 // Should we treat different rendering intents differently? 141 // Should we treat different rendering intents differently?
139 // Valid rendering intents include kPerceptual (0), kRelative (1), 142 // Valid rendering intents include kPerceptual (0), kRelative (1),
140 // kSaturation (2), and kAbsolute (3). 143 // kSaturation (2), and kAbsolute (3).
141 if (fRenderingIntent > 3) { 144 if (fRenderingIntent > 3) {
142 // Warn rather than fail here. Occasionally, we see perfectly 145 // Warn rather than fail here. Occasionally, we see perfectly
143 // normal profiles with wacky rendering intents. 146 // normal profiles with wacky rendering intents.
(...skipping 517 matching lines...) Expand 10 before | Expand all | Expand 10 after
661 664
662 return true; 665 return true;
663 } 666 }
664 667
665 static bool load_matrix(SkMatrix44* toXYZ, const uint8_t* src, size_t len) { 668 static bool load_matrix(SkMatrix44* toXYZ, const uint8_t* src, size_t len) {
666 if (len < 48) { 669 if (len < 48) {
667 SkColorSpacePrintf("Matrix tag is too small (%d bytes).", len); 670 SkColorSpacePrintf("Matrix tag is too small (%d bytes).", len);
668 return false; 671 return false;
669 } 672 }
670 673
671 // For this matrix to behave like our "to XYZ D50" matrices, it needs to be scaled.
672 constexpr float scale = 65535.0 / 32768.0;
673 float array[16]; 674 float array[16];
674 array[ 0] = scale * SkFixedToFloat(read_big_endian_i32(src)); 675 array[ 0] = SkFixedToFloat(read_big_endian_i32(src));
675 array[ 1] = scale * SkFixedToFloat(read_big_endian_i32(src + 4)); 676 array[ 1] = SkFixedToFloat(read_big_endian_i32(src + 4));
676 array[ 2] = scale * SkFixedToFloat(read_big_endian_i32(src + 8)); 677 array[ 2] = SkFixedToFloat(read_big_endian_i32(src + 8));
677 array[ 3] = scale * SkFixedToFloat(read_big_endian_i32(src + 36)); // transl ate R 678 array[ 3] = SkFixedToFloat(read_big_endian_i32(src + 36)); // translate R
678 array[ 4] = scale * SkFixedToFloat(read_big_endian_i32(src + 12)); 679 array[ 4] = SkFixedToFloat(read_big_endian_i32(src + 12));
679 array[ 5] = scale * SkFixedToFloat(read_big_endian_i32(src + 16)); 680 array[ 5] = SkFixedToFloat(read_big_endian_i32(src + 16));
680 array[ 6] = scale * SkFixedToFloat(read_big_endian_i32(src + 20)); 681 array[ 6] = SkFixedToFloat(read_big_endian_i32(src + 20));
681 array[ 7] = scale * SkFixedToFloat(read_big_endian_i32(src + 40)); // transl ate G 682 array[ 7] = SkFixedToFloat(read_big_endian_i32(src + 40)); // translate G
682 array[ 8] = scale * SkFixedToFloat(read_big_endian_i32(src + 24)); 683 array[ 8] = SkFixedToFloat(read_big_endian_i32(src + 24));
683 array[ 9] = scale * SkFixedToFloat(read_big_endian_i32(src + 28)); 684 array[ 9] = SkFixedToFloat(read_big_endian_i32(src + 28));
684 array[10] = scale * SkFixedToFloat(read_big_endian_i32(src + 32)); 685 array[10] = SkFixedToFloat(read_big_endian_i32(src + 32));
685 array[11] = scale * SkFixedToFloat(read_big_endian_i32(src + 44)); // transl ate B 686 array[11] = SkFixedToFloat(read_big_endian_i32(src + 44)); // translate B
686 array[12] = 0.0f; 687 array[12] = 0.0f;
687 array[13] = 0.0f; 688 array[13] = 0.0f;
688 array[14] = 0.0f; 689 array[14] = 0.0f;
689 array[15] = 1.0f; 690 array[15] = 1.0f;
690 toXYZ->setRowMajorf(array); 691 toXYZ->setRowMajorf(array);
691 return true; 692 return true;
692 } 693 }
693 694
694 static inline SkGammaNamed is_named(const sk_sp<SkGammas>& gammas) { 695 static inline SkGammaNamed is_named(const sk_sp<SkGammas>& gammas) {
695 if (gammas->isNamed(0) && gammas->isNamed(1) && gammas->isNamed(2) && 696 if (gammas->isNamed(0) && gammas->isNamed(1) && gammas->isNamed(2) &&
696 gammas->fRedData.fNamed == gammas->fGreenData.fNamed && 697 gammas->fRedData.fNamed == gammas->fGreenData.fNamed &&
697 gammas->fRedData.fNamed == gammas->fBlueData.fNamed) 698 gammas->fRedData.fNamed == gammas->fBlueData.fNamed)
698 { 699 {
699 return gammas->fRedData.fNamed; 700 return gammas->fRedData.fNamed;
700 } 701 }
701 702
702 return kNonStandard_SkGammaNamed; 703 return kNonStandard_SkGammaNamed;
703 } 704 }
704 705
706 /**
707 * Parse and load an entire stored curve. Handles invalid gammas as well.
708 *
709 * There's nothing to do for the simple cases, but for table gammas we need to actually
710 * read the table into heap memory. And for parametric gammas, we need to copy over the
711 * parameter values.
712 *
713 * @param gammaNamed Out-variable. The named gamma curve.
714 * @param gammas Out-variable. The stored gamma curve information. Can be n ull if
715 * gammaNamed is a named curve
716 * @param rTagPtr Pointer to start of the gamma tag.
717 * @param taglen The size in bytes of the tag
718 *
719 * @return false on failure, true on success
720 */
721 static bool parse_and_load_gamma(SkGammaNamed* gammaNamed, sk_sp<SkGammas>* gamm as,
722 const uint8_t* rTagPtr, size_t tagLen)
723 {
724 SkGammas::Data rData;
725 SkColorSpaceTransferFn rParams;
705 726
706 static bool load_a2b0(sk_sp<SkColorLookUpTable>* colorLUT, SkGammaNamed* gammaNa med, 727 // On an invalid first gamma, tagBytes remains set as zero. This causes the two
707 sk_sp<SkGammas>* gammas, SkMatrix44* toXYZ, const uint8_t* src, size_t len) { 728 // subsequent to be treated as identical (which is what we want).
729 size_t tagBytes = 0;
730 SkGammas::Type rType = parse_gamma(&rData, &rParams, &tagBytes, rTagPtr, tag Len);
731 handle_invalid_gamma(&rType, &rData);
732 size_t alignedTagBytes = SkAlign4(tagBytes);
733
734 if ((3 * alignedTagBytes <= tagLen) &&
735 !memcmp(rTagPtr, rTagPtr + 1 * alignedTagBytes, tagBytes) &&
736 !memcmp(rTagPtr, rTagPtr + 2 * alignedTagBytes, tagBytes))
737 {
738 if (SkGammas::Type::kNamed_Type == rType) {
739 *gammaNamed = rData.fNamed;
740 } else {
741 size_t allocSize = sizeof(SkGammas);
742 return_if_false(safe_add(allocSize, gamma_alloc_size(rType, rData), &allocSize),
743 "SkGammas struct is too large to allocate");
744 void* memory = sk_malloc_throw(allocSize);
745 *gammas = sk_sp<SkGammas>(new (memory) SkGammas());
746 load_gammas(memory, 0, rType, &rData, rParams, rTagPtr);
747
748 (*gammas)->fRedType = rType;
749 (*gammas)->fGreenType = rType;
750 (*gammas)->fBlueType = rType;
751
752 (*gammas)->fRedData = rData;
753 (*gammas)->fGreenData = rData;
754 (*gammas)->fBlueData = rData;
755 }
756 } else {
757 const uint8_t* gTagPtr = rTagPtr + alignedTagBytes;
758 tagLen = tagLen > alignedTagBytes ? tagLen - alignedTagBytes : 0;
759 SkGammas::Data gData;
760 SkColorSpaceTransferFn gParams;
761 tagBytes = 0;
762 SkGammas::Type gType = parse_gamma(&gData, &gParams, &tagBytes, gTagPtr,
763 tagLen);
764 handle_invalid_gamma(&gType, &gData);
765
766 alignedTagBytes = SkAlign4(tagBytes);
767 const uint8_t* bTagPtr = gTagPtr + alignedTagBytes;
768 tagLen = tagLen > alignedTagBytes ? tagLen - alignedTagBytes : 0;
769 SkGammas::Data bData;
770 SkColorSpaceTransferFn bParams;
771 SkGammas::Type bType = parse_gamma(&bData, &bParams, &tagBytes, bTagPtr,
772 tagLen);
773 handle_invalid_gamma(&bType, &bData);
774
775 size_t allocSize = sizeof(SkGammas);
776 return_if_false(safe_add(allocSize, gamma_alloc_size(rType, rData), &all ocSize),
777 "SkGammas struct is too large to allocate");
778 return_if_false(safe_add(allocSize, gamma_alloc_size(gType, gData), &all ocSize),
779 "SkGammas struct is too large to allocate");
780 return_if_false(safe_add(allocSize, gamma_alloc_size(bType, bData), &all ocSize),
781 "SkGammas struct is too large to allocate");
782 void* memory = sk_malloc_throw(allocSize);
783 *gammas = sk_sp<SkGammas>(new (memory) SkGammas());
784
785 uint32_t offset = 0;
786 (*gammas)->fRedType = rType;
787 offset += load_gammas(memory, offset, rType, &rData, rParams, rTagPtr);
788
789 (*gammas)->fGreenType = gType;
790 offset += load_gammas(memory, offset, gType, &gData, gParams, gTagPtr);
791
792 (*gammas)->fBlueType = bType;
793 load_gammas(memory, offset, bType, &bData, bParams, bTagPtr);
794
795 (*gammas)->fRedData = rData;
796 (*gammas)->fGreenData = gData;
797 (*gammas)->fBlueData = bData;
798 }
799
800 if (kNonStandard_SkGammaNamed == *gammaNamed) {
801 *gammaNamed = is_named(*gammas);
802 if (kNonStandard_SkGammaNamed != *gammaNamed) {
803 // No need to keep the gammas struct, the enum is enough.
804 *gammas = nullptr;
805 }
806 }
807 return true;
808 }
809
810 static bool load_a2b0(sk_sp<SkColorLookUpTable>* colorLUT,
811 SkGammaNamed* aCurveNamed, sk_sp<SkGammas>* aCurve,
812 SkGammaNamed* mCurveNamed, sk_sp<SkGammas>* mCurve,
813 SkGammaNamed* bCurveNamed, sk_sp<SkGammas>* bCurve,
814 SkMatrix44* matrix, const uint8_t* src, size_t len) {
708 if (len < 32) { 815 if (len < 32) {
709 SkColorSpacePrintf("A to B tag is too small (%d bytes).", len); 816 SkColorSpacePrintf("A to B tag is too small (%d bytes).", len);
710 return false; 817 return false;
711 } 818 }
712 819
713 uint32_t type = read_big_endian_u32(src); 820 uint32_t type = read_big_endian_u32(src);
714 if (kTAG_AtoBType != type) { 821 if (kTAG_AtoBType != type) {
715 // FIXME (msarett): Need to support lut8Type and lut16Type. 822 // FIXME (msarett): Need to support lut8Type and lut16Type.
716 SkColorSpacePrintf("Unsupported A to B tag type.\n"); 823 SkColorSpacePrintf("Unsupported A to B tag type.\n");
717 return false; 824 return false;
718 } 825 }
719 826
720 // Read the number of channels. The four bytes that we skipped are reserved and 827 // Read the number of channels. The four bytes that we skipped are reserved and
721 // must be zero. 828 // must be zero.
722 uint8_t inputChannels = src[8]; 829 uint8_t inputChannels = src[8];
723 uint8_t outputChannels = src[9]; 830 uint8_t outputChannels = src[9];
724 if (3 != inputChannels || SkColorLookUpTable::kOutputChannels != outputChann els) { 831 if (3 != inputChannels || SkColorLookUpTable::kOutputChannels != outputChann els) {
725 // We only handle (supposedly) RGB inputs and RGB outputs. The numbers of input 832 // We only handle (supposedly) RGB inputs and RGB outputs. The numbers of input
726 // channels and output channels both must be 3. 833 // channels and output channels both must be 3.
727 // TODO (msarett): 834 // TODO (msarett):
728 // Support different numbers of input channels. Ex: CMYK (4). 835 // Support different numbers of input channels. Ex: CMYK (4).
729 SkColorSpacePrintf("Input and output channels must equal 3 in A to B tag .\n"); 836 SkColorSpacePrintf("Input and output channels must equal 3 in A to B tag .\n");
730 return false; 837 return false;
731 } 838 }
732 839
733 // Read the offsets of each element in the A to B tag. With the exception o f A curves and
734 // B curves (which we do not yet support), we will handle these elements in the order in
735 // which they should be applied (rather than the order in which they occur i n the tag).
736 // If the offset is non-zero it indicates that the element is present. 840 // If the offset is non-zero it indicates that the element is present.
737 uint32_t offsetToACurves = read_big_endian_i32(src + 28); 841 uint32_t offsetToACurves = read_big_endian_i32(src + 28);
738 uint32_t offsetToBCurves = read_big_endian_i32(src + 12); 842 if (0 != offsetToACurves && offsetToACurves < len) {
739 if ((0 != offsetToACurves) || (0 != offsetToBCurves)) { 843 const size_t tagLen = len - offsetToACurves;
740 // FIXME (msarett): Handle A and B curves. 844 if (!parse_and_load_gamma(aCurveNamed, aCurve, src + offsetToACurves, ta gLen)) {
741 // Note that the A curve is technically required in order to have a colo r LUT. 845 return false;
742 // However, all the A curves I have seen so far have are just placeholde rs that 846 }
743 // don't actually transform the data.
744 SkColorSpacePrintf("Ignoring A and/or B curve. Output may be wrong.\n") ;
745 } 847 }
746 848
747 uint32_t offsetToColorLUT = read_big_endian_i32(src + 24); 849 uint32_t offsetToColorLUT = read_big_endian_i32(src + 24);
748 if (0 != offsetToColorLUT && offsetToColorLUT < len) { 850 if (0 != offsetToColorLUT && offsetToColorLUT < len) {
749 if (!load_color_lut(colorLUT, inputChannels, src + offsetToColorLUT, 851 if (!load_color_lut(colorLUT, inputChannels, src + offsetToColorLUT,
750 len - offsetToColorLUT)) { 852 len - offsetToColorLUT)) {
751 SkColorSpacePrintf("Failed to read color LUT from A to B tag.\n"); 853 SkColorSpacePrintf("Failed to read color LUT from A to B tag.\n");
854 return false;
752 } 855 }
753 } 856 }
754 857
755 uint32_t offsetToMCurves = read_big_endian_i32(src + 20); 858 uint32_t offsetToMCurves = read_big_endian_i32(src + 20);
756 if (0 != offsetToMCurves && offsetToMCurves < len) { 859 if (0 != offsetToMCurves && offsetToMCurves < len) {
757 const uint8_t* rTagPtr = src + offsetToMCurves; 860 const size_t tagLen = len - offsetToMCurves;
758 size_t tagLen = len - offsetToMCurves; 861 if (!parse_and_load_gamma(mCurveNamed, mCurve, src + offsetToMCurves, ta gLen)) {
759 862 return false;
760 SkGammas::Data rData;
761 SkColorSpaceTransferFn rParams;
762
763 // On an invalid first gamma, tagBytes remains set as zero. This causes the two
764 // subsequent to be treated as identical (which is what we want).
765 size_t tagBytes = 0;
766 SkGammas::Type rType = parse_gamma(&rData, &rParams, &tagBytes, rTagPtr, tagLen);
767 handle_invalid_gamma(&rType, &rData);
768 size_t alignedTagBytes = SkAlign4(tagBytes);
769
770 if ((3 * alignedTagBytes <= tagLen) &&
771 !memcmp(rTagPtr, rTagPtr + 1 * alignedTagBytes, tagBytes) &&
772 !memcmp(rTagPtr, rTagPtr + 2 * alignedTagBytes, tagBytes))
773 {
774 if (SkGammas::Type::kNamed_Type == rType) {
775 *gammaNamed = rData.fNamed;
776 } else {
777 size_t allocSize = sizeof(SkGammas);
778 return_if_false(safe_add(allocSize, gamma_alloc_size(rType, rDat a), &allocSize),
779 "SkGammas struct is too large to allocate");
780 void* memory = sk_malloc_throw(allocSize);
781 *gammas = sk_sp<SkGammas>(new (memory) SkGammas());
782 load_gammas(memory, 0, rType, &rData, rParams, rTagPtr);
783
784 (*gammas)->fRedType = rType;
785 (*gammas)->fGreenType = rType;
786 (*gammas)->fBlueType = rType;
787
788 (*gammas)->fRedData = rData;
789 (*gammas)->fGreenData = rData;
790 (*gammas)->fBlueData = rData;
791 }
792 } else {
793 const uint8_t* gTagPtr = rTagPtr + alignedTagBytes;
794 tagLen = tagLen > alignedTagBytes ? tagLen - alignedTagBytes : 0;
795 SkGammas::Data gData;
796 SkColorSpaceTransferFn gParams;
797 tagBytes = 0;
798 SkGammas::Type gType = parse_gamma(&gData, &gParams, &tagBytes, gTag Ptr,
799 tagLen);
800 handle_invalid_gamma(&gType, &gData);
801
802 alignedTagBytes = SkAlign4(tagBytes);
803 const uint8_t* bTagPtr = gTagPtr + alignedTagBytes;
804 tagLen = tagLen > alignedTagBytes ? tagLen - alignedTagBytes : 0;
805 SkGammas::Data bData;
806 SkColorSpaceTransferFn bParams;
807 SkGammas::Type bType = parse_gamma(&bData, &bParams, &tagBytes, bTag Ptr,
808 tagLen);
809 handle_invalid_gamma(&bType, &bData);
810
811 size_t allocSize = sizeof(SkGammas);
812 return_if_false(safe_add(allocSize, gamma_alloc_size(rType, rData), &allocSize),
813 "SkGammas struct is too large to allocate");
814 return_if_false(safe_add(allocSize, gamma_alloc_size(gType, gData), &allocSize),
815 "SkGammas struct is too large to allocate");
816 return_if_false(safe_add(allocSize, gamma_alloc_size(bType, bData), &allocSize),
817 "SkGammas struct is too large to allocate");
818 void* memory = sk_malloc_throw(allocSize);
819 *gammas = sk_sp<SkGammas>(new (memory) SkGammas());
820
821 uint32_t offset = 0;
822 (*gammas)->fRedType = rType;
823 offset += load_gammas(memory, offset, rType, &rData, rParams, rTagPt r);
824
825 (*gammas)->fGreenType = gType;
826 offset += load_gammas(memory, offset, gType, &gData, gParams, gTagPt r);
827
828 (*gammas)->fBlueType = bType;
829 load_gammas(memory, offset, bType, &bData, bParams, bTagPtr);
830
831 (*gammas)->fRedData = rData;
832 (*gammas)->fGreenData = gData;
833 (*gammas)->fBlueData = bData;
834 }
835 } else {
836 // Guess sRGB if the chunk is missing a transfer function.
837 *gammaNamed = kSRGB_SkGammaNamed;
838 }
839
840 if (kNonStandard_SkGammaNamed == *gammaNamed) {
841 *gammaNamed = is_named(*gammas);
842 if (kNonStandard_SkGammaNamed != *gammaNamed) {
843 // No need to keep the gammas struct, the enum is enough.
844 *gammas = nullptr;
845 } 863 }
846 } 864 }
847 865
848 uint32_t offsetToMatrix = read_big_endian_i32(src + 16); 866 uint32_t offsetToMatrix = read_big_endian_i32(src + 16);
849 if (0 != offsetToMatrix && offsetToMatrix < len) { 867 if (0 != offsetToMatrix && offsetToMatrix < len) {
850 if (!load_matrix(toXYZ, src + offsetToMatrix, len - offsetToMatrix)) { 868 if (!load_matrix(matrix, src + offsetToMatrix, len - offsetToMatrix)) {
851 SkColorSpacePrintf("Failed to read matrix from A to B tag.\n"); 869 SkColorSpacePrintf("Failed to read matrix from A to B tag.\n");
852 toXYZ->setIdentity(); 870 matrix->setIdentity();
871 }
872 }
873
874 uint32_t offsetToBCurves = read_big_endian_i32(src + 12);
875 if (0 != offsetToBCurves && offsetToBCurves < len) {
876 const size_t tagLen = len - offsetToBCurves;
877 if (!parse_and_load_gamma(bCurveNamed, bCurve, src + offsetToBCurves, ta gLen)) {
878 return false;
853 } 879 }
854 } 880 }
855 881
856 return true; 882 return true;
857 } 883 }
858 884
859 static bool tag_equals(const ICCTag* a, const ICCTag* b, const uint8_t* base) { 885 static bool tag_equals(const ICCTag* a, const ICCTag* b, const uint8_t* base) {
860 if (!a || !b) { 886 if (!a || !b) {
861 return a == b; 887 return a == b;
862 } 888 }
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
920 } 946 }
921 } 947 }
922 948
923 switch (header.fInputColorSpace) { 949 switch (header.fInputColorSpace) {
924 case kRGB_ColorSpace: { 950 case kRGB_ColorSpace: {
925 // Recognize the rXYZ, gXYZ, and bXYZ tags. 951 // Recognize the rXYZ, gXYZ, and bXYZ tags.
926 const ICCTag* r = ICCTag::Find(tags.get(), tagCount, kTAG_rXYZ); 952 const ICCTag* r = ICCTag::Find(tags.get(), tagCount, kTAG_rXYZ);
927 const ICCTag* g = ICCTag::Find(tags.get(), tagCount, kTAG_gXYZ); 953 const ICCTag* g = ICCTag::Find(tags.get(), tagCount, kTAG_gXYZ);
928 const ICCTag* b = ICCTag::Find(tags.get(), tagCount, kTAG_bXYZ); 954 const ICCTag* b = ICCTag::Find(tags.get(), tagCount, kTAG_bXYZ);
929 if (r && g && b) { 955 if (r && g && b) {
956 // Lab PCS means the profile is required to be an n-component LU T-based
957 // profile, so 3-component matrix-based profiles can only have a n XYZ PCS
958 if (kXYZ_PCSSpace != header.fPCS) {
959 return_null("Unsupported PCS space");
960 }
930 float toXYZ[9]; 961 float toXYZ[9];
931 if (!load_xyz(&toXYZ[0], r->addr(base), r->fLength) || 962 if (!load_xyz(&toXYZ[0], r->addr(base), r->fLength) ||
932 !load_xyz(&toXYZ[3], g->addr(base), g->fLength) || 963 !load_xyz(&toXYZ[3], g->addr(base), g->fLength) ||
933 !load_xyz(&toXYZ[6], b->addr(base), b->fLength)) 964 !load_xyz(&toXYZ[6], b->addr(base), b->fLength))
934 { 965 {
935 return_null("Need valid rgb tags for XYZ space"); 966 return_null("Need valid rgb tags for XYZ space");
936 } 967 }
937 SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor); 968 SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor);
938 mat.set3x3(toXYZ[0], toXYZ[1], toXYZ[2], 969 mat.set3x3(toXYZ[0], toXYZ[1], toXYZ[2],
939 toXYZ[3], toXYZ[4], toXYZ[5], 970 toXYZ[3], toXYZ[4], toXYZ[5],
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
1037 } 1068 }
1038 } else { 1069 } else {
1039 // Guess sRGB if the profile is missing transfer functions. 1070 // Guess sRGB if the profile is missing transfer functions.
1040 gammaNamed = kSRGB_SkGammaNamed; 1071 gammaNamed = kSRGB_SkGammaNamed;
1041 } 1072 }
1042 1073
1043 if (kNonStandard_SkGammaNamed == gammaNamed) { 1074 if (kNonStandard_SkGammaNamed == gammaNamed) {
1044 // It's possible that we'll initially detect non-matching ga mmas, only for 1075 // It's possible that we'll initially detect non-matching ga mmas, only for
1045 // them to evaluate to the same named gamma curve. 1076 // them to evaluate to the same named gamma curve.
1046 gammaNamed = is_named(gammas); 1077 gammaNamed = is_named(gammas);
1047 if (kNonStandard_SkGammaNamed == gammaNamed) { 1078 }
1048 return sk_sp<SkColorSpace>(new SkColorSpace_Base(nullptr , gammaNamed, 1079
1049 std::mo ve(gammas), mat, 1080 if (kNonStandard_SkGammaNamed == gammaNamed) {
1050 std::mo ve(data))); 1081 return sk_sp<SkColorSpace>(new SkColorSpace_XYZ(gammaNamed,
1051 } 1082 std::move(ga mmas),
1083 mat, std::mo ve(data)));
1052 } 1084 }
1053 1085
1054 return SkColorSpace_Base::NewRGB(gammaNamed, mat); 1086 return SkColorSpace_Base::NewRGB(gammaNamed, mat);
1055 } 1087 }
1056 1088
1057 // Recognize color profile specified by A2B0 tag. 1089 // Recognize color profile specified by A2B0 tag.
1058 const ICCTag* a2b0 = ICCTag::Find(tags.get(), tagCount, kTAG_A2B0); 1090 const ICCTag* a2b0 = ICCTag::Find(tags.get(), tagCount, kTAG_A2B0);
1059 if (a2b0) { 1091 if (a2b0) {
1060 SkGammaNamed gammaNamed = kNonStandard_SkGammaNamed; 1092 // default to Linear transforms for when the curves are not
1061 sk_sp<SkGammas> gammas = nullptr; 1093 // in the profile (which is legal behavior for a profile)
1094 SkGammaNamed aCurveNamed = kLinear_SkGammaNamed;
1095 SkGammaNamed mCurveNamed = kLinear_SkGammaNamed;
1096 SkGammaNamed bCurveNamed = kLinear_SkGammaNamed;
1097 sk_sp<SkGammas> aCurve = nullptr;
1098 sk_sp<SkGammas> mCurve = nullptr;
1099 sk_sp<SkGammas> bCurve = nullptr;
1062 sk_sp<SkColorLookUpTable> colorLUT = nullptr; 1100 sk_sp<SkColorLookUpTable> colorLUT = nullptr;
1063 SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor); 1101 SkMatrix44 matrix(SkMatrix44::kUninitialized_Constructor);
1064 if (!load_a2b0(&colorLUT, &gammaNamed, &gammas, &toXYZ, a2b0->ad dr(base), 1102 if (!load_a2b0(&colorLUT, &aCurveNamed, &aCurve, &mCurveNamed, & mCurve,
1065 a2b0->fLength)) { 1103 &bCurveNamed, &bCurve, &matrix, a2b0->addr(base), a2b0->fLength)) {
1066 return_null("Failed to parse A2B0 tag"); 1104 return_null("Failed to parse A2B0 tag");
1067 } 1105 }
1068 1106
1069 if (colorLUT || kNonStandard_SkGammaNamed == gammaNamed) { 1107 SkColorSpace_A2B::PCS pcs = SkColorSpace_A2B::PCS::kLAB;
1070 return sk_sp<SkColorSpace>(new SkColorSpace_Base(std::move(c olorLUT), 1108 if (header.fPCS == kXYZ_PCSSpace) {
1071 gammaNamed, std::move(gammas), 1109 pcs = SkColorSpace_A2B::PCS::kXYZ;
1072 toXYZ, std: :move(data)));
1073 } 1110 }
1074 1111
1075 return SkColorSpace_Base::NewRGB(gammaNamed, toXYZ); 1112 return sk_sp<SkColorSpace>(new SkColorSpace_A2B(aCurveNamed, std ::move(aCurve),
1113 std::move(colorL UT),
1114 mCurveNamed, std ::move(mCurve),
1115 matrix,
1116 bCurveNamed, std ::move(bCurve),
1117 pcs, std::move(d ata)));
1076 } 1118 }
1077 } 1119 }
1078 default: 1120 default:
1079 break; 1121 break;
1080 } 1122 }
1081 1123
1082 return_null("ICC profile contains unsupported colorspace"); 1124 return_null("ICC profile contains unsupported colorspace");
1083 } 1125 }
1084 1126
1085 //////////////////////////////////////////////////////////////////////////////// /////////////////// 1127 //////////////////////////////////////////////////////////////////////////////// ///////////////////
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
1210 // Pad tag with zero. 1252 // Pad tag with zero.
1211 ptr16[1] = 0; 1253 ptr16[1] = 0;
1212 } 1254 }
1213 1255
1214 sk_sp<SkData> SkColorSpace_Base::writeToICC() const { 1256 sk_sp<SkData> SkColorSpace_Base::writeToICC() const {
1215 // Return if this object was created from a profile, or if we have already s erialized 1257 // Return if this object was created from a profile, or if we have already s erialized
1216 // the profile. 1258 // the profile.
1217 if (fProfileData) { 1259 if (fProfileData) {
1218 return fProfileData; 1260 return fProfileData;
1219 } 1261 }
1262 // Profile Data is be mandatory for A2B0 Color Spaces
1263 SkASSERT(type() == Type::kXYZ);
1220 1264
1221 // The client may create an SkColorSpace using an SkMatrix44, but currently we only 1265 // The client may create an SkColorSpace using an SkMatrix44, but currently we only
1222 // support writing profiles with 3x3 matrices. 1266 // support writing profiles with 3x3 matrices.
1223 // TODO (msarett): Fix this! 1267 // TODO (msarett): Fix this!
1224 if (0.0f != fToXYZD50.getFloat(3, 0) || 0.0f != fToXYZD50.getFloat(3, 1) || 1268 const SkColorSpace_XYZ* thisXYZ = static_cast<const SkColorSpace_XYZ*>(this) ;
1225 0.0f != fToXYZD50.getFloat(3, 2) || 0.0f != fToXYZD50.getFloat(0, 3) || 1269 const SkMatrix44& toXYZD50 = *thisXYZ->toXYZD50();
1226 0.0f != fToXYZD50.getFloat(1, 3) || 0.0f != fToXYZD50.getFloat(2, 3)) 1270 if (0.0f != toXYZD50.getFloat(3, 0) || 0.0f != toXYZD50.getFloat(3, 1) ||
1271 0.0f != toXYZD50.getFloat(3, 2) || 0.0f != toXYZD50.getFloat(0, 3) ||
1272 0.0f != toXYZD50.getFloat(1, 3) || 0.0f != toXYZD50.getFloat(2, 3))
1227 { 1273 {
1228 return nullptr; 1274 return nullptr;
1229 } 1275 }
1230 1276
1231 SkAutoMalloc profile(kICCProfileSize); 1277 SkAutoMalloc profile(kICCProfileSize);
1232 uint8_t* ptr = (uint8_t*) profile.get(); 1278 uint8_t* ptr = (uint8_t*) profile.get();
1233 1279
1234 // Write profile header 1280 // Write profile header
1235 memcpy(ptr, gICCHeader, sizeof(gICCHeader)); 1281 memcpy(ptr, gICCHeader, sizeof(gICCHeader));
1236 ptr += sizeof(gICCHeader); 1282 ptr += sizeof(gICCHeader);
1237 1283
1238 // Write tag table 1284 // Write tag table
1239 memcpy(ptr, gICCTagTable, sizeof(gICCTagTable)); 1285 memcpy(ptr, gICCTagTable, sizeof(gICCTagTable));
1240 ptr += sizeof(gICCTagTable); 1286 ptr += sizeof(gICCTagTable);
1241 1287
1242 // Write profile description tag 1288 // Write profile description tag
1243 memcpy(ptr, gEmptyTextTag, sizeof(gEmptyTextTag)); 1289 memcpy(ptr, gEmptyTextTag, sizeof(gEmptyTextTag));
1244 ptr += sizeof(gEmptyTextTag); 1290 ptr += sizeof(gEmptyTextTag);
1245 1291
1246 // Write XYZ tags 1292 // Write XYZ tags
1247 write_xyz_tag((uint32_t*) ptr, fToXYZD50, 0); 1293 write_xyz_tag((uint32_t*) ptr, toXYZD50, 0);
1248 ptr += kTAG_XYZ_Bytes; 1294 ptr += kTAG_XYZ_Bytes;
1249 write_xyz_tag((uint32_t*) ptr, fToXYZD50, 1); 1295 write_xyz_tag((uint32_t*) ptr, toXYZD50, 1);
1250 ptr += kTAG_XYZ_Bytes; 1296 ptr += kTAG_XYZ_Bytes;
1251 write_xyz_tag((uint32_t*) ptr, fToXYZD50, 2); 1297 write_xyz_tag((uint32_t*) ptr, toXYZD50, 2);
1252 ptr += kTAG_XYZ_Bytes; 1298 ptr += kTAG_XYZ_Bytes;
1253 1299
1254 // Write TRC tags 1300 // Write TRC tags
1255 SkGammaNamed gammaNamed = this->gammaNamed(); 1301 SkGammaNamed gammaNamed = thisXYZ->gammaNamed();
1256 if (kNonStandard_SkGammaNamed == gammaNamed) { 1302 if (kNonStandard_SkGammaNamed == gammaNamed) {
1257 // FIXME (msarett): 1303 // FIXME (msarett):
1258 // Write the correct gamma representation rather than 2.2f. 1304 // Write the correct gamma representation rather than 2.2f.
1259 write_trc_tag((uint32_t*) ptr, 2.2f); 1305 write_trc_tag((uint32_t*) ptr, 2.2f);
1260 ptr += SkAlign4(kTAG_TRC_Bytes); 1306 ptr += SkAlign4(kTAG_TRC_Bytes);
1261 write_trc_tag((uint32_t*) ptr, 2.2f); 1307 write_trc_tag((uint32_t*) ptr, 2.2f);
1262 ptr += SkAlign4(kTAG_TRC_Bytes); 1308 ptr += SkAlign4(kTAG_TRC_Bytes);
1263 write_trc_tag((uint32_t*) ptr, 2.2f); 1309 write_trc_tag((uint32_t*) ptr, 2.2f);
1264 ptr += SkAlign4(kTAG_TRC_Bytes); 1310 ptr += SkAlign4(kTAG_TRC_Bytes);
1265 } else { 1311 } else {
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
1302 ptr32[4] = SkEndian_SwapBE32(0x000116cc); 1348 ptr32[4] = SkEndian_SwapBE32(0x000116cc);
1303 ptr += kTAG_XYZ_Bytes; 1349 ptr += kTAG_XYZ_Bytes;
1304 1350
1305 // Write copyright tag 1351 // Write copyright tag
1306 memcpy(ptr, gEmptyTextTag, sizeof(gEmptyTextTag)); 1352 memcpy(ptr, gEmptyTextTag, sizeof(gEmptyTextTag));
1307 1353
1308 // TODO (msarett): Should we try to hold onto the data so we can return imme diately if 1354 // TODO (msarett): Should we try to hold onto the data so we can return imme diately if
1309 // the client calls again? 1355 // the client calls again?
1310 return SkData::MakeFromMalloc(profile.release(), kICCProfileSize); 1356 return SkData::MakeFromMalloc(profile.release(), kICCProfileSize);
1311 } 1357 }
OLDNEW
« no previous file with comments | « src/core/SkColorSpace_Base.h ('k') | src/core/SkColorSpace_XYZ.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698