Commit af96d1487 for imagemagick.org

commit af96d14875a68f76c4057c03e879ad6d2d1d9ff4
Author: Greg B <64932474+gregbenz@users.noreply.github.com>
Date:   Sun Sep 6 09:33:18 2026 -0500

    fix: preserve UHDR resize filters (#8942)

diff --git a/MagickCore/resize.c b/MagickCore/resize.c
index e1d1149d3..b3825f63a 100644
--- a/MagickCore/resize.c
+++ b/MagickCore/resize.c
@@ -3825,7 +3825,7 @@ MagickExport Image *ResizeImage(const Image *image,const size_t columns,
   if (resize_image != (Image *) NULL)
     {
       resize_filter=DestroyResizeFilter(resize_filter);
-      return(resize_image);
+      goto record_resize_transform;
     }
 #endif
   resize_image=CloneImage(image,columns,rows,MagickTrue,exception);
@@ -3874,14 +3874,17 @@ MagickExport Image *ResizeImage(const Image *image,const size_t columns,
       return((Image *) NULL);
     }
   resize_image->type=image->type;
+#if defined(MAGICKCORE_OPENCL_SUPPORT)
+record_resize_transform:
+#endif
   {
     char
       transform[MagickPathExtent];

     (void) FormatLocaleString(transform,MagickPathExtent,
-      "resize %.17gx%.17g %.17gx%.17g",(double) image->columns,
+      "resize %.17gx%.17g %.17gx%.17g %d",(double) image->columns,
       (double) image->rows,(double) resize_image->columns,
-      (double) resize_image->rows);
+      (double) resize_image->rows,(int) filter_type);
     AppendImageProfileProperty(resize_image,"hdrgm","hdrgm:Transform",
       transform,exception);
   }
diff --git a/Makefile.in b/Makefile.in
index ddfde75e2..04fb2f3ad 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -6277,6 +6277,7 @@ TESTS_TESTS = \
   tests/cli-svg.tap \
   tests/cli-uhdr.tap \
   tests/cli-uhdr-encoder.tap \
+  tests/cli-uhdr-resize-filter.tap \
   tests/validate-colorspace.tap \
   tests/validate-compare.tap \
   tests/validate-composite.tap \
diff --git a/coders/uhdr.c b/coders/uhdr.c
index ad7e71aa2..552050d65 100644
--- a/coders/uhdr.c
+++ b/coders/uhdr.c
@@ -794,7 +794,7 @@ static MagickBooleanType CropGainMapImage(Image **gainmap_image,

 static MagickBooleanType ResizeGainMapImage(Image **gainmap_image,
   size_t *base_columns,size_t *base_rows,const size_t columns,
-  const size_t rows,const Image *image,ExceptionInfo *exception)
+  const size_t rows,const FilterType filter_type,ExceptionInfo *exception)
 {
   Image
     *resize_image;
@@ -812,7 +812,7 @@ static MagickBooleanType ResizeGainMapImage(Image **gainmap_image,
       (target_rows != (*gainmap_image)->rows))
     {
       resize_image=ResizeImage(*gainmap_image,target_columns,target_rows,
-        image->filter,exception);
+        filter_type,exception);
       if (ReplaceGainMapImage(gainmap_image,resize_image) == MagickFalse)
         return(MagickFalse);
     }
@@ -839,6 +839,13 @@ static MagickBooleanType ApplyGainMapTransform(Image **gainmap_image,
   size_t
     rotations;

+  FilterType
+    filter_type;
+
+  int
+    fields,
+    filter_value;
+
   if (LocaleNCompare(transform,"crop ",5) == 0)
     {
       if (sscanf(transform+5,"%lfx%lf %lfx%lf%lf%lf",&source_columns,
@@ -856,14 +863,26 @@ static MagickBooleanType ApplyGainMapTransform(Image **gainmap_image,
     }
   if (LocaleNCompare(transform,"resize ",7) == 0)
     {
-      if (sscanf(transform+7,"%lfx%lf %lfx%lf",&source_columns,
-          &source_rows,&columns,&rows) != 4)
+      fields=sscanf(transform+7,"%lfx%lf %lfx%lf %d",&source_columns,
+        &source_rows,&columns,&rows,&filter_value);
+      if ((fields != 4) && (fields != 5))
         return(MagickFalse);
+      filter_type=UndefinedFilter;
+      if (fields == 5)
+        {
+          if ((filter_value <= (int) UndefinedFilter) ||
+              (filter_value >= (int) SentinelFilter))
+            return(MagickFalse);
+          filter_type=(FilterType) filter_value;
+        }
+      else
+        filter_type=image->filter;
       if (IsGainMapBaseGeometry(*base_columns,*base_rows,source_columns,
           source_rows) == MagickFalse)
         return(MagickFalse);
       return(ResizeGainMapImage(gainmap_image,base_columns,base_rows,
-        CastDoubleToSizeT(columns),CastDoubleToSizeT(rows),image,exception));
+        CastDoubleToSizeT(columns),CastDoubleToSizeT(rows),filter_type,
+        exception));
     }
   if (LocaleNCompare(transform,"flip ",5) == 0)
     {
diff --git a/tests/Makefile.am b/tests/Makefile.am
index bf1ee4131..c1c61e32d 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -46,6 +46,7 @@ TESTS_TESTS = \
   tests/cli-svg.tap \
   tests/cli-uhdr.tap \
   tests/cli-uhdr-encoder.tap \
+  tests/cli-uhdr-resize-filter.tap \
   tests/validate-colorspace.tap \
   tests/validate-compare.tap \
   tests/validate-composite.tap \
diff --git a/tests/cli-uhdr-resize-filter.tap b/tests/cli-uhdr-resize-filter.tap
new file mode 100755
index 000000000..e1ca0a3fb
--- /dev/null
+++ b/tests/cli-uhdr-resize-filter.tap
@@ -0,0 +1,126 @@
+#!/bin/sh
+# Regression tests for Ultra HDR gain-map resize filter replay.
+. ./common.shi
+. ${srcdir}/tests/common.shi
+
+resize_sdr=cli-uhdr-resize-filter-sdr.miff
+resize_hdr=cli-uhdr-resize-filter-hdr.miff
+resize_source=cli-uhdr-resize-filter-source.jpg
+resize_point=cli-uhdr-resize-filter-point.jpg
+resize_lanczos=cli-uhdr-resize-filter-lanczos.jpg
+resize_point_linear=cli-uhdr-resize-filter-point-linear.miff
+resize_lanczos_linear=cli-uhdr-resize-filter-lanczos-linear.miff
+legacy_output=cli-uhdr-resize-filter-legacy.jpg
+modern_output=cli-uhdr-resize-filter-modern.jpg
+legacy_linear=cli-uhdr-resize-filter-legacy-linear.miff
+modern_linear=cli-uhdr-resize-filter-modern-linear.miff
+default_point=cli-uhdr-resize-filter-default-point.jpg
+default_lanczos=cli-uhdr-resize-filter-default-lanczos.jpg
+default_point_linear=cli-uhdr-resize-filter-default-point-linear.miff
+default_lanczos_linear=cli-uhdr-resize-filter-default-lanczos-linear.miff
+
+cleanup()
+{
+  rm -f "$resize_sdr" "$resize_hdr" "$resize_source" "$resize_point" \
+    "$resize_lanczos" "$resize_point_linear" "$resize_lanczos_linear" \
+    "$legacy_output" "$modern_output" "$legacy_linear" "$modern_linear" \
+    "$default_point" "$default_lanczos" "$default_point_linear" \
+    "$default_lanczos_linear"
+}
+
+check_metric()
+{
+  description=$1
+  first=$2
+  second=$3
+  actual=`${MAGICK} compare -metric AE "$first" "$second" null: 2>&1`
+  status=$?
+  metric=`echo "$actual" | awk '{print $1}'`
+  if [ "$status" = "0" ] && [ "X$metric" = "X0" ]; then
+    echo "ok - $description"
+  else
+    echo "not ok - $description"
+    echo "# expected zero absolute error, got '$actual'"
+  fi
+}
+
+cleanup
+if ! ${MAGICK} -list configure 2>/dev/null | awk '
+    $1 == "DELEGATES" {
+      for (i=2; i <= NF; i++)
+        {
+          if ($i == "jpeg")
+            jpeg=1
+          if ($i == "uhdr")
+            uhdr=1
+        }
+    }
+    END { exit(jpeg && uhdr ? 0 : 1) }
+  '; then
+  echo "1..0 # SKIP JPEG or UHDR coder unavailable"
+  exit 0
+fi
+
+echo "1..3"
+if ! ${MAGICK} "${SRCDIR}/rose.pnm" -depth 8 "$resize_sdr" \
+    >/dev/null 2>&1 ||
+   ! ${MAGICK} "${SRCDIR}/rose.pnm" -depth 16 -evaluate multiply 1.4 \
+    "$resize_hdr" >/dev/null 2>&1 ||
+   ! ${MAGICK} "$resize_sdr" "$resize_hdr" \
+    -define uhdr:hdr-color-transfer=linear "UHDR:$resize_source" \
+    >/dev/null 2>&1; then
+  echo "Bail out! unable to create spatial gain-map fixture"
+  cleanup
+  exit 0
+fi
+
+if ${MAGICK} "UHDR:$resize_source" \
+    -filter point -resize 35x23 -filter box -resize 18x12 -filter point \
+    "UHDR:$resize_point" >/dev/null 2>&1 &&
+   ${MAGICK} "UHDR:$resize_source" \
+    -filter point -resize 35x23 -filter box -resize 18x12 -filter lanczos \
+    "UHDR:$resize_lanczos" >/dev/null 2>&1 &&
+   ${MAGICK} -define uhdr:output-color-transfer=linear \
+    "UHDR:$resize_point" "$resize_point_linear" >/dev/null 2>&1 &&
+   ${MAGICK} -define uhdr:output-color-transfer=linear \
+    "UHDR:$resize_lanczos" "$resize_lanczos_linear" >/dev/null 2>&1; then
+  check_metric "historical resize filters are independent of final filter" \
+    "$resize_point_linear" "$resize_lanczos_linear"
+else
+  echo "not ok - historical resize filters are independent of final filter"
+  echo "# unable to create or decode resize outputs"
+fi
+
+if ${MAGICK} "UHDR:$resize_source" -filter point -resize 35x23 \
+    -set hdrgm:Transform 'resize 70x46 35x23' -filter point \
+    "UHDR:$legacy_output" >/dev/null 2>&1 &&
+   ${MAGICK} "UHDR:$resize_source" -filter point -resize 35x23 \
+    -filter point "UHDR:$modern_output" >/dev/null 2>&1 &&
+   ${MAGICK} -define uhdr:output-color-transfer=linear \
+    "UHDR:$legacy_output" "$legacy_linear" >/dev/null 2>&1 &&
+   ${MAGICK} -define uhdr:output-color-transfer=linear \
+    "UHDR:$modern_output" "$modern_linear" >/dev/null 2>&1; then
+  check_metric "legacy four-field resize records remain compatible" \
+    "$legacy_linear" "$modern_linear"
+else
+  echo "not ok - legacy four-field resize records remain compatible"
+  echo "# unable to create or decode legacy outputs"
+fi
+
+if ${MAGICK} "UHDR:$resize_source" -resize 35x23 -filter point \
+    "UHDR:$default_point" >/dev/null 2>&1 &&
+   ${MAGICK} "UHDR:$resize_source" -resize 35x23 -filter lanczos \
+    "UHDR:$default_lanczos" >/dev/null 2>&1 &&
+   ${MAGICK} -define uhdr:output-color-transfer=linear \
+    "UHDR:$default_point" "$default_point_linear" >/dev/null 2>&1 &&
+   ${MAGICK} -define uhdr:output-color-transfer=linear \
+    "UHDR:$default_lanczos" "$default_lanczos_linear" >/dev/null 2>&1; then
+  check_metric "resolved default resize filter is recorded" \
+    "$default_point_linear" "$default_lanczos_linear"
+else
+  echo "not ok - resolved default resize filter is recorded"
+  echo "# unable to create or decode default-filter outputs"
+fi
+
+cleanup
+: