-
Notifications
You must be signed in to change notification settings - Fork 12
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
Formalize Apple's CgBI chunk #45
Comments
Note that Apple's variant is patented: https://patents.google.com/patent/US20080177769 Also IIUC any official documentation, if it exists, is under NDA. |
from 14.1 Additional chunk types:
From 14.3.1 Ordering of critical chunks:
So as soon as this chunk was standardized, it would be a backwards-incompatible change because all older decoders would terminate on encountering it. (They would now, which is fine because it is a critical private chunk). From Guidelines for new chunk types
From Introduction
It does not seem that this PNG-like asset has been designed with a view to possible later standardization. |
I contacted some friends at Apple to see if anyone from Apple would like to join the PNG WG. But for the moment, I think this issue about the CgBI chunk can be closed. @svgeesus is right that if we wanted to add support for premultiplied and/or BGRA, they should be new chunks anyway. I'll close for now. If we want to revisit BGRA / premultiplied alpha, lets open a new issue. |
https://patents.google.com/patent/US20080177769 links to https://patentcenter.uspto.gov/#!/applications/11650712 which says that that patent expired on 06/11/2018. In any case, I am following up with a professional patent lawyer.
I'm not asking to create a new Yes, it might require an asterisk to the "chunk type's second byte denotes private/public status" rule: "an exception was made for the I develop software that processes PNG images (amongst other things). In practical terms, this means things that start with an 8 byte A decade or two from now, if a digital archaeologist came across a PNG/CgBI image (there's possibly orders of magnitude more PNG/CgBI images than APNG images in existence, because of iOS), their job would be easier if the official PNG specification described how to decode it.
I don't see the change as backwards-incompatible: your quote from the spec says "encounter unknown critical chunks", not "encounter unknown critical public chunks". Older decoders used to terminate on encountering it. They can still do after PNG/CgBI gets written up in the spec.
I am reminded of APNG's long road to being officially blessed. As you know, the PNG spec authors were reluctant to embrace it for many years. If I remember correctly, APNG folks were officially told (by Glenn??) that PNG isn't animated, so APNG should use a different magic string. But given a critical mass of software support (Firefox first and other browsers later in APNG's case, iOS in CgBI's case), popular implementation trumps specification. |
Is there precedent for standardizing a reverse-engineered (and incomplete) specification? If someone had to tell us how to handle Apple's variant of PNG it would be the company who invented it. |
That's a good argument. You convinced me, actually. I'll have to reflect for a bit. Would this be a good candidate for an extension rather than the core spec? |
I'm re-opening since 1.) the patent may have expired, and 2.) the public/private bit may not actually be a deciding factor. I still hope we can get input from a Apple. |
The related |
I have been trying to reverse-engineer this chunk properly, since nobody ever figured out what the chunk content means, most third-party tools just look at the chunk's mere presence and assume "raw zlib, premultiplied alpha, BGRA", which isn't correct (some don't even fix the premultiplied alpha which is worse). While experimenting, I found even Apple software doesn't handle it consistently. I easily made a png file that is shown differently on Preview vs Safari on Mac, and another that is shown differently on Mac vs iOS. The one thing I found for sure is that bit 0x1 in the first byte of the chunk data (ie. bit 0x10000000 if you consider the chunk as containing a big-endian uint32) is what determines whether the file is using raw zlib. Every third-party tool I found to deal with Apple's PNGs assumes the IDAT will have headerless raw zlib if the CgBI chunk is present, without checking if that bit is set. I also spent days trying to understand bit 0x2 in the first byte; it maps to an internal flag called ...do you really want to put this mess into a standard spec? |
This and the fact that not even Apple implements it consistently are more reasons I won't be supporting it in spng.
It could mean some or all scanlines are encoded with filter type 1 (Sub), some tools might tell you the filter type for each scanline (spng exposes this through |
Thank you for your research, @nicolas17 . This is both good to hear and also unfortunate. On one hand, the PNG Working Group has agreed to accept private chunks into the standard in rare occasions where it makes sense, such as existing APNGs. This opens the doors for accepting the private CgBI chunk. But on the other hand:
@nicolas17 , do you happen to know if most (almost all?) CgBI-supporting decoders are consistent and only a handful are off? For example, maybe only a recent version of MacOS changed behavior and it is consistent-enough to not discredit. If we want to support premultiplied alpha and/or BGRA, it might be best for us to introduce those as a new chunks in a clean-room approach, not considering what Apple has done. Unfortunately, that rather defeats the purpose of accepting widely-adopted, existing chunks. |
Do |
There certainly are some situational benefits:
That said, it might be best for us to consider these things outside of Apple's chunks. I still have not heard back from Apple. And the original intent (IIUC) was to recognize a defacto standard. But if there are multiple interpretations within Apple then I'm not sure the defacto standard idea applies. It would be great to have Apple's involvement to form a standard, single interpretation. But as-is, we might want to file separate issues to consider each of those benefits individually and not use Apple's chunks. |
I assume you mean 0x1000000 (with 6 zeroes after the one) instead of 0x10000000 (with 7 zeroes after the one). In any case, I believe CgBI stands for CGBitmapInfo. https://developer.apple.com/documentation/coregraphics/cgbitmapinfo is Apple's official documentation. https://developer.apple.com/documentation/coregraphics/cgimagealphainfo sounds related, and there's constants within that like https://developer.apple.com/documentation/coregraphics/cgimagealphainfo/kcgimagealphapremultipliedlast that says "The alpha component is stored in the least significant bits of each pixel and the color components have already been multiplied by this alpha value. For example, premultiplied RGBA. [emphasis added]". That kcgimagealphapremultipliedlast web page doesn't actually give a numerical value, but https://docs.rs/core-graphics/0.14.0/i686-apple-darwin/core_graphics/base/constant.kCGImageAlphaPremultipliedLast.html gives a value of 1.
|
Yes, the original intent is to recognize a de facto standard used today by billions of devices. Minting new chunks in a clean-room approach doesn't address that. "Multiple interpretations" might merely be down to some Apple software using ther internal library version N (and using fallback behavior for unknown feature bits / chunks, or simply a bug whose fix wasn't backported) and other Apple software using version N+1.
Yes, that would be the ideal scenario. |
A raw deflate stream (instead of zlib) can also be faster to encode and decode. The Adler-32 checksum computation is cheap but it isn't free and can show up in CPU profiles. |
I believe that Of course, |
I made a png using paeth filter on all scanlines, I added a CgBI chunk with the 0x2000_0000 bit set, I hooked _cg_png_read_row and confirmed I didn't really make any more research progress during January though, and I have been procrastinating a proper writeup... |
Decompiling Apple's pngcrush shows code like
An example: when Apple's pngcrush adds CgBI to a file, it sets the last byte to 0x02 or 0x06 depending on whether there is an alpha channel. When reading a file with CgBI (eg. converting it back to a normal png), it seems to ignore the last byte altogether. The ImageIO framework does look at the last byte, and software like Safari renders images differently depending on the value. So that's Apple's ImageIO and pngcrush interpreting different values of the last byte in different ways (one ignores it). |
My +1 here as we just encountered this issue with We may create an extension to pngchunk to deal with iDOT as described at the hackerfactor link. |
The 4th letter being capitalized means it is unsafe to change the file if the chunk isn't understood. But if a user is using pngcheck-ruby only to read the file (and not alter it), it should be able to skip ancillary chunks it does not understand. That might be an issue to fix in pngcheck-ruby. |
Thanks @ProgramMax for the tip. Since pngcheck is an associated part of the reference libpng library, we will have to either fork pngcheck to allow a "read-only" validation, or implement it at the binding level that encountering iDOT is acceptable for read-only purposes. |
Apple has an unofficial PNG extension, used by their tools (a modified pngcrush:
xcrun -sdk iphoneos pngcrush -iphone
) to create iOS app assets.If you're updating the PNG spec to 3.0, consider making it official. It might not be the extension I would have designed, but if there's millions of iOS devices out there, there's zillions of PNG/CgBI images already out there in the real world.
I don't have official documentation, but here's what others have deduced:
https://iphonedev.wiki/index.php/CgBI_file_format
https://github.com/DHowett/pincrush
https://www.hackerfactor.com/blog/index.php?/archives/895-Connecting-the-iDOTs.html
http://jongware.com/pngdefry.html
This has an example PNG/CgBI image.
https://github.com/jakubknejzlik/cgbi-to-png
This has an example PNG/CgBI image. Not sure if their code does the premul -> non-premul conversion properly.
https://axelbrz.com/?mod=iphone-png-images-normalizer
Not sure if their code does the premul -> non-premul conversion properly.
The text was updated successfully, but these errors were encountered: