From: Tiago Vignatti <tiago.vigna...@intel.com> It caches the image using load_jpeg at initialization and the draw handler does the repaint with the correct size. I set nearest-neighbor filtering on cairo which gives a better effect when resizing.
Images now are scaled-up correctly without ugly black background. Signed-off-by: Tiago Vignatti <tiago.vigna...@intel.com> --- clients/image.c | 138 +++++++++++++++---------------------------------------- 1 files changed, 37 insertions(+), 101 deletions(-) diff --git a/clients/image.c b/clients/image.c index b12a360..a1920db 100644 --- a/clients/image.c +++ b/clients/image.c @@ -38,121 +38,41 @@ #include <wayland-client.h> #include "window.h" +#include "cairo-util.h" struct image { struct window *window; struct display *display; uint32_t key; gchar *filename; + cairo_surface_t *c_image; }; static void -set_source_pixbuf(cairo_t *cr, - const GdkPixbuf *pixbuf, - double src_x, - double src_y, - double src_width, - double src_height) +image_load(struct image *image) { - gint width = gdk_pixbuf_get_width (pixbuf); - gint height = gdk_pixbuf_get_height (pixbuf); - guchar *gdk_pixels = gdk_pixbuf_get_pixels (pixbuf); - int gdk_rowstride = gdk_pixbuf_get_rowstride (pixbuf); - int n_channels = gdk_pixbuf_get_n_channels (pixbuf); - int cairo_stride; - guchar *cairo_pixels; - cairo_format_t format; - cairo_surface_t *surface; - int j; - - if (n_channels == 3) - format = CAIRO_FORMAT_RGB24; + if (image->filename) + image->c_image = load_jpeg(image->filename); else - format = CAIRO_FORMAT_ARGB32; - - surface = cairo_image_surface_create(format, width, height); - if (cairo_surface_status(surface)) { - cairo_set_source_surface(cr, surface, 0, 0); - return; - } - - cairo_stride = cairo_image_surface_get_stride(surface); - cairo_pixels = cairo_image_surface_get_data(surface); - - for (j = height; j; j--) { - guchar *p = gdk_pixels; - guchar *q = cairo_pixels; - - if (n_channels == 3) { - guchar *end = p + 3 * width; - - while (p < end) { -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - q[0] = p[2]; - q[1] = p[1]; - q[2] = p[0]; -#else - q[1] = p[0]; - q[2] = p[1]; - q[3] = p[2]; -#endif - p += 3; - q += 4; - } - } else { - guchar *end = p + 4 * width; - guint t1,t2,t3; - -#define MULT(d,c,a,t) G_STMT_START { t = c * a + 0x7f; d = ((t >> 8) + t) >> 8; } G_STMT_END - - while (p < end) { -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - MULT(q[0], p[2], p[3], t1); - MULT(q[1], p[1], p[3], t2); - MULT(q[2], p[0], p[3], t3); - q[3] = p[3]; -#else - q[0] = p[3]; - MULT(q[1], p[0], p[3], t1); - MULT(q[2], p[1], p[3], t2); - MULT(q[3], p[2], p[3], t3); -#endif - - p += 4; - q += 4; - } -#undef MULT - } - - gdk_pixels += gdk_rowstride; - cairo_pixels += cairo_stride; - } - cairo_surface_mark_dirty(surface); - - cairo_set_source_surface(cr, surface, - src_x + .5 * (src_width - width), - src_y + .5 * (src_height - height)); - cairo_surface_destroy(surface); + fprintf(stderr, "failed loading image\n"); } static void image_draw(struct image *image) { struct rectangle allocation; - GdkPixbuf *pb; cairo_t *cr; cairo_surface_t *surface; + cairo_pattern_t *pattern; + cairo_matrix_t matrix; + double sx, sy; + int width, height; window_draw(image->window); window_get_child_allocation(image->window, &allocation); - - pb = gdk_pixbuf_new_from_file_at_size(image->filename, - allocation.width, - allocation.height, - NULL); - if (pb == NULL) - return; + width = allocation.width; + height = allocation.height; surface = window_get_surface(image->window); cr = cairo_create(surface); @@ -164,17 +84,23 @@ image_draw(struct image *image) cairo_translate(cr, allocation.x, allocation.y); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - cairo_set_source_rgba(cr, 0, 0, 0, 1); + cairo_set_source_rgba(cr, 0.0, 0.0, 0.2, 1.0); cairo_paint(cr); - set_source_pixbuf(cr, pb, - 0, 0, - allocation.width, allocation.height); + + pattern = cairo_pattern_create_for_surface(image->c_image); + sx = (double) cairo_image_surface_get_width(image->c_image) / width; + sy = (double) cairo_image_surface_get_height(image->c_image) / height; + cairo_matrix_init_scale(&matrix, sx, sy); + cairo_pattern_set_filter(pattern, CAIRO_FILTER_NEAREST); + cairo_pattern_set_matrix(pattern, &matrix); + cairo_set_source(cr, pattern); + cairo_pattern_destroy (pattern); + cairo_set_operator(cr, CAIRO_OPERATOR_OVER); cairo_paint(cr); - g_object_unref(pb); - cairo_pop_group_to_source(cr); + cairo_paint(cr); cairo_destroy(cr); @@ -229,12 +155,20 @@ image_create(struct display *display, uint32_t key, const char *filename) window_set_redraw_handler(image->window, redraw_handler); window_set_keyboard_focus_handler(image->window, keyboard_focus_handler); - + image_load(image); image_draw(image); return image; } +static void +image_destroy(struct image *image) +{ + if (image->c_image) + cairo_surface_destroy(image->c_image); + free(image); +} + static int filter(const struct dirent *entry) { @@ -285,6 +219,7 @@ int main(int argc, char *argv[]) { struct display *d; + struct image *image; int i; d = display_create(&argc, &argv, option_entries); @@ -295,12 +230,13 @@ main(int argc, char *argv[]) /* if not enough args, pick a random image from the system */ if (argc == 1) - image_create (d, 1, get_image_random()); + image = image_create (d, 1, get_image_random()); else for (i = 1; i < argc; i++) - image_create (d, i, argv[i]); + image = image_create (d, i, argv[i]); display_run(d); + image_destroy(image); return 0; } -- 1.7.5.4 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel