Commit 42aac9763 for imagemagick.org

commit 42aac97639ab91c296bf3770b387f046b33729a2
Author: Dirk Lemstra <dirk@lemstra.org>
Date:   Sun Nov 15 18:59:41 2026 +0100

    Add 24-bit floating-point quantum channel export.

diff --git a/MagickCore/quantum-export.c b/MagickCore/quantum-export.c
index d65aa6714..5f0d042e6 100644
--- a/MagickCore/quantum-export.c
+++ b/MagickCore/quantum-export.c
@@ -172,6 +172,84 @@ static inline unsigned char *PopQuantumFloatPixel(QuantumInfo *quantum_info,
   return(pixels);
 }

+static inline unsigned char *PopQuantumFloat24Pixel(QuantumInfo *quantum_info,
+  const float pixel,unsigned char *magick_restrict pixels)
+{
+  union
+  {
+    unsigned int
+      fixed_point;
+
+    float
+      single_precision;
+  } map;
+
+  double
+    scaled_pixel;
+
+  unsigned int
+    exponent,
+    significand,
+    sign_bit,
+    value;
+
+  scaled_pixel=(double) pixel*quantum_info->state.inverse_scale;
+  if (quantum_info->minimum != 0.0)
+    scaled_pixel+=quantum_info->minimum;
+  map.single_precision=(float) scaled_pixel;
+  sign_bit=(map.fixed_point >> 8) & 0x00800000U;
+  exponent=(map.fixed_point >> 23) & 0xffU;
+  significand=map.fixed_point & 0x007fffffU;
+  /*
+    One sign bit, seven exponent bits (bias 63), and sixteen fraction bits.
+  */
+  if (exponent == 255U)
+    {
+      value=0x007f0000U | (significand >> 7);
+      if ((significand != 0U) && ((value & 0xffffU) == 0U))
+        value|=1U;
+    }
+  else
+    if (exponent <= 64U)
+      {
+        value=0U;
+        if (exponent >= 48U)
+          {
+            unsigned int
+              shift;
+
+            significand|=0x00800000U;
+            shift=72U-exponent;
+            value=(significand+((1U << (shift-1))-1U)+
+              ((significand >> shift) & 1U)) >> shift;
+          }
+      }
+    else
+      {
+        exponent-=64U;
+        significand=(significand+0x3fU+((significand >> 7) & 1U)) >> 7;
+        if (significand == 0x10000U)
+          {
+            significand=0U;
+            exponent++;
+          }
+        value=exponent >= 127U ? 0x007f0000U :
+          (exponent << 16) | significand;
+      }
+  value|=sign_bit;
+  if (quantum_info->endian == LSBEndian)
+    {
+      *pixels++=(unsigned char) value;
+      *pixels++=(unsigned char) (value >> 8);
+      *pixels++=(unsigned char) (value >> 16);
+      return(pixels);
+    }
+  *pixels++=(unsigned char) (value >> 16);
+  *pixels++=(unsigned char) (value >> 8);
+  *pixels++=(unsigned char) value;
+  return(pixels);
+}
+
 static inline unsigned char *PopQuantumPixel(QuantumInfo *quantum_info,
   const QuantumAny pixel,unsigned char *magick_restrict pixels)
 {
@@ -313,6 +391,20 @@ static void ExportPixelChannel(const Image *image,QuantumInfo *quantum_info,
       }
       break;
     }
+    case 24:
+    {
+      if (quantum_info->format == FloatingPointQuantumFormat)
+        {
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            q=PopQuantumFloat24Pixel(quantum_info,(float) *p,q);
+            p+=(ptrdiff_t) GetPixelChannels(image);
+            q+=(ptrdiff_t) quantum_info->pad;
+          }
+          break;
+        }
+      magick_fallthrough;
+    }
     case 64:
     {
       if (quantum_info->format == FloatingPointQuantumFormat)