Skip to content

Commit

Permalink
initial support for special HEIF metadata
Browse files Browse the repository at this point in the history
Signed-off-by: Alexander Piskun <[email protected]>
  • Loading branch information
bigcat88 committed Jul 26, 2024
1 parent 48a9760 commit ee3b5ad
Show file tree
Hide file tree
Showing 11 changed files with 268 additions and 24 deletions.
8 changes: 6 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
All notable changes to this project will be documented in this file.

## [0.18.0 - 2024-0x-xx]
## [0.18.0 - 2024-07-27]

### Added

- `image.info["heif"]` dictionary with `camera_intrinsic_matrix` HEIF specific metadata. Currently only reading is supported. #234

### Changed

- libheif updated from `1.17.6` to `1.18.1` version.
- libheif updated from `1.17.6` to `1.18.1` version. #249

## [0.17.0 - 2024-07-02]

Expand Down
8 changes: 4 additions & 4 deletions LICENSES_bundled.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ Binary wheels combine several license-compatible libraries. Here they are listed
Name: libheif
License: LGPLv3
Files: libheif.[dylib|so|dll]
For details, see https://github.com/strukturag/libheif/tree/v1.17.3/COPYING
Source code: https://github.com/strukturag/libheif/tree/v1.17.3
For details, see https://github.com/strukturag/libheif/tree/v1.18.1/COPYING
Source code: https://github.com/strukturag/libheif/tree/v1.18.1

Name: libde265
License: LGPLv3
Files: libde265.[dylib|so|dll]
For details, see https://github.com/strukturag/libde265/tree/v1.0.12/COPYING
Source code: https://github.com/strukturag/libde265/tree/v1.0.12
For details, see https://github.com/strukturag/libde265/tree/v1.0.15/COPYING
Source code: https://github.com/strukturag/libde265/tree/v1.0.15

Name: x265
License: GPLv2
Expand Down
140 changes: 131 additions & 9 deletions libheif/heif.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ extern "C" {
#include <stdint.h>

//#include <libheif/heif_version.h>
#define LIBHEIF_NUMERIC_VERSION ((1<<24) | (17<<16) | (6<<8) | 0)
#define LIBHEIF_NUMERIC_VERSION ((1<<24) | (18<<16) | (1<<8) | 0)

// API versions table
//
Expand Down Expand Up @@ -232,6 +232,23 @@ enum heif_suberror_code
// Invalid specification of region item
heif_suberror_Invalid_region_data = 136,

// Image has no ispe property
heif_suberror_No_ispe_property = 137,

heif_suberror_Camera_intrinsic_matrix_undefined = 138,

heif_suberror_Camera_extrinsic_matrix_undefined = 139,

// Invalid JPEG 2000 codestream - usually a missing marker
heif_suberror_Invalid_J2K_codestream = 140,

heif_suberror_No_vvcC_box = 141,

// icbr is only needed in some situations, this error is for those cases
heif_suberror_No_icbr_box = 142,

// Decompressing generic compression or header compression data failed (e.g. bitstream corruption)
heif_suberror_Decompression_invalid_data = 150,

// --- Memory_allocation_error ---

Expand All @@ -240,6 +257,9 @@ enum heif_suberror_code
// security limits further.
heif_suberror_Security_limit_exceeded = 1000,

// There was an error from the underlying compression / decompression library.
// One possibility is lack of resources (e.g. memory).
heif_suberror_Compression_initialisation_error = 1001,

// --- Usage_error ---

Expand Down Expand Up @@ -288,6 +308,8 @@ enum heif_suberror_code

heif_suberror_Unsupported_header_compression_method = 3005,

// Generically compressed data used an unsupported compression method
heif_suberror_Unsupported_generic_compression_method = 3006,

// --- Encoder_plugin_error ---

Expand All @@ -307,9 +329,10 @@ enum heif_suberror_code

// --- Plugin loading error ---

heif_suberror_Plugin_loading_error = 6000, // a specific plugin file cannot be loaded
heif_suberror_Plugin_is_not_loaded = 6001, // trying to remove a plugin that is not loaded
heif_suberror_Cannot_read_plugin_directory = 6002 // error while scanning the directory for plugins
heif_suberror_Plugin_loading_error = 6000, // a specific plugin file cannot be loaded
heif_suberror_Plugin_is_not_loaded = 6001, // trying to remove a plugin that is not loaded
heif_suberror_Cannot_read_plugin_directory = 6002, // error while scanning the directory for plugins
heif_suberror_No_matching_decoder_installed = 6003 // no decoder found for that compression format
};


