diff options
author | Cody Russell <bratsche@src.gnome.org> | 1999-11-13 01:27:21 +0000 |
---|---|---|
committer | Cody Russell <bratsche@src.gnome.org> | 1999-11-13 01:27:21 +0000 |
commit | 9599825ea912a88ef4ce450a1a4d07dbc4cf1d70 (patch) | |
tree | efa60686bfd458a580b23f6428d13c03ef8d004c /gdk/gdkpixbuf-drawable.c | |
parent | 28bcddaca2688b2051f6af967e272d5ac1729d07 (diff) | |
download | gtk+-9599825ea912a88ef4ce450a1a4d07dbc4cf1d70.tar.gz |
Applying Michael Zucchi's changes to significantly speed up pixbuf from drawable code.
Diffstat (limited to 'gdk/gdkpixbuf-drawable.c')
-rw-r--r-- | gdk/gdkpixbuf-drawable.c | 589 |
1 files changed, 477 insertions, 112 deletions
diff --git a/gdk/gdkpixbuf-drawable.c b/gdk/gdkpixbuf-drawable.c index d0c3151f10..0dd668406c 100644 --- a/gdk/gdkpixbuf-drawable.c +++ b/gdk/gdkpixbuf-drawable.c @@ -1,9 +1,11 @@ /* * Creates an GdkPixbuf from a Drawable * - * Author: + * Authors: * Cody Russell <bratsche@dfw.net> + * Michael Zucchi <zucchi@zedzone.mmc.com.au> */ + #include <config.h> #include <stdio.h> #include <string.h> @@ -12,130 +14,493 @@ #include "gdk-pixbuf.h" #include "gdk-pixbuf-drawable.h" -/* private function */ + +#if (G_BYTE_ORDER == G_LITTLE_ENDIAN) +#define LITTLE +#endif +#define d(x) + +unsigned long mask_table[] = { + 0x00000000, 0x00000001, 0x00000003, 0x00000007, + 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, + 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, + 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, + 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff, + 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff, + 0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff, + 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, + 0xffffffff +}; static GdkPixbuf * -gdk_pixbuf_from_drawable_core (GdkWindow *window, gint x, gint y, gint width, gint height, - gint with_alpha) +gdk_pixbuf_from_drawable_core (GdkPixmap * window, gint x, gint y, gint width, + gint height, gint with_alpha) { - GdkImage *image; - ArtPixBuf *art_pixbuf; - GdkColormap *colormap; - art_u8 *buff; - art_u8 *pixels; - gulong pixel; - gint rowstride; - art_u8 r, g, b; - gint xx, yy; - gint fatness; - gint screen_width, screen_height; - gint window_width, window_height, window_x, window_y; - - g_return_val_if_fail (window != NULL, NULL); - - screen_width = gdk_screen_width(); - screen_height = gdk_screen_height(); - gdk_window_get_geometry(window, NULL, NULL, - &window_width, &window_height, NULL); - gdk_window_get_origin(window, &window_x, &window_y); - - /* If part of the requested image is offscreen, return NULL. */ - if((window_x) < 0 || (window_y < 0) || - (window_x + window_width > screen_width) || - (window_y + window_height > screen_height)) - { - return NULL; - } - - image = gdk_image_get (window, x, y, width, height); + GdkImage *image; + ArtPixBuf *art_pixbuf; + GdkColormap *colormap; + art_u8 *buff; + art_u8 *pixels; + gulong pixel; + gint rowstride; + art_u8 r, g, b; + gint xx, yy; + gint fatness; + gint screen_width, screen_height; + gint window_width, window_height, window_x, window_y; + int bpl; + + g_return_val_if_fail (window != NULL, NULL); + + /* always returns image in ZPixmap format ... */ + image = gdk_image_get (window, x, y, width, height); + + fatness = with_alpha ? 4 : 3; + rowstride = width * fatness; + + buff = art_alloc (rowstride * height); + pixels = buff; + +#if 0 + printf ("bpp = %d\n", image->bpp); + printf ("depth = %d\n", image->depth); + printf ("byte order = %d\n", image->byte_order); + printf ("bytes/line = %d\n", image->bpl); +#endif + + bpl = image->bpl; + + switch (image->bpp) + { + case 1: + { + unsigned char *s; + register unsigned char bits; + register unsigned char data; + unsigned char *o; + unsigned char *srow = image->mem, *orow = pixels; + int i, base; + + d (printf ("1 bits/pixel\n")); + + /* convert upto 8 pixels/time */ colormap = gdk_rgb_get_cmap (); + for (yy = 0; yy < height; yy++) + { + s = srow; + o = orow; + + for (xx = 0; xx < width; xx += 8) + { + bits = *s++; + + if (xx + 8 >= width) + base = 7 - (xx + 8 - width); + else + base = 0; + + for (i = 7; i >= base; i--) + { + data = (bits & (0x80 >> i)) & 1; + *o++ = colormap->colors[data].red; + *o++ = colormap->colors[data].green; + *o++ = colormap->colors[data].blue; + } + } + + srow += bpl; + orow += rowstride; + } + break; + } + + case 8: + { + unsigned char *s; + unsigned long mask; + register unsigned long data; + unsigned char *o; + unsigned char *srow = image->mem, *orow = pixels; + + d (printf ("8 bits/pixel\n")); + + colormap = gdk_rgb_get_cmap (); + mask = mask_table[image->depth]; + + for (yy = 0; yy < height; yy++) + { + s = srow; + o = orow; + for (xx = 0; xx < width; xx++) + { + data = *s++ & mask; + *o++ = colormap->colors[data].red; + *o++ = colormap->colors[data].green; + *o++ = colormap->colors[data].blue; + } + srow += bpl; + orow += rowstride; + } + break; + } + + /*#define SIMPLE_16 this is really quite slow ! */ + case 16: + { +#ifdef SIMPLE_16 + unsigned short *s; +#else + unsigned long *s; /* read 2 pixels at once */ +#endif + register unsigned long data; + unsigned short *o; + unsigned char *srow = image->mem, *orow = pixels; + + printf ("16 bits/pixel\n"); + + for (yy = 0; yy < height; yy++) + { + s = srow; + o = orow; + + if (image->byte_order == GDK_LSB_FIRST) + { +#ifdef SIMPLE_16 + for (xx = 0; xx < width; xx++) + { + data = *s++; + *o++ = (data >> 8) & 0xf8; + *o++ = (data >> 3) & 0xfc; + *o++ = (data << 3) & 0xf8; + } +#else + switch (image->depth) + { + case 15: + /* starts at 1, so we dont over-flow the conversion */ + for (xx = 0; xx < width; xx += 2) + { + /* read/convert 2 pixels at a time */ + + /* little endian, lsb data */ +#ifdef LITTLE + /*7c 3e 1f */ + data = *s++; + *o++ = (data & 0x7c00) >> 7 | (data & 0x3e0) << 6; + *o++ = (data & 0x1f) << 3 | (data & 0x7c000000) >> 15; + *o++ = + ((data & 0x3e00000) >> 18) | (data & 0x1f0000) >> 5; +#else + /* big endian, lsb data */ + /* swap endianness first */ + data = (unsigned long) ((unsigned char *) s)[3] << 24 + | (unsigned long) ((unsigned char *) s)[2] << 16 + | (unsigned long) ((unsigned char *) s)[1] << 8 + | (unsigned long) ((unsigned char *) s)[0]; + s++; + *o++ = (data & 0x7c00) << 1 | (data & 0x3e0) >> 2; + *o++ = + (data & 0x1f) << 11 | (data & 0x7c000000) >> 23; + *o++ = + ((data & 0x3e00000) >> 10) | (data & 0x1f0000) >> + 13; +#endif + } + /* check for last remaining pixel */ + if (width & 1) + { + register unsigned short data; +#ifdef LITTLE + data = *((short *) s); +#else + data = *((short *) s); + data = ((data >> 8) & 0xff) | ((data & 0xff) << 8); + data &= mask; +#endif + ((char *) o)[0] = (data & 0x7c0) >> 7; + ((char *) o)[1] = (data & 0x3e0) >> 2; + ((char *) o)[2] = (data & 0x1f) << 3; + } + break; + case 16: + for (xx = 0; xx < width; xx += 2) + { + /* read/convert 2 pixels at a time */ + + /* little endian, lsb data */ +#ifdef LITTLE + data = *s++; + *o++ = (data & 0xf800) >> 8 | (data & 0x7e0) << 5; + *o++ = (data & 0x1f) << 3 | (data & 0xf8000000) >> 16; + *o++ = + ((data & 0x7e00000) >> 19) | (data & 0x1f0000) >> 5; +#else + /* big endian, lsb data */ + /* swap endianness first */ + data = (unsigned long) ((unsigned char *) s)[3] << 24 + | (unsigned long) ((unsigned char *) s)[2] << 16 + | (unsigned long) ((unsigned char *) s)[1] << 8 + | (unsigned long) ((unsigned char *) s)[0]; + s++; + *o++ = (data & 0xf800) | (data & 0x7e0) >> 3; + *o++ = + (data & 0x1f) << 11 | (data & 0xf8000000) >> 24; + *o++ = + ((data & 0x7e00000) >> 11) | (data & 0x1f0000) >> + 13; +#endif + } + /* check for last remaining pixel */ + if (width & 1) + { + register unsigned short data; +#ifdef LITTLE + data = *((short *) s); +#else + data = *((short *) s); + data = ((data >> 8) & 0xff) | ((data & 0xff) << 8); +#endif + ((char *) o)[0] = (data >> 8) & 0xf8; + ((char *) o)[1] = (data >> 3) & 0xfc; + ((char *) o)[2] = (data << 3) & 0xf8; + } + break; + } +#endif /* SIMPLE_16 */ + } + else + { + switch (image->depth) + { + case 15: + for (xx = 0; xx < width; xx += 2) + { + /* read/convert 2 pixels at a time */ +#ifdef LITTLE + /* little endian, msb data */ + /* swap endianness first */ + data = (unsigned long) ((unsigned char *) s)[0] << 24 + | (unsigned long) ((unsigned char *) s)[1] << 16 + | (unsigned long) ((unsigned char *) s)[2] << 8 + | (unsigned long) ((unsigned char *) s)[3]; + s++; + /*7c 3e 1f */ + *o++ = (data & 0x7c00) >> 7 | (data & 0x3e0) << 6; + *o++ = (data & 0x1f) << 3 | (data & 0x7c000000) >> 15; + *o++ = + ((data & 0x3e00000) >> 18) | (data & 0x1f0000) >> 5; +#else + /* big endian, lsb data */ + data = *s++; + *o++ = (data & 0x7c00) << 1 | (data & 0x3e0) >> 2; + *o++ = + (data & 0x1f) << 11 | (data & 0x7c000000) >> 23; + *o++ = + ((data & 0x3e00000) >> 10) | (data & 0x1f0000) >> + 13; +#endif + } + /* check for last remaining pixel */ + if (width & 1) + { + register unsigned short data; +#ifdef LITTLE + data = *((short *) s); + data = ((data >> 8) & 0xff) | ((data & 0xff) << 8); +#else + data = *((short *) s); +#endif + ((char *) o)[0] = (data >> 8) & 0xf8; + ((char *) o)[1] = (data >> 3) & 0xfc; + ((char *) o)[2] = (data << 3) & 0xf8; + } + break; + case 16: + for (xx = 0; xx < width; xx += 2) + { + /* read/convert 2 pixels at a time */ +#ifdef LITTLE + /* little endian, msb data */ + /* swap endianness first */ + data = (unsigned long) ((unsigned char *) s)[0] << 24 + | (unsigned long) ((unsigned char *) s)[1] << 16 + | (unsigned long) ((unsigned char *) s)[2] << 8 + | (unsigned long) ((unsigned char *) s)[3]; + s++; + *o++ = (data & 0xf800) >> 8 | (data & 0x7e0) << 5; + *o++ = (data & 0x1f) << 3 | (data & 0xf8000000) >> 16; + *o++ = + ((data & 0x7e00000) >> 19) | (data & 0x1f0000) >> 5; +#else + /* big endian, lsb data */ + data = *s++; + *o++ = (data & 0xf800) | (data & 0x7e0) >> 3; + *o++ = + (data & 0x1f) << 11 | (data & 0xf8000000) >> 24; + *o++ = + ((data & 0x7e00000) >> 11) | (data & 0x1f0000) >> + 13; +#endif + } + /* check for last remaining pixel */ + if (width & 1) + { + register unsigned short data; +#ifdef LITTLE + data = *((short *) s); + data = ((data >> 8) & 0xff) | ((data & 0xff) << 8); +#else + data = *((short *) s); +#endif + ((char *) o)[0] = (data >> 8) & 0xf8; + ((char *) o)[1] = (data >> 3) & 0xfc; + ((char *) o)[2] = (data << 3) & 0xf8; + } + break; + } + } + srow += bpl; + orow += rowstride; + } + break; + } + /*#define HAIRY_32 this is slowest implementation */ +#define SIMPLE_32 /* this is fastest implementation */ + case 32: + { +#ifdef SIMPLE_32 + unsigned char *s; /* read 1 pixels at once */ +#else + unsigned long *s; /* read 1 pixels at once */ +#endif +#ifdef HAIRY_32 + register unsigned long data2; + unsigned short *o; +#else + unsigned char *o; +#endif + register unsigned long data; + unsigned char *srow = image->mem, *orow = pixels; + + printf ("32 bits/pixel\n"); + + for (yy = 0; yy < height; yy++) + { + s = srow; + o = orow; + + if (image->byte_order == GDK_LSB_FIRST) + { +#ifdef HAIRY_32 + for (xx = 0; xx < width; xx += 2) + { +#else + for (xx = 0; xx < width; xx++) + { +#endif + /* read/convert 2 pixels at a time */ + + /* little endian, lsb data */ +#ifdef SIMPLE_32 + *o++ = s[2]; + *o++ = s[1]; + *o++ = s[0]; + s += 4; +#else + +#ifdef LITTLE +#ifdef HAIRY_32 + data = *s++; + data2 = *s++; +#else + data = *s++; +#endif +#else + /* big endian, lsb data */ + /* swap endianness first */ + data = (unsigned long) ((unsigned char *) s)[3] << 24 + | (unsigned long) ((unsigned char *) s)[2] << 16 + | (unsigned long) ((unsigned char *) s)[1] << 8 + | (unsigned long) ((unsigned char *) s)[0]; + s++; +#endif +#ifdef HAIRY_32 + *o++ = (data & 0xff0000) >> 16 | (data & 0xff00); + *o++ = (data & 0xff) | (data2 & 0xff0000) >> 8; + *o++ = ((data2 & 0xff00) >> 8) | (data2 & 0xff) << 8; +#else + /* FIXME: endianness conversion can be done here .. doh! */ + *o++ = data & 0xff0000 >> 16; + *o++ = data & 0x00ff00 >> 8; + *o++ = data & 0x0000ff; +#endif + +#endif /* SIMPLE_32 */ + } + } + else + { + for (xx = 0; xx < width; xx++) + { + /* read/convert 2 pixels at a time */ +#ifdef LITTLE + /* little endian, msb data */ + /* swap endianness first */ +#if 1 /* which is faster?? */ + data = (unsigned long) ((unsigned char *) s)[0] << 24 + | (unsigned long) ((unsigned char *) s)[1] << 16 + | (unsigned long) ((unsigned char *) s)[2] << 8 + | (unsigned long) ((unsigned char *) s)[3]; + s++; +#else /* this is probably slower */ + data = *s++; + data = ((data >> 16) & 0xffff) | ((data & 0xffff) << 16); + data = + ((data & 0xff00ff00) >> 8) | ((data & 0xff00ff) << 8); +#endif +#else + /* big endian, lsb data */ + data = *s++; +#endif + /* FIXME: endianness conversion can be done here .. doh! */ + *o++ = data & 0xff0000 >> 16; + *o++ = data & 0x00ff00 >> 8; + *o++ = data & 0x0000ff; + } + } + srow += bpl; + orow += rowstride; + } + break; + } + default: + g_warning ("gdk_pixbuf_from_drawable: Unsupported image format\n"); + } + + gdk_image_destroy (image); + + art_pixbuf = + with_alpha ? art_pixbuf_new_rgba (buff, width, height, + rowstride) : art_pixbuf_new_rgb (buff, + width, + height, + rowstride); - fatness = with_alpha ? 4 : 3; - rowstride = width * fatness; - - buff = art_alloc (rowstride * height); - pixels = buff; - - switch (image->depth) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - for (yy = 0; yy < height; yy++) { - for (xx = 0; xx < width; xx++) { - pixel = gdk_image_get_pixel (image, xx, yy); - pixels[0] = colormap->colors[pixel].red; - pixels[1] = colormap->colors[pixel].green; - pixels[2] = colormap->colors[pixel].blue; - if (with_alpha) - pixels[3] = 0; - pixels += fatness; - - } - } - break; - - case 16: - case 15: - for (yy = 0; yy < height; yy++) { - for (xx = 0; xx < width; xx++) { - pixel = gdk_image_get_pixel (image, xx, yy); - r = (pixel >> 8) & 0xf8; - g = (pixel >> 3) & 0xfc; - b = (pixel << 3) & 0xf8; - pixels[0] = r; - pixels[1] = g; - pixels[2] = b; - if (with_alpha) - pixels[3] = 0; /* GdkImages don't have alpha =) */ - pixels += fatness; - } - } - break; - - case 24: - case 32: - for (yy = 0; yy < height; yy++) { - for (xx = 0; xx < width; xx++) { - pixel = gdk_image_get_pixel (image, xx, yy); - r = (pixel >> 16) & 0xff; - g = (pixel >> 8) & 0xff; - b = pixel & 0xff; - pixels[0] = r; - pixels[1] = g; - pixels[2] = b; - if (with_alpha) - pixels[3] = 0; /* GdkImages don't have alpha.. */ - pixels += fatness; - } - } - break; - - default: - g_error ("art_pixbuf_from_drawable_core (): Unknown depth."); - } - - art_pixbuf = with_alpha ? art_pixbuf_new_rgba (buff, width, height, rowstride) : - art_pixbuf_new_rgb (buff, width, height, rowstride); - - return gdk_pixbuf_new_from_art_pixbuf(art_pixbuf); + return gdk_pixbuf_new_from_art_pixbuf (art_pixbuf); } /* Public functions */ GdkPixbuf * -gdk_pixbuf_rgb_from_drawable (GdkWindow *window, gint x, gint y, gint width, gint height) +gdk_pixbuf_rgb_from_drawable (GdkWindow * window, gint x, gint y, gint width, + gint height) { - return gdk_pixbuf_from_drawable_core (window, x, y, width, height, 0); + return gdk_pixbuf_from_drawable_core (window, x, y, width, height, 0); } GdkPixbuf * -gdk_pixbuf_rgba_from_drawable (GdkWindow *window, gint x, gint y, gint width, gint height) +gdk_pixbuf_rgba_from_drawable (GdkWindow * window, gint x, gint y, gint width, + gint height) { - return gdk_pixbuf_from_drawable_core (window, x, y, width, height, 1); + return gdk_pixbuf_from_drawable_core (window, x, y, width, height, 1); } |