Commit 409bb6b5 for libheif
commit 409bb6b583e6562659954627d8f85842fcfe80c3
Author: Torusrxxx <torusrxxx@users.noreply.github.com>
Date: Tue Feb 10 13:09:58 2026 +0000
Add support for decoding PNG cICP, cLLI and mDCV chunks
diff --git a/heifio/decoder_png.cc b/heifio/decoder_png.cc
index 3dbf1e56..69ff6c6b 100644
--- a/heifio/decoder_png.cc
+++ b/heifio/decoder_png.cc
@@ -30,6 +30,7 @@
#include <iostream>
#include <memory>
#include "decoder_png.h"
+#include "common_utils.h"
#include "exif.h"
extern "C" {
@@ -75,6 +76,19 @@ heif_error loadPNG(const char* filename, int output_bit_depth, InputImage *input
#endif
uint8_t* profile_data = nullptr;
png_uint_32 profile_length = 5;
+#ifdef PNG_cICP_SUPPORTED
+ uint8_t color_primaries, transfer_characteristics, matrix_coefficients, video_full_range;
+ bool has_cICP = false;
+#endif
+#ifdef PNG_cLLI_SUPPORTED
+ uint32_t maximum_content_light_level_scaled_by_10000, maximum_frame_average_light_level_scaled_by_10000;
+ bool has_cLL = false;
+#endif
+#ifdef PNG_mDCV_SUPPORTED
+ png_fixed_point white_point_x, white_point_y, display_primaries_x[3], display_primaries_y[3];
+ png_uint_32 max_display_mastering_luminance, min_display_mastering_luminance;
+ bool has_mDCV = false;
+#endif
/* Create and initialize the png_struct with the desired error handler
* functions. If you want to use the default stderr and longjump method,
@@ -181,6 +195,38 @@ heif_error loadPNG(const char* filename, int output_bit_depth, InputImage *input
*/
png_read_update_info(png_ptr, info_ptr);
+ /* PNGv3 header */
+#ifdef PNG_cLLI_SUPPORTED
+ /* Set content light level
+ */
+ if (png_get_cLLI_fixed(png_ptr, info_ptr, &maximum_content_light_level_scaled_by_10000, &maximum_frame_average_light_level_scaled_by_10000) == PNG_INFO_cLLI)
+ {
+ has_cLL = true;
+ }
+ else {
+ has_cLL = false;
+ }
+#endif
+#ifdef PNG_cICP_SUPPORTED
+ if (png_get_cICP(png_ptr, info_ptr, &color_primaries, &transfer_characteristics, &matrix_coefficients, &video_full_range) == PNG_INFO_cICP)
+ {
+ has_cICP = true;
+ }
+ else {
+ has_cICP = false;
+ }
+#endif
+#ifdef PNG_mDCV_SUPPORTED
+ if (png_get_mDCV_fixed(png_ptr, info_ptr, &white_point_x, &white_point_y,
+ &display_primaries_x[0], &display_primaries_y[0], &display_primaries_x[1], &display_primaries_y[1], &display_primaries_x[2], &display_primaries_y[2],
+ &max_display_mastering_luminance, &min_display_mastering_luminance) == PNG_INFO_cICP) {
+ has_mDCV = true;
+ }
+ else {
+ has_mDCV = false;
+ }
+#endif
+
/* Allocate the memory to hold the image using the fields of info_ptr. */
/* The easiest way to read the image: */
@@ -419,6 +465,65 @@ heif_error loadPNG(const char* filename, int output_bit_depth, InputImage *input
}
}
else {
+ // band > 2, output_bit_depth > 8
+#ifdef PNG_cICP_SUPPORTED
+ if (has_cICP) {
+ heif_color_profile_nclx* nclx = heif_nclx_color_profile_alloc();
+ if (nclx) {
+ heif_nclx_color_profile_set_color_primaries(nclx, color_primaries);
+ heif_nclx_color_profile_set_transfer_characteristics(nclx, transfer_characteristics);
+ switch (color_primaries) {
+ case heif_color_primaries_ITU_R_BT_709_5:
+ default:
+ matrix_coefficients = heif_matrix_coefficients_ITU_R_BT_709_5;
+ break;
+ case heif_color_primaries_ITU_R_BT_470_6_System_B_G:
+ matrix_coefficients = heif_matrix_coefficients_ITU_R_BT_470_6_System_B_G;
+ break;
+ case heif_color_primaries_ITU_R_BT_601_6:
+ matrix_coefficients = heif_matrix_coefficients_ITU_R_BT_601_6;
+ break;
+ case heif_color_primaries_SMPTE_240M:
+ matrix_coefficients = heif_matrix_coefficients_SMPTE_240M;
+ break;
+ case heif_color_primaries_ITU_R_BT_2020_2_and_2100_0:
+ matrix_coefficients = heif_matrix_coefficients_ITU_R_BT_2020_2_constant_luminance;
+ break;
+ }
+ heif_nclx_color_profile_set_matrix_coefficients(nclx, matrix_coefficients);
+ nclx->full_range_flag = true;
+ heif_image_set_nclx_color_profile(image, nclx);
+ heif_nclx_color_profile_free(nclx);
+ }
+ }
+#endif
+
+#ifdef PNG_cLLI_SUPPORTED
+ if (has_cLL) {
+ heif_content_light_level clli;
+ clli.max_content_light_level = clip_int_u16(maximum_content_light_level_scaled_by_10000 / 10000, 10000);
+ clli.max_pic_average_light_level = clip_int_u16(maximum_frame_average_light_level_scaled_by_10000 / 10000, 10000);
+ heif_image_set_content_light_level(image, &clli);
+ }
+#endif
+
+#ifdef PNG_mDCV_SUPPORTED
+ if (has_mDCV) {
+ heif_mastering_display_colour_volume mdcv;
+ mdcv.white_point_x = clip_int_u16(white_point_x, 37000);
+ mdcv.white_point_y = clip_int_u16(white_point_y, 42000);
+ mdcv.display_primaries_x[0] = clip_int_u16(display_primaries_x[0], 37000);
+ mdcv.display_primaries_x[1] = clip_int_u16(display_primaries_x[1], 37000);
+ mdcv.display_primaries_x[2] = clip_int_u16(display_primaries_x[2], 37000);
+ mdcv.display_primaries_y[0] = clip_int_u16(display_primaries_y[0], 42000);
+ mdcv.display_primaries_y[1] = clip_int_u16(display_primaries_y[1], 42000);
+ mdcv.display_primaries_y[2] = clip_int_u16(display_primaries_y[2], 42000);
+ mdcv.max_display_mastering_luminance = max_display_mastering_luminance;
+ mdcv.min_display_mastering_luminance = min_display_mastering_luminance;
+ heif_image_set_mastering_display_colour_volume(image, &mdcv);
+ }
+#endif
+
for (uint32_t y = 0; y < height; y++) {
uint8_t* p = row_pointers[y];