1 /*
2 FLIF - Free Lossless Image Format
3 
4 Copyright 2010-2016, Jon Sneyers & Pieter Wuille
5 
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9 
10     http://www.apache.org/licenses/LICENSE-2.0
11 
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17 */
18 
19 #include <stdio.h>
20 
21 #include "flif-interface-private_dec.hpp"
22 #include "flif-interface_common.cpp"
23 
24 #include <functional>
25 
FLIF_DECODER()26 FLIF_DECODER::FLIF_DECODER()
27 : options(FLIF_DEFAULT_OPTIONS)
28 , callback(NULL)
29 , user_data(NULL)
30 , first_quality(0)
31 , working(false)
32 { options.crc_check = 0; options.keep_palette = 1; }
33 
34 
decode_file(const char * filename)35 int32_t FLIF_DECODER::decode_file(const char* filename) {
36     FILE *file = fopen(filename,"rb");
37     if(!file)
38         return 0;
39 
40     return decode_filepointer(file, filename);
41 }
42 
decode_filepointer(FILE * file,const char * filename)43 int32_t FLIF_DECODER::decode_filepointer(FILE *file, const char *filename) {
44     internal_images.clear();
45     images.clear();
46 
47     FileIO fio(file, filename);
48 
49     working = true;
50     metadata_options md_default = {
51          true, // icc
52          true, // exif
53          true, // xmp
54     };
55     if(!flif_decode(fio, internal_images, reinterpret_cast<callback_t>(callback), user_data, first_quality, images, options, md_default, 0))
56         { working = false; return 0; }
57     working = false;
58 
59     images.clear();
60     for (Image& image : internal_images) images.emplace_back(std::move(image));
61 
62     return 1;
63 }
64 
decode_memory(const void * buffer,size_t buffer_size_bytes)65 int32_t FLIF_DECODER::decode_memory(const void* buffer, size_t buffer_size_bytes) {
66     internal_images.clear();
67     images.clear();
68 
69     BlobReader reader(reinterpret_cast<const uint8_t*>(buffer), buffer_size_bytes);
70 
71     working = true;
72     metadata_options md_default = {
73 		true, // icc
74 		true, // exif
75 		true, // xmp
76     };
77     if(!flif_decode(reader, internal_images, reinterpret_cast<callback_t>(callback), user_data, first_quality, images, options, md_default, 0))
78         { working = false; return 0; }
79     working = false;
80 
81     images.clear();
82     for (Image& image : internal_images) images.emplace_back(std::move(image));
83     return 1;
84 }
85 
abort()86 int32_t FLIF_DECODER::abort() {
87       if (working) {
88         if (images.size() > 0) images[0].abort_decoding();
89         return 1;
90       } else return 0;
91 }
92 
num_images()93 size_t FLIF_DECODER::num_images() {
94     return images.size();
95 }
96 
num_loops()97 int32_t FLIF_DECODER::num_loops() {
98     return 0; // TODO: return actual loop count of the animation
99 }
100 
get_image(size_t index)101 FLIF_IMAGE* FLIF_DECODER::get_image(size_t index) {
102     if(index >= images.size())
103         return 0;
104     if(index >= requested_images.size()) requested_images.resize(images.size());
105     if (!requested_images[index].get()) requested_images[index].reset( new FLIF_IMAGE());
106     if (images[index].rows() || images[index].metadata.size() > 0) {
107         requested_images[index]->image = std::move(images[index]); // moves and invalidates images[index]
108     }
109     return requested_images[index].get();
110 }
111 
112 
113 //=============================================================================
114 
115 
FLIF_INFO()116 FLIF_INFO::FLIF_INFO()
117 : width(0)
118 , height(0)
119 , channels(0)
120 , bit_depth(0)
121 , num_images(0)
122 { }
123 
124 
125 //=============================================================================
126 
127 /*!
128 Notes about the C interface:
129 
130 Only use types known to C.
131 Use types that are unambiguous across all compilers, like uint32_t.
132 Each function must have it's call convention set.
133 Exceptions must be caught no matter what.
134 
135 */
136 
137 //=============================================================================
138 
139 
140 extern "C" {
141 
flif_create_decoder()142 FLIF_DLLEXPORT FLIF_DECODER* FLIF_API flif_create_decoder() {
143     try
144     {
145         std::unique_ptr<FLIF_DECODER> decoder(new FLIF_DECODER());
146         return decoder.release();
147     }
148     catch(...) {}
149     return 0;
150 }
151 
flif_abort_decoder(FLIF_DECODER * decoder)152 FLIF_DLLEXPORT int32_t FLIF_API flif_abort_decoder(FLIF_DECODER* decoder) {
153     try {
154       return decoder->abort();
155     } catch(...) {}
156     return 0;
157 }
flif_destroy_decoder(FLIF_DECODER * decoder)158 FLIF_DLLEXPORT void FLIF_API flif_destroy_decoder(FLIF_DECODER* decoder) {
159     // delete should never let exceptions out
160     delete decoder;
161     decoder = NULL;
162 }
163 
flif_decoder_set_crc_check(FLIF_DECODER * decoder,int32_t crc_check)164 FLIF_DLLEXPORT void FLIF_API flif_decoder_set_crc_check(FLIF_DECODER* decoder, int32_t crc_check) {
165     decoder->options.crc_check = crc_check;
166 }
167 
flif_decoder_set_quality(FLIF_DECODER * decoder,int32_t quality)168 FLIF_DLLEXPORT void FLIF_API flif_decoder_set_quality(FLIF_DECODER* decoder, int32_t quality) {
169     decoder->options.quality = quality;
170 }
171 
flif_decoder_set_scale(FLIF_DECODER * decoder,uint32_t scale)172 FLIF_DLLEXPORT void FLIF_API flif_decoder_set_scale(FLIF_DECODER* decoder, uint32_t scale) {
173     decoder->options.scale = scale;
174 }
175 
flif_decoder_set_resize(FLIF_DECODER * decoder,uint32_t rw,uint32_t rh)176 FLIF_DLLEXPORT void FLIF_API flif_decoder_set_resize(FLIF_DECODER* decoder, uint32_t rw, uint32_t rh) {
177     decoder->options.resize_width = rw;
178     decoder->options.resize_height = rh;
179 }
180 
flif_decoder_set_fit(FLIF_DECODER * decoder,uint32_t rw,uint32_t rh)181 FLIF_DLLEXPORT void FLIF_API flif_decoder_set_fit(FLIF_DECODER* decoder, uint32_t rw, uint32_t rh) {
182     decoder->options.resize_width = rw;
183     decoder->options.resize_height = rh;
184     decoder->options.fit = 1;
185 }
186 
flif_decoder_set_callback(FLIF_DECODER * decoder,callback_t callback,void * user_data)187 FLIF_DLLEXPORT void FLIF_API flif_decoder_set_callback(FLIF_DECODER* decoder, callback_t callback, void *user_data) {
188     try
189     {
190         decoder->callback = (void*) callback;
191         decoder->user_data = user_data;
192     }
193     catch(...) {}
194 }
195 
flif_decoder_set_first_callback_quality(FLIF_DECODER * decoder,int32_t quality)196 FLIF_DLLEXPORT void FLIF_API flif_decoder_set_first_callback_quality(FLIF_DECODER* decoder, int32_t quality) {
197     try
198     {
199         decoder->first_quality = quality;
200     }
201     catch(...) {}
202 }
203 
204 
205 /*!
206 * \return non-zero if the function succeeded
207 */
flif_decoder_decode_file(FLIF_DECODER * decoder,const char * filename)208 FLIF_DLLEXPORT int32_t FLIF_API flif_decoder_decode_file(FLIF_DECODER* decoder, const char* filename) {
209     try
210     {
211         return decoder->decode_file(filename);
212     }
213     catch(...) {}
214     return 0;
215 }
216 
217 /*!
218  * The filename here is used for error messages.
219  * It would be helpful to pass an actual filename here, but a non-NULL dummy one can be used instead.
220  * \return non-zero if the function succeeded
221  */
flif_decoder_decode_filepointer(FLIF_DECODER * decoder,FILE * filepointer,const char * filename)222 FLIF_DLLEXPORT int32_t FLIF_API flif_decoder_decode_filepointer(FLIF_DECODER* decoder, FILE* filepointer, const char *filename) {
223     try
224     {
225         return decoder->decode_filepointer(filepointer, filename);
226     }
227     catch(...) {}
228     return 0;
229 }
230 
231 /*!
232 * \return non-zero if the function succeeded
233 */
flif_decoder_decode_memory(FLIF_DECODER * decoder,const void * buffer,size_t buffer_size_bytes)234 FLIF_DLLEXPORT int32_t FLIF_API flif_decoder_decode_memory(FLIF_DECODER* decoder, const void* buffer, size_t buffer_size_bytes) {
235     try
236     {
237         return decoder->decode_memory(buffer, buffer_size_bytes);
238     }
239     catch(...) {}
240     return 0;
241 }
242 
flif_decoder_num_images(FLIF_DECODER * decoder)243 FLIF_DLLEXPORT size_t FLIF_API flif_decoder_num_images(FLIF_DECODER* decoder) {
244     try
245     {
246         return decoder->num_images();
247     }
248     catch(...) {}
249     return 0;
250 }
251 
flif_decoder_num_loops(FLIF_DECODER * decoder)252 FLIF_DLLEXPORT int32_t FLIF_API flif_decoder_num_loops(FLIF_DECODER* decoder) {
253     try
254     {
255         return decoder->num_loops();
256     }
257     catch(...) {}
258     return 0;
259 }
260 
flif_decoder_get_image(FLIF_DECODER * decoder,size_t index)261 FLIF_DLLEXPORT FLIF_IMAGE* FLIF_API flif_decoder_get_image(FLIF_DECODER* decoder, size_t index) {
262     try
263     {
264         return decoder->get_image(index);
265     }
266     catch(...) {}
267     return 0;
268 }
269 
flif_decoder_generate_preview(void * context)270 FLIF_DLLEXPORT void FLIF_API flif_decoder_generate_preview(void *context) {
271     try
272     {
273         auto func = (std::function<void ()> *) context;
274         (*func)();
275     }
276     catch(...) {}
277 }
278 
279 
flif_read_info_from_memory(const void * buffer,size_t buffer_size_bytes)280 FLIF_DLLEXPORT FLIF_INFO* FLIF_API flif_read_info_from_memory(const void* buffer, size_t buffer_size_bytes) {
281     try
282     {
283         std::unique_ptr<FLIF_INFO> info(new FLIF_INFO());
284 
285         BlobReader reader(reinterpret_cast<const uint8_t*>(buffer), buffer_size_bytes);
286 
287         callback_t callback = NULL;
288         void *user_data = NULL;
289         int first_quality = 0;
290         Images images;
291 
292         metadata_options md_default = {
293             true, // icc
294             true, // exif
295             true, // xmp
296         };
297         flif_options options = FLIF_DEFAULT_OPTIONS;
298 
299         if(flif_decode(reader, images, reinterpret_cast<callback_t>(callback), user_data, first_quality, images, options, md_default, info.get()))
300         {
301             return info.release();
302         }
303     }
304     catch(...) {}
305     return 0;
306 }
307 
flif_destroy_info(FLIF_INFO * info)308 FLIF_DLLEXPORT void FLIF_API flif_destroy_info(FLIF_INFO* info) {
309     try
310     {
311         delete info;
312     }
313     catch(...) {}
314 }
315 
flif_info_get_width(FLIF_INFO * info)316 FLIF_DLLEXPORT uint32_t FLIF_API flif_info_get_width(FLIF_INFO* info) {
317     try
318     {
319         return info->width;
320     }
321     catch(...) {}
322     return 0;
323 }
324 
flif_info_get_height(FLIF_INFO * info)325 FLIF_DLLEXPORT uint32_t FLIF_API flif_info_get_height(FLIF_INFO* info) {
326     try
327     {
328         return info->height;
329     }
330     catch(...) {}
331     return 0;
332 }
333 
flif_info_get_nb_channels(FLIF_INFO * info)334 FLIF_DLLEXPORT uint8_t FLIF_API flif_info_get_nb_channels(FLIF_INFO* info) {
335     try
336     {
337         return info->channels;
338     }
339     catch(...) {}
340     return 0;
341 }
342 
flif_info_get_depth(FLIF_INFO * info)343 FLIF_DLLEXPORT uint8_t FLIF_API flif_info_get_depth(FLIF_INFO* info) {
344     try
345     {
346         return info->bit_depth;
347     }
348     catch(...) {}
349     return 0;
350 }
351 
flif_info_num_images(FLIF_INFO * info)352 FLIF_DLLEXPORT size_t FLIF_API flif_info_num_images(FLIF_INFO* info) {
353     try
354     {
355         return info->num_images;
356     }
357     catch(...) {}
358     return 0;
359 }
360 
361 
362 } // extern "C"
363