diff --git a/CMakeLists.txt b/CMakeLists.txt index 77e5398b6a..c55ab950b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -812,6 +812,10 @@ if(PNG_TESTS AND PNG_SHARED) COMMAND pngtest FILES "${PNGTEST_PNG}") + png_add_test(NAME pngtest-cicp + COMMAND pngtest + FILES "${CMAKE_CURRENT_SOURCE_DIR}/cicp-display-p3_reencoded.png") + add_executable(pngvalid ${pngvalid_sources}) target_link_libraries(pngvalid PRIVATE png_shared) diff --git a/cicp-display-p3_reencoded.png b/cicp-display-p3_reencoded.png new file mode 100644 index 0000000000..47830bd6b3 Binary files /dev/null and b/cicp-display-p3_reencoded.png differ diff --git a/png.h b/png.h index b71bd7064a..ae05752cee 100644 --- a/png.h +++ b/png.h @@ -745,6 +745,7 @@ typedef png_unknown_chunk * * png_unknown_chunkpp; #define PNG_INFO_sCAL 0x4000U /* ESR, 1.0.6 */ #define PNG_INFO_IDAT 0x8000U /* ESR, 1.0.6 */ #define PNG_INFO_eXIf 0x10000U /* GR-P, 1.6.31 */ +#define PNG_INFO_cICP 0x20000U /* This is used for the transformation routines, as some of them * change these values for the row. It also should enable using @@ -1974,6 +1975,17 @@ PNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed, (png_const_structrp png_ptr, png_fixed_point int_blue_Z)) #endif +#ifdef PNG_cICP_SUPPORTED +PNG_EXPORT(250, png_uint_32, png_get_cICP, (png_const_structrp png_ptr, + png_inforp info_ptr, png_bytep colour_primaries, + png_bytep transfer_function, png_bytep matrix_coefficients, + png_bytep video_full_range_flag)); +PNG_EXPORT(251, void, png_set_cICP, (png_const_structrp png_ptr, + png_inforp info_ptr, png_byte colour_primaries, + png_byte transfer_function, png_byte matrix_coefficients, + png_byte video_full_range_flag)); +#endif + #ifdef PNG_eXIf_SUPPORTED PNG_EXPORT(246, png_uint_32, png_get_eXIf, (png_const_structrp png_ptr, png_inforp info_ptr, png_bytep *exif)); @@ -3238,7 +3250,7 @@ PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option, * one to use is one more than this.) */ #ifdef PNG_EXPORT_LAST_ORDINAL - PNG_EXPORT_LAST_ORDINAL(249); + PNG_EXPORT_LAST_ORDINAL(251); #endif #ifdef __cplusplus diff --git a/pngget.c b/pngget.c index 1084b268ff..7f31e7b46f 100644 --- a/pngget.c +++ b/pngget.c @@ -785,6 +785,31 @@ png_get_sPLT(png_const_structrp png_ptr, png_inforp info_ptr, } #endif +#ifdef PNG_cICP_SUPPORTED +png_uint_32 PNGAPI +png_get_cICP(png_const_structrp png_ptr, + png_inforp info_ptr, png_bytep colour_primaries, + png_bytep transfer_function, png_bytep matrix_coefficients, + png_bytep video_full_range_flag) +{ + png_debug1(1, "in %s retrieval function", "cICP"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_cICP) != 0 && + colour_primaries != NULL && transfer_function != NULL && + matrix_coefficients != NULL && video_full_range_flag != NULL) + { + *colour_primaries = info_ptr->cicp_colour_primaries; + *transfer_function = info_ptr->cicp_transfer_function; + *matrix_coefficients = info_ptr->cicp_matrix_coefficients; + *video_full_range_flag = info_ptr->cicp_video_full_range_flag; + return (PNG_INFO_cICP); + } + + return (0); +} +#endif + #ifdef PNG_eXIf_SUPPORTED png_uint_32 PNGAPI png_get_eXIf(png_const_structrp png_ptr, png_inforp info_ptr, diff --git a/pnginfo.h b/pnginfo.h index 1f98dedc42..7df4f5b845 100644 --- a/pnginfo.h +++ b/pnginfo.h @@ -101,6 +101,14 @@ struct png_info_def png_colorspace colorspace; #endif +#ifdef PNG_cICP_SUPPORTED + /* cICP chunk data */ + png_byte cicp_colour_primaries; + png_byte cicp_transfer_function; + png_byte cicp_matrix_coefficients; + png_byte cicp_video_full_range_flag; +#endif + #ifdef PNG_iCCP_SUPPORTED /* iCCP chunk data. */ png_charp iccp_name; /* profile name */ diff --git a/pngpread.c b/pngpread.c index ffab19c08c..c5fa70523f 100644 --- a/pngpread.c +++ b/pngpread.c @@ -294,6 +294,14 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr) png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length); } +#endif +#ifdef PNG_READ_cICP_SUPPORTED + else if (png_ptr->chunk_name == png_cICP) + { + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_cICP(png_ptr, info_ptr, png_ptr->push_length); + } + #endif #ifdef PNG_READ_eXIf_SUPPORTED else if (png_ptr->chunk_name == png_eXIf) diff --git a/pngpriv.h b/pngpriv.h index 9bfdb71342..1a7484c2be 100644 --- a/pngpriv.h +++ b/pngpriv.h @@ -876,6 +876,7 @@ #define png_PLTE PNG_U32( 80, 76, 84, 69) #define png_bKGD PNG_U32( 98, 75, 71, 68) #define png_cHRM PNG_U32( 99, 72, 82, 77) +#define png_cICP PNG_U32( 99, 73, 67, 80) #define png_eXIf PNG_U32(101, 88, 73, 102) /* registered July 2017 */ #define png_fRAc PNG_U32(102, 82, 65, 99) /* registered, not defined */ #define png_gAMA PNG_U32(103, 65, 77, 65) @@ -1172,6 +1173,12 @@ PNG_INTERNAL_FUNCTION(void,png_write_cHRM_fixed,(png_structrp png_ptr, /* The xy value must have been previously validated */ #endif +#ifdef PNG_WRITE_cICP_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_cICP,(png_structrp png_ptr, + png_byte colour_primaries, png_byte transfer_function, + png_byte matrix_coefficients, png_byte video_full_range_flag), PNG_EMPTY); +#endif + #ifdef PNG_WRITE_sRGB_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_write_sRGB,(png_structrp png_ptr, int intent),PNG_EMPTY); @@ -1515,6 +1522,11 @@ PNG_INTERNAL_FUNCTION(void,png_handle_cHRM,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif +#ifdef PNG_READ_cICP_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_cICP,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + #ifdef PNG_READ_eXIf_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_handle_eXIf,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); diff --git a/pngread.c b/pngread.c index 07a39df6e2..e29218b394 100644 --- a/pngread.c +++ b/pngread.c @@ -174,6 +174,10 @@ png_read_info(png_structrp png_ptr, png_inforp info_ptr) else if (chunk_name == png_cHRM) png_handle_cHRM(png_ptr, info_ptr, length); #endif +#ifdef PNG_READ_cICP_SUPPORTED + else if (chunk_name == png_cICP) + png_handle_cICP(png_ptr, info_ptr, length); +#endif #ifdef PNG_READ_eXIf_SUPPORTED else if (chunk_name == png_eXIf) diff --git a/pngrutil.c b/pngrutil.c index d31dc21dae..6dd1cf5f17 100644 --- a/pngrutil.c +++ b/pngrutil.c @@ -2032,6 +2032,43 @@ png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) } #endif +#ifdef PNG_READ_cICP_SUPPORTED +void /* PRIVATE */ +png_handle_cICP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_byte buf[4]; + + png_debug(1, "in png_handle_cICP"); + + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cICP) != 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) + png_ptr->mode |= PNG_AFTER_IDAT; + + if (length != 4) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_crc_read(png_ptr, buf, 4); + + if (png_crc_finish(png_ptr, 0) != 0) + return; + + png_set_cICP(png_ptr, info_ptr, buf[0], buf[1], buf[2], buf[3]); +} +#endif + #ifdef PNG_READ_eXIf_SUPPORTED void /* PRIVATE */ png_handle_eXIf(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) diff --git a/pngset.c b/pngset.c index eb1c8c7a35..b8ca635a9b 100644 --- a/pngset.c +++ b/pngset.c @@ -134,6 +134,26 @@ png_set_cHRM_XYZ(png_const_structrp png_ptr, png_inforp info_ptr, double red_X, #endif /* cHRM */ +#ifdef PNG_cICP_SUPPORTED +void PNGAPI +png_set_cICP(png_const_structrp png_ptr, + png_inforp info_ptr, png_byte colour_primaries, + png_byte transfer_function, png_byte matrix_coefficients, + png_byte video_full_range_flag) +{ + png_debug1(1, "in %s storage function", "cICP"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->cicp_colour_primaries = colour_primaries; + info_ptr->cicp_transfer_function = transfer_function; + info_ptr->cicp_matrix_coefficients = matrix_coefficients; + info_ptr->cicp_video_full_range_flag = video_full_range_flag; + info_ptr->valid |= PNG_INFO_cICP; +} +#endif /* cICP */ + #ifdef PNG_eXIf_SUPPORTED void PNGAPI png_set_eXIf(png_const_structrp png_ptr, png_inforp info_ptr, diff --git a/pngtest.c b/pngtest.c index 81da721263..7a7b90f80b 100644 --- a/pngtest.c +++ b/pngtest.c @@ -1206,6 +1206,23 @@ test_one_file(const char *inname, const char *outname) png_set_bKGD(write_ptr, write_info_ptr, background); } #endif +#ifdef PNG_cICP_SUPPORTED + { + png_byte colour_primaries; + png_byte transfer_function; + png_byte matrix_coefficients; + png_byte video_full_range_flag; + + if (png_get_cICP(read_ptr, read_info_ptr, &colour_primaries, + &transfer_function, &matrix_coefficients, + &video_full_range_flag) != 0) +#ifdef PNG_WRITE_cICP_SUPPORTED + png_set_cICP(write_ptr, write_info_ptr, colour_primaries, + transfer_function, matrix_coefficients, + video_full_range_flag); +#endif + } +#endif #ifdef PNG_READ_eXIf_SUPPORTED { png_bytep exif = NULL; diff --git a/pngwrite.c b/pngwrite.c index 77e412f43d..fb5514841e 100644 --- a/pngwrite.c +++ b/pngwrite.c @@ -237,6 +237,16 @@ png_write_info(png_structrp png_ptr, png_const_inforp info_ptr) png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type); #endif +#ifdef PNG_WRITE_cICP_SUPPORTED + if ((info_ptr->valid & PNG_INFO_cICP) != 0) + { + png_write_cICP(png_ptr, info_ptr->cicp_colour_primaries, + info_ptr->cicp_transfer_function, + info_ptr->cicp_matrix_coefficients, + info_ptr->cicp_video_full_range_flag); + } +#endif + #ifdef PNG_WRITE_eXIf_SUPPORTED if ((info_ptr->valid & PNG_INFO_eXIf) != 0) { diff --git a/pngwutil.c b/pngwutil.c index 14cc4ce367..dddd5f744f 100644 --- a/pngwutil.c +++ b/pngwutil.c @@ -1471,6 +1471,26 @@ png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type) } #endif +#ifdef PNG_WRITE_cICP_SUPPORTED +/* Write the cICP data */ +void /* PRIVATE */ +png_write_cICP(png_structrp png_ptr, + png_byte colour_primaries, png_byte transfer_function, + png_byte matrix_coefficients, png_byte video_full_range_flag) +{ + png_debug(1, "in png_write_cICP"); + + png_write_chunk_header(png_ptr, png_cICP, 4); + + png_write_chunk_data(png_ptr, &colour_primaries, 1); + png_write_chunk_data(png_ptr, &transfer_function, 1); + png_write_chunk_data(png_ptr, &matrix_coefficients, 1); + png_write_chunk_data(png_ptr, &video_full_range_flag, 1); + + png_write_chunk_end(png_ptr); +} +#endif + #ifdef PNG_WRITE_eXIf_SUPPORTED /* Write the Exif data */ void /* PRIVATE */ diff --git a/scripts/pnglibconf.dfa b/scripts/pnglibconf.dfa index fe8e481238..1eba9e3b26 100644 --- a/scripts/pnglibconf.dfa +++ b/scripts/pnglibconf.dfa @@ -846,6 +846,7 @@ setting IDAT_READ_SIZE default PNG_ZBUF_SIZE # Ancillary chunks chunk bKGD chunk cHRM enables COLORSPACE +chunk cICP chunk eXIf chunk gAMA enables GAMMA chunk hIST diff --git a/scripts/pnglibconf.h.prebuilt b/scripts/pnglibconf.h.prebuilt index 2c95cd5df2..7e39391b25 100644 --- a/scripts/pnglibconf.h.prebuilt +++ b/scripts/pnglibconf.h.prebuilt @@ -88,6 +88,7 @@ #define PNG_READ_USER_TRANSFORM_SUPPORTED #define PNG_READ_bKGD_SUPPORTED #define PNG_READ_cHRM_SUPPORTED +#define PNG_READ_cICP_SUPPORTED #define PNG_READ_eXIf_SUPPORTED #define PNG_READ_gAMA_SUPPORTED #define PNG_READ_hIST_SUPPORTED @@ -158,6 +159,7 @@ #define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED #define PNG_WRITE_bKGD_SUPPORTED #define PNG_WRITE_cHRM_SUPPORTED +#define PNG_WRITE_cICP_SUPPORTED #define PNG_WRITE_eXIf_SUPPORTED #define PNG_WRITE_gAMA_SUPPORTED #define PNG_WRITE_hIST_SUPPORTED @@ -176,6 +178,7 @@ #define PNG_WRITE_zTXt_SUPPORTED #define PNG_bKGD_SUPPORTED #define PNG_cHRM_SUPPORTED +#define PNG_cICP_SUPPORTED #define PNG_eXIf_SUPPORTED #define PNG_gAMA_SUPPORTED #define PNG_hIST_SUPPORTED diff --git a/scripts/symbols.def b/scripts/symbols.def index 82494bbf94..305bd1a28e 100644 --- a/scripts/symbols.def +++ b/scripts/symbols.def @@ -253,3 +253,5 @@ EXPORTS png_set_eXIf @247 png_get_eXIf_1 @248 png_set_eXIf_1 @249 + png_get_cICP @250 + png_set_cICP @251