-
Notifications
You must be signed in to change notification settings - Fork 732
APNG — let's do this! #706
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
Conversation
|
@unitarou, @ProgramMax, @svgeesus, @jbowler, @peterkaczorowski: |
|
Wonderful! A merge with independent APNG support has just been prepared for GiMP, but the team is very willing to prepare a version compatible with the new LIBPNG. I’ll resume work on wxWidgets and my extensions for KiCad. Great news. Thank you, Cosmin! |
It's sooo nice to see the enthusiasm, @peterkaczorowski :-) Mind you, this comes with the important caveat that we are in the earliest alpha stage of libpng v2. This PR is going to be literally the first feature added, and it will still take a while until this brand new libpng thingy becomes ready for prime time. I added you to the list of reviewers, but please spread the word over to those projects, too: anybody who wants to contribute a review is hereby invited to contribute a review. |
|
@ctruta: this should be checked in already shouldn't it? My understanding of the git development process is that a branch is created for a set of changes ("develop" in this case) and then changes are submitted and checked in. To start the process you have to actually check the changes in to the branch... |
|
@ctruta: The changes use This is a point where consistency is important. Just change all the |
|
There's no handling for out-of-order or damaged sequence numbers. Better than what is being done move the sequence number iterator on read into the app space, then it can choose how to handle the error. It is also better to allow the frames to be saved. As it is an editor can't fix up a damaged APNG using libpng. In any case |
|
I did some tests with
This is because the It's standard, and unfortunate, that adding "known" chunks breaks programs that rely on the unknown handling; the chunks are "known" by libpng but not the app so apps that use png_info from read to write a PNG can end up doing the wrong thing with the new chunks.
I strongly recommend disabling APNG handling by default. It's no significant work for an app to call an "enable APNG" API (e.g. png_set_option) since it has to call all the complex "next_frame" APIs and allocate buffers for the frames anyway. If you don't like that it could be enabled automagically when the app calls png_get_acTL but that's a little more complicated internally. |
|
CDfcTL in pngrutil.c is wrong (not a result of this change): "25U" should be "26U"; it's a typo and it is in 1.6 as well. The "handle" functions for those two chunks should just invoke the "unknown" handling; this will discard them by default. This will avoid the warning/error if the sequence number is wrong; if the chunks are being skipped why issue a stream of warnings? I've already made the point out png_error'ing out on an ancillary chunk which is not used. |
|
I hacked the first fcTL in "clock.png" to have an invalid sequence number (1) then tried pngcrush again; remember pngcrush correctly removes acTL, fcTL and fdAT. pngcrush errors out with "Out-of-order sequence number in fcTL or fdAT". This is a major bug; it's an ancillary chunk and the app isn't going to use it. Preventing it being read by, I think, any app that doesn't have special handling for the APNG chunks is wrong. It's a png_chunk_benign_error, just like having a bad length hIST or, indeed, tRNS. AND Chrome displays it correctly (as a static image). Just use TweakPNG to change the first fcTL sequence number (I don't know if clock.png is copyright so I won't post the hacked version.) |
|
BUG (serious): the Fixing this will probably unbork a number of apps that would otherwise be borked. I'm working on a separate PR for pngcp that will, necessarily, include the change but it can be done anyway by anyone; the table is stored alphabetically. |
|
#710 fixes both the pngcp handling of the Apple banding chunk (this was wrong in 1.6 as well) and the handling of APNG when #706 is applied. The contrib/tools/pngcp.c fix can be applied to 1.6 (with adjustment for the different C dialect), the pngset.c change is not required though it is harmless (APNG chunks are not "known" in 1.6). The pngset.c change is required iff APNG support is added to 2.0 but is harmless regardless; every known chunk must be added to the list in pngset.c! |
|
Spurious and confusing code In In This is just plain confusing, even more so because png_handle_{acTL,fcTL and fdAT} are defined in pngrutil.c but not put in the table. Note that is no other png_handle_ function in the whole of libpng that is not fdAT handling needs to be consistent with IDAT. There are only two things that can happen; process it in the same way as IDAT or treat it as unknown. Hand crafting a completely new way of doing this doesn't make any sense to me; it's already done for IDAT so do it the same way! acTL and fcTL should not need special treatment. Repeating checks in png_handle_{acTL,fcTL} that are already in png_handle_chunk is unnecessary and confusing code duplication. |
|
Test case: Take "clock.png" and use TweakPNG to add a tEXt chunk before the third frame fcTL (sequence number 3, the second fcTL after IDAT). The resultant APNG animates fine with Chrome and is to spec, however the code around 4406 of pngrutil.c "ignores" the chunk and skips it, with a warning which should certainly not be there because the APNG is valid. Those chunks need to be cf my comment elsewhere on the KiCAD issue of needing labels on frames. I don't think I suggested anything but I'm thinking:
So Anyway, here are the conditions for the code:
Three of those recommendations are simply unimplementable with the current PR:
So my bogus fcTL before IDAT must be fixed.
So png_error is simply unacceptable.
So an editor needs to be able to extract out-of-order frames. While this can be done in the manner I demonstrated with AREATK that approach does not handle decoding of individual frames; the editor would have to write a new APNG first, possibly dropping incomplete frames. The AREATK solution was to read the whole APNG then just get the APNG chunks in order. That would work but it has to load the whole APNG first. An alternative is to buffer fcTL/fdAT in the unknown list then, when the next fcTL is found start decoding of the previous frame. If the fdAT are incomplete by the end of the APNG then the frame could be discarded or played with, most likely, only part of it rendering as the app preferred. |
|
I've merged all the PRs I've submitted into: https://github.com/jbowler/libpng/tree/libpng2-apng I added @MaartenBent 's fix for png_read_reinit when png_read_update_info is not called along with the fix for png_get_rowbytes in the contrary case where it is called. |
|
I reviewed the png_get_ functions, the png_get_next_frame... accessors are pure code bloat; they aren't necessary because they just duplicate the code in png_get_next_frame_fcTL and the caller needs all of the data sometime. Nothing else in PNG does this; the non-chunk accessors pull data out of png_struct, not png_info and it is weirdly confusing to have undocumented API duplication like this; which one should be used? |
|
png_set_... these should be (void) functions and need to call png_chunk_report. The error messages are inconsistently wordy; libpng lacks any i18n and the checks need to be concise and understandable because of that (libpng1 is very inconsistent, I'm trying to fix that!) Bear in mind that these checks are often simply blurted out to the application user so, for example, "Ignoring wasteful fcTL BLEND_OP_OVER in opaque images" is not going to be useful. Also that warning is erroneous; does libpng issue a warning if the filter on the first line of a pass is UP? Only NONE, SUB and AVG are useful on the first line, but it is not appropriate for the code which read a PNG to output diagnostics about the unknown code which wrote the PNG! The optimisation is also incorrect; see |
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.
I'm working on changes to address these and other comments.
|
There's a major bug in the new code to clear flags in png_struct::mode; that cannot happen and just does not work. It changes the whole way the parser (both progressive and sequential) works and only seems to have been done to implement png_handle_fcTL and reuse the row reading code. Clearly the row reading code can be changed to use different flags and I think it should be changed in that way: the design of "mode" is to store information about the position within the PNG stream WRT critical chunks, these are not critical chunks so removing the "AFTER_IDAT" flag is going to, as a minimum, mess up tests for chunks which must occur before IDAT. What happens if I add a cICP after IDAT in an APNG? That's not valid because of the positioning rules, but those check for !(png_struct::mode & PNG_HAVE_IDAT) In fact I think IEND will always fail. |
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.
This is all leading me to the conclusion that using a control structure in the manner of the simplified API would make this much easier to understand (well, some documentation would help). This doesn't just apply to "write", the control structure on "read" is also much better because doing it in both avoids the need from the unfortunate use of png_info (which png_info) in its place, I might have a look at that as it seems productive but I'll probably see if the PNG_HAVE_IDAT/AFTER_IDAT misuse can be fixed easily (I think it can).
|
@jbowler wrote:
John's assumption is correct. (Speaking for myself, about myself, to be clear.) Under the On the other hand, as far as I know, this APNG patch has been long in use in various APNG-supporting software, most notably in Mozilla. For that reason, I don't consider it to be bleeding-edge-untested, either. FYI, the CI verifications for the master branch (which stands for libpng-1.6.x) and for the develop branch (which stands for libpng-2.x) are here: Thank you everyone for your participation :-) |
Co-authored-by: Daisuke Nishikawa <daisuken@users.sourceforge.net> Reviewed-by: John Bowler <jbowler@acm.org> Reviewed-by: Maarten Bent <MaartenBent@users.noreply.github.com> Signed-off-by: Cosmin Truta <ctruta@gmail.com>
Delete redundant initializations, rename macros, rephrase messages, tidy up comments, etc. Reviewed-by: John Bowler <jbowler@acm.org> Reviewed-by: Maarten Bent <MaartenBent@users.noreply.github.com> Signed-off-by: Cosmin Truta <ctruta@gmail.com>
|
@svgeesus @ctruta The GIMP approach (in the development branch, 3.1.2) is the same as I have suggested before but (unlike AREATK) it is stateful so it uses the "unknown chunk callback" to store the frames as the PNG is read. It's clean and a good example of how to do it. It's a simple modification of the main GIMP PNG read code in 3.0.4, Max Stepin is quoted as the reference for the APNG implementation. The patch appears to be from the sourceforge web site. There is also a version for GIMP with is covered by GPL-2/GPL-3 The patch itself does not contain a copyright; SourceForge lists the license as "zlib/libpng" but that's not in the patch anywhere either. That aside I looked at the original patch (from sourceforge) applies to 1.6. The way it works is a bit of a problem because it seems certain it will break GIMP. At one point it was known to cause problems for Chromium as well. This comes back to what I've said before about adding new "known" chunks however I'm pretty sure that this particular breakage can be avoided. |
|
@peterkaczorowski this is the code: https://sourceforge.net/p/libpng-apng/code/ci/master/tree/ It's been available since 1.2.29, possibly earlier elsewhere. It's the code in the NetScape/Mozilla browser, I think. It's available on many systems. The problem is it causes problems to some existing code, not least Chromium but it's pretty much always been there. |
|
Better, here is the code in git: https://github.com/mozilla-firefox/firefox/tree/main/media/libpng The authors still aren't there for sure because the log shows changes that are apparently part of the changes in a new release checked in separately via a patch, however this file would seem to be authorative: https://github.com/mozilla-firefox/firefox/blob/main/media/libpng/MOZCHANGES |
|
@jbowler wrote: For the record: this is what I applied. https://sourceforge.net/projects/libpng-apng/files/libpng16/1.6.49/ I started with a temporary application to my local libpng16 branch. Then I did a cherry-pick with an obligatory rework onto the develop branch. And then, finally, the subsequent cleanup commit, and the fixes that everybody else contributed. I credited @unitarou (Daisuke Nishikawa) in the AUTHORS file.
Thank you for pointing it out. The AUTHORS file must be updated for sure. |
|
@ctruta wrote:
Hello! I'm happy it's merged. |
|
Arigatō, @unshumikan 👍 |
No description provided.