[PATCH 5/6] clients: image: use cairo for getting image
Tiago Vignatti
vignatti at freedesktop.org
Wed Dec 21 09:34:13 PST 2011
From: Tiago Vignatti <tiago.vignatti at 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.vignatti at 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
More information about the wayland-devel
mailing list