Skip to content

Commit

Permalink
heif_image_handle_get_image_tiling() support for image transformations
Browse files Browse the repository at this point in the history
  • Loading branch information
farindk committed Oct 6, 2024
1 parent 71eed2e commit e18ac58
Show file tree
Hide file tree
Showing 14 changed files with 207 additions and 36 deletions.
7 changes: 6 additions & 1 deletion examples/heif_info.cc
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,12 @@ int main(int argc, char** argv)

printf("image: %dx%d (id=%d)%s\n", width, height, IDs[i], primary ? ", primary" : "");

heif_image_tiling tiling = heif_image_handle_get_image_tiling(handle);
heif_image_tiling tiling;
err = heif_image_handle_get_image_tiling(handle, true, &tiling);
if (err.code) {
std::cerr << err.message << "\n";
return 10;
}
if (tiling.num_columns > 0) {
std::cout << " tiles: " << tiling.num_columns << "x" << tiling.num_rows
<< ", tile size: " << tiling.tile_width << "x" << tiling.tile_height << "\n";
Expand Down
31 changes: 12 additions & 19 deletions libheif/api/libheif/heif.cc
Original file line number Diff line number Diff line change
Expand Up @@ -860,31 +860,24 @@ struct heif_context* heif_image_handle_get_context(const struct heif_image_handl
}


struct heif_image_tiling heif_image_handle_get_image_tiling(const struct heif_image_handle* handle)
heif_error heif_image_handle_get_image_tiling(const struct heif_image_handle* handle, int process_image_transformations, struct heif_image_tiling* tiling)
{
struct heif_image_tiling tiling{};
if (!handle) {
return tiling;
if (!handle || !tiling) {
return {heif_error_Usage_error,
heif_suberror_Null_pointer_argument,
"NULL passed to heif_image_handle_get_image_tiling()"};
}

std::shared_ptr<ImageItem_Grid> gridItem = std::dynamic_pointer_cast<ImageItem_Grid>(handle->image);
if (gridItem) {
return gridItem->get_heif_image_tiling();
}
*tiling = handle->image->get_heif_image_tiling();

std::shared_ptr<ImageItem_Tild> tildItem = std::dynamic_pointer_cast<ImageItem_Tild>(handle->image);
if (tildItem) {
return tildItem->get_heif_image_tiling();
}

#if WITH_UNCOMPRESSED_CODEC
std::shared_ptr<ImageItem_uncompressed> unciItem = std::dynamic_pointer_cast<ImageItem_uncompressed>(handle->image);
if (unciItem) {
return unciItem->get_heif_image_tiling();
if (process_image_transformations) {
Error error = handle->image->process_image_transformations_on_tiling(*tiling);
if (error) {
return error.error_struct(handle->context.get());
}
}
#endif

return tiling;
return heif_error_ok;
}


Expand Down
18 changes: 14 additions & 4 deletions libheif/api/libheif/heif.h
Original file line number Diff line number Diff line change
Expand Up @@ -1182,21 +1182,31 @@ struct heif_context* heif_image_handle_get_context(const struct heif_image_handl

struct heif_image_tiling
{
int version;

// --- version 1

uint32_t num_columns;
uint32_t num_rows;
uint32_t tile_width;
uint32_t tile_height;

uint32_t image_width;
uint32_t image_height;

// Position of the top left tile.
// Usually, this is (0;0), but if a tiled image is rotated or cropped, it may be that the top left tile should be placed at a negative position.
int32_t top_left_x_position;
int32_t top_left_y_position;

uint8_t number_of_extra_dimensions; // 0 for normal images, 1 for volumetric (3D), ...
uint32_t extra_dimensions[8]; // size of extra dimensions (first 8 dimensions)
uint32_t extra_dimension_size[8]; // size of extra dimensions (first 8 dimensions)
};

// If the image is not tiled, all entries of he returned struct will be zero.
// TODO: how do we handle width/height when there are image rotations?

// If 'process_image_transformations' is true, this returns modified sizes. If it is true, the top_left_x/y_position will always be (0;0).
LIBHEIF_API
struct heif_image_tiling heif_image_handle_get_image_tiling(const struct heif_image_handle* handle);
struct heif_error heif_image_handle_get_image_tiling(const struct heif_image_handle* handle, int process_image_transformations, struct heif_image_tiling* out_tiling);

// TODO: we may also need the valid area of the tile because it may be partly cut off at the image border
LIBHEIF_API
Expand Down
2 changes: 1 addition & 1 deletion libheif/api/libheif/heif_properties.cc
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ int heif_item_get_property_transform_rotation_ccw(const struct heif_context* con
return -1;
}

return irot->get_rotation();
return irot->get_rotation_ccw();
}


Expand Down
2 changes: 1 addition & 1 deletion libheif/box.h
Original file line number Diff line number Diff line change
Expand Up @@ -815,7 +815,7 @@ class Box_irot : public Box

std::string dump(Indent&) const override;

int get_rotation() const { return m_rotation; }
int get_rotation_ccw() const { return m_rotation; }

// Only these multiples of 90 are allowed: 0, 90, 180, 270.
void set_rotation_ccw(int rot) { m_rotation = rot; }
Expand Down
4 changes: 2 additions & 2 deletions libheif/context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -431,8 +431,8 @@ Error HeifContext::interpret_heif_file()

auto irot = std::dynamic_pointer_cast<Box_irot>(prop);
if (irot) {
if (irot->get_rotation() == 90 ||
irot->get_rotation() == 270) {
if (irot->get_rotation_ccw() == 90 ||
irot->get_rotation_ccw() == 270) {
// swap width and height
image->set_resolution(image->get_height(),
image->get_width());
Expand Down
12 changes: 12 additions & 0 deletions libheif/image-items/grid.cc
Original file line number Diff line number Diff line change
Expand Up @@ -509,3 +509,15 @@ int ImageItem_Grid::get_chroma_bits_per_pixel() const
auto image = get_context()->get_image(child);
return image->get_chroma_bits_per_pixel();
}

std::shared_ptr<Decoder> ImageItem_Grid::get_decoder() const
{
heif_item_id child;
Error err = get_context()->get_id_of_non_virtual_child_image(get_id(), child);
if (err) {
return nullptr;
}

auto image = get_context()->get_image(child);
return image->get_decoder();
}
6 changes: 5 additions & 1 deletion libheif/image-items/grid.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,14 +104,18 @@ class ImageItem_Grid : public ImageItem
Result<std::shared_ptr<HeifPixelImage>> decode_compressed_image(const struct heif_decoding_options& options,
bool decode_tile_only, uint32_t tile_x0, uint32_t tile_y0) const override;

protected:
std::shared_ptr<Decoder> get_decoder() const override;

public:

// --- grid specific

const ImageGrid& get_grid_spec() const { return m_grid_spec; }

const std::vector<heif_item_id>& get_grid_tiles() const { return m_grid_tile_ids; }

heif_image_tiling get_heif_image_tiling() const;
heif_image_tiling get_heif_image_tiling() const override;

void get_tile_size(uint32_t& w, uint32_t& h) const override;

Expand Down
143 changes: 142 additions & 1 deletion libheif/image-items/image_item.cc
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,7 @@ Result<std::shared_ptr<HeifPixelImage>> ImageItem::decode_image(const struct hei

for (const auto& property : properties) {
if (auto rot = std::dynamic_pointer_cast<Box_irot>(property)) {
auto rotateResult = img->rotate_ccw(rot->get_rotation());
auto rotateResult = img->rotate_ccw(rot->get_rotation_ccw());
if (rotateResult.error) {
return error;
}
Expand Down Expand Up @@ -930,3 +930,144 @@ Result<std::shared_ptr<HeifPixelImage>> ImageItem::decode_compressed_image(const

return decoder->decode_single_frame_from_compressed_data(options);
}


heif_image_tiling ImageItem::get_heif_image_tiling() const
{
// --- Return a dummy tiling consisting of only a single tile for the whole image

heif_image_tiling tiling{};

tiling.version = 1;
tiling.num_columns = 1;
tiling.num_rows = 1;

tiling.tile_width = m_width;
tiling.tile_height = m_height;
tiling.image_width = m_width;
tiling.image_height = m_height;

tiling.top_left_x_position = 0;
tiling.top_left_y_position = 0;
tiling.number_of_extra_dimensions = 0;

for (uint32_t& s : tiling.extra_dimension_size) {
s = 0;
}

return tiling;
}


Result<std::vector<std::shared_ptr<Box>>> ImageItem::get_properties() const
{
std::vector<std::shared_ptr<Box>> properties;
auto ipco_box = get_file()->get_ipco_box();
auto ipma_box = get_file()->get_ipma_box();
Error error = ipco_box->get_properties_for_item_ID(m_id, ipma_box, properties);
if (error) {
return error;
}

return properties;
}


Error ImageItem::process_image_transformations_on_tiling(heif_image_tiling& tiling) const
{
Result<std::vector<std::shared_ptr<Box>>> propertiesResult = get_properties();
if (propertiesResult.error) {
return propertiesResult.error;
}

const std::vector<std::shared_ptr<Box>>& properties = *propertiesResult;

uint32_t left_excess = 0;
uint32_t top_excess = 0;
uint32_t right_excess = tiling.image_width % tiling.tile_width;
uint32_t bottom_excess = tiling.image_height % tiling.tile_height;

for (const auto& property : properties) {
if (auto rot = std::dynamic_pointer_cast<Box_irot>(property)) {
int angle = rot->get_rotation_ccw();
if (angle == 90 || angle == 270) {
std::swap(tiling.tile_width, tiling.tile_height);
std::swap(tiling.image_width, tiling.image_height);
std::swap(tiling.num_rows, tiling.num_columns);
}

switch (angle) {
case 0:
break;
case 180:
std::swap(left_excess, right_excess);
std::swap(top_excess, bottom_excess);
break;
case 90: {
uint32_t old_top_excess = top_excess;
top_excess = right_excess;
right_excess = bottom_excess;
bottom_excess = left_excess;
left_excess = old_top_excess;
break;
}
case 270: {
uint32_t old_top_excess = top_excess;
top_excess = left_excess;
left_excess = bottom_excess;
bottom_excess = right_excess;
right_excess = old_top_excess;
break;
}
default:
assert(false);
break;
}
}

if (auto mirror = std::dynamic_pointer_cast<Box_imir>(property)) {
switch (mirror->get_mirror_direction()) {
case heif_transform_mirror_direction_horizontal:
std::swap(left_excess, right_excess);
break;
case heif_transform_mirror_direction_vertical:
std::swap(top_excess, bottom_excess);
break;
default:
assert(false);
break;
}
}

if (auto clap = std::dynamic_pointer_cast<Box_clap>(property)) {
std::shared_ptr<HeifPixelImage> clap_img;

int left = clap->left_rounded(tiling.image_width);
int right = clap->right_rounded(tiling.image_width);
int top = clap->top_rounded(tiling.image_height);
int bottom = clap->bottom_rounded(tiling.image_height);

if (left < 0) { left = 0; }
if (top < 0) { top = 0; }

if ((uint32_t)right >= tiling.image_width) { right = tiling.image_width - 1; }
if ((uint32_t)bottom >= tiling.image_height) { bottom = tiling.image_height - 1; }

if (left > right ||
top > bottom) {
return {heif_error_Invalid_input,
heif_suberror_Invalid_clean_aperture};
}

left_excess += left;
right_excess += right;
top_excess += top;
bottom_excess += bottom;
}
}

tiling.top_left_x_position = -left_excess;
tiling.top_left_y_position = -top_excess;

return Error::Ok;
}
10 changes: 8 additions & 2 deletions libheif/image-items/image_item.h
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,8 @@ class ImageItem : public ErrorBuffer

Error check_for_valid_image_size(uint32_t width, uint32_t height) const;

Result<std::vector<std::shared_ptr<Box>>> get_properties() const;

// === encoding ===

struct CodedImageData
Expand Down Expand Up @@ -348,6 +350,12 @@ class ImageItem : public ErrorBuffer

const std::vector<Error>& get_decoding_warnings() const { return m_decoding_warnings; }

virtual heif_image_tiling get_heif_image_tiling() const;

Error process_image_transformations_on_tiling(heif_image_tiling&) const;

virtual std::shared_ptr<class Decoder> get_decoder() const { return nullptr; }

private:
HeifContext* m_heif_context;

Expand Down Expand Up @@ -405,8 +413,6 @@ class ImageItem : public ErrorBuffer
enum heif_image_input_class input_class,
const heif_color_profile_nclx* target_heif_nclx,
ImageItem::CodedImageData& inout_codedImage);

virtual std::shared_ptr<class Decoder> get_decoder() const { return nullptr; }
};


Expand Down
2 changes: 1 addition & 1 deletion libheif/image-items/tild.cc
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,7 @@ heif_image_tiling ImageItem_Tild::get_heif_image_tiling() const
tiling.image_height = m_tild_header.get_parameters().image_height;
tiling.number_of_extra_dimensions = m_tild_header.get_parameters().number_of_extra_dimensions;
for (int i = 0; i < std::min(tiling.number_of_extra_dimensions, uint8_t(8)); i++) {
tiling.extra_dimensions[i] = m_tild_header.get_parameters().extra_dimensions[i];
tiling.extra_dimension_size[i] = m_tild_header.get_parameters().extra_dimensions[i];
}

return tiling;
Expand Down
2 changes: 1 addition & 1 deletion libheif/image-items/tild.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ class ImageItem_Tild : public ImageItem

void set_next_tild_position(uint64_t pos) { m_next_tild_position = pos; }

heif_image_tiling get_heif_image_tiling() const;
heif_image_tiling get_heif_image_tiling() const override;

void get_tile_size(uint32_t& w, uint32_t& h) const override;

Expand Down
2 changes: 1 addition & 1 deletion libheif/image-items/unc_image.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class ImageItem_uncompressed : public ImageItem
Result<std::shared_ptr<HeifPixelImage>> decode_compressed_image(const struct heif_decoding_options& options,
bool decode_tile_only, uint32_t tile_x0, uint32_t tile_y0) const override;

heif_image_tiling get_heif_image_tiling() const;
heif_image_tiling get_heif_image_tiling() const override;

Error on_load_file() override;

Expand Down
2 changes: 1 addition & 1 deletion libheif/region.cc
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,7 @@ RegionCoordinateTransform RegionCoordinateTransform::create(std::shared_ptr<Heif
case fourcc("irot"): {
auto irot = std::dynamic_pointer_cast<Box_irot>(property);
RegionCoordinateTransform tmp;
switch (irot->get_rotation()) {
switch (irot->get_rotation_ccw()) {
case 90:
tmp.a = transform.c;
tmp.b = transform.d;
Expand Down

0 comments on commit e18ac58

Please sign in to comment.