Skip to content

Commit

Permalink
PNG v3: Support for mDCV and cLLI
Browse files Browse the repository at this point in the history
This adds APIs to get/set the two remaining new PNG-v3 colour space
chunks.  The mDCV API matches that of cHRM.  Both chunks support
floating point APIs (all values in the two chunks are real numbers).

Both chunk have a new encoded type, a 4dp fixed point number, which
cannot be represented in the existing png_fixed_point type so a
png_uint_32 is used.

Test examples for cICP, cLLI and mDCV are now in 'pngtest.png' and a
necessary change to the pngunknown test has been made to accomodate the
additions.

Signed-off-by: John Bowler <[email protected]>
  • Loading branch information
jbowler committed Jan 4, 2025
1 parent 0cc367a commit 8c7c2cf
Show file tree
Hide file tree
Showing 15 changed files with 716 additions and 5 deletions.
24 changes: 24 additions & 0 deletions contrib/libtests/pngunknown.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ typedef png_byte *png_const_bytep;
#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) /* PNGv3 */
#define png_cLLI PNG_U32( 99, 76, 76, 73) /* PNGv3 */
#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 All @@ -122,6 +124,7 @@ typedef png_byte *png_const_bytep;
#define png_hIST PNG_U32(104, 73, 83, 84)
#define png_iCCP PNG_U32(105, 67, 67, 80)
#define png_iTXt PNG_U32(105, 84, 88, 116)
#define png_mDCV PNG_U32(109, 68, 67, 86) /* PNGv3 */
#define png_oFFs PNG_U32(111, 70, 70, 115)
#define png_pCAL PNG_U32(112, 67, 65, 76)
#define png_pHYs PNG_U32(112, 72, 89, 115)
Expand Down Expand Up @@ -208,6 +211,20 @@ static struct
0,
# else
1,
# endif
1, START, 0 },
{ "cICP", PNG_INFO_cICP, png_cICP,
# ifdef PNG_READ_cICP_SUPPORTED
0,
# else
1,
# endif
1, START, 0 },
{ "cLLI", PNG_INFO_cLLI, png_cLLI,
# ifdef PNG_READ_cLLI_SUPPORTED
0,
# else
1,
# endif
1, START, 0 },
{ "eXIf", PNG_INFO_eXIf, png_eXIf,
Expand Down Expand Up @@ -245,6 +262,13 @@ static struct
1,
# endif
1, ABSENT, 0 },
{ "mDCV", PNG_INFO_mDCV, png_mDCV,
# ifdef PNG_READ_mDCV_SUPPORTED
0,
# else
1,
# endif
1, START, 0 },
{ "oFFs", PNG_INFO_oFFs, png_oFFs,
# ifdef PNG_READ_oFFs_SUPPORTED
0,
Expand Down
20 changes: 20 additions & 0 deletions png.c
Original file line number Diff line number Diff line change
Expand Up @@ -3390,6 +3390,26 @@ png_fixed(png_const_structrp png_ptr, double fp, png_const_charp text)
}
#endif

#if defined(PNG_FLOATING_POINT_SUPPORTED) && \
!defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \
(defined(PNG_cLLI_SUPPORTED) || defined(PNG_mDCV_SUPPORTED))
png_uint_32
png_fixed_ITU(png_const_structrp png_ptr, double fp, png_const_charp text)
{
double r = floor(10000 * fp + .5);

if (r > 2147483647. || r < 0)
png_fixed_error(png_ptr, text);

# ifndef PNG_ERROR_TEXT_SUPPORTED
PNG_UNUSED(text)
# endif

return (png_uint_32)r;
}
#endif


#if defined(PNG_GAMMA_SUPPORTED) || defined(PNG_COLORSPACE_SUPPORTED) ||\
defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG_READ_pHYs_SUPPORTED)
/* muldiv functions */
Expand Down
101 changes: 99 additions & 2 deletions png.h
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,21 @@ 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
#define PNG_INFO_cICP 0x20000U /* PNGv3: 1.6.45 */
#define PNG_INFO_cLLI 0x40000U /* PNGv3: 1.6.45 */
#define PNG_INFO_mDCV 0x80000U /* PNGv3: 1.6.45 */
/* APNG: these chunks are stored as unknown, these flags are never set
* however they are provided as a convenience for implementors of APNG and
* avoids any merge conflicts.
*
* Private chunks: these chunk names violate the chunk name recommendations
* because the chunk definitions have no signature and because the private
* chunks with these names have been reserved. Private definitions should
* avoid them.
*/
#define PNG_INFO_acTL 0x100000U /* PNGv3: 1.6.45: unknown */
#define PNG_INFO_fcTL 0x200000U /* PNGv3: 1.6.45: unknown */
#define PNG_INFO_fdAT 0x400000U /* PNGv3: 1.6.45: unknown */

/* 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 @@ -1976,15 +1990,44 @@ PNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed, (png_const_structrp png_ptr,

#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_const_inforp info_ptr, png_bytep colour_primaries,
png_bytep transfer_function, png_bytep matrix_coefficients,
png_bytep video_full_range_flag));
#endif

#ifdef PNG_cICP_SUPPORTED
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_cLLI_SUPPORTED
PNG_FP_EXPORT(252, png_uint_32, png_get_cLLI, (png_const_structrp png_ptr,
png_const_inforp info_ptr, double *maximum_content_light_level,
double *maximum_frame_average_light_level));
PNG_FIXED_EXPORT(253, png_uint_32, png_get_cLLI_fixed,
(png_const_structrp png_ptr, png_const_inforp info_ptr,
/* The values below are in cd/m2 (nits) and are scaled by 10,000; not
* 100,000 as in the case of png_fixed_point.
*/
png_uint_32p maximum_content_light_level_scaled_by_10000,
png_uint_32p maximum_frame_average_light_level_scaled_by_10000));
#endif

#ifdef PNG_cLLI_SUPPORTED
PNG_FP_EXPORT(254, void, png_set_cLLI, (png_const_structrp png_ptr,
png_inforp info_ptr, double maximum_content_light_level,
double maximum_frame_average_light_level));
PNG_FIXED_EXPORT(255, void, png_set_cLLI_fixed, (png_const_structrp png_ptr,
png_inforp info_ptr,
/* The values below are in cd/m2 (nits) and are scaled by 10,000; not
* 100,000 as in the case of png_fixed_point.
*/
png_uint_32 maximum_content_light_level_scaled_by_10000,
png_uint_32 maximum_frame_average_light_level_scaled_by_10000));
#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));
Expand Down Expand Up @@ -2029,6 +2072,60 @@ PNG_EXPORT(144, void, png_set_IHDR, (png_const_structrp png_ptr,
int color_type, int interlace_method, int compression_method,
int filter_method));

#ifdef PNG_mDCV_SUPPORTED
PNG_FP_EXPORT(256, png_uint_32, png_get_mDCV, (png_const_structrp png_ptr,
png_const_inforp info_ptr,
/* The chromaticities of the mastering display. As cHRM, but independent of
* the encoding endpoints in cHRM, or cICP, or iCCP. These values will
* always be in the range 0 to 1.3107.
*/
double *white_x, double *white_y, double *red_x, double *red_y,
double *green_x, double *green_y, double *blue_x, double *blue_y,
/* Mastering display luminance in cd/m2 (nits). */
double *mastering_display_maximum_luminance,
double *mastering_display_minimum_luminance));

PNG_FIXED_EXPORT(257, png_uint_32, png_get_mDCV_fixed,
(png_const_structrp png_ptr, png_const_inforp info_ptr,
png_fixed_point *int_white_x, png_fixed_point *int_white_y,
png_fixed_point *int_red_x, png_fixed_point *int_red_y,
png_fixed_point *int_green_x, png_fixed_point *int_green_y,
png_fixed_point *int_blue_x, png_fixed_point *int_blue_y,
/* Mastering display luminance in cd/m2 (nits) multiplied (scaled) by
* 10,000.
*/
png_uint_32p mastering_display_maximum_luminance_scaled_by_10000,
png_uint_32p mastering_display_minimum_luminance_scaled_by_10000));
#endif

#ifdef PNG_mDCV_SUPPORTED
PNG_FP_EXPORT(258, void, png_set_mDCV, (png_const_structrp png_ptr,
png_inforp info_ptr,
/* The chromaticities of the mastering display. As cHRM, but independent of
* the encoding endpoints in cHRM, or cICP, or iCCP.
*/
double white_x, double white_y, double red_x, double red_y, double green_x,
double green_y, double blue_x, double blue_y,
/* Mastering display luminance in cd/m2 (nits). */
double mastering_display_maximum_luminance,
double mastering_display_minimum_luminance));

