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