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