53ca1c7c0e34a2ce6091db1c939f4b0d72ddee9c
[platform/core/api/maps-service.git] / src / api / maps_view_snapshot.cpp
1 /* Copyright (c) 2010-2014 Samsung Electronics Co., Ltd. All rights reserved.
2  *
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdlib.h>
18 #include <image_util.h>
19 #include <unistd.h> /* access */
20
21 #include <maps_view_plugin.h>
22 #include <maps_condition.h>
23 #include <module.h>
24 #include <empty_module.h>
25 #include "maps_condition.h"
26
27
28 const plugin::interface_s *__get_plugin_interface(maps_view_h view);
29
30 static void __convert_rgba_to_bgra(unsigned char *data, int width, int height)
31 {
32         int len = width * height;
33         unsigned int *p = (unsigned int *)data;
34         for (int i = 0; i < len; i++)
35         {
36                 *p = (*p & 0xFF00FF00) |
37                         ((*p & 0x00FF0000) >> 16) |
38                         ((*p & 0x000000FF) << 16);
39                 p++;
40         };
41 }
42
43 static bool __encode_bitmap_file(const void *data, int width, int height, const char *file)
44 {
45        struct {
46               unsigned char magic[2];
47        } bmpfile_magic = { {'B', 'M'} };
48
49        struct {
50               unsigned int filesz;
51               unsigned short creator1;
52               unsigned short creator2;
53               unsigned int bmp_offset;
54        } bmpfile_header = { 0, 0, 0, 0x36 };
55
56        struct {
57               unsigned int header_sz;
58               unsigned int width;
59               unsigned int height;
60               unsigned short nplanes;
61               unsigned short bitspp;
62               unsigned int compress_type;
63               unsigned int bmp_bytesz;
64               unsigned int hres;
65               unsigned int vres;
66               unsigned int ncolors;
67               unsigned int nimpcolors;
68        } bmp_dib_v3_header_t = { 0x28, 0, 0, 1, 24, 0, 0, 0, 0, 0, 0 };
69
70        unsigned int *blocks;
71        FILE *fp = fopen(file, "w+");
72        int i;
73
74        if (fp == NULL) {
75               MAPS_LOGE("fopen fail");
76               return false;
77        }
78        bmpfile_header.filesz = sizeof(bmpfile_magic) + sizeof(bmpfile_header) + sizeof(bmp_dib_v3_header_t) + (width * height * 3);
79        bmp_dib_v3_header_t.header_sz = sizeof(bmp_dib_v3_header_t);
80        bmp_dib_v3_header_t.width = width;
81        bmp_dib_v3_header_t.height = -height;
82        bmp_dib_v3_header_t.bmp_bytesz = width * height * 3;
83
84        fwrite(&bmpfile_magic, sizeof(bmpfile_magic), 1, fp);
85        fwrite(&bmpfile_header, sizeof(bmpfile_header), 1, fp);
86        fwrite(&bmp_dib_v3_header_t, sizeof(bmp_dib_v3_header_t), 1, fp);
87        blocks = (unsigned int *)data;
88
89        for (i = 0; i < height * width; i++) {
90               fwrite(&blocks[i], 3, 1, fp);
91        }
92        fclose(fp);
93            return true;
94 }
95
96 static image_util_colorspace_e __convert_colorspace(maps_view_colorspace_type_e cs)
97 {
98         switch (cs) {
99                 case MAPS_VIEW_COLORSPACE_RGBA8888:
100                         return IMAGE_UTIL_COLORSPACE_RGBA8888;
101                 case MAPS_VIEW_COLORSPACE_BGRA8888:
102                         return IMAGE_UTIL_COLORSPACE_BGRA8888;
103         }
104         return IMAGE_UTIL_COLORSPACE_RGBA8888;
105 }
106
107 static int __encode_to_jpeg(unsigned char *image_buffer, int w, int h,
108         maps_view_colorspace_type_e cs, int quality, const char *file_path)
109 {
110         if (!image_buffer || !file_path || (file_path && *file_path == '\0'))
111                 return MAPS_ERROR_INVALID_OPERATION;
112 #if (TIZEN_VER >= VERSION(3, 0, 0))
113         image_util_encode_h image_handle = NULL;
114         unsigned long long image_size = 0;
115         int error = IMAGE_UTIL_ERROR_NONE;
116
117         do {
118                 error = image_util_encode_create(IMAGE_UTIL_JPEG, &image_handle);
119                 if (error != IMAGE_UTIL_ERROR_NONE) {
120                         MAPS_LOGE("Failed to create the image handle with JPEG format. error=%d", error);
121                         break;
122                 }
123                 error = image_util_encode_set_input_buffer(image_handle, image_buffer);
124                 if (error != IMAGE_UTIL_ERROR_NONE) {
125                         MAPS_LOGE("Failed to set image_buffer to image handle. error=%d", error);
126                         break;
127                 }
128                 error = image_util_encode_set_resolution(image_handle, w, h);
129                 if (error != IMAGE_UTIL_ERROR_NONE) {
130                         MAPS_LOGE("Failed to set resolution to image handle. error=%d", error);
131                         break;
132                 }
133                 error = image_util_encode_set_colorspace(image_handle, __convert_colorspace(cs));
134                 if (error != IMAGE_UTIL_ERROR_NONE) {
135                         MAPS_LOGE("Failed to set colorspace to image handle. error=%d", error);
136                         break;
137                 }
138                 error = image_util_encode_set_quality(image_handle, quality);
139                 if (error != IMAGE_UTIL_ERROR_NONE) {
140                         MAPS_LOGE("Failed to set quality to image handle. error=%d", error);
141                         break;
142                 }
143                 error = image_util_encode_set_output_path(image_handle, file_path);
144                 if (error != IMAGE_UTIL_ERROR_NONE) {
145                         MAPS_LOGE("Failed to set path to image handle. error=%d", error);
146                         break;
147                 }
148                 error = image_util_encode_run(image_handle, &image_size);
149                 if (error != IMAGE_UTIL_ERROR_NONE) {
150                         MAPS_LOGE("Failed to encode with image handle. error=%d", error);
151                         break;
152                 }
153         } while (0);
154
155         image_util_encode_destroy(image_handle);
156         image_handle = NULL;
157 #else
158         int error = image_util_encode_jpeg(image_buffer, w, h,
159                                                                                 __convert_colorspace(cs), quality, file_path);
160         if (error != IMAGE_UTIL_ERROR_NONE) {
161                 MAPS_LOGD("image_buffer=%p, w=%d, h=%d, cs=%d, quality=%d, file_path=%s",
162                         image_buffer, w, h, cs, quality, file_path);
163                 MAPS_LOGE("Failed to encode it with JPEG format. error=%d", error);
164         }
165 #endif
166
167         return (error == IMAGE_UTIL_ERROR_NONE ? MAPS_ERROR_NONE : MAPS_ERROR_INVALID_OPERATION);
168 }
169
170 static int __encode_to_bmp(unsigned char *image_buffer, int w, int h,
171         maps_view_colorspace_type_e cs, const char *file_path)
172 {
173         if (!image_buffer || !file_path || (file_path && *file_path == '\0'))
174                 return MAPS_ERROR_INVALID_OPERATION;
175
176         int error = MAPS_ERROR_NONE;
177
178         if (cs == MAPS_VIEW_COLORSPACE_RGBA8888) {
179                 __convert_rgba_to_bgra(image_buffer, w, h);
180                 cs = MAPS_VIEW_COLORSPACE_BGRA8888;
181         }
182
183         if (!__encode_bitmap_file(image_buffer, w, h, file_path)) {
184                 MAPS_LOGE("Failed to store it to a file.");
185                 error = MAPS_ERROR_INVALID_OPERATION;
186         }
187         return error;
188 }
189
190 static int __build_tmp_path(const char *path, char **tmp_path)
191 {
192         if (!path || !tmp_path)
193                 return MAPS_ERROR_INVALID_PARAMETER;
194
195         int error = MAPS_ERROR_NONE;
196         int tmp_path_len = strlen(path);
197         *tmp_path = (char*)malloc(tmp_path_len + 10);
198         if (!*tmp_path)
199                 return MAPS_ERROR_INVALID_OPERATION;
200
201         int retry = 0;
202         const int retry_max = 20;
203         sprintf(*tmp_path, "%s.tmp", path);
204         while(access(*tmp_path, F_OK) != -1 && ++retry < retry_max) {
205                 sprintf(*tmp_path, "%s.tmp%d", path, retry);
206         }
207         if (retry >= retry_max) {
208                 MAPS_LOGD("There are already too many temporary files.");
209                 error = MAPS_ERROR_INVALID_OPERATION;
210                 free(*tmp_path);
211                 *tmp_path = NULL;
212         }
213         return error;
214 }
215
216
217 EXPORT_API int maps_view_capture_snapshot(maps_view_h view,
218                                                                 maps_view_snapshot_format_type_e type,
219                                                                 int quality,
220                                                                 const char *path)
221 {
222         if (!maps_condition_check_maps_feature())
223                 return MAPS_ERROR_NOT_SUPPORTED;
224         if (!view)
225                 return MAPS_ERROR_INVALID_PARAMETER;
226         if (!maps_condition_check_view_service_supported(view, MAPS_SERVICE_VIEW_SNAPSHOT))
227                 return MAPS_ERROR_NOT_SUPPORTED;
228         if (type < MAPS_VIEW_SNAPSHOT_BMP || type > MAPS_VIEW_SNAPSHOT_JPEG ||
229                 quality < 0 || quality > 100 || !path || (path && *path == '\0'))
230                 return MAPS_ERROR_INVALID_PARAMETER;
231         if (!maps_condition_check_privilege())
232                 return MAPS_ERROR_PERMISSION_DENIED;
233
234         int error = MAPS_ERROR_UNKNOWN;
235         int w, h;
236         unsigned char *image_buffer = NULL;
237         maps_view_colorspace_type_e cs = MAPS_VIEW_COLORSPACE_RGBA8888;
238         char *tmp_path = NULL;
239
240         do {
241                 if (!__get_plugin_interface(view)->maps_plugin_capture_snapshot) {
242                         error = MAPS_ERROR_SERVICE_NOT_AVAILABLE;
243                         break;
244                 }
245
246                 error = __get_plugin_interface(view)->maps_plugin_capture_snapshot(view,
247                                                                                                 (void**)&image_buffer, &w, &h, &cs);
248                 if (error != MAPS_ERROR_NONE) break;
249
250                 if (cs != MAPS_VIEW_COLORSPACE_RGBA8888 && cs != MAPS_VIEW_COLORSPACE_BGRA8888) {
251                         MAPS_LOGE("The color space is not supported yet. (%d)", cs);
252                         error = MAPS_ERROR_INVALID_OPERATION;
253                         break;
254                 }
255
256                 error = __build_tmp_path(path, &tmp_path);
257                 if (error != MAPS_ERROR_NONE) break;
258
259                 if (type == MAPS_VIEW_SNAPSHOT_JPEG) {
260                         error = __encode_to_jpeg(image_buffer, w, h, cs, quality, tmp_path);
261                 } else if (type == MAPS_VIEW_SNAPSHOT_BMP) {
262                         error = __encode_to_bmp(image_buffer, w, h, cs, tmp_path);
263                 } else {
264                         error = MAPS_ERROR_INVALID_PARAMETER;
265                 }
266         } while (0);
267
268         if (tmp_path) {
269                 if (error == MAPS_ERROR_NONE) {
270                         MAPS_LOGD("The snapshot is saved to %s", path);
271                         remove(path);
272                         rename(tmp_path, path);
273                 } else {
274                         remove(tmp_path);
275                 }
276                 free(tmp_path);
277         }
278         g_free(image_buffer);
279         return error;
280 }