Hi.
I had some spare time to kill today, so I quickly wrote simple application that showcases the functionality you need. As you can see, I haven't used GTK+ at all (application is linked only against glib, gdk-pixbuf and cairo).
Hope this sample code helps you a bit with your endeavor.
Cheers,
Tadej
Code:
#include <glib.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <cairo.h>
/* RGBA image */
/*#define INPUT "Exhausted.gif" */
/* RGB image */
#define INPUT "Exhausted.jpg"
#define OUTPUT "out.png"
static cairo_surface_t *
convert_pixbuf_to_cairo_surface (GdkPixbuf *pixbuf)
{
/* Pixbuf properties */
int w = gdk_pixbuf_get_width (pixbuf),
h = gdk_pixbuf_get_height (pixbuf),
p_stride = gdk_pixbuf_get_rowstride (pixbuf),
ch = gdk_pixbuf_get_n_channels (pixbuf);
unsigned char *p_pixels = gdk_pixbuf_get_pixels (pixbuf);
/* Equavalent cairo props */
cairo_surface_t *surface;
int c_stride;
unsigned char *c_pixels;
cairo_format_t format;
/* Initialize properties */
if (ch == 3)
format = CAIRO_FORMAT_RGB24;
else
format = CAIRO_FORMAT_ARGB32;
surface = cairo_image_surface_create (format, w, h);
c_stride = cairo_image_surface_get_stride (surface);
c_pixels = cairo_image_surface_get_data (surface);
/* Loop that copies the pixels */
if (ch == 3) /* RGB image */
{
int i;
for (i = 0; i < h; i++)
{
unsigned char *pp = p_pixels + i * p_stride,
*pc = c_pixels + i * c_stride;
int j;
for (j = 0; j < w; j++)
{
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
/* RGB -> BGR(A) */
pc[0] = pp[2];
pc[1] = pp[1];
pc[2] = pp[0];
#else
/* RGB -> (A)RGB */
pc[1] = pp[0];
pc[2] = pp[1];
pc[3] = pp[2];
#endif
pc += 4;
pp += 3;
}
}
}
else /* RGBA image - rounding is not 100% right */
{
int i;
for (i = 0; i < h; i++)
{
unsigned char *pp = p_pixels + i * p_stride,
*pc = c_pixels + i * c_stride;
int j;
for (j = 0; j < w; j++)
{
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
/* RGBA -> BGRA */
pc[0] = (pp[2] * pp[3] + 0x7f) / 0xff;
pc[1] = (pp[1] * pp[3] + 0x7f) / 0xff;
pc[2] = (pp[0] * pp[3] + 0x7f) / 0xff;
pc[3] = pp[3];
#else
/* RGBA -> ARGB */
pc[0] = pp[3];
pc[1] = (pp[0] * pp[3] + 0x7f) / 0xff;
pc[2] = (pp[1] * pp[3] + 0x7f) / 0xff;
pc[3] = (pp[2] * pp[3] + 0x7f) / 0xff;
#endif
pc += 4;
pp += 4;
}
}
}
return surface;
}
int
main (int argc,
char **argv)
{
GdkPixbuf *pixbuf;
cairo_surface_t *surf;
g_type_init ();
pixbuf = gdk_pixbuf_new_from_file (INPUT, NULL);
g_print ("Channels: %d\n", gdk_pixbuf_get_n_channels (pixbuf));
surf = convert_pixbuf_to_cairo_surface (pixbuf);
/* You can now do just about anything you want using cairo */
cairo_surface_write_to_png (surf, OUTPUT);
return 0;
}
Makefile (for convenience)
Code:
PKGS=glib-2.0 gdk-pixbuf-2.0 cairo
CFLAGS=-ggdb -Wall `pkg-config --cflags ${PKGS}`
LDFLAGS=-ggdb -Wall `pkg-config --libs ${PKGS}`
all: stamp
clean:
rm -f stamp *.o