diff --git a/lib/include/ultrahdr/gainmapmetadata.h b/lib/include/ultrahdr/gainmapmetadata.h index 1159e293..7a2f8be9 100644 --- a/lib/include/ultrahdr/gainmapmetadata.h +++ b/lib/include/ultrahdr/gainmapmetadata.h @@ -23,25 +23,25 @@ constexpr uint8_t kUseBaseColorSpaceMask = (1u << 6); // Gain map metadata, for tone mapping between SDR and HDR. // This is the fraction version of {@code uhdr_gainmap_metadata_ext_t}. struct uhdr_gainmap_metadata_frac { - int32_t gainMapMinN[3]; - uint32_t gainMapMinD[3]; - int32_t gainMapMaxN[3]; - uint32_t gainMapMaxD[3]; - uint32_t gainMapGammaN[3]; - uint32_t gainMapGammaD[3]; - - int32_t baseOffsetN[3]; - uint32_t baseOffsetD[3]; - int32_t alternateOffsetN[3]; - uint32_t alternateOffsetD[3]; - - uint32_t baseHdrHeadroomN; - uint32_t baseHdrHeadroomD; - uint32_t alternateHdrHeadroomN; - uint32_t alternateHdrHeadroomD; - - bool backwardDirection; - bool useBaseColorSpace; + int32_t gainMapMinN[3] = {0, 0, 0}; + uint32_t gainMapMinD[3] = {1, 1, 1}; + int32_t gainMapMaxN[3] = {1, 1, 1}; + uint32_t gainMapMaxD[3] = {1, 1, 1}; + uint32_t gainMapGammaN[3] = {1, 1, 1}; + uint32_t gainMapGammaD[3] = {1, 1, 1}; + + int32_t baseOffsetN[3] = {0, 0, 0}; + uint32_t baseOffsetD[3] = {1, 1, 1}; + int32_t alternateOffsetN[3] = {0, 0, 0}; + uint32_t alternateOffsetD[3] = {1, 1, 1}; + + uint32_t baseHdrHeadroomN = 0; + uint32_t baseHdrHeadroomD = 1; + uint32_t alternateHdrHeadroomN = 1; + uint32_t alternateHdrHeadroomD = 1; + + bool backwardDirection = false; + bool useBaseColorSpace = true; static uhdr_error_info_t encodeGainmapMetadata(const uhdr_gainmap_metadata_frac* in_metadata, std::vector& out_data); diff --git a/lib/src/gainmapmetadata.cpp b/lib/src/gainmapmetadata.cpp index e1b965a8..432c2a74 100644 --- a/lib/src/gainmapmetadata.cpp +++ b/lib/src/gainmapmetadata.cpp @@ -13,6 +13,7 @@ #include "ultrahdr/gainmapmath.h" #include "ultrahdr/gainmapmetadata.h" +#include "ultrahdr/ultrahdrcommon.h" namespace ultrahdr { @@ -342,7 +343,7 @@ uhdr_error_info_t uhdr_gainmap_metadata_frac::gainmapMetadataFractionToFloat( to->hdr_capacity_min = exp2((float)from->baseHdrHeadroomN / from->baseHdrHeadroomD); to->use_base_cg = from->useBaseColorSpace; - return g_no_error; + return uhdr_validate_gainmap_metadata_descriptor(to); } uhdr_error_info_t uhdr_gainmap_metadata_frac::gainmapMetadataFloatToFraction( diff --git a/lib/src/jpegrutils.cpp b/lib/src/jpegrutils.cpp index 230b8ee6..3f064ade 100644 --- a/lib/src/jpegrutils.cpp +++ b/lib/src/jpegrutils.cpp @@ -870,7 +870,7 @@ uhdr_error_info_t getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, uint8_t std::fill_n(metadata->offset_hdr + 1, 2, metadata->offset_hdr[0]); std::fill_n(metadata->offset_sdr + 1, 2, metadata->offset_sdr[0]); - return g_no_error; + return uhdr_validate_gainmap_metadata_descriptor(metadata); } string generateXmpForPrimaryImage(size_t secondary_image_length, diff --git a/lib/src/ultrahdr_api.cpp b/lib/src/ultrahdr_api.cpp index 2fd00629..2b10739f 100644 --- a/lib/src/ultrahdr_api.cpp +++ b/lib/src/ultrahdr_api.cpp @@ -1721,17 +1721,18 @@ uhdr_error_info_t uhdr_dec_probe(uhdr_codec_private_t* dec) { ultrahdr::uhdr_gainmap_metadata_frac frac; if (ultrahdr::uhdr_gainmap_metadata_frac::decodeGainmapMetadata(meta, &frac).error_code == UHDR_CODEC_OK) { ultrahdr::uhdr_gainmap_metadata_ext_t metadata; - ultrahdr::uhdr_gainmap_metadata_frac::gainmapMetadataFractionToFloat(&frac, &metadata); - std::copy(metadata.max_content_boost, metadata.max_content_boost + 3, - handle->m_metadata.max_content_boost); - std::copy(metadata.min_content_boost, metadata.min_content_boost + 3, - handle->m_metadata.min_content_boost); - std::copy(metadata.gamma, metadata.gamma + 3, handle->m_metadata.gamma); - std::copy(metadata.offset_sdr, metadata.offset_sdr + 3, handle->m_metadata.offset_sdr); - std::copy(metadata.offset_hdr, metadata.offset_hdr + 3, handle->m_metadata.offset_hdr); - handle->m_metadata.hdr_capacity_min = metadata.hdr_capacity_min; - handle->m_metadata.hdr_capacity_max = metadata.hdr_capacity_max; - handle->m_metadata.use_base_cg = metadata.use_base_cg; + if (ultrahdr::uhdr_gainmap_metadata_frac::gainmapMetadataFractionToFloat(&frac, &metadata).error_code == UHDR_CODEC_OK) { + std::copy(metadata.max_content_boost, metadata.max_content_boost + 3, + handle->m_metadata.max_content_boost); + std::copy(metadata.min_content_boost, metadata.min_content_boost + 3, + handle->m_metadata.min_content_boost); + std::copy(metadata.gamma, metadata.gamma + 3, handle->m_metadata.gamma); + std::copy(metadata.offset_sdr, metadata.offset_sdr + 3, handle->m_metadata.offset_sdr); + std::copy(metadata.offset_hdr, metadata.offset_hdr + 3, handle->m_metadata.offset_hdr); + handle->m_metadata.hdr_capacity_min = metadata.hdr_capacity_min; + handle->m_metadata.hdr_capacity_max = metadata.hdr_capacity_max; + handle->m_metadata.use_base_cg = metadata.use_base_cg; + } } } heif_image_handle_release(gainmap_handle); diff --git a/tests/gainmapmetadata_test.cpp b/tests/gainmapmetadata_test.cpp index 9ffcd78f..604b2826 100644 --- a/tests/gainmapmetadata_test.cpp +++ b/tests/gainmapmetadata_test.cpp @@ -82,8 +82,8 @@ TEST_F(GainMapMetadataTest, encodeMetadataThenDecode) { data.clear(); for (int i = 0; i < 3; i++) { expected.min_content_boost[i] = 0.000578369f + i * 0.001f; - expected.offset_sdr[i] = -0.0625f + i * 0.001f; - expected.offset_hdr[i] = -0.0625f + i * 0.001f; + expected.offset_sdr[i] = 0.0625f + i * 0.001f; + expected.offset_hdr[i] = 0.0625f + i * 0.001f; } expected.hdr_capacity_max = 1000.0f / 203.0f; expected.use_base_cg = true; @@ -112,4 +112,39 @@ TEST_F(GainMapMetadataTest, encodeMetadataThenDecode) { EXPECT_EQ(expected.use_base_cg, decodedUHdrMetadata.use_base_cg); } +TEST(GainmapMetadataTest, RejectsMalformedISO21496_1Ratios) { + uhdr_gainmap_metadata_frac frac{}; + for (int i = 0; i < 3; ++i) { + frac.gainMapMaxN[i] = 1; + frac.gainMapMaxD[i] = 1; + frac.gainMapMinN[i] = 0; + frac.gainMapMinD[i] = 1; + frac.gainMapGammaN[i] = 1; + frac.gainMapGammaD[i] = 1; + frac.baseOffsetN[i] = 0; + frac.baseOffsetD[i] = 1; + frac.alternateOffsetN[i] = 0; + frac.alternateOffsetD[i] = 1; + } + frac.baseHdrHeadroomN = 0; + frac.baseHdrHeadroomD = 1; + frac.alternateHdrHeadroomN = 1; + frac.alternateHdrHeadroomD = 1; + + // Test 1: max_content_boost < min_content_boost + frac.gainMapMaxN[0] = 0; // log2(max_boost) = 0 -> max_boost = 1.0 + frac.gainMapMinN[0] = 2; // log2(min_boost) = 2 -> min_boost = 4.0 + uhdr_gainmap_metadata_ext_t float_meta; + EXPECT_EQ(uhdr_gainmap_metadata_frac::gainmapMetadataFractionToFloat(&frac, &float_meta).error_code, + UHDR_CODEC_INVALID_PARAM); + + // Test 2: Inverted HDR capacity range (max <= min) + frac.gainMapMaxN[0] = 1; + frac.gainMapMinN[0] = 0; + frac.alternateHdrHeadroomN = 0; // log2(headroom_max) = 0 -> 1.0 + frac.baseHdrHeadroomN = 1; // log2(headroom_min) = 1 -> 2.0 + EXPECT_EQ(uhdr_gainmap_metadata_frac::gainmapMetadataFractionToFloat(&frac, &float_meta).error_code, + UHDR_CODEC_INVALID_PARAM); +} + } // namespace ultrahdr