2 * draw.c - draw functions
4 * Copyright © 2007-2009 Julien Danjou <julien@danjou.info>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
31 #include <gdk-pixbuf/gdk-pixbuf.h>
32 #include <cairo-xcb.h>
35 /** Convert text from any charset to UTF-8 using iconv.
36 * \param iso The ISO string to convert.
37 * \param len The string size.
38 * \param dest The destination pointer. Memory will be allocated, up to you to
39 * free, like any char *.
40 * \param dlen The destination length, can be NULL.
41 * \return True if conversion was done.
44 draw_iso2utf8(const char *iso
, size_t len
, char **dest
, ssize_t
*dlen
)
46 static iconv_t iso2utf8
= (iconv_t
) -1;
47 static int8_t dont_need_convert
= -1;
49 if(dont_need_convert
== -1)
50 dont_need_convert
= A_STREQ(nl_langinfo(CODESET
), "UTF-8");
52 if(!len
|| dont_need_convert
)
55 if(iso2utf8
== (iconv_t
) -1)
57 iso2utf8
= iconv_open("UTF-8", nl_langinfo(CODESET
));
58 if(iso2utf8
== (iconv_t
) -1)
61 warn("unable to convert text from %s to UTF-8, not available",
62 nl_langinfo(CODESET
));
64 warn("unable to convert text: %s", strerror(errno
));
70 size_t orig_utf8len
, utf8len
;
73 orig_utf8len
= utf8len
= 2 * len
+ 1;
74 utf8
= *dest
= p_new(char, utf8len
);
76 if(iconv(iso2utf8
, (char **) &iso
, &len
, &utf8
, &utf8len
) == (size_t) -1)
78 warn("text conversion failed: %s", strerror(errno
));
84 *dlen
= orig_utf8len
- utf8len
;
89 static cairo_user_data_key_t data_key
;
97 /** Create a surface object from this image data.
98 * \param L The lua stack.
99 * \param width The width of the image.
100 * \param height The height of the image
101 * \param data The image's data in ARGB format, will be copied by this function.
102 * \return Number of items pushed on the lua stack.
105 draw_surface_from_data(int width
, int height
, uint32_t *data
)
107 unsigned long int len
= width
* height
;
109 uint32_t *buffer
= p_new(uint32_t, len
);
110 cairo_surface_t
*surface
;
112 /* Cairo wants premultiplied alpha, meh :( */
113 for(i
= 0; i
< len
; i
++)
115 uint8_t a
= (data
[i
] >> 24) & 0xff;
116 double alpha
= a
/ 255.0;
117 uint8_t r
= ((data
[i
] >> 16) & 0xff) * alpha
;
118 uint8_t g
= ((data
[i
] >> 8) & 0xff) * alpha
;
119 uint8_t b
= ((data
[i
] >> 0) & 0xff) * alpha
;
120 buffer
[i
] = (a
<< 24) | (r
<< 16) | (g
<< 8) | b
;
124 cairo_image_surface_create_for_data((unsigned char *) buffer
,
129 /* This makes sure that buffer will be freed */
130 cairo_surface_set_user_data(surface
, &data_key
, buffer
, &free_data
);
135 /** Create a surface object from this pixbuf
136 * \param buf The pixbuf
137 * \return Number of items pushed on the lua stack.
139 static cairo_surface_t
*
140 draw_surface_from_pixbuf(GdkPixbuf
*buf
)
142 int width
= gdk_pixbuf_get_width(buf
);
143 int height
= gdk_pixbuf_get_height(buf
);
144 int pix_stride
= gdk_pixbuf_get_rowstride(buf
);
145 guchar
*pixels
= gdk_pixbuf_get_pixels(buf
);
146 int channels
= gdk_pixbuf_get_n_channels(buf
);
147 cairo_surface_t
*surface
;
149 unsigned char *cairo_pixels
;
151 cairo_format_t format
= CAIRO_FORMAT_ARGB32
;
153 format
= CAIRO_FORMAT_RGB24
;
155 surface
= cairo_image_surface_create(format
, width
, height
);
156 cairo_surface_flush(surface
);
157 cairo_stride
= cairo_image_surface_get_stride(surface
);
158 cairo_pixels
= cairo_image_surface_get_data(surface
);
160 for (int y
= 0; y
< height
; y
++)
162 guchar
*row
= pixels
;
163 uint32_t *cairo
= (uint32_t *) cairo_pixels
;
164 for (int x
= 0; x
< width
; x
++) {
170 *cairo
++ = (r
<< 16) | (g
<< 8) | b
;
176 double alpha
= a
/ 255.0;
180 *cairo
++ = (a
<< 24) | (r
<< 16) | (g
<< 8) | b
;
183 pixels
+= pix_stride
;
184 cairo_pixels
+= cairo_stride
;
187 cairo_surface_mark_dirty(surface
);
191 /** Duplicate the specified image surface.
192 * \param surface The surface to copy
193 * \return A pointer to a new cairo image surface.
196 draw_dup_image_surface(cairo_surface_t
*surface
)
198 cairo_surface_t
*res
= cairo_image_surface_create(
199 cairo_image_surface_get_format(surface
),
200 cairo_image_surface_get_width(surface
),
201 cairo_image_surface_get_height(surface
));
203 cairo_t
*cr
= cairo_create(res
);
204 cairo_set_source_surface(cr
, surface
, 0, 0);
205 cairo_set_operator(cr
, CAIRO_OPERATOR_SOURCE
);
212 /** Load the specified path into a cairo surface
214 * \param path file to load
215 * \return A cairo image surface or NULL on error.
218 draw_load_image(lua_State
*L
, const char *path
)
220 GError
*error
= NULL
;
221 cairo_surface_t
*ret
;
222 GdkPixbuf
*buf
= gdk_pixbuf_new_from_file(path
, &error
);
226 lua_pushstring(L
, error
->message
);
233 ret
= draw_surface_from_pixbuf(buf
);
238 xcb_visualtype_t
*draw_find_visual(const xcb_screen_t
*s
, xcb_visualid_t visual
)
240 xcb_depth_iterator_t depth_iter
= xcb_screen_allowed_depths_iterator(s
);
243 for(; depth_iter
.rem
; xcb_depth_next (&depth_iter
))
244 for(xcb_visualtype_iterator_t visual_iter
= xcb_depth_visuals_iterator(depth_iter
.data
);
245 visual_iter
.rem
; xcb_visualtype_next (&visual_iter
))
246 if(visual
== visual_iter
.data
->visual_id
)
247 return visual_iter
.data
;
252 xcb_visualtype_t
*draw_default_visual(const xcb_screen_t
*s
)
254 return draw_find_visual(s
, s
->root_visual
);
257 xcb_visualtype_t
*draw_argb_visual(const xcb_screen_t
*s
)
259 xcb_depth_iterator_t depth_iter
= xcb_screen_allowed_depths_iterator(s
);
262 for(; depth_iter
.rem
; xcb_depth_next (&depth_iter
))
263 if(depth_iter
.data
->depth
== 32)
264 for(xcb_visualtype_iterator_t visual_iter
= xcb_depth_visuals_iterator(depth_iter
.data
);
265 visual_iter
.rem
; xcb_visualtype_next (&visual_iter
))
266 return visual_iter
.data
;
271 uint8_t draw_visual_depth(const xcb_screen_t
*s
, xcb_visualid_t vis
)
273 xcb_depth_iterator_t depth_iter
= xcb_screen_allowed_depths_iterator(s
);
276 for(; depth_iter
.rem
; xcb_depth_next (&depth_iter
))
277 for(xcb_visualtype_iterator_t visual_iter
= xcb_depth_visuals_iterator(depth_iter
.data
);
278 visual_iter
.rem
; xcb_visualtype_next (&visual_iter
))
279 if(vis
== visual_iter
.data
->visual_id
)
280 return depth_iter
.data
->depth
;
282 fatal("Could not find a visual's depth");
285 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80