Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

heif-enc with tiles input #1334

Merged
merged 11 commits into from
Oct 13, 2024
342 changes: 329 additions & 13 deletions examples/heif_enc.cc

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions heifio/decoder_tiff.cc
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,15 @@ heif_error readBandInterleave(TIFF *tif, uint16_t samplesPerPixel, heif_image **
}
}


static void suppress_warnings(const char* module, const char* fmt, va_list ap) {
// Do nothing
}


heif_error loadTIFF(const char* filename, InputImage *input_image) {
TIFFSetWarningHandler(suppress_warnings);

std::unique_ptr<TIFF, void(*)(TIFF*)> tifPtr(TIFFOpen(filename, "r"), [](TIFF* tif) { TIFFClose(tif); });
if (!tifPtr) {
struct heif_error err = {
Expand Down
26 changes: 11 additions & 15 deletions libheif/api/libheif/heif.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3429,14 +3429,10 @@ struct heif_error heif_context_add_grid_image(struct heif_context* ctx,
uint32_t image_height,
uint32_t tile_columns,
uint32_t tile_rows,
const heif_item_id* image_ids,
const struct heif_encoding_options* encoding_options,
struct heif_image_handle** out_grid_image_handle)
{
if (!image_ids) {
return Error(heif_error_Usage_error,
heif_suberror_Null_pointer_argument).error_struct(ctx->context.get());
}
else if (tile_rows == 0 || tile_columns == 0) {
if (tile_rows == 0 || tile_columns == 0) {
return Error(heif_error_Usage_error,
heif_suberror_Invalid_parameter_value).error_struct(ctx->context.get());
}
Expand All @@ -3446,16 +3442,11 @@ struct heif_error heif_context_add_grid_image(struct heif_context* ctx,
"Number of tile rows/columns may not exceed 65535"};
}


std::vector<heif_item_id> tiles(tile_rows * tile_columns);
for (uint64_t i = 0; i < tile_rows * tile_columns; i++) {
tiles[i] = image_ids[i];
}

std::shared_ptr<ImageItem> gridimage;
Error error = ctx->context->add_grid_item(tiles, image_width, image_height,
std::shared_ptr<ImageItem_Grid> gridimage;
Error error = ctx->context->add_grid_item(image_width, image_height,
static_cast<uint16_t>(tile_rows),
static_cast<uint16_t>(tile_columns),
encoding_options,
gridimage);

if (error != Error::Ok) {
Expand Down Expand Up @@ -3529,10 +3520,11 @@ struct heif_error heif_context_add_overlay_image(struct heif_context* ctx,
struct heif_error heif_context_add_tiled_image(struct heif_context* ctx,
const struct heif_tiled_image_parameters* parameters,
const struct heif_encoding_options* options, // TODO: do we need this?
const struct heif_encoder* encoder,
struct heif_image_handle** out_grid_image_handle)
{
Result<std::shared_ptr<ImageItem_Tiled>> gridImageResult;
gridImageResult = ctx->context->add_tiled_item(parameters);
gridImageResult = ctx->context->add_tiled_item(parameters, encoder);

if (gridImageResult.error != Error::Ok) {
return gridImageResult.error.error_struct(ctx->context.get());
Expand Down Expand Up @@ -3564,6 +3556,10 @@ struct heif_error heif_context_add_image_tile(struct heif_context* ctx,
return err.error_struct(ctx->context.get());
}
#endif
else if (tiled_image->image->get_infe_type() == fourcc("grid")) {
Error err = ctx->context->add_grid_image_tile(tiled_image->image->get_id(), tile_x, tile_y, image->image, encoder);
return err.error_struct(ctx->context.get());
}
else {
return {
heif_error_Usage_error,
Expand Down
2 changes: 1 addition & 1 deletion libheif/api/libheif/heif.h
Original file line number Diff line number Diff line change
Expand Up @@ -2369,7 +2369,7 @@ struct heif_error heif_context_add_grid_image(struct heif_context* ctx,
uint32_t image_height,
uint32_t tile_columns,
uint32_t tile_rows,
const heif_item_id* image_ids,
const struct heif_encoding_options* encoding_options,
struct heif_image_handle** out_grid_image_handle);

LIBHEIF_API
Expand Down
3 changes: 2 additions & 1 deletion libheif/api/libheif/heif_experimental.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ struct heif_tiled_image_parameters {
uint32_t tile_width;
uint32_t tile_height;

uint32_t compression_type_fourcc; // TODO: can this be set automatically ?
uint32_t compression_format_fourcc; // will be set automatically when calling heif_context_add_tiled_image()

uint8_t offset_field_length; // one of: 32, 40, 48, 64
uint8_t size_field_length; // one of: 0, 24, 32, 64
Expand All @@ -140,6 +140,7 @@ LIBHEIF_API
struct heif_error heif_context_add_tiled_image(struct heif_context* ctx,
const struct heif_tiled_image_parameters* parameters,
const struct heif_encoding_options* options, // TODO: do we need this?
const struct heif_encoder* encoder,
struct heif_image_handle** out_tiled_image_handle);


Expand Down
63 changes: 50 additions & 13 deletions libheif/box.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2766,6 +2766,15 @@ void Box_ipma::add_property_for_item_ID(heif_item_id itemID,
m_entries.push_back(entry);
}

// If the property is already associated with the item, skip.
for (auto const& a : m_entries[idx].associations) {
if (a.property_index == assoc.property_index) {
return;
}

// TODO: should we check that the essential flag matches and return an internal error if not?
}

// add the property association
m_entries[idx].associations.push_back(assoc);
}
Expand Down Expand Up @@ -3209,18 +3218,8 @@ Error Box_iref::parse(BitstreamRange& range, const heif_security_limits* limits)

// --- check for duplicate references

for (const auto& ref : m_references) {
std::set<heif_item_id> to_ids;
for (const auto to_id : ref.to_item_ID) {
if (to_ids.find(to_id) == to_ids.end()) {
to_ids.insert(to_id);
}
else {
return Error(heif_error_Invalid_input,
heif_suberror_Unspecified,
"'iref' has double references");
}
}
if (auto error = check_for_double_references()) {
return error;
}


Expand Down Expand Up @@ -3279,6 +3278,26 @@ Error Box_iref::parse(BitstreamRange& range, const heif_security_limits* limits)
}


Error Box_iref::check_for_double_references() const
{
for (const auto& ref : m_references) {
std::set<heif_item_id> to_ids;
for (const auto to_id : ref.to_item_ID) {
if (to_ids.find(to_id) == to_ids.end()) {
to_ids.insert(to_id);
}
else {
return {heif_error_Invalid_input,
heif_suberror_Unspecified,
"'iref' has double references"};
}
}
}

return Error::Ok;
}


void Box_iref::derive_box_version()
{
uint8_t version = 0;
Expand All @@ -3303,6 +3322,10 @@ void Box_iref::derive_box_version()

Error Box_iref::write(StreamWriter& writer) const
{
if (auto error = check_for_double_references()) {
return error;
}

size_t box_start = reserve_box_header_space(writer);

int id_size = ((get_version() == 0) ? 2 : 4);
Expand All @@ -3322,7 +3345,6 @@ Error Box_iref::write(StreamWriter& writer) const
}
}


prepend_header(writer, box_start);

return Error::Ok;
Expand Down Expand Up @@ -3400,6 +3422,21 @@ void Box_iref::add_references(heif_item_id from_id, uint32_t type, const std::ve
}


void Box_iref::overwrite_reference(heif_item_id from_id, uint32_t type, uint32_t reference_idx, heif_item_id to_item)
{
for (auto& ref : m_references) {
if (ref.from_item_ID == from_id && ref.header.get_short_type() == type) {
assert(reference_idx >= 0 && reference_idx < ref.to_item_ID.size());

ref.to_item_ID[reference_idx] = to_item;
return;
}
}

assert(false); // reference was not found
}


Error Box_idat::parse(BitstreamRange& range, const heif_security_limits* limits)
{
//parse_full_box_header(range);
Expand Down
4 changes: 4 additions & 0 deletions libheif/box.h
Original file line number Diff line number Diff line change
Expand Up @@ -932,13 +932,17 @@ class Box_iref : public FullBox

void add_references(heif_item_id from_id, uint32_t type, const std::vector<heif_item_id>& to_ids);

void overwrite_reference(heif_item_id from_id, uint32_t type, uint32_t reference_idx, heif_item_id to_item);

protected:
Error parse(BitstreamRange& range, const heif_security_limits*) override;

Error write(StreamWriter& writer) const override;

void derive_box_version() override;

Error check_for_double_references() const;

private:
std::vector<Reference> m_references;
};
Expand Down
72 changes: 51 additions & 21 deletions libheif/context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1243,26 +1243,19 @@ Error HeifContext::encode_grid(const std::vector<std::shared_ptr<HeifPixelImage>
}


Error HeifContext::add_grid_item(const std::vector<heif_item_id>& tile_ids,
uint32_t output_width,
uint32_t output_height,
uint16_t tile_rows,
uint16_t tile_columns,
std::shared_ptr<ImageItem>& out_grid_image)
Error HeifContext::add_grid_item(uint32_t output_width,
uint32_t output_height,
uint16_t tile_rows,
uint16_t tile_columns,
const struct heif_encoding_options* encoding_options,
std::shared_ptr<ImageItem_Grid>& out_grid_image)
{
if (tile_ids.size() > 0xFFFF) {
if (tile_rows > 0xFFFF / tile_columns) {
return {heif_error_Usage_error,
heif_suberror_Unspecified,
"Too many tiles (maximum: 65535)"};
}

#if 1
for (heif_item_id tile_id : tile_ids) {
m_heif_file->get_infe_box(tile_id)->set_hidden_item(true); // only show the full grid
}
#endif


// Create ImageGrid

ImageGrid grid;
Expand All @@ -1273,20 +1266,25 @@ Error HeifContext::add_grid_item(const std::vector<heif_item_id>& tile_ids,
// Create Grid Item

heif_item_id grid_id = m_heif_file->add_new_image(fourcc("grid"));
out_grid_image = std::make_shared<ImageItem>(this, grid_id);
out_grid_image = std::make_shared<ImageItem_Grid>(this, grid_id);
out_grid_image->set_encoding_options(encoding_options);
out_grid_image->set_grid_spec(grid);

m_all_images.insert(std::make_pair(grid_id, out_grid_image));
const int construction_method = 1; // 0=mdat 1=idat
m_heif_file->append_iloc_data(grid_id, grid_data, construction_method);

// generate dummy grid item IDs (0)
std::vector<heif_item_id> tile_ids;
tile_ids.resize(tile_rows * tile_columns);

// Connect tiles to grid
m_heif_file->add_iref_reference(grid_id, fourcc("dimg"), tile_ids);

// Add ISPE property
m_heif_file->add_ispe_property(grid_id, output_width, output_height, false);

// Add PIXI property (copy from first tile)
auto pixi = m_heif_file->get_property<Box_pixi>(tile_ids[0]);
m_heif_file->add_property(grid_id, pixi, true);
// PIXI property will be added when the first tile is set

// Set Brands
//m_heif_file->set_brand(encoder->plugin->compression_format,
Expand Down Expand Up @@ -1342,9 +1340,10 @@ Result<std::shared_ptr<ImageItem_Overlay>> HeifContext::add_iovl_item(const Imag
}


Result<std::shared_ptr<ImageItem_Tiled>> HeifContext::add_tiled_item(const heif_tiled_image_parameters* parameters)
Result<std::shared_ptr<ImageItem_Tiled>> HeifContext::add_tiled_item(const heif_tiled_image_parameters* parameters,
const struct heif_encoder* encoder)
{
return ImageItem_Tiled::add_new_tiled_item(this, parameters);
return ImageItem_Tiled::add_new_tiled_item(this, parameters, encoder);
}


Expand All @@ -1354,7 +1353,7 @@ Error HeifContext::add_tiled_image_tile(heif_item_id tild_id, uint32_t tile_x, u
{
auto item = ImageItem::alloc_for_compression_format(this, encoder->plugin->compression_format);

heif_encoding_options* options = heif_encoding_options_alloc();
heif_encoding_options* options = heif_encoding_options_alloc(); // TODO: should this be taken from heif_context_add_tiled_image() ?

Result<std::shared_ptr<HeifPixelImage>> colorConversionResult = item->convert_colorspace_for_encoding(image, encoder, *options);
if (colorConversionResult.error) {
Expand Down Expand Up @@ -1426,6 +1425,37 @@ Error HeifContext::add_tiled_image_tile(heif_item_id tild_id, uint32_t tile_x, u
}


Error HeifContext::add_grid_image_tile(heif_item_id grid_id, uint32_t tile_x, uint32_t tile_y,
const std::shared_ptr<HeifPixelImage>& image,
struct heif_encoder* encoder)
{
auto grid_item = std::dynamic_pointer_cast<ImageItem_Grid>(get_image(grid_id));
auto encoding_options = grid_item->get_encoding_options();

std::shared_ptr<ImageItem> encoded_image;
Error error = encode_image(image,
encoder,
*encoding_options,
heif_image_input_class_normal,
encoded_image);
if (error != Error::Ok) {
return error;
}

m_heif_file->get_infe_box(encoded_image->get_id())->set_hidden_item(true); // grid tiles are hidden items

// Assign tile to grid
heif_image_tiling tiling = grid_item->get_heif_image_tiling();
m_heif_file->set_iref_reference(grid_id, fourcc("dimg"), tile_y * tiling.num_columns + tile_x, encoded_image->get_id());

// Add PIXI property (copy from first tile)
auto pixi = m_heif_file->get_property<Box_pixi>(encoded_image->get_id());
m_heif_file->add_property(grid_id, pixi, true);

return Error::Ok;
}


Result<std::shared_ptr<ImageItem_uncompressed>> HeifContext::add_unci_item(const heif_unci_image_parameters* parameters,
const struct heif_encoding_options* encoding_options,
const std::shared_ptr<const HeifPixelImage>& prototype)
Expand Down
13 changes: 9 additions & 4 deletions libheif/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,21 +151,26 @@ class HeifContext : public ErrorBuffer
const struct heif_encoding_options& options,
std::shared_ptr<ImageItem>& out_image);

Error add_grid_item(const std::vector<heif_item_id>& tile_ids,
uint32_t output_width,
Error add_grid_item(uint32_t output_width,
uint32_t output_height,
uint16_t tile_rows,
uint16_t tile_columns,
std::shared_ptr<ImageItem>& out_grid_image);
const struct heif_encoding_options* encoding_options,
std::shared_ptr<class ImageItem_Grid>& out_grid_image);

Result<std::shared_ptr<ImageItem_Overlay>> add_iovl_item(const ImageOverlay& overlayspec);

Result<std::shared_ptr<ImageItem_Tiled>> add_tiled_item(const heif_tiled_image_parameters* parameters);
Result<std::shared_ptr<ImageItem_Tiled>> add_tiled_item(const heif_tiled_image_parameters* parameters,
const struct heif_encoder* encoder);

Error add_tiled_image_tile(heif_item_id tili_id, uint32_t tile_x, uint32_t tile_y,
const std::shared_ptr<HeifPixelImage>& image,
struct heif_encoder* encoder);

Error add_grid_image_tile(heif_item_id grid_id, uint32_t tile_x, uint32_t tile_y,
const std::shared_ptr<HeifPixelImage>& image,
struct heif_encoder* encoder);

Result<std::shared_ptr<ImageItem_uncompressed>> add_unci_item(const heif_unci_image_parameters* parameters,
const struct heif_encoding_options* encoding_options,
const std::shared_ptr<const HeifPixelImage>& prototype);
Expand Down
7 changes: 7 additions & 0 deletions libheif/file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1045,6 +1045,13 @@ void HeifFile::add_iref_reference(heif_item_id from, uint32_t type,
}


void HeifFile::set_iref_reference(heif_item_id from, uint32_t type, int reference_idx, heif_item_id to_item)
{
assert(m_iref_box);
m_iref_box->overwrite_reference(from, type, reference_idx, to_item);
}


void HeifFile::add_entity_group_box(const std::shared_ptr<Box>& entity_group_box)
{
if (!m_grpl_box) {
Expand Down
Loading
Loading