Skip to content

Commit

Permalink
Add support for reading and writing the cICP chunk
Browse files Browse the repository at this point in the history
This chunk was added in the third edition of the PNG specification and
contains Coding Independent Code Points (related to color space
description). It is fairly simple as it only contains four fields of one
byte each: Colour Primaries, Transfer Function, Matrix Coefficients,
Video Full Range Flag.

The test file originally comes from the related WPT test case:
https://github.com/web-platform-tests/wpt/blob/master/png/support/cicp-display-p3.png

Note that I reencoded the file to make it match libpng's default
encoding parameters (it only modifies the IDAT chunk).

Reviewed-by: John Bowler <[email protected]>
Reviewed-by: Chris Blume <[email protected]>
Reviewed-by: Cosmin Truta <[email protected]>
Signed-off-by: Cosmin Truta <[email protected]>
  • Loading branch information
LucasChollet authored and ctruta committed Sep 30, 2024
1 parent a604b12 commit 65925ad
Show file tree
Hide file tree
Showing 17 changed files with 185 additions and 1 deletion.
1 change: 1 addition & 0 deletions AUTHORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Authors, for copyright and licensing purposes.
* James Yu
* John Bowler
* Kevin Bracey
* Lucas Chollet
* Magnus Holmgren
* Mandar Sahastrabuddhe
* Mans Rullgard
Expand Down
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -811,6 +811,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)

Expand Down
Binary file added cicp-display-p3_reencoded.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 13 additions & 1 deletion png.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -1960,6 +1961,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_REMOVED(246, png_uint_32, png_get_eXIf, (png_const_structrp png_ptr,
png_inforp info_ptr, png_bytep *exif),PNG_DEPRECATED);
Expand Down Expand Up @@ -3224,7 +3236,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
Expand Down
25 changes: 25 additions & 0 deletions pngget.c
Original file line number Diff line number Diff line change
Expand Up @@ -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_1(png_const_structrp png_ptr, png_const_inforp info_ptr,
Expand Down
8 changes: 8 additions & 0 deletions pnginfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
8 changes: 8 additions & 0 deletions pngpread.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
12 changes: 12 additions & 0 deletions pngpriv.h
Original file line number Diff line number Diff line change
Expand Up @@ -835,6 +835,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)
Expand Down Expand Up @@ -1131,6 +1132,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);
Expand Down Expand Up @@ -1474,6 +1481,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);
Expand Down
4 changes: 4 additions & 0 deletions pngread.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
37 changes: 37 additions & 0 deletions pngrutil.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
20 changes: 20 additions & 0 deletions pngset.c
Original file line number Diff line number Diff line change
Expand Up @@ -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_1(png_const_structrp png_ptr, png_inforp info_ptr,
Expand Down
17 changes: 17 additions & 0 deletions pngtest.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
10 changes: 10 additions & 0 deletions pngwrite.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
20 changes: 20 additions & 0 deletions pngwutil.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
1 change: 1 addition & 0 deletions scripts/pnglibconf.dfa
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,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
Expand Down
3 changes: 3 additions & 0 deletions scripts/pnglibconf.h.prebuilt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -157,6 +158,7 @@
#define PNG_WRITE_USER_TRANSFORM_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
Expand All @@ -175,6 +177,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
Expand Down
2 changes: 2 additions & 0 deletions scripts/symbols.def
Original file line number Diff line number Diff line change
Expand Up @@ -248,3 +248,5 @@ EXPORTS
png_image_write_to_memory @245
png_get_eXIf_1 @248
png_set_eXIf_1 @249
png_get_cICP @250
png_set_cICP @251

0 comments on commit 65925ad

Please sign in to comment.