Skip to content
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

Preserve 8-bit color tables when importing/exporting 8-bit images #255

Open
tannerhelland opened this issue Mar 25, 2018 · 0 comments
Open

Comments

@tannerhelland
Copy link
Owner

I received the following feedback on photodemon.org and am seriously considering it for 7.2's release:

Today I came upon this app while searching for dither related apps and the sort and frankly this is very good!

However, there is one thing that could use improvement. Namely, when you open indexed 256 color images, be it gif/pcx/bmp/png-8 and do anything you lose the original indexing of the color table!

Method to reproduce is simple: open any 256 color indexed file and then go just save it, choose gif or bmp, doesn't matter which, and then go inspect the color table of result file. It has been reordered by PhotoDemon. In my example, PhotoDemon reduced the 255 colors into 160 shades and filled the rest with grayscale shades at end that are not even used by the art.

Now I figure the response is along the lines of...our app converts the indexed art into RGB24/32 within app memory for editing functions and thus mangles the color list when it rebuilds the table...

...but it's worth asking if this could allow edit and still keep original palette positions while of course allowing some of the editing functions (I realise not all editing options can be viable for indexed) to change said colors.

If not, then I will just have to settle for doing prior palettization edits than after hand edits with this.

I've just added a series of commits that will make this... "more" possible than before (see 7bd5e70, for example, also 490f58d), but because file import/export is heavily reliant on 3rd-party libraries, there are parts of this equation I don't control - and as usual, they're the parts that will be most tedious to work around. (At present, I pass our internal 32-bpp RGBA data, with only minor preprocessing based on export settings, to various 3rd-party libraries - and they are then responsible of converting the image data to appropriate export color depths.)

To preserve color tables, I'll need to switch PD's export engine over to a fully internal solution for generating 1/2/4/8-bpp data. We have most of these capabilities already, thanks to a bunch of palette-related work in this release cycle, but these features are currently built around "effect" usage, not formal export usage. I'll need to rework a bunch of internal guts - including PD's entire export interface - so that PD itself handles things like 8-bpp data generation, and that data gets passed to external libraries who only handle the write to file (as opposed to generating the 8-bpp data themselves).

Because image export is horrifically complicated, and it's so crucial to a working program, I'll need to tackle this more slowly and cautiously than I usually do. I'll try to reference this commit as various bits fall into place.

tannerhelland added a commit that referenced this issue Apr 20, 2018
I still need to do a final round of testing (and a bit of code clean-up
now that everything is implemented), but with this feature finished and
active, I can (proudly!) state that PhotoDemon now loads all PNG files
using its own internal, custom-built PNG parser.  Our parser handles all
combinations of color types and bit-depths (yes, even strange ones like
HDR grayscale+alpha), and for the first time, color-management is deeply
integrated into the loader.  When ICC profiles are embedded, they are
applied directly to raw PNG data, without any pre-processing (as we had
to do with 3rd-party libraries).  This guarantees maximum quality across
the board, and allows us to produce identical results to Photoshop on
HDR images.

Similarly, on paletted images we now detect and store the original,
unmodified file palette.  This is a huge step toward serious work on
#255 (although I still need to write a PNG exporter, *sigh*), and it
lets me drop a bunch of tedious code that requires multiple 3rd-party
libraries to correctly identify embedded image palettes.

Esoteric PNG chunks are also no problem; we grab the ones that are
relevant to PD and process them fully.  Ones that are *not* essential to
PD are off-loaded to ExifTool.

I'll be doing some heavy testing over the next few days to ensure that I
haven't missed anything, but as of now, nightly builds are already using
the new PNG parser.  Please let me know if you run into any unexpected
results.
tannerhelland added a commit that referenced this issue Apr 9, 2019
I think I'm about ready to call PD's new PNG engine "finished".

By default, PD now outputs smaller PNGs than any other major software (including Photoshop!).  It uses the full breadth of PNG encoding features plus a [high-performance Deflate engine](https://github.com/ebiggers/libdeflate) to achieve this.  If you don't care about the new compression gains, note that the new system also outputs PNGs *faster* than previous versions - which is particularly relevant when exporting ORA files (which hold a collection of individual PNG layers).  As part of this commit, PD's ORA exporter has been fully switched to the new PNG engine.

Because I finally have total control of the PNG import/export process, I hope a number of long-requested features will finally be possible (e.g. #255 is *finally* feasible).

Also included in this commit is a new German language file c/o Roy K.  Thank you, Roy!
tannerhelland added a commit that referenced this issue Jul 1, 2020
Relates to #255

It has taken me a long time to add this, sorry!  Also, this feature is only available for PNG files at present because that's a file format that I control end-to-end (e.g. no 3rd-party libraries involved).  That's the only way I can make this work, as libraries like FreeImage can modify palettes internally (like always padding out to 256-colors) without any way to override 'em.

Anyway, the idea here is simple: if a user loads a PNG file, then modifies it, then wants to save it out to file with identical color-depth settings (including palette order), there is now a "use original file settings" toggle that does just that.

Per the request I originally received, this is useful when editing 8-bpp images with fixed palettes.  Sometimes these files have palettes where palette order matters, and reordering the palette - even if it reduces file size - is undesirable.

This was a complicated feature to enable because has to work across the huge matrix of possible PNG settings - some of which we now need to cache when a file is first-loaded, just in case we need to access them again later.  I think I've covered all possible branches, including esoteric ones like HDR images, but please let me know if you encounter any surprises.

In the future, I may be able to extend this to other file formats, but it'll always require custom encoders and decoders to make it work.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant