GraphicsMagick: JXL: Support reading and writing 32-bit 'float' ...

GraphicsMagick Commits <[email protected]>
Newsgroups gmane.comp.video.graphicsmagick.cvs
Message-ID <mailman.33666.1671400394.1567.graphicsmagick-commit@lists.sourceforge.net>
changeset ad870e7ecd12 in /hg/GraphicsMagick
details: http://hg.GraphicsMagick.org/hg/GraphicsMagick?cmd=changeset;node=ad870e7ecd12
summary: JXL: Support reading and writing 32-bit 'float' images.

diffstat:

 ChangeLog          |    9 +++
 NEWS.txt           |    6 +-
 coders/jxl.c       |  136 ++++++++++++++++++++++++++++++++++++++++++++++------
 magick/image.c     |    6 ++
 www/Changelog.html |    6 ++
 www/NEWS.html      |    5 +-
 6 files changed, 149 insertions(+), 19 deletions(-)

diffs (322 lines):

diff -r 6e880ceeaece -r ad870e7ecd12 ChangeLog
--- a/ChangeLog	Sun Dec 18 09:11:27 2022 -0600
+++ b/ChangeLog	Sun Dec 18 15:53:02 2022 -0600
@@ -1,5 +1,14 @@
 2022-12-18  Bob Friesenhahn  <[email protected]>
 
+	* NEWS.txt: Updated the news.
+
+	* magick/image.c (SetImageDepth): Restore is_monochrome and
+	is_grayscale image flags.  Changing depth should not change the
+	nature of 'gray'.
+
+	* coders/jxl.c: Support reading and writing 32-bit 'float'
+	images. Need a Q32 build in order to write 32-bit 'float' images.
+
 	* fuzzing/oss-fuzz-build.sh: Remove xz --with-pic=yes option which
 	now seems to annoy oss-fuzz build.
 
diff -r 6e880ceeaece -r ad870e7ecd12 NEWS.txt
--- a/NEWS.txt	Sun Dec 18 09:11:27 2022 -0600
+++ b/NEWS.txt	Sun Dec 18 15:53:02 2022 -0600
@@ -140,6 +140,10 @@
 * Blob: The ReadBlobString() function has been re-written to perform
   better when reading from files.
 
+* JXL: The JXL coder is updated to compile with what will likely
+  become JXL 0.8.0.  Support for 16-bit 'short' samples and 32-bit
+  float samples added.
+
 * MIME: GM "magick" to MIME mappings have been added for apng, avif,
   bmp, ico, and webp (regardless of if they are supported).
 
@@ -154,7 +158,7 @@
 
 * Update bundled libjpeg to version 9e.
 
-* Update bundled libtiff to version 4.4.0 (but still compilable using MSVC2008!).
+* Update bundled libtiff to version 4.5.0 (but still compilable using MSVC2008!).
 
 Build Changes:
 
diff -r 6e880ceeaece -r ad870e7ecd12 coders/jxl.c
--- a/coders/jxl.c	Sun Dec 18 09:11:27 2022 -0600
+++ b/coders/jxl.c	Sun Dec 18 15:53:02 2022 -0600
@@ -19,8 +19,15 @@
 % Status: Only support basic images (no animations) with grayscale/SRGB colorspace
 * Note that JXL is a C++ library so does require linking with a c++ compiler.
 *
-* Currently tested vs libjxl-0.6.1 on ubuntu only, likely will have build problems
+* Currently tested vs libjxl-0.7.0 on ubuntu only, likely will have build problems
 * on other platforms. Also note the amount of third-party-libs required!
+*
+* Features still to be completed:
+*
+*   * Support linear gray
+*   * Support CMYK
+*   * Support embedded profiles
+*   * Support 16-bit float ("Half") format
 */
 
 #include "magick/studio.h"
@@ -294,9 +301,10 @@
       if (image->matte) {
         FOR_PIXEL_PACKETS
           {
-            SetRedSample(q,ScaleCharToQuantum(*p));
-            SetGreenSample(q,ScaleCharToQuantum(*p));
-            SetBlueSample(q,ScaleCharToQuantum(*p)); p++;
+            const Quantum s = ScaleCharToQuantum(*p); p++;
+            SetRedSample(q,s);
+            SetGreenSample(q,s);
+            SetBlueSample(q,s);
             SetOpacitySample(q,MaxRGB-ScaleCharToQuantum(*p)); p++;
             q++;
           }
@@ -304,9 +312,10 @@
           } else {
         FOR_PIXEL_PACKETS
           {
-            SetRedSample(q,ScaleCharToQuantum(*p));
-            SetGreenSample(q,ScaleCharToQuantum(*p));
-            SetBlueSample(q,ScaleCharToQuantum(*p)); p++;
+            const Quantum s = ScaleCharToQuantum(*p); p++;
+            SetRedSample(q,s);
+            SetGreenSample(q,s);
+            SetBlueSample(q,s); p++;
             SetOpacitySample(q,OpaqueOpacity);
             q++;
           }
@@ -361,9 +370,10 @@
       if (image->matte) {
         FOR_PIXEL_PACKETS
           {
-            SetRedSample(q,ScaleShortToQuantum(*p));
-            SetGreenSample(q,ScaleShortToQuantum(*p));
-            SetBlueSample(q,ScaleShortToQuantum(*p)); p++;
+            Quantum s = ScaleShortToQuantum(*p); p++;
+            SetRedSample(q,s);
+            SetGreenSample(q,s);
+            SetBlueSample(q,s);
             SetOpacitySample(q,MaxRGB-ScaleShortToQuantum(*p)); p++;
             q++;
           }
@@ -371,9 +381,10 @@
           } else {
         FOR_PIXEL_PACKETS
           {
-            SetRedSample(q,ScaleShortToQuantum(*p));
-            SetGreenSample(q,ScaleShortToQuantum(*p));
-            SetBlueSample(q,ScaleShortToQuantum(*p)); p++;
+            Quantum s = ScaleShortToQuantum(*p); p++;
+            SetRedSample(q,s);
+            SetGreenSample(q,s);
+            SetBlueSample(q,s);
             SetOpacitySample(q,OpaqueOpacity);
             q++;
           }
@@ -384,6 +395,47 @@
 }
 
 
+static MagickBool fill_pixels_float_grayscale(Image *image,
+                                              ExceptionInfo *exception,
+                                              float *p)
+{
+  long
+    x,
+    y;
+
+  PixelPacket
+    *q;
+
+  image->storage_class = DirectClass;
+
+  if (image->matte) {
+    FOR_PIXEL_PACKETS
+      {
+        Quantum s = RoundFloatToQuantum(*p * MaxRGBFloat); p++;
+        SetRedSample(q,s);
+        SetGreenSample(q,s);
+        SetBlueSample(q,s);
+        SetOpacitySample(q,MaxRGB-RoundFloatToQuantum(*p * MaxRGBFloat)); p++;
+        q++;
+      }
+    END_FOR_PIXEL_PACKETS
+      } else {
+    FOR_PIXEL_PACKETS
+      {
+        Quantum s = RoundFloatToQuantum(*p * MaxRGBFloat); p++;
+        SetRedSample(q,s);
+        SetGreenSample(q,s);
+        SetBlueSample(q,s);
+        SetOpacitySample(q,OpaqueOpacity);
+        q++;
+      }
+    END_FOR_PIXEL_PACKETS
+      }
+
+  return MagickTrue;
+}
+
+
 /** Convert any linear RGB to SRGB
  *  Formula from wikipedia:
  *      https://en.wikipedia.org/wiki/SRGB
@@ -587,6 +639,29 @@
   return str;
 }
 
+static const char *JxlDataTypeAsString(const JxlDataType data_type)
+{
+  const char *str = "Unknown";
+
+  switch (data_type)
+    {
+    case JXL_TYPE_FLOAT:
+      str = "Float";
+      break;
+    case JXL_TYPE_UINT8:
+      str = "UINT8";
+      break;
+    case JXL_TYPE_UINT16:
+      str = "UINT16";
+      break;
+    case JXL_TYPE_FLOAT16:
+      str = "FLOAT16";
+      break;
+    }
+
+  return str;
+}
+
 #define JXLReadCleanup()                                \
   MagickFreeResourceLimitedMemory(out_buf);             \
   MagickFreeResourceLimitedMemory(in_buf);              \
@@ -955,6 +1030,10 @@
                   {
                     res=fill_pixels_short_grayscale(image, exception, (unsigned short *) out_buf);
                   }
+                else if (format.data_type == JXL_TYPE_FLOAT)
+                  {
+                    res=fill_pixels_float_grayscale(image, exception, (float *) out_buf);
+                  }
               }
 
             if (!res)
@@ -1020,6 +1099,28 @@
   ThrowWriterException(code_,reason_,image_); \
  } while(1)
 
+static StorageType JxlDataTypeToDispatchStorageType(const JxlDataType data_type)
+{
+  StorageType storage_type = 0;
+
+  switch (data_type)
+    {
+    case JXL_TYPE_FLOAT:
+      storage_type = FloatPixel;
+      break;
+    case JXL_TYPE_UINT8:
+      storage_type = CharPixel;
+      break;
+    case JXL_TYPE_UINT16:
+      storage_type = ShortPixel;
+      break;
+    case JXL_TYPE_FLOAT16:
+      storage_type = ShortPixel; // FIXME: Not actually supported yet
+      break;
+    }
+
+  return storage_type;
+}
 
 static unsigned int WriteJXLImage(const ImageInfo *image_info,Image *image)
 {
@@ -1133,10 +1234,13 @@
   else if (image->depth <= 16)
     pixel_format.data_type = JXL_TYPE_UINT16;
   else if (image->depth <= 32)
-    pixel_format.data_type = JXL_TYPE_UINT16; /* or JXL_TYPE_FLOAT */
+    pixel_format.data_type = JXL_TYPE_FLOAT; /* or JXL_TYPE_FLOAT JXL_TYPE_UINT16 */
   else
     ThrowJXLWriterException(CoderError,ColorspaceModelIsNotSupported,image);
 
+  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                        "Using JXL '%s' data type", JxlDataTypeAsString(pixel_format.data_type));
+
   /* Initialize JxlBasicInfo struct to default values. */
   JxlEncoderInitBasicInfo(&basic_info);
   /* Width of the image in pixels, before applying orientation. */
@@ -1272,9 +1376,7 @@
 
   status=DispatchImage(image,0,0,image->columns,image->rows,
                        characteristics.grayscale ? "I" : (image->matte ? "RGBA" : "RGB"),
-                       basic_info.bits_per_sample == 8 ? CharPixel :
-                       (basic_info.bits_per_sample == 16 ? ShortPixel :
-                        basic_info.bits_per_sample == LongPixel),
+                       JxlDataTypeToDispatchStorageType(pixel_format.data_type),
                        in_buf,&image->exception);
   if (status == MagickFail)
     ThrowJXLWriterException(ResourceLimitError,MemoryAllocationFailed,image);
diff -r 6e880ceeaece -r ad870e7ecd12 magick/image.c
--- a/magick/image.c	Sun Dec 18 09:11:27 2022 -0600
+++ b/magick/image.c	Sun Dec 18 15:53:02 2022 -0600
@@ -2700,6 +2700,10 @@
   MagickPassFail
     status=MagickPass;
 
+  MagickBool
+    is_monochrome = image->is_monochrome,
+    is_grayscale = image->is_grayscale;
+
   assert(image != (Image *) NULL);
 
   status=QuantumOperatorImage(image,AllChannels,DepthQuantumOp,(double) depth,
@@ -2708,6 +2712,8 @@
     status=QuantumOperatorImage(image,OpacityChannel,DepthQuantumOp,(double) depth,
                                 &image->exception);
   image->depth=Min(depth,QuantumDepth);
+  image->is_monochrome = is_monochrome;
+  image->is_grayscale = is_grayscale;
   return status;
 }
 
diff -r 6e880ceeaece -r ad870e7ecd12 www/Changelog.html
--- a/www/Changelog.html	Sun Dec 18 09:11:27 2022 -0600
+++ b/www/Changelog.html	Sun Dec 18 15:53:02 2022 -0600
@@ -40,6 +40,12 @@
 <p>2022-12-18  Bob Friesenhahn  &lt;<a class="reference external" href="mailto:bfriesen&#37;&#52;&#48;simple&#46;dallas&#46;tx&#46;us">bfriesen<span>&#64;</span>simple<span>&#46;</span>dallas<span>&#46;</span>tx<span>&#46;</span>us</a>&gt;</p>
 <blockquote>
 <ul class="simple">
+<li><p>NEWS.txt: Updated the news.</p></li>
+<li><p>magick/image.c (SetImageDepth): Restore is_monochrome and
+is_grayscale image flags.  Changing depth should not change the
+nature of 'gray'.</p></li>
+<li><p>coders/jxl.c: Support reading and writing 32-bit 'float'
+images. Need a Q32 build in order to write 32-bit 'float' images.</p></li>
 <li><p>fuzzing/oss-fuzz-build.sh: Remove xz --with-pic=yes option which
 now seems to annoy oss-fuzz build.</p></li>
 </ul>
diff -r 6e880ceeaece -r ad870e7ecd12 www/NEWS.html
--- a/www/NEWS.html	Sun Dec 18 09:11:27 2022 -0600
+++ b/www/NEWS.html	Sun Dec 18 15:53:02 2022 -0600
@@ -189,6 +189,9 @@
 distribution size.</p></li>
 <li><p>Blob: The ReadBlobString() function has been re-written to perform
 better when reading from files.</p></li>
+<li><p>JXL: The JXL coder is updated to compile with what will likely
+become JXL 0.8.0.  Support for 16-bit 'short' samples and 32-bit
+float samples added.</p></li>
 <li><p>MIME: GM &quot;magick&quot; to MIME mappings have been added for apng, avif,
 bmp, ico, and webp (regardless of if they are supported).</p></li>
 <li><p>XPM: The XPM reader performance is dramatically improved and is
@@ -200,7 +203,7 @@
 <p>Windows Delegate Updates/Additions:</p>
 <ul class="simple">
 <li><p>Update bundled libjpeg to version 9e.</p></li>
-<li><p>Update bundled libtiff to version 4.4.0 (but still compilable using MSVC2008!).</p></li>
+<li><p>Update bundled libtiff to version 4.5.0 (but still compilable using MSVC2008!).</p></li>
 </ul>
 <p>Build Changes:</p>
 <ul class="simple">
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.