Modify parameters in encoding APIs have been changed from mm_image_info_s to mm_util_...
[platform/core/multimedia/libmm-utility.git] / bmp / mm_util_bmp.c
1 /*
2  * libmm-utility
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Vineeth T M <vineeth.tm@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 <stdio.h>
23 #include <sys/stat.h>
24 #include <unistd.h>
25
26 #include <libnsbmp.h>
27 #include <bmpfile.h>
28
29 #include "mm_util_bmp.h"
30 #include "mm_util_private.h"
31
32 #define BYTES_PER_PIXEL 4
33
34 /* for bmp_bitmap_callback_vt of nsbmp */
35 void *__bitmap_create(int width, int height, unsigned int state);
36 unsigned char *__bitmap_get_buffer(void *bitmap);
37 size_t __bitmap_get_bpp(void *bitmap);
38 void __bitmap_destroy(void *bitmap);
39
40 void *__bitmap_create(int width, int height, unsigned int state)
41 {
42         return calloc(width * height, BYTES_PER_PIXEL);
43 }
44
45 unsigned char *__bitmap_get_buffer(void *bitmap)
46 {
47         return bitmap;
48 }
49
50 size_t __bitmap_get_bpp(void *bitmap)
51 {
52         return BYTES_PER_PIXEL;
53 }
54
55 void __bitmap_destroy(void *bitmap)
56 {
57         MMUTIL_SAFE_FREE(bitmap);
58 }
59
60 static unsigned char *__load_file(const char *path, size_t * data_size)
61 {
62         FILE *fd;
63         struct stat sb;
64         unsigned char *buffer;
65         size_t size;
66         size_t n;
67
68         if (MM_UTIL_ERROR_NONE != mm_util_safe_fopen(path, "rb", &fd)) {
69                 mm_util_error("mm_util_safe_fopen failed");
70                 return NULL;
71         }
72
73         if (stat(path, &sb)) {
74                 mm_util_error("file stat failed");
75                 mm_util_safe_fclose(fd);
76                 return NULL;
77         }
78         size = sb.st_size;
79
80         buffer = calloc(1, size);
81         if (!buffer) {
82                 mm_util_error("Unable to allocate %lld bytes", (long long)size);
83                 mm_util_safe_fclose(fd);
84                 return NULL;
85         }
86
87         n = fread(buffer, 1, size, fd);
88         if (n != size) {
89                 mm_util_error("file read failed");
90                 MMUTIL_SAFE_FREE(buffer);
91                 mm_util_safe_fclose(fd);
92                 return NULL;
93         }
94
95         mm_util_safe_fclose(fd);
96         *data_size = size;
97         return buffer;
98 }
99
100 static void __print_error(const char *context, bmp_result code)
101 {
102         switch (code) {
103         case BMP_INSUFFICIENT_MEMORY:
104                 mm_util_error("%s failed: BMP_INSUFFICIENT_MEMORY", context);
105                 break;
106         case BMP_INSUFFICIENT_DATA:
107                 mm_util_error("%s failed: BMP_INSUFFICIENT_DATA", context);
108                 break;
109         case BMP_DATA_ERROR:
110                 mm_util_error("%s failed: BMP_DATA_ERROR", context);
111                 break;
112         default:
113                 mm_util_error("%s failed: unknown code %i", context, code);
114                 break;
115         }
116 }
117
118 /* decodes bmp image to color image */
119 static int __read_bmp(const char *file_path, void *memory, size_t src_size, mm_util_image_h *decoded)
120 {
121         bmp_bitmap_callback_vt bitmap_callbacks = {
122                 __bitmap_create,
123                 __bitmap_destroy,
124                 __bitmap_get_buffer,
125                 __bitmap_get_bpp
126         };
127         bmp_result code;
128         bmp_image bmp;
129         size_t size = 0;
130         int res = MM_UTIL_ERROR_NONE;
131         unsigned char *data = NULL;
132
133         mm_util_retvm_if(!MMUTIL_STRING_VALID(file_path) && !memory, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid bmp image");
134         mm_util_retvm_if(!decoded, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid image handle");
135
136         mm_util_fenter();
137
138         if (MMUTIL_STRING_VALID(file_path)) {
139                 mm_util_sec_debug("read from file [%s]", file_path);
140                 data = __load_file(file_path, &size);
141                 if (data == NULL)
142                         return MM_UTIL_ERROR_INVALID_OPERATION;
143         } else {
144                 mm_util_debug("read from memory");
145                 data = (unsigned char *)memory;
146                 size = src_size;
147         }
148
149         nsbmp_create(&bmp, &bitmap_callbacks);
150
151         code = bmp_analyse(&bmp, size, data);
152         if (code != BMP_OK) {
153                 __print_error("bmp_analyse", code);
154                 res = MM_UTIL_ERROR_INVALID_OPERATION;
155                 goto cleanup;
156         }
157
158         code = bmp_decode(&bmp);
159
160         if ((code != BMP_OK) || (bmp.bitmap == NULL)) {
161                 __print_error("bmp_decode", code);
162                 /* allow partially decoded images */
163                 if (code != BMP_INSUFFICIENT_DATA) {
164                         res = MM_UTIL_ERROR_INVALID_OPERATION;
165                         goto cleanup;
166                 }
167         }
168
169         res = mm_image_create_image(bmp.width, bmp.height, MM_UTIL_COLOR_RGBA, bmp.bitmap, bmp.width * bmp.height * BYTES_PER_PIXEL, decoded);
170
171  cleanup:
172         bmp_finalise(&bmp);
173         if (file_path)
174                 MMUTIL_SAFE_FREE(data);
175
176         mm_util_fleave();
177
178         return res;
179 }
180
181 /* encodes color image to bmp image */
182 static int __write_bmp(mm_util_image_h decoded, const char *file_path, void **buffer, size_t *src_size)
183 {
184         mm_image_info_s *_decoded = (mm_image_info_s *)decoded;
185         bmpfile_t *bmp;
186         rgb_pixel_t pixel = { 0, 0, 0, 0 };
187         uint16_t row, col;
188         uint8_t *image;
189
190         mm_util_retvm_if(!decoded, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid image src");
191         mm_util_retvm_if(!MMUTIL_STRING_VALID(file_path) && (!buffer || !src_size), MM_UTIL_ERROR_INVALID_PARAMETER, "invalid parameter");
192         mm_util_retvm_if(_decoded->color != MM_UTIL_COLOR_RGBA, MM_UTIL_ERROR_NOT_SUPPORTED_FORMAT, "not supported color [%d]", _decoded->color);
193
194         mm_util_fenter();
195
196         /* header of bmp image is create at 'bmp' */
197         if ((bmp = bmp_create(_decoded->width, _decoded->height, BYTES_PER_PIXEL * 8)) == NULL) {
198                 mm_util_error("Invalid depth value.");
199                 return MM_UTIL_ERROR_INVALID_OPERATION;
200         }
201
202         /* pixcels of bmp image is stored at 'bmp' */
203         image = (uint8_t *) _decoded->data;
204         for (row = 0; row != _decoded->height; row++) {
205                 for (col = 0; col != _decoded->width; col++) {
206                         size_t z = (row * _decoded->width + col) * BYTES_PER_PIXEL;
207                         pixel.red = image[z];
208                         pixel.green = image[z + 1];
209                         pixel.blue = image[z + 2];
210                         bmp_set_pixel(bmp, col, row, pixel);
211                 }
212         }
213
214         /* write 'bmp' to file or buffer */
215         if (MMUTIL_STRING_VALID(file_path)) {
216                 mm_util_sec_debug("Save to file [%s]", file_path);
217                 if (bmp_save(bmp, file_path) == false) {
218                         mm_util_error("Saving bmp was failed.");
219                         bmp_destroy(bmp);
220                         return MM_UTIL_ERROR_INVALID_OPERATION;
221                 }
222         } else {
223                 mm_util_sec_debug("Save to buffer");
224                 if (bmp_save2(bmp, buffer, src_size) == false) {
225                         mm_util_error("Saving bmp was failed.");
226                         bmp_destroy(bmp);
227                         MMUTIL_SAFE_FREE(*buffer);
228                         *src_size = 0;
229                         return MM_UTIL_ERROR_INVALID_OPERATION;
230                 }
231         }
232
233         bmp_destroy(bmp);
234
235         mm_util_fleave();
236
237         return MM_UTIL_ERROR_NONE;
238 }
239
240 int mm_util_decode_from_bmp_file(const char *file_path, mm_util_image_h *decoded)
241 {
242         mm_util_retvm_if(!MMUTIL_STRING_VALID(file_path), MM_UTIL_ERROR_INVALID_PARAMETER, "invalid file_path");
243
244         return __read_bmp(file_path, NULL, 0, decoded);
245 }
246
247 int mm_util_decode_from_bmp_memory(void *memory, const size_t src_size, mm_util_image_h *decoded)
248 {
249         mm_util_retvm_if(!memory, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid bmp image");
250         mm_util_retvm_if(!src_size, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid src_size");
251
252         return __read_bmp(NULL, memory, src_size, decoded);
253 }
254
255 int mm_util_encode_bmp_to_file(mm_util_image_h decoded, const char *file_path)
256 {
257         mm_util_retvm_if(!MMUTIL_STRING_VALID(file_path), MM_UTIL_ERROR_INVALID_PARAMETER, "invalid file_path");
258
259         return __write_bmp(decoded, file_path, NULL, NULL);
260 }
261
262 int mm_util_encode_bmp_to_memory(mm_util_image_h decoded, void **buffer, size_t *size)
263 {
264         mm_util_retvm_if(!buffer, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid buffer");
265         mm_util_retvm_if(!size, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid size");
266
267         return __write_bmp(decoded, NULL, buffer, size);
268 }