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

Reply via email to