1 /*
2 * HEIF codec.
3 * Copyright (c) 2017 struktur AG, Dirk Farin <farin@struktur.de>
4 *
5 * This file is part of libheif.
6 *
7 * libheif is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation, either version 3 of
10 * the License, or (at your option) any later version.
11 *
12 * libheif is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with libheif. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #if defined(HAVE_CONFIG_H)
22 #include "config.h"
23 #endif
24
25 #include "heif.h"
26 #include "heif_image.h"
27 #include "heif_api_structs.h"
28 #include "heif_context.h"
29 #include "heif_plugin_registry.h"
30 #include "error.h"
31 #include "bitstream.h"
32
33 #if defined(__EMSCRIPTEN__)
34 #include "heif_emscripten.h"
35 #endif
36
37 #include <algorithm>
38 #include <iostream>
39 #include <fstream>
40 #include <memory>
41 #include <string>
42 #include <utility>
43 #include <vector>
44 #include <string.h>
45 #if defined(HAVE_UNISTD_H)
46 #include <unistd.h>
47 #endif
48
49 #if defined(_MSC_VER)
50 // for _write
51 #include <io.h>
52 #endif
53
54 using namespace heif;
55
56 static struct heif_error error_Ok = { heif_error_Ok, heif_suberror_Unspecified, kSuccess };
57 static struct heif_error error_unsupported_parameter = { heif_error_Usage_error,
58 heif_suberror_Unsupported_parameter,
59 "Unsupported encoder parameter" };
60 static struct heif_error error_unsupported_plugin_version = { heif_error_Usage_error,
61 heif_suberror_Unsupported_plugin_version,
62 "Unsupported plugin version" };
63 static struct heif_error error_null_parameter = { heif_error_Usage_error,
64 heif_suberror_Null_pointer_argument,
65 "NULL passed" };
66
heif_get_version(void)67 const char *heif_get_version(void) {
68 return (LIBHEIF_VERSION);
69 }
70
heif_get_version_number(void)71 uint32_t heif_get_version_number(void) {
72 return (LIBHEIF_NUMERIC_VERSION);
73 }
74
heif_get_version_number_major(void)75 int heif_get_version_number_major(void) {
76 return ((LIBHEIF_NUMERIC_VERSION)>>24) & 0xFF;
77 }
78
heif_get_version_number_minor(void)79 int heif_get_version_number_minor(void) {
80 return ((LIBHEIF_NUMERIC_VERSION)>>16) & 0xFF;
81 }
82
heif_get_version_number_maintenance(void)83 int heif_get_version_number_maintenance(void) {
84 return ((LIBHEIF_NUMERIC_VERSION)>>8) & 0xFF;
85 }
86
87
heif_check_filetype(const uint8_t * data,int len)88 heif_filetype_result heif_check_filetype(const uint8_t* data, int len)
89 {
90 if (len<8) {
91 return heif_filetype_maybe;
92 }
93
94 if (data[4] != 'f' ||
95 data[5] != 't' ||
96 data[6] != 'y' ||
97 data[7] != 'p') {
98 return heif_filetype_no;
99 }
100
101 if (len>=12) {
102 heif_brand brand = heif_main_brand(data, len);
103
104 if (brand == heif_heic) {
105 return heif_filetype_yes_supported;
106 }
107 else if (brand == heif_heix) {
108 return heif_filetype_yes_supported;
109 }
110 else if (brand == heif_unknown_brand) {
111 return heif_filetype_no;
112 }
113 else if (brand == heif_mif1) {
114 return heif_filetype_maybe;
115 }
116 else {
117 return heif_filetype_yes_unsupported;
118 }
119 }
120
121 return heif_filetype_maybe;
122 }
123
124
heif_main_brand(const uint8_t * data,int len)125 heif_brand heif_main_brand(const uint8_t* data, int len)
126 {
127 if (len<12) {
128 return heif_unknown_brand;
129 }
130
131 char brand[5];
132 brand[0]=data[8];
133 brand[1]=data[9];
134 brand[2]=data[10];
135 brand[3]=data[11];
136 brand[4]=0;
137
138 if (strcmp(brand, "heic")==0) {
139 return heif_heic;
140 }
141 else if (strcmp(brand, "heix")==0) {
142 return heif_heix;
143 }
144 else if (strcmp(brand, "hevc")==0) {
145 return heif_hevc;
146 }
147 else if (strcmp(brand, "hevx")==0) {
148 return heif_hevx;
149 }
150 else if (strcmp(brand, "heim")==0) {
151 return heif_heim;
152 }
153 else if (strcmp(brand, "heis")==0) {
154 return heif_heis;
155 }
156 else if (strcmp(brand, "hevm")==0) {
157 return heif_hevm;
158 }
159 else if (strcmp(brand, "hevs")==0) {
160 return heif_hevs;
161 }
162 else if (strcmp(brand, "mif1")==0) {
163 return heif_mif1;
164 }
165 else if (strcmp(brand, "msf1")==0) {
166 return heif_msf1;
167 }
168 else {
169 return heif_unknown_brand;
170 }
171 }
172
173
174 enum class TriBool {
175 No, Yes, Unknown
176 };
177
is_jpeg(const uint8_t * data,int len)178 TriBool is_jpeg(const uint8_t* data, int len) {
179 if (len < 12) {
180 return TriBool::Unknown;
181 }
182
183 if (data[0] == 0xFF && data[1] == 0xD8 && data[2] == 0xFF && data[3] == 0xE0 &&
184 data[4] == 0x00 && data[5] == 0x10 && data[6] == 0x4A && data[7] == 0x46 &&
185 data[8] == 0x49 && data[9] == 0x46 && data[10] == 0x00 && data[11] == 0x01) {
186 return TriBool::Yes;
187 }
188 if (data[0] == 0xFF && data[1] == 0xD8 && data[2] == 0xFF && data[3] == 0xE1 &&
189 data[6] == 0x45 && data[7] == 0x78 && data[8] == 0x69 && data[9] == 0x66 &&
190 data[10] == 0x00 && data[11] == 0x00) {
191 return TriBool::Yes;
192 }
193 else {
194 return TriBool::No;
195 }
196 }
197
198
is_png(const uint8_t * data,int len)199 TriBool is_png(const uint8_t* data, int len) {
200 if (len < 8) {
201 return TriBool::Unknown;
202 }
203
204 if (data[0] == 0x89 && data[1]==0x50 && data[2]==0x4E && data[3]==0x47 &&
205 data[4] == 0x0D && data[5]==0x0A && data[6]==0x1A && data[7]==0x0A) {
206 return TriBool::Yes;
207 }
208 else {
209 return TriBool::No;
210 }
211 }
212
213
heif_get_file_mime_type(const uint8_t * data,int len)214 const char* heif_get_file_mime_type(const uint8_t* data, int len)
215 {
216 heif_brand mainBrand = heif_main_brand(data,len);
217
218 if (mainBrand == heif_heic ||
219 mainBrand == heif_heix ||
220 mainBrand == heif_heim ||
221 mainBrand == heif_heis) {
222 return "image/heic";
223 }
224 else if (mainBrand == heif_mif1) {
225 return "image/heif";
226 }
227 if (mainBrand == heif_hevc ||
228 mainBrand == heif_hevx ||
229 mainBrand == heif_hevm ||
230 mainBrand == heif_hevs) {
231 return "image/heic-sequence";
232 }
233 else if (mainBrand == heif_msf1) {
234 return "image/heif-sequence";
235 }
236 else if (is_jpeg(data,len)==TriBool::Yes) {
237 return "image/jpeg";
238 }
239 else if (is_png(data,len)==TriBool::Yes) {
240 return "image/png";
241 }
242 else {
243 return "";
244 }
245 }
246
247
heif_context_alloc()248 heif_context* heif_context_alloc()
249 {
250 struct heif_context* ctx = new heif_context;
251 ctx->context = std::make_shared<HeifContext>();
252
253 return ctx;
254 }
255
heif_context_free(heif_context * ctx)256 void heif_context_free(heif_context* ctx)
257 {
258 delete ctx;
259 }
260
heif_context_read_from_file(heif_context * ctx,const char * filename,const struct heif_reading_options *)261 heif_error heif_context_read_from_file(heif_context* ctx, const char* filename,
262 const struct heif_reading_options*)
263 {
264 Error err = ctx->context->read_from_file(filename);
265 return err.error_struct(ctx->context.get());
266 }
267
heif_context_read_from_memory(heif_context * ctx,const void * mem,size_t size,const struct heif_reading_options *)268 heif_error heif_context_read_from_memory(heif_context* ctx, const void* mem, size_t size,
269 const struct heif_reading_options*)
270 {
271 Error err = ctx->context->read_from_memory(mem, size, true);
272 return err.error_struct(ctx->context.get());
273 }
274
heif_context_read_from_memory_without_copy(heif_context * ctx,const void * mem,size_t size,const struct heif_reading_options *)275 heif_error heif_context_read_from_memory_without_copy(heif_context* ctx, const void* mem, size_t size,
276 const struct heif_reading_options*)
277 {
278 Error err = ctx->context->read_from_memory(mem, size, false);
279 return err.error_struct(ctx->context.get());
280 }
281
heif_context_read_from_reader(struct heif_context * ctx,const struct heif_reader * reader_func_table,void * userdata,const struct heif_reading_options *)282 heif_error heif_context_read_from_reader(struct heif_context* ctx,
283 const struct heif_reader* reader_func_table,
284 void* userdata,
285 const struct heif_reading_options*)
286 {
287 auto reader = std::make_shared<StreamReader_CApi>(reader_func_table, userdata);
288
289 Error err = ctx->context->read(reader);
290 return err.error_struct(ctx->context.get());
291 }
292
293 // TODO: heif_error heif_context_read_from_file_descriptor(heif_context*, int fd);
294
heif_context_debug_dump_boxes_to_file(struct heif_context * ctx,int fd)295 void heif_context_debug_dump_boxes_to_file(struct heif_context* ctx, int fd) {
296 if (!ctx) {
297 return;
298 }
299
300 std::string dump = ctx->context->debug_dump_boxes();
301 // TODO(fancycode): Should we return an error if writing fails?
302 #if defined(_MSC_VER)
303 auto written = _write(fd, dump.c_str(), dump.size());
304 #else
305 auto written = write(fd, dump.c_str(), dump.size());
306 #endif
307 (void) written;
308 }
309
heif_context_get_primary_image_handle(heif_context * ctx,heif_image_handle ** img)310 heif_error heif_context_get_primary_image_handle(heif_context* ctx, heif_image_handle** img)
311 {
312 if (!img) {
313 Error err(heif_error_Usage_error,
314 heif_suberror_Null_pointer_argument);
315 return err.error_struct(ctx->context.get());
316 }
317
318 std::shared_ptr<HeifContext::Image> primary_image = ctx->context->get_primary_image();
319
320 // It is a requirement of an HEIF file there is always a primary image.
321 // If there is none, an error is generated when loading the file.
322 if (!primary_image) {
323 Error err(heif_error_Invalid_input,
324 heif_suberror_No_or_invalid_primary_item);
325 return err.error_struct(ctx->context.get());
326 }
327
328 *img = new heif_image_handle();
329 (*img)->image = std::move(primary_image);
330 (*img)->context = ctx->context;
331
332 return Error::Ok.error_struct(ctx->context.get());
333 }
334
335
heif_context_get_primary_image_ID(struct heif_context * ctx,heif_item_id * id)336 struct heif_error heif_context_get_primary_image_ID(struct heif_context* ctx, heif_item_id* id)
337 {
338 if (!id) {
339 return Error(heif_error_Usage_error,
340 heif_suberror_Null_pointer_argument).error_struct(ctx->context.get());
341 }
342
343 std::shared_ptr<HeifContext::Image> primary = ctx->context->get_primary_image();
344 if (!primary) {
345 return Error(heif_error_Invalid_input,
346 heif_suberror_No_or_invalid_primary_item).error_struct(ctx->context.get());
347 }
348
349 *id = primary->get_id();
350
351 return Error::Ok.error_struct(ctx->context.get());
352 }
353
354
heif_context_is_top_level_image_ID(struct heif_context * ctx,heif_item_id id)355 int heif_context_is_top_level_image_ID(struct heif_context* ctx, heif_item_id id)
356 {
357 const std::vector<std::shared_ptr<HeifContext::Image>> images = ctx->context->get_top_level_images();
358
359 for (const auto& img : images) {
360 if (img->get_id() == id) {
361 return true;
362 }
363 }
364
365 return false;
366 }
367
368
heif_context_get_number_of_top_level_images(heif_context * ctx)369 int heif_context_get_number_of_top_level_images(heif_context* ctx)
370 {
371 return (int)ctx->context->get_top_level_images().size();
372 }
373
374
heif_context_get_list_of_top_level_image_IDs(struct heif_context * ctx,heif_item_id * ID_array,int count)375 int heif_context_get_list_of_top_level_image_IDs(struct heif_context* ctx,
376 heif_item_id* ID_array,
377 int count)
378 {
379 if (ID_array == nullptr || count==0 || ctx==nullptr) {
380 return 0;
381 }
382
383
384 // fill in ID values into output array
385
386 const std::vector<std::shared_ptr<HeifContext::Image>> imgs = ctx->context->get_top_level_images();
387 int n = (int)std::min(count,(int)imgs.size());
388 for (int i=0;i<n;i++) {
389 ID_array[i] = imgs[i]->get_id();
390 }
391
392 return n;
393 }
394
395
heif_context_get_image_handle(struct heif_context * ctx,heif_item_id id,struct heif_image_handle ** imgHdl)396 struct heif_error heif_context_get_image_handle(struct heif_context* ctx,
397 heif_item_id id,
398 struct heif_image_handle** imgHdl)
399 {
400 if (!imgHdl) {
401 Error err(heif_error_Usage_error,
402 heif_suberror_Null_pointer_argument);
403 return err.error_struct(ctx->context.get());
404 }
405
406 const std::vector<std::shared_ptr<HeifContext::Image>> images = ctx->context->get_top_level_images();
407
408 std::shared_ptr<HeifContext::Image> image;
409 for (auto& img : images) {
410 if (img->get_id() == id) {
411 image = img;
412 break;
413 }
414 }
415
416 if (!image) {
417 Error err(heif_error_Usage_error, heif_suberror_Nonexisting_item_referenced);
418 return err.error_struct(ctx->context.get());
419 }
420
421 *imgHdl = new heif_image_handle();
422 (*imgHdl)->image = image;
423 (*imgHdl)->context = ctx->context;
424
425 return Error::Ok.error_struct(ctx->context.get());
426 }
427
428
heif_image_handle_is_primary_image(const struct heif_image_handle * handle)429 int heif_image_handle_is_primary_image(const struct heif_image_handle* handle)
430 {
431 return handle->image->is_primary();
432 }
433
434
heif_image_handle_get_number_of_thumbnails(const struct heif_image_handle * handle)435 int heif_image_handle_get_number_of_thumbnails(const struct heif_image_handle* handle)
436 {
437 return (int)handle->image->get_thumbnails().size();
438 }
439
440
heif_image_handle_get_list_of_thumbnail_IDs(const struct heif_image_handle * handle,heif_item_id * ids,int count)441 int heif_image_handle_get_list_of_thumbnail_IDs(const struct heif_image_handle* handle,
442 heif_item_id* ids, int count)
443 {
444 if (ids==nullptr) {
445 return 0;
446 }
447
448 auto thumbnails = handle->image->get_thumbnails();
449 int n = (int)std::min(count, (int)thumbnails.size());
450
451 for (int i=0;i<n;i++) {
452 ids[i] = thumbnails[i]->get_id();
453 }
454
455 return n;
456 }
457
458
heif_image_handle_get_thumbnail(const struct heif_image_handle * handle,heif_item_id thumbnail_id,struct heif_image_handle ** out_thumbnail_handle)459 heif_error heif_image_handle_get_thumbnail(const struct heif_image_handle* handle,
460 heif_item_id thumbnail_id,
461 struct heif_image_handle** out_thumbnail_handle)
462 {
463 if (!out_thumbnail_handle) {
464 return Error(heif_error_Usage_error,
465 heif_suberror_Null_pointer_argument).error_struct(handle->image.get());
466 }
467
468 auto thumbnails = handle->image->get_thumbnails();
469 for (auto thumb : thumbnails) {
470 if (thumb->get_id() == thumbnail_id) {
471 *out_thumbnail_handle = new heif_image_handle();
472 (*out_thumbnail_handle)->image = thumb;
473 (*out_thumbnail_handle)->context = handle->context;
474
475 return Error::Ok.error_struct(handle->image.get());
476 }
477 }
478
479 Error err(heif_error_Usage_error, heif_suberror_Nonexisting_item_referenced);
480 return err.error_struct(handle->image.get());
481 }
482
483
heif_image_handle_get_width(const struct heif_image_handle * handle)484 int heif_image_handle_get_width(const struct heif_image_handle* handle)
485 {
486 if (handle && handle->image) {
487 return handle->image->get_width();
488 }
489 else {
490 return 0;
491 }
492 }
493
494
heif_image_handle_get_height(const struct heif_image_handle * handle)495 int heif_image_handle_get_height(const struct heif_image_handle* handle)
496 {
497 if (handle && handle->image) {
498 return handle->image->get_height();
499 }
500 else {
501 return 0;
502 }
503 }
504
505
heif_image_handle_get_ispe_width(const struct heif_image_handle * handle)506 int heif_image_handle_get_ispe_width(const struct heif_image_handle* handle)
507 {
508 if (handle && handle->image) {
509 return handle->image->get_ispe_width();
510 }
511 else {
512 return 0;
513 }
514 }
515
516
heif_image_handle_get_ispe_height(const struct heif_image_handle * handle)517 int heif_image_handle_get_ispe_height(const struct heif_image_handle* handle)
518 {
519 if (handle && handle->image) {
520 return handle->image->get_ispe_height();
521 }
522 else {
523 return 0;
524 }
525 }
526
527
heif_image_handle_has_alpha_channel(const struct heif_image_handle * handle)528 int heif_image_handle_has_alpha_channel(const struct heif_image_handle* handle)
529 {
530 return handle->image->get_alpha_channel() != nullptr;
531 }
532
533
heif_image_handle_get_luma_bits_per_pixel(const struct heif_image_handle * handle)534 int heif_image_handle_get_luma_bits_per_pixel(const struct heif_image_handle* handle)
535 {
536 return handle->image->get_luma_bits_per_pixel();
537 }
538
539
heif_image_handle_get_chroma_bits_per_pixel(const struct heif_image_handle * handle)540 int heif_image_handle_get_chroma_bits_per_pixel(const struct heif_image_handle* handle)
541 {
542 return handle->image->get_chroma_bits_per_pixel();
543 }
544
545
heif_image_handle_has_depth_image(const struct heif_image_handle * handle)546 int heif_image_handle_has_depth_image(const struct heif_image_handle* handle)
547 {
548 return handle->image->get_depth_channel() != nullptr;
549 }
550
heif_depth_representation_info_free(const struct heif_depth_representation_info * info)551 void heif_depth_representation_info_free(const struct heif_depth_representation_info* info)
552 {
553 delete info;
554 }
555
heif_image_handle_get_depth_image_representation_info(const struct heif_image_handle * handle,heif_item_id depth_image_id,const struct heif_depth_representation_info ** out)556 int heif_image_handle_get_depth_image_representation_info(const struct heif_image_handle* handle,
557 heif_item_id depth_image_id,
558 const struct heif_depth_representation_info** out)
559 {
560 if (out) {
561 if (handle->image->has_depth_representation_info()) {
562 auto info = new heif_depth_representation_info;
563 *info = handle->image->get_depth_representation_info();
564 *out = info;
565 return true;
566 }
567 else {
568 *out = nullptr;
569 }
570 }
571
572 return false;
573 }
574
575
heif_image_handle_get_number_of_depth_images(const struct heif_image_handle * handle)576 int heif_image_handle_get_number_of_depth_images(const struct heif_image_handle* handle)
577 {
578 auto depth_image = handle->image->get_depth_channel();
579
580 if (depth_image) {
581 return 1;
582 }
583 else {
584 return 0;
585 }
586 }
587
588
heif_image_handle_get_list_of_depth_image_IDs(const struct heif_image_handle * handle,heif_item_id * ids,int count)589 int heif_image_handle_get_list_of_depth_image_IDs(const struct heif_image_handle* handle,
590 heif_item_id* ids, int count)
591 {
592 auto depth_image = handle->image->get_depth_channel();
593
594 if (count==0) {
595 return 0;
596 }
597
598 if (depth_image) {
599 ids[0] = depth_image->get_id();
600 return 1;
601 }
602 else {
603 return 0;
604 }
605 }
606
607
heif_image_handle_get_depth_image_handle(const struct heif_image_handle * handle,heif_item_id depth_id,struct heif_image_handle ** out_depth_handle)608 struct heif_error heif_image_handle_get_depth_image_handle(const struct heif_image_handle* handle,
609 heif_item_id depth_id,
610 struct heif_image_handle** out_depth_handle)
611 {
612 auto depth_image = handle->image->get_depth_channel();
613
614 if (depth_image->get_id() != depth_id) {
615 *out_depth_handle = nullptr;
616
617 Error err(heif_error_Usage_error, heif_suberror_Nonexisting_item_referenced);
618 return err.error_struct(handle->image.get());
619 }
620
621 *out_depth_handle = new heif_image_handle();
622 (*out_depth_handle)->image = depth_image;
623 (*out_depth_handle)->context = handle->context;
624
625 return Error::Ok.error_struct(handle->image.get());
626 }
627
628
heif_decoding_options_alloc()629 heif_decoding_options* heif_decoding_options_alloc()
630 {
631 auto options = new heif_decoding_options;
632
633 options->version = 1;
634
635 options->ignore_transformations = false;
636
637 options->start_progress = NULL;
638 options->on_progress = NULL;
639 options->end_progress = NULL;
640 options->progress_user_data = NULL;
641
642 return options;
643 }
644
645
heif_decoding_options_free(heif_decoding_options * options)646 void heif_decoding_options_free(heif_decoding_options* options)
647 {
648 delete options;
649 }
650
651
heif_decode_image(const struct heif_image_handle * in_handle,struct heif_image ** out_img,heif_colorspace colorspace,heif_chroma chroma,const struct heif_decoding_options * options)652 struct heif_error heif_decode_image(const struct heif_image_handle* in_handle,
653 struct heif_image** out_img,
654 heif_colorspace colorspace,
655 heif_chroma chroma,
656 const struct heif_decoding_options* options)
657 {
658 std::shared_ptr<HeifPixelImage> img;
659
660 Error err = in_handle->image->decode_image(img,
661 colorspace,
662 chroma,
663 options);
664 if (err.error_code != heif_error_Ok) {
665 return err.error_struct(in_handle->image.get());
666 }
667
668 *out_img = new heif_image();
669 (*out_img)->image = std::move(img);
670
671 return Error::Ok.error_struct(in_handle->image.get());
672 }
673
674
heif_image_create(int width,int height,heif_colorspace colorspace,heif_chroma chroma,struct heif_image ** image)675 struct heif_error heif_image_create(int width, int height,
676 heif_colorspace colorspace,
677 heif_chroma chroma,
678 struct heif_image** image)
679 {
680 struct heif_image* img = new heif_image;
681 img->image = std::make_shared<HeifPixelImage>();
682
683 img->image->create(width, height, colorspace, chroma);
684
685 *image = img;
686
687 struct heif_error err = { heif_error_Ok, heif_suberror_Unspecified, Error::kSuccess };
688 return err;
689 }
690
heif_image_release(const struct heif_image * img)691 void heif_image_release(const struct heif_image* img)
692 {
693 delete img;
694 }
695
heif_image_handle_release(const struct heif_image_handle * handle)696 void heif_image_handle_release(const struct heif_image_handle* handle)
697 {
698 delete handle;
699 }
700
701
heif_image_get_colorspace(const struct heif_image * img)702 enum heif_colorspace heif_image_get_colorspace(const struct heif_image* img)
703 {
704 return img->image->get_colorspace();
705 }
706
heif_image_get_chroma_format(const struct heif_image * img)707 enum heif_chroma heif_image_get_chroma_format(const struct heif_image* img)
708 {
709 return img->image->get_chroma_format();
710 }
711
712
heif_image_get_width(const struct heif_image * img,enum heif_channel channel)713 int heif_image_get_width(const struct heif_image* img,enum heif_channel channel)
714 {
715 return img->image->get_width(channel);
716 }
717
heif_image_get_height(const struct heif_image * img,enum heif_channel channel)718 int heif_image_get_height(const struct heif_image* img,enum heif_channel channel)
719 {
720 return img->image->get_height(channel);
721 }
722
723
heif_image_get_bits_per_pixel(const struct heif_image * img,enum heif_channel channel)724 int heif_image_get_bits_per_pixel(const struct heif_image* img,enum heif_channel channel)
725 {
726 return img->image->get_storage_bits_per_pixel(channel);
727 }
728
729
heif_image_get_bits_per_pixel_range(const struct heif_image * img,enum heif_channel channel)730 int heif_image_get_bits_per_pixel_range(const struct heif_image* img,enum heif_channel channel)
731 {
732 return img->image->get_bits_per_pixel(channel);
733 }
734
735
heif_image_has_channel(const struct heif_image * img,enum heif_channel channel)736 int heif_image_has_channel(const struct heif_image* img, enum heif_channel channel)
737 {
738 return img->image->has_channel(channel);
739 }
740
741
heif_image_add_plane(struct heif_image * image,heif_channel channel,int width,int height,int bit_depth)742 struct heif_error heif_image_add_plane(struct heif_image* image,
743 heif_channel channel, int width, int height, int bit_depth)
744 {
745 if (!image->image->add_plane(channel, width, height, bit_depth)) {
746 struct heif_error err = { heif_error_Memory_allocation_error,
747 heif_suberror_Unspecified,
748 "Cannot allocate memory for image plane" };
749 return err;
750 }
751 else {
752 struct heif_error err = { heif_error_Ok, heif_suberror_Unspecified, Error::kSuccess };
753 return err;
754 }
755 }
756
757
758
heif_image_get_plane_readonly(const struct heif_image * image,enum heif_channel channel,int * out_stride)759 const uint8_t* heif_image_get_plane_readonly(const struct heif_image* image,
760 enum heif_channel channel,
761 int* out_stride)
762 {
763 if (!image || !image->image) {
764 *out_stride = 0;
765 return nullptr;
766 }
767
768 return image->image->get_plane(channel, out_stride);
769 }
770
771
heif_image_get_plane(struct heif_image * image,enum heif_channel channel,int * out_stride)772 uint8_t* heif_image_get_plane(struct heif_image* image,
773 enum heif_channel channel,
774 int* out_stride)
775 {
776 if (!image || !image->image) {
777 *out_stride = 0;
778 return nullptr;
779 }
780
781 return image->image->get_plane(channel, out_stride);
782 }
783
784
heif_image_scale_image(const struct heif_image * input,struct heif_image ** output,int width,int height,const struct heif_scaling_options * options)785 struct heif_error heif_image_scale_image(const struct heif_image* input,
786 struct heif_image** output,
787 int width, int height,
788 const struct heif_scaling_options* options)
789 {
790 std::shared_ptr<HeifPixelImage> out_img;
791
792 Error err = input->image->scale_nearest_neighbor(out_img, width, height);
793 if (err) {
794 return err.error_struct(input->image.get());
795 }
796
797 *output = new heif_image;
798 (*output)->image = out_img;
799
800 return Error::Ok.error_struct(input->image.get());
801 }
802
heif_image_set_raw_color_profile(struct heif_image * image,const char * color_profile_type_fourcc,const void * profile_data,const size_t profile_size)803 struct heif_error heif_image_set_raw_color_profile(struct heif_image* image,
804 const char* color_profile_type_fourcc,
805 const void* profile_data,
806 const size_t profile_size)
807 {
808 if (strlen(color_profile_type_fourcc) != 4) {
809 heif_error err = { heif_error_Usage_error,
810 heif_suberror_Unspecified,
811 "Invalid color_profile_type (must be 4 characters)" };
812 return err;
813 }
814
815 uint32_t color_profile_type = fourcc(color_profile_type_fourcc);
816
817 std::vector<uint8_t> data;
818 data.insert(data.end(),
819 (const uint8_t*)profile_data,
820 (const uint8_t*)profile_data + profile_size);
821
822 auto color_profile = std::make_shared<color_profile_raw>(color_profile_type, data);
823
824 image->image->set_color_profile(color_profile);
825
826 struct heif_error err = { heif_error_Ok, heif_suberror_Unspecified, Error::kSuccess };
827 return err;
828 }
829
830
heif_image_set_nclx_color_profile(struct heif_image * image,const struct heif_color_profile_nclx * color_profile)831 struct heif_error heif_image_set_nclx_color_profile(struct heif_image* image,
832 const struct heif_color_profile_nclx* color_profile)
833 {
834 auto nclx = std::make_shared<color_profile_nclx>();
835
836 nclx->set_colour_primaries(color_profile->color_primaries);
837 nclx->set_transfer_characteristics(color_profile->transfer_characteristics);
838 nclx->set_matrix_coefficients(color_profile->matrix_coefficients);
839 nclx->set_full_range_flag(color_profile->full_range_flag);
840
841 image->image->set_color_profile(nclx);
842
843 return error_Ok;
844 }
845
846
847 /*
848 void heif_image_remove_color_profile(struct heif_image* image)
849 {
850 image->image->set_color_profile(nullptr);
851 }
852 */
853
854
heif_image_handle_get_number_of_metadata_blocks(const struct heif_image_handle * handle,const char * type_filter)855 int heif_image_handle_get_number_of_metadata_blocks(const struct heif_image_handle* handle,
856 const char* type_filter)
857 {
858 auto metadata_list = handle->image->get_metadata();
859
860 int cnt=0;
861 for (const auto& metadata : metadata_list) {
862 if (type_filter==nullptr ||
863 metadata->item_type == type_filter) {
864 cnt++;
865 }
866 }
867
868 return cnt;
869 }
870
871
heif_image_handle_get_list_of_metadata_block_IDs(const struct heif_image_handle * handle,const char * type_filter,heif_item_id * ids,int count)872 int heif_image_handle_get_list_of_metadata_block_IDs(const struct heif_image_handle* handle,
873 const char* type_filter,
874 heif_item_id* ids, int count)
875 {
876 auto metadata_list = handle->image->get_metadata();
877
878 int cnt=0;
879 for (const auto& metadata : metadata_list) {
880 if (type_filter==nullptr ||
881 metadata->item_type == type_filter) {
882 if (cnt < count) {
883 ids[cnt] = metadata->item_id;
884 cnt++;
885 }
886 else {
887 break;
888 }
889 }
890 }
891
892 return cnt;
893 }
894
895
heif_image_handle_get_metadata_type(const struct heif_image_handle * handle,heif_item_id metadata_id)896 const char* heif_image_handle_get_metadata_type(const struct heif_image_handle* handle,
897 heif_item_id metadata_id)
898 {
899 auto metadata_list = handle->image->get_metadata();
900
901 for (auto metadata : metadata_list) {
902 if (metadata->item_id == metadata_id) {
903 return metadata->item_type.c_str();
904 }
905 }
906
907 return NULL;
908 }
909
910
heif_image_handle_get_metadata_content_type(const struct heif_image_handle * handle,heif_item_id metadata_id)911 const char* heif_image_handle_get_metadata_content_type(const struct heif_image_handle* handle,
912 heif_item_id metadata_id)
913 {
914 auto metadata_list = handle->image->get_metadata();
915
916 for (auto metadata : metadata_list) {
917 if (metadata->item_id == metadata_id) {
918 return metadata->content_type.c_str();
919 }
920 }
921
922 return NULL;
923 }
924
925
heif_image_handle_get_metadata_size(const struct heif_image_handle * handle,heif_item_id metadata_id)926 size_t heif_image_handle_get_metadata_size(const struct heif_image_handle* handle,
927 heif_item_id metadata_id)
928 {
929 auto metadata_list = handle->image->get_metadata();
930
931 for (auto metadata : metadata_list) {
932 if (metadata->item_id == metadata_id) {
933 return metadata->m_data.size();
934 }
935 }
936
937 return 0;
938 }
939
940
heif_image_handle_get_metadata(const struct heif_image_handle * handle,heif_item_id metadata_id,void * out_data)941 struct heif_error heif_image_handle_get_metadata(const struct heif_image_handle* handle,
942 heif_item_id metadata_id,
943 void* out_data)
944 {
945 if (out_data==nullptr) {
946 Error err(heif_error_Usage_error,
947 heif_suberror_Null_pointer_argument);
948 return err.error_struct(handle->image.get());
949 }
950
951 auto metadata_list = handle->image->get_metadata();
952
953 for (auto metadata : metadata_list) {
954 if (metadata->item_id == metadata_id) {
955 memcpy(out_data,
956 metadata->m_data.data(),
957 metadata->m_data.size());
958
959 return Error::Ok.error_struct(handle->image.get());
960 }
961 }
962
963 Error err(heif_error_Usage_error,
964 heif_suberror_Nonexisting_item_referenced);
965 return err.error_struct(handle->image.get());
966 }
967
heif_image_handle_get_color_profile_type(const struct heif_image_handle * handle)968 heif_color_profile_type heif_image_handle_get_color_profile_type(const struct heif_image_handle* handle)
969 {
970 auto profile = handle->image->get_color_profile();
971 if (!profile) {
972 return heif_color_profile_type_not_present;
973 }
974 else {
975 return (heif_color_profile_type)profile->get_type();
976 }
977 }
978
heif_image_handle_get_raw_color_profile_size(const struct heif_image_handle * handle)979 size_t heif_image_handle_get_raw_color_profile_size(const struct heif_image_handle* handle)
980 {
981 auto profile = handle->image->get_color_profile();
982 auto raw_profile = std::dynamic_pointer_cast<const color_profile_raw>(profile);
983 if (raw_profile) {
984 return raw_profile->get_data().size();
985 }
986 else {
987 return 0;
988 }
989 }
990
991 static struct color_primaries_table_entry {
992 int id;
993 float gx,gy, bx,by, rx,ry, wx,wy;
994 } color_primaries_table[] = {
995 { 0, 0.000f,0.000f, 0.000f,0.000f, 0.000f,0.000f, 0.0000f,0.0000f },
996 { 1, 0.300f,0.600f, 0.150f,0.060f, 0.640f,0.330f, 0.3127f,0.3290f },
997 { 4, 0.210f,0.710f, 0.140f,0.080f, 0.670f,0.330f, 0.3100f,0.3160f },
998 { 5, 0.290f,0.600f, 0.150f,0.060f, 0.640f,0.330f, 0.3127f,0.3290f },
999 { 6, 0.310f,0.595f, 0.155f,0.070f, 0.630f,0.340f, 0.3127f,0.3290f },
1000 { 7, 0.310f,0.595f, 0.155f,0.707f, 0.630f,0.340f, 0.3127f,0.3290f },
1001 { -1 }
1002 };
1003
1004
get_nclx_color_profile(std::shared_ptr<const color_profile_nclx> nclx_profile,struct heif_color_profile_nclx ** out_data)1005 static Error get_nclx_color_profile(std::shared_ptr<const color_profile_nclx> nclx_profile,
1006 struct heif_color_profile_nclx** out_data)
1007 {
1008 if (nclx_profile) {
1009 *out_data = (struct heif_color_profile_nclx*)malloc(sizeof(struct heif_color_profile_nclx));
1010
1011 struct heif_color_profile_nclx* nclx = *out_data;
1012
1013 nclx->version = 1;
1014 nclx->color_primaries = (enum heif_color_primaries)nclx_profile->get_colour_primaries();
1015 nclx->transfer_characteristics = (enum heif_transfer_characteristics)nclx_profile->get_transfer_characteristics();
1016 nclx->matrix_coefficients = (enum heif_matrix_coefficients)nclx_profile->get_matrix_coefficients();
1017 nclx->full_range_flag = nclx_profile->get_full_range_flag();
1018
1019 // fill color primaries
1020
1021 int tableIdx = 0;
1022 for (int i=0; color_primaries_table[i].id >= 0; i++) {
1023 const auto& c = color_primaries_table[i];
1024 if (c.id == (*out_data)->color_primaries) {
1025 tableIdx = i;
1026 break;
1027 }
1028 }
1029
1030 const auto& c = color_primaries_table[tableIdx];
1031 nclx->color_primary_red_x = c.rx;
1032 nclx->color_primary_red_y = c.ry;
1033 nclx->color_primary_green_x = c.gx;
1034 nclx->color_primary_green_y = c.gy;
1035 nclx->color_primary_blue_x = c.bx;
1036 nclx->color_primary_blue_y = c.by;
1037 nclx->color_primary_white_x = c.wx;
1038 nclx->color_primary_white_y = c.wy;
1039
1040 return Error::Ok;
1041 }
1042 else {
1043 return Error(heif_error_Usage_error,
1044 heif_suberror_Unspecified);
1045 }
1046 }
1047
heif_image_handle_get_nclx_color_profile(const struct heif_image_handle * handle,struct heif_color_profile_nclx ** out_data)1048 struct heif_error heif_image_handle_get_nclx_color_profile(const struct heif_image_handle* handle,
1049 struct heif_color_profile_nclx** out_data)
1050 {
1051 if (!out_data) {
1052 Error err(heif_error_Usage_error,
1053 heif_suberror_Null_pointer_argument);
1054 return err.error_struct(handle->image.get());
1055 }
1056
1057 auto profile = handle->image->get_color_profile();
1058 auto nclx_profile = std::dynamic_pointer_cast<const color_profile_nclx>(profile);
1059 Error err = get_nclx_color_profile(nclx_profile, out_data);
1060
1061 return err.error_struct(handle->image.get());
1062 }
1063
1064
heif_image_handle_get_raw_color_profile(const struct heif_image_handle * handle,void * out_data)1065 struct heif_error heif_image_handle_get_raw_color_profile(const struct heif_image_handle* handle,
1066 void* out_data)
1067 {
1068 if (out_data==nullptr) {
1069 Error err(heif_error_Usage_error,
1070 heif_suberror_Null_pointer_argument);
1071 return err.error_struct(handle->image.get());
1072 }
1073
1074 auto profile = handle->image->get_color_profile();
1075 auto raw_profile = std::dynamic_pointer_cast<const color_profile_raw>(profile);
1076 if (raw_profile) {
1077 memcpy(out_data,
1078 raw_profile->get_data().data(),
1079 raw_profile->get_data().size());
1080 }
1081
1082 return Error::Ok.error_struct(handle->image.get());
1083 }
1084
1085
1086
heif_image_get_color_profile_type(const struct heif_image * image)1087 enum heif_color_profile_type heif_image_get_color_profile_type(const struct heif_image* image)
1088 {
1089 auto profile = image->image->get_color_profile();
1090 if (!profile) {
1091 return heif_color_profile_type_not_present;
1092 }
1093 else {
1094 return (heif_color_profile_type)profile->get_type();
1095 }
1096 }
1097
1098
heif_image_get_raw_color_profile_size(const struct heif_image * image)1099 size_t heif_image_get_raw_color_profile_size(const struct heif_image* image)
1100 {
1101 auto profile = image->image->get_color_profile();
1102 auto raw_profile = std::dynamic_pointer_cast<const color_profile_raw>(profile);
1103 if (raw_profile) {
1104 return raw_profile->get_data().size();
1105 }
1106 else {
1107 return 0;
1108 }
1109 }
1110
1111
heif_image_get_raw_color_profile(const struct heif_image * image,void * out_data)1112 struct heif_error heif_image_get_raw_color_profile(const struct heif_image* image,
1113 void* out_data)
1114 {
1115 if (out_data==nullptr) {
1116 Error err(heif_error_Usage_error,
1117 heif_suberror_Null_pointer_argument);
1118 return err.error_struct(image->image.get());
1119 }
1120
1121 auto profile = image->image->get_color_profile();
1122 auto raw_profile = std::dynamic_pointer_cast<const color_profile_raw>(profile);
1123 if (raw_profile) {
1124 memcpy(out_data,
1125 raw_profile->get_data().data(),
1126 raw_profile->get_data().size());
1127 }
1128
1129 return Error::Ok.error_struct(image->image.get());
1130 }
1131
1132
heif_image_get_nclx_color_profile(const struct heif_image * image,struct heif_color_profile_nclx ** out_data)1133 struct heif_error heif_image_get_nclx_color_profile(const struct heif_image* image,
1134 struct heif_color_profile_nclx** out_data)
1135 {
1136 if (!out_data) {
1137 Error err(heif_error_Usage_error,
1138 heif_suberror_Null_pointer_argument);
1139 return err.error_struct(image->image.get());
1140 }
1141
1142 auto profile = image->image->get_color_profile();
1143 auto nclx_profile = std::dynamic_pointer_cast<const color_profile_nclx>(profile);
1144 Error err = get_nclx_color_profile(nclx_profile, out_data);
1145
1146 return err.error_struct(image->image.get());
1147 }
1148
1149
1150
1151
1152
1153 // DEPRECATED
heif_register_decoder(heif_context * heif,const heif_decoder_plugin * decoder_plugin)1154 struct heif_error heif_register_decoder(heif_context* heif, const heif_decoder_plugin* decoder_plugin)
1155 {
1156 if (!decoder_plugin) {
1157 return error_null_parameter;
1158 } else if (decoder_plugin->plugin_api_version != 1) {
1159 return error_unsupported_plugin_version;
1160 }
1161
1162 heif->context->register_decoder(decoder_plugin);
1163 return Error::Ok.error_struct(heif->context.get());
1164 }
1165
1166
heif_register_decoder_plugin(const heif_decoder_plugin * decoder_plugin)1167 struct heif_error heif_register_decoder_plugin(const heif_decoder_plugin* decoder_plugin)
1168 {
1169 if (!decoder_plugin) {
1170 return error_null_parameter;
1171 } else if (decoder_plugin->plugin_api_version != 1) {
1172 return error_unsupported_plugin_version;
1173 }
1174
1175 register_decoder(decoder_plugin);
1176 return error_Ok;
1177 }
1178
1179
heif_register_encoder_plugin(const heif_encoder_plugin * encoder_plugin)1180 struct heif_error heif_register_encoder_plugin(const heif_encoder_plugin* encoder_plugin)
1181 {
1182 if (!encoder_plugin) {
1183 return error_null_parameter;
1184 } else if (encoder_plugin->plugin_api_version != 1) {
1185 return error_unsupported_plugin_version;
1186 }
1187
1188 register_encoder(encoder_plugin);
1189 return error_Ok;
1190 }
1191
1192
1193
1194
1195 /*
1196 int heif_image_get_number_of_data_chunks(heif_image* img);
1197
1198 void heif_image_get_data_chunk(heif_image* img, int chunk_index,
1199 uint8_t const*const* dataptr,
1200 int const* data_size);
1201
1202 void heif_image_free_data_chunk(heif_image* img, int chunk_index);
1203 */
1204
1205
1206 /*
1207 void heif_context_reset(struct heif_context* ctx)
1208 {
1209 ctx->context->reset_to_empty_heif();
1210 }
1211 */
1212
heif_file_writer_write(struct heif_context * ctx,const void * data,size_t size,void * userdata)1213 static struct heif_error heif_file_writer_write(struct heif_context* ctx,
1214 const void* data, size_t size, void* userdata) {
1215 const char* filename = static_cast<const char*>(userdata);
1216
1217 std::ofstream ostr(filename, std::ios_base::binary);
1218 ostr.write(static_cast<const char*>(data), size);
1219 // TODO: handle write errors
1220 return Error::Ok.error_struct(ctx->context.get());
1221 }
1222
1223
heif_context_write_to_file(struct heif_context * ctx,const char * filename)1224 struct heif_error heif_context_write_to_file(struct heif_context* ctx,
1225 const char* filename)
1226 {
1227 heif_writer writer;
1228 writer.writer_api_version = 1;
1229 writer.write = heif_file_writer_write;
1230 return heif_context_write(ctx, &writer, (void*)filename);
1231 }
1232
1233
heif_context_write(struct heif_context * ctx,struct heif_writer * writer,void * userdata)1234 struct heif_error heif_context_write(struct heif_context* ctx,
1235 struct heif_writer* writer,
1236 void* userdata)
1237 {
1238 if (!writer) {
1239 return Error(heif_error_Usage_error,
1240 heif_suberror_Null_pointer_argument).error_struct(ctx->context.get());
1241 } else if (writer->writer_api_version != 1) {
1242 Error err(heif_error_Usage_error, heif_suberror_Unsupported_writer_version);
1243 return err.error_struct(ctx->context.get());
1244 }
1245
1246 StreamWriter swriter;
1247 ctx->context->write(swriter);
1248
1249 const auto& data = swriter.get_data();
1250 return writer->write(ctx, data.data(), data.size(), userdata);
1251 }
1252
1253
heif_context_get_encoder_descriptors(struct heif_context * ctx,enum heif_compression_format format,const char * name,const struct heif_encoder_descriptor ** out_encoder_descriptors,int count)1254 int heif_context_get_encoder_descriptors(struct heif_context* ctx,
1255 enum heif_compression_format format,
1256 const char* name,
1257 const struct heif_encoder_descriptor** out_encoder_descriptors,
1258 int count)
1259 {
1260 if (out_encoder_descriptors == nullptr || count <= 0) {
1261 return 0;
1262 }
1263
1264 std::vector<const struct heif_encoder_descriptor*> descriptors;
1265 descriptors = get_filtered_encoder_descriptors(format, name);
1266
1267 int i;
1268 for (i=0 ; i < count && static_cast<size_t>(i) < descriptors.size() ; i++) {
1269 out_encoder_descriptors[i] = descriptors[i];
1270 }
1271
1272 return i;
1273 }
1274
1275
heif_encoder_descriptor_get_name(const struct heif_encoder_descriptor * descriptor)1276 const char* heif_encoder_descriptor_get_name(const struct heif_encoder_descriptor* descriptor)
1277 {
1278 return descriptor->plugin->get_plugin_name();
1279 }
1280
1281
heif_encoder_descriptor_get_id_name(const struct heif_encoder_descriptor * descriptor)1282 const char* heif_encoder_descriptor_get_id_name(const struct heif_encoder_descriptor* descriptor)
1283 {
1284 return descriptor->plugin->id_name;
1285 }
1286
1287
heif_encoder_descriptor_supportes_lossy_compression(const struct heif_encoder_descriptor * descriptor)1288 int heif_encoder_descriptor_supportes_lossy_compression(const struct heif_encoder_descriptor* descriptor)
1289 {
1290 return descriptor->plugin->supports_lossy_compression;
1291 }
1292
1293
heif_encoder_descriptor_supportes_lossless_compression(const struct heif_encoder_descriptor * descriptor)1294 int heif_encoder_descriptor_supportes_lossless_compression(const struct heif_encoder_descriptor* descriptor)
1295 {
1296 return descriptor->plugin->supports_lossless_compression;
1297 }
1298
1299
1300
heif_encoder_get_name(const struct heif_encoder * encoder)1301 const char* heif_encoder_get_name(const struct heif_encoder* encoder)
1302 {
1303 return encoder->plugin->get_plugin_name();
1304 }
1305
1306
heif_context_get_encoder(struct heif_context * context,const struct heif_encoder_descriptor * descriptor,struct heif_encoder ** encoder)1307 struct heif_error heif_context_get_encoder(struct heif_context* context,
1308 const struct heif_encoder_descriptor* descriptor,
1309 struct heif_encoder** encoder)
1310 {
1311 if (!descriptor || !encoder) {
1312 return Error(heif_error_Usage_error,
1313 heif_suberror_Null_pointer_argument).error_struct(nullptr);
1314 }
1315
1316 if (context==nullptr) {
1317 *encoder = new struct heif_encoder(nullptr, descriptor->plugin);
1318 }
1319 else {
1320 // DEPRECATED. We do not need the context anywhere.
1321 *encoder = new struct heif_encoder(context->context, descriptor->plugin);
1322 }
1323
1324 (*encoder)->alloc();
1325
1326 struct heif_error err = { heif_error_Ok, heif_suberror_Unspecified, kSuccess };
1327 return err;
1328 }
1329
1330
heif_have_decoder_for_format(enum heif_compression_format format)1331 int heif_have_decoder_for_format(enum heif_compression_format format)
1332 {
1333 auto plugin = heif::get_decoder(format);
1334 return plugin != nullptr;
1335 }
1336
1337
heif_have_encoder_for_format(enum heif_compression_format format)1338 int heif_have_encoder_for_format(enum heif_compression_format format)
1339 {
1340 auto plugin = heif::get_encoder(format);
1341 return plugin != nullptr;
1342 }
1343
1344
heif_context_get_encoder_for_format(struct heif_context * context,enum heif_compression_format format,struct heif_encoder ** encoder)1345 struct heif_error heif_context_get_encoder_for_format(struct heif_context* context,
1346 enum heif_compression_format format,
1347 struct heif_encoder** encoder)
1348 {
1349 if (!encoder) {
1350 return Error(heif_error_Usage_error,
1351 heif_suberror_Null_pointer_argument).error_struct(nullptr);
1352 }
1353
1354 std::vector<const struct heif_encoder_descriptor*> descriptors;
1355 descriptors = get_filtered_encoder_descriptors(format, nullptr);
1356
1357 if (descriptors.size()>0) {
1358 if (context==nullptr) {
1359 *encoder = new struct heif_encoder(nullptr, descriptors[0]->plugin);
1360 }
1361 else {
1362 // DEPRECATED. We do not need the context anywhere.
1363 *encoder = new struct heif_encoder(context->context, descriptors[0]->plugin);
1364 }
1365
1366 (*encoder)->alloc();
1367
1368 struct heif_error err = { heif_error_Ok, heif_suberror_Unspecified, kSuccess };
1369 return err;
1370 }
1371 else {
1372 struct heif_error err = { heif_error_Unsupported_filetype, // TODO: is this the right error code?
1373 heif_suberror_Unspecified, kSuccess };
1374 return err;
1375 }
1376 }
1377
1378
heif_encoder_release(struct heif_encoder * encoder)1379 void heif_encoder_release(struct heif_encoder* encoder)
1380 {
1381 if (encoder) {
1382 delete encoder;
1383 }
1384 }
1385
1386
1387 //struct heif_encoder_param* heif_encoder_get_param(struct heif_encoder* encoder)
1388 //{
1389 // return nullptr;
1390 //}
1391
1392
1393 //void heif_encoder_release_param(struct heif_encoder_param* param)
1394 //{
1395 //}
1396
1397
1398 // Set a 'quality' factor (0-100). How this is mapped to actual encoding parameters is
1399 // encoder dependent.
heif_encoder_set_lossy_quality(struct heif_encoder * encoder,int quality)1400 struct heif_error heif_encoder_set_lossy_quality(struct heif_encoder* encoder,
1401 int quality)
1402 {
1403 if (!encoder) {
1404 return Error(heif_error_Usage_error,
1405 heif_suberror_Null_pointer_argument).error_struct(nullptr);
1406 }
1407
1408 return encoder->plugin->set_parameter_quality(encoder->encoder, quality);
1409 }
1410
1411
heif_encoder_set_lossless(struct heif_encoder * encoder,int enable)1412 struct heif_error heif_encoder_set_lossless(struct heif_encoder* encoder, int enable)
1413 {
1414 if (!encoder) {
1415 return Error(heif_error_Usage_error,
1416 heif_suberror_Null_pointer_argument).error_struct(nullptr);
1417 }
1418
1419 return encoder->plugin->set_parameter_lossless(encoder->encoder, enable);
1420 }
1421
1422
heif_encoder_set_logging_level(struct heif_encoder * encoder,int level)1423 struct heif_error heif_encoder_set_logging_level(struct heif_encoder* encoder, int level)
1424 {
1425 if (!encoder) {
1426 return Error(heif_error_Usage_error,
1427 heif_suberror_Null_pointer_argument).error_struct(nullptr);
1428 }
1429
1430 if (encoder->plugin->set_parameter_logging_level) {
1431 return encoder->plugin->set_parameter_logging_level(encoder->encoder, level);
1432 }
1433
1434 struct heif_error err = { heif_error_Ok, heif_suberror_Unspecified, kSuccess };
1435 return err;
1436 }
1437
1438
heif_encoder_list_parameters(struct heif_encoder * encoder)1439 const struct heif_encoder_parameter*const* heif_encoder_list_parameters(struct heif_encoder* encoder)
1440 {
1441 return encoder->plugin->list_parameters(encoder->encoder);
1442 }
1443
1444
heif_encoder_parameter_get_name(const struct heif_encoder_parameter * param)1445 const char* heif_encoder_parameter_get_name(const struct heif_encoder_parameter* param)
1446 {
1447 return param->name;
1448 }
1449
1450 enum heif_encoder_parameter_type
heif_encoder_parameter_get_type(const struct heif_encoder_parameter * param)1451 heif_encoder_parameter_get_type(const struct heif_encoder_parameter* param)
1452 {
1453 return param->type;
1454 }
1455
1456
heif_encoder_set_parameter_integer(struct heif_encoder * encoder,const char * parameter_name,int value)1457 struct heif_error heif_encoder_set_parameter_integer(struct heif_encoder* encoder,
1458 const char* parameter_name,
1459 int value)
1460 {
1461 return encoder->plugin->set_parameter_integer(encoder->encoder, parameter_name, value);
1462 }
1463
heif_encoder_get_parameter_integer(struct heif_encoder * encoder,const char * parameter_name,int * value_ptr)1464 struct heif_error heif_encoder_get_parameter_integer(struct heif_encoder* encoder,
1465 const char* parameter_name,
1466 int* value_ptr)
1467 {
1468 return encoder->plugin->get_parameter_integer(encoder->encoder, parameter_name, value_ptr);
1469 }
1470
1471 struct heif_error
heif_encoder_parameter_get_valid_integer_range(const struct heif_encoder_parameter * param,int * have_minimum_maximum,int * minimum,int * maximum)1472 heif_encoder_parameter_get_valid_integer_range(const struct heif_encoder_parameter* param,
1473 int* have_minimum_maximum,
1474 int* minimum, int* maximum)
1475 {
1476 if (param->type != heif_encoder_parameter_type_integer) {
1477 return error_unsupported_parameter; // TODO: correct error ?
1478 }
1479
1480 if (param->integer.have_minimum_maximum) {
1481 if (minimum) {
1482 *minimum = param->integer.minimum;
1483 }
1484
1485 if (maximum) {
1486 *maximum = param->integer.maximum;
1487 }
1488 }
1489
1490 if (have_minimum_maximum) {
1491 *have_minimum_maximum = param->integer.have_minimum_maximum;
1492 }
1493
1494 return error_Ok;
1495 }
1496
1497 struct heif_error
heif_encoder_parameter_get_valid_string_values(const struct heif_encoder_parameter * param,const char * const ** out_stringarray)1498 heif_encoder_parameter_get_valid_string_values(const struct heif_encoder_parameter* param,
1499 const char*const** out_stringarray)
1500 {
1501 if (param->type != heif_encoder_parameter_type_string) {
1502 return error_unsupported_parameter; // TODO: correct error ?
1503 }
1504
1505 if (out_stringarray) {
1506 *out_stringarray = param->string.valid_values;
1507 }
1508
1509 return error_Ok;
1510 }
1511
heif_encoder_parameter_integer_valid_range(struct heif_encoder * encoder,const char * parameter_name,int * have_minimum_maximum,int * minimum,int * maximum)1512 struct heif_error heif_encoder_parameter_integer_valid_range(struct heif_encoder* encoder,
1513 const char* parameter_name,
1514 int* have_minimum_maximum,
1515 int* minimum, int* maximum)
1516 {
1517 for (const struct heif_encoder_parameter*const* params = heif_encoder_list_parameters(encoder);
1518 *params;
1519 params++) {
1520 if (strcmp((*params)->name, parameter_name)==0) {
1521 return heif_encoder_parameter_get_valid_integer_range(*params, have_minimum_maximum,
1522 minimum, maximum);
1523 }
1524 }
1525
1526 return error_unsupported_parameter;
1527 }
1528
heif_encoder_set_parameter_boolean(struct heif_encoder * encoder,const char * parameter_name,int value)1529 struct heif_error heif_encoder_set_parameter_boolean(struct heif_encoder* encoder,
1530 const char* parameter_name,
1531 int value)
1532 {
1533 return encoder->plugin->set_parameter_boolean(encoder->encoder, parameter_name, value);
1534 }
1535
heif_encoder_get_parameter_boolean(struct heif_encoder * encoder,const char * parameter_name,int * value_ptr)1536 struct heif_error heif_encoder_get_parameter_boolean(struct heif_encoder* encoder,
1537 const char* parameter_name,
1538 int* value_ptr)
1539 {
1540 return encoder->plugin->get_parameter_boolean(encoder->encoder, parameter_name, value_ptr);
1541 }
1542
heif_encoder_set_parameter_string(struct heif_encoder * encoder,const char * parameter_name,const char * value)1543 struct heif_error heif_encoder_set_parameter_string(struct heif_encoder* encoder,
1544 const char* parameter_name,
1545 const char* value)
1546 {
1547 return encoder->plugin->set_parameter_string(encoder->encoder, parameter_name, value);
1548 }
1549
heif_encoder_get_parameter_string(struct heif_encoder * encoder,const char * parameter_name,char * value_ptr,int value_size)1550 struct heif_error heif_encoder_get_parameter_string(struct heif_encoder* encoder,
1551 const char* parameter_name,
1552 char* value_ptr, int value_size)
1553 {
1554 return encoder->plugin->get_parameter_string(encoder->encoder, parameter_name,
1555 value_ptr, value_size);
1556 }
1557
heif_encoder_parameter_string_valid_values(struct heif_encoder * encoder,const char * parameter_name,const char * const ** out_stringarray)1558 struct heif_error heif_encoder_parameter_string_valid_values(struct heif_encoder* encoder,
1559 const char* parameter_name,
1560 const char*const** out_stringarray)
1561 {
1562 for (const struct heif_encoder_parameter*const* params = heif_encoder_list_parameters(encoder);
1563 *params;
1564 params++) {
1565 if (strcmp((*params)->name, parameter_name)==0) {
1566 return heif_encoder_parameter_get_valid_string_values(*params, out_stringarray);
1567 }
1568 }
1569
1570 return error_unsupported_parameter;
1571 }
1572
1573
1574
parse_boolean(const char * value)1575 static bool parse_boolean(const char* value)
1576 {
1577 if (strcmp(value,"true")==0) {
1578 return true;
1579 }
1580 else if (strcmp(value,"false")==0) {
1581 return false;
1582 }
1583 else if (strcmp(value,"1")==0) {
1584 return true;
1585 }
1586 else if (strcmp(value,"0")==0) {
1587 return false;
1588 }
1589
1590 return false;
1591 }
1592
1593
heif_encoder_set_parameter(struct heif_encoder * encoder,const char * parameter_name,const char * value)1594 struct heif_error heif_encoder_set_parameter(struct heif_encoder* encoder,
1595 const char* parameter_name,
1596 const char* value)
1597 {
1598 for (const struct heif_encoder_parameter*const* params = heif_encoder_list_parameters(encoder);
1599 *params;
1600 params++) {
1601 if (strcmp((*params)->name, parameter_name)==0) {
1602 switch ((*params)->type) {
1603 case heif_encoder_parameter_type_integer:
1604 return heif_encoder_set_parameter_integer(encoder, parameter_name, atoi(value));
1605
1606 case heif_encoder_parameter_type_boolean:
1607 return heif_encoder_set_parameter_boolean(encoder, parameter_name, parse_boolean(value));
1608
1609 case heif_encoder_parameter_type_string:
1610 return heif_encoder_set_parameter_string(encoder, parameter_name, value);
1611 break;
1612 }
1613
1614 return error_Ok;
1615 }
1616 }
1617
1618 return heif_encoder_set_parameter_string(encoder, parameter_name, value);
1619
1620 //return error_unsupported_parameter;
1621 }
1622
1623
heif_encoder_get_parameter(struct heif_encoder * encoder,const char * parameter_name,char * value_ptr,int value_size)1624 struct heif_error heif_encoder_get_parameter(struct heif_encoder* encoder,
1625 const char* parameter_name,
1626 char* value_ptr, int value_size)
1627 {
1628 for (const struct heif_encoder_parameter*const* params = heif_encoder_list_parameters(encoder);
1629 *params;
1630 params++) {
1631 if (strcmp((*params)->name, parameter_name)==0) {
1632 switch ((*params)->type) {
1633 case heif_encoder_parameter_type_integer:
1634 {
1635 int value;
1636 struct heif_error error = heif_encoder_get_parameter_integer(encoder, parameter_name, &value);
1637 if (error.code) {
1638 return error;
1639 }
1640 else {
1641 snprintf(value_ptr, value_size, "%d",value);
1642 }
1643 }
1644 break;
1645
1646 case heif_encoder_parameter_type_boolean:
1647 {
1648 int value;
1649 struct heif_error error = heif_encoder_get_parameter_boolean(encoder, parameter_name, &value);
1650 if (error.code) {
1651 return error;
1652 }
1653 else {
1654 snprintf(value_ptr, value_size, "%d",value);
1655 }
1656 }
1657 break;
1658
1659 case heif_encoder_parameter_type_string:
1660 {
1661 struct heif_error error = heif_encoder_get_parameter_string(encoder, parameter_name,
1662 value_ptr, value_size);
1663 if (error.code) {
1664 return error;
1665 }
1666 }
1667 break;
1668 }
1669
1670 return error_Ok;
1671 }
1672 }
1673
1674 return error_unsupported_parameter;
1675 }
1676
1677
heif_encoder_has_default(struct heif_encoder * encoder,const char * parameter_name)1678 int heif_encoder_has_default(struct heif_encoder* encoder,
1679 const char* parameter_name)
1680 {
1681 for (const struct heif_encoder_parameter*const* params = heif_encoder_list_parameters(encoder);
1682 *params;
1683 params++) {
1684 if (strcmp((*params)->name, parameter_name)==0) {
1685
1686 if ((*params)->version >= 2) {
1687 return (*params)->has_default;
1688 }
1689 else {
1690 return true;
1691 }
1692 }
1693 }
1694
1695 return false;
1696 }
1697
1698
set_default_options(heif_encoding_options & options)1699 static void set_default_options(heif_encoding_options& options)
1700 {
1701 options.version = 1;
1702
1703 options.save_alpha_channel = true;
1704 }
1705
1706
heif_encoding_options_alloc()1707 heif_encoding_options* heif_encoding_options_alloc()
1708 {
1709 auto options = new heif_encoding_options;
1710
1711 set_default_options(*options);
1712
1713 return options;
1714 }
1715
1716
heif_encoding_options_free(heif_encoding_options * options)1717 void heif_encoding_options_free(heif_encoding_options* options)
1718 {
1719 delete options;
1720 }
1721
heif_context_encode_image(struct heif_context * ctx,const struct heif_image * input_image,struct heif_encoder * encoder,const struct heif_encoding_options * options,struct heif_image_handle ** out_image_handle)1722 struct heif_error heif_context_encode_image(struct heif_context* ctx,
1723 const struct heif_image* input_image,
1724 struct heif_encoder* encoder,
1725 const struct heif_encoding_options* options,
1726 struct heif_image_handle** out_image_handle)
1727 {
1728 if (!encoder) {
1729 return Error(heif_error_Usage_error,
1730 heif_suberror_Null_pointer_argument).error_struct(ctx->context.get());
1731 }
1732
1733 heif_encoding_options default_options;
1734 if (options==nullptr) {
1735 set_default_options(default_options);
1736 options = &default_options;
1737 }
1738
1739 std::shared_ptr<HeifContext::Image> image;
1740 Error error;
1741
1742 error = ctx->context->encode_image(input_image->image,
1743 encoder,
1744 options,
1745 heif_image_input_class_normal,
1746 image);
1747 if (error != Error::Ok) {
1748 return error.error_struct(ctx->context.get());
1749 }
1750
1751 // mark the new image as primary image
1752
1753 if (ctx->context->is_primary_image_set() == false) {
1754 ctx->context->set_primary_image(image);
1755 }
1756
1757 if (out_image_handle) {
1758 *out_image_handle = new heif_image_handle;
1759 (*out_image_handle)->image = image;
1760 (*out_image_handle)->context = ctx->context;
1761 }
1762
1763 return error_Ok;
1764 }
1765
1766
heif_context_assign_thumbnail(struct heif_context * ctx,const struct heif_image_handle * master_image,const struct heif_image_handle * thumbnail_image)1767 struct heif_error heif_context_assign_thumbnail(struct heif_context* ctx,
1768 const struct heif_image_handle* master_image,
1769 const struct heif_image_handle* thumbnail_image)
1770 {
1771 Error error = ctx->context->assign_thumbnail(thumbnail_image->image, master_image->image);
1772 return error.error_struct(ctx->context.get());
1773 }
1774
1775
heif_context_encode_thumbnail(struct heif_context * ctx,const struct heif_image * image,const struct heif_image_handle * image_handle,struct heif_encoder * encoder,const struct heif_encoding_options * options,int bbox_size,struct heif_image_handle ** out_image_handle)1776 struct heif_error heif_context_encode_thumbnail(struct heif_context* ctx,
1777 const struct heif_image* image,
1778 const struct heif_image_handle* image_handle,
1779 struct heif_encoder* encoder,
1780 const struct heif_encoding_options* options,
1781 int bbox_size,
1782 struct heif_image_handle** out_image_handle)
1783 {
1784 std::shared_ptr<HeifContext::Image> thumbnail_image;
1785
1786 heif_encoding_options default_options;
1787 if (options==nullptr) {
1788 set_default_options(default_options);
1789 options = &default_options;
1790 }
1791
1792 Error error = ctx->context->encode_thumbnail(image->image,
1793 encoder,
1794 options,
1795 bbox_size,
1796 thumbnail_image);
1797 if (error != Error::Ok) {
1798 return error.error_struct(ctx->context.get());
1799 } else if (!thumbnail_image) {
1800 Error err(heif_error_Usage_error,
1801 heif_suberror_Invalid_parameter_value,
1802 "Thumbnail images must be smaller than the original image.");
1803 return err.error_struct(ctx->context.get());
1804 }
1805
1806 error = ctx->context->assign_thumbnail(image_handle->image, thumbnail_image);
1807 if (error != Error::Ok) {
1808 return error.error_struct(ctx->context.get());
1809 }
1810
1811
1812 if (out_image_handle) {
1813 if (thumbnail_image) {
1814 *out_image_handle = new heif_image_handle;
1815 (*out_image_handle)->image = thumbnail_image;
1816 (*out_image_handle)->context = ctx->context;
1817 }
1818 else {
1819 *out_image_handle = nullptr;
1820 }
1821 }
1822
1823 return error_Ok;
1824 }
1825
1826
heif_context_set_primary_image(struct heif_context * ctx,struct heif_image_handle * image_handle)1827 struct heif_error heif_context_set_primary_image(struct heif_context* ctx,
1828 struct heif_image_handle* image_handle)
1829 {
1830 ctx->context->set_primary_image(image_handle->image);
1831
1832 return error_Ok;
1833 }
1834
1835
heif_context_add_exif_metadata(struct heif_context * ctx,const struct heif_image_handle * image_handle,const void * data,int size)1836 struct heif_error heif_context_add_exif_metadata(struct heif_context* ctx,
1837 const struct heif_image_handle* image_handle,
1838 const void* data, int size)
1839 {
1840 Error error = ctx->context->add_exif_metadata(image_handle->image, data, size);
1841 if (error != Error::Ok) {
1842 return error.error_struct(ctx->context.get());
1843 }
1844 else {
1845 return error_Ok;
1846 }
1847 }
1848
1849
heif_context_add_XMP_metadata(struct heif_context * ctx,const struct heif_image_handle * image_handle,const void * data,int size)1850 struct heif_error heif_context_add_XMP_metadata(struct heif_context* ctx,
1851 const struct heif_image_handle* image_handle,
1852 const void* data, int size)
1853 {
1854 Error error = ctx->context->add_XMP_metadata(image_handle->image, data, size);
1855 if (error != Error::Ok) {
1856 return error.error_struct(ctx->context.get());
1857 }
1858 else {
1859 return error_Ok;
1860 }
1861 }
1862
1863
heif_context_add_generic_metadata(struct heif_context * ctx,const struct heif_image_handle * image_handle,const void * data,int size,const char * item_type,const char * content_type)1864 struct heif_error heif_context_add_generic_metadata(struct heif_context* ctx,
1865 const struct heif_image_handle* image_handle,
1866 const void* data, int size,
1867 const char* item_type, const char* content_type)
1868 {
1869 Error error = ctx->context->add_generic_metadata(image_handle->image, data, size,
1870 item_type, content_type);
1871 if (error != Error::Ok) {
1872 return error.error_struct(ctx->context.get());
1873 }
1874 else {
1875 return error_Ok;
1876 }
1877 }
1878
1879
heif_context_set_maximum_image_size_limit(struct heif_context * ctx,int maximum_width)1880 void heif_context_set_maximum_image_size_limit(struct heif_context* ctx, int maximum_width)
1881 {
1882 ctx->context->set_maximum_image_size_limit(maximum_width);
1883 }
1884