4ae41670b63911a69b96841c8a71ed8048211c36
[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         mm_util_img_codec_type codec = IMG_CODEC_JPEG;
350
351         mm_util_fenter();
352
353         mm_util_retvm_if(!image, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid image");
354         mm_util_retvm_if(!MMUTIL_STRING_VALID(out_path), MM_UTIL_ERROR_INVALID_PARAMETER, "invalid out_path");
355
356         if (g_strlcpy(image->filename, out_path, sizeof(image->filename)) >= MaxTextExtent) {
357                 mm_util_error("Error: truncation occurred");
358                 return MM_UTIL_ERROR_INVALID_OPERATION;
359         }
360
361         GetExceptionInfo(&exception);
362
363         _image_info = CloneImageInfo(0);
364         mm_util_retvm_if(!_image_info, MM_UTIL_ERROR_INVALID_OPERATION, "Error: CloneImageInfo failed.");
365
366         DeleteImageProfile(image, "EXIF");
367         DeleteImageProfile(image, "8BIM");
368         DeleteImageProfile(image, "ICM");
369         DeleteImageProfile(image, "IPTC");
370         DeleteImageProfile(image, "XMP");
371
372         if (option)
373                 codec = option->codec;
374
375         switch (codec) {
376         case IMG_CODEC_JPEG:
377                 AddDefinition(_image_info, "jpeg", "dct-method", "FASTEST", &exception);
378                 AddDefinition(_image_info, "jpeg", "optimize-coding", "FALSE", &exception);
379                 break;
380
381         case IMG_CODEC_PNG:
382                 mm_util_sec_debug("PNG compression: %d", option->compression);
383                 _image_info->quality = option->compression * 10;
384                 break;
385
386         case IMG_CODEC_WEBP:
387                 mm_util_sec_debug("WEBP lossless: %s", (option->lossless ? "TRUE" : "FALSE"));
388                 AddDefinition(_image_info, "webp", "lossless", (option->lossless ? "TRUE" : "FALSE"), &exception);
389                 break;
390
391         case IMG_CODEC_GIF:
392                 /* fall through */
393         case IMG_CODEC_BMP:
394                 /* fall through */
395         case IMG_CODEC_WBMP:
396                 break;
397
398         default:
399                 mm_util_error("invalid codec [%d]", codec);
400                 break;
401         }
402
403         if (WriteImage (_image_info, image) == MagickFalse) {
404                 mm_util_error("Error: Writing Image failed.");
405                 if (exception.severity != UndefinedException)
406                         CatchException(&exception);
407
408                 ret = MM_UTIL_ERROR_INVALID_OPERATION;
409         }
410
411         DestroyImageInfo(_image_info);
412         DestroyExceptionInfo(&exception);
413
414         mm_util_fleave();
415
416         return ret;
417 }
418
419 static int __mm_util_dispatch_image(Image *image, mm_util_color_format_e format, mm_util_image_h *dispatched_image)
420 {
421         int ret = MM_UTIL_ERROR_NONE;
422         ExceptionInfo exception;
423         size_t pixels_size = 0;
424         void *pixels = NULL;
425         unsigned int width = 0;
426         unsigned int height = 0;
427         const char *map = NULL;
428
429         mm_util_fenter();
430
431         mm_util_retvm_if(!image, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid image");
432
433         map = __mm_util_get_map(format);
434         mm_util_retvm_if(!map, MM_UTIL_ERROR_INVALID_PARAMETER, "fail to get map");
435
436         GetExceptionInfo(&exception);
437
438         width = image->columns;
439         height = image->rows;
440
441         pixels_size = sizeof(unsigned char) * strlen(map) * width * height;
442         pixels = MagickMalloc(pixels_size);
443
444         if (!pixels) {
445                 mm_util_error("Error: MagickMalloc failed.");
446                 ret = MM_UTIL_ERROR_OUT_OF_MEMORY;
447                 goto END;
448         }
449
450         ret = DispatchImage(image, 0, 0, width, height, map, CharPixel, pixels, &exception);
451         if (ret == MagickFail) {
452                 mm_util_error("Failed to Dispatch Image into dst buffer");
453                 if (exception.severity != UndefinedException)
454                         CatchException(&exception);
455
456                 MagickFree(pixels);
457                 ret = MM_UTIL_ERROR_INVALID_OPERATION;
458                 goto END;
459         }
460
461         ret = mm_image_create_image(width, height, format, pixels, pixels_size, dispatched_image);
462         if (ret != MM_UTIL_ERROR_NONE)
463                 mm_util_error("Error: mm_image_create_image failed.");
464
465         MagickFree(pixels);
466
467 END:
468
469         DestroyExceptionInfo(&exception);
470
471         mm_util_fleave();
472
473         return ret;
474 }
475
476 static bool __mm_util_check_rotation(mm_util_rotate_type_e rotation)
477 {
478         switch (rotation) {
479         case MM_UTIL_ROTATE_0:
480         case MM_UTIL_ROTATE_90:
481         case MM_UTIL_ROTATE_180:
482         case MM_UTIL_ROTATE_270:
483         case MM_UTIL_ROTATE_FLIP_HORZ:
484         case MM_UTIL_ROTATE_FLIP_VERT:
485                 return true;
486         default:
487                 return false;
488         }
489 }
490
491 static int __mm_util_make_tmp_file(mm_util_img_codec_type type, char **path)
492 {
493         int fd = 0;
494         const char *template = NULL;
495         GError *error = NULL;
496
497         /* GraphicsMagick determine image codec from file extension */
498         switch(type) {
499         case IMG_CODEC_GIF:
500                 template = "XXXXXX.gif";
501                 break;
502         case IMG_CODEC_PNG:
503                 template = "XXXXXX.png";
504                 break;
505         case IMG_CODEC_JPEG:
506                 template = "XXXXXX.jpg";
507                 break;
508         case IMG_CODEC_BMP:
509                 template = "XXXXXX.bmp";
510                 break;
511         case IMG_CODEC_WEBP:
512                 template = "XXXXXX.webp";
513                 break;
514         default:
515                 mm_util_error("invalid type [%u]", type);
516                 return MM_UTIL_ERROR_INVALID_PARAMETER;
517         }
518
519         fd = g_file_open_tmp(template, path, &error);
520         if (fd < 0) {
521                 mm_util_sec_debug("g_file_open_tmp error [%s]", (error ? error->message : "none"));
522                 g_error_free(error);
523                 return MM_UTIL_ERROR_INVALID_OPERATION;
524         }
525
526         mm_util_sec_debug("g_file_open_tmp [%s]", *path);
527
528         close(fd);
529
530         return MM_UTIL_ERROR_NONE;
531 }
532
533 int mm_util_rotate_B_B(mm_util_image_h src_handle, mm_util_rotate_type_e rotation, mm_util_image_h *dst_handle)
534 {
535         int ret = MM_UTIL_ERROR_NONE;
536         mm_image_info_s *_src_handle = (mm_image_info_s*)src_handle;
537         Image *_image = NULL;
538         Image *_processed_image = NULL;
539         ExceptionInfo exception;
540
541         mm_util_debug("rotation [%d]", rotation);
542
543         __mm_util_init(&exception);
544
545         ret = __mm_util_constitute_image(src_handle, &_image);
546         if (ret != MM_UTIL_ERROR_NONE) {
547                 mm_util_error("Error: __mm_util_constitute_image failed.");
548                 goto END;
549         }
550
551         ret = __mm_util_rotate_image(_image, rotation, &_processed_image);
552         if (ret != MM_UTIL_ERROR_NONE) {
553                 mm_util_error("Error: __mm_util_rotate_image failed.");
554                 goto END;
555         }
556
557         ret = __mm_util_dispatch_image(_processed_image, _src_handle->color, dst_handle);
558
559 END:
560
561         __mm_util_finalize(_image, _processed_image, &exception);
562
563         mm_util_fleave();
564
565         return ret;
566 }
567
568 int mm_util_rotate_B_P(mm_util_image_h src_handle, mm_util_rotate_type_e rotation, const char *dst_path)
569 {
570         int ret = MM_UTIL_ERROR_NONE;
571         Image *_image = NULL;
572         Image *_processed_image = NULL;
573         ExceptionInfo exception;
574
575         mm_util_sec_debug("rotation [%d] dst_path [%s]", rotation, dst_path);
576
577         __mm_util_init(&exception);
578
579         ret = __mm_util_constitute_image(src_handle, &_image);
580         if (ret != MM_UTIL_ERROR_NONE) {
581                 mm_util_error("Error: __mm_util_constitute_image failed.");
582                 goto END;
583         }
584
585         ret = __mm_util_rotate_image(_image, rotation, &_processed_image);
586         if (ret != MM_UTIL_ERROR_NONE) {
587                 mm_util_error("Error: __mm_util_rotate_image failed.");
588                 goto END;
589         }
590
591         ret = __mm_util_write_image_to_file(_processed_image, NULL, dst_path);
592
593 END:
594
595         __mm_util_finalize(_image, _processed_image, &exception);
596
597         mm_util_fleave();
598
599         return ret;
600 }
601
602 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)
603 {
604         int ret = MM_UTIL_ERROR_NONE;
605         Image *_image = NULL;
606         Image *_processed_image = NULL;
607         ExceptionInfo exception;
608
609         mm_util_sec_debug("src_path [%s] rotation [%d] req_format [%d]", src_path, rotation, req_format);
610
611         __mm_util_init(&exception);
612
613         ret = __mm_util_read_image_from_file(src_path, &_image);
614         if (ret != MM_UTIL_ERROR_NONE) {
615                 mm_util_error("Error: __mm_util_read_image_from_file failed.");
616                 goto END;
617         }
618
619         ret = __mm_util_rotate_image(_image, rotation, &_processed_image);
620         if (ret != MM_UTIL_ERROR_NONE) {
621                 mm_util_error("Error: __mm_util_rotate_image failed.");
622                 goto END;
623         }
624
625         ret = __mm_util_dispatch_image(_processed_image, req_format, dst_handle);
626
627 END:
628
629         __mm_util_finalize(_image, _processed_image, &exception);
630
631         mm_util_fleave();
632
633         return ret;
634 }
635
636
637 int mm_util_rotate_P_P(const char *src_path, mm_util_rotate_type_e rotation, const char *dst_path)
638 {
639         int ret = MM_UTIL_ERROR_NONE;
640         Image *_image = NULL;
641         Image *_processed_image = NULL;
642         ExceptionInfo exception;
643
644         __mm_util_init(&exception);
645
646         ret = __mm_util_read_image_from_file(src_path, &_image);
647         if (ret != MM_UTIL_ERROR_NONE) {
648                 mm_util_error("Error: __mm_util_read_image_from_file failed.");
649                 goto END;
650         }
651
652         ret = __mm_util_rotate_image(_image, rotation, &_processed_image);
653         if (ret != MM_UTIL_ERROR_NONE) {
654                 mm_util_error("Error: __mm_util_rotate_image failed.");
655                 goto END;
656         }
657
658         ret = __mm_util_write_image_to_file(_processed_image, NULL, dst_path);
659
660 END:
661
662         __mm_util_finalize(_image, _processed_image, &exception);
663
664         mm_util_fleave();
665
666         return ret;
667 }
668
669 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)
670 {
671         int ret = MM_UTIL_ERROR_NONE;
672         mm_image_info_s *_src_handle = (mm_image_info_s*)src_handle;
673         Image *_image = NULL;
674         Image *_processed_image = NULL;
675         ExceptionInfo exception;
676
677         mm_util_debug("req_width [%u] req_height [%u]", req_width, req_height);
678
679         __mm_util_init(&exception);
680
681         ret = __mm_util_constitute_image(src_handle, &_image);
682         if (ret != MM_UTIL_ERROR_NONE) {
683                 mm_util_error("Error: __mm_util_constitute_image failed.");
684                 goto END;
685         }
686
687         ret = __mm_util_resize_image(_image, req_width, req_height, &_processed_image);
688         if (ret != MM_UTIL_ERROR_NONE) {
689                 mm_util_error("Error: __mm_util_resize_image failed.");
690                 goto END;
691         }
692
693         ret = __mm_util_dispatch_image(_processed_image, _src_handle->color, dst_handle);
694
695 END:
696
697         __mm_util_finalize(_image, _processed_image, &exception);
698
699         mm_util_fleave();
700
701         return ret;
702 }
703
704 int mm_util_resize_B_P(mm_util_image_h src_handle, unsigned int req_width, unsigned int req_height, const char *dst_path)
705 {
706         int ret = MM_UTIL_ERROR_NONE;
707         Image *_image = NULL;
708         Image *_processed_image = NULL;
709         ExceptionInfo exception;
710
711         mm_util_sec_debug("req_width [%u] req_height [%u] dst_path [%s]", req_width, req_height, dst_path);
712
713         __mm_util_init(&exception);
714
715         ret = __mm_util_constitute_image(src_handle, &_image);
716         if (ret != MM_UTIL_ERROR_NONE) {
717                 mm_util_error("Error: __mm_util_constitute_image failed.");
718                 goto END;
719         }
720
721         ret = __mm_util_resize_image(_image, req_width, req_height, &_processed_image);
722         if (ret != MM_UTIL_ERROR_NONE) {
723                 mm_util_error("Error: __mm_util_resize_image failed.");
724                 goto END;
725         }
726
727         ret = __mm_util_write_image_to_file(_processed_image, NULL, dst_path);
728
729 END:
730
731         __mm_util_finalize(_image, _processed_image, &exception);
732
733         mm_util_fleave();
734
735         return ret;
736 }
737
738 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)
739 {
740         int ret = MM_UTIL_ERROR_NONE;
741         Image *_image = NULL;
742         Image *_processed_image = NULL;
743         ExceptionInfo exception;
744
745         mm_util_sec_debug("src_path [%s] req_width [%u] req_height [%u]", src_path, req_width, req_height);
746
747         __mm_util_init(&exception);
748
749         ret = __mm_util_read_image_from_file(src_path, &_image);
750         if (ret != MM_UTIL_ERROR_NONE) {
751                 mm_util_error("Error: __mm_util_read_image_from_file failed.");
752                 goto END;
753         }
754
755         ret = __mm_util_resize_image(_image, req_width, req_height, &_processed_image);
756         if (ret != MM_UTIL_ERROR_NONE) {
757                 mm_util_error("Error: __mm_util_resize_image failed.");
758                 goto END;
759         }
760
761         ret = __mm_util_dispatch_image(_processed_image, req_format, dst_handle);
762
763 END:
764
765         __mm_util_finalize(_image, _processed_image, &exception);
766
767         mm_util_fleave();
768
769         return ret;
770 }
771
772 int mm_util_resize_P_P(const char *src_path, unsigned int req_width, unsigned int req_height, const char *dst_path)
773 {
774         int ret = MM_UTIL_ERROR_NONE;
775         Image *_image = NULL;
776         Image *_processed_image = NULL;
777         ExceptionInfo exception;
778
779         mm_util_sec_debug("src_path [%s] req_width [%u] req_height [%u] dst_path [%s]", src_path, req_width, req_height, dst_path);
780
781         __mm_util_init(&exception);
782
783         ret = __mm_util_read_image_from_file(src_path, &_image);
784         if (ret != MM_UTIL_ERROR_NONE) {
785                 mm_util_error("Error: __mm_util_read_image_from_file failed.");
786                 goto END;
787         }
788
789         ret = __mm_util_resize_image(_image, req_width, req_height, &_processed_image);
790         if (ret != MM_UTIL_ERROR_NONE) {
791                 mm_util_error("Error: __mm_util_resize_image failed.");
792                 goto END;
793         }
794
795         ret = __mm_util_write_image_to_file(_processed_image, NULL, dst_path);
796
797 END:
798
799         __mm_util_finalize(_image, _processed_image, &exception);
800
801         mm_util_fleave();
802
803         return ret;
804 }
805
806 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)
807 {
808         int ret = MM_UTIL_ERROR_NONE;
809         mm_image_info_s *_src_handle = (mm_image_info_s*)src_handle;
810         Image *_image = NULL;
811         ExceptionInfo exception;
812
813         mm_util_debug("input format [%d] req_format [%d]", _src_handle->color, req_format);
814
815         __mm_util_init(&exception);
816
817         ret = __mm_util_constitute_image(src_handle, &_image);
818         if (ret != MM_UTIL_ERROR_NONE) {
819                 mm_util_error("Error: __mm_util_constitute_image failed.");
820                 goto END;
821         }
822
823         ret = __mm_util_dispatch_image(_image, req_format, dst_handle);
824
825 END:
826
827         __mm_util_finalize(_image, NULL, &exception);
828
829         mm_util_fleave();
830
831         return ret;
832 }
833
834 int mm_util_decode_image_from_file(const char *path, mm_util_color_format_e format, mm_util_image_h *decoded_image)
835 {
836         int ret = MM_UTIL_ERROR_NONE;
837         Image *_image = NULL;
838
839         mm_util_sec_debug("path [%s] format [%d]", path, format);
840
841         __mm_util_init(NULL);
842
843         ret = __mm_util_read_image_from_file(path, &_image);
844         if (ret != MM_UTIL_ERROR_NONE) {
845                 mm_util_error("Error: __mm_util_read_image_from_file failed.");
846                 goto END;
847         }
848
849         ret = __mm_util_dispatch_image(_image, format, decoded_image);
850
851 END:
852
853         __mm_util_finalize(_image, NULL, NULL);
854
855         mm_util_fleave();
856
857         return ret;
858 }
859
860 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)
861 {
862         int ret = MM_UTIL_ERROR_NONE;
863         Image *_image = NULL;
864
865         mm_util_sec_debug("path [%p] buf_size [%zu] format [%d]", buf, buf_size, format);
866
867         __mm_util_init(NULL);
868
869         ret = __mm_util_read_image_from_buffer(buf, buf_size, &_image);
870         if (ret != MM_UTIL_ERROR_NONE) {
871                 mm_util_error("Error: __mm_util_read_image_from_buffer failed.");
872                 goto END;
873         }
874
875         ret = __mm_util_dispatch_image(_image, format, decoded_image);
876
877 END:
878
879         __mm_util_finalize(_image, NULL, NULL);
880
881         mm_util_fleave();
882
883         return ret;
884 }
885
886 int mm_util_encode_image_to_file(mm_util_image_h decoded_image, mm_util_enc_opt_h opt, const char *path)
887 {
888         int ret = MM_UTIL_ERROR_NONE;
889         Image *_image = NULL;
890         mm_util_image_h converted_image = NULL, source = NULL;
891         mm_util_enc_opt_t *_opt = (mm_util_enc_opt_t *)opt;
892
893         mm_util_retvm_if(!_opt, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid opt");
894
895         mm_util_sec_debug("path [%s]", path);
896
897         if (_opt->codec == IMG_CODEC_BMP) {
898                 /*
899                   GraphicsMagick doesn't support alpha overlay(compression method:BI_ALPHABITFIELDS) for bmp.
900                   Officially BMP format supports alpha overlay since BMP4(version 4), but GraphicsMagick
901                   support BMP, BMP2(v2) and BMP3(v3) except BMP4.
902                   So decoded_image should be converted to RGB888(RGB24) which has not alpha overlay.
903                   ps. BMP4 image does not guarantee backward compatibility. BMP4 is not visible on old devices.
904                   For the reasons, BMP4 is used in certain cases of windows OS, not widely used in general cases.
905                 */
906
907                 if (((mm_image_info_s *)decoded_image)->color == MM_UTIL_COLOR_RGBA) {
908                         ret = mm_util_convert_B_B(decoded_image, MM_UTIL_COLOR_RGB24, &converted_image);
909                         if (ret != MM_UTIL_ERROR_NONE) {
910                                 mm_util_error("Error: mm_util_convert_B_B failed.");
911                                 goto END;
912                         }
913                 }
914         }
915
916         source = (converted_image) ? converted_image : decoded_image;
917
918         __mm_util_init(NULL);
919
920         ret = __mm_util_constitute_image(source, &_image);
921         if (ret != MM_UTIL_ERROR_NONE) {
922                 mm_util_error("Error: __mm_util_constitute_image failed.");
923                 goto END;
924         }
925
926         ret = __mm_util_write_image_to_file(_image, _opt, path);
927
928 END:
929
930         __mm_util_finalize(_image, NULL, NULL);
931
932         mm_image_destroy_image(converted_image);
933
934         mm_util_fleave();
935
936         return ret;
937 }
938
939 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)
940 {
941         int ret = MM_UTIL_ERROR_NONE;
942         char *tmp_file = NULL;
943
944         mm_util_retvm_if(!opt, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid opt");
945
946         ret = __mm_util_make_tmp_file(((mm_util_enc_opt_t *)opt)->codec, &tmp_file);
947         mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "Error: __mm_util_make_tmp_file failed.");
948
949         ret = mm_util_encode_image_to_file(decoded_image, opt, tmp_file);
950         if (ret != MM_UTIL_ERROR_NONE) {
951                 mm_util_error("Error: mm_util_encode_image_P failed.");
952                 goto END;
953         }
954
955         ret = mm_util_file_read(tmp_file, buf, buf_size);
956         if (ret != MM_UTIL_ERROR_NONE)
957                 mm_util_error("Error: mm_util_file_read failed.");
958
959 END:
960
961         if (g_remove(tmp_file) != 0)
962                 mm_util_sec_debug("Temporary file was not removed [%s]", tmp_file);
963         g_free(tmp_file);
964
965         mm_util_fleave();
966
967         return ret;
968 }
969
970 int mm_util_resize_and_rotate_P_P(const char *src_path, unsigned int req_width, unsigned int req_height, const char *dst_path)
971 {
972         int ret = MM_UTIL_ERROR_NONE;
973         Image *_image = NULL;
974         Image *_resized_image = NULL;
975         Image *_rotated_image = NULL;
976         Image *_write_image = NULL;
977         ExceptionInfo exception;
978         mm_util_rotate_type_e rotation = MM_UTIL_ROTATE_0;
979
980         mm_util_sec_debug("src_path [%s] req_width [%u] req_height [%u] dst_path [%s]", src_path, req_width, req_height, dst_path);
981
982         __mm_util_init(&exception);
983
984         ret = __mm_util_read_image_from_file(src_path, &_image);
985         if (ret != MM_UTIL_ERROR_NONE) {
986                 mm_util_error("Error: __mm_util_read_image_from_file failed.");
987                 goto END;
988         }
989
990         ret = __mm_util_resize_image(_image, req_width, req_height, &_resized_image);
991         DestroyImageList(_image);
992         _image = NULL;
993         if (ret != MM_UTIL_ERROR_NONE) {
994                 mm_util_error("Error: __mm_util_resize_image failed.");
995                 goto END;
996         }
997
998         switch(_resized_image->orientation) {
999         case TopRightOrientation:
1000         case RightTopOrientation:
1001                 rotation = MM_UTIL_ROTATE_90;
1002                 break;
1003         case BottomRightOrientation:
1004         case RightBottomOrientation:
1005                 rotation = MM_UTIL_ROTATE_180;
1006                 break;
1007         case BottomLeftOrientation:
1008         case LeftBottomOrientation:
1009                 rotation = MM_UTIL_ROTATE_270;
1010                 break;
1011         case TopLeftOrientation:
1012         case LeftTopOrientation:
1013                 break;
1014         default:
1015                 mm_util_warn("Not supported orientation %d. so apply MM_UTIL_ROTATE_0", _resized_image->orientation);
1016                 break;
1017         }
1018
1019         if (rotation != MM_UTIL_ROTATE_0) {
1020                 ret = __mm_util_rotate_image(_resized_image, rotation, &_rotated_image);
1021                 if (ret != MM_UTIL_ERROR_NONE) {
1022                         mm_util_error("Error: __mm_util_rotate_image failed.");
1023                         goto END;
1024                 }
1025         }
1026
1027         _write_image = (_rotated_image) ? _rotated_image : _resized_image;
1028
1029         /* problem. a thumbnail of grayscale image is invisible
1030            add converting grayscale image into rgb(jpeg) or true color(png)
1031            the rgb(jpeg) and true-color(png) are default(else case) value.
1032          */
1033         if (IsGrayImage(_write_image, &exception)) {
1034                 mm_util_info("IsGrayImage, convert image into rgb(jpeg)/true-color(png).");
1035                 _write_image->is_grayscale = MagickFalse;
1036         }
1037
1038         ret = __mm_util_write_image_to_file(_write_image, NULL, dst_path);
1039
1040 END:
1041
1042         __mm_util_finalize(_resized_image, _rotated_image, &exception);
1043
1044         mm_util_fleave();
1045
1046         return ret;
1047 }