[RFC][PATCH] remove gdk-pixbuf and use libpng

Tiago Vignatti tiago.vignatti at nokia.com
Wed Feb 9 03:06:39 PST 2011


Signed-off-by: Tiago Vignatti <tiago.vignatti at nokia.com>
---

This patch is a WIP to remove gdk-pixbuf dependency and use libpng instead.
It is unfinished though and only compositor with simple-client works.

In principle, gdk-pixbuf is a bit bloated and brings a big package dependency
in some platforms which makes harder to try Wayland. On the other hand,
gdk-pixbuf has several modules to convert a bunch of image formats in pixel
data, whereas libpng has only one, obviously. This is the drawback on using
lipng. However, I guess compositor and clients could live happy with libpng
only given they are made for demonstration purposes (well, at least at the
moment).

I won't be playing with this on the next days, but I'd love to help anyone
with this work in the case I got a positive feedback here. Then, the short
TODO on my mind:

- fix command line parsing in compositor.c
- apply analogue changes for other clients and screenshooter


Thanks!

      Tiago

 clients/dnd.c              |    2 +
 clients/image.c            |    6 +++
 clients/window.c           |    6 +++
 compositor/compositor.c    |   92 +++++++++++++++++++++++++++++++++-----------
 compositor/screenshooter.c |    8 ++++
 configure.ac               |    4 +-
 6 files changed, 93 insertions(+), 25 deletions(-)

diff --git a/clients/dnd.c b/clients/dnd.c
index 1625ffd..48d8dc0 100644
--- a/clients/dnd.c
+++ b/clients/dnd.c
@@ -30,7 +30,9 @@
 #include <sys/time.h>
 #include <cairo.h>
 #include <glib.h>
+#ifdef GDK_STUFF
 #include <gdk-pixbuf/gdk-pixbuf.h>
+#endif
 
 #include "wayland-client.h"
 #include "wayland-glib.h"
diff --git a/clients/image.c b/clients/image.c
index 3eada1e..ca144e4 100644
--- a/clients/image.c
+++ b/clients/image.c
@@ -31,7 +31,9 @@
 #include <time.h>
 #include <cairo.h>
 #include <glib.h>
+#ifdef GDK_STUFF
 #include <gdk-pixbuf/gdk-pixbuf.h>
+#endif
 
 #include "wayland-client.h"
 #include "wayland-glib.h"
@@ -45,6 +47,7 @@ struct image {
 	gchar *filename;
 };
 
+#ifdef GDK_STUFF
 static void
 set_source_pixbuf(cairo_t         *cr,
 		  const GdkPixbuf *pixbuf,
@@ -133,10 +136,12 @@ set_source_pixbuf(cairo_t         *cr,
 				 src_y + .5 * (src_height - height));
 	cairo_surface_destroy(surface);
 }
+#endif
 
 static void
 image_draw(struct image *image)
 {
+#ifdef GDK_STUFF
 	struct rectangle allocation;
 	GdkPixbuf *pb;
 	cairo_t *cr;
@@ -179,6 +184,7 @@ image_draw(struct image *image)
 
 	window_flush(image->window);
 	cairo_surface_destroy(surface);
+#endif
 }
 
 static void
diff --git a/clients/window.c b/clients/window.c
index b802518..9fa523e 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -33,7 +33,9 @@
 #include <cairo.h>
 #include <glib.h>
 #include <glib-object.h>
+#ifdef GDK_STUFF
 #include <gdk-pixbuf/gdk-pixbuf.h>
+#endif
 #include <sys/mman.h>
 
 #define EGL_EGLEXT_PROTOTYPES 1
@@ -281,6 +283,7 @@ display_create_egl_image_surface_from_file(struct display *display,
 					   const char *filename,
 					   struct rectangle *rect)
 {
+#ifdef GDK_STUFF
 	cairo_surface_t *surface;
 	GdkPixbuf *pixbuf;
 	GError *error = NULL;
@@ -335,6 +338,7 @@ display_create_egl_image_surface_from_file(struct display *display,
 	g_object_unref(pixbuf);
 
 	return surface;
+#endif
 }
 
 #endif
@@ -429,6 +433,7 @@ display_create_shm_surface_from_file(struct display *display,
 				     const char *filename,
 				     struct rectangle *rect)
 {
+#ifdef GDK_STUFF
 	cairo_surface_t *surface;
 	GdkPixbuf *pixbuf;
 	GError *error = NULL;
@@ -481,6 +486,7 @@ display_create_shm_surface_from_file(struct display *display,
 	g_object_unref(pixbuf);
 
 	return surface;
+#endif
 }
 
 static int
diff --git a/compositor/compositor.c b/compositor/compositor.c
index 535b3f1..8bbe387 100644
--- a/compositor/compositor.c
+++ b/compositor/compositor.c
@@ -28,7 +28,8 @@
 #include <sys/ioctl.h>
 #include <fcntl.h>
 #include <unistd.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <png.h>
+#include <signal.h> /* SIGTERM and SIGINT */
 #include <math.h>
 #include <linux/input.h>
 
@@ -45,10 +46,11 @@ struct wlsc_switcher {
  * advertise that through a service on the session dbus.
  */
 static const char *option_socket_name = NULL;
-static const char *option_background = "background.jpg";
+static const char *option_background = "background.png";
 static const char *option_geometry = "1024x640";
 static int option_connector = 0;
 
+#ifdef GDK_STUFF
 static const GOptionEntry option_entries[] = {
 	{ "background", 'b', 0, G_OPTION_ARG_STRING,
 	  &option_background, "Background image" },
@@ -60,6 +62,7 @@ static const GOptionEntry option_entries[] = {
 	  &option_socket_name, "Socket Name" },
 	{ NULL }
 };
+#endif
 
 static void
 wlsc_matrix_init(struct wlsc_matrix *matrix)
@@ -198,33 +201,76 @@ destroy_surface(struct wl_resource *resource, struct wl_client *client)
 uint32_t *
 wlsc_load_image(const char *filename, int width, int height)
 {
-	GdkPixbuf *pixbuf;
-	GError *error = NULL;
 	int stride, i, n_channels;
-	unsigned char *pixels, *end, *argb_pixels, *s, *d;
-
-	pixbuf = gdk_pixbuf_new_from_file_at_scale(filename,
-						   width, height,
-						   FALSE, &error);
-	if (error != NULL) {
-		fprintf(stderr, "failed to load image: %s\n", error->message);
-		g_error_free(error);
+	unsigned char *end, *argb_pixels, *s, *d;
+
+	int y;
+	png_byte bit_depth;
+	png_structp png_ptr;
+	png_infop info_ptr;
+	int number_of_passes;
+	png_bytep * row_pointers;
+
+	char header[8];    // 8 is the maximum size that can be checked
+
+	/* open file and test for it being a png */
+	FILE *fp = fopen(filename, "rb");
+	if (!fp)
+		fprintf(stderr, "file %s could not be opened for reading", filename);
+
+	fread(header, 1, 8, fp);
+
+	if (png_sig_cmp((png_bytep) header, 0, 8)) {
+		fprintf(stderr, "file %s is not recognized as a PNG file", filename);
 		return NULL;
 	}
 
-	stride = gdk_pixbuf_get_rowstride(pixbuf);
-	pixels = gdk_pixbuf_get_pixels(pixbuf);
-	n_channels = gdk_pixbuf_get_n_channels(pixbuf);
+	/* initialize stuff */
+	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+	if (!png_ptr)
+		fprintf(stderr, "png_create_read_struct failed");
 
-	argb_pixels = malloc (height * width * 4);
-	if (argb_pixels == NULL) {
-		g_object_unref(pixbuf);
+	info_ptr = png_create_info_struct(png_ptr);
+	if (!info_ptr)
+		fprintf(stderr, "png_create_info_struct failed");
+
+	if (setjmp(png_jmpbuf(png_ptr))) {
+		fprintf(stderr, "error during init_io");
 		return NULL;
 	}
 
+	png_init_io(png_ptr, fp);
+	png_set_sig_bytes(png_ptr, 8);
+	png_set_swap_alpha(png_ptr);
+	png_read_info(png_ptr, info_ptr);
+
+	bit_depth = png_get_bit_depth(png_ptr, info_ptr);
+	n_channels = png_get_channels(png_ptr, info_ptr);
+	stride = width * bit_depth * n_channels / 8;
+
+	number_of_passes = png_set_interlace_handling(png_ptr);
+	png_read_update_info(png_ptr, info_ptr);
+
+	/* read file */
+	if (setjmp(png_jmpbuf(png_ptr)))
+		fprintf(stderr, "error during read_image");
+
+	row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
+	for (y=0; y < height; y++)
+		row_pointers[y] = malloc(png_get_rowbytes(png_ptr, info_ptr));
+
+	png_read_image(png_ptr, row_pointers);
+	fclose(fp);
+
+	/* TODO: implement color type checking */
+
+	argb_pixels = malloc (height * width * 4);
+	if (argb_pixels == NULL)
+		return NULL;
+
 	if (n_channels == 4) {
 		for (i = 0; i < height; i++) {
-			s = pixels + i * stride;
+			s = (unsigned char *)row_pointers[i];
 			end = s + width * 4;
 			d = argb_pixels + i * width * 4;
 			while (s < end) {
@@ -243,7 +289,7 @@ wlsc_load_image(const char *filename, int width, int height)
 		}
 	} else if (n_channels == 3) {
 		for (i = 0; i < height; i++) {
-			s = pixels + i * stride;
+			s = (unsigned char *)row_pointers[i];
 			end = s + width * 3;
 			d = argb_pixels + i * width * 4;
 			while (s < end) {
@@ -257,8 +303,6 @@ wlsc_load_image(const char *filename, int width, int height)
 		}
 	}
 
-	g_object_unref(pixbuf);
-
 	return (uint32_t *) argb_pixels;
 }
 
@@ -1283,9 +1327,10 @@ int main(int argc, char *argv[])
 	struct wl_display *display;
 	struct wlsc_compositor *ec;
 	struct wl_event_loop *loop;
+	int width, height;
+#ifdef GDK_STUFF
 	GError *error = NULL;
 	GOptionContext *context;
-	int width, height;
 
 	g_type_init(); /* GdkPixbuf needs this, it seems. */
 
@@ -1295,6 +1340,7 @@ int main(int argc, char *argv[])
 		fprintf(stderr, "option parsing failed: %s\n", error->message);
 		exit(EXIT_FAILURE);
 	}
+#endif
 	if (sscanf(option_geometry, "%dx%d", &width, &height) != 2) {
 		fprintf(stderr, "invalid geometry option: %s \n",
 			option_geometry);
diff --git a/compositor/screenshooter.c b/compositor/screenshooter.c
index 53ed931..a5cece3 100644
--- a/compositor/screenshooter.c
+++ b/compositor/screenshooter.c
@@ -18,7 +18,11 @@
 
 #include <stdlib.h>
 #include <GLES2/gl2.h>
+#ifdef GDK_STUFF
 #include <gdk-pixbuf/gdk-pixbuf.h>
+#else
+#include <stdio.h>
+#endif
 
 #include "compositor.h"
 #include "screenshooter-server-protocol.h"
@@ -34,8 +38,10 @@ screenshooter_shoot(struct wl_client *client, struct wl_screenshooter *shooter)
 	struct wlsc_compositor *ec = shooter->ec;
 	struct wlsc_output *output;
 	char buffer[256];
+#ifdef GDK_STUFF
 	GdkPixbuf *pixbuf;
 	GError *error = NULL;
+#endif
 	unsigned char *data;
 	int i, j;
 
@@ -56,11 +62,13 @@ screenshooter_shoot(struct wl_client *client, struct wl_screenshooter *shooter)
 		for (j = 3; j < output->width * output->height * 4; j += 4)
 			data[j] = 0xff;
 
+#ifdef GDK_STUFF
 		pixbuf = gdk_pixbuf_new_from_data(data, GDK_COLORSPACE_RGB, TRUE,
 						  8, output->width, output->height, output->width * 4,
 						  NULL, NULL);
 		gdk_pixbuf_save(pixbuf, buffer, "png", &error, NULL);
 		g_object_unref(pixbuf);
+#endif
 		free(data);
 	}
 }
diff --git a/configure.ac b/configure.ac
index 868ebb8..38e4ab5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -23,9 +23,9 @@ PKG_PROG_PKG_CONFIG()
 PKG_CHECK_MODULES(FFI, [libffi])
 
 PKG_CHECK_MODULES(COMPOSITOR,
-		  [egl >= 7.10 glesv2 gdk-pixbuf-2.0 libudev >= 136 libdrm >= 2.4.23] xcb-dri2 xcb-xfixes)
+		  [egl >= 7.10 glesv2 libudev >= 136 libdrm >= 2.4.23] libpng xcb-dri2 xcb-xfixes)
 PKG_CHECK_MODULES(GLES2, [egl >= 7.10 glesv2 libdrm >= 2.4.23])
-PKG_CHECK_MODULES(CLIENT, [egl >= 7.10 gl cairo >= 1.10.0 gdk-pixbuf-2.0 glib-2.0 gobject-2.0 xkbcommon libdrm >= 2.4.23])
+PKG_CHECK_MODULES(CLIENT, [egl >= 7.10 gl cairo >= 1.10.0 libpng glib-2.0 gobject-2.0 xkbcommon libdrm >= 2.4.23])
 PKG_CHECK_MODULES(POPPLER, [poppler-glib gdk-2.0 gio-2.0],
 			   [have_poppler=yes], [have_poppler=no])
 AM_CONDITIONAL(HAVE_POPPLER, test "x$have_poppler" = "xyes")
-- 
1.7.1



More information about the wayland-devel mailing list