Commit 4793527c8 for imagemagick.org

commit 4793527c8d7a2971a94c931c862f251ba68444bb
Author: Nol Moonen <nolmoonen@hotmail.nl>
Date:   Tue Sep 29 20:55:20 2026 +0200

    Preserve Ultra HDR JPEG gain maps for scale operator (#8986)

    * eliminate dead code

    if the else case is hit, transform is not resize and applying the transform will always fail

    * add scale support for uhdr

diff --git a/MagickCore/resize.c b/MagickCore/resize.c
index b3825f63a..c8be33d21 100644
--- a/MagickCore/resize.c
+++ b/MagickCore/resize.c
@@ -4538,6 +4538,17 @@ MagickExport Image *ScaleImage(const Image *image,const size_t columns,
     scanline=(double *) RelinquishMagickMemory(scanline);
   x_vector=(double *) RelinquishMagickMemory(x_vector);
   scale_image->type=image->type;
+  {
+    char
+      transform[MagickPathExtent];
+
+    (void) FormatLocaleString(transform,MagickPathExtent,
+      "scale %.17gx%.17g %.17gx%.17g",(double) image->columns,
+      (double) image->rows,(double) scale_image->columns,
+      (double) scale_image->rows);
+    AppendImageProfileProperty(scale_image,"hdrgm","hdrgm:Transform",
+      transform,exception);
+  }
   if (status == MagickFalse)
     scale_image=DestroyImage(scale_image);
   return(scale_image);
diff --git a/coders/uhdr.c b/coders/uhdr.c
index bf63037a3..9820d0682 100644
--- a/coders/uhdr.c
+++ b/coders/uhdr.c
@@ -1065,6 +1065,35 @@ static MagickBooleanType ResizeGainMapImage(Image **gainmap_image,
   return(MagickTrue);
 }

+static MagickBooleanType ScaleGainMapImage(Image **gainmap_image,
+  size_t *base_columns,size_t *base_rows,const size_t columns,
+  const size_t rows,ExceptionInfo *exception)
+{
+  Image
+    *scale_image;
+
+  size_t
+    target_columns,
+    target_rows;
+
+  target_columns=ScaleGainMapExtent((*gainmap_image)->columns,columns,
+    *base_columns);
+  target_rows=ScaleGainMapExtent((*gainmap_image)->rows,rows,*base_rows);
+  if ((target_columns == 0) || (target_rows == 0))
+    return(MagickFalse);
+  if ((target_columns != (*gainmap_image)->columns) ||
+      (target_rows != (*gainmap_image)->rows))
+    {
+      scale_image=ScaleImage(*gainmap_image,target_columns,target_rows,
+        exception);
+      if (ReplaceGainMapImage(gainmap_image,scale_image) == MagickFalse)
+        return(MagickFalse);
+    }
+  *base_columns=columns;
+  *base_rows=rows;
+  return(MagickTrue);
+}
+
 static MagickBooleanType ApplyGainMapTransform(Image **gainmap_image,
   size_t *base_columns,size_t *base_rows,const Image *image,
   const char *transform,ExceptionInfo *exception)
@@ -1114,6 +1143,27 @@ static MagickBooleanType ApplyGainMapTransform(Image **gainmap_image,
         CastDoubleToSizeT(columns),CastDoubleToSizeT(rows),filter_type,
         exception));
     }
+  else if (LocaleNCompare(transform,"scale ",6) == 0)
+    {
+      fields=sscanf(transform+6,"%lfx%lf %lfx%lf",&source_columns,
+        &source_rows,&columns,&rows);
+      if (fields != 4)
+        return(MagickFalse);
+      if ((IsNaN(source_columns) != 0) || (IsNaN(source_rows) != 0) ||
+          (IsNaN(columns) != 0) || (IsNaN(rows) != 0) ||
+          (source_columns > (double) MAGICK_SSIZE_MAX) ||
+          (source_rows > (double) MAGICK_SSIZE_MAX) ||
+          (columns <= 0.0) || (rows <= 0.0) ||
+          (columns > (double) MAGICK_SSIZE_MAX) ||
+          (rows > (double) MAGICK_SSIZE_MAX) ||
+          (columns != floor(columns)) || (rows != floor(rows)))
+        return(MagickFalse);
+      if (IsGainMapBaseGeometry(*base_columns,*base_rows,source_columns,
+          source_rows) == MagickFalse)
+        return(MagickFalse);
+      return(ScaleGainMapImage(gainmap_image,base_columns,base_rows,
+        CastDoubleToSizeT(columns),CastDoubleToSizeT(rows),exception));
+    }
   return(MagickFalse);
 }

@@ -1424,7 +1474,8 @@ static StringInfo *TransformGainMapProfile(const ImageInfo *image_info,
                       }
                   }
               }
-            else if (LocaleNCompare(transform,"resize ",7) == 0)
+            else if ((LocaleNCompare(transform,"resize ",7) == 0) ||
+                (LocaleNCompare(transform,"scale ", 6) == 0))
               {
                 if (transform_pending != MagickFalse)
                   {
@@ -1465,17 +1516,7 @@ static StringInfo *TransformGainMapProfile(const ImageInfo *image_info,
               }
             else
               {
-                if (transform_pending != MagickFalse)
-                  {
-                    status=FlushGainMapTransform(&gainmap_images,
-                      &transform_state,exception);
-                    transform_pending=MagickFalse;
-                  }
-                if (status != MagickFalse)
-                  status=ApplyGainMapTransform(&gainmap_images,&base_columns,
-                    &base_rows,image,transform,exception);
-                if (status != MagickFalse)
-                  transformed=MagickTrue;
+                status=MagickFalse;
               }
             if (status == MagickFalse)
               break;
diff --git a/tests/cli-uhdr.tap b/tests/cli-uhdr.tap
index 83c8edb2b..373f25f12 100755
--- a/tests/cli-uhdr.tap
+++ b/tests/cli-uhdr.tap
@@ -23,6 +23,7 @@ raw_source=cli-uhdr-offset-raw.jpg
 source=cli-uhdr-offset-source.jpg
 output=cli-uhdr-offset-output.jpg
 transformed_output=cli-uhdr-offset-transformed.jpg
+scaled_output=cli-uhdr-offset-scaled.jpg
 locale_output=cli-uhdr-offset-locale.jpg
 jpeg_probe=cli-uhdr-jpeg-probe.jpg
 whitespace_output=cli-uhdr-offset-whitespace.jpg
@@ -61,7 +62,7 @@ comments-local-second-line'

 cleanup()
 {
-  rm -f "$raw_source" "$source" "$output" "$transformed_output" \
+  rm -f "$raw_source" "$source" "$output" "$transformed_output" "$scaled_output" \
     "$locale_output" "$jpeg_probe" "$whitespace_output" "$invalid_output" \
     "$iptc_source" "$iptc_output"
   rm -f "$commented_source" "$comment_roundtrip" \
@@ -113,7 +114,7 @@ if [ "X$jpeg_format" != "XJPEG" ]; then
   exit 0
 fi

-echo "1..20"
+echo "1..21"
 if ! ${MAGICK} \( "${SRCDIR}/rose.pnm" -depth 8 \) \
     \( "${SRCDIR}/rose.pnm" -depth 16 \) \
     -define uhdr:hdr-color-transfer=linear "UHDR:$raw_source" \
@@ -254,6 +255,17 @@ check_value "offset values survive a geometry transform" \
 check_value "capacity values survive a geometry transform" \
   "$transformed_capacity" "$capacity_min $capacity_max"

+if ${MAGICK} "UHDR:$source" -scale 50% \
+    "UHDR:$scaled_output" >/dev/null 2>&1; then
+  scaled_offsets=`${IDENTIFY} -quiet -format \
+    '%[hdrgm:OffsetSDR] %[hdrgm:OffsetHDR]' \
+    "UHDR:$scaled_output" 2>/dev/null`
+else
+  scaled_offsets=
+fi
+check_value "offset values survive a scale transform" \
+  "$scaled_offsets" "$source_offsets"
+
 if ${MAGICK} "UHDR:$source" -quality 85 \
     -define uhdr:gainmap-quality=35 -resize 50% \
     "UHDR:$quality35_output" >/dev/null 2>&1 &&