blob: b6fb866ee7beae78288ac07ba6fb349150114143 [file] [log] [blame]
/*
* 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