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