Expand Down Expand Up @@ -411,7 +434,14 @@ enum heif_compression_format
*
* See ISO/IEC 23008-12:2022 Section 6.10.2
*/
heif_compression_mask = 9
heif_compression_mask = 9,
/**
* High Throughput JPEG 2000 (HT-J2K) compression.
*
* The encapsulation of HT-J2K is specified in ISO/IEC 15444-16:2021.
* The core encoding is defined in ISO/IEC 15444-15, or ITU-T T.814.
*/
heif_compression_HTJ2K = 10
};

enum heif_chroma
Expand Down Expand Up @@ -567,6 +597,18 @@ enum heif_filetype_result
LIBHEIF_API
enum heif_filetype_result heif_check_filetype(const uint8_t* data, int len);

/**
* Check the filetype box content for a supported file type.
*
* <p>The data is assumed to start from the start of the `ftyp` box.
*
* <p>This function checks the compatible brands.
*
* @returns heif_error_ok if a supported brand is found, or other error if not.
*/
LIBHEIF_API
struct heif_error heif_has_compatible_filetype(const uint8_t* data, int len);

LIBHEIF_API
int heif_check_jpeg_filetype(const uint8_t* data, int len);

Expand Down Expand Up @@ -1371,6 +1413,44 @@ struct heif_error heif_image_get_nclx_color_profile(const struct heif_image* ima
struct heif_color_profile_nclx** out_data);


// ------------------------- intrinsic and extrinsic matrices -------------------------

struct heif_camera_intrinsic_matrix
{
double focal_length_x;
double focal_length_y;
double principal_point_x;
double principal_point_y;
double skew;
};


LIBHEIF_API
int heif_image_handle_has_camera_intrinsic_matrix(const struct heif_image_handle* handle);

LIBHEIF_API
struct heif_error heif_image_handle_get_camera_intrinsic_matrix(const struct heif_image_handle* handle,
struct heif_camera_intrinsic_matrix* out_matrix);


struct heif_camera_extrinsic_matrix;

LIBHEIF_API
int heif_image_handle_has_camera_extrinsic_matrix(const struct heif_image_handle* handle);

LIBHEIF_API
struct heif_error heif_image_handle_get_camera_extrinsic_matrix(const struct heif_image_handle* handle,
struct heif_camera_extrinsic_matrix** out_matrix);

LIBHEIF_API
void heif_camera_extrinsic_matrix_release(struct heif_camera_extrinsic_matrix*);

LIBHEIF_API
struct heif_error heif_camera_extrinsic_matrix_get_rotation_matrix(const struct heif_camera_extrinsic_matrix*,
double* out_matrix_row_major);



// ========================= heif_image =========================

// An heif_image contains a decoded pixel image in various colorspaces, chroma formats,
Expand Down Expand Up @@ -1714,6 +1794,10 @@ struct heif_error heif_context_write(struct heif_context*,
struct heif_writer* writer,
void* userdata);

// Add a compatible brand that is now added automatically by libheif when encoding images (e.g. some application brands like 'geo1').
LIBHEIF_API
void heif_context_add_compatible_brand(struct heif_context* ctx,
heif_brand2 compatible_brand);

// ----- encoder -----

Expand Down Expand Up @@ -1904,7 +1988,7 @@ struct heif_error heif_encoder_get_parameter_integer(struct heif_encoder*,
const char* parameter_name,
int* value);

// TOD-O: name should be changed to heif_encoder_get_valid_integer_parameter_range
// TO-DO: name should be changed to heif_encoder_get_valid_integer_parameter_range
LIBHEIF_API // DEPRECATED.
struct heif_error heif_encoder_parameter_integer_valid_range(struct heif_encoder*,
const char* parameter_name,
Expand Down Expand Up @@ -2019,6 +2103,11 @@ struct heif_encoding_options
// version 6 options

struct heif_color_conversion_options color_conversion_options;

// version 7 options

// Set this to true to use compressed form of uncC where possible
uint8_t prefer_uncC_short_form;
};

