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;