Commit 0023d8a4 for libheif
commit 0023d8a4af80c8423566a62b4fbec39d19a4aea6
Author: Dirk Farin <dirk.farin@gmail.com>
Date: Sun Feb 8 21:40:27 2026 +0100
unci: fold tile_component_interleave decoder into component_interleave decoder
diff --git a/libheif/CMakeLists.txt b/libheif/CMakeLists.txt
index 93843028..4b02353a 100644
--- a/libheif/CMakeLists.txt
+++ b/libheif/CMakeLists.txt
@@ -305,8 +305,6 @@ if (WITH_UNCOMPRESSED_CODEC)
codecs/uncompressed/unc_decoder_mixed_interleave.cc
codecs/uncompressed/unc_decoder_row_interleave.h
codecs/uncompressed/unc_decoder_row_interleave.cc
- codecs/uncompressed/unc_decoder_tile_component_interleave.h
- codecs/uncompressed/unc_decoder_tile_component_interleave.cc
codecs/uncompressed/unc_encoder.h
codecs/uncompressed/unc_encoder.cc
codecs/uncompressed/unc_encoder_rgb3_rgba.cc
diff --git a/libheif/codecs/uncompressed/unc_codec.cc b/libheif/codecs/uncompressed/unc_codec.cc
index d9947978..89f4734f 100644
--- a/libheif/codecs/uncompressed/unc_codec.cc
+++ b/libheif/codecs/uncompressed/unc_codec.cc
@@ -530,8 +530,15 @@ Error UncompressedImageCodec::decode_uncompressed_image_tile(const HeifContext*
DataExtent dataExtent;
dataExtent.set_from_image_item(file, ID);
- return decoder->decode_tile(dataExtent, properties, img, 0, 0,
- tile_x0, tile_y0);
+ decoder->ensure_channel_list(img);
+
+ std::vector<uint8_t> tile_data;
+ Error err = decoder->fetch_tile_data(dataExtent, properties, tile_x0, tile_y0, tile_data);
+ if (err) {
+ return err;
+ }
+
+ return decoder->decode_tile(tile_data, img, 0, 0, tile_x0, tile_y0);
}
diff --git a/libheif/codecs/uncompressed/unc_decoder.cc b/libheif/codecs/uncompressed/unc_decoder.cc
index be4a81ca..dd461734 100644
--- a/libheif/codecs/uncompressed/unc_decoder.cc
+++ b/libheif/codecs/uncompressed/unc_decoder.cc
@@ -26,9 +26,9 @@
#include "unc_decoder_pixel_interleave.h"
#include "unc_decoder_mixed_interleave.h"
#include "unc_decoder_row_interleave.h"
-#include "unc_decoder_tile_component_interleave.h"
#include "unc_codec.h"
#include "unc_boxes.h"
+#include "compression.h"
#include "codecs/decoder.h"
#include "security_limits.h"
@@ -51,6 +51,175 @@ unc_decoder::unc_decoder(uint32_t width, uint32_t height,
}
+const Error unc_decoder::get_compressed_image_data_uncompressed(const DataExtent& dataExtent,
+ const UncompressedImageCodec::unci_properties& properties,
+ std::vector<uint8_t>* data,
+ uint64_t range_start_offset, uint64_t range_size,
+ uint32_t tile_idx,
+ const Box_iloc::Item* item) const
+{
+ // --- get codec configuration
+
+ std::shared_ptr<const Box_cmpC> cmpC_box = properties.cmpC;
+ std::shared_ptr<const Box_icef> icef_box = properties.icef;
+
+ if (!cmpC_box) {
+ // assume no generic compression
+ auto readResult = dataExtent.read_data(range_start_offset, range_size);
+ if (!readResult) {
+ return readResult.error();
+ }
+
+ data->insert(data->end(), readResult->begin(), readResult->end());
+
+ return Error::Ok;
+ }
+
+ if (icef_box && cmpC_box->get_compressed_unit_type() == heif_cmpC_compressed_unit_type_image_tile) {
+ const auto& units = icef_box->get_units();
+ if (tile_idx >= units.size()) {
+ return {heif_error_Invalid_input,
+ heif_suberror_Unspecified,
+ "no icef-box entry for tile index"};
+ }
+
+ const auto unit = units[tile_idx];
+
+ // get data needed for one tile
+ Result<std::vector<uint8_t>> readingResult = dataExtent.read_data(unit.unit_offset, unit.unit_size);
+ if (!readingResult) {
+ return readingResult.error();
+ }
+
+ const std::vector<uint8_t>& compressed_bytes = *readingResult;
+
+ // decompress only the unit
+ auto dataResult = do_decompress_data(cmpC_box, compressed_bytes);
+ if (!dataResult) {
+ return dataResult.error();
+ }
+
+ *data = std::move(*dataResult);
+ }
+ else if (icef_box) {
+ // get all data and decode all
+ Result<std::vector<uint8_t>*> readResult = dataExtent.read_data();
+ if (!readResult) {
+ return readResult.error();
+ }
+
+ const std::vector<uint8_t> compressed_bytes = std::move(**readResult);
+
+ for (Box_icef::CompressedUnitInfo unit_info : icef_box->get_units()) {
+ if (unit_info.unit_offset + unit_info.unit_size > compressed_bytes.size()) {
+ return Error{
+ heif_error_Invalid_input,
+ heif_suberror_Unspecified,
+ "incomplete data in unci image"
+ };
+ }
+
+ auto unit_start = compressed_bytes.begin() + unit_info.unit_offset;
+ auto unit_end = unit_start + unit_info.unit_size;
+ std::vector<uint8_t> compressed_unit_data = std::vector<uint8_t>(unit_start, unit_end);
+
+ auto dataResult = do_decompress_data(cmpC_box, std::move(compressed_unit_data));
+ if (!dataResult) {
+ return dataResult.error();
+ }
+
+ const std::vector<uint8_t> uncompressed_unit_data = std::move(*dataResult);
+ data->insert(data->end(), uncompressed_unit_data.data(), uncompressed_unit_data.data() + uncompressed_unit_data.size());
+ }
+
+ if (range_start_offset + range_size > data->size()) {
+ return {heif_error_Invalid_input,
+ heif_suberror_Unspecified,
+ "Data range out of existing range"};
+ }
+
+ // cut out the range that we actually need
+ memcpy(data->data(), data->data() + range_start_offset, range_size);
+ data->resize(range_size);
+ }
+ else {
+ // get all data and decode all
+ Result<std::vector<uint8_t>*> readResult = dataExtent.read_data();
+ if (!readResult) {
+ return readResult.error();
+ }
+
+ std::vector<uint8_t> compressed_bytes = std::move(**readResult);
+
+ // Decode as a single blob
+ auto dataResult = do_decompress_data(cmpC_box, compressed_bytes);
+ if (!dataResult) {
+ return dataResult.error();
+ }
+
+ *data = std::move(*dataResult);
+
+ if (range_start_offset + range_size > data->size()) {
+ return {heif_error_Invalid_input,
+ heif_suberror_Unspecified,
+ "Data range out of existing range"};
+ }
+
+ // cut out the range that we actually need
+ memcpy(data->data(), data->data() + range_start_offset, range_size);
+ data->resize(range_size);
+ }
+
+ return Error::Ok;
+}
+
+
+Result<std::vector<uint8_t>> unc_decoder::do_decompress_data(std::shared_ptr<const Box_cmpC>& cmpC_box,
+ std::vector<uint8_t> compressed_data) const
+{
+ if (cmpC_box->get_compression_type() == fourcc("brot")) {
+#if HAVE_BROTLI
+ return decompress_brotli(compressed_data);
+#else
+ std::stringstream sstr;
+ sstr << "cannot decode unci item with brotli compression - not enabled" << std::endl;
+ return Error(heif_error_Unsupported_feature,
+ heif_suberror_Unsupported_generic_compression_method,
+ sstr.str());
+#endif
+ }
+ else if (cmpC_box->get_compression_type() == fourcc("zlib")) {
+#if HAVE_ZLIB
+ return decompress_zlib(compressed_data);
+#else
+ std::stringstream sstr;
+ sstr << "cannot decode unci item with zlib compression - not enabled" << std::endl;
+ return Error(heif_error_Unsupported_feature,
+ heif_suberror_Unsupported_generic_compression_method,
+ sstr.str());
+#endif
+ }
+ else if (cmpC_box->get_compression_type() == fourcc("defl")) {
+#if HAVE_ZLIB
+ return decompress_deflate(compressed_data);
+#else
+ std::stringstream sstr;
+ sstr << "cannot decode unci item with deflate compression - not enabled" << std::endl;
+ return Error(heif_error_Unsupported_feature,
+ heif_suberror_Unsupported_generic_compression_method,
+ sstr.str());
+#endif
+ }
+ else {
+ std::stringstream sstr;
+ sstr << "cannot decode unci item with unsupported compression type: " << cmpC_box->get_compression_type() << std::endl;
+ return Error(heif_error_Unsupported_feature,
+ heif_suberror_Unsupported_generic_compression_method,
+ sstr.str());
+ }
+}
+
+
Error unc_decoder::decode_image(const DataExtent& extent,
const UncompressedImageCodec::unci_properties& properties,
std::shared_ptr<HeifPixelImage>& img)
@@ -58,10 +227,20 @@ Error unc_decoder::decode_image(const DataExtent& extent,
uint32_t tile_width = m_width / m_uncC->get_number_of_tile_columns();
uint32_t tile_height = m_height / m_uncC->get_number_of_tile_rows();
+ ensure_channel_list(img);
+
for (uint32_t tile_y0 = 0; tile_y0 < m_height; tile_y0 += tile_height)
for (uint32_t tile_x0 = 0; tile_x0 < m_width; tile_x0 += tile_width) {
- Error error = decode_tile(extent, properties, img, tile_x0, tile_y0,
- tile_x0 / tile_width, tile_y0 / tile_height);
+ uint32_t tile_x = tile_x0 / tile_width;
+ uint32_t tile_y = tile_y0 / tile_height;
+
+ std::vector<uint8_t> tile_data;
+ Error error = fetch_tile_data(extent, properties, tile_x, tile_y, tile_data);
+ if (error) {
+ return error;
+ }
+
+ error = decode_tile(tile_data, img, tile_x0, tile_y0, tile_x, tile_y);
if (error) {
return error;
}
@@ -82,10 +261,9 @@ Result<std::unique_ptr<unc_decoder>> unc_decoder_factory::get_unc_decoder(
static unc_decoder_factory_pixel_interleave dec_pixel;
static unc_decoder_factory_mixed_interleave dec_mixed;
static unc_decoder_factory_row_interleave dec_row;
- static unc_decoder_factory_tile_component_interleave dec_tile_component;
static const unc_decoder_factory* decoders[]{
- &dec_component, &dec_pixel, &dec_mixed, &dec_row, &dec_tile_component
+ &dec_component, &dec_pixel, &dec_mixed, &dec_row
};
for (const unc_decoder_factory* dec : decoders) {
diff --git a/libheif/codecs/uncompressed/unc_decoder.h b/libheif/codecs/uncompressed/unc_decoder.h
index 226cc1bb..fb47dd34 100644
--- a/libheif/codecs/uncompressed/unc_decoder.h
+++ b/libheif/codecs/uncompressed/unc_decoder.h
@@ -23,6 +23,7 @@
#include <cstdint>
#include <memory>
+#include <vector>
#include "error.h"
#include "unc_codec.h"
@@ -38,8 +39,14 @@ class unc_decoder
public:
virtual ~unc_decoder() = default;
- virtual Error decode_tile(const DataExtent& dataExtent,
- const UncompressedImageCodec::unci_properties& properties,
+ virtual void ensure_channel_list(std::shared_ptr<HeifPixelImage>& img) {}
+
+ virtual Error fetch_tile_data(const DataExtent& dataExtent,
+ const UncompressedImageCodec::unci_properties& properties,
+ uint32_t tile_x, uint32_t tile_y,
+ std::vector<uint8_t>& tile_data) = 0;
+
+ virtual Error decode_tile(const std::vector<uint8_t>& tile_data,
std::shared_ptr<HeifPixelImage>& img,
uint32_t out_x0, uint32_t out_y0,
uint32_t tile_x, uint32_t tile_y) = 0;
@@ -58,6 +65,16 @@ protected:
const std::shared_ptr<const Box_cmpd>& cmpd,
const std::shared_ptr<const Box_uncC>& uncC);
+ const Error get_compressed_image_data_uncompressed(const DataExtent& dataExtent,
+ const UncompressedImageCodec::unci_properties& properties,
+ std::vector<uint8_t>* data,
+ uint64_t range_start_offset, uint64_t range_size,
+ uint32_t tile_idx,
+ const Box_iloc::Item* item) const;
+
+ Result<std::vector<uint8_t>> do_decompress_data(std::shared_ptr<const Box_cmpC>& cmpC_box,
+ std::vector<uint8_t> compressed_data) const;
+
const uint32_t m_width;
const uint32_t m_height;
const std::shared_ptr<const Box_cmpd> m_cmpd;
diff --git a/libheif/codecs/uncompressed/unc_decoder_component_interleave.cc b/libheif/codecs/uncompressed/unc_decoder_component_interleave.cc
index 09e8be67..a86d3b6a 100644
--- a/libheif/codecs/uncompressed/unc_decoder_component_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_decoder_component_interleave.cc
@@ -23,22 +23,24 @@
#include "error.h"
#include <cassert>
+#include <map>
#include <vector>
-Error unc_decoder_component_interleave::decode_tile(const DataExtent& dataExtent,
- const UncompressedImageCodec::unci_properties& properties,
- std::shared_ptr<HeifPixelImage>& img,
- uint32_t out_x0, uint32_t out_y0,
- uint32_t tile_x, uint32_t tile_y)
+Error unc_decoder_component_interleave::fetch_tile_data(const DataExtent& dataExtent,
+ const UncompressedImageCodec::unci_properties& properties,
+ uint32_t tile_x, uint32_t tile_y,
+ std::vector<uint8_t>& tile_data)
{
- ensureChannelList(img);
-
if (m_tile_width == 0) {
return {heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "Internal error: unc_decoder_component_interleave tile_width=0"};
}
- // --- compute which file range we need to read for the tile
+ if (m_uncC->get_interleave_type() == interleave_mode_tile_component) {
+ return fetch_tile_data_tile_component(dataExtent, properties, tile_x, tile_y, tile_data);
+ }
+
+ // --- interleave_mode_component: single contiguous read
uint64_t total_tile_size = 0;
@@ -64,21 +66,88 @@ Error unc_decoder_component_interleave::decode_tile(const DataExtent& dataExtent
uint32_t tileIdx = tile_x + tile_y * (m_width / m_tile_width);
uint64_t tile_start_offset = total_tile_size * tileIdx;
+ return get_compressed_image_data_uncompressed(dataExtent, properties, &tile_data, tile_start_offset, total_tile_size, tileIdx, nullptr);
+}
+
+
+Error unc_decoder_component_interleave::fetch_tile_data_tile_component(const DataExtent& dataExtent,
+ const UncompressedImageCodec::unci_properties& properties,
+ uint32_t tile_x, uint32_t tile_y,
+ std::vector<uint8_t>& tile_data)
+{
+ if (m_tile_height == 0) {
+ return {heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "Internal error: unc_decoder_component_interleave tile_height=0"};
+ }
+
+ // Compute per-channel tile sizes (with per-channel tile alignment)
+ std::map<heif_channel, uint64_t> channel_tile_size;
+
+ for (ChannelListEntry& entry : channelList) {
+ uint32_t bits_per_pixel = entry.bits_per_component_sample;
+ if (entry.component_alignment > 0) {
+ uint32_t bytes_per_component = (bits_per_pixel + 7) / 8;
+ skip_to_alignment(bytes_per_component, entry.component_alignment);
+ bits_per_pixel = bytes_per_component * 8;
+ }
+
+ uint32_t bytes_per_row;
+ if (m_uncC->get_pixel_size() != 0) {
+ uint32_t bytes_per_pixel = (bits_per_pixel + 7) / 8;
+ skip_to_alignment(bytes_per_pixel, m_uncC->get_pixel_size());
+ bytes_per_row = bytes_per_pixel * m_tile_width;
+ }
+ else {
+ bytes_per_row = (bits_per_pixel * m_tile_width + 7) / 8;
+ }
+
+ skip_to_alignment(bytes_per_row, m_uncC->get_row_align_size());
- // --- read required file range
+ uint64_t component_tile_size = bytes_per_row * static_cast<uint64_t>(m_tile_height);
- std::vector<uint8_t> src_data;
- Error err = get_compressed_image_data_uncompressed(dataExtent, properties, &src_data, tile_start_offset, total_tile_size, tileIdx, nullptr);
- if (err) {
- return err;
+ if (m_uncC->get_tile_align_size() != 0) {
+ skip_to_alignment(component_tile_size, m_uncC->get_tile_align_size());
+ }
+
+ channel_tile_size[entry.channel] = component_tile_size;
}
- UncompressedBitReader srcBits(src_data);
+ // Read each channel's tile data and concatenate
+ uint64_t component_start_offset = 0;
+ uint32_t num_tiles = (m_width / m_tile_width) * (m_height / m_tile_height);
+ uint32_t tileIdx = tile_x + tile_y * (m_width / m_tile_width);
+ assert(m_tile_width > 0);
+ assert(m_tile_height > 0);
- // --- decode tile
+ for (ChannelListEntry& entry : channelList) {
+ uint64_t tile_start_offset = component_start_offset + channel_tile_size[entry.channel] * tileIdx;
+
+ std::vector<uint8_t> channel_data;
+ Error err = get_compressed_image_data_uncompressed(dataExtent, properties, &channel_data, tile_start_offset, channel_tile_size[entry.channel], tileIdx, nullptr);
+ if (err) {
+ return err;
+ }
+
+ tile_data.insert(tile_data.end(), channel_data.begin(), channel_data.end());
+
+ component_start_offset += channel_tile_size[entry.channel] * num_tiles;
+ }
+
+ return Error::Ok;
+}
+
+
+Error unc_decoder_component_interleave::decode_tile(const std::vector<uint8_t>& tile_data,
+ std::shared_ptr<HeifPixelImage>& img,
+ uint32_t out_x0, uint32_t out_y0,
+ uint32_t tile_x, uint32_t tile_y)
+{
+ UncompressedBitReader srcBits(tile_data);
+
+ bool per_channel_tile_align = (m_uncC->get_interleave_type() == interleave_mode_tile_component);
for (ChannelListEntry& entry : channelList) {
+ srcBits.markTileStart();
for (uint32_t y = 0; y < entry.tile_height; y++) {
srcBits.markRowStart();
if (entry.use_channel) {
@@ -90,6 +159,9 @@ Error unc_decoder_component_interleave::decode_tile(const DataExtent& dataExtent
}
srcBits.handleRowAlignment(m_uncC->get_row_align_size());
}
+ if (per_channel_tile_align) {
+ srcBits.handleTileAlignment(m_uncC->get_tile_align_size());
+ }
}
return Error::Ok;
@@ -98,7 +170,8 @@ Error unc_decoder_component_interleave::decode_tile(const DataExtent& dataExtent
bool unc_decoder_factory_component_interleave::can_decode(const std::shared_ptr<const Box_uncC>& uncC) const
{
- return uncC->get_interleave_type() == interleave_mode_component;
+ return uncC->get_interleave_type() == interleave_mode_component ||
+ uncC->get_interleave_type() == interleave_mode_tile_component;
}
std::unique_ptr<unc_decoder> unc_decoder_factory_component_interleave::create(
diff --git a/libheif/codecs/uncompressed/unc_decoder_component_interleave.h b/libheif/codecs/uncompressed/unc_decoder_component_interleave.h
index 234064f4..0d54771d 100644
--- a/libheif/codecs/uncompressed/unc_decoder_component_interleave.h
+++ b/libheif/codecs/uncompressed/unc_decoder_component_interleave.h
@@ -34,11 +34,21 @@ public:
std::shared_ptr<const Box_uncC> uncC) :
unc_decoder_legacybase(width, height, std::move(cmpd), std::move(uncC)) {}
- Error decode_tile(const DataExtent& dataExtent,
- const UncompressedImageCodec::unci_properties& properties,
+ Error fetch_tile_data(const DataExtent& dataExtent,
+ const UncompressedImageCodec::unci_properties& properties,
+ uint32_t tile_x, uint32_t tile_y,
+ std::vector<uint8_t>& tile_data) override;
+
+ Error decode_tile(const std::vector<uint8_t>& tile_data,
std::shared_ptr<HeifPixelImage>& img,
uint32_t out_x0, uint32_t out_y0,
uint32_t tile_x, uint32_t tile_y) override;
+
+private:
+ Error fetch_tile_data_tile_component(const DataExtent& dataExtent,
+ const UncompressedImageCodec::unci_properties& properties,
+ uint32_t tile_x, uint32_t tile_y,
+ std::vector<uint8_t>& tile_data);
};
diff --git a/libheif/codecs/uncompressed/unc_decoder_legacybase.cc b/libheif/codecs/uncompressed/unc_decoder_legacybase.cc
index a3d177b9..21aef652 100644
--- a/libheif/codecs/uncompressed/unc_decoder_legacybase.cc
+++ b/libheif/codecs/uncompressed/unc_decoder_legacybase.cc
@@ -166,172 +166,4 @@ unc_decoder_legacybase::ChannelListEntry unc_decoder_legacybase::buildChannelLis
}
-const Error unc_decoder_legacybase::get_compressed_image_data_uncompressed(const DataExtent& dataExtent,
- const UncompressedImageCodec::unci_properties& properties,
- std::vector<uint8_t>* data,
- uint64_t range_start_offset, uint64_t range_size,
- uint32_t tile_idx,
- const Box_iloc::Item* item) const
-{
- // --- get codec configuration
-
- std::shared_ptr<const Box_cmpC> cmpC_box = properties.cmpC;
- std::shared_ptr<const Box_icef> icef_box = properties.icef;
-
- if (!cmpC_box) {
- // assume no generic compression
- auto readResult = dataExtent.read_data(range_start_offset, range_size);
- if (!readResult) {
- return readResult.error();
- }
-
- data->insert(data->end(), readResult->begin(), readResult->end());
-
- return Error::Ok;
- }
-
- if (icef_box && cmpC_box->get_compressed_unit_type() == heif_cmpC_compressed_unit_type_image_tile) {
- const auto& units = icef_box->get_units();
- if (tile_idx >= units.size()) {
- return {heif_error_Invalid_input,
- heif_suberror_Unspecified,
- "no icef-box entry for tile index"};
- }
-
- const auto unit = units[tile_idx];
-
- // get data needed for one tile
- Result<std::vector<uint8_t>> readingResult = dataExtent.read_data(unit.unit_offset, unit.unit_size);
- if (!readingResult) {
- return readingResult.error();
- }
-
- const std::vector<uint8_t>& compressed_bytes = *readingResult;
-
- // decompress only the unit
- auto dataResult = do_decompress_data(cmpC_box, compressed_bytes);
- if (!dataResult) {
- return dataResult.error();
- }
-
- *data = std::move(*dataResult);
- }
- else if (icef_box) {
- // get all data and decode all
- Result<std::vector<uint8_t>*> readResult = dataExtent.read_data();
- if (!readResult) {
- return readResult.error();
- }
-
- const std::vector<uint8_t> compressed_bytes = std::move(**readResult);
-
- for (Box_icef::CompressedUnitInfo unit_info : icef_box->get_units()) {
- if (unit_info.unit_offset + unit_info.unit_size > compressed_bytes.size()) {
- return Error{
- heif_error_Invalid_input,
- heif_suberror_Unspecified,
- "incomplete data in unci image"
- };
- }
-
- auto unit_start = compressed_bytes.begin() + unit_info.unit_offset;
- auto unit_end = unit_start + unit_info.unit_size;
- std::vector<uint8_t> compressed_unit_data = std::vector<uint8_t>(unit_start, unit_end);
-
- auto dataResult = do_decompress_data(cmpC_box, std::move(compressed_unit_data));
- if (!dataResult) {
- return dataResult.error();
- }
-
- const std::vector<uint8_t> uncompressed_unit_data = std::move(*dataResult);
- data->insert(data->end(), uncompressed_unit_data.data(), uncompressed_unit_data.data() + uncompressed_unit_data.size());
- }
-
- if (range_start_offset + range_size > data->size()) {
- return {heif_error_Invalid_input,
- heif_suberror_Unspecified,
- "Data range out of existing range"};
- }
-
- // cut out the range that we actually need
- memcpy(data->data(), data->data() + range_start_offset, range_size);
- data->resize(range_size);
- }
- else {
- // get all data and decode all
- Result<std::vector<uint8_t>*> readResult = dataExtent.read_data();
- if (!readResult) {
- return readResult.error();
- }
-
- std::vector<uint8_t> compressed_bytes = std::move(**readResult);
-
- // Decode as a single blob
- auto dataResult = do_decompress_data(cmpC_box, compressed_bytes);
- if (!dataResult) {
- return dataResult.error();
- }
-
- *data = std::move(*dataResult);
-
- if (range_start_offset + range_size > data->size()) {
- return {heif_error_Invalid_input,
- heif_suberror_Unspecified,
- "Data range out of existing range"};
- }
-
- // cut out the range that we actually need
- memcpy(data->data(), data->data() + range_start_offset, range_size);
- data->resize(range_size);
- }
-
- return Error::Ok;
-}
-
-
-Result<std::vector<uint8_t>> unc_decoder_legacybase::do_decompress_data(std::shared_ptr<const Box_cmpC>& cmpC_box,
- std::vector<uint8_t> compressed_data) const
-{
- if (cmpC_box->get_compression_type() == fourcc("brot")) {
-#if HAVE_BROTLI
- return decompress_brotli(compressed_data);
-#else
- std::stringstream sstr;
- sstr << "cannot decode unci item with brotli compression - not enabled" << std::endl;
- return Error(heif_error_Unsupported_feature,
- heif_suberror_Unsupported_generic_compression_method,
- sstr.str());
-#endif
- }
- else if (cmpC_box->get_compression_type() == fourcc("zlib")) {
-#if HAVE_ZLIB
- return decompress_zlib(compressed_data);
-#else
- std::stringstream sstr;
- sstr << "cannot decode unci item with zlib compression - not enabled" << std::endl;
- return Error(heif_error_Unsupported_feature,
- heif_suberror_Unsupported_generic_compression_method,
- sstr.str());
-#endif
- }
- else if (cmpC_box->get_compression_type() == fourcc("defl")) {
-#if HAVE_ZLIB
- return decompress_deflate(compressed_data);
-#else
- std::stringstream sstr;
- sstr << "cannot decode unci item with deflate compression - not enabled" << std::endl;
- return Error(heif_error_Unsupported_feature,
- heif_suberror_Unsupported_generic_compression_method,
- sstr.str());
-#endif
- }
- else {
- std::stringstream sstr;
- sstr << "cannot decode unci item with unsupported compression type: " << cmpC_box->get_compression_type() << std::endl;
- return Error(heif_error_Unsupported_feature,
- heif_suberror_Unsupported_generic_compression_method,
- sstr.str());
- }
-}
-
diff --git a/libheif/codecs/uncompressed/unc_decoder_legacybase.h b/libheif/codecs/uncompressed/unc_decoder_legacybase.h
index 4489b36f..f2a60123 100644
--- a/libheif/codecs/uncompressed/unc_decoder_legacybase.h
+++ b/libheif/codecs/uncompressed/unc_decoder_legacybase.h
@@ -134,6 +134,8 @@ class unc_decoder_legacybase : public unc_decoder
public:
~unc_decoder_legacybase() override = default;
+ void ensure_channel_list(std::shared_ptr<HeifPixelImage>& img) override { ensureChannelList(img); }
+
protected:
unc_decoder_legacybase(uint32_t width, uint32_t height,
const std::shared_ptr<const Box_cmpd>& cmpd,
@@ -188,17 +190,6 @@ protected:
// Not valid for multi-Y pixel interleave
void processComponentTileRow(ChannelListEntry& entry, UncompressedBitReader& srcBits, uint64_t dst_offset);
- // generic compression and uncompressed, per 23001-17
- const Error get_compressed_image_data_uncompressed(const DataExtent& dataExtent,
- const UncompressedImageCodec::unci_properties& properties,
- std::vector<uint8_t>* data,
- uint64_t range_start_offset, uint64_t range_size,
- uint32_t tile_idx,
- const Box_iloc::Item* item) const;
-
- Result<std::vector<uint8_t>> do_decompress_data(std::shared_ptr<const Box_cmpC>& cmpC_box,
- std::vector<uint8_t> compressed_data) const;
-
protected:
void memcpy_to_native_endian(uint8_t* dst, uint32_t value, uint32_t bytes_per_sample);
diff --git a/libheif/codecs/uncompressed/unc_decoder_mixed_interleave.cc b/libheif/codecs/uncompressed/unc_decoder_mixed_interleave.cc
index 89f14c0d..48eca4d0 100644
--- a/libheif/codecs/uncompressed/unc_decoder_mixed_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_decoder_mixed_interleave.cc
@@ -27,20 +27,15 @@
#include <vector>
-Error unc_decoder_mixed_interleave::decode_tile(const DataExtent& dataExtent,
- const UncompressedImageCodec::unci_properties& properties,
- std::shared_ptr<HeifPixelImage>& img,
- uint32_t out_x0, uint32_t out_y0,
- uint32_t tile_x, uint32_t tile_y)
+Error unc_decoder_mixed_interleave::fetch_tile_data(const DataExtent& dataExtent,
+ const UncompressedImageCodec::unci_properties& properties,
+ uint32_t tile_x, uint32_t tile_y,
+ std::vector<uint8_t>& tile_data)
{
- ensureChannelList(img);
-
if (m_tile_width == 0) {
return {heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "Internal error: unc_decoder_mixed_interleave tile_width=0"};
}
- // --- compute which file range we need to read for the tile
-
uint64_t tile_size = 0;
for (ChannelListEntry& entry : channelList) {
@@ -65,7 +60,6 @@ Error unc_decoder_mixed_interleave::decode_tile(const DataExtent& dataExtent,
}
}
-
if (m_uncC->get_tile_align_size() != 0) {
skip_to_alignment(tile_size, m_uncC->get_tile_align_size());
}
@@ -74,16 +68,16 @@ Error unc_decoder_mixed_interleave::decode_tile(const DataExtent& dataExtent,
uint32_t tileIdx = tile_x + tile_y * (m_width / m_tile_width);
uint64_t tile_start_offset = tile_size * tileIdx;
+ return get_compressed_image_data_uncompressed(dataExtent, properties, &tile_data, tile_start_offset, tile_size, tileIdx, nullptr);
+}
- // --- read required file range
-
- std::vector<uint8_t> src_data;
- Error err = get_compressed_image_data_uncompressed(dataExtent, properties, &src_data, tile_start_offset, tile_size, tileIdx, nullptr);
- if (err) {
- return err;
- }
- UncompressedBitReader srcBits(src_data);
+Error unc_decoder_mixed_interleave::decode_tile(const std::vector<uint8_t>& tile_data,
+ std::shared_ptr<HeifPixelImage>& img,
+ uint32_t out_x0, uint32_t out_y0,
+ uint32_t tile_x, uint32_t tile_y)
+{
+ UncompressedBitReader srcBits(tile_data);
processTile(srcBits, tile_y, tile_x, out_x0, out_y0);
diff --git a/libheif/codecs/uncompressed/unc_decoder_mixed_interleave.h b/libheif/codecs/uncompressed/unc_decoder_mixed_interleave.h
index c90e283a..7b6b58f5 100644
--- a/libheif/codecs/uncompressed/unc_decoder_mixed_interleave.h
+++ b/libheif/codecs/uncompressed/unc_decoder_mixed_interleave.h
@@ -32,8 +32,12 @@ public:
unc_decoder_mixed_interleave(uint32_t width, uint32_t height, std::shared_ptr<const Box_cmpd> cmpd, std::shared_ptr<const Box_uncC> uncC) :
unc_decoder_legacybase(width, height, std::move(cmpd), std::move(uncC)) {}
- Error decode_tile(const DataExtent& dataExtent,
- const UncompressedImageCodec::unci_properties& properties,
+ Error fetch_tile_data(const DataExtent& dataExtent,
+ const UncompressedImageCodec::unci_properties& properties,
+ uint32_t tile_x, uint32_t tile_y,
+ std::vector<uint8_t>& tile_data) override;
+
+ Error decode_tile(const std::vector<uint8_t>& tile_data,
std::shared_ptr<HeifPixelImage>& img,
uint32_t out_x0, uint32_t out_y0,
uint32_t tile_x, uint32_t tile_y) override;
diff --git a/libheif/codecs/uncompressed/unc_decoder_pixel_interleave.cc b/libheif/codecs/uncompressed/unc_decoder_pixel_interleave.cc
index 4ef31a0c..93933ebc 100644
--- a/libheif/codecs/uncompressed/unc_decoder_pixel_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_decoder_pixel_interleave.cc
@@ -26,20 +26,15 @@
#include <vector>
-Error unc_decoder_pixel_interleave::decode_tile(const DataExtent& dataExtent,
- const UncompressedImageCodec::unci_properties& properties,
- std::shared_ptr<HeifPixelImage>& img,
- uint32_t out_x0, uint32_t out_y0,
- uint32_t tile_x, uint32_t tile_y)
+Error unc_decoder_pixel_interleave::fetch_tile_data(const DataExtent& dataExtent,
+ const UncompressedImageCodec::unci_properties& properties,
+ uint32_t tile_x, uint32_t tile_y,
+ std::vector<uint8_t>& tile_data)
{
- ensureChannelList(img);
-
if (m_tile_width == 0) {
return {heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "Internal error: unc_decoder_pixel_interleave tile_width=0"};
}
- // --- compute which file range we need to read for the tile
-
uint32_t bits_per_row = 0;
for (uint32_t x = 0; x < m_tile_width; x++) {
uint32_t bits_per_pixel = 0;
@@ -79,23 +74,18 @@ Error unc_decoder_pixel_interleave::decode_tile(const DataExtent& dataExtent,
uint32_t tileIdx = tile_x + tile_y * (m_width / m_tile_width);
uint64_t tile_start_offset = total_tile_size * tileIdx;
+ return get_compressed_image_data_uncompressed(dataExtent, properties, &tile_data, tile_start_offset, total_tile_size, tileIdx, nullptr);
+}
- // --- read required file range
-
- std::vector<uint8_t> src_data;
- Error err = get_compressed_image_data_uncompressed(dataExtent, properties, &src_data, tile_start_offset, total_tile_size, tileIdx, nullptr);
- if (err) {
- return err;
- }
-
- UncompressedBitReader srcBits(src_data);
- err = processTile(srcBits, tile_y, tile_x, out_x0, out_y0);
- if (err) {
- return err;
- }
+Error unc_decoder_pixel_interleave::decode_tile(const std::vector<uint8_t>& tile_data,
+ std::shared_ptr<HeifPixelImage>& img,
+ uint32_t out_x0, uint32_t out_y0,
+ uint32_t tile_x, uint32_t tile_y)
+{
+ UncompressedBitReader srcBits(tile_data);
- return Error::Ok;
+ return processTile(srcBits, tile_y, tile_x, out_x0, out_y0);
}
diff --git a/libheif/codecs/uncompressed/unc_decoder_pixel_interleave.h b/libheif/codecs/uncompressed/unc_decoder_pixel_interleave.h
index 7c644374..40eb5d44 100644
--- a/libheif/codecs/uncompressed/unc_decoder_pixel_interleave.h
+++ b/libheif/codecs/uncompressed/unc_decoder_pixel_interleave.h
@@ -32,8 +32,12 @@ public:
unc_decoder_pixel_interleave(uint32_t width, uint32_t height, std::shared_ptr<const Box_cmpd> cmpd, std::shared_ptr<const Box_uncC> uncC) :
unc_decoder_legacybase(width, height, std::move(cmpd), std::move(uncC)) {}
- Error decode_tile(const DataExtent& dataExtent,
- const UncompressedImageCodec::unci_properties& properties,
+ Error fetch_tile_data(const DataExtent& dataExtent,
+ const UncompressedImageCodec::unci_properties& properties,
+ uint32_t tile_x, uint32_t tile_y,
+ std::vector<uint8_t>& tile_data) override;
+
+ Error decode_tile(const std::vector<uint8_t>& tile_data,
std::shared_ptr<HeifPixelImage>& img,
uint32_t out_x0, uint32_t out_y0,
uint32_t tile_x, uint32_t tile_y) override;
diff --git a/libheif/codecs/uncompressed/unc_decoder_row_interleave.cc b/libheif/codecs/uncompressed/unc_decoder_row_interleave.cc
index 5bae63fc..f437a1fb 100644
--- a/libheif/codecs/uncompressed/unc_decoder_row_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_decoder_row_interleave.cc
@@ -26,20 +26,15 @@
#include <vector>
-Error unc_decoder_row_interleave::decode_tile(const DataExtent& dataExtent,
- const UncompressedImageCodec::unci_properties& properties,
- std::shared_ptr<HeifPixelImage>& img,
- uint32_t out_x0, uint32_t out_y0,
- uint32_t tile_x, uint32_t tile_y)
+Error unc_decoder_row_interleave::fetch_tile_data(const DataExtent& dataExtent,
+ const UncompressedImageCodec::unci_properties& properties,
+ uint32_t tile_x, uint32_t tile_y,
+ std::vector<uint8_t>& tile_data)
{
- ensureChannelList(img);
-
if (m_tile_width == 0) {
return {heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "Internal error: unc_decoder_row_interleave tile_width=0"};
}
- // --- compute which file range we need to read for the tile
-
uint32_t bits_per_row = 0;
for (ChannelListEntry& entry : channelList) {
uint32_t bits_per_component = entry.bits_per_component_sample;
@@ -80,16 +75,16 @@ Error unc_decoder_row_interleave::decode_tile(const DataExtent& dataExtent,
uint32_t tileIdx = tile_x + tile_y * (m_width / m_tile_width);
uint64_t tile_start_offset = total_tile_size * tileIdx;
+ return get_compressed_image_data_uncompressed(dataExtent, properties, &tile_data, tile_start_offset, total_tile_size, tileIdx, nullptr);
+}
- // --- read required file range
-
- std::vector<uint8_t> src_data;
- Error err = get_compressed_image_data_uncompressed(dataExtent, properties, &src_data, tile_start_offset, total_tile_size, tileIdx, nullptr);
- if (err) {
- return err;
- }
- UncompressedBitReader srcBits(src_data);
+Error unc_decoder_row_interleave::decode_tile(const std::vector<uint8_t>& tile_data,
+ std::shared_ptr<HeifPixelImage>& img,
+ uint32_t out_x0, uint32_t out_y0,
+ uint32_t tile_x, uint32_t tile_y)
+{
+ UncompressedBitReader srcBits(tile_data);
processTile(srcBits, tile_y, tile_x, out_x0, out_y0);
diff --git a/libheif/codecs/uncompressed/unc_decoder_row_interleave.h b/libheif/codecs/uncompressed/unc_decoder_row_interleave.h
index eee442bf..0d8d9304 100644
--- a/libheif/codecs/uncompressed/unc_decoder_row_interleave.h
+++ b/libheif/codecs/uncompressed/unc_decoder_row_interleave.h
@@ -34,8 +34,12 @@ public:
unc_decoder_legacybase(width, height, std::move(cmpd), std::move(uncC)) {}
- Error decode_tile(const DataExtent& dataExtent,
- const UncompressedImageCodec::unci_properties& properties,
+ Error fetch_tile_data(const DataExtent& dataExtent,
+ const UncompressedImageCodec::unci_properties& properties,
+ uint32_t tile_x, uint32_t tile_y,
+ std::vector<uint8_t>& tile_data) override;
+
+ Error decode_tile(const std::vector<uint8_t>& tile_data,
std::shared_ptr<HeifPixelImage>& img,
uint32_t out_x0, uint32_t out_y0,
uint32_t tile_x, uint32_t tile_y) override;