LIBHEIF_API
Expand All @@ -2040,6 +2129,27 @@ struct heif_error heif_context_encode_image(struct heif_context*,
const struct heif_encoding_options* options,
struct heif_image_handle** out_image_handle);

/**
* @brief Encodes an array of images into a grid.
*
* @param ctx The file context
* @param tiles User allocated array of images that will form the grid.
* @param rows The number of rows in the grid.
* @param columns The number of columns in the grid.
* @param encoder Defines the encoder to use. See heif_context_get_encoder_for_format()
* @param input_options Optional, may be nullptr.
* @param out_image_handle Returns a handle to the grid. The caller is responsible for freeing it.
* @return Returns an error if ctx, tiles, or encoder is nullptr. If rows or columns is 0.
*/
LIBHEIF_API
struct heif_error heif_context_encode_grid(struct heif_context* ctx,
struct heif_image** tiles,
uint16_t rows,
uint16_t columns,
struct heif_encoder* encoder,
const struct heif_encoding_options* input_options,
struct heif_image_handle** out_image_handle);

LIBHEIF_API
struct heif_error heif_context_set_primary_image(struct heif_context*,
struct heif_image_handle* image_handle);
Expand All @@ -2062,9 +2172,12 @@ struct heif_error heif_context_encode_thumbnail(struct heif_context*,

enum heif_metadata_compression
{
heif_metadata_compression_off,
heif_metadata_compression_auto,
heif_metadata_compression_deflate
heif_metadata_compression_off = 0,
heif_metadata_compression_auto = 1,
heif_metadata_compression_unknown = 2, // only used when reading unknown method from input file
heif_metadata_compression_deflate = 3,
heif_metadata_compression_zlib = 4, // do not use for header data
heif_metadata_compression_brotli = 5
};

// Assign 'thumbnail_image' as the thumbnail image of 'master_image'.
Expand Down Expand Up @@ -2102,6 +2215,15 @@ struct heif_error heif_context_add_generic_metadata(struct heif_context* ctx,
const void* data, int size,
const char* item_type, const char* content_type);

// Add generic metadata with item_type "uri ". Items with this type do not have a content_type, but
// an item_uri_type and they have no content_encoding (they are always stored uncompressed).
LIBHEIF_API
struct heif_error heif_context_add_generic_uri_metadata(struct heif_context* ctx,
const struct heif_image_handle* image_handle,
const void* data, int size,
const char* item_uri_type,
heif_item_id* out_item_id);

// --- heif_image allocation

/**
Expand Down
8 changes: 4 additions & 4 deletions pi-heif/LICENSES_bundled.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ Binary wheels combine several license-compatible libraries. Here they are listed
Name: libheif
License: LGPLv3
Files: libheif.[dylib|so|dll]
For details, see https://github.com/strukturag/libheif/tree/v1.17.3/COPYING
Source code: https://github.com/strukturag/libheif/tree/v1.17.3
For details, see https://github.com/strukturag/libheif/tree/v1.18.1/COPYING
Source code: https://github.com/strukturag/libheif/tree/v1.18.1

Name: libde265
License: LGPLv3
Files: libde265.[dylib|so|dll]
For details, see https://github.com/strukturag/libde265/tree/v1.0.12/COPYING
Source code: https://github.com/strukturag/libde265/tree/v1.0.12
For details, see https://github.com/strukturag/libde265/tree/v1.0.15/COPYING
Source code: https://github.com/strukturag/libde265/tree/v1.0.15
52 changes: 52 additions & 0 deletions pillow_heif/_pillow_heif.c
Original file line number Diff line number Diff line change
Expand Up @@ -1183,6 +1183,56 @@ static PyObject* _CtxImage_depth_image_list(CtxImageObject* self, void* closure)
return images_list;
}

/* =========== CtxImage Experimental Part ======== */

static PyObject* _CtxImage_camera_intrinsic_matrix(CtxImageObject* self, void* closure) {
#if LIBHEIF_HAVE_VERSION(1,18,0)
struct heif_camera_intrinsic_matrix camera_intrinsic_matrix;

if (!heif_image_handle_has_camera_intrinsic_matrix(self->handle)) {
Py_RETURN_NONE;
}
if (check_error(heif_image_handle_get_camera_intrinsic_matrix(self->handle, &camera_intrinsic_matrix))) {
Py_RETURN_NONE;
}
return Py_BuildValue(
"(ddddd)",
camera_intrinsic_matrix.focal_length_x,
camera_intrinsic_matrix.focal_length_y,
camera_intrinsic_matrix.principal_point_x,
camera_intrinsic_matrix.principal_point_y,
camera_intrinsic_matrix.skew
);
#else
Py_RETURN_NONE;
#endif
}

static PyObject* _CtxImage_camera_extrinsic_matrix_rot(CtxImageObject* self, void* closure) {
#if LIBHEIF_HAVE_VERSION(1,18,0)
struct heif_camera_extrinsic_matrix* camera_extrinsic_matrix;
double rot[9];
struct heif_error error;

if (!heif_image_handle_has_camera_extrinsic_matrix(self->handle)) {
Py_RETURN_NONE;
}
if (check_error(heif_image_handle_get_camera_extrinsic_matrix(self->handle, &camera_extrinsic_matrix))) {
Py_RETURN_NONE;
}
error = heif_camera_extrinsic_matrix_get_rotation_matrix(camera_extrinsic_matrix, rot);
heif_camera_extrinsic_matrix_release(camera_extrinsic_matrix);
if (check_error(error)) {
Py_RETURN_NONE;
}
return Py_BuildValue("(ddddddddd)", rot[0], rot[1], rot[2], rot[3], rot[4], rot[5], rot[6], rot[7], rot[8]);
#else
Py_RETURN_NONE;
#endif
}

/* =========== CtxImage properties available to Python Part ======== */

static struct PyGetSetDef _CtxImage_getseters[] = {
{"size_mode", (getter)_CtxImage_size_mode, NULL, NULL, NULL},
{"primary", (getter)_CtxImage_primary, NULL, NULL, NULL},
Expand All @@ -1195,6 +1245,8 @@ static struct PyGetSetDef _CtxImage_getseters[] = {
{"stride", (getter)_CtxImage_stride, NULL, NULL, NULL},
{"data", (getter)_CtxImage_data, NULL, NULL, NULL},
{"depth_image_list", (getter)_CtxImage_depth_image_list, NULL, NULL, NULL},
{"camera_intrinsic_matrix", (getter)_CtxImage_camera_intrinsic_matrix, NULL, NULL, NULL},
{"camera_extrinsic_matrix_rot", (getter)_CtxImage_camera_extrinsic_matrix_rot, NULL, NULL, NULL},
{NULL, NULL, NULL, NULL, NULL}
};

Expand Down
2 changes: 1 addition & 1 deletion pillow_heif/_version.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""Version of pillow_heif/pi_heif."""

__version__ = "0.17.0"
__version__ = "0.18.0.dev0"
4 changes: 4 additions & 0 deletions pillow_heif/heif.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
MimCImage,
_exif_from_pillow,
_get_bytes,
_get_heif_meta,
_get_orientation_for_encoder,
_get_primary_index,
_pil_to_supported_mode,
Expand Down Expand Up @@ -151,6 +152,7 @@ def __init__(self, c_image):
_depth_images: List[Optional[HeifDepthImage]] = (
[HeifDepthImage(i) for i in c_image.depth_image_list if i is not None] if options.DEPTH_IMAGES else []
)
_heif_meta = _get_heif_meta(c_image)
self.info = {
"primary": bool(c_image.primary),
"bit_depth": int(c_image.bit_depth),
Expand All @@ -161,6 +163,8 @@ def __init__(self, c_image):
}
if _xmp:
self.info["xmp"] = _xmp
if _heif_meta:
self.info["heif"] = _heif_meta
save_colorspace_chroma(c_image, self.info)
_color_profile: Dict[str, Any] = c_image.color_profile
if _color_profile:
Expand Down
Loading

0 comments on commit ee3b5ad

Please sign in to comment.