PNG_FIXED_EXPORT(259, void, png_set_mDCV_fixed, (png_const_structrp png_ptr,
png_inforp info_ptr,
/* The admissible range of these values is not the full range of a PNG
* fixed point value. Negative values cannot be encoded and the maximum
* value is about 1.3 */
png_fixed_point int_white_x, png_fixed_point int_white_y,
png_fixed_point int_red_x, png_fixed_point int_red_y,
png_fixed_point int_green_x, png_fixed_point int_green_y,
png_fixed_point int_blue_x, png_fixed_point int_blue_y,
/* These are PNG unsigned 4 byte values: 31-bit unsigned values. The MSB
* must be zero.
*/
png_uint_32 mastering_display_maximum_luminance_scaled_by_10000,
png_uint_32 mastering_display_minimum_luminance_scaled_by_10000));
#endif

#ifdef PNG_oFFs_SUPPORTED
PNG_EXPORT(145, png_uint_32, png_get_oFFs, (png_const_structrp png_ptr,
png_const_inforp info_ptr, png_int_32 *offset_x, png_int_32 *offset_y,
Expand Down
109 changes: 107 additions & 2 deletions pngget.c
Original file line number Diff line number Diff line change
Expand Up @@ -787,7 +787,7 @@ png_get_sPLT(png_const_structrp png_ptr, png_inforp info_ptr,
#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_const_inforp info_ptr, png_bytep colour_primaries,
png_bytep transfer_function, png_bytep matrix_coefficients,
png_bytep video_full_range_flag)
{
Expand All @@ -805,10 +805,115 @@ png_get_cICP(png_const_structrp png_ptr,
return (PNG_INFO_cICP);
}

return (0);
return 0;
}
#endif

#ifdef PNG_cLLI_SUPPORTED
# ifdef PNG_FIXED_POINT_SUPPORTED
png_uint_32 PNGAPI
png_get_cLLI_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,
png_uint_32p maxCLL,
png_uint_32p maxFALL)
{
png_debug1(1, "in %s retrieval function", "cLLI");

if (png_ptr != NULL && info_ptr != NULL &&
(info_ptr->valid & PNG_INFO_cLLI) != 0)
{
if (maxCLL != NULL) *maxCLL = info_ptr->maxCLL;
if (maxFALL != NULL) *maxFALL = info_ptr->maxFALL;
return PNG_INFO_cLLI;
}

return 0;
}
# endif

# ifdef PNG_FLOATING_POINT_SUPPORTED
png_uint_32 PNGAPI
png_get_cLLI(png_const_structrp png_ptr, png_const_inforp info_ptr,
double *maxCLL, double *maxFALL)
{
png_debug1(1, "in %s retrieval function", "cLLI(float)");

if (png_ptr != NULL && info_ptr != NULL &&
(info_ptr->valid & PNG_INFO_cLLI) != 0)
{
if (maxCLL != NULL) *maxCLL = info_ptr->maxCLL * .0001;
if (maxFALL != NULL) *maxFALL = info_ptr->maxFALL * .0001;
return PNG_INFO_cLLI;
}

return 0;
}
# endif
#endif /* cLLI */

#ifdef PNG_mDCV_SUPPORTED
# ifdef PNG_FIXED_POINT_SUPPORTED
png_uint_32 PNGAPI
png_get_mDCV_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,
png_fixed_point *white_x, png_fixed_point *white_y,
png_fixed_point *red_x, png_fixed_point *red_y,
png_fixed_point *green_x, png_fixed_point *green_y,
png_fixed_point *blue_x, png_fixed_point *blue_y,
png_uint_32p mastering_maxDL, png_uint_32p mastering_minDL)
{
png_debug1(1, "in %s retrieval function", "mDCV");

if (png_ptr != NULL && info_ptr != NULL &&
(info_ptr->valid & PNG_INFO_mDCV) != 0)
{
if (white_x != NULL) *white_x = info_ptr->mastering_white_x * 2;
if (white_y != NULL) *white_y = info_ptr->mastering_white_y * 2;
if (red_x != NULL) *red_x = info_ptr->mastering_red_x * 2;
if (red_y != NULL) *red_y = info_ptr->mastering_red_y * 2;
if (green_x != NULL) *green_x = info_ptr->mastering_green_x * 2;
if (green_y != NULL) *green_y = info_ptr->mastering_green_y * 2;
if (blue_x != NULL) *blue_x = info_ptr->mastering_blue_x * 2;
if (blue_y != NULL) *blue_y = info_ptr->mastering_blue_y * 2;
if (mastering_maxDL != NULL) *mastering_maxDL = info_ptr->mastering_maxDL;
if (mastering_minDL != NULL) *mastering_minDL = info_ptr->mastering_minDL;
return PNG_INFO_mDCV;
}

return 0;
}
# endif

