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

Image decode API for color spaces and gamma correction. #39

Closed
nigeltao opened this issue Mar 25, 2021 · 5 comments
Closed

Image decode API for color spaces and gamma correction. #39

nigeltao opened this issue Mar 25, 2021 · 5 comments

Comments

@nigeltao
Copy link
Collaborator

wuffs_base should have some way to represent or process a PNG image's gAMA, iCCP or similar chunks.

nigeltao added a commit that referenced this issue Oct 15, 2021
nigeltao added a commit that referenced this issue Oct 20, 2021
nigeltao added a commit that referenced this issue Oct 20, 2021
nigeltao added a commit that referenced this issue Nov 5, 2021
@nigeltao
Copy link
Collaborator Author

nigeltao commented Nov 11, 2021

Code has landed to decode PNG's cHRM, gAMA, iCCP and sRGB chunks. The example/imageviewer program demonstrates basic gamma correction: it has a -screen_gamma=N.N flag and test/data/red-blue-gradient.*.png is a very basic test suite.

This is all admittedly very rough and under-documented. This is relatively new code, a work in progress, and in terms of prioritizing limited work time, documentation competes with other feature work.

That example/imageviewer program uses the higher level wuffs_aux::DecodeImage C++ API. If you're curious to follow that rabbit hole to the lower level C/C++ API, look for the DecodeImageHandleMetadata and HandleMetadata implementations in internal/cgen/auxiliary/*.cc. Again, this is not well documented yet, but the lower level APIs might make a little more sense if you keep in mind:

  1. Wuffs' image, image metadata and color correction APIs span many file formats and ICC profiles aren't just about PNG. I'd like to avoid those APIs having tens of little, format-specific methods, so there's some abstraction that might look weird at first glance.
  2. Those APIs also support streaming input and cannot assume that the entire input resides in contiguous memory.
  3. Those APIs cannot allocate memory.

Currently, the example/imageviewer program code (instead of the Wuffs library per se) has to explicitly apply gamma correction (look for lut in example/imageviewer/imageviewer.cc). Long term, this (and color correction in general) may move into the Wuffs library for "out of the box" support, but that would need some substantial API design work, implementation work, and maybe SIMD-related compiler work too.

For chunks other than gAMA, this patch below demonstrates how to get the raw data but, today, you will need additional third party code (e.g. Skia's Color Management System, skcms) to do something with that data (other than printf it). For manual testing, test/data/bricks-*.png have some cHRM and sRGB chunks.

diff --git a/example/imageviewer/imageviewer.cc b/example/imageviewer/imageviewer.cc
index 96938453..21b12ff9 100644
--- a/example/imageviewer/imageviewer.cc
+++ b/example/imageviewer/imageviewer.cc
@@ -167,14 +167,33 @@ class MyDecodeImageCallbacks : public wuffs_aux::DecodeImageCallbacks {
   std::string  //
   HandleMetadata(const wuffs_base__more_information& minfo,
                  wuffs_base__slice_u8 raw) override {
-    if (minfo.flavor == WUFFS_BASE__MORE_INFORMATION__FLAVOR__METADATA_PARSED) {
-      switch (minfo.metadata__fourcc()) {
-        case WUFFS_BASE__FOURCC__GAMA:
-          // metadata_parsed__gama returns the inverse gamma scaled by 1e5.
-          m_combined_gamma =
-              1e5 / (g_flags.screen_gamma * minfo.metadata_parsed__gama());
-          break;
-      }
+    switch (minfo.metadata__fourcc()) {
+      case WUFFS_BASE__FOURCC__CHRM:
+        printf(
+            "  HandleMetadata chrm_wx=%u\n",
+            minfo.metadata_parsed__chrm(
+                WUFFS_BASE__MORE_INFORMATION__METADATA_PARSED__CHRM__WHITE_X));
+        printf(
+            "  HandleMetadata chrm_wy=%u\n",
+            minfo.metadata_parsed__chrm(
+                WUFFS_BASE__MORE_INFORMATION__METADATA_PARSED__CHRM__WHITE_Y));
+        printf("  HandleMetadata chrm_rx=%u\n",
+               minfo.metadata_parsed__chrm(
+                   WUFFS_BASE__MORE_INFORMATION__METADATA_PARSED__CHRM__RED_X));
+        // Etcetera.
+        break;
+      case WUFFS_BASE__FOURCC__GAMA:
+        printf("  HandleMetadata gama=%u\n", minfo.metadata_parsed__gama());
+        // metadata_parsed__gama returns the inverse gamma scaled by 1e5.
+        m_combined_gamma =
+            1e5 / (g_flags.screen_gamma * minfo.metadata_parsed__gama());
+        break;
+      case WUFFS_BASE__FOURCC__ICCP:
+        printf("  HandleMetadata iccp ptr=%p len=%zu\n", raw.ptr, raw.len);
+        break;
+      case WUFFS_BASE__FOURCC__SRGB:
+        printf("  HandleMetadata srgb=%u\n", minfo.metadata_parsed__srgb());
+        break;
     }
     return wuffs_aux::DecodeImageCallbacks::HandleMetadata(minfo, raw);
   }
@@ -243,7 +262,10 @@ load_image(const char* filename) {
 
   uint64_t dia_flags = 0;
   if (g_flags.screen_gamma > 0) {
+    dia_flags |= wuffs_aux::DecodeImageArgFlags::REPORT_METADATA_CHRM;
     dia_flags |= wuffs_aux::DecodeImageArgFlags::REPORT_METADATA_GAMA;
+    dia_flags |= wuffs_aux::DecodeImageArgFlags::REPORT_METADATA_ICCP;
+    dia_flags |= wuffs_aux::DecodeImageArgFlags::REPORT_METADATA_SRGB;
   }
 
   MyDecodeImageCallbacks callbacks;

@nigeltao
Copy link
Collaborator Author

Code has landed to decode PNG's cHRM, gAMA, iCCP and sRGB chunks.

I forgot to mention: this has landed in release/c/wuffs-unsupported-snapshot.c but it won't hit release/c/wuffs-v0.3.c (or the wuffs-mirror-release-c repo) until the next 0.3 beta gets tagged.

@nigeltao
Copy link
Collaborator Author

v0.3.0-beta.11 has been tagged.

@pjanx
Copy link
Contributor

pjanx commented Nov 18, 2021

Thanks, I have a terrible backlog that includes learning OpenGL, but I'll try to integrate and test it soon-ish.

@pjanx
Copy link
Contributor

pjanx commented Dec 26, 2021

As far as I can tell, it works very well and there is nothing to add, except for, perhaps, documentation of all the possibilities within supported formats. Luckily, so far I haven't felt a need to special-case any format.

One ugly detail: wuffs_base__frame_config__struct::background_color needs to be unpremultiplied, colour corrected, and remultiplied for any sort of accurate processing. But it will likely be either fully opaque or fully transparent.

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

2 participants