Commit 7cd3669b for libheif
commit 7cd3669b8267034e990f7edbc5694975f0f5a779
Author: Dirk Farin <dirk.farin@gmail.com>
Date: Sat Sep 19 15:43:49 2026 +0200
Return the 'pclr' entry count as uint16_t
NE is a 16-bit field (1 to 1024 per ISO/IEC 15444-1 Table I.12), but
get_num_entries() returned uint8_t, so the writer emitted a truncated
count for palettes with more than 255 entries. Also drop the pointless
const on the by-value return types.
Add a 300-entry write and parse round trip.
diff --git a/libheif/codecs/jpeg2000_boxes.h b/libheif/codecs/jpeg2000_boxes.h
index 5d1e61c5..fd165ae9 100644
--- a/libheif/codecs/jpeg2000_boxes.h
+++ b/libheif/codecs/jpeg2000_boxes.h
@@ -222,14 +222,15 @@ public:
return m_bitDepths;
}
- const uint8_t get_num_entries() const
+ // NE is a 16-bit field (1 to 1024 per ISO/IEC 15444-1 Table I.12).
+ uint16_t get_num_entries() const
{
- return (uint8_t)(m_entries.size());
+ return static_cast<uint16_t>(m_entries.size());
}
- const uint8_t get_num_columns() const
+ uint8_t get_num_columns() const
{
- return (uint8_t)(m_bitDepths.size());
+ return static_cast<uint8_t>(m_bitDepths.size());
}
void add_entry(const PaletteEntry& entry)
diff --git a/tests/jpeg2000.cc b/tests/jpeg2000.cc
index ead451e6..143675f5 100644
--- a/tests/jpeg2000.cc
+++ b/tests/jpeg2000.cc
@@ -863,6 +863,36 @@ TEST_CASE("pclr write and parse round trip")
}
+TEST_CASE("pclr more than 255 entries round trip")
+{
+ // NE is a 16-bit field; get_num_entries() used to return uint8_t, so the
+ // writer emitted a truncated count for palettes above 255 entries.
+ auto pclr = std::make_shared<Box_pclr>();
+ pclr->set_columns(1, 8);
+ for (int i = 0; i < 300; i++) {
+ Box_pclr::PaletteEntry entry;
+ entry.columns = {static_cast<uint16_t>(i & 0xff)};
+ pclr->add_entry(entry);
+ }
+ REQUIRE(pclr->get_num_entries() == 300);
+
+ StreamWriter writer;
+ REQUIRE(pclr->write(writer) == Error::Ok);
+ const std::vector<uint8_t> bytes = writer.get_data();
+ REQUIRE(bytes.size() == 8 + 2 + 1 + 1 + 300);
+ REQUIRE(bytes[8] == 0x01); // NE = 0x012c
+ REQUIRE(bytes[9] == 0x2c);
+
+ std::shared_ptr<Box> box;
+ Error err = parse_box(bytes, heif_get_global_security_limits(), &box);
+ REQUIRE(err == Error::Ok);
+ auto parsed = std::dynamic_pointer_cast<Box_pclr>(box);
+ REQUIRE(parsed);
+ REQUIRE(parsed->get_num_entries() == 300);
+ REQUIRE(parsed->get_entries()[299].columns == std::vector<uint16_t>{299 & 0xff});
+}
+
+
TEST_CASE("pclr zero columns rejected")
{
// NE=65535, NPC=0: the 11-byte box from the advisory.