| /* |
| * Copyright 2025 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "include/core/SkStream.h" |
| #include "include/core/SkString.h" |
| #include "include/private/SkHdrMetadata.h" |
| #include "src/core/SkStreamPriv.h" |
| |
| namespace skhdr { |
| |
| SkString ContentLightLevelInformation::toString() const { |
| return SkStringPrintf("{maxCLL:%f, maxFALL:%f}", fMaxCLL, fMaxFALL); |
| } |
| |
| bool ContentLightLevelInformation::parse(const SkData* data) { |
| if (data->size() != 4) { |
| return false; |
| } |
| SkMemoryStream s(data->data(), data->size()); |
| |
| uint16_t max_cll = 0; |
| uint16_t max_fall = 0; |
| if (!SkStreamReadU16BE(&s, &max_cll)) { |
| return false; |
| } |
| if (!SkStreamReadU16BE(&s, &max_fall)) { |
| return false; |
| } |
| |
| fMaxCLL = max_cll; |
| fMaxFALL = max_fall; |
| return true; |
| } |
| |
| sk_sp<SkData> ContentLightLevelInformation::serialize() const { |
| SkDynamicMemoryWStream s; |
| SkWStreamWriteU16BE(&s, std::llroundf(fMaxCLL)); |
| SkWStreamWriteU16BE(&s, std::llroundf(fMaxFALL)); |
| return s.detachAsData(); |
| } |
| |
| // The PNG CLLI metadata stores luminance as an integer equal to the floating point value, multipled |
| // by clli_png_luminance_divisor. |
| static constexpr float clli_png_luminance_divisor = 10000.f; |
| |
| bool ContentLightLevelInformation::parsePngChunk(const SkData* data) { |
| if (data->size() != 8) { |
| return false; |
| } |
| SkMemoryStream s(data->data(), data->size()); |
| |
| uint32_t max_cll_times_10000 = 0; |
| uint32_t max_fall_times_10000 = 0; |
| if (!SkStreamReadU32BE(&s, &max_cll_times_10000)) { |
| return false; |
| } |
| if (!SkStreamReadU32BE(&s, &max_fall_times_10000)) { |
| return false; |
| } |
| |
| fMaxCLL = max_cll_times_10000 / clli_png_luminance_divisor; |
| fMaxFALL = max_fall_times_10000 / clli_png_luminance_divisor; |
| return true; |
| } |
| |
| sk_sp<SkData> ContentLightLevelInformation::serializePngChunk() const { |
| SkDynamicMemoryWStream s; |
| SkWStreamWriteU32BE(&s, std::llroundf(fMaxCLL * clli_png_luminance_divisor)); |
| SkWStreamWriteU32BE(&s, std::llroundf(fMaxFALL * clli_png_luminance_divisor)); |
| return s.detachAsData(); |
| } |
| |
| bool ContentLightLevelInformation::operator==(const ContentLightLevelInformation& other) const { |
| return fMaxCLL == other.fMaxCLL && |
| fMaxFALL == other.fMaxFALL; |
| } |
| |
| // The MDCV metadata stores chrominance [luminance] as an integer equal to the floating point value, |
| // multipled by mdcv_chrominance[luminance]_divisor. |
| static constexpr float mdcv_chrominance_divisor = 50000.f; |
| static constexpr float mdcv_luminance_divisor = 10000.f; |
| |
| SkString MasteringDisplayColorVolume::toString() const { |
| return SkStringPrintf( |
| "{red:[%1.8f,%1.8f], green:[%1.8f,%1.8f], blue:[%1.8f,%1.8f], white:[%1.8f,%1.8f], maxLum:%f, minLum:%f}", |
| fDisplayPrimaries.fRX, fDisplayPrimaries.fRY, |
| fDisplayPrimaries.fGX, fDisplayPrimaries.fGY, |
| fDisplayPrimaries.fBX, fDisplayPrimaries.fBY, |
| fDisplayPrimaries.fWX, fDisplayPrimaries.fWY, |
| fMaximumDisplayMasteringLuminance, |
| fMinimumDisplayMasteringLuminance); |
| } |
| |
| bool MasteringDisplayColorVolume::parse(const SkData* data) { |
| if (data->size() != 24) { |
| return false; |
| } |
| SkMemoryStream s(data->data(), data->size()); |
| |
| uint16_t chromaticities_times_50000[8]; |
| for (auto& chromaticity_times_50000 : chromaticities_times_50000) { |
| if (!SkStreamReadU16BE(&s, &chromaticity_times_50000)) { |
| return false; |
| } |
| } |
| uint32_t max_luminance_times_10000 = 0; |
| uint32_t min_luminance_times_10000 = 0; |
| if (!SkStreamReadU32BE(&s, &max_luminance_times_10000)) { |
| return false; |
| } |
| if (!SkStreamReadU32BE(&s, &min_luminance_times_10000)) { |
| return false; |
| } |
| |
| fDisplayPrimaries = SkColorSpacePrimaries({ |
| chromaticities_times_50000[0] / mdcv_chrominance_divisor, |
| chromaticities_times_50000[1] / mdcv_chrominance_divisor, |
| chromaticities_times_50000[2] / mdcv_chrominance_divisor, |
| chromaticities_times_50000[3] / mdcv_chrominance_divisor, |
| chromaticities_times_50000[4] / mdcv_chrominance_divisor, |
| chromaticities_times_50000[5] / mdcv_chrominance_divisor, |
| chromaticities_times_50000[6] / mdcv_chrominance_divisor, |
| chromaticities_times_50000[7] / mdcv_chrominance_divisor, |
| }); |
| fMaximumDisplayMasteringLuminance = max_luminance_times_10000 / mdcv_luminance_divisor; |
| fMinimumDisplayMasteringLuminance = min_luminance_times_10000 / mdcv_luminance_divisor; |
| return true; |
| } |
| |
| sk_sp<SkData> MasteringDisplayColorVolume::serialize() const { |
| SkDynamicMemoryWStream s; |
| SkWStreamWriteU16BE(&s, std::llroundf(fDisplayPrimaries.fRX * mdcv_chrominance_divisor)); |
| SkWStreamWriteU16BE(&s, std::llroundf(fDisplayPrimaries.fRY * mdcv_chrominance_divisor)); |
| SkWStreamWriteU16BE(&s, std::llroundf(fDisplayPrimaries.fGX * mdcv_chrominance_divisor)); |
| SkWStreamWriteU16BE(&s, std::llroundf(fDisplayPrimaries.fGY * mdcv_chrominance_divisor)); |
| SkWStreamWriteU16BE(&s, std::llroundf(fDisplayPrimaries.fBX * mdcv_chrominance_divisor)); |
| SkWStreamWriteU16BE(&s, std::llroundf(fDisplayPrimaries.fBY * mdcv_chrominance_divisor)); |
| SkWStreamWriteU16BE(&s, std::llroundf(fDisplayPrimaries.fWX * mdcv_chrominance_divisor)); |
| SkWStreamWriteU16BE(&s, std::llroundf(fDisplayPrimaries.fWY * mdcv_chrominance_divisor)); |
| SkWStreamWriteU32BE( |
| &s, std::llroundf(fMaximumDisplayMasteringLuminance * mdcv_luminance_divisor)); |
| SkWStreamWriteU32BE( |
| &s, std::llroundf(fMinimumDisplayMasteringLuminance * mdcv_luminance_divisor)); |
| return s.detachAsData(); |
| } |
| |
| bool MasteringDisplayColorVolume::operator==(const MasteringDisplayColorVolume& other) const { |
| return fDisplayPrimaries.fRX == other.fDisplayPrimaries.fRX && |
| fDisplayPrimaries.fRY == other.fDisplayPrimaries.fRY && |
| fDisplayPrimaries.fGX == other.fDisplayPrimaries.fGX && |
| fDisplayPrimaries.fGY == other.fDisplayPrimaries.fGY && |
| fDisplayPrimaries.fBX == other.fDisplayPrimaries.fBX && |
| fDisplayPrimaries.fBY == other.fDisplayPrimaries.fBY && |
| fDisplayPrimaries.fWX == other.fDisplayPrimaries.fWX && |
| fDisplayPrimaries.fWY == other.fDisplayPrimaries.fWY && |
| fMaximumDisplayMasteringLuminance == other.fMaximumDisplayMasteringLuminance && |
| fMinimumDisplayMasteringLuminance == other.fMinimumDisplayMasteringLuminance; |
| } |
| |
| Metadata Metadata::MakeEmpty() { |
| return Metadata(); |
| } |
| |
| bool Metadata::getContentLightLevelInformation(ContentLightLevelInformation* clli) const { |
| if (!fContentLightLevelInformation.has_value()) { |
| return false; |
| } |
| if (clli) { |
| *clli = fContentLightLevelInformation.value(); |
| } |
| return true; |
| } |
| |
| bool Metadata::getMasteringDisplayColorVolume(MasteringDisplayColorVolume* mdcv) const { |
| if (!fMasteringDisplayColorVolume.has_value()) { |
| return false; |
| } |
| if (mdcv) { |
| *mdcv = fMasteringDisplayColorVolume.value(); |
| } |
| return true; |
| } |
| |
| void Metadata::setMasteringDisplayColorVolume(const MasteringDisplayColorVolume& mdcv) { |
| fMasteringDisplayColorVolume = mdcv; |
| } |
| |
| void Metadata::setContentLightLevelInformation(const ContentLightLevelInformation& clli) { |
| fContentLightLevelInformation = clli; |
| } |
| |
| SkString Metadata::toString() const { |
| return SkStringPrintf("{clli:%s, mdcv:%s}", |
| fContentLightLevelInformation.has_value() ? |
| fContentLightLevelInformation->toString().c_str() : "None", |
| fMasteringDisplayColorVolume.has_value() ? |
| fMasteringDisplayColorVolume->toString().c_str() : "None"); |
| } |
| |
| bool Metadata::operator==(const Metadata& other) const { |
| return fContentLightLevelInformation == other.fContentLightLevelInformation && |
| fMasteringDisplayColorVolume == other.fMasteringDisplayColorVolume; |
| } |
| |
| } // namespace skhdr |
| |