Commit 9f7c289d for libheif

commit 9f7c289d09da044c7ec040d4efe238f3df57fdeb
Author: Dirk Farin <dirk.farin@gmail.com>
Date:   Thu May 28 17:09:02 2026 +0200

    implement parsing/writing of 'iscl' box

diff --git a/libheif/box.cc b/libheif/box.cc
index a3350333..649704c6 100644
--- a/libheif/box.cc
+++ b/libheif/box.cc
@@ -530,6 +530,10 @@ Error Box::read(BitstreamRange& range, std::shared_ptr<Box>* result, const heif_
       box = std::make_shared<Box_clap>();
       break;

+    case fourcc("iscl"):
+      box = std::make_shared<Box_iscl>();
+      break;
+
     case fourcc("iref"):
       box = std::make_shared<Box_iref>();
       break;
@@ -3572,6 +3576,57 @@ std::string Box_imir::dump(Indent& indent) const
 }


+Error Box_iscl::parse(BitstreamRange& range, const heif_security_limits* limits)
+{
+  parse_full_box_header(range);
+
+  if (get_version() != 0) {
+    return unsupported_version_error("iscl");
+  }
+
+  m_target_width_numerator = range.read16();
+  m_target_width_denominator = range.read16();
+  m_target_height_numerator = range.read16();
+  m_target_height_denominator = range.read16();
+
+  if (m_target_width_numerator == 0 || m_target_width_denominator == 0 ||
+      m_target_height_numerator == 0 || m_target_height_denominator == 0) {
+    return {heif_error_Invalid_input,
+            heif_suberror_Invalid_fractional_number,
+            "iscl property has zero numerator or denominator"};
+  }
+
+  return range.get_error();
+}
+
+
+Error Box_iscl::write(StreamWriter& writer) const
+{
+  size_t box_start = reserve_box_header_space(writer);
+
+  writer.write16(m_target_width_numerator);
+  writer.write16(m_target_width_denominator);
+  writer.write16(m_target_height_numerator);
+  writer.write16(m_target_height_denominator);
+
+  prepend_header(writer, box_start);
+
+  return Error::Ok;
+}
+
+
+std::string Box_iscl::dump(Indent& indent) const
+{
+  std::ostringstream sstr;
+  sstr << FullBox::dump(indent);
+
+  sstr << indent << "horizontal scaling factor: " << m_target_width_numerator << " / " << m_target_width_denominator << "\n";
+  sstr << indent << "vertical scaling factor:   " << m_target_height_numerator << " / " << m_target_height_denominator << "\n";
+
+  return sstr.str();
+}
+
+
 Error Box_clap::parse(BitstreamRange& range, const heif_security_limits* limits)
 {
   //parse_full_box_header(range);
diff --git a/libheif/box.h b/libheif/box.h
index 1cbdbf6e..5f77ce3d 100644
--- a/libheif/box.h
+++ b/libheif/box.h
@@ -950,6 +950,50 @@ private:
 };


+class Box_iscl : public FullBox
+{
+public:
+  Box_iscl()
+  {
+    set_short_type(fourcc("iscl"));
+  }
+
+  bool is_essential() const override { return true; }
+
+  bool is_transformative_property() const override { return true; }
+
+  uint16_t get_target_width_numerator() const { return m_target_width_numerator; }
+  uint16_t get_target_width_denominator() const { return m_target_width_denominator; }
+  uint16_t get_target_height_numerator() const { return m_target_height_numerator; }
+  uint16_t get_target_height_denominator() const { return m_target_height_denominator; }
+
+  void set_scale(uint16_t w_num, uint16_t w_den, uint16_t h_num, uint16_t h_den)
+  {
+    m_target_width_numerator = w_num;
+    m_target_width_denominator = w_den;
+    m_target_height_numerator = h_num;
+    m_target_height_denominator = h_den;
+  }
+
+  std::string dump(Indent&) const override;
+
+  const char* debug_box_name() const override { return "Image Scaling"; }
+
+  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::ignorable; }
+
+protected:
+  Error parse(BitstreamRange& range, const heif_security_limits*) override;
+
+  Error write(StreamWriter& writer) const override;
+
+private:
+  uint16_t m_target_width_numerator = 1;
+  uint16_t m_target_width_denominator = 1;
+  uint16_t m_target_height_numerator = 1;
+  uint16_t m_target_height_denominator = 1;
+};
+
+
 class Box_clap : public Box
 {
 public:
diff --git a/libheif/image-items/image_item.cc b/libheif/image-items/image_item.cc
index c0e50185..ef813535 100644
--- a/libheif/image-items/image_item.cc
+++ b/libheif/image-items/image_item.cc
@@ -1009,6 +1009,13 @@ Result<std::shared_ptr<HeifPixelImage>> ImageItem::decode_image(const heif_decod
           img = *cropResult;
         }
       }
+
+
+      if (auto iscl = std::dynamic_pointer_cast<Box_iscl>(property)) {
+        return Error(heif_error_Unsupported_feature,
+                     heif_suberror_Unspecified,
+                     "Image scaling (iscl) transformative property is not yet supported");
+      }
     }
   }

@@ -1471,6 +1478,14 @@ Error ImageItem::process_image_transformations_on_tiling(heif_image_tiling& tili
       top_excess += top;
       bottom_excess += bottom;
     }
+
+    // --- scaling (not supported yet)
+
+    if (auto iscl = std::dynamic_pointer_cast<Box_iscl>(property)) {
+      return {heif_error_Unsupported_feature,
+              heif_suberror_Unspecified,
+              "Image scaling (iscl) transformative property is not yet supported"};
+    }
   }

   tiling.left_offset = left_excess;