Prevent unintentional progress
[platform/core/multimedia/libmm-utility.git] / magick / mm_util_magick.c
1 /*
2  * libmm-utility
3  *
4  * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved.
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
20 #include <glib.h>
21 #include <glib/gstdio.h>
22 #include <unistd.h>
23
24 #include <magick/api.h>
25
26 #include "mm_util_private.h"
27 #include "mm_util_magick.h"
28
29
30 static bool __mm_util_check_rotation(mm_util_rotate_type_e rotation);
31 static void __mm_util_magick_fatal_error_handler(const ExceptionType excep, const char *reason, const char *message) MAGICK_FUNC_NORETURN;
32
33 static void __mm_util_magick_log_method(const ExceptionType excep, const char *message)
34 {
35         /* To exclude time, user time and pid */
36         unsigned int start_idx = 31;
37
38         if ((message == NULL) || (strlen(message) < start_idx)) {
39                 start_idx = 0;
40         }
41
42         if (excep >= ErrorException)
43                 mm_util_error("[GM][Ex:%3u] %s", excep, message + start_idx);
44         else if (excep >= WarningException)
45                 mm_util_warn("[GM][Ex:%3u] %s", excep, message + start_idx);
46         else
47                 mm_util_debug("[GM][Ex:%3u] %s", excep, message + start_idx);
48 }
49
50 static void __mm_util_magick_error_handler(const ExceptionType excep, const char *reason, const char *message)
51 {
52         if (excep >= ErrorException)
53                 mm_util_error("[GM][Ex:%3u][Rs:%s] %s", excep, reason, message);
54         else
55                 mm_util_warn("[GM][Ex:%3u][Rs:%s] %s", excep, reason, message);
56 }
57
58 static void __mm_util_magick_fatal_error_handler(const ExceptionType excep, const char *reason, const char *message)
59 {
60         if (excep >= ErrorException)
61                 mm_util_error("[GM][Ex:%3u][Rs:%s] %s", excep, reason, message);
62         else
63                 mm_util_warn("[GM][Ex:%3u][Rs:%s] %s", excep, reason, message);
64
65         exit(1);
66 }
67
68 static void __mm_util_init(ExceptionInfo *exception)
69 {
70         InitializeMagick(NULL);
71         if (exception != NULL)
72                 GetExceptionInfo(exception);
73
74         /* set LogEventMask to show like "all" or "warning, error" */
75         /* <LogEventMask List>
76          * "none", "information", "warning", "error", "fatalerror", "configure", "annotate",
77          * "render", "transform", "locale", "coder", "x11", "cache", "blob", "deprecate",
78          * "user", "resource", "temporaryfile", "exception", "option", "all"
79          */
80 #if (GMAGICK_DEBUG == 1)
81         SetLogEventMask("all");
82 #else
83         SetLogEventMask("warning, error, fatalerror, exception, coder");
84 #endif
85         SetLogMethod(__mm_util_magick_log_method);
86         SetErrorHandler(__mm_util_magick_error_handler);
87         SetFatalErrorHandler(__mm_util_magick_fatal_error_handler);
88         SetWarningHandler(__mm_util_magick_error_handler);
89 }
90
91 static void __mm_util_finalize(Image *image_1, Image *image_2, ExceptionInfo *exception)
92 {
93
94         DestroyImageList(image_1);
95         DestroyImageList(image_2);
96
97         if (exception != NULL)
98                 DestroyExceptionInfo(exception);
99
100         DestroyMagick();
101 }
102
103 static const char * __mm_util_get_map(mm_util_color_format_e format)
104 {
105
106         switch (format) {
107         case MM_UTIL_COLOR_RGB24:
108                 return "RGB";
109         case MM_UTIL_COLOR_ARGB:
110                 return "ARGB";
111         case MM_UTIL_COLOR_BGRA:
112                 return "BGRA";
113         case MM_UTIL_COLOR_RGBA:
114                 return "RGBA";
115         default:
116                 mm_util_error("Not supported format. [%d]", format);
117                 return NULL;
118         }
119 }
120
121 static int __mm_util_constitute_image(mm_util_image_h handle, Image **image)
122 {
123         int ret = MM_UTIL_ERROR_NONE;
124         mm_image_info_s *_handle = (mm_image_info_s*)handle;
125         const char *map = NULL;
126         Image *_image = NULL;
127         ExceptionInfo exception;
128
129         mm_util_fenter();
130
131         mm_util_retvm_if(!handle, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid handle");
132         mm_util_retvm_if(!image, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid image");
133
134         map = __mm_util_get_map(_handle->color);
135         mm_util_retvm_if(!map, MM_UTIL_ERROR_INVALID_PARAMETER, "fail to get map");
136
137         GetExceptionInfo(&exception);
138
139         /* Read image from buffer */
140         _image = ConstituteImage(_handle->width, _handle->height, map, CharPixel, _handle->data, &exception);
141         if (_image) {
142                 *image = _image;
143         } else {
144                 mm_util_error("Error: Getting Image failed.");
145                 if (exception.severity != UndefinedException)
146                         CatchException(&exception);
147                 ret = MM_UTIL_ERROR_INVALID_OPERATION;
148         }
149
150         DestroyExceptionInfo(&exception);
151
152         mm_util_fleave();
153
154         return ret;
155 }
156
157 static int __mm_util_rotate_image(Image *image, mm_util_rotate_type_e rotation, Image **rotated_image)
158 {
159         int ret = MM_UTIL_ERROR_NONE;
160         Image *_processed_image = NULL;
161         ExceptionInfo exception;
162
163         mm_util_fenter();
164
165         mm_util_retvm_if(!image, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid image");
166         mm_util_retvm_if(!__mm_util_check_rotation(rotation), MM_UTIL_ERROR_INVALID_PARAMETER, "invalid rotation [%d]", rotation);
167         mm_util_retvm_if(!rotated_image, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid rotated_image");
168
169         GetExceptionInfo(&exception);
170
171         switch (rotation) {
172         case MM_UTIL_ROTATE_0:
173         case MM_UTIL_ROTATE_90:
174         case MM_UTIL_ROTATE_180:
175         case MM_UTIL_ROTATE_270:
176                 /*
177                  RotateImage(const Image *image,const double degrees, ExceptionInfo *exception)
178                  degrees: Specifies the number of degrees to rotate the image.
179                  degrees is rotation multiplied by 90.
180                 */
181                 _processed_image = RotateImage(image, (rotation * 90), &exception);
182                 break;
183         case MM_UTIL_ROTATE_FLIP_HORZ:
184                 _processed_image = FlopImage(image, &exception);
185                 break;
186         case MM_UTIL_ROTATE_FLIP_VERT:
187                 _processed_image = FlipImage(image, &exception);
188                 break;
189         default:
190                 mm_util_error("Invalid rotation. [%d]", rotation);
191                 break;
192         }
193
194         if (_processed_image) {
195                 *rotated_image = _processed_image;
196         } else {
197                 mm_util_error("Error: Image processing failed.");
198                 if (exception.severity != UndefinedException)
199                         CatchException(&exception);
200                 ret = MM_UTIL_ERROR_INVALID_OPERATION;
201         }
202
203         DestroyExceptionInfo(&exception);
204
205         mm_util_fleave();
206
207         return ret;
208 }
209
210 static int __mm_util_resize_image(Image *image, unsigned int width, unsigned int height, Image **resized_image)
211 {
212         int ret = MM_UTIL_ERROR_NONE;
213         Image *_processed_image = NULL;
214         Image *_sampled_image = NULL;
215         ExceptionInfo exception;
216         unsigned long check_factor = 3;
217         unsigned long sample_factor = 2;
218
219         mm_util_fenter();
220
221         mm_util_retvm_if(!image, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid image");
222         mm_util_retvm_if(width == 0 || height == 0, MM_UTIL_ERROR_INVALID_PARAMETER,
223                                 "invalid request[%u * %u]", width, height);
224         mm_util_retvm_if((image->columns < width) || (image->rows < height), MM_UTIL_ERROR_INVALID_PARAMETER,
225                                 "request[%u * %u] is larger than image [%lu * %lu]", width, height, image->columns, image->rows);
226         mm_util_retvm_if(!resized_image, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid resized_image");
227
228         GetExceptionInfo(&exception);
229
230         if ((image->columns > width * check_factor) && (image->rows > height * check_factor)) {
231                 _sampled_image = SampleImage(image, width * sample_factor, height * sample_factor, &exception);
232                 if (_sampled_image == (Image *) NULL)
233                         mm_util_error("Error: Sampling Image failed.");
234         }
235
236         if (_sampled_image != NULL)
237                 _processed_image = ScaleImage(_sampled_image, width, height, &exception);
238         else
239                 _processed_image = ScaleImage(image, width, height, &exception);
240
241         if (_processed_image) {
242                 *resized_image = _processed_image;
243         } else {
244                 mm_util_error("Error: Resizing Image failed.");
245                 if (exception.severity != UndefinedException)
246                         CatchException(&exception);
247                 ret = MM_UTIL_ERROR_INVALID_OPERATION;
248         }
249
250         DestroyImageList(_sampled_image);
251
252         DestroyExceptionInfo(&exception);
253
254         mm_util_fleave();
255
256         return ret;
257 }
258
259 static Image * __mm_util_read_image(ImageInfo *image_info)
260 {
261         Image *_image = NULL;
262         ExceptionInfo exception;
263
264         mm_util_fenter();
265
266         mm_util_retvm_if(!image_info, NULL, "invalid image_info");
267
268         GetExceptionInfo(&exception);
269
270         AddDefinition(image_info, "jpeg", "dct-method", "FASTEST", &exception);
271         AddDefinition(image_info, "jpeg", "block-smoothing", "FALSE", &exception);
272         AddDefinition(image_info, "jpeg", "fancy-upsampling", "FALSE", &exception);
273
274         _image = ReadImage(image_info, &exception);
275         if (!_image) {
276                 mm_util_error("Error: Reading Image failed.");
277                 if (exception.severity != UndefinedException)
278                         CatchException(&exception);
279         }
280
281         DestroyExceptionInfo(&exception);
282
283         mm_util_fleave();
284
285         return _image;
286 }
287
288 static int __mm_util_read_image_from_file(const char *path, Image **image)
289 {
290         ImageInfo *_image_info = NULL;
291         Image *_image = NULL;
292
293         mm_util_fenter();
294
295         mm_util_retvm_if(!MMUTIL_STRING_VALID(path), MM_UTIL_ERROR_INVALID_PARAMETER, "invalid path");
296         mm_util_retvm_if(!image, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid image");
297
298         _image_info = CloneImageInfo(0);
299         mm_util_retvm_if(!_image_info, MM_UTIL_ERROR_INVALID_OPERATION, "Error: CloneImageInfo failed.");
300         g_strlcpy(_image_info->filename, path, sizeof(_image_info->filename));
301
302         _image = __mm_util_read_image(_image_info);
303         DestroyImageInfo(_image_info);
304         if (!_image) {
305                 mm_util_error("Error: __mm_util_read_image failed.");
306                 return MM_UTIL_ERROR_INVALID_OPERATION;
307         }
308         *image = _image;
309
310         mm_util_fleave();
311
312         return MM_UTIL_ERROR_NONE;
313 }
314
315 static int __mm_util_read_image_from_buffer(const void *buf, size_t buf_size, Image **image)
316 {
317         ImageInfo *_image_info = NULL;
318         Image *_image = NULL;
319
320         mm_util_fenter();
321
322         mm_util_retvm_if(!buf, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid buf");
323         mm_util_retvm_if(buf_size == 0, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid buf_size");
324         mm_util_retvm_if(!image, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid image");
325
326         _image_info = CloneImageInfo(0);
327         mm_util_retvm_if(!_image_info, MM_UTIL_ERROR_INVALID_OPERATION, "Error: CloneImageInfo failed.");
328         _image_info->blob = (void *)buf;
329         _image_info->length = buf_size;
330
331         _image = __mm_util_read_image(_image_info);
332         DestroyImageInfo(_image_info);
333         if (!_image) {
334                 mm_util_error("Error: __mm_util_read_image failed.");
335                 return MM_UTIL_ERROR_INVALID_OPERATION;
336         }
337         *image = _image;
338
339         mm_util_fleave();
340
341         return MM_UTIL_ERROR_NONE;
342 }
343
344 static int __mm_util_write_image_to_file(Image *image, mm_util_enc_opt_t *option, const char *out_path)
345 {
346         int ret = MM_UTIL_ERROR_NONE;
347         ImageInfo *_image_info = NULL;
348         ExceptionInfo exception;
349
350         mm_util_fenter();
351
352         mm_util_retvm_if(!image, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid image");
353         mm_util_retvm_if(!MMUTIL_STRING_VALID(out_path), MM_UTIL_ERROR_INVALID_PARAMETER, "invalid out_path");
354
355         if (g_strlcpy(image->filename, out_path, sizeof(image->filename)) >= MaxTextExtent) {
356                 mm_util_error("Error: truncation occurred");
357                 return MM_UTIL_ERROR_INVALID_OPERATION;
358         }
359
360         GetExceptionInfo(&exception);
361
362         _image_info = CloneImageInfo(0);
363         mm_util_retvm_if(!_image_info, MM_UTIL_ERROR_INVALID_OPERATION, "Error: CloneImageInfo failed.");
364
365         DeleteImageProfile(image, "EXIF");
366         DeleteImageProfile(image, "8BIM");
367         DeleteImageProfile(image, "ICM");
368         DeleteImageProfile(image, "IPTC");
369         DeleteImageProfile(image, "XMP");
370
371         if (option) {
372                 switch (option->codec) {
373                 case IMG_CODEC_JPEG:
374                         AddDefinition(_image_info, "jpeg", "dct-method", "FASTEST", &exception);
375                         AddDefinition(_image_info, "jpeg", "optimize-coding", "FALSE", &exception);
376                         break;
377
378                 case IMG_CODEC_PNG:
379                         mm_util_sec_debug("PNG compression: %d", option->compression);
380                         _image_info->quality = option->compression * 10;
381                         break;
382
383                 case IMG_CODEC_WEBP:
384                         mm_util_sec_debug("WEBP lossless: %s", (option->lossless ? "TRUE" : "FALSE"));
385                         AddDefinition(_image_info, "webp", "lossless", (option->lossless ? "TRUE" : "FALSE"), &exception);
386                         break;
387
388                 case IMG_CODEC_GIF:
389                         /* fall through */
390                 case IMG_CODEC_BMP:
391                         /* fall through */
392                 case IMG_CODEC_WBMP:
393                         break;
394
395                 default:
396                         mm_util_error("invalid codec [%d]", option->codec);
397                         break;
398                 }
399         }
400
401         if (WriteImage(_image_info, image) == MagickFalse) {
402                 mm_util_error("Error: Writing Image failed.");
403                 if (exception.severity != UndefinedException)
404                         CatchException(&exception);
405
406                 ret = MM_UTIL_ERROR_INVALID_OPERATION;
407         }
408
409         DestroyImageInfo(_image_info);
410         DestroyExceptionInfo(&exception);
411
412         mm_util_fleave();
413
414         return ret;
415 }
416
417 static int __mm_util_dispatch_image(Image *image, mm_util_color_format_e format, mm_util_image_h *dispatched_image)
418 {
419         int ret = MM_UTIL_ERROR_NONE;
420         ExceptionInfo exception;
421         size_t pixels_size = 0;
422         void *pixels = NULL;
423         unsigned int width = 0;
424         unsigned int height = 0;
425         const char *map = NULL;
426
427         mm_util_fenter();
428
429         mm_util_retvm_if(!image, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid image");
430
431         map = __mm_util_get_map(format);
432         mm_util_retvm_if(!map, MM_UTIL_ERROR_INVALID_PARAMETER, "fail to get map");
433
434         GetExceptionInfo(&exception);
435
436         width = image->columns;
437         height = image->rows;
438
439         pixels_size = sizeof(unsigned char) * strlen(map) * width * height;
440         pixels = MagickMalloc(pixels_size);
441
442         if (!pixels) {
443                 mm_util_error("Error: MagickMalloc failed.");
444                 ret = MM_UTIL_ERROR_OUT_OF_MEMORY;
445                 goto END;
446         }
447
448         ret = DispatchImage(image, 0, 0, width, height, map, CharPixel, pixels, &exception);
449         if (ret == MagickFail) {
450                 mm_util_error("Failed to Dispatch Image into dst buffer");
451                 if (exception.severity != UndefinedException)
452                         CatchException(&exception);
453
454                 MagickFree(pixels);
455                 ret = MM_UTIL_ERROR_INVALID_OPERATION;
456                 goto END;
457         }
458
459         ret = mm_image_create_image(width, height, format, pixels, pixels_size, dispatched_image);
460         if (ret != MM_UTIL_ERROR_NONE)
461                 mm_util_error("Error: mm_image_create_image failed.");
462
463         MagickFree(pixels);
464
465 END:
466
467         DestroyExceptionInfo(&exception);
468
469         mm_util_fleave();
470
471         return ret;
472 }
473
474 static bool __mm_util_check_rotation(mm_util_rotate_type_e rotation)
475 {
476         switch (rotation) {
477         case MM_UTIL_ROTATE_0:
478         case MM_UTIL_ROTATE_90:
479         case MM_UTIL_ROTATE_180:
480         case MM_UTIL_ROTATE_270:
481         case MM_UTIL_ROTATE_FLIP_HORZ:
482         case MM_UTIL_ROTATE_FLIP_VERT:
483                 return true;
484         default:
485                 return false;
486         }
487 }
488
489 static int __mm_util_make_tmp_file(mm_util_img_codec_type type, char **path)
490 {
491         int fd = 0;
492         const char *template = NULL;
493         GError *error = NULL;
494
495         /* GraphicsMagick determine image codec from file extension */
496         switch(type) {
497         case IMG_CODEC_GIF:
498                 template = "XXXXXX.gif";
499                 break;
500         case IMG_CODEC_PNG:
501                 template = "XXXXXX.png";
502                 break;
503         case IMG_CODEC_JPEG:
504                 template = "XXXXXX.jpg";
505                 break;
506         case IMG_CODEC_BMP:
507                 template = "XXXXXX.bmp";
508                 break;
509         case IMG_CODEC_WEBP:
510                 template = "XXXXXX.webp";
511                 break;
512         default:
513                 mm_util_error("invalid type [%u]", type);
514                 return MM_UTIL_ERROR_INVALID_PARAMETER;
515         }
516
517         fd = g_file_open_tmp(template, path, &error);
518         if (fd < 0) {
519                 mm_util_sec_debug("g_file_open_tmp error [%s]", (error ? error->message : "none"));
520                 g_error_free(error);
521                 return MM_UTIL_ERROR_INVALID_OPERATION;
522         }
523
524         mm_util_sec_debug("g_file_open_tmp [%s]", *path);
525
526         close(fd);
527
528         return MM_UTIL_ERROR_NONE;
529 }
530
531 int mm_util_rotate_B_B(mm_util_image_h src_handle, mm_util_rotate_type_e rotation, mm_util_image_h *dst_handle)
532 {
533         int ret = MM_UTIL_ERROR_NONE;
534         mm_image_info_s *_src_handle = (mm_image_info_s*)src_handle;
535         Image *_image = NULL;
536         Image *_processed_image = NULL;
537         ExceptionInfo exception;
538
539         mm_util_debug("rotation [%d]", rotation);
540
541         __mm_util_init(&exception);
542
543         ret = __mm_util_constitute_image(src_handle, &_image);
544         if (ret != MM_UTIL_ERROR_NONE) {
545                 mm_util_error("Error: __mm_util_constitute_image failed.");
546                 goto END;
547         }
548
549         ret = __mm_util_rotate_image(_image, rotation, &_processed_image);
550         if (ret != MM_UTIL_ERROR_NONE) {
551                 mm_util_error("Error: __mm_util_rotate_image failed.");
552                 goto END;
553         }
554
555         ret = __mm_util_dispatch_image(_processed_image, _src_handle->color, dst_handle);
556
557 END:
558
559         __mm_util_finalize(_image, _processed_image, &exception);
560
561         mm_util_fleave();
562
563         return ret;
564 }
565
566 int mm_util_rotate_B_P(mm_util_image_h src_handle, mm_util_rotate_type_e rotation, const char *dst_path)
567 {
568         int ret = MM_UTIL_ERROR_NONE;
569         Image *_image = NULL;
570         Image *_processed_image = NULL;
571         ExceptionInfo exception;
572
573         mm_util_sec_debug("rotation [%d] dst_path [%s]", rotation, dst_path);
574
575         __mm_util_init(&exception);
576
577         ret = __mm_util_constitute_image(src_handle, &_image);
578         if (ret != MM_UTIL_ERROR_NONE) {
579                 mm_util_error("Error: __mm_util_constitute_image failed.");
580                 goto END;
581         }
582
583         ret = __mm_util_rotate_image(_image, rotation, &_processed_image);
584         if (ret != MM_UTIL_ERROR_NONE) {
585                 mm_util_error("Error: __mm_util_rotate_image failed.");
586                 goto END;
587         }
588
589         ret = __mm_util_write_image_to_file(_processed_image, NULL, dst_path);
590
591 END:
592
593         __mm_util_finalize(_image, _processed_image, &exception);
594
595         mm_util_fleave();
596
597         return ret;
598 }
599
600 int mm_util_rotate_P_B(const char *src_path, mm_util_rotate_type_e rotation, mm_util_color_format_e req_format, mm_util_image_h *dst_handle)
601 {
602         int ret = MM_UTIL_ERROR_NONE;
603         Image *_image = NULL;
604         Image *_processed_image = NULL;
605         ExceptionInfo exception;
606
607         mm_util_sec_debug("src_path [%s] rotation [%d] req_format [%d]", src_path, rotation, req_format);
608
609         __mm_util_init(&exception);
610
611         ret = __mm_util_read_image_from_file(src_path, &_image);
612         if (ret != MM_UTIL_ERROR_NONE) {
613                 mm_util_error("Error: __mm_util_read_image_from_file failed.");
614                 goto END;
615         }
616
617         ret = __mm_util_rotate_image(_image, rotation, &_processed_image);
618         if (ret != MM_UTIL_ERROR_NONE) {
619                 mm_util_error("Error: __mm_util_rotate_image failed.");
620                 goto END;
621         }
622
623         ret = __mm_util_dispatch_image(_processed_image, req_format, dst_handle);
624
625 END:
626
627         __mm_util_finalize(_image, _processed_image, &exception);
628
629         mm_util_fleave();
630
631         return ret;
632 }
633
634
635 int mm_util_rotate_P_P(const char *src_path, mm_util_rotate_type_e rotation, const char *dst_path)
636 {
637         int ret = MM_UTIL_ERROR_NONE;
638         Image *_image = NULL;
639         Image *_processed_image = NULL;
640         ExceptionInfo exception;
641
642         __mm_util_init(&exception);
643
644         ret = __mm_util_read_image_from_file(src_path, &_image);
645         if (ret != MM_UTIL_ERROR_NONE) {
646                 mm_util_error("Error: __mm_util_read_image_from_file failed.");
647                 goto END;
648         }
649
650         ret = __mm_util_rotate_image(_image, rotation, &_processed_image);
651         if (ret != MM_UTIL_ERROR_NONE) {
652                 mm_util_error("Error: __mm_util_rotate_image failed.");
653                 goto END;
654         }
655
656         ret = __mm_util_write_image_to_file(_processed_image, NULL, dst_path);
657
658 END:
659
660         __mm_util_finalize(_image, _processed_image, &exception);
661
662         mm_util_fleave();
663
664         return ret;
665 }
666
667 int mm_util_resize_B_B(mm_util_image_h src_handle, unsigned int req_width, unsigned int req_height, mm_util_image_h *dst_handle)
668 {
669         int ret = MM_UTIL_ERROR_NONE;
670         mm_image_info_s *_src_handle = (mm_image_info_s*)src_handle;
671         Image *_image = NULL;
672         Image *_processed_image = NULL;
673         ExceptionInfo exception;
674
675         mm_util_debug("req_width [%u] req_height [%u]", req_width, req_height);
676
677         __mm_util_init(&exception);
678
679         ret = __mm_util_constitute_image(src_handle, &_image);
680         if (ret != MM_UTIL_ERROR_NONE) {
681                 mm_util_error("Error: __mm_util_constitute_image failed.");
682                 goto END;
683         }
684
685         ret = __mm_util_resize_image(_image, req_width, req_height, &_processed_image);
686         if (ret != MM_UTIL_ERROR_NONE) {
687                 mm_util_error("Error: __mm_util_resize_image failed.");
688                 goto END;
689         }
690
691         ret = __mm_util_dispatch_image(_processed_image, _src_handle->color, dst_handle);
692
693 END:
694
695         __mm_util_finalize(_image, _processed_image, &exception);
696
697         mm_util_fleave();
698
699         return ret;
700 }
701
702 int mm_util_resize_B_P(mm_util_image_h src_handle, unsigned int req_width, unsigned int req_height, const char *dst_path)
703 {
704         int ret = MM_UTIL_ERROR_NONE;
705         Image *_image = NULL;
706         Image *_processed_image = NULL;
707         ExceptionInfo exception;
708
709         mm_util_sec_debug("req_width [%u] req_height [%u] dst_path [%s]", req_width, req_height, dst_path);
710
711         __mm_util_init(&exception);
712
713         ret = __mm_util_constitute_image(src_handle, &_image);
714         if (ret != MM_UTIL_ERROR_NONE) {
715                 mm_util_error("Error: __mm_util_constitute_image failed.");
716                 goto END;
717         }
718
719         ret = __mm_util_resize_image(_image, req_width, req_height, &_processed_image);
720         if (ret != MM_UTIL_ERROR_NONE) {
721                 mm_util_error("Error: __mm_util_resize_image failed.");
722                 goto END;
723         }
724
725         ret = __mm_util_write_image_to_file(_processed_image, NULL, dst_path);
726
727 END:
728
729         __mm_util_finalize(_image, _processed_image, &exception);
730
731         mm_util_fleave();
732
733         return ret;
734 }
735
736 int mm_util_resize_P_B(const char *src_path, unsigned int req_width, unsigned int req_height, mm_util_color_format_e req_format, mm_util_image_h *dst_handle)
737 {
738         int ret = MM_UTIL_ERROR_NONE;
739         Image *_image = NULL;
740         Image *_processed_image = NULL;
741         ExceptionInfo exception;
742
743         mm_util_sec_debug("src_path [%s] req_width [%u] req_height [%u]", src_path, req_width, req_height);
744
745         __mm_util_init(&exception);
746
747         ret = __mm_util_read_image_from_file(src_path, &_image);
748         if (ret != MM_UTIL_ERROR_NONE) {
749                 mm_util_error("Error: __mm_util_read_image_from_file failed.");
750                 goto END;
751         }
752
753         ret = __mm_util_resize_image(_image, req_width, req_height, &_processed_image);
754         if (ret != MM_UTIL_ERROR_NONE) {
755                 mm_util_error("Error: __mm_util_resize_image failed.");
756                 goto END;
757         }
758
759         ret = __mm_util_dispatch_image(_processed_image, req_format, dst_handle);
760
761 END:
762
763         __mm_util_finalize(_image, _processed_image, &exception);
764
765         mm_util_fleave();
766
767         return ret;
768 }
769
770 int mm_util_resize_P_P(const char *src_path, unsigned int req_width, unsigned int req_height, const char *dst_path)
771 {
772         int ret = MM_UTIL_ERROR_NONE;
773         Image *_image = NULL;
774         Image *_processed_image = NULL;
775         ExceptionInfo exception;
776
777         mm_util_sec_debug("src_path [%s] req_width [%u] req_height [%u] dst_path [%s]", src_path, req_width, req_height, dst_path);
778
779         __mm_util_init(&exception);
780
781         ret = __mm_util_read_image_from_file(src_path, &_image);
782         if (ret != MM_UTIL_ERROR_NONE) {
783                 mm_util_error("Error: __mm_util_read_image_from_file failed.");
784                 goto END;
785         }
786
787         ret = __mm_util_resize_image(_image, req_width, req_height, &_processed_image);
788         if (ret != MM_UTIL_ERROR_NONE) {
789                 mm_util_error("Error: __mm_util_resize_image failed.");
790                 goto END;
791         }
792
793         ret = __mm_util_write_image_to_file(_processed_image, NULL, dst_path);
794
795 END:
796
797         __mm_util_finalize(_image, _processed_image, &exception);
798
799         mm_util_fleave();
800
801         return ret;
802 }
803
804 int mm_util_convert_B_B(mm_util_image_h src_handle, mm_util_color_format_e req_format, mm_util_image_h *dst_handle)
805 {
806         int ret = MM_UTIL_ERROR_NONE;
807         mm_image_info_s *_src_handle = (mm_image_info_s*)src_handle;
808         Image *_image = NULL;
809         ExceptionInfo exception;
810
811         mm_util_debug("input format [%d] req_format [%d]", _src_handle->color, req_format);
812
813         __mm_util_init(&exception);
814
815         ret = __mm_util_constitute_image(src_handle, &_image);
816         if (ret != MM_UTIL_ERROR_NONE) {
817                 mm_util_error("Error: __mm_util_constitute_image failed.");
818                 goto END;
819         }
820
821         ret = __mm_util_dispatch_image(_image, req_format, dst_handle);
822
823 END:
824
825         __mm_util_finalize(_image, NULL, &exception);
826
827         mm_util_fleave();
828
829         return ret;
830 }
831
832 int mm_util_decode_image_from_file(const char *path, mm_util_color_format_e format, mm_util_image_h *decoded_image)
833 {
834         int ret = MM_UTIL_ERROR_NONE;
835         Image *_image = NULL;
836
837         mm_util_sec_debug("path [%s] format [%d]", path, format);
838
839         __mm_util_init(NULL);
840
841         ret = __mm_util_read_image_from_file(path, &_image);
842         if (ret != MM_UTIL_ERROR_NONE) {
843                 mm_util_error("Error: __mm_util_read_image_from_file failed.");
844                 goto END;
845         }
846
847         ret = __mm_util_dispatch_image(_image, format, decoded_image);
848
849 END:
850
851         __mm_util_finalize(_image, NULL, NULL);
852
853         mm_util_fleave();
854
855         return ret;
856 }
857
858 int mm_util_decode_image_from_buffer(const void *buf, size_t buf_size, mm_util_color_format_e format, mm_util_image_h *decoded_image)
859 {
860         int ret = MM_UTIL_ERROR_NONE;
861         Image *_image = NULL;
862
863         mm_util_sec_debug("path [%p] buf_size [%zu] format [%d]", buf, buf_size, format);
864
865         __mm_util_init(NULL);
866
867         ret = __mm_util_read_image_from_buffer(buf, buf_size, &_image);
868         if (ret != MM_UTIL_ERROR_NONE) {
869                 mm_util_error("Error: __mm_util_read_image_from_buffer failed.");
870                 goto END;
871         }
872
873         ret = __mm_util_dispatch_image(_image, format, decoded_image);
874
875 END:
876
877         __mm_util_finalize(_image, NULL, NULL);
878
879         mm_util_fleave();
880
881         return ret;
882 }
883
884 int mm_util_encode_image_to_file(mm_util_image_h decoded_image, mm_util_enc_opt_h opt, const char *path)
885 {
886         int ret = MM_UTIL_ERROR_NONE;
887         Image *_image = NULL;
888         mm_util_image_h converted_image = NULL, source = NULL;
889         mm_util_enc_opt_t *_opt = (mm_util_enc_opt_t *)opt;
890
891         mm_util_retvm_if(!_opt, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid opt");
892
893         mm_util_sec_debug("path [%s]", path);
894
895         if (_opt->codec == IMG_CODEC_BMP) {
896                 /*
897                   GraphicsMagick doesn't support alpha overlay(compression method:BI_ALPHABITFIELDS) for bmp.
898                   Officially BMP format supports alpha overlay since BMP4(version 4), but GraphicsMagick
899                   support BMP, BMP2(v2) and BMP3(v3) except BMP4.
900                   So decoded_image should be converted to RGB888(RGB24) which has not alpha overlay.
901                   ps. BMP4 image does not guarantee backward compatibility. BMP4 is not visible on old devices.
902                   For the reasons, BMP4 is used in certain cases of windows OS, not widely used in general cases.
903                 */
904
905                 if (((mm_image_info_s *)decoded_image)->color == MM_UTIL_COLOR_RGBA) {
906                         ret = mm_util_convert_B_B(decoded_image, MM_UTIL_COLOR_RGB24, &converted_image);
907                         if (ret != MM_UTIL_ERROR_NONE) {
908                                 mm_util_error("Error: mm_util_convert_B_B failed.");
909                                 goto END;
910                         }
911                 }
912         }
913
914         source = (converted_image) ? converted_image : decoded_image;
915
916         __mm_util_init(NULL);
917
918         ret = __mm_util_constitute_image(source, &_image);
919         if (ret != MM_UTIL_ERROR_NONE) {
920                 mm_util_error("Error: __mm_util_constitute_image failed.");
921                 goto END;
922         }
923
924         ret = __mm_util_write_image_to_file(_image, _opt, path);
925
926 END:
927
928         __mm_util_finalize(_image, NULL, NULL);
929
930         mm_image_destroy_image(converted_image);
931
932         mm_util_fleave();
933
934         return ret;
935 }
936
937 int mm_util_encode_image_to_buffer(mm_util_image_h decoded_image, mm_util_enc_opt_h opt, void **buf, size_t *buf_size)
938 {
939         int ret = MM_UTIL_ERROR_NONE;
940         char *tmp_file = NULL;
941
942         mm_util_retvm_if(!opt, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid opt");
943
944         ret = __mm_util_make_tmp_file(((mm_util_enc_opt_t *)opt)->codec, &tmp_file);
945         mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "Error: __mm_util_make_tmp_file failed.");
946
947         ret = mm_util_encode_image_to_file(decoded_image, opt, tmp_file);
948         if (ret != MM_UTIL_ERROR_NONE) {
949                 mm_util_error("Error: mm_util_encode_image_P failed.");
950                 goto END;
951         }
952
953         ret = mm_util_file_read(tmp_file, buf, buf_size);
954         if (ret != MM_UTIL_ERROR_NONE)
955                 mm_util_error("Error: mm_util_file_read failed.");
956
957 END:
958
959         if (g_remove(tmp_file) != 0)
960                 mm_util_sec_debug("Temporary file was not removed [%s]", tmp_file);
961         g_free(tmp_file);
962
963         mm_util_fleave();
964
965         return ret;
966 }
967
968 int mm_util_resize_and_rotate_P_P(const char *src_path, unsigned int req_width, unsigned int req_height, const char *dst_path)
969 {
970         int ret = MM_UTIL_ERROR_NONE;
971         Image *_image = NULL;
972         Image *_resized_image = NULL;
973         Image *_rotated_image = NULL;
974         Image *_write_image = NULL;
975         ExceptionInfo exception;
976         mm_util_rotate_type_e rotation = MM_UTIL_ROTATE_0;
977
978         mm_util_sec_debug("src_path [%s] req_width [%u] req_height [%u] dst_path [%s]", src_path, req_width, req_height, dst_path);
979
980         __mm_util_init(&exception);
981
982         ret = __mm_util_read_image_from_file(src_path, &_image);
983         if (ret != MM_UTIL_ERROR_NONE) {
984                 mm_util_error("Error: __mm_util_read_image_from_file failed.");
985                 goto END;
986         }
987
988         ret = __mm_util_resize_image(_image, req_width, req_height, &_resized_image);
989         DestroyImageList(_image);
990         _image = NULL;
991         if (ret != MM_UTIL_ERROR_NONE) {
992                 mm_util_error("Error: __mm_util_resize_image failed.");
993                 goto END;
994         }
995
996         switch(_resized_image->orientation) {
997         case TopRightOrientation:
998         case RightTopOrientation:
999                 rotation = MM_UTIL_ROTATE_90;
1000                 break;
1001         case BottomRightOrientation:
1002         case RightBottomOrientation:
1003                 rotation = MM_UTIL_ROTATE_180;
1004                 break;
1005         case BottomLeftOrientation:
1006         case LeftBottomOrientation:
1007                 rotation = MM_UTIL_ROTATE_270;
1008                 break;
1009         case TopLeftOrientation:
1010         case LeftTopOrientation:
1011                 break;
1012         default:
1013                 mm_util_warn("Not supported orientation %d. so apply MM_UTIL_ROTATE_0", _resized_image->orientation);
1014                 break;
1015         }
1016
1017         if (rotation != MM_UTIL_ROTATE_0) {
1018                 ret = __mm_util_rotate_image(_resized_image, rotation, &_rotated_image);
1019                 if (ret != MM_UTIL_ERROR_NONE) {
1020                         mm_util_error("Error: __mm_util_rotate_image failed.");
1021                         goto END;
1022                 }
1023         }
1024
1025         _write_image = (_rotated_image) ? _rotated_image : _resized_image;
1026
1027         /* problem. a thumbnail of grayscale image is invisible
1028            add converting grayscale image into rgb(jpeg) or true color(png)
1029            the rgb(jpeg) and true-color(png) are default(else case) value.
1030          */
1031         if (IsGrayImage(_write_image, &exception)) {
1032                 mm_util_info("IsGrayImage, convert image into rgb(jpeg)/true-color(png).");
1033                 _write_image->is_grayscale = MagickFalse;
1034         }
1035
1036         ret = __mm_util_write_image_to_file(_write_image, NULL, dst_path);
1037
1038 END:
1039
1040         __mm_util_finalize(_resized_image, _rotated_image, &exception);
1041
1042         mm_util_fleave();
1043
1044         return ret;
1045 }