Update package changelog.
[profile/ivi/weston.git] / shared / image-loader.c
1 /*
2  * Copyright © 2008-2012 Kristian Høgsberg
3  * Copyright © 2012 Intel Corporation
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and its
6  * documentation for any purpose is hereby granted without fee, provided that
7  * the above copyright notice appear in all copies and that both that copyright
8  * notice and this permission notice appear in supporting documentation, and
9  * that the name of the copyright holders not be used in advertising or
10  * publicity pertaining to distribution of the software without specific,
11  * written prior permission.  The copyright holders make no representations
12  * about the suitability of this software for any purpose.  It is provided "as
13  * is" without express or implied warranty.
14  *
15  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21  * OF THIS SOFTWARE.
22  */
23
24 #include "../config.h"
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <jpeglib.h>
29 #include <png.h>
30 #include <pixman.h>
31
32 #include "image-loader.h"
33
34 #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
35
36 #ifdef HAVE_WEBP
37 #include <webp/decode.h>
38 #endif
39
40 static int
41 stride_for_width(int width)
42 {
43         return width * 4;
44 }
45
46 static void
47 swizzle_row(JSAMPLE *row, JDIMENSION width)
48 {
49         JSAMPLE *s;
50         uint32_t *d;
51
52         s = row + (width - 1) * 3;
53         d = (uint32_t *) (row + (width - 1) * 4);
54         while (s >= row) {
55                 *d = 0xff000000 | (s[0] << 16) | (s[1] << 8) | (s[2] << 0);
56                 s -= 3;
57                 d--;
58         }
59 }
60
61 static void
62 error_exit(j_common_ptr cinfo)
63 {
64         longjmp(cinfo->client_data, 1);
65 }
66
67 static void
68 pixman_image_destroy_func(pixman_image_t *image, void *data)
69 {
70         free(data);
71 }
72
73 static pixman_image_t *
74 load_jpeg(FILE *fp)
75 {
76         struct jpeg_decompress_struct cinfo;
77         struct jpeg_error_mgr jerr;
78         pixman_image_t *pixman_image = NULL;
79         unsigned int i;
80         int stride, first;
81         JSAMPLE *data, *rows[4];
82         jmp_buf env;
83
84         cinfo.err = jpeg_std_error(&jerr);
85         jerr.error_exit = error_exit;
86         cinfo.client_data = env;
87         if (setjmp(env))
88                 return NULL;
89
90         jpeg_create_decompress(&cinfo);
91
92         jpeg_stdio_src(&cinfo, fp);
93
94         jpeg_read_header(&cinfo, TRUE);
95
96         cinfo.out_color_space = JCS_RGB;
97         jpeg_start_decompress(&cinfo);
98
99         stride = cinfo.output_width * 4;
100         data = malloc(stride * cinfo.output_height);
101         if (data == NULL) {
102                 fprintf(stderr, "couldn't allocate image data\n");
103                 return NULL;
104         }
105
106         while (cinfo.output_scanline < cinfo.output_height) {
107                 first = cinfo.output_scanline;
108                 for (i = 0; i < ARRAY_LENGTH(rows); i++)
109                         rows[i] = data + (first + i) * stride;
110
111                 jpeg_read_scanlines(&cinfo, rows, ARRAY_LENGTH(rows));
112                 for (i = 0; first + i < cinfo.output_scanline; i++)
113                         swizzle_row(rows[i], cinfo.output_width);
114         }
115
116         jpeg_finish_decompress(&cinfo);
117
118         jpeg_destroy_decompress(&cinfo);
119
120         pixman_image = pixman_image_create_bits(PIXMAN_a8r8g8b8,
121                                         cinfo.output_width,
122                                         cinfo.output_height,
123                                         (uint32_t *) data, stride);
124
125         pixman_image_set_destroy_function(pixman_image,
126                                 pixman_image_destroy_func, data);
127
128         return pixman_image;
129 }
130
131 static inline int
132 multiply_alpha(int alpha, int color)
133 {
134     int temp = (alpha * color) + 0x80;
135
136     return ((temp + (temp >> 8)) >> 8);
137 }
138
139 static void
140 premultiply_data(png_structp   png,
141                  png_row_infop row_info,
142                  png_bytep     data)
143 {
144     unsigned int i;
145     png_bytep p;
146
147     for (i = 0, p = data; i < row_info->rowbytes; i += 4, p += 4) {
148         png_byte  alpha = p[3];
149         uint32_t w;
150
151         if (alpha == 0) {
152                 w = 0;
153         } else {
154                 png_byte red   = p[0];
155                 png_byte green = p[1];
156                 png_byte blue  = p[2];
157
158                 if (alpha != 0xff) {
159                         red   = multiply_alpha(alpha, red);
160                         green = multiply_alpha(alpha, green);
161                         blue  = multiply_alpha(alpha, blue);
162                 }
163                 w = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
164         }
165
166         * (uint32_t *) p = w;
167     }
168 }
169
170 static void
171 read_func(png_structp png, png_bytep data, png_size_t size)
172 {
173         FILE *fp = png_get_io_ptr(png);
174
175         if (fread(data, 1, size, fp) != size)
176                 png_error(png, NULL);
177 }
178
179 static void
180 png_error_callback(png_structp png, png_const_charp error_msg)
181 {
182     longjmp (png_jmpbuf (png), 1);
183 }
184
185 static pixman_image_t *
186 load_png(FILE *fp)
187 {
188         png_struct *png;
189         png_info *info;
190         png_byte *data = NULL;
191         png_byte **row_pointers = NULL;
192         png_uint_32 width, height;
193         int depth, color_type, interlace, stride;
194         unsigned int i;
195         pixman_image_t *pixman_image = NULL;
196
197         png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
198                                      png_error_callback, NULL);
199         if (!png)
200                 return NULL;
201
202         info = png_create_info_struct(png);
203         if (!info) {
204                 png_destroy_read_struct(&png, &info, NULL);
205                 return NULL;
206         }
207
208         if (setjmp(png_jmpbuf(png))) {
209                 if (data)
210                         free(data);
211                 if (row_pointers)
212                         free(row_pointers);
213                 png_destroy_read_struct(&png, &info, NULL);
214                 return NULL;
215         }
216
217         png_set_read_fn(png, fp, read_func);
218         png_read_info(png, info);
219         png_get_IHDR(png, info,
220                      &width, &height, &depth,
221                      &color_type, &interlace, NULL, NULL);
222
223         if (color_type == PNG_COLOR_TYPE_PALETTE)
224                 png_set_palette_to_rgb(png);
225
226         if (color_type == PNG_COLOR_TYPE_GRAY)
227                 png_set_expand_gray_1_2_4_to_8(png);
228
229         if (png_get_valid(png, info, PNG_INFO_tRNS))
230                 png_set_tRNS_to_alpha(png);
231
232         if (depth == 16)
233                 png_set_strip_16(png);
234
235         if (depth < 8)
236                 png_set_packing(png);
237
238         if (color_type == PNG_COLOR_TYPE_GRAY ||
239             color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
240                 png_set_gray_to_rgb(png);
241
242         if (interlace != PNG_INTERLACE_NONE)
243                 png_set_interlace_handling(png);
244
245         png_set_filler(png, 0xff, PNG_FILLER_AFTER);
246         png_set_read_user_transform_fn(png, premultiply_data);
247         png_read_update_info(png, info);
248         png_get_IHDR(png, info,
249                      &width, &height, &depth,
250                      &color_type, &interlace, NULL, NULL);
251
252
253         stride = stride_for_width(width);
254         data = malloc(stride * height);
255         if (!data) {
256                 png_destroy_read_struct(&png, &info, NULL);
257                 return NULL;
258         }
259
260         row_pointers = malloc(height * sizeof row_pointers[0]);
261         if (row_pointers == NULL) {
262                 free(data);
263                 png_destroy_read_struct(&png, &info, NULL);
264                 return NULL;
265         }
266
267         for (i = 0; i < height; i++)
268                 row_pointers[i] = &data[i * stride];
269
270         png_read_image(png, row_pointers);
271         png_read_end(png, info);
272
273         free(row_pointers);
274         png_destroy_read_struct(&png, &info, NULL);
275
276         pixman_image = pixman_image_create_bits(PIXMAN_a8r8g8b8,
277                                 width, height, (uint32_t *) data, stride);
278
279         pixman_image_set_destroy_function(pixman_image,
280                                 pixman_image_destroy_func, data);
281
282         return pixman_image;
283 }
284
285 #ifdef HAVE_WEBP
286
287 static pixman_image_t *
288 load_webp(FILE *fp)
289 {
290         WebPDecoderConfig config;
291         uint8_t buffer[16 * 1024];
292         int len;
293         VP8StatusCode status;
294         WebPIDecoder *idec;
295
296         if (!WebPInitDecoderConfig(&config)) {
297                 fprintf(stderr, "Library version mismatch!\n");
298                 return NULL;
299         }
300
301         /* webp decoding api doesn't seem to specify a min size that's
302            usable for GetFeatures, but 256 works... */
303         len = fread(buffer, 1, 256, fp);
304         status = WebPGetFeatures(buffer, len, &config.input);
305         if (status != VP8_STATUS_OK) {
306                 fprintf(stderr, "failed to parse webp header\n");
307                 WebPFreeDecBuffer(&config.output);
308                 return NULL;
309         }
310
311         config.output.colorspace = MODE_BGRA;
312         config.output.u.RGBA.stride = stride_for_width(config.input.width);
313         config.output.u.RGBA.size =
314                 config.output.u.RGBA.stride * config.input.height;
315         config.output.u.RGBA.rgba =
316                 malloc(config.output.u.RGBA.stride * config.input.height);
317         config.output.is_external_memory = 1;
318         if (!config.output.u.RGBA.rgba) {
319                 WebPFreeDecBuffer(&config.output);
320                 return NULL;
321         }
322
323         rewind(fp);
324         idec = WebPINewDecoder(&config.output);
325         if (!idec) {
326                 WebPFreeDecBuffer(&config.output);
327                 return NULL;
328         }
329
330         while (!feof(fp)) {
331                 len = fread(buffer, 1, sizeof buffer, fp);
332                 status = WebPIAppend(idec, buffer, len);
333                 if (status != VP8_STATUS_OK) {
334                         fprintf(stderr, "webp decode status %d\n", status);
335                         WebPIDelete(idec);
336                         WebPFreeDecBuffer(&config.output);
337                         return NULL;
338                 }
339         }
340
341         WebPIDelete(idec);
342         WebPFreeDecBuffer(&config.output);
343
344         return pixman_image_create_bits(PIXMAN_a8r8g8b8,
345                                         config.input.width,
346                                         config.input.height,
347                                         (uint32_t *) config.output.u.RGBA.rgba,
348                                         config.output.u.RGBA.stride);
349 }
350
351 #endif
352
353
354 struct image_loader {
355         unsigned char header[4];
356         int header_size;
357         pixman_image_t *(*load)(FILE *fp);
358 };
359
360 static const struct image_loader loaders[] = {
361         { { 0x89, 'P', 'N', 'G' }, 4, load_png },
362         { { 0xff, 0xd8 }, 2, load_jpeg },
363 #ifdef HAVE_WEBP
364         { { 'R', 'I', 'F', 'F' }, 4, load_webp }
365 #endif
366 };
367
368 pixman_image_t *
369 load_image(const char *filename)
370 {
371         pixman_image_t *image;
372         unsigned char header[4];
373         FILE *fp;
374         unsigned int i;
375
376         fp = fopen(filename, "rb");
377         if (fp == NULL)
378                 return NULL;
379
380         if (fread(header, sizeof header, 1, fp) != 1) {
381                 fclose(fp);
382                 return NULL;
383         }
384
385         rewind(fp);
386         for (i = 0; i < ARRAY_LENGTH(loaders); i++) {
387                 if (memcmp(header, loaders[i].header,
388                            loaders[i].header_size) == 0) {
389                         image = loaders[i].load(fp);
390                         break;
391                 }
392         }
393
394         fclose(fp);
395
396         if (i == ARRAY_LENGTH(loaders)) {
397                 fprintf(stderr, "unrecognized file header for %s: "
398                         "0x%02x 0x%02x 0x%02x 0x%02x\n",
399                         filename, header[0], header[1], header[2], header[3]);
400                 image = NULL;
401         }
402
403         return image;
404 }