# ifdef PNG_FLOATING_POINT_SUPPORTED
png_uint_32 PNGAPI
png_get_mDCV(png_const_structrp png_ptr, png_const_inforp info_ptr,
double *white_x, double *white_y, double *red_x, double *red_y,
double *green_x, double *green_y, double *blue_x, double *blue_y,
double *mastering_maxDL, double *mastering_minDL)
{
png_debug1(1, "in %s retrieval function", "mDCV(float)");

if (png_ptr != NULL && info_ptr != NULL &&
(info_ptr->valid & PNG_INFO_mDCV) != 0)
{
if (white_x != NULL) *white_x = info_ptr->mastering_white_x * .00002;
if (white_y != NULL) *white_y = info_ptr->mastering_white_y * .00002;
if (red_x != NULL) *red_x = info_ptr->mastering_red_x * .00002;
if (red_y != NULL) *red_y = info_ptr->mastering_red_y * .00002;
if (green_x != NULL) *green_x = info_ptr->mastering_green_x * .00002;
if (green_y != NULL) *green_y = info_ptr->mastering_green_y * .00002;
if (blue_x != NULL) *blue_x = info_ptr->mastering_blue_x * .00002;
if (blue_y != NULL) *blue_y = info_ptr->mastering_blue_y * .00002;
if (mastering_maxDL != NULL)
*mastering_maxDL = info_ptr->mastering_maxDL * .0001;
if (mastering_minDL != NULL)
*mastering_minDL = info_ptr->mastering_minDL * .0001;
return PNG_INFO_mDCV;
}

return 0;
}
# endif /* FLOATING_POINT */
#endif /* mDCV */

#ifdef PNG_eXIf_SUPPORTED
png_uint_32 PNGAPI
png_get_eXIf(png_const_structrp png_ptr, png_inforp info_ptr,
Expand Down
18 changes: 18 additions & 0 deletions pnginfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,24 @@ struct png_info_def
png_uint_32 iccp_proflen; /* ICC profile data length */
#endif

#ifdef PNG_cLLI_SUPPORTED
png_uint_32 maxCLL; /* cd/m2 (nits) * 10,000 */
png_uint_32 maxFALL;
#endif

#ifdef PNG_mDCV_SUPPORTED
png_uint_16 mastering_red_x; /* CIE (xy) x * 50,000 */
png_uint_16 mastering_red_y;
png_uint_16 mastering_green_x;
png_uint_16 mastering_green_y;
png_uint_16 mastering_blue_x;
png_uint_16 mastering_blue_y;
png_uint_16 mastering_white_x;
png_uint_16 mastering_white_y;
png_uint_32 mastering_maxDL; /* cd/m2 (nits) * 10,000 */
png_uint_32 mastering_minDL;
#endif

#ifdef PNG_TEXT_SUPPORTED
/* The tEXt, and zTXt chunks contain human-readable textual data in
* uncompressed, compressed, and optionally compressed forms, respectively.
Expand Down
16 changes: 16 additions & 0 deletions pngpread.c
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,22 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)
png_handle_cICP(png_ptr, info_ptr, png_ptr->push_length);
}

#endif
#ifdef PNG_READ_cLLI_SUPPORTED
else if (png_ptr->chunk_name == png_cLLI)
{
PNG_PUSH_SAVE_BUFFER_IF_FULL
png_handle_cLLI(png_ptr, info_ptr, png_ptr->push_length);
}

#endif
#ifdef PNG_READ_mDCV_SUPPORTED
else if (png_ptr->chunk_name == png_mDCV)
{
PNG_PUSH_SAVE_BUFFER_IF_FULL
png_handle_mDCV(png_ptr, info_ptr, png_ptr->push_length);
}

#endif
#ifdef PNG_READ_eXIf_SUPPORTED
else if (png_ptr->chunk_name == png_eXIf)
Expand Down
Loading

0 comments on commit 8c7c2cf

Please sign in to comment.