diff options
author | 2016-06-22 08:18:54 -0700 | |
---|---|---|
committer | 2016-06-22 08:18:54 -0700 | |
commit | 111a42d9cebf0bb8844c5d24f67fac57cc619d29 (patch) | |
tree | ce93848c7176621f02b2ced77d56572932ebd4e4 /src | |
parent | 05dceabf3422b785b52439378aa5527c42c6ca18 (diff) |
Enable flattening and unflattening of SkColorSpace
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2085653003
Review-Url: https://codereview.chromium.org/2085653003
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkColorSpace.cpp | 175 | ||||
-rw-r--r-- | src/core/SkColorSpace_Base.h | 6 | ||||
-rw-r--r-- | src/core/SkImageInfo.cpp | 79 | ||||
-rw-r--r-- | src/core/SkMatrix44.cpp | 19 |
4 files changed, 196 insertions, 83 deletions
diff --git a/src/core/SkColorSpace.cpp b/src/core/SkColorSpace.cpp index 5df45fff41..95c38f2263 100644 --- a/src/core/SkColorSpace.cpp +++ b/src/core/SkColorSpace.cpp @@ -9,6 +9,8 @@ #include "SkColorSpace_Base.h" #include "SkEndian.h" #include "SkOnce.h" +#include "SkReadBuffer.h" +#include "SkWriteBuffer.h" #define SkColorSpacePrintf(...) @@ -24,11 +26,10 @@ SkColorSpace::SkColorSpace(GammaNamed gammaNamed, const SkMatrix44& toXYZD50, Na , fNamed(named) {} -SkColorSpace_Base::SkColorSpace_Base(GammaNamed gammaNamed, const SkMatrix44& toXYZD50, Named named, - sk_sp<SkData> profileData) +SkColorSpace_Base::SkColorSpace_Base(GammaNamed gammaNamed, const SkMatrix44& toXYZD50, Named named) : INHERITED(gammaNamed, toXYZD50, named) , fGammas(nullptr) - , fProfileData(std::move(profileData)) + , fProfileData(nullptr) {} SkColorSpace_Base::SkColorSpace_Base(SkColorLookUpTable* colorLUT, sk_sp<SkGammas> gammas, @@ -102,11 +103,10 @@ sk_sp<SkColorSpace> SkColorSpace_Base::NewRGB(float values[3], const SkMatrix44& return sk_sp<SkColorSpace>(new SkColorSpace_Base(nullptr, gammas, toXYZD50, nullptr)); } - return SkColorSpace_Base::NewRGB(gammaNamed, toXYZD50, nullptr); + return SkColorSpace_Base::NewRGB(gammaNamed, toXYZD50); } -sk_sp<SkColorSpace> SkColorSpace_Base::NewRGB(GammaNamed gammaNamed, const SkMatrix44& toXYZD50, - sk_sp<SkData> profileData) { +sk_sp<SkColorSpace> SkColorSpace_Base::NewRGB(GammaNamed gammaNamed, const SkMatrix44& toXYZD50) { switch (gammaNamed) { case kSRGB_GammaNamed: if (xyz_almost_equal(toXYZD50, gSRGB_toXYZD50)) { @@ -125,12 +125,11 @@ sk_sp<SkColorSpace> SkColorSpace_Base::NewRGB(GammaNamed gammaNamed, const SkMat break; } - return sk_sp<SkColorSpace>(new SkColorSpace_Base(gammaNamed, toXYZD50, kUnknown_Named, - profileData)); + return sk_sp<SkColorSpace>(new SkColorSpace_Base(gammaNamed, toXYZD50, kUnknown_Named)); } sk_sp<SkColorSpace> SkColorSpace::NewRGB(GammaNamed gammaNamed, const SkMatrix44& toXYZD50) { - return SkColorSpace_Base::NewRGB(gammaNamed, toXYZD50, nullptr); + return SkColorSpace_Base::NewRGB(gammaNamed, toXYZD50); } sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) { @@ -144,7 +143,7 @@ sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) { sRGBOnce([] { SkMatrix44 srgbToxyzD50(SkMatrix44::kUninitialized_Constructor); srgbToxyzD50.set3x3ColMajorf(gSRGB_toXYZD50); - sRGB = new SkColorSpace_Base(kSRGB_GammaNamed, srgbToxyzD50, kSRGB_Named, nullptr); + sRGB = new SkColorSpace_Base(kSRGB_GammaNamed, srgbToxyzD50, kSRGB_Named); }); return sk_ref_sp(sRGB); } @@ -153,7 +152,7 @@ sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) { SkMatrix44 adobergbToxyzD50(SkMatrix44::kUninitialized_Constructor); adobergbToxyzD50.set3x3ColMajorf(gAdobeRGB_toXYZD50); adobeRGB = new SkColorSpace_Base(k2Dot2Curve_GammaNamed, adobergbToxyzD50, - kAdobeRGB_Named, nullptr); + kAdobeRGB_Named); }); return sk_ref_sp(adobeRGB); } @@ -930,7 +929,7 @@ sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* input, size_t len) { return sk_sp<SkColorSpace>(new SkColorSpace_Base(nullptr, std::move(gammas), mat, std::move(data))); } else { - return SkColorSpace_Base::NewRGB(gammaNamed, mat, std::move(data)); + return SkColorSpace_Base::NewRGB(gammaNamed, mat); } } @@ -955,7 +954,7 @@ sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* input, size_t len) { std::move(gammas), toXYZ, std::move(data))); } else { - return SkColorSpace_Base::NewRGB(gammaNamed, toXYZ, std::move(data)); + return SkColorSpace_Base::NewRGB(gammaNamed, toXYZ); } } } @@ -1208,3 +1207,153 @@ sk_sp<SkData> SkColorSpace_Base::writeToICC() const { // the client calls again? return SkData::MakeFromMalloc(profile.release(), kICCProfileSize); } + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +enum Version { + k0_Version, // Initial version, header + flags for matrix and profile +}; + +struct ColorSpaceHeader { + /** + * If kMatrix_Flag is set, we will write 12 floats after the header. + * Should not be set at the same time as the kICC_Flag. + */ + static constexpr uint8_t kMatrix_Flag = 1 << 0; + + /** + * If kICC_Flag is set, we will write an ICC profile after the header. + * The ICC profile will be written as a uint32 size, followed immediately + * by the data (padded to 4 bytes). + * Should not be set at the same time as the kMatrix_Flag. + */ + static constexpr uint8_t kICC_Flag = 1 << 1; + + static ColorSpaceHeader Pack(Version version, SkColorSpace::Named named, + SkColorSpace::GammaNamed gammaNamed, uint8_t flags) { + ColorSpaceHeader header; + + SkASSERT(k0_Version == version); + header.fVersion = (uint8_t) version; + + SkASSERT(named <= SkColorSpace::kAdobeRGB_Named); + header.fNamed = (uint8_t) named; + + SkASSERT(gammaNamed <= SkColorSpace::kNonStandard_GammaNamed); + header.fGammaNamed = (uint8_t) gammaNamed; + + SkASSERT(flags <= kICC_Flag); + header.fFlags = flags; + return header; + } + + uint8_t fVersion; // Always zero + uint8_t fNamed; // Must be a SkColorSpace::Named + uint8_t fGammaNamed; // Must be a SkColorSpace::GammaNamed + uint8_t fFlags; // Some combination of the flags listed above +}; + +sk_sp<SkData> SkColorSpace::serialize() const { + // If we have a named profile, only write the enum. + switch (fNamed) { + case kSRGB_Named: + case kAdobeRGB_Named: { + sk_sp<SkData> data = SkData::MakeUninitialized(sizeof(ColorSpaceHeader)); + *((ColorSpaceHeader*) data->writable_data()) = + ColorSpaceHeader::Pack(k0_Version, fNamed, fGammaNamed, 0); + return data; + } + default: + break; + } + + // If we have a named gamma, write the enum and the matrix. + switch (fGammaNamed) { + case kSRGB_GammaNamed: + case k2Dot2Curve_GammaNamed: + case kLinear_GammaNamed: { + sk_sp<SkData> data = SkData::MakeUninitialized(sizeof(ColorSpaceHeader) + + 12 * sizeof(float)); + void* dataPtr = data->writable_data(); + + *((ColorSpaceHeader*) dataPtr) = ColorSpaceHeader::Pack(k0_Version, fNamed, fGammaNamed, + ColorSpaceHeader::kMatrix_Flag); + dataPtr = SkTAddOffset<void>(dataPtr, sizeof(ColorSpaceHeader)); + + fToXYZD50.as4x3ColMajorf((float*) dataPtr); + return data; + } + default: + break; + } + + // If we do not have a named gamma, this must have been created from an ICC profile. + // Since we were unable to recognize the gamma, we will have saved the ICC data. + SkASSERT(as_CSB(this)->fProfileData); + + size_t profileSize = as_CSB(this)->fProfileData->size(); + if (SkAlign4(profileSize) != (uint32_t) SkAlign4(profileSize)) { + return nullptr; + } + + sk_sp<SkData> data = SkData::MakeUninitialized(sizeof(ColorSpaceHeader) + sizeof(uint32_t) + + SkAlign4(profileSize)); + void* dataPtr = data->writable_data(); + + *((ColorSpaceHeader*) dataPtr) = ColorSpaceHeader::Pack(k0_Version, fNamed, fGammaNamed, + ColorSpaceHeader::kICC_Flag); + dataPtr = SkTAddOffset<void>(dataPtr, sizeof(ColorSpaceHeader)); + + *((uint32_t*) dataPtr) = (uint32_t) SkAlign4(profileSize); + dataPtr = SkTAddOffset<void>(dataPtr, sizeof(uint32_t)); + + memcpy(dataPtr, as_CSB(this)->fProfileData->data(), profileSize); + memset(SkTAddOffset<void>(dataPtr, profileSize), 0, SkAlign4(profileSize) - profileSize); + return data; +} + +sk_sp<SkColorSpace> SkColorSpace::Deserialize(const void* data, size_t length) { + if (length < sizeof(ColorSpaceHeader)) { + return nullptr; + } + + ColorSpaceHeader header = *((const ColorSpaceHeader*) data); + data = SkTAddOffset<const void>(data, sizeof(ColorSpaceHeader)); + length -= sizeof(ColorSpaceHeader); + switch ((Named) header.fNamed) { + case kSRGB_Named: + case kAdobeRGB_Named: + return NewNamed((Named) header.fNamed); + default: + break; + } + + switch ((GammaNamed) header.fGammaNamed) { + case kSRGB_GammaNamed: + case k2Dot2Curve_GammaNamed: + case kLinear_GammaNamed: { + if (ColorSpaceHeader::kMatrix_Flag != header.fFlags || length < 12 * sizeof(float)) { + return nullptr; + } + + SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor); + toXYZ.set4x3ColMajorf((const float*) data); + return NewRGB((GammaNamed) header.fGammaNamed, toXYZ); + } + default: + break; + } + + if (ColorSpaceHeader::kICC_Flag != header.fFlags || length < sizeof(uint32_t)) { + return nullptr; + } + + uint32_t profileSize = *((uint32_t*) data); + data = SkTAddOffset<const void>(data, sizeof(uint32_t)); + length -= sizeof(uint32_t); + if (length < profileSize) { + return nullptr; + } + + return NewICC(data, profileSize); +} diff --git a/src/core/SkColorSpace_Base.h b/src/core/SkColorSpace_Base.h index fc4f665e68..9f639153f4 100644 --- a/src/core/SkColorSpace_Base.h +++ b/src/core/SkColorSpace_Base.h @@ -159,11 +159,9 @@ public: private: - static sk_sp<SkColorSpace> NewRGB(GammaNamed gammaNamed, const SkMatrix44& toXYZD50, - sk_sp<SkData> profileData); + static sk_sp<SkColorSpace> NewRGB(GammaNamed gammaNamed, const SkMatrix44& toXYZD50); - SkColorSpace_Base(GammaNamed gammaNamed, const SkMatrix44& toXYZ, Named named, - sk_sp<SkData> profileData); + SkColorSpace_Base(GammaNamed gammaNamed, const SkMatrix44& toXYZ, Named named); SkColorSpace_Base(SkColorLookUpTable* colorLUT, sk_sp<SkGammas> gammas, const SkMatrix44& toXYZ, sk_sp<SkData> profileData); diff --git a/src/core/SkImageInfo.cpp b/src/core/SkImageInfo.cpp index ee169239ef..ba418d5198 100644 --- a/src/core/SkImageInfo.cpp +++ b/src/core/SkImageInfo.cpp @@ -9,50 +9,6 @@ #include "SkReadBuffer.h" #include "SkWriteBuffer.h" -/* - * We store this as a byte in the ImageInfo flatten buffer. - */ -enum class SkFlattenColorSpaceEnum { - kUnspecified, - kSRGB, - kAdobe1998, - // ... add more here - kLastEnum = kAdobe1998, - // final value means the actual profile data follows the info - kICCProfile = 0xFF, -}; - -static sk_sp<SkColorSpace> make_from_enum(SkFlattenColorSpaceEnum value) { - switch (value) { - case SkFlattenColorSpaceEnum::kSRGB: - return SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named); - case SkFlattenColorSpaceEnum::kAdobe1998: - return SkColorSpace::NewNamed(SkColorSpace::kAdobeRGB_Named); - default: - return nullptr; - } -} - -SkColorSpace::Named sk_deduce_named_from_colorspace(SkColorSpace* cs) { - return cs->fNamed; -} - -static SkFlattenColorSpaceEnum deduce_from_colorspace(SkColorSpace* cs) { - if (!cs) { - return SkFlattenColorSpaceEnum::kUnspecified; - } - switch (sk_deduce_named_from_colorspace(cs)) { - case SkColorSpace::kSRGB_Named: - return SkFlattenColorSpaceEnum::kSRGB; - case SkColorSpace::kAdobeRGB_Named: - return SkFlattenColorSpaceEnum::kAdobe1998; - default: - return SkFlattenColorSpaceEnum::kICCProfile; - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - #ifdef SK_SUPPORT_LEGACY_COLORPROFILETYPE SkColorProfileType SkImageInfo::profileType() const { return fColorSpace && fColorSpace->gammaCloseToSRGB() @@ -81,40 +37,31 @@ void SkImageInfo::unflatten(SkReadBuffer& buffer) { SkASSERT(0 == (packed >> 24)); fColorType = (SkColorType)((packed >> 0) & 0xFF); fAlphaType = (SkAlphaType)((packed >> 8) & 0xFF); - SkFlattenColorSpaceEnum csenum = (SkFlattenColorSpaceEnum)((packed >> 16) & 0xFF); buffer.validate(alpha_type_is_valid(fAlphaType) && color_type_is_valid(fColorType)); - if (SkFlattenColorSpaceEnum::kICCProfile == csenum) { - SkASSERT(false); // we shouldn't hit this yet, as we don't write these yet - fColorSpace.reset(); - } else { - if (csenum > SkFlattenColorSpaceEnum::kLastEnum) { - csenum = SkFlattenColorSpaceEnum::kUnspecified; - } - fColorSpace = make_from_enum(csenum); - } + sk_sp<SkData> data = buffer.readByteArrayAsData(); + fColorSpace = SkColorSpace::Deserialize(data->data(), data->size()); } void SkImageInfo::flatten(SkWriteBuffer& buffer) const { buffer.write32(fWidth); buffer.write32(fHeight); - SkFlattenColorSpaceEnum csenum = deduce_from_colorspace(fColorSpace.get()); - - // TODO: when we actually support flattening the colorspace to a profile blob, remove this - // hack (and write the blob after we write packed. - if (SkFlattenColorSpaceEnum::kICCProfile == csenum) { - csenum = SkFlattenColorSpaceEnum::kUnspecified; - } - - SkASSERT(0 == ((int)csenum & ~0xFF)); SkASSERT(0 == (fAlphaType & ~0xFF)); SkASSERT(0 == (fColorType & ~0xFF)); - uint32_t packed = ((int)csenum << 16) | (fAlphaType << 8) | fColorType; + uint32_t packed = (fAlphaType << 8) | fColorType; buffer.write32(packed); - if (SkFlattenColorSpaceEnum::kICCProfile == csenum) { - // TODO: write the ICCProfile blob + if (fColorSpace) { + sk_sp<SkData> data = fColorSpace->serialize(); + if (data) { + buffer.writeDataAsByteArray(data.get()); + } else { + buffer.writeByteArray(nullptr, 0); + } + } else { + sk_sp<SkData> data = SkData::MakeEmpty(); + buffer.writeDataAsByteArray(data.get()); } } diff --git a/src/core/SkMatrix44.cpp b/src/core/SkMatrix44.cpp index 34b5327519..56c2e8a142 100644 --- a/src/core/SkMatrix44.cpp +++ b/src/core/SkMatrix44.cpp @@ -85,6 +85,17 @@ void SkMatrix44::asColMajorf(float dst[]) const { #endif } +void SkMatrix44::as4x3ColMajorf(float dst[]) const { + const SkMScalar* src = &fMat[0][0]; +#ifdef SK_MSCALAR_IS_DOUBLE + for (int i = 0; i < 12; ++i) { + dst[i] = SkMScalarToFloat(src[i]); + } +#elif defined SK_MSCALAR_IS_FLOAT + memcpy(dst, src, 12 * sizeof(float)); +#endif +} + void SkMatrix44::asColMajord(double dst[]) const { const SkMScalar* src = &fMat[0][0]; #ifdef SK_MSCALAR_IS_DOUBLE @@ -217,6 +228,14 @@ void SkMatrix44::set3x3ColMajorf(const float src[]) { this->dirtyTypeMask(); } +void SkMatrix44::set4x3ColMajorf(const float src[]) { + fMat[0][0] = src[0]; fMat[0][1] = src[1]; fMat[0][2] = src[2]; fMat[0][3] = src[3]; + fMat[1][0] = src[4]; fMat[1][1] = src[5]; fMat[1][2] = src[6]; fMat[1][3] = src[7]; + fMat[2][0] = src[8]; fMat[2][1] = src[9]; fMat[2][2] = src[10]; fMat[2][3] = src[11]; + fMat[3][0] = 0; fMat[3][1] = 0; fMat[3][2] = 0; fMat[3][3] = 1; + this->dirtyTypeMask(); +} + /////////////////////////////////////////////////////////////////////////////// void SkMatrix44::setTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) { |