Index: src/core/SkColorSpace.cpp |
diff --git a/src/core/SkColorSpace.cpp b/src/core/SkColorSpace.cpp |
index 0a543bb83937bfa0dbbcfa3af5e5d06e08b5e60c..ca63b5e16108e2015af2f67585d89fd83497a071 100644 |
--- a/src/core/SkColorSpace.cpp |
+++ b/src/core/SkColorSpace.cpp |
@@ -7,6 +7,7 @@ |
#include "SkColorSpace.h" |
#include "SkColorSpace_Base.h" |
+#include "SkEndian.h" |
#include "SkOnce.h" |
static bool color_space_almost_equal(float a, float b) { |
@@ -22,31 +23,35 @@ SkColorSpace::SkColorSpace(GammaNamed gammaNamed, const SkMatrix44& toXYZD50, Na |
{} |
SkColorSpace_Base::SkColorSpace_Base(sk_sp<SkGammas> gammas, const SkMatrix44& toXYZD50, |
- Named named) |
+ Named named, sk_sp<SkData> profileData) |
: INHERITED(kNonStandard_GammaNamed, toXYZD50, named) |
, fGammas(std::move(gammas)) |
+ , fProfileData(std::move(profileData)) |
{} |
SkColorSpace_Base::SkColorSpace_Base(sk_sp<SkGammas> gammas, GammaNamed gammaNamed, |
- const SkMatrix44& toXYZD50, Named named) |
+ const SkMatrix44& toXYZD50, Named named, |
+ sk_sp<SkData> profileData) |
: INHERITED(gammaNamed, toXYZD50, named) |
, fGammas(std::move(gammas)) |
+ , fProfileData(std::move(profileData)) |
{} |
SkColorSpace_Base::SkColorSpace_Base(SkColorLookUpTable* colorLUT, sk_sp<SkGammas> gammas, |
- const SkMatrix44& toXYZD50) |
+ const SkMatrix44& toXYZD50, sk_sp<SkData> profileData) |
: INHERITED(kNonStandard_GammaNamed, toXYZD50, kUnknown_Named) |
, fColorLUT(colorLUT) |
, fGammas(std::move(gammas)) |
+ , fProfileData(std::move(profileData)) |
{} |
-const float gSRGB_toXYZD50[] { |
+static constexpr float gSRGB_toXYZD50[] { |
0.4358f, 0.2224f, 0.0139f, // * R |
0.3853f, 0.7170f, 0.0971f, // * G |
0.1430f, 0.0606f, 0.7139f, // * B |
}; |
-const float gAdobeRGB_toXYZD50[] { |
+static constexpr float gAdobeRGB_toXYZD50[] { |
0.6098f, 0.3111f, 0.0195f, // * R |
0.2052f, 0.6257f, 0.0609f, // * G |
0.1492f, 0.0632f, 0.7448f, // * B |
@@ -83,6 +88,11 @@ static SkOnce gLinearGammasOnce; |
static SkGammas* gLinearGammas; |
sk_sp<SkColorSpace> SkColorSpace::NewRGB(const float gammaVals[3], const SkMatrix44& toXYZD50) { |
+ return SkColorSpace_Base::NewRGB(gammaVals, toXYZD50, nullptr); |
+} |
+ |
+sk_sp<SkColorSpace> SkColorSpace_Base::NewRGB(const float gammaVals[3], const SkMatrix44& toXYZD50, |
+ sk_sp<SkData> profileData) { |
sk_sp<SkGammas> gammas = nullptr; |
GammaNamed gammaNamed = kNonStandard_GammaNamed; |
@@ -116,7 +126,8 @@ sk_sp<SkColorSpace> SkColorSpace::NewRGB(const float gammaVals[3], const SkMatri |
if (!gammas) { |
gammas = sk_sp<SkGammas>(new SkGammas(gammaVals[0], gammaVals[1], gammaVals[2])); |
} |
- return sk_sp<SkColorSpace>(new SkColorSpace_Base(gammas, gammaNamed, toXYZD50, kUnknown_Named)); |
+ return sk_sp<SkColorSpace>(new SkColorSpace_Base(gammas, gammaNamed, toXYZD50, kUnknown_Named, |
+ std::move(profileData))); |
} |
sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) { |
@@ -135,7 +146,7 @@ sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) { |
SkMatrix44 srgbToxyzD50(SkMatrix44::kUninitialized_Constructor); |
srgbToxyzD50.set3x3ColMajorf(gSRGB_toXYZD50); |
sRGB = new SkColorSpace_Base(sk_ref_sp(g2Dot2CurveGammas), k2Dot2Curve_GammaNamed, |
- srgbToxyzD50, kSRGB_Named); |
+ srgbToxyzD50, kSRGB_Named, nullptr); |
}); |
return sk_ref_sp(sRGB); |
} |
@@ -149,7 +160,7 @@ sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) { |
adobergbToxyzD50.set3x3ColMajorf(gAdobeRGB_toXYZD50); |
adobeRGB = new SkColorSpace_Base(sk_ref_sp(g2Dot2CurveGammas), |
k2Dot2Curve_GammaNamed, adobergbToxyzD50, |
- kAdobeRGB_Named); |
+ kAdobeRGB_Named, nullptr); |
}); |
return sk_ref_sp(adobeRGB); |
} |
@@ -195,12 +206,17 @@ static int32_t read_big_endian_int(const uint8_t* ptr) { |
// This is equal to the header size according to the ICC specification (128) |
// plus the size of the tag count (4). We include the tag count since we |
// always require it to be present anyway. |
-static const size_t kICCHeaderSize = 132; |
+static constexpr size_t kICCHeaderSize = 132; |
// Contains a signature (4), offset (4), and size (4). |
-static const size_t kICCTagTableEntrySize = 12; |
+static constexpr size_t kICCTagTableEntrySize = 12; |
-static const uint32_t kRGB_ColorSpace = SkSetFourByteTag('R', 'G', 'B', ' '); |
+static constexpr uint32_t kRGB_ColorSpace = SkSetFourByteTag('R', 'G', 'B', ' '); |
+static constexpr uint32_t kDisplay_Profile = SkSetFourByteTag('m', 'n', 't', 'r'); |
+static constexpr uint32_t kInput_Profile = SkSetFourByteTag('s', 'c', 'n', 'r'); |
+static constexpr uint32_t kOutput_Profile = SkSetFourByteTag('p', 'r', 't', 'r'); |
+static constexpr uint32_t kXYZ_PCSSpace = SkSetFourByteTag('X', 'Y', 'Z', ' '); |
+static constexpr uint32_t kACSP_Signature = SkSetFourByteTag('a', 'c', 's', 'p'); |
struct ICCProfileHeader { |
uint32_t fSize; |
@@ -266,9 +282,6 @@ struct ICCProfileHeader { |
// These are the three basic classes of profiles that we might expect to see embedded |
// in images. Four additional classes exist, but they generally are used as a convenient |
// way for CMMs to store calculated transforms. |
- const uint32_t kDisplay_Profile = SkSetFourByteTag('m', 'n', 't', 'r'); |
- const uint32_t kInput_Profile = SkSetFourByteTag('s', 'c', 'n', 'r'); |
- const uint32_t kOutput_Profile = SkSetFourByteTag('p', 'r', 't', 'r'); |
return_if_false(fProfileClass == kDisplay_Profile || |
fProfileClass == kInput_Profile || |
fProfileClass == kOutput_Profile, |
@@ -280,10 +293,9 @@ struct ICCProfileHeader { |
// TODO (msarett): |
// All the profiles we've tested so far use XYZ as the profile connection space. |
- const uint32_t kXYZ_PCSSpace = SkSetFourByteTag('X', 'Y', 'Z', ' '); |
return_if_false(fPCS == kXYZ_PCSSpace, "Unsupported PCS space"); |
- return_if_false(fSignature == SkSetFourByteTag('a', 'c', 's', 'p'), "Bad signature"); |
+ return_if_false(fSignature == kACSP_Signature, "Bad signature"); |
// TODO (msarett): |
// Should we treat different rendering intents differently? |
@@ -333,13 +345,13 @@ struct ICCTag { |
} |
}; |
-static const uint32_t kTAG_rXYZ = SkSetFourByteTag('r', 'X', 'Y', 'Z'); |
-static const uint32_t kTAG_gXYZ = SkSetFourByteTag('g', 'X', 'Y', 'Z'); |
-static const uint32_t kTAG_bXYZ = SkSetFourByteTag('b', 'X', 'Y', 'Z'); |
-static const uint32_t kTAG_rTRC = SkSetFourByteTag('r', 'T', 'R', 'C'); |
-static const uint32_t kTAG_gTRC = SkSetFourByteTag('g', 'T', 'R', 'C'); |
-static const uint32_t kTAG_bTRC = SkSetFourByteTag('b', 'T', 'R', 'C'); |
-static const uint32_t kTAG_A2B0 = SkSetFourByteTag('A', '2', 'B', '0'); |
+static constexpr uint32_t kTAG_rXYZ = SkSetFourByteTag('r', 'X', 'Y', 'Z'); |
+static constexpr uint32_t kTAG_gXYZ = SkSetFourByteTag('g', 'X', 'Y', 'Z'); |
+static constexpr uint32_t kTAG_bXYZ = SkSetFourByteTag('b', 'X', 'Y', 'Z'); |
+static constexpr uint32_t kTAG_rTRC = SkSetFourByteTag('r', 'T', 'R', 'C'); |
+static constexpr uint32_t kTAG_gTRC = SkSetFourByteTag('g', 'T', 'R', 'C'); |
+static constexpr uint32_t kTAG_bTRC = SkSetFourByteTag('b', 'T', 'R', 'C'); |
+static constexpr uint32_t kTAG_A2B0 = SkSetFourByteTag('A', '2', 'B', '0'); |
bool load_xyz(float dst[3], const uint8_t* src, size_t len) { |
if (len < 20) { |
@@ -354,8 +366,8 @@ bool load_xyz(float dst[3], const uint8_t* src, size_t len) { |
return true; |
} |
-static const uint32_t kTAG_CurveType = SkSetFourByteTag('c', 'u', 'r', 'v'); |
-static const uint32_t kTAG_ParaCurveType = SkSetFourByteTag('p', 'a', 'r', 'a'); |
+static constexpr uint32_t kTAG_CurveType = SkSetFourByteTag('c', 'u', 'r', 'v'); |
+static constexpr uint32_t kTAG_ParaCurveType = SkSetFourByteTag('p', 'a', 'r', 'a'); |
bool load_gammas(SkGammaCurve* gammas, uint32_t numGammas, const uint8_t* src, size_t len) { |
for (uint32_t i = 0; i < numGammas; i++) { |
@@ -563,7 +575,7 @@ bool load_gammas(SkGammaCurve* gammas, uint32_t numGammas, const uint8_t* src, s |
return true; |
} |
-static const uint32_t kTAG_AtoBType = SkSetFourByteTag('m', 'A', 'B', ' '); |
+static constexpr uint32_t kTAG_AtoBType = SkSetFourByteTag('m', 'A', 'B', ' '); |
bool load_color_lut(SkColorLookUpTable* colorLUT, uint32_t inputChannels, uint32_t outputChannels, |
const uint8_t* src, size_t len) { |
@@ -705,13 +717,18 @@ bool load_a2b0(SkColorLookUpTable* colorLUT, SkGammaCurve* gammas, SkMatrix44* t |
return true; |
} |
-sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* base, size_t len) { |
- const uint8_t* ptr = (const uint8_t*) base; |
- |
+sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* input, size_t len) { |
if (len < kICCHeaderSize) { |
return_null("Data is not large enough to contain an ICC profile"); |
} |
+ // Create our own copy of the input. |
+ void* memory = sk_malloc_throw(len); |
+ memcpy(memory, input, len); |
+ sk_sp<SkData> data = SkData::MakeFromMalloc(memory, len); |
+ const void* base = data->data(); |
+ const uint8_t* ptr = (const uint8_t*) base; |
+ |
// Read the ICC profile header and check to make sure that it is valid. |
ICCProfileHeader header; |
header.init(ptr, len); |
@@ -793,10 +810,11 @@ sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* base, size_t len) { |
gammaVals[0] = gammas->fRed.fValue; |
gammaVals[1] = gammas->fGreen.fValue; |
gammaVals[2] = gammas->fBlue.fValue; |
- return SkColorSpace::NewRGB(gammaVals, mat); |
+ return SkColorSpace_Base::NewRGB(gammaVals, mat, std::move(data)); |
} else { |
return sk_sp<SkColorSpace>(new SkColorSpace_Base(std::move(gammas), mat, |
- kUnknown_Named)); |
+ kUnknown_Named, |
+ std::move(data))); |
} |
} |
@@ -815,7 +833,8 @@ sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* base, size_t len) { |
std::move(curves[2]))); |
if (colorLUT->fTable) { |
return sk_sp<SkColorSpace>(new SkColorSpace_Base(colorLUT.release(), |
- std::move(gammas), toXYZ)); |
+ std::move(gammas), toXYZ, |
+ std::move(data))); |
} else if (gammas->isValues()) { |
// When we have values, take advantage of the NewFromRGB initializer. |
// This allows us to check for canonical sRGB and Adobe RGB. |
@@ -823,10 +842,11 @@ sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* base, size_t len) { |
gammaVals[0] = gammas->fRed.fValue; |
gammaVals[1] = gammas->fGreen.fValue; |
gammaVals[2] = gammas->fBlue.fValue; |
- return SkColorSpace::NewRGB(gammaVals, toXYZ); |
+ return SkColorSpace_Base::NewRGB(gammaVals, toXYZ, std::move(data)); |
} else { |
return sk_sp<SkColorSpace>(new SkColorSpace_Base(std::move(gammas), toXYZ, |
- kUnknown_Named)); |
+ kUnknown_Named, |
+ std::move(data))); |
} |
} |
} |
@@ -836,3 +856,202 @@ sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* base, size_t len) { |
return_null("ICC profile contains unsupported colorspace"); |
} |
+ |
+/////////////////////////////////////////////////////////////////////////////////////////////////// |
+ |
+// We will write a profile with the minimum nine required tags. |
+static constexpr uint32_t kICCNumEntries = 9; |
+ |
+static constexpr uint32_t kTAG_desc = SkSetFourByteTag('d', 'e', 's', 'c'); |
+static constexpr uint32_t kTAG_desc_Bytes = 12; |
+static constexpr uint32_t kTAG_desc_Offset = kICCHeaderSize + kICCNumEntries*kICCTagTableEntrySize; |
+ |
+static constexpr uint32_t kTAG_XYZ_Bytes = 20; |
+static constexpr uint32_t kTAG_rXYZ_Offset = kTAG_desc_Offset + kTAG_desc_Bytes; |
+static constexpr uint32_t kTAG_gXYZ_Offset = kTAG_rXYZ_Offset + kTAG_XYZ_Bytes; |
+static constexpr uint32_t kTAG_bXYZ_Offset = kTAG_gXYZ_Offset + kTAG_XYZ_Bytes; |
+ |
+static constexpr uint32_t kTAG_TRC_Bytes = 14; |
+static constexpr uint32_t kTAG_rTRC_Offset = kTAG_bXYZ_Offset + kTAG_XYZ_Bytes; |
+static constexpr uint32_t kTAG_gTRC_Offset = kTAG_rTRC_Offset + SkAlign4(kTAG_TRC_Bytes); |
+static constexpr uint32_t kTAG_bTRC_Offset = kTAG_gTRC_Offset + SkAlign4(kTAG_TRC_Bytes); |
+ |
+static constexpr uint32_t kTAG_wtpt = SkSetFourByteTag('w', 't', 'p', 't'); |
+static constexpr uint32_t kTAG_wtpt_Offset = kTAG_bTRC_Offset + SkAlign4(kTAG_TRC_Bytes); |
+ |
+static constexpr uint32_t kTAG_cprt = SkSetFourByteTag('c', 'p', 'r', 't'); |
+static constexpr uint32_t kTAG_cprt_Bytes = 12; |
+static constexpr uint32_t kTAG_cprt_Offset = kTAG_wtpt_Offset + kTAG_XYZ_Bytes; |
+ |
+static constexpr uint32_t kICCProfileSize = kTAG_cprt_Offset + kTAG_cprt_Bytes; |
+ |
+static constexpr uint32_t gICCHeader[kICCHeaderSize / 4] { |
+ SkEndian_SwapBE32(kICCProfileSize), // Size of the profile |
+ 0, // Preferred CMM type (ignored) |
+ SkEndian_SwapBE32(0x02100000), // Version 2.1 |
+ SkEndian_SwapBE32(kDisplay_Profile), // Display device profile |
+ SkEndian_SwapBE32(kRGB_ColorSpace), // RGB input color space |
+ SkEndian_SwapBE32(kXYZ_PCSSpace), // XYZ profile connection space |
+ 0, 0, 0, // Date and time (ignored) |
+ SkEndian_SwapBE32(kACSP_Signature), // Profile signature |
+ 0, // Platform target (ignored) |
+ 0x00000000, // Flags: not embedded, can be used independently |
+ 0, // Device manufacturer (ignored) |
+ 0, // Device model (ignored) |
+ 0, 0, // Device attributes (ignored) |
+ SkEndian_SwapBE32(1), // Relative colorimetric rendering intent |
+ SkEndian_SwapBE32(0x0000f6d6), // D50 standard illuminant (X) |
+ SkEndian_SwapBE32(0x00010000), // D50 standard illuminant (Y) |
+ SkEndian_SwapBE32(0x0000d32d), // D50 standard illuminant (Z) |
+ 0, // Profile creator (ignored) |
+ 0, 0, 0, 0, // Profile id checksum (ignored) |
+ 0, 0, 0, 0, 0, 0, 0, // Reserved (ignored) |
+ SkEndian_SwapBE32(kICCNumEntries), // Number of tags |
+}; |
+ |
+static constexpr uint32_t gICCTagTable[3 * kICCNumEntries] { |
+ // Profile description |
+ SkEndian_SwapBE32(kTAG_desc), |
+ SkEndian_SwapBE32(kTAG_desc_Offset), |
+ SkEndian_SwapBE32(kTAG_desc_Bytes), |
+ |
+ // rXYZ |
+ SkEndian_SwapBE32(kTAG_rXYZ), |
+ SkEndian_SwapBE32(kTAG_rXYZ_Offset), |
+ SkEndian_SwapBE32(kTAG_XYZ_Bytes), |
+ |
+ // gXYZ |
+ SkEndian_SwapBE32(kTAG_gXYZ), |
+ SkEndian_SwapBE32(kTAG_gXYZ_Offset), |
+ SkEndian_SwapBE32(kTAG_XYZ_Bytes), |
+ |
+ // bXYZ |
+ SkEndian_SwapBE32(kTAG_bXYZ), |
+ SkEndian_SwapBE32(kTAG_bXYZ_Offset), |
+ SkEndian_SwapBE32(kTAG_XYZ_Bytes), |
+ |
+ // rTRC |
+ SkEndian_SwapBE32(kTAG_rTRC), |
+ SkEndian_SwapBE32(kTAG_rTRC_Offset), |
+ SkEndian_SwapBE32(kTAG_TRC_Bytes), |
+ |
+ // gTRC |
+ SkEndian_SwapBE32(kTAG_gTRC), |
+ SkEndian_SwapBE32(kTAG_gTRC_Offset), |
+ SkEndian_SwapBE32(kTAG_TRC_Bytes), |
+ |
+ // bTRC |
+ SkEndian_SwapBE32(kTAG_bTRC), |
+ SkEndian_SwapBE32(kTAG_bTRC_Offset), |
+ SkEndian_SwapBE32(kTAG_TRC_Bytes), |
+ |
+ // White point |
+ SkEndian_SwapBE32(kTAG_wtpt), |
+ SkEndian_SwapBE32(kTAG_wtpt_Offset), |
+ SkEndian_SwapBE32(kTAG_XYZ_Bytes), |
+ |
+ // Copyright |
+ SkEndian_SwapBE32(kTAG_cprt), |
+ SkEndian_SwapBE32(kTAG_cprt_Offset), |
+ SkEndian_SwapBE32(kTAG_cprt_Bytes), |
+}; |
+ |
+static constexpr uint32_t kTAG_TextType = SkSetFourByteTag('m', 'l', 'u', 'c'); |
+static constexpr uint32_t gEmptyTextTag[3] { |
+ SkEndian_SwapBE32(kTAG_TextType), // Type signature |
+ 0, // Reserved |
+ 0, // Zero records |
+}; |
+ |
+static void write_xyz_tag(uint32_t* ptr, const SkMatrix44& toXYZ, int row) { |
+ ptr[0] = SkEndian_SwapBE32(kXYZ_PCSSpace); |
+ ptr[1] = 0; |
+ ptr[2] = SkEndian_SwapBE32(SkFloatToFixed(toXYZ.getFloat(row, 0))); |
+ ptr[3] = SkEndian_SwapBE32(SkFloatToFixed(toXYZ.getFloat(row, 1))); |
+ ptr[4] = SkEndian_SwapBE32(SkFloatToFixed(toXYZ.getFloat(row, 2))); |
+} |
+ |
+static void write_trc_tag(uint32_t* ptr, float value) { |
+ ptr[0] = SkEndian_SwapBE32(kTAG_CurveType); |
+ ptr[1] = 0; |
+ |
+ // Gamma will be specified with a single value. |
+ ptr[2] = SkEndian_SwapBE32(1); |
+ |
+ // Convert gamma to 16-bit fixed point. |
+ uint16_t* ptr16 = (uint16_t*) (ptr + 3); |
+ ptr16[0] = SkEndian_SwapBE16((uint16_t) (value * 256.0f)); |
+ |
+ // Pad tag with zero. |
+ ptr16[1] = 0; |
+} |
+ |
+sk_sp<SkData> SkColorSpace_Base::writeToICC() const { |
+ // Return if this object was created from a profile, or if we have already serialized |
+ // the profile. |
+ if (fProfileData) { |
+ return fProfileData; |
+ } |
+ |
+ // The client may create an SkColorSpace using an SkMatrix44, but currently we only |
+ // support writing profiles with 3x3 matrices. |
+ // TODO (msarett): Fix this! |
+ if (0.0f != fToXYZD50.getFloat(3, 0) || 0.0f != fToXYZD50.getFloat(3, 1) || |
+ 0.0f != fToXYZD50.getFloat(3, 2) || 0.0f != fToXYZD50.getFloat(0, 3) || |
+ 0.0f != fToXYZD50.getFloat(1, 3) || 0.0f != fToXYZD50.getFloat(2, 3)) |
+ { |
+ return nullptr; |
+ } |
+ |
+ SkAutoMalloc profile(kICCProfileSize); |
+ uint8_t* ptr = (uint8_t*) profile.get(); |
+ |
+ // Write profile header |
+ memcpy(ptr, gICCHeader, sizeof(gICCHeader)); |
+ ptr += sizeof(gICCHeader); |
+ |
+ // Write tag table |
+ memcpy(ptr, gICCTagTable, sizeof(gICCTagTable)); |
+ ptr += sizeof(gICCTagTable); |
+ |
+ // Write profile description tag |
+ memcpy(ptr, gEmptyTextTag, sizeof(gEmptyTextTag)); |
+ ptr += sizeof(gEmptyTextTag); |
+ |
+ // Write XYZ tags |
+ write_xyz_tag((uint32_t*) ptr, fToXYZD50, 0); |
+ ptr += kTAG_XYZ_Bytes; |
+ write_xyz_tag((uint32_t*) ptr, fToXYZD50, 1); |
+ ptr += kTAG_XYZ_Bytes; |
+ write_xyz_tag((uint32_t*) ptr, fToXYZD50, 2); |
+ ptr += kTAG_XYZ_Bytes; |
+ |
+ // Write TRC tags |
+ SkASSERT(as_CSB(this)->fGammas->fRed.isValue()); |
+ write_trc_tag((uint32_t*) ptr, as_CSB(this)->fGammas->fRed.fValue); |
+ ptr += SkAlign4(kTAG_TRC_Bytes); |
+ SkASSERT(as_CSB(this)->fGammas->fGreen.isValue()); |
+ write_trc_tag((uint32_t*) ptr, as_CSB(this)->fGammas->fGreen.fValue); |
+ ptr += SkAlign4(kTAG_TRC_Bytes); |
+ SkASSERT(as_CSB(this)->fGammas->fBlue.isValue()); |
+ write_trc_tag((uint32_t*) ptr, as_CSB(this)->fGammas->fBlue.fValue); |
+ ptr += SkAlign4(kTAG_TRC_Bytes); |
+ |
+ // Write white point tag |
+ uint32_t* ptr32 = (uint32_t*) ptr; |
+ ptr32[0] = SkEndian_SwapBE32(kXYZ_PCSSpace); |
+ ptr32[1] = 0; |
+ // TODO (msarett): These values correspond to the D65 white point. This may not always be |
+ // correct. |
+ ptr32[2] = SkEndian_SwapBE32(0x0000f351); |
+ ptr32[3] = SkEndian_SwapBE32(0x00010000); |
+ ptr32[4] = SkEndian_SwapBE32(0x000116cc); |
+ ptr += kTAG_XYZ_Bytes; |
+ |
+ // Write copyright tag |
+ memcpy(ptr, gEmptyTextTag, sizeof(gEmptyTextTag)); |
+ |
+ // TODO (msarett): Should we try to hold onto the data so we can return immediately if |
+ // the client calls again? |
+ return SkData::MakeFromMalloc(profile.release(), kICCProfileSize); |
+} |