-
Notifications
You must be signed in to change notification settings - Fork 624
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for reading and writing the cICP chunk #565
base: libpng16
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not an important comment. Just an interesting observation that I may not have considered before: An interesting trade off. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That stuff isn't compiled in; see pngdebug.h It's not supported, or, more accurately, it's maintainer only and pulls in unexpected stuff. I've never even tried to enable it! Compilers use string table compaction algorithms. The one I know was implemented as a unix command based on finding common trailing substrings. Use "readelf -S .libs/libpng16.so.16.44.0" to see the section sizes; the bad news is the .text segment (i.e. the code) which is close to 1/4MByte, the string table is 12532 bytes (this is on a 64-bit Intel/AMD system). |
||
|
||
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, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interestingly, the string literal sharing doesn't happen here. |
||
|
||
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; | ||
Comment on lines
+2053
to
+2054
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this is the right place to set this. Rather, this is where we should confirm the IDAT hasn't yet arrived. if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch. The chunk placement has to be checked first. This code is extremely unmaintainable; it's a state machine implemented by copy'n'paste and then replicated in pngpread.c. Any non-IDAT chunk which interrupts the IDAT stream, even if misplaced, should terminate the IDAT stream but it looks like the only ones that do are the ones that are valid after IDAT. But take a look at line 129 of png.c; line 132 should have already set the flag before calling any of the ancillary png_handle_ routines... But then I suspect line 129 can never succeed. |
||
|
||
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; | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Insert after the read & finish: /* If a colorspace error has already been output skip this chunk */ |
||
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) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The file is invalid and should fail; cICP is following PLTE. See table 6 in PNG-3. I suggest you just add an sRGB cICP to pngtest.png (in the correct place; run pngtest a couple of times to sort pngout.png).
Gwenview reports this error (using the current, unpatched, libpng):
"Gwenview cannot apply color profile on QImage::Format_Indexed8 images."
I'm guessing Qt6 already has support for cICP but I'll investigate.
UPDATE: I see what happened. I hadn't realized you had run it through pngtest (I should have known given that I know pngtest fails on chunk-reorder!) Your call to png_write_cICP is after the call to png_write_info_before_PLTE. I moved it to line 140 (i.e. inside the PNG_COLORSPACE_SUPPORTED, after png_write_gAMA_fixed) and that fixed the problem (since the read code doesn't notice the original error).
You can fix the file easily with TweakPNG (which preserves but is capable of altering the order).
FYI the three individual png_write_info_... calls can be called with three different png_info structures as can the three sequential png_read_info_ APIs but maybe not the progressive reader. Doing that (using three png_infos) is the only way to control where chunks which may appear in multiple locations appear.