diff --git a/AUTHORS b/AUTHORS index 544341694..f30a4ee19 100644 --- a/AUTHORS +++ b/AUTHORS @@ -17,6 +17,7 @@ Authors, for copyright and licensing purposes. * James Yu * John Bowler * Kevin Bracey + * Lucas Chollet * Magnus Holmgren * Mandar Sahastrabuddhe * Mans Rullgard diff --git a/CMakeLists.txt b/CMakeLists.txt index d62485412..5c6866f42 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -814,6 +814,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 000000000..47830bd6b Binary files /dev/null and b/cicp-display-p3_reencoded.png differ diff --git a/png.h b/png.h index e288f8844..3e130a998 100644 --- a/png.h +++ b/png.h @@ -744,6 +744,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 @@ -1973,6 +1974,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)); @@ -3237,7 +3249,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 fac370d04..9be881432 100644 --- a/pngget.c +++ b/pngget.c @@ -784,6 +784,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 ea4f11500..e85420c1a 100644 --- a/pnginfo.h +++ b/pnginfo.h @@ -100,6 +100,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 322b0cf9f..efa03f978 100644 --- a/pngpread.c +++ b/pngpread.c @@ -308,6 +308,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 62615bee8..84f77c350 100644 --- a/pngpriv.h +++ b/pngpriv.h @@ -834,6 +834,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) @@ -1130,6 +1131,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); @@ -1473,6 +1480,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 b10b42651..317951f3d 100644 --- a/pngread.c +++ b/pngread.c @@ -173,6 +173,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 44b3a6869..282d976c8 100644 --- a/pngrutil.c +++ b/pngrutil.c @@ -2046,6 +2046,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 b530f65d1..c4f286733 100644 --- a/pngset.c +++ b/pngset.c @@ -133,6 +133,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 bcf0f30b5..60da60825 100644 --- a/pngtest.c +++ b/pngtest.c @@ -1205,6 +1205,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 0ed6a551a..8b72304f4 100644 --- a/pngwrite.c +++ b/pngwrite.c @@ -236,6 +236,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 abe7b07f9..11f343daa 100644 --- a/pngwutil.c +++ b/pngwutil.c @@ -1488,6 +1488,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 0648f0721..0a2345447 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 6c3e43ecd..613d7e91f 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 82494bbf9..305bd1a28 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