cairo-util: Add helper to load jpeg files
[profile/ivi/weston-ivi-shell.git] / clients / cairo-util.c
1 /*
2  * Copyright © 2008 Kristian Høgsberg
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that copyright
7  * notice and this permission notice appear in supporting documentation, and
8  * that the name of the copyright holders not be used in advertising or
9  * publicity pertaining to distribution of the software without specific,
10  * written prior permission.  The copyright holders make no representations
11  * about the suitability of this software for any purpose.  It is provided "as
12  * is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20  * OF THIS SOFTWARE.
21  */
22
23 #include <stdint.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <math.h>
28 #include <cairo.h>
29 #include "cairo-util.h"
30
31 #include <jpeglib.h>
32
33 #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
34
35 void
36 surface_flush_device(cairo_surface_t *surface)
37 {
38         cairo_device_t *device;
39
40         device = cairo_surface_get_device(surface);
41         if (device)
42                 cairo_device_flush(device);
43 }
44
45 void
46 blur_surface(cairo_surface_t *surface, int margin)
47 {
48         int32_t width, height, stride, x, y, z, w;
49         uint8_t *src, *dst;
50         uint32_t *s, *d, a, p;
51         int i, j, k, size, half;
52         uint32_t kernel[49];
53         double f;
54
55         size = ARRAY_LENGTH(kernel);
56         width = cairo_image_surface_get_width(surface);
57         height = cairo_image_surface_get_height(surface);
58         stride = cairo_image_surface_get_stride(surface);
59         src = cairo_image_surface_get_data(surface);
60
61         dst = malloc(height * stride);
62
63         half = size / 2;
64         a = 0;
65         for (i = 0; i < size; i++) {
66                 f = (i - half);
67                 kernel[i] = exp(- f * f / ARRAY_LENGTH(kernel)) * 10000;
68                 a += kernel[i];
69         }
70
71         for (i = 0; i < height; i++) {
72                 s = (uint32_t *) (src + i * stride);
73                 d = (uint32_t *) (dst + i * stride);
74                 for (j = 0; j < width; j++) {
75                         if (margin < j && j < width - margin) {
76                                 d[j] = s[j];
77                                 continue;
78                         }
79
80                         x = 0;
81                         y = 0;
82                         z = 0;
83                         w = 0;
84                         for (k = 0; k < size; k++) {
85                                 if (j - half + k < 0 || j - half + k >= width)
86                                         continue;
87                                 p = s[j - half + k];
88
89                                 x += (p >> 24) * kernel[k];
90                                 y += ((p >> 16) & 0xff) * kernel[k];
91                                 z += ((p >> 8) & 0xff) * kernel[k];
92                                 w += (p & 0xff) * kernel[k];
93                         }
94                         d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a;
95                 }
96         }
97
98         for (i = 0; i < height; i++) {
99                 s = (uint32_t *) (dst + i * stride);
100                 d = (uint32_t *) (src + i * stride);
101                 for (j = 0; j < width; j++) {
102                         if (margin <= i && i < height - margin) {
103                                 d[j] = s[j];
104                                 continue;
105                         }
106
107                         x = 0;
108                         y = 0;
109                         z = 0;
110                         w = 0;
111                         for (k = 0; k < size; k++) {
112                                 if (i - half + k < 0 || i - half + k >= height)
113                                         continue;
114                                 s = (uint32_t *) (dst + (i - half + k) * stride);
115                                 p = s[j];
116
117                                 x += (p >> 24) * kernel[k];
118                                 y += ((p >> 16) & 0xff) * kernel[k];
119                                 z += ((p >> 8) & 0xff) * kernel[k];
120                                 w += (p & 0xff) * kernel[k];
121                         }
122                         d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a;
123                 }
124         }
125
126         free(dst);
127         cairo_surface_mark_dirty(surface);
128 }
129
130 void
131 tile_mask(cairo_t *cr, cairo_surface_t *surface,
132           int x, int y, int width, int height, int margin, int top_margin)
133 {
134         cairo_pattern_t *pattern;
135         cairo_matrix_t matrix;
136         int i, fx, fy, vmargin;
137
138         cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
139         pattern = cairo_pattern_create_for_surface (surface);
140
141         for (i = 0; i < 4; i++) {
142                 fx = i & 1;
143                 fy = i >> 1;
144
145                 cairo_matrix_init_translate(&matrix,
146                                             -x + fx * (128 - width),
147                                             -y + fy * (128 - height));
148                 cairo_pattern_set_matrix(pattern, &matrix);
149
150                 if (fy)
151                         vmargin = margin;
152                 else
153                         vmargin = top_margin;
154
155                 cairo_reset_clip(cr);
156                 cairo_rectangle(cr,
157                                 x + fx * (width - margin),
158                                 y + fy * (height - vmargin),
159                                 margin, vmargin);
160                 cairo_clip (cr);
161                 cairo_mask(cr, pattern);
162         }
163
164         /* Top strecth */
165         cairo_matrix_init_translate(&matrix, 64, 0);
166         cairo_matrix_scale(&matrix, 64.0 / (width - 2 * margin), 1);
167         cairo_matrix_translate(&matrix, -x - width / 2, -y);
168         cairo_pattern_set_matrix(pattern, &matrix);
169         cairo_rectangle(cr, x + margin, y, width - 2 * margin, margin);
170
171         cairo_reset_clip(cr);
172         cairo_rectangle(cr,
173                         x + margin,
174                         y,
175                         width - 2 * margin, margin);
176         cairo_clip (cr);
177         cairo_mask(cr, pattern);
178
179         /* Bottom strecth */
180         cairo_matrix_translate(&matrix, 0, -height + 128);
181         cairo_pattern_set_matrix(pattern, &matrix);
182
183         cairo_reset_clip(cr);
184         cairo_rectangle(cr, x + margin, y + height - margin,
185                         width - 2 * margin, margin);
186         cairo_clip (cr);
187         cairo_mask(cr, pattern);
188
189         /* Left strecth */
190         cairo_matrix_init_translate(&matrix, 0, 64);
191         cairo_matrix_scale(&matrix, 1, 64.0 / (height - 2 * margin));
192         cairo_matrix_translate(&matrix, -x, -y - height / 2);
193         cairo_pattern_set_matrix(pattern, &matrix);
194         cairo_reset_clip(cr);
195         cairo_rectangle(cr, x, y + margin, margin, height - 2 * margin);
196         cairo_clip (cr);
197         cairo_mask(cr, pattern);
198
199         /* Right strecth */
200         cairo_matrix_translate(&matrix, -width + 128, 0);
201         cairo_pattern_set_matrix(pattern, &matrix);
202         cairo_rectangle(cr, x + width - margin, y + margin,
203                         margin, height - 2 * margin);
204         cairo_reset_clip(cr);
205         cairo_clip (cr);
206         cairo_mask(cr, pattern);
207
208         cairo_pattern_destroy(pattern);
209         cairo_reset_clip(cr);
210 }
211
212 void
213 tile_source(cairo_t *cr, cairo_surface_t *surface,
214             int x, int y, int width, int height, int margin, int top_margin)
215 {
216         cairo_pattern_t *pattern;
217         cairo_matrix_t matrix;
218         int i, fx, fy, vmargin;
219
220         cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
221         pattern = cairo_pattern_create_for_surface (surface);
222         cairo_set_source(cr, pattern);
223         cairo_pattern_destroy(pattern);
224
225         for (i = 0; i < 4; i++) {
226                 fx = i & 1;
227                 fy = i >> 1;
228
229                 cairo_matrix_init_translate(&matrix,
230                                             -x + fx * (128 - width),
231                                             -y + fy * (128 - height));
232                 cairo_pattern_set_matrix(pattern, &matrix);
233
234                 if (fy)
235                         vmargin = margin;
236                 else
237                         vmargin = top_margin;
238
239                 cairo_rectangle(cr,
240                                 x + fx * (width - margin),
241                                 y + fy * (height - vmargin),
242                                 margin, vmargin);
243                 cairo_fill(cr);
244         }
245
246         /* Top strecth */
247         cairo_matrix_init_translate(&matrix, 64, 0);
248         cairo_matrix_scale(&matrix, 64.0 / (width - 2 * margin), 1);
249         cairo_matrix_translate(&matrix, -x - width / 2, -y);
250         cairo_pattern_set_matrix(pattern, &matrix);
251         cairo_rectangle(cr, x + margin, y, width - 2 * margin, top_margin);
252         cairo_fill(cr);
253
254         /* Bottom strecth */
255         cairo_matrix_translate(&matrix, 0, -height + 128);
256         cairo_pattern_set_matrix(pattern, &matrix);
257         cairo_rectangle(cr, x + margin, y + height - margin,
258                         width - 2 * margin, margin);
259         cairo_fill(cr);
260
261         /* Left strecth */
262         cairo_matrix_init_translate(&matrix, 0, 64);
263         cairo_matrix_scale(&matrix, 1, 64.0 / (height - margin - top_margin));
264         cairo_matrix_translate(&matrix, -x, -y - height / 2);
265         cairo_pattern_set_matrix(pattern, &matrix);
266         cairo_rectangle(cr, x, y + top_margin,
267                         margin, height - margin - top_margin);
268         cairo_fill(cr);
269
270         /* Right strecth */
271         cairo_matrix_translate(&matrix, -width + 128, 0);
272         cairo_pattern_set_matrix(pattern, &matrix);
273         cairo_rectangle(cr, x + width - margin, y + top_margin,
274                         margin, height - margin - top_margin);
275         cairo_fill(cr);
276 }
277
278 void
279 rounded_rect(cairo_t *cr, int x0, int y0, int x1, int y1, int radius)
280 {
281         cairo_move_to(cr, x0, y0 + radius);
282         cairo_arc(cr, x0 + radius, y0 + radius, radius, M_PI, 3 * M_PI / 2);
283         cairo_line_to(cr, x1 - radius, y0);
284         cairo_arc(cr, x1 - radius, y0 + radius, radius, 3 * M_PI / 2, 2 * M_PI);
285         cairo_line_to(cr, x1, y1 - radius);
286         cairo_arc(cr, x1 - radius, y1 - radius, radius, 0, M_PI / 2);
287         cairo_line_to(cr, x0 + radius, y1);
288         cairo_arc(cr, x0 + radius, y1 - radius, radius, M_PI / 2, M_PI);
289         cairo_close_path(cr);
290 }
291
292 cairo_surface_t *
293 load_jpeg(const char *filename)
294 {
295         struct jpeg_decompress_struct cinfo;
296         struct jpeg_error_mgr jerr;
297         FILE *fp;
298         int stride, i;
299         JSAMPLE *data, *rows[4];
300
301         cinfo.err = jpeg_std_error(&jerr);
302         jpeg_create_decompress(&cinfo);
303
304         fp = fopen(filename, "rb");
305         if (fp == NULL) {
306                 fprintf(stderr, "can't open %s\n", filename);
307                 return NULL;
308         }
309         jpeg_stdio_src(&cinfo, fp);
310
311         jpeg_read_header(&cinfo, TRUE);
312
313         cinfo.out_color_space = JCS_EXT_BGRX;
314         jpeg_start_decompress(&cinfo);
315
316         stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24,
317                                                cinfo.output_width);
318         data = malloc(stride * cinfo.output_height);
319         if (data == NULL) {
320                 fprintf(stderr, "couldn't allocate image data\n");
321                 return NULL;
322         }
323
324         while (cinfo.output_scanline < cinfo.output_height) {
325                 for (i = 0; i < ARRAY_LENGTH(rows); i++, p += stride)
326                         rows[i] = data + (cinfo.output_scanline + i) * stride;
327
328                 jpeg_read_scanlines(&cinfo, rows, ARRAY_LENGTH(rows));
329         }
330
331         jpeg_finish_decompress(&cinfo);
332
333         fclose(fp);
334
335         jpeg_destroy_decompress(&cinfo);
336
337         return cairo_image_surface_create_for_data (data,
338                                                     CAIRO_FORMAT_RGB24,
339                                                     cinfo.output_width,
340                                                     cinfo.output_height,
341                                                     stride);
342 }