Skip to content

Commit 91fe62c

Browse files
committed
initial support for special HEIF metadata
Signed-off-by: Alexander Piskun <[email protected]>
1 parent 48a9760 commit 91fe62c

File tree

10 files changed

+266
-20
lines changed

10 files changed

+266
-20
lines changed

CHANGELOG.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
All notable changes to this project will be documented in this file.
22

3-
## [0.18.0 - 2024-0x-xx]
3+
## [0.18.0 - 2024-07-27]
4+
5+
### Added
6+
7+
- `image.info["heif"]` dictionary with `camera_intrinsic_matrix` HEIF specific metadata. Currently only reading is supported. #234
48

59
### Changed
610

7-
- libheif updated from `1.17.6` to `1.18.1` version.
11+
- libheif updated from `1.17.6` to `1.18.1` version. #249
812

913
## [0.17.0 - 2024-07-02]
1014

LICENSES_bundled.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ Binary wheels combine several license-compatible libraries. Here they are listed
55
Name: libheif
66
License: LGPLv3
77
Files: libheif.[dylib|so|dll]
8-
For details, see https://github.com/strukturag/libheif/tree/v1.17.3/COPYING
9-
Source code: https://github.com/strukturag/libheif/tree/v1.17.3
8+
For details, see https://github.com/strukturag/libheif/tree/v1.18.1/COPYING
9+
Source code: https://github.com/strukturag/libheif/tree/v1.18.1
1010

1111
Name: libde265
1212
License: LGPLv3
1313
Files: libde265.[dylib|so|dll]
14-
For details, see https://github.com/strukturag/libde265/tree/v1.0.12/COPYING
15-
Source code: https://github.com/strukturag/libde265/tree/v1.0.12
14+
For details, see https://github.com/strukturag/libde265/tree/v1.0.15/COPYING
15+
Source code: https://github.com/strukturag/libde265/tree/v1.0.15
1616

1717
Name: x265
1818
License: GPLv2

libheif/heif.h

Lines changed: 131 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ extern "C" {
3737
#include <stdint.h>
3838

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

4242
// API versions table
4343
//
@@ -232,6 +232,23 @@ enum heif_suberror_code
232232
// Invalid specification of region item
233233
heif_suberror_Invalid_region_data = 136,
234234

235+
// Image has no ispe property
236+
heif_suberror_No_ispe_property = 137,
237+
238+
heif_suberror_Camera_intrinsic_matrix_undefined = 138,
239+
240+
heif_suberror_Camera_extrinsic_matrix_undefined = 139,
241+
242+
// Invalid JPEG 2000 codestream - usually a missing marker
243+
heif_suberror_Invalid_J2K_codestream = 140,
244+
245+
heif_suberror_No_vvcC_box = 141,
246+
247+
// icbr is only needed in some situations, this error is for those cases
248+
heif_suberror_No_icbr_box = 142,
249+
250+
// Decompressing generic compression or header compression data failed (e.g. bitstream corruption)
251+
heif_suberror_Decompression_invalid_data = 150,
235252

236253
// --- Memory_allocation_error ---
237254

@@ -240,6 +257,9 @@ enum heif_suberror_code
240257
// security limits further.
241258
heif_suberror_Security_limit_exceeded = 1000,
242259

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

244264
// --- Usage_error ---
245265

@@ -288,6 +308,8 @@ enum heif_suberror_code
288308

289309
heif_suberror_Unsupported_header_compression_method = 3005,
290310

311+
// Generically compressed data used an unsupported compression method
312+
heif_suberror_Unsupported_generic_compression_method = 3006,
291313

292314
// --- Encoder_plugin_error ---
293315

@@ -307,9 +329,10 @@ enum heif_suberror_code
307329

308330
// --- Plugin loading error ---
309331

310-
heif_suberror_Plugin_loading_error = 6000, // a specific plugin file cannot be loaded
311-
heif_suberror_Plugin_is_not_loaded = 6001, // trying to remove a plugin that is not loaded
312-
heif_suberror_Cannot_read_plugin_directory = 6002 // error while scanning the directory for plugins
332+
heif_suberror_Plugin_loading_error = 6000, // a specific plugin file cannot be loaded
333+
heif_suberror_Plugin_is_not_loaded = 6001, // trying to remove a plugin that is not loaded
334+
heif_suberror_Cannot_read_plugin_directory = 6002, // error while scanning the directory for plugins
335+
heif_suberror_No_matching_decoder_installed = 6003 // no decoder found for that compression format
313336
};
314337

315338

@@ -411,7 +434,14 @@ enum heif_compression_format
411434
*
412435
* See ISO/IEC 23008-12:2022 Section 6.10.2
413436
*/
414-
heif_compression_mask = 9
437+
heif_compression_mask = 9,
438+
/**
439+
* High Throughput JPEG 2000 (HT-J2K) compression.
440+
*
441+
* The encapsulation of HT-J2K is specified in ISO/IEC 15444-16:2021.
442+
* The core encoding is defined in ISO/IEC 15444-15, or ITU-T T.814.
443+
*/
444+
heif_compression_HTJ2K = 10
415445
};
416446

417447
enum heif_chroma
@@ -567,6 +597,18 @@ enum heif_filetype_result
567597
LIBHEIF_API
568598
enum heif_filetype_result heif_check_filetype(const uint8_t* data, int len);
569599

600+
/**
601+
* Check the filetype box content for a supported file type.
602+
*
603+
* <p>The data is assumed to start from the start of the `ftyp` box.
604+
*
605+
* <p>This function checks the compatible brands.
606+
*
607+
* @returns heif_error_ok if a supported brand is found, or other error if not.
608+
*/
609+
LIBHEIF_API
610+
struct heif_error heif_has_compatible_filetype(const uint8_t* data, int len);
611+
570612
LIBHEIF_API
571613
int heif_check_jpeg_filetype(const uint8_t* data, int len);
572614

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

13731415

1416+
// ------------------------- intrinsic and extrinsic matrices -------------------------
1417+
1418+
struct heif_camera_intrinsic_matrix
1419+
{
1420+
double focal_length_x;
1421+
double focal_length_y;
1422+
double principal_point_x;
1423+
double principal_point_y;
1424+
double skew;
1425+
};
1426+
1427+
1428+
LIBHEIF_API
1429+
int heif_image_handle_has_camera_intrinsic_matrix(const struct heif_image_handle* handle);
1430+
1431+
LIBHEIF_API
1432+
struct heif_error heif_image_handle_get_camera_intrinsic_matrix(const struct heif_image_handle* handle,
1433+
struct heif_camera_intrinsic_matrix* out_matrix);
1434+
1435+
1436+
struct heif_camera_extrinsic_matrix;
1437+
1438+
LIBHEIF_API
1439+
int heif_image_handle_has_camera_extrinsic_matrix(const struct heif_image_handle* handle);
1440+
1441+
LIBHEIF_API
1442+
struct heif_error heif_image_handle_get_camera_extrinsic_matrix(const struct heif_image_handle* handle,
1443+
struct heif_camera_extrinsic_matrix** out_matrix);
1444+
1445+
LIBHEIF_API
1446+
void heif_camera_extrinsic_matrix_release(struct heif_camera_extrinsic_matrix*);
1447+
1448+
LIBHEIF_API
1449+
struct heif_error heif_camera_extrinsic_matrix_get_rotation_matrix(const struct heif_camera_extrinsic_matrix*,
1450+
double* out_matrix_row_major);
1451+
1452+
1453+
13741454
// ========================= heif_image =========================
13751455

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

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

17181802
// ----- encoder -----
17191803

@@ -1904,7 +1988,7 @@ struct heif_error heif_encoder_get_parameter_integer(struct heif_encoder*,
19041988
const char* parameter_name,
19051989
int* value);
19061990

1907-
// TOD-O: name should be changed to heif_encoder_get_valid_integer_parameter_range
1991+
// TO-DO: name should be changed to heif_encoder_get_valid_integer_parameter_range
19081992
LIBHEIF_API // DEPRECATED.
19091993
struct heif_error heif_encoder_parameter_integer_valid_range(struct heif_encoder*,
19101994
const char* parameter_name,
@@ -2019,6 +2103,11 @@ struct heif_encoding_options
20192103
// version 6 options
20202104

20212105
struct heif_color_conversion_options color_conversion_options;
2106+
2107+
// version 7 options
2108+
2109+
// Set this to true to use compressed form of uncC where possible
2110+
uint8_t prefer_uncC_short_form;
20222111
};
20232112

20242113
LIBHEIF_API
@@ -2040,6 +2129,27 @@ struct heif_error heif_context_encode_image(struct heif_context*,
20402129
const struct heif_encoding_options* options,
20412130
struct heif_image_handle** out_image_handle);
20422131

2132+
/**
2133+
* @brief Encodes an array of images into a grid.
2134+
*
2135+
* @param ctx The file context
2136+
* @param tiles User allocated array of images that will form the grid.
2137+
* @param rows The number of rows in the grid.
2138+
* @param columns The number of columns in the grid.
2139+
* @param encoder Defines the encoder to use. See heif_context_get_encoder_for_format()
2140+
* @param input_options Optional, may be nullptr.
2141+
* @param out_image_handle Returns a handle to the grid. The caller is responsible for freeing it.
2142+
* @return Returns an error if ctx, tiles, or encoder is nullptr. If rows or columns is 0.
2143+
*/
2144+
LIBHEIF_API
2145+
struct heif_error heif_context_encode_grid(struct heif_context* ctx,
2146+
struct heif_image** tiles,
2147+
uint16_t rows,
2148+
uint16_t columns,
2149+
struct heif_encoder* encoder,
2150+
const struct heif_encoding_options* input_options,
2151+
struct heif_image_handle** out_image_handle);
2152+
20432153
LIBHEIF_API
20442154
struct heif_error heif_context_set_primary_image(struct heif_context*,
20452155
struct heif_image_handle* image_handle);
@@ -2062,9 +2172,12 @@ struct heif_error heif_context_encode_thumbnail(struct heif_context*,
20622172

20632173
enum heif_metadata_compression
20642174
{
2065-
heif_metadata_compression_off,
2066-
heif_metadata_compression_auto,
2067-
heif_metadata_compression_deflate
2175+
heif_metadata_compression_off = 0,
2176+
heif_metadata_compression_auto = 1,
2177+
heif_metadata_compression_unknown = 2, // only used when reading unknown method from input file
2178+
heif_metadata_compression_deflate = 3,
2179+
heif_metadata_compression_zlib = 4, // do not use for header data
2180+
heif_metadata_compression_brotli = 5
20682181
};
20692182

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

2218+
// Add generic metadata with item_type "uri ". Items with this type do not have a content_type, but
2219+
// an item_uri_type and they have no content_encoding (they are always stored uncompressed).
2220+
LIBHEIF_API
2221+
struct heif_error heif_context_add_generic_uri_metadata(struct heif_context* ctx,
2222+
const struct heif_image_handle* image_handle,
2223+
const void* data, int size,
2224+
const char* item_uri_type,
2225+
heif_item_id* out_item_id);
2226+
21052227
// --- heif_image allocation
21062228

21072229
/**

pi-heif/LICENSES_bundled.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ Binary wheels combine several license-compatible libraries. Here they are listed
55
Name: libheif
66
License: LGPLv3
77
Files: libheif.[dylib|so|dll]
8-
For details, see https://github.com/strukturag/libheif/tree/v1.17.3/COPYING
9-
Source code: https://github.com/strukturag/libheif/tree/v1.17.3
8+
For details, see https://github.com/strukturag/libheif/tree/v1.18.1/COPYING
9+
Source code: https://github.com/strukturag/libheif/tree/v1.18.1
1010

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

pillow_heif/_pillow_heif.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,6 +1183,56 @@ static PyObject* _CtxImage_depth_image_list(CtxImageObject* self, void* closure)
11831183
return images_list;
11841184
}
11851185

1186+
/* =========== CtxImage Experimental Part ======== */
1187+
1188+
static PyObject* _CtxImage_camera_intrinsic_matrix(CtxImageObject* self, void* closure) {
1189+
#if LIBHEIF_HAVE_VERSION(1,18,0)
1190+
struct heif_camera_intrinsic_matrix camera_intrinsic_matrix;
1191+
1192+
if (!heif_image_handle_has_camera_intrinsic_matrix(self->handle)) {
1193+
Py_RETURN_NONE;
1194+
}
1195+
if (check_error(heif_image_handle_get_camera_intrinsic_matrix(self->handle, &camera_intrinsic_matrix))) {
1196+
Py_RETURN_NONE;
1197+
}
1198+
return Py_BuildValue(
1199+
"(ddddd)",
1200+
camera_intrinsic_matrix.focal_length_x,
1201+
camera_intrinsic_matrix.focal_length_y,
1202+
camera_intrinsic_matrix.principal_point_x,
1203+
camera_intrinsic_matrix.principal_point_y,
1204+
camera_intrinsic_matrix.skew
1205+
);
1206+
#else
1207+
Py_RETURN_NONE;
1208+
#endif
1209+
}
1210+
1211+
static PyObject* _CtxImage_camera_extrinsic_matrix_rot(CtxImageObject* self, void* closure) {
1212+
#if LIBHEIF_HAVE_VERSION(1,18,0)
1213+
struct heif_camera_extrinsic_matrix* camera_extrinsic_matrix;
1214+
double rot[9];
1215+
struct heif_error error;
1216+
1217+
if (!heif_image_handle_has_camera_extrinsic_matrix(self->handle)) {
1218+
Py_RETURN_NONE;
1219+
}
1220+
if (check_error(heif_image_handle_get_camera_extrinsic_matrix(self->handle, &camera_extrinsic_matrix))) {
1221+
Py_RETURN_NONE;
1222+
}
1223+
error = heif_camera_extrinsic_matrix_get_rotation_matrix(camera_extrinsic_matrix, rot);
1224+
heif_camera_extrinsic_matrix_release(camera_extrinsic_matrix);
1225+
if (check_error(error)) {
1226+
Py_RETURN_NONE;
1227+
}
1228+
return Py_BuildValue("(ddddddddd)", rot[0], rot[1], rot[2], rot[3], rot[4], rot[5], rot[6], rot[7], rot[8]);
1229+
#else
1230+
Py_RETURN_NONE;
1231+
#endif
1232+
}
1233+
1234+
/* =========== CtxImage properties available to Python Part ======== */
1235+
11861236
static struct PyGetSetDef _CtxImage_getseters[] = {
11871237
{"size_mode", (getter)_CtxImage_size_mode, NULL, NULL, NULL},
11881238
{"primary", (getter)_CtxImage_primary, NULL, NULL, NULL},
@@ -1195,6 +1245,8 @@ static struct PyGetSetDef _CtxImage_getseters[] = {
11951245
{"stride", (getter)_CtxImage_stride, NULL, NULL, NULL},
11961246
{"data", (getter)_CtxImage_data, NULL, NULL, NULL},
11971247
{"depth_image_list", (getter)_CtxImage_depth_image_list, NULL, NULL, NULL},
1248+
{"camera_intrinsic_matrix", (getter)_CtxImage_camera_intrinsic_matrix, NULL, NULL, NULL},
1249+
{"camera_extrinsic_matrix_rot", (getter)_CtxImage_camera_extrinsic_matrix_rot, NULL, NULL, NULL},
11981250
{NULL, NULL, NULL, NULL, NULL}
11991251
};
12001252

pillow_heif/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
"""Version of pillow_heif/pi_heif."""
22

3-
__version__ = "0.17.0"
3+
__version__ = "0.18.0.dev0"

pillow_heif/heif.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
MimCImage,
1515
_exif_from_pillow,
1616
_get_bytes,
17+
_get_heif_meta,
1718
_get_orientation_for_encoder,
1819
_get_primary_index,
1920
_pil_to_supported_mode,
@@ -151,6 +152,7 @@ def __init__(self, c_image):
151152
_depth_images: List[Optional[HeifDepthImage]] = (
152153
[HeifDepthImage(i) for i in c_image.depth_image_list if i is not None] if options.DEPTH_IMAGES else []
153154
)
155+
_heif_meta = _get_heif_meta(c_image)
154156
self.info = {
155157
"primary": bool(c_image.primary),
156158
"bit_depth": int(c_image.bit_depth),
@@ -161,6 +163,8 @@ def __init__(self, c_image):
161163
}
162164
if _xmp:
163165
self.info["xmp"] = _xmp
166+
if _heif_meta:
167+
self.info["heif"] = _heif_meta
164168
save_colorspace_chroma(c_image, self.info)
165169
_color_profile: Dict[str, Any] = c_image.color_profile
166170
if _color_profile:

0 commit comments

Comments
 (0)