]> Pileus Git - ~andy/gtk/commitdiff
contrib subdir
authorHavoc Pennington <hp@redhat.com>
Mon, 9 Oct 2000 17:22:20 +0000 (17:22 +0000)
committerHavoc Pennington <hp@src.gnome.org>
Mon, 9 Oct 2000 17:22:20 +0000 (17:22 +0000)
2000-10-06  Havoc Pennington  <hp@redhat.com>

* Makefile.am (SRC_SUBDIRS): contrib subdir

* gdk/gdkpixbuf.h: Move GdkPixbufAlphaMode to gdk-pixbuf library,
so it can be used in Xlib version

* demos/testpixbuf.c (update_timeout): error checking from 1.0
tree

* gtk/gdk-pixbuf-loader.c (gdk_pixbuf_loader_get_pixbuf): Sync
change from 1.0 tree that returns first frame of animation
if the loaded file is an animation.

        * contrib: add new directory to hold stuff that comes with GTK+
but isn't really part of GTK+ (for now, gdk-pixbuf-xlib)

* configure.in: add contrib/*

2000-10-06  Havoc Pennington  <hp@redhat.com>

* gdk-pixbuf.h: add GdkPixbufAlphaMode

2000-10-06  Havoc Pennington  <hp@redhat.com>

        This entry is a summary of the merged-in changes from 1.0.
Relevant original ChangeLog entries are spliced in after
this entry; the files they refer to are from the 1.0
gdk-pixbuf sources.

* pixops/pixops.c (pixops_composite_nearest): sync a small fix
from 1.0

* io-xpm.c (xpm_seek_string): add fscanf error check from 1.0
Add progressive loader from 1.0

* io-tiff.c (gdk_pixbuf__tiff_image_begin_load): mem leak fixes
from 1.0 tree

* io-pnm.c: new version from 1.0 tree

* io-jpeg.c (gdk_pixbuf__jpeg_image_load): sync from 1.0, use
malloc not g_malloc

* io-gif.c (lzw_read_byte): sync from 1.0, change a g_error to
g_warning
(gif_get_next_step): return 0 here, sync from 1.0

* gdk-pixbuf-util.c: sync email address change for Cody
Russell

2000-09-11  Jeffrey Stedfast  <fejj@helixcode.com>

* gdk-pixbuf/io-pnm.c: Pretty much totally rewrote again because
last nights code was still "broken". Should now properly handle
all error conditions gracefully.

2000-09-10  Jeffrey Stedfast  <fejj@helixcode.com>

* gdk-pixbuf/io-pnm.c: Rewrote.

2000-09-09  Federico Mena Quintero  <federico@helixcode.com>

* gdk-pixbuf/pixops/pixops.c (pixops_composite_nearest): Compute
the correct dest offset.

2000-08-25  Federico Mena Quintero  <federico@helixcode.com>

* gdk-pixbuf/io-xpm.c: #include <unistd.h>

2000-08-05  Larry Ewing  <lewing@helixcode.com>

* gdk-pixbuf/io-tiff.c: stop leaking context->tempname.

* gdk-pixbuf/io-xpm.c: same as above.

2000-07-26  Michael Meeks  <michael@helixcode.com>

* gdk-pixbuf/io-jpeg.c (gdk_pixbuf__jpeg_image_load): make
g_malloc a malloc.

2000-07-21  Larry Ewing  <lewing@helixcode.com>

* gdk-pixbuf/io-xpm.c: add a fake progressive loader so that
xpm at least supports the progressive interface like the one in
io-tiff.c. This should be reimplemented as an actual progressive
loader.

2000-07-19  Jonathan Blandford  <jrb@redhat.com>

* demo/pixbuf-demo.c (update_timeout): changed scaling level to
make it look better.
* gdk-pixbuf/testpixbuf.c (update_timeout): Patch from michael
meeks to handle errors better.

52 files changed:
ChangeLog
ChangeLog.pre-2-0
ChangeLog.pre-2-10
ChangeLog.pre-2-2
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
Makefile.am
configure.in
contrib/gdk-pixbuf-xlib/ChangeLog [new file with mode: 0644]
contrib/gdk-pixbuf-xlib/gdk-pixbuf-xlib-2.0.pc.in [new file with mode: 0644]
contrib/gdk-pixbuf-xlib/gdk-pixbuf-xlib-drawable.c [new file with mode: 0644]
contrib/gdk-pixbuf-xlib/gdk-pixbuf-xlib-private.h [new file with mode: 0644]
contrib/gdk-pixbuf-xlib/gdk-pixbuf-xlib-render.c [new file with mode: 0644]
contrib/gdk-pixbuf-xlib/gdk-pixbuf-xlib.c [new file with mode: 0644]
contrib/gdk-pixbuf-xlib/gdk-pixbuf-xlib.h [new file with mode: 0644]
contrib/gdk-pixbuf-xlib/gdk-pixbuf-xlibrgb.c [new file with mode: 0644]
contrib/gdk-pixbuf-xlib/gdk-pixbuf-xlibrgb.h [new file with mode: 0644]
demos/testpixbuf.c
docs/reference/ChangeLog
docs/reference/gdk-pixbuf/Makefile.am
docs/reference/gdk-pixbuf/compiling.sgml
docs/reference/gdk-pixbuf/gdk-pixbuf-sections.txt
docs/reference/gdk-pixbuf/gdk-pixbuf.sgml
docs/reference/gdk-pixbuf/porting-from-imlib.sgml [new file with mode: 0644]
docs/reference/gdk-pixbuf/tmpl/animation.sgml
docs/reference/gdk-pixbuf/tmpl/file-loading.sgml
docs/reference/gdk-pixbuf/tmpl/gdk-pixbuf-unused.sgml
docs/reference/gdk-pixbuf/tmpl/gdk-pixbuf-xlib-from-drawables.sgml [new file with mode: 0644]
docs/reference/gdk-pixbuf/tmpl/gdk-pixbuf-xlib-init.sgml [new file with mode: 0644]
docs/reference/gdk-pixbuf/tmpl/gdk-pixbuf-xlib-rendering.sgml [new file with mode: 0644]
docs/reference/gdk-pixbuf/tmpl/gdk-pixbuf-xlib-rgb.sgml [new file with mode: 0644]
docs/reference/gdk-pixbuf/tmpl/gdk-pixbuf.sgml
docs/reference/gdk-pixbuf/tmpl/module_interface.sgml
docs/reference/gdk-pixbuf/tmpl/scaling.sgml
docs/reference/gdk/gdk-decl.txt
docs/reference/gdk/gdk-docs.sgml
docs/reference/gdk/tmpl/gdk-unused.sgml
docs/reference/gdk/tmpl/pixbufs.sgml
docs/reference/gdk/tmpl/windows.sgml
gdk-pixbuf/ChangeLog
gdk-pixbuf/gdk-pixbuf-loader.c
gdk-pixbuf/gdk-pixbuf-util.c
gdk-pixbuf/gdk-pixbuf.h
gdk-pixbuf/io-gif.c
gdk-pixbuf/io-jpeg.c
gdk-pixbuf/io-pnm.c
gdk-pixbuf/io-tiff.c
gdk-pixbuf/io-xpm.c
gdk-pixbuf/pixops/pixops.c
gdk/gdkpixbuf.h
gtk/gdk-pixbuf-loader.c

index e2562f508a51767482a0b97b2cbb68fdd807dbfe..6caace12040c5bdb6df5a2f5cc6d8f25e84f2b97 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2000-10-06  Havoc Pennington  <hp@redhat.com>
+
+       * Makefile.am (SRC_SUBDIRS): contrib subdir
+
+       * gdk/gdkpixbuf.h: Move GdkPixbufAlphaMode to gdk-pixbuf library,
+       so it can be used in Xlib version
+
+       * demos/testpixbuf.c (update_timeout): error checking from 1.0
+       tree
+
+       * gtk/gdk-pixbuf-loader.c (gdk_pixbuf_loader_get_pixbuf): Sync
+       change from 1.0 tree that returns first frame of animation
+       if the loaded file is an animation.
+
+        * contrib: add new directory to hold stuff that comes with GTK+
+       but isn't really part of GTK+ (for now, gdk-pixbuf-xlib)
+       
+       * configure.in: add contrib/*
+
 2000-10-05  Havoc Pennington  <hp@redhat.com>
 
         * demos/testpixbuf-save.c: add pixbuf save test
index e2562f508a51767482a0b97b2cbb68fdd807dbfe..6caace12040c5bdb6df5a2f5cc6d8f25e84f2b97 100644 (file)
@@ -1,3 +1,22 @@
+2000-10-06  Havoc Pennington  <hp@redhat.com>
+
+       * Makefile.am (SRC_SUBDIRS): contrib subdir
+
+       * gdk/gdkpixbuf.h: Move GdkPixbufAlphaMode to gdk-pixbuf library,
+       so it can be used in Xlib version
+
+       * demos/testpixbuf.c (update_timeout): error checking from 1.0
+       tree
+
+       * gtk/gdk-pixbuf-loader.c (gdk_pixbuf_loader_get_pixbuf): Sync
+       change from 1.0 tree that returns first frame of animation
+       if the loaded file is an animation.
+
+        * contrib: add new directory to hold stuff that comes with GTK+
+       but isn't really part of GTK+ (for now, gdk-pixbuf-xlib)
+       
+       * configure.in: add contrib/*
+
 2000-10-05  Havoc Pennington  <hp@redhat.com>
 
         * demos/testpixbuf-save.c: add pixbuf save test
index e2562f508a51767482a0b97b2cbb68fdd807dbfe..6caace12040c5bdb6df5a2f5cc6d8f25e84f2b97 100644 (file)
@@ -1,3 +1,22 @@
+2000-10-06  Havoc Pennington  <hp@redhat.com>
+
+       * Makefile.am (SRC_SUBDIRS): contrib subdir
+
+       * gdk/gdkpixbuf.h: Move GdkPixbufAlphaMode to gdk-pixbuf library,
+       so it can be used in Xlib version
+
+       * demos/testpixbuf.c (update_timeout): error checking from 1.0
+       tree
+
+       * gtk/gdk-pixbuf-loader.c (gdk_pixbuf_loader_get_pixbuf): Sync
+       change from 1.0 tree that returns first frame of animation
+       if the loaded file is an animation.
+
+        * contrib: add new directory to hold stuff that comes with GTK+
+       but isn't really part of GTK+ (for now, gdk-pixbuf-xlib)
+       
+       * configure.in: add contrib/*
+
 2000-10-05  Havoc Pennington  <hp@redhat.com>
 
         * demos/testpixbuf-save.c: add pixbuf save test
index e2562f508a51767482a0b97b2cbb68fdd807dbfe..6caace12040c5bdb6df5a2f5cc6d8f25e84f2b97 100644 (file)
@@ -1,3 +1,22 @@
+2000-10-06  Havoc Pennington  <hp@redhat.com>
+
+       * Makefile.am (SRC_SUBDIRS): contrib subdir
+
+       * gdk/gdkpixbuf.h: Move GdkPixbufAlphaMode to gdk-pixbuf library,
+       so it can be used in Xlib version
+
+       * demos/testpixbuf.c (update_timeout): error checking from 1.0
+       tree
+
+       * gtk/gdk-pixbuf-loader.c (gdk_pixbuf_loader_get_pixbuf): Sync
+       change from 1.0 tree that returns first frame of animation
+       if the loaded file is an animation.
+
+        * contrib: add new directory to hold stuff that comes with GTK+
+       but isn't really part of GTK+ (for now, gdk-pixbuf-xlib)
+       
+       * configure.in: add contrib/*
+
 2000-10-05  Havoc Pennington  <hp@redhat.com>
 
         * demos/testpixbuf-save.c: add pixbuf save test
index e2562f508a51767482a0b97b2cbb68fdd807dbfe..6caace12040c5bdb6df5a2f5cc6d8f25e84f2b97 100644 (file)
@@ -1,3 +1,22 @@
+2000-10-06  Havoc Pennington  <hp@redhat.com>
+
+       * Makefile.am (SRC_SUBDIRS): contrib subdir
+
+       * gdk/gdkpixbuf.h: Move GdkPixbufAlphaMode to gdk-pixbuf library,
+       so it can be used in Xlib version
+
+       * demos/testpixbuf.c (update_timeout): error checking from 1.0
+       tree
+
+       * gtk/gdk-pixbuf-loader.c (gdk_pixbuf_loader_get_pixbuf): Sync
+       change from 1.0 tree that returns first frame of animation
+       if the loaded file is an animation.
+
+        * contrib: add new directory to hold stuff that comes with GTK+
+       but isn't really part of GTK+ (for now, gdk-pixbuf-xlib)
+       
+       * configure.in: add contrib/*
+
 2000-10-05  Havoc Pennington  <hp@redhat.com>
 
         * demos/testpixbuf-save.c: add pixbuf save test
index e2562f508a51767482a0b97b2cbb68fdd807dbfe..6caace12040c5bdb6df5a2f5cc6d8f25e84f2b97 100644 (file)
@@ -1,3 +1,22 @@
+2000-10-06  Havoc Pennington  <hp@redhat.com>
+
+       * Makefile.am (SRC_SUBDIRS): contrib subdir
+
+       * gdk/gdkpixbuf.h: Move GdkPixbufAlphaMode to gdk-pixbuf library,
+       so it can be used in Xlib version
+
+       * demos/testpixbuf.c (update_timeout): error checking from 1.0
+       tree
+
+       * gtk/gdk-pixbuf-loader.c (gdk_pixbuf_loader_get_pixbuf): Sync
+       change from 1.0 tree that returns first frame of animation
+       if the loaded file is an animation.
+
+        * contrib: add new directory to hold stuff that comes with GTK+
+       but isn't really part of GTK+ (for now, gdk-pixbuf-xlib)
+       
+       * configure.in: add contrib/*
+
 2000-10-05  Havoc Pennington  <hp@redhat.com>
 
         * demos/testpixbuf-save.c: add pixbuf save test
index e2562f508a51767482a0b97b2cbb68fdd807dbfe..6caace12040c5bdb6df5a2f5cc6d8f25e84f2b97 100644 (file)
@@ -1,3 +1,22 @@
+2000-10-06  Havoc Pennington  <hp@redhat.com>
+
+       * Makefile.am (SRC_SUBDIRS): contrib subdir
+
+       * gdk/gdkpixbuf.h: Move GdkPixbufAlphaMode to gdk-pixbuf library,
+       so it can be used in Xlib version
+
+       * demos/testpixbuf.c (update_timeout): error checking from 1.0
+       tree
+
+       * gtk/gdk-pixbuf-loader.c (gdk_pixbuf_loader_get_pixbuf): Sync
+       change from 1.0 tree that returns first frame of animation
+       if the loaded file is an animation.
+
+        * contrib: add new directory to hold stuff that comes with GTK+
+       but isn't really part of GTK+ (for now, gdk-pixbuf-xlib)
+       
+       * configure.in: add contrib/*
+
 2000-10-05  Havoc Pennington  <hp@redhat.com>
 
         * demos/testpixbuf-save.c: add pixbuf save test
index eb9a24f29757815dc0edcfd9b84b24123261a025..42577a920564b249cd7e77b9d28d5423d98fdb56 100644 (file)
@@ -1,6 +1,6 @@
 ## Makefile.am for GTK+
 
-SRC_SUBDIRS = gdk-pixbuf gdk modules gtk demos
+SRC_SUBDIRS = gdk-pixbuf gdk modules gtk demos contrib
 SUBDIRS = po $(SRC_SUBDIRS) docs build
 
 bin_SCRIPTS = gtk-config-2.0
index 7a30ef012000872b5a4a0e40f693f8d44cce98cf..c5f81d32b27cd6fe80f33ff1c2c241422e98f1df 100644 (file)
@@ -825,6 +825,14 @@ AC_SUBST(GDK_PIXBUF_LIBDIR)
 AC_SUBST(GDK_PIXBUF_INCLUDEDIR)
 AC_SUBST(GDK_PIXBUF_LIBS)
 
+GDK_PIXBUF_XLIB_LIBDIR=$GDK_PIXBUF_LIBDIR
+GDK_PIXBUF_XLIB_INCLUDEDIR=$GDK_PIXBUF_INCLUDEDIR
+GDK_PIXBUF_XLIB_LIBS="$GLIB_LIBS -lgdk_pixbuf_xlib $deps $X11_LIBS"
+
+AC_SUBST(GDK_PIXBUF_XLIB_LIBDIR)
+AC_SUBST(GDK_PIXBUF_XLIB_INCLUDEDIR)
+AC_SUBST(GDK_PIXBUF_XLIB_LIBS)
+
 # Checks to see if we should compile in MMX support (there will be
 # a runtime test when the code is actually run to see if it should
 # be used - this just checks if we can compile it.)
@@ -1037,4 +1045,7 @@ gtk/gtkcompat.h
 gtk/stock-icons/Makefile
 modules/Makefile
 modules/linux-fb/Makefile
+contrib/Makefile
+contrib/gdk-pixbuf-xlib/Makefile
+contrib/gdk-pixbuf-xlib/gdk-pixbuf-xlib-2.0.pc
 ], [chmod +x gtk-config-2.0])
diff --git a/contrib/gdk-pixbuf-xlib/ChangeLog b/contrib/gdk-pixbuf-xlib/ChangeLog
new file mode 100644 (file)
index 0000000..14bec62
--- /dev/null
@@ -0,0 +1,53 @@
+2000-10-06  Havoc Pennington  <hp@redhat.com>
+
+       * gdk-pixbuf-xlib.c: Put display/screen here, instead of in 
+       the main gdk-pixbuf library as it was in 1.0; since the io-xpm 
+       loader doesn't use these variables anymore it should be OK
+
+2000-09-26  Federico Mena Quintero  <federico@helixcode.com>
+
+       * gdk-pixbuf/gdk-pixbuf-xlib-drawable.c
+       (gdk_pixbuf_xlib_get_from_drawable): Do not use
+       gdk_screen_{width,height}().  Thanks to John Harper for pointing
+       this out.
+
+2000-08-26  Federico Mena Quintero  <federico@helixcode.com>
+
+       * gdk-pixbuf/gdk-pixbuf-xlibrgb.c: Added API reference docs.
+
+2000-08-25  Federico Mena Quintero  <federico@helixcode.com>
+
+       * gdk-pixbuf/gdk-pixbuf-xlib-drawable.c (handle_x_error): Return
+       0.
+       (xlib_window_is_viewable): Return FALSE in the last case.
+
+       * gdk-pixbuf/gdk-pixbuf-xlib-render.c: Updated the inline docs.
+
+       * gdk-pixbuf/gdk-pixbuf-xlib.c: Added API docs.
+
+2000-08-25  John Harper  <john@dcs.warwick.ac.uk>
+
+       Work to create an Xlib version of gdk-pixbuf (with the Xlib
+       port of GdkRGB for rendering):
+
+       * configure.in: check for X libraries, set and substitute
+       GDK_PIXBUF_XLIB_{LIBDIR,INCLUDEDIR,LIBS} variables
+
+       * gdk_pixbuf_xlibConf.sh.in: new file -- gnome-config details
+       for the gdk-pixbuf-xlib library
+       * Makefile.am: build and install gdk_pixbuf_xlibConf.sh
+
+       * gdk-pixbuf/gdk-pixbuf-xlib-render.c,
+       gdk-pixbuf/gdk-pixbuf-xlib.c, gdk-pixbuf/gdk-pixbuf-xlib.h,
+       gdk-pixbuf/gdk-pixbuf-xlib-private.h,
+       gdk-pixbuf/gdk-pixbuf-xlib-drawable.c: new files, ported the
+       GDK dependent parts of gdk-pixbuf to use Xlib. Functions that
+       were called gdk_pixbuf_FOO are now gdk_pixbuf_xlib_FOO
+
+       * gdk-pixbuf/gdk-pixbuf-xlibrgb.c,
+       gdk-pixbuf/gdk-pixbuf-xlibrgb.h: added Chris Blizzard's Xlib
+       port of GdkRGB (from Mozilla CVS)
+
+       * gdk-pixbuf/Makefile.am: build a library libgdk_pixbuf_xlib.la
+       including the non-GDK dependent objects from libgdk_pixbuf.la
+       plus the Xlib ports and xlibrgb
diff --git a/contrib/gdk-pixbuf-xlib/gdk-pixbuf-xlib-2.0.pc.in b/contrib/gdk-pixbuf-xlib/gdk-pixbuf-xlib-2.0.pc.in
new file mode 100644 (file)
index 0000000..197c03c
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: GdkPixbufXlib
+Description: Image loading and scaling for Xlib
+Version: @VERSION@
+Requires: gobject-2.0,gmodule-2.0,gdk-pixbuf-2.0
+Libs: -L${libdir} -lgdk_pixbuf_xlib-1.3
+Cflags: -I${includedir}
diff --git a/contrib/gdk-pixbuf-xlib/gdk-pixbuf-xlib-drawable.c b/contrib/gdk-pixbuf-xlib/gdk-pixbuf-xlib-drawable.c
new file mode 100644 (file)
index 0000000..9e007bd
--- /dev/null
@@ -0,0 +1,1335 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* GdkPixbuf library - convert X drawable information to RGB
+ *
+ * Copyright (C) 1999 Michael Zucchi
+ *
+ * Authors: Michael Zucchi <zucchi@zedzone.mmc.com.au>
+ *          Cody Russell <bratsche@dfw.net>
+ *         Federico Mena-Quintero <federico@gimp.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Ported to Xlib by John Harper <john@dcs.warwick.ac.uk> */
+
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <gdk-pixbuf/gdk-pixbuf-private.h>
+#include "gdk-pixbuf-xlib-private.h"
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
+#define LITTLE
+#endif
+#define d(x)
+
+\f
+
+static guint32 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
+};
+
+\f
+/* color handling */
+
+typedef struct xlib_colormap_struct xlib_colormap;
+struct xlib_colormap_struct {
+       int size;
+       XColor *colors;
+       Visual *visual;
+       Colormap colormap;
+};
+
+static xlib_colormap *
+xlib_get_colormap (Colormap id, Visual *visual)
+{
+       int i;
+       xlib_colormap *xc = g_new (xlib_colormap, 1);
+
+       xc->size = visual->map_entries;
+       xc->colors = g_new (XColor, xc->size);
+       xc->visual = visual;
+       xc->colormap = id;
+
+       for (i = 0; i < xc->size; i++) {
+               xc->colors[i].pixel = i;
+               xc->colors[i].flags = DoRed | DoGreen | DoBlue;
+       }
+
+       XQueryColors (gdk_pixbuf_dpy, xc->colormap, xc->colors, xc->size);
+
+       return xc;
+}
+
+static void
+xlib_colormap_free (xlib_colormap *xc)
+{
+       g_free (xc->colors);
+       g_free (xc);
+}
+
+/* from gdkvisual.c */
+static void
+visual_decompose_mask (gulong  mask,
+                      gint   *shift,
+                      gint   *prec)
+{
+       *shift = 0;
+       *prec = 0;
+
+       while (!(mask & 0x1)) {
+               (*shift)++;
+               mask >>= 1;
+       }
+
+       while (mask & 0x1) {
+               (*prec)++;
+               mask >>= 1;
+       }
+}
+
+static gboolean x_error;
+
+static int
+handle_x_error (Display *dpy, XErrorEvent *ev)
+{
+       x_error = TRUE;
+       return 0;
+}
+
+static gboolean
+drawable_is_pixmap (Drawable d)
+{
+       /* copied from Imlib */
+
+       XErrorHandler errh;
+       XWindowAttributes wa;
+       gboolean is_pixmap;
+
+       errh = XSetErrorHandler (handle_x_error);
+       x_error = FALSE;
+       XGetWindowAttributes (gdk_pixbuf_dpy, d, &wa);
+       XSync (gdk_pixbuf_dpy, False);
+       is_pixmap = x_error;
+       XSetErrorHandler (errh);
+
+       return is_pixmap;
+}
+
+\f
+
+/*
+  convert 1 bits-pixel data
+  no alpha
+*/
+static void
+rgb1 (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
+{
+       int xx, yy;
+       int width, height;
+       int bpl;
+       guint8 *s;
+       register guint8 data;
+       guint8 *o;
+       guint8 *srow = image->data, *orow = pixels;
+
+       d (printf ("1 bits/pixel\n"));
+
+       /* convert upto 8 pixels/time */
+       /* its probably not worth trying to make this run very fast, who uses
+          1 bit displays anymore? */
+       width = image->width;
+       height = image->height;
+       bpl = image->bytes_per_line;
+
+       for (yy = 0; yy < height; yy++) {
+               s = srow;
+               o = orow;
+
+               for (xx = 0; xx < width; xx ++) {
+                       data = srow[xx >> 3] >> (7 - (xx & 7)) & 1;
+                       *o++ = colormap->colors[data].red;
+                       *o++ = colormap->colors[data].green;
+                       *o++ = colormap->colors[data].blue;
+               }
+               srow += bpl;
+               orow += rowstride;
+       }
+}
+
+/*
+  convert 1 bits/pixel data
+  with alpha
+*/
+static void
+rgb1a (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
+{
+       int xx, yy;
+       int width, height;
+       int bpl;
+       guint8 *s;
+       register guint8 data;
+       guint8 *o;
+       guint8 *srow = image->data, *orow = pixels;
+       guint32 remap[2];
+
+       d (printf ("1 bits/pixel\n"));
+
+       /* convert upto 8 pixels/time */
+       /* its probably not worth trying to make this run very fast, who uses
+          1 bit displays anymore? */
+       width = image->width;
+       height = image->height;
+       bpl = image->bytes_per_line;
+
+       for (xx = 0; xx < 2; xx++) {
+#ifdef LITTLE
+               remap[xx] = 0xff000000
+                       | colormap->colors[xx].blue << 16
+                       | colormap->colors[xx].green << 8
+                       | colormap->colors[xx].red;
+#else
+               remap[xx] = 0xff
+                       | colormap->colors[xx].red << 24
+                       | colormap->colors[xx].green << 16
+                       | colormap->colors[xx].blue << 8;
+#endif
+       }
+
+       for (yy = 0; yy < height; yy++) {
+               s = srow;
+               o = orow;
+
+               for (xx = 0; xx < width; xx ++) {
+                       data = srow[xx >> 3] >> (7 - (xx & 7)) & 1;
+                       *o++ = remap[data];
+               }
+               srow += bpl;
+               orow += rowstride;
+       }
+}
+
+/*
+  convert 8 bits/pixel data
+  no alpha
+*/
+static void
+rgb8 (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
+{
+       int xx, yy;
+       int width, height;
+       int bpl;
+       guint32 mask;
+       register guint32 data;
+       guint8 *srow = image->data, *orow = pixels;
+       register guint8 *s;
+       register guint8 *o;
+
+       width = image->width;
+       height = image->height;
+       bpl = image->bytes_per_line;
+
+       d (printf ("8 bit, no alpha output\n"));
+
+       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;
+       }
+}
+
+/*
+  convert 8 bits/pixel data
+  with alpha
+*/
+static void
+rgb8a (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
+{
+       int xx, yy;
+       int width, height;
+       int bpl;
+       guint32 mask;
+       register guint32 data;
+       guint32 remap[256];
+       register guint8 *s;     /* read 2 pixels at once */
+       register guint32 *o;
+       guint8 *srow = image->data, *orow = pixels;
+
+       width = image->width;
+       height = image->height;
+       bpl = image->bytes_per_line;
+
+       d (printf ("8 bit, with alpha output\n"));
+
+       mask = mask_table[image->depth];
+
+       for (xx = 0; xx < colormap->size; xx++) {
+#ifdef LITTLE
+               remap[xx] = 0xff000000
+                       | colormap->colors[xx].blue << 16
+                       | colormap->colors[xx].green << 8
+                       | colormap->colors[xx].red;
+#else
+               remap[xx] = 0xff
+                       | colormap->colors[xx].red << 24
+                       | colormap->colors[xx].green << 16
+                       | colormap->colors[xx].blue << 8;
+#endif
+       }
+
+       for (yy = 0; yy < height; yy++) {
+               s = srow;
+               o = (guint32 *) orow;
+               for (xx = 0; xx < width; xx ++) {
+                       data = *s++ & mask;
+                       *o++ = remap[data];
+               }
+               srow += bpl;
+               orow += rowstride;
+       }
+}
+
+/*
+  convert 16 bits/pixel data
+  no alpha
+  data in lsb format
+*/
+static void
+rgb565lsb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
+{
+       int xx, yy;
+       int width, height;
+       int bpl;
+
+#ifdef LITTLE
+       register guint32 *s;    /* read 2 pixels at once */
+#else
+       register guint8 *s;     /* read 2 pixels at once */
+#endif
+       register guint16 *o;
+       guint8 *srow = image->data, *orow = pixels;
+
+       width = image->width;
+       height = image->height;
+       bpl = image->bytes_per_line;
+
+       for (yy = 0; yy < height; yy++) {
+#ifdef LITTLE
+               s = (guint32 *) srow;
+#else
+               s = srow;
+#endif
+               o = (guint16 *) orow;
+               for (xx = 1; xx < width; xx += 2) {
+                       register guint32 data;
+#ifdef LITTLE
+                       data = *s++;
+                       *o++ = (data & 0xf800) >> 8 | (data & 0xe000) >> 13
+                               | (data & 0x7e0) << 5 | (data & 0x600) >> 1;
+                       *o++ = (data & 0x1f) << 3 | (data & 0x1c) >> 2
+                               | (data & 0xf8000000) >> 16 | (data & 0xe0000000) >> 21;
+                       *o++ = (data & 0x7e00000) >> 19 | (data & 0x6000000) >> 25
+                               | (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10;
+#else
+                       /* swap endianness first */
+                       data = s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24;
+                       s += 4;
+                       *o++ = (data & 0xf800) | (data & 0xe000) >> 5
+                               | (data & 0x7e0) >> 3 | (data & 0x600) >> 9;
+                       *o++ = (data & 0x1f) << 11 | (data & 0x1c) << 6
+                               | (data & 0xf8000000) >> 24 | (data & 0xe0000000) >> 29;
+                       *o++ = (data & 0x7e00000) >> 11 | (data & 0x6000000) >> 17
+                               | (data & 0x1f0000) >> 13 | (data & 0x1c0000) >> 18;
+#endif
+               }
+               /* check for last remaining pixel */
+               if (width & 1) {
+                       register guint16 data;
+#ifdef LITTLE
+                       data = *((short *) s);
+#else
+                       data = *((short *) s);
+                       data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
+#endif
+                       ((char *) o)[0] = ((data >> 8) & 0xf8) | ((data >> 13) & 0x7);
+                       ((char *) o)[1] = ((data >> 3) & 0xfc) | ((data >> 9) & 0x3);
+                       ((char *) o)[2] = ((data << 3) & 0xf8) | ((data >> 2) & 0x7);
+               }
+               srow += bpl;
+               orow += rowstride;
+       }
+}
+
+/*
+  convert 16 bits/pixel data
+  no alpha
+  data in msb format
+*/
+static void
+rgb565msb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
+{
+       int xx, yy;
+       int width, height;
+       int bpl;
+
+#ifdef LITTLE
+       register guint8 *s;     /* need to swap data order */
+#else
+       register guint32 *s;    /* read 2 pixels at once */
+#endif
+       register guint16 *o;
+       guint8 *srow = image->data, *orow = pixels;
+
+       width = image->width;
+       height = image->height;
+       bpl = image->bytes_per_line;
+
+       for (yy = 0; yy < height; yy++) {
+#ifdef LITTLE
+               s = srow;
+#else
+               s = (guint32 *) srow;
+#endif
+               o = (guint16 *) orow;
+               for (xx = 1; xx < width; xx += 2) {
+                       register guint32 data;
+#ifdef LITTLE
+                       /* swap endianness first */
+                       data = s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24;
+                       s += 4;
+                       *o++ = (data & 0xf800) >> 8 | (data & 0xe000) >> 13
+                               | (data & 0x7e0) << 5 | (data & 0x600) >> 1;
+                       *o++ = (data & 0x1f) << 3 | (data & 0x1c) >> 2
+                               | (data & 0xf8000000) >> 16 | (data & 0xe0000000) >> 21;
+                       *o++ = (data & 0x7e00000) >> 19 | (data & 0x6000000) >> 25
+                               | (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10;
+#else
+                       data = *s++;
+                       *o++ = (data & 0xf800) | (data & 0xe000) >> 5
+                               | (data & 0x7e0) >> 3 | (data & 0x600) >> 9;
+                       *o++ = (data & 0x1f) << 11 | (data & 0x1c) << 6
+                               | (data & 0xf8000000) >> 24 | (data & 0xe0000000) >> 29;
+                       *o++ = (data & 0x7e00000) >> 11 | (data & 0x6000000) >> 17
+                               | (data & 0x1f0000) >> 13 | (data & 0x1c0000) >> 18;
+#endif
+               }
+               /* check for last remaining pixel */
+               if (width & 1) {
+                       register guint16 data;
+#ifdef LITTLE
+                       data = *((short *) s);
+                       data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
+#else
+                       data = *((short *) s);
+#endif
+                       ((char *) o)[0] = ((data >> 8) & 0xf8) | ((data >> 13) & 0x7);
+                       ((char *) o)[1] = ((data >> 3) & 0xfc) | ((data >> 9) & 0x3);
+                       ((char *) o)[2] = ((data << 3) & 0xf8) | ((data >> 2) & 0x7);
+               }
+               srow += bpl;
+               orow += rowstride;
+       }
+}
+
+/*
+  convert 16 bits/pixel data
+  with alpha
+  data in lsb format
+*/
+static void
+rgb565alsb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
+{
+       int xx, yy;
+       int width, height;
+       int bpl;
+
+#ifdef LITTLE
+       register guint16 *s;    /* read 1 pixels at once */
+#else
+       register guint8 *s;
+#endif
+       register guint32 *o;
+
+       guint8 *srow = image->data, *orow = pixels;
+
+       width = image->width;
+       height = image->height;
+       bpl = image->bytes_per_line;
+
+       for (yy = 0; yy < height; yy++) {
+#ifdef LITTLE
+               s = (guint16 *) srow;
+#else
+               s = (guint8 *) srow;
+#endif
+               o = (guint32 *) orow;
+               for (xx = 0; xx < width; xx ++) {
+                       register guint32 data;
+                       /*  rrrrrggg gggbbbbb -> rrrrrRRR ggggggGG bbbbbBBB aaaaaaaa */
+                       /*  little endian: aaaaaaaa bbbbbBBB ggggggGG rrrrrRRR */
+#ifdef LITTLE
+                       data = *s++;
+                       *o++ = (data & 0xf800) >> 8 | (data & 0xe000) >> 13
+                               | (data & 0x7e0) << 5 | (data & 0x600) >> 1
+                               | (data & 0x1f) << 19 | (data & 0x1c) << 14
+                               | 0xff000000;
+#else
+                       /* swap endianness first */
+                       data = s[0] | s[1] << 8;
+                       s += 2;
+                       *o++ = (data & 0xf800) << 16 | (data & 0xe000) << 11
+                               | (data & 0x7e0) << 13 | (data & 0x600) << 7
+                               | (data & 0x1f) << 11 | (data & 0x1c) << 6
+                               | 0xff;
+#endif
+               }
+               srow += bpl;
+               orow += rowstride;
+       }
+}
+
+/*
+  convert 16 bits/pixel data
+  with alpha
+  data in msb format
+*/
+static void
+rgb565amsb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
+{
+       int xx, yy;
+       int width, height;
+       int bpl;
+
+#ifdef LITTLE
+       register guint8 *s;
+#else
+       register guint16 *s;    /* read 1 pixels at once */
+#endif
+       register guint32 *o;
+
+       guint8 *srow = image->data, *orow = pixels;
+
+       width = image->width;
+       height = image->height;
+       bpl = image->bytes_per_line;
+
+       for (yy = 0; yy < height; yy++) {
+               s = srow;
+               o = (guint32 *) orow;
+               for (xx = 0; xx < width; xx ++) {
+                       register guint32 data;
+                       /*  rrrrrggg gggbbbbb -> rrrrrRRR gggggg00 bbbbbBBB aaaaaaaa */
+                       /*  little endian: aaaaaaaa bbbbbBBB gggggg00 rrrrrRRR */
+#ifdef LITTLE
+                       /* swap endianness first */
+                       data = s[0] | s[1] << 8;
+                       s += 2;
+                       *o++ = (data & 0xf800) >> 8 | (data & 0xe000) >> 13
+                               | (data & 0x7e0) << 5 | (data & 0x600) >> 1
+                               | (data & 0x1f) << 19 | (data & 0x1c) << 14
+                               | 0xff000000;
+#else
+                       data = *s++;
+                       *o++ = (data & 0xf800) << 16 | (data & 0xe000) << 11
+                               | (data & 0x7e0) << 13 | (data & 0x600) << 7
+                               | (data & 0x1f) << 11 | (data & 0x1c) << 6
+                               | 0xff;
+#endif
+               }
+               srow += bpl;
+               orow += rowstride;
+       }
+}
+
+/*
+  convert 15 bits/pixel data
+  no alpha
+  data in lsb format
+*/
+static void
+rgb555lsb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
+{
+       int xx, yy;
+       int width, height;
+       int bpl;
+
+#ifdef LITTLE
+       register guint32 *s;    /* read 2 pixels at once */
+#else
+       register guint8 *s;     /* read 2 pixels at once */
+#endif
+       register guint16 *o;
+       guint8 *srow = image->data, *orow = pixels;
+
+       width = image->width;
+       height = image->height;
+       bpl = image->bytes_per_line;
+
+       for (yy = 0; yy < height; yy++) {
+#ifdef LITTLE
+               s = (guint32 *) srow;
+#else
+               s = srow;
+#endif
+               o = (guint16 *) orow;
+               for (xx = 1; xx < width; xx += 2) {
+                       register guint32 data;
+#ifdef LITTLE
+                       data = *s++;
+                       *o++ = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12
+                               | (data & 0x3e0) << 6 | (data & 0x380) << 1;
+                       *o++ = (data & 0x1f) << 3 | (data & 0x1c) >> 2
+                               | (data & 0x7c000000) >> 15 | (data & 0x70000000) >> 20;
+                       *o++ = (data & 0x3e00000) >> 18 | (data & 0x3800000) >> 23
+                               | (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10;
+#else
+                       /* swap endianness first */
+                       data = s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24;
+                       s += 4;
+                       *o++ = (data & 0x7c00) << 1 | (data & 0x7000) >> 4
+                               | (data & 0x3e0) >> 2 | (data & 0x380) >> 7;
+                       *o++ = (data & 0x1f) << 11 | (data & 0x1c) << 6
+                               | (data & 0x7c000000) >> 23 | (data & 0x70000000) >> 28;
+                       *o++ = (data & 0x3e00000) >> 10 | (data & 0x3800000) >> 15
+                               | (data & 0x1f0000) >> 13 | (data & 0x1c0000) >> 18;
+#endif
+               }
+               /* check for last remaining pixel */
+               if (width & 1) {
+                       register guint16 data;
+#ifdef LITTLE
+                       data = *((short *) s);
+#else
+                       data = *((short *) s);
+                       data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
+#endif
+                       ((char *) o)[0] = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12;
+                       ((char *) o)[1] = (data & 0x3e0) >> 2 | (data & 0x380) >> 7;
+                       ((char *) o)[2] = (data & 0x1f) << 3 | (data & 0x1c) >> 2;
+               }
+               srow += bpl;
+               orow += rowstride;
+       }
+}
+
+/*
+  convert 15 bits/pixel data
+  no alpha
+  data in msb format
+*/
+static void
+rgb555msb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
+{
+       int xx, yy;
+       int width, height;
+       int bpl;
+
+#ifdef LITTLE
+       register guint8 *s;     /* read 2 pixels at once */
+#else
+       register guint32 *s;    /* read 2 pixels at once */
+#endif
+       register guint16 *o;
+       guint8 *srow = image->data, *orow = pixels;
+
+       width = image->width;
+       height = image->height;
+       bpl = image->bytes_per_line;
+
+       for (yy = 0; yy < height; yy++) {
+               s = srow;
+               o = (guint16 *) orow;
+               for (xx = 1; xx < width; xx += 2) {
+                       register guint32 data;
+#ifdef LITTLE
+                       /* swap endianness first */
+                       data = s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24;
+                       s += 4;
+                       *o++ = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12
+                               | (data & 0x3e0) << 6 | (data & 0x380) << 1;
+                       *o++ = (data & 0x1f) << 3 | (data & 0x1c) >> 2
+                               | (data & 0x7c000000) >> 15 | (data & 0x70000000) >> 20;
+                       *o++ = (data & 0x3e00000) >> 18 | (data & 0x3800000) >> 23
+                               | (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10;
+#else
+                       data = *s++;
+                       *o++ = (data & 0x7c00) << 1 | (data & 0x7000) >> 4
+                               | (data & 0x3e0) >> 2 | (data & 0x380) >> 7;
+                       *o++ = (data & 0x1f) << 11 | (data & 0x1c) << 6
+                               | (data & 0x7c000000) >> 23 | (data & 0x70000000) >> 28;
+                       *o++ = (data & 0x3e00000) >> 10 | (data & 0x3800000) >> 15
+                               | (data & 0x1f0000) >> 13 | (data & 0x1c0000) >> 18;
+#endif
+               }
+               /* check for last remaining pixel */
+               if (width & 1) {
+                       register guint16 data;
+#ifdef LITTLE
+                       data = *((short *) s);
+                       data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
+#else
+                       data = *((short *) s);
+#endif
+                       ((char *) o)[0] = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12;
+                       ((char *) o)[1] = (data & 0x3e0) >> 2 | (data & 0x380) >> 7;
+                       ((char *) o)[2] = (data & 0x1f) << 3 | (data & 0x1c) >> 2;
+               }
+               srow += bpl;
+               orow += rowstride;
+       }
+}
+
+/*
+  convert 15 bits/pixel data
+  with alpha
+  data in lsb format
+*/
+static void
+rgb555alsb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
+{
+       int xx, yy;
+       int width, height;
+       int bpl;
+
+#ifdef LITTLE
+       register guint16 *s;    /* read 1 pixels at once */
+#else
+       register guint8 *s;
+#endif
+       register guint32 *o;
+
+       guint8 *srow = image->data, *orow = pixels;
+
+       width = image->width;
+       height = image->height;
+       bpl = image->bytes_per_line;
+
+       for (yy = 0; yy < height; yy++) {
+#ifdef LITTLE
+               s = (guint16 *) srow;
+#else
+               s = srow;
+#endif
+               o = (guint32 *) orow;
+               for (xx = 0; xx < width; xx++) {
+                       register guint32 data;
+                       /*  rrrrrggg gggbbbbb -> rrrrrRRR gggggGGG bbbbbBBB aaaaaaaa */
+                       /*  little endian: aaaaaaaa bbbbbBBB gggggGGG rrrrrRRR */
+#ifdef LITTLE
+                       data = *s++;
+                       *o++ = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12
+                               | (data & 0x3e0) << 6 | (data & 0x380) << 1
+                               | (data & 0x1f) << 19 | (data & 0x1c) << 14
+                               | 0xff000000;
+#else
+                       /* swap endianness first */
+                       data = s[0] | s[1] << 8;
+                       s += 2;
+                       *o++ = (data & 0x7c00) << 17 | (data & 0x7000) << 12
+                               | (data & 0x3e0) << 14 | (data & 0x380) << 9
+                               | (data & 0x1f) << 11 | (data & 0x1c) << 6
+                               | 0xff;
+#endif
+               }
+               srow += bpl;
+               orow += rowstride;
+       }
+}
+
+/*
+  convert 15 bits/pixel data
+  with alpha
+  data in msb format
+*/
+static void
+rgb555amsb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
+{
+       int xx, yy;
+       int width, height;
+       int bpl;
+
+#ifdef LITTLE
+       register guint16 *s;    /* read 1 pixels at once */
+#else
+       register guint8 *s;
+#endif
+       register guint32 *o;
+
+       guint8 *srow = image->data, *orow = pixels;
+
+       width = image->width;
+       height = image->height;
+       bpl = image->bytes_per_line;
+
+       for (yy = 0; yy < height; yy++) {
+#ifdef LITTLE
+               s = (guint16 *) srow;
+#else
+               s = srow;
+#endif
+               o = (guint32 *) orow;
+               for (xx = 0; xx < width; xx++) {
+                       register guint32 data;
+                       /*  rrrrrggg gggbbbbb -> rrrrrRRR gggggGGG bbbbbBBB aaaaaaaa */
+                       /*  little endian: aaaaaaaa bbbbbBBB gggggGGG rrrrrRRR */
+#ifdef LITTLE
+                       /* swap endianness first */
+                       data = s[0] | s[1] << 8;
+                       s += 2;
+                       *o++ = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12
+                               | (data & 0x3e0) << 6 | (data & 0x380) << 1
+                               | (data & 0x1f) << 19 | (data & 0x1c) << 14
+                               | 0xff000000;
+#else
+                       data = *s++;
+                       *o++ = (data & 0x7c00) << 17 | (data & 0x7000) << 12
+                               | (data & 0x3e0) << 14 | (data & 0x380) << 9
+                               | (data & 0x1f) << 11 | (data & 0x1c) << 6
+                               | 0xff;
+#endif
+               }
+               srow += bpl;
+               orow += rowstride;
+       }
+}
+
+
+static void
+rgb888alsb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
+{
+       int xx, yy;
+       int width, height;
+       int bpl;
+
+       guint8 *s;      /* for byte order swapping */
+       guint8 *o;
+       guint8 *srow = image->data, *orow = pixels;
+
+       width = image->width;
+       height = image->height;
+       bpl = image->bytes_per_line;
+
+       d (printf ("32 bits/pixel with alpha\n"));
+
+       /* lsb data */
+       for (yy = 0; yy < height; yy++) {
+               s = srow;
+               o = orow;
+               for (xx = 0; xx < width; xx++) {
+                       *o++ = s[2];
+                       *o++ = s[1];
+                       *o++ = s[0];
+                       *o++ = 0xff;
+                       s += 4;
+               }
+               srow += bpl;
+               orow += rowstride;
+       }
+}
+
+static void
+rgb888lsb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
+{
+       int xx, yy;
+       int width, height;
+       int bpl;
+
+       guint8 *srow = image->data, *orow = pixels;
+       guint8 *o, *s;
+
+       width = image->width;
+       height = image->height;
+       bpl = image->bytes_per_line;
+
+       d (printf ("32 bit, lsb, no alpha\n"));
+
+       for (yy = 0; yy < height; yy++) {
+               s = srow;
+               o = orow;
+               for (xx = 0; xx < width; xx++) {
+                       *o++ = s[2];
+                       *o++ = s[1];
+                       *o++ = s[0];
+                       s += 4;
+               }
+               srow += bpl;
+               orow += rowstride;
+       }
+}
+
+static void
+rgb888amsb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
+{
+       int xx, yy;
+       int width, height;
+       int bpl;
+
+       guint8 *srow = image->data, *orow = pixels;
+#ifdef LITTLE
+       guint32 *o;
+       guint32 *s;
+#else
+       guint8 *s;      /* for byte order swapping */
+       guint8 *o;
+#endif
+
+       d (printf ("32 bit, msb, with alpha\n"));
+
+       width = image->width;
+       height = image->height;
+       bpl = image->bytes_per_line;
+
+       /* msb data */
+       for (yy = 0; yy < height; yy++) {
+#ifdef LITTLE
+               s = (guint32 *) srow;
+               o = (guint32 *) orow;
+#else
+               s = srow;
+               o = orow;
+#endif
+               for (xx = 0; xx < width; xx++) {
+#ifdef LITTLE
+                       *o++ = s[1];
+                       *o++ = s[2];
+                       *o++ = s[3];
+                       *o++ = 0xff;
+                       s += 4;
+#else
+                       *o++ = (*s << 8) | 0xff; /* untested */
+                       s++;
+#endif
+               }
+               srow += bpl;
+               orow += rowstride;
+       }
+}
+
+static void
+rgb888msb (XImage *image, guchar *pixels, int rowstride, xlib_colormap *colormap)
+{
+       int xx, yy;
+       int width, height;
+       int bpl;
+
+       guint8 *srow = image->data, *orow = pixels;
+       guint8 *s;
+       guint8 *o;
+
+       d (printf ("32 bit, msb, no alpha\n"));
+
+       width = image->width;
+       height = image->height;
+       bpl = image->bytes_per_line;
+
+       for (yy = 0; yy < height; yy++) {
+               s = srow;
+               o = orow;
+               for (xx = 0; xx < width; xx++) {
+                       *o++ = s[1];
+                       *o++ = s[2];
+                       *o++ = s[3];
+                       s += 4;
+               }
+               srow += bpl;
+               orow += rowstride;
+       }
+}
+
+/*
+  This should work correctly with any display/any endianness, but will probably
+  run quite slow
+*/
+static void
+convert_real_slow (XImage *image, guchar *pixels, int rowstride, xlib_colormap *cmap, int alpha)
+{
+       int xx, yy;
+       int width, height;
+       int bpl;
+       guint8 *srow = image->data, *orow = pixels;
+       guint8 *s;
+       guint8 *o;
+       guint32 pixel;
+       Visual *v;
+       guint8 component;
+       int i;
+       int red_shift, red_prec, green_shift, green_prec, blue_shift, blue_prec;
+
+       width = image->width;
+       height = image->height;
+       bpl = image->bytes_per_line;
+       v = cmap->visual;
+
+       visual_decompose_mask (v->red_mask, &red_shift, &red_prec);
+       visual_decompose_mask (v->green_mask, &green_shift, &green_prec);
+       visual_decompose_mask (v->blue_mask, &blue_shift, &blue_prec);
+
+       d(printf("rgb  mask/shift/prec = %x:%x:%x %d:%d:%d  %d:%d:%d\n",
+                v->red_mask, v->green_mask, v->blue_mask,
+                red_shift, green_shift, blue_shift,
+                red_prec, green_prec, blue_prec));
+
+       for (yy = 0; yy < height; yy++) {
+               s = srow;
+               o = orow;
+               for (xx = 0; xx < width; xx++) {
+                       pixel = XGetPixel (image, xx, yy);
+                       switch (v->class) {
+                               /* I assume this is right for static & greyscale's too? */
+                       case StaticGray:
+                       case GrayScale:
+                       case StaticColor:
+                       case PseudoColor:
+                               *o++ = cmap->colors[pixel].red;
+                               *o++ = cmap->colors[pixel].green;
+                               *o++ = cmap->colors[pixel].blue;
+                               break;
+                       case TrueColor:
+                               /* This is odd because it must sometimes shift left (otherwise
+                                  I'd just shift >> (*_shift - 8 + *_prec + <0-7>). This logic
+                                  should work for all bit sizes/shifts/etc. */
+                               component = 0;
+                               for (i = 24; i < 32; i += red_prec)
+                                       component |= ((pixel & v->red_mask) << (32 - red_shift - red_prec)) >> i;
+                               *o++ = component;
+                               component = 0;
+                               for (i = 24; i < 32; i += green_prec)
+                                       component |= ((pixel & v->green_mask) << (32 - green_shift - green_prec)) >> i;
+                               *o++ = component;
+                               component = 0;
+                               for (i = 24; i < 32; i += blue_prec)
+                                       component |= ((pixel & v->blue_mask) << (32 - blue_shift - blue_prec)) >> i;
+                               *o++ = component;
+                               break;
+                       case DirectColor:
+                               *o++ = cmap->colors[((pixel & v->red_mask) << (32 - red_shift - red_prec)) >> 24].red;
+                               *o++ = cmap->colors[((pixel & v->green_mask) << (32 - green_shift - green_prec)) >> 24].green;
+                               *o++ = cmap->colors[((pixel & v->blue_mask) << (32 - blue_shift - blue_prec)) >> 24].blue;
+                               break;
+                       }
+                       if (alpha)
+                               *o++ = 0xff;
+               }
+               srow += bpl;
+               orow += rowstride;
+       }
+}
+
+typedef void (* cfunc) (XImage *image, guchar *pixels, int rowstride, xlib_colormap *cmap);
+
+static cfunc convert_map[] = {
+       rgb1,rgb1,rgb1a,rgb1a,
+       rgb8,rgb8,rgb8a,rgb8a,
+       rgb555lsb,rgb555msb,rgb555alsb,rgb555amsb,
+       rgb565lsb,rgb565msb,rgb565alsb,rgb565amsb,
+       rgb888lsb,rgb888msb,rgb888alsb,rgb888amsb
+};
+
+/*
+  perform actual conversion
+
+  If we can, try and use the optimised code versions, but as a default
+  fallback, and always for direct colour, use the generic/slow but complete
+  conversion function.
+*/
+static void
+rgbconvert (XImage *image, guchar *pixels, int rowstride, int alpha, xlib_colormap *cmap)
+{
+       int index = (image->byte_order == MSBFirst) | (alpha != 0) << 1;
+       int bank=5;             /* default fallback converter */
+       Visual *v = cmap->visual;
+
+       d(printf("masks = %x:%x:%x\n", v->red_mask, v->green_mask, v->blue_mask));
+       d(printf("image depth = %d, bpp = %d\n", image->depth, image->bits_per_pixel));
+
+       switch (v->class) {
+                               /* I assume this is right for static & greyscale's too? */
+       case StaticGray:
+       case GrayScale:
+       case StaticColor:
+       case PseudoColor:
+               switch (image->bits_per_pixel) {
+               case 1:
+                       bank = 0;
+                       break;
+               case 8:
+                       bank = 1;
+                       break;
+               }
+               break;
+       case TrueColor:
+               switch (image->depth) {
+               case 15:
+                       if (v->red_mask == 0x7c00 && v->green_mask == 0x3e0 && v->blue_mask == 0x1f
+                           && image->bits_per_pixel == 16)
+                               bank = 2;
+                       break;
+               case 16:
+                       if (v->red_mask == 0xf800 && v->green_mask == 0x7e0 && v->blue_mask == 0x1f
+                           && image->bits_per_pixel == 16)
+                               bank = 3;
+                       break;
+               case 24:
+               case 32:
+                       if (v->red_mask == 0xff0000 && v->green_mask == 0xff00 && v->blue_mask == 0xff
+                           && image->bits_per_pixel == 32)
+                               bank = 4;
+                       break;
+               }
+               break;
+       case DirectColor:
+               /* always use the slow version */
+               break;
+       }
+
+       d(printf("converting using conversion function in bank %d\n", bank));
+
+       if (bank==5) {
+               convert_real_slow(image, pixels, rowstride, cmap, alpha);
+       } else {
+               index |= bank << 2;
+               (* convert_map[index]) (image, pixels, rowstride, cmap);
+       }
+}
+
+static gboolean
+xlib_window_is_viewable (Window w)
+{
+       XWindowAttributes wa;
+
+       while (w != 0) {
+               Window parent, root, *children;
+               int nchildren;
+
+               XGetWindowAttributes (gdk_pixbuf_dpy, w, &wa);
+               if (wa.map_state != IsViewable)
+                       return FALSE;
+
+               if (!XQueryTree (gdk_pixbuf_dpy, w, &root,
+                                &parent, &children, &nchildren))
+                       return FALSE;
+
+               if (nchildren > 0)
+                       XFree (children);
+
+               if (parent == root)
+                       return TRUE;
+
+               w = parent;
+       }
+
+       return FALSE;
+}
+
+static gint
+xlib_window_get_origin (Window w, gint *x, gint *y)
+{
+       Window child;
+       return XTranslateCoordinates (gdk_pixbuf_dpy, w,
+                                     RootWindow (gdk_pixbuf_dpy,
+                                                 gdk_pixbuf_screen),
+                                     0, 0, x, y, &child);
+}
+
+/* Exported functions */
+
+/**
+ * gdk_pixbuf_xlib_get_from_drawable:
+ * @dest: Destination pixbuf, or NULL if a new pixbuf should be created.
+ * @src: Source drawable.
+ * @cmap: A colormap if @src is a pixmap.  If it is a window, this argument will
+ * be ignored.
+ * @visual: A visual if @src is a pixmap.  If it is a window, this argument will
+ * be ignored.
+ * @src_x: Source X coordinate within drawable.
+ * @src_y: Source Y coordinate within drawable.
+ * @dest_x: Destination X coordinate in pixbuf, or 0 if @dest is NULL.
+ * @dest_y: Destination Y coordinate in pixbuf, or 0 if @dest is NULL.
+ * @width: Width in pixels of region to get.
+ * @height: Height in pixels of region to get.
+ *
+ * Transfers image data from a Gdk drawable and converts it to an RGB(A)
+ * representation inside a GdkPixbuf.
+ *
+ * If the drawable @src is a pixmap, then a suitable colormap must be specified,
+ * since pixmaps are just blocks of pixel data without an associated colormap.
+ * If the drawable is a window, the @cmap argument will be ignored and the
+ * window's own colormap will be used instead.
+ *
+ * If the specified destination pixbuf @dest is #NULL, then this function will
+ * create an RGB pixbuf with 8 bits per channel and no alpha, with the same size
+ * specified by the @width and @height arguments.  In this case, the @dest_x and
+ * @dest_y arguments must be specified as 0, otherwise the function will return
+ * #NULL.  If the specified destination pixbuf is not NULL and it contains alpha
+ * information, then the filled pixels will be set to full opacity.
+ *
+ * If the specified drawable is a pixmap, then the requested source rectangle
+ * must be completely contained within the pixmap, otherwise the function will
+ * return #NULL.
+ *
+ * If the specified drawable is a window, then it must be viewable, i.e. all of
+ * its ancestors up to the root window must be mapped.  Also, the specified
+ * source rectangle must be completely contained within the window and within
+ * the screen.  If regions of the window are obscured by noninferior windows, the
+ * contents of those regions are undefined.  The contents of regions obscured by
+ * inferior windows of a different depth than that of the source window will also
+ * be undefined.
+ *
+ * Return value: The same pixbuf as @dest if it was non-NULL, or a newly-created
+ * pixbuf with a reference count of 1 if no destination pixbuf was specified; in
+ * the latter case, NULL will be returned if not enough memory could be
+ * allocated for the pixbuf to be created.
+ **/
+GdkPixbuf *
+gdk_pixbuf_xlib_get_from_drawable (GdkPixbuf *dest,
+                                  Drawable src,
+                                  Colormap cmap, Visual *visual,
+                                  int src_x, int src_y,
+                                  int dest_x, int dest_y,
+                                  int width, int height)
+{
+       int src_width, src_height;
+       XImage *image;
+       int rowstride, bpp, alpha;
+       XWindowAttributes wa;
+       xlib_colormap *x_cmap;
+       gboolean is_pixmap;
+
+       /* General sanity checks */
+
+       g_return_val_if_fail (src != 0, NULL);
+
+       is_pixmap = drawable_is_pixmap (src);
+
+       if (is_pixmap) {
+               g_return_val_if_fail (cmap != 0, NULL);
+               g_return_val_if_fail (visual != NULL, NULL);
+       }
+       else
+               g_return_val_if_fail (xlib_window_is_viewable (src), NULL);
+
+       if (!dest)
+               g_return_val_if_fail (dest_x == 0 && dest_y == 0, NULL);
+       else {
+               g_return_val_if_fail (dest->colorspace == GDK_COLORSPACE_RGB, NULL);
+               g_return_val_if_fail (dest->n_channels == 3
+                                     || dest->n_channels == 4, NULL);
+               g_return_val_if_fail (dest->bits_per_sample == 8, NULL);
+       }
+
+       /* Coordinate sanity checks */
+
+       if (!is_pixmap) {
+           XGetWindowAttributes (gdk_pixbuf_dpy, src, &wa);
+           src_width = wa.width;
+           src_height = wa.height;
+       } else {
+           Window root;
+           int tx, ty, bwidth, depth;
+           XGetGeometry (gdk_pixbuf_dpy, src, &root, &tx, &ty,
+                         &src_width, &src_height, &bwidth, &depth);
+       }
+
+       g_return_val_if_fail (src_x >= 0 && src_y >= 0, NULL);
+       g_return_val_if_fail (src_x + width <= src_width
+                             && src_y + height <= src_height, NULL);
+
+       if (dest) {
+               g_return_val_if_fail (dest_x >= 0 && dest_y >= 0, NULL);
+               g_return_val_if_fail (dest_x + width <= dest->width, NULL);
+               g_return_val_if_fail (dest_y + height <= dest->height, NULL);
+       }
+
+       if (!is_pixmap) {
+               int ret;
+               int src_xorigin, src_yorigin;
+               int screen_width, screen_height;
+               int screen_srcx, screen_srcy;
+
+               ret = xlib_window_get_origin (src, &src_xorigin, &src_yorigin);
+               g_return_val_if_fail (ret != FALSE, NULL);
+
+               screen_width = DisplayWidth (gdk_pixbuf_dpy, gdk_pixbuf_screen);
+               screen_height = DisplayHeight (gdk_pixbuf_dpy, gdk_pixbuf_screen);
+
+               screen_srcx = src_xorigin + src_x;
+               screen_srcy = src_yorigin + src_y;
+
+               g_return_val_if_fail (screen_srcx >= 0 && screen_srcy >= 0, NULL);
+               g_return_val_if_fail (screen_srcx + width <= screen_width, NULL);
+               g_return_val_if_fail (screen_srcy + height <= screen_height, NULL);
+       }
+
+       /* Get Image in ZPixmap format (packed bits). */
+       image = XGetImage (gdk_pixbuf_dpy, src, src_x, src_y,
+                          width, height, AllPlanes, ZPixmap);
+       g_return_val_if_fail (image != NULL, NULL);
+
+       /* Create the pixbuf if needed */
+       if (!dest) {
+               dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+                                      FALSE, 8, width, height);
+               if (!dest) {
+                       XDestroyImage (image);
+                       return NULL;
+               }
+       }
+
+       /* Get the colormap if needed */
+       if (!is_pixmap)
+       {
+               cmap = wa.colormap;
+               visual = wa.visual;
+       }
+
+       x_cmap = xlib_get_colormap (cmap, visual);
+
+       alpha = dest->has_alpha;
+       rowstride = dest->rowstride;
+       bpp = alpha ? 4 : 3;
+
+       /* we offset into the image data based on the position we are retrieving from */
+       rgbconvert (image, dest->pixels +
+                   (dest_y * rowstride) + (dest_x * bpp),
+                   rowstride,
+                   alpha,
+                   x_cmap);
+
+       xlib_colormap_free (x_cmap);
+       XDestroyImage (image);
+
+       return dest;
+}
diff --git a/contrib/gdk-pixbuf-xlib/gdk-pixbuf-xlib-private.h b/contrib/gdk-pixbuf-xlib/gdk-pixbuf-xlib-private.h
new file mode 100644 (file)
index 0000000..6605be5
--- /dev/null
@@ -0,0 +1,30 @@
+/* GdkPixbuf library - Xlib header file
+ *
+ * Authors: John Harper <john@dcs.warwick.ac.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GDK_PIXBUF_XLIB_PRIVATE_H
+#define GDK_PIXBUF_XLIB_PRIVATE_H
+
+#include "gdk-pixbuf-xlib.h"
+#include <X11/Xlib.h>
+
+extern Display *gdk_pixbuf_dpy;
+extern int gdk_pixbuf_screen;
+
+#endif
diff --git a/contrib/gdk-pixbuf-xlib/gdk-pixbuf-xlib-render.c b/contrib/gdk-pixbuf-xlib/gdk-pixbuf-xlib-render.c
new file mode 100644 (file)
index 0000000..b6a26eb
--- /dev/null
@@ -0,0 +1,398 @@
+/* GdkPixbuf library - Rendering functions
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Author: Federico Mena-Quintero <federico@gimp.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Trivially ported to Xlib(RGB) by John Harper. */
+
+#include <config.h>
+#include "gdk-pixbuf-private.h"
+#include "gdk-pixbuf-xlib-private.h"
+
+\f
+
+/**
+ * gdk_pixbuf_xlib_render_threshold_alpha:
+ * @pixbuf: A pixbuf.
+ * @bitmap: Bitmap where the bilevel mask will be painted to.
+ * @src_x: Source X coordinate.
+ * @src_y: source Y coordinate.
+ * @dest_x: Destination X coordinate.
+ * @dest_y: Destination Y coordinate.
+ * @width: Width of region to threshold.
+ * @height: Height of region to threshold.
+ * @alpha_threshold: Opacity values below this will be painted as zero; all
+ * other values will be painted as one.
+ *
+ * Takes the opacity values in a rectangular portion of a pixbuf and thresholds
+ * them to produce a bi-level alpha mask that can be used as a clipping mask for
+ * a drawable.
+ *
+ **/
+void
+gdk_pixbuf_xlib_render_threshold_alpha (GdkPixbuf *pixbuf, Pixmap bitmap,
+                                       int src_x, int src_y,
+                                       int dest_x, int dest_y,
+                                       int width, int height,
+                                       int alpha_threshold)
+{
+       GC gc;
+       XColor color;
+       int x, y;
+       guchar *p;
+       int start, start_status;
+       int status;
+       XGCValues gcv;
+
+       g_return_if_fail (pixbuf != NULL);
+       g_return_if_fail (pixbuf->colorspace == GDK_COLORSPACE_RGB);
+       g_return_if_fail (pixbuf->n_channels == 3 || pixbuf->n_channels == 4);
+       g_return_if_fail (pixbuf->bits_per_sample == 8);
+
+       g_return_if_fail (bitmap != 0);
+       g_return_if_fail (width >= 0 && height >= 0);
+       g_return_if_fail (src_x >= 0 && src_x + width <= pixbuf->width);
+       g_return_if_fail (src_y >= 0 && src_y + height <= pixbuf->height);
+
+       g_return_if_fail (alpha_threshold >= 0 && alpha_threshold <= 255);
+
+       if (width == 0 || height == 0)
+               return;
+
+       gc = XCreateGC (gdk_pixbuf_dpy, bitmap, 0, &gcv);
+
+       if (!pixbuf->has_alpha) {
+               color.pixel = (alpha_threshold == 255) ? 0 : 1;
+               XSetForeground (gdk_pixbuf_dpy, gc, color.pixel);
+               XFillRectangle (gdk_pixbuf_dpy, bitmap, gc,
+                               dest_x, dest_y, width, height);
+               XFreeGC (gdk_pixbuf_dpy, gc);
+               return;
+       }
+
+       color.pixel = 0;
+       XSetForeground (gdk_pixbuf_dpy, gc, color.pixel);
+       XFillRectangle (gdk_pixbuf_dpy, bitmap, gc,
+                       dest_x, dest_y, width, height);
+
+       color.pixel = 1;
+       XSetForeground (gdk_pixbuf_dpy, gc, color.pixel);
+
+       for (y = 0; y < height; y++) {
+               p = (pixbuf->pixels + (y + src_y) * pixbuf->rowstride + src_x * pixbuf->n_channels
+                    + pixbuf->n_channels - 1);
+
+               start = 0;
+               start_status = *p < alpha_threshold;
+
+               for (x = 0; x < width; x++) {
+                       status = *p < alpha_threshold;
+
+                       if (status != start_status) {
+                               if (!start_status)
+                                       XDrawLine (gdk_pixbuf_dpy, bitmap, gc,
+                                                  start + dest_x, y + dest_y,
+                                                  x - 1 + dest_x, y + dest_y);
+
+                               start = x;
+                               start_status = status;
+                       }
+
+                       p += pixbuf->n_channels;
+               }
+
+               if (!start_status)
+                       XDrawLine (gdk_pixbuf_dpy, bitmap, gc,
+                                  start + dest_x, y + dest_y,
+                                  x - 1 + dest_x, y + dest_y);
+       }
+
+       XFreeGC (gdk_pixbuf_dpy, gc);
+}
+
+\f
+
+/* Creates a buffer by stripping the alpha channel of a pixbuf */
+static guchar *
+remove_alpha (GdkPixbuf *pixbuf, int x, int y, int width, int height, int *rowstride)
+{
+       guchar *buf;
+       int xx, yy;
+       guchar *src, *dest;
+
+       g_assert (pixbuf->n_channels == 4);
+       g_assert (pixbuf->has_alpha);
+       g_assert (width > 0 && height > 0);
+       g_assert (x >= 0 && x + width <= pixbuf->width);
+       g_assert (y >= 0 && y + height <= pixbuf->height);
+
+       *rowstride = 4 * ((width * 3 + 3) / 4);
+
+       buf = g_new (guchar, *rowstride * height);
+
+       for (yy = 0; yy < height; yy++) {
+               src = pixbuf->pixels + pixbuf->rowstride * (yy + y) + x * pixbuf->n_channels;
+               dest = buf + *rowstride * yy;
+
+               for (xx = 0; xx < width; xx++) {
+                       *dest++ = *src++;
+                       *dest++ = *src++;
+                       *dest++ = *src++;
+                       src++;
+               }
+       }
+
+       return buf;
+}
+
+/**
+ * gdk_pixbuf_xlib_render_to_drawable:
+ * @pixbuf: A pixbuf.
+ * @drawable: Destination drawable.
+ * @gc: GC used for rendering.
+ * @src_x: Source X coordinate within pixbuf.
+ * @src_y: Source Y coordinate within pixbuf.
+ * @dest_x: Destination X coordinate within drawable.
+ * @dest_y: Destination Y coordinate within drawable.
+ * @width: Width of region to render, in pixels.
+ * @height: Height of region to render, in pixels.
+ * @dither: Dithering mode for XlibRGB.
+ * @x_dither: X offset for dither.
+ * @y_dither: Y offset for dither.
+ *
+ * Renders a rectangular portion of a pixbuf to a drawable while using the
+ * specified GC.  This is done using XlibRGB, so the specified drawable must
+ * have the XlibRGB visual and colormap.  Note that this function will ignore
+ * the opacity information for images with an alpha channel; the GC must already
+ * have the clipping mask set if you want transparent regions to show through.
+ *
+ * For an explanation of dither offsets, see the XlibRGB documentation.  In
+ * brief, the dither offset is important when re-rendering partial regions of an
+ * image to a rendered version of the full image, or for when the offsets to a
+ * base position change, as in scrolling.  The dither matrix has to be shifted
+ * for consistent visual results.  If you do not have any of these cases, the
+ * dither offsets can be both zero.
+ **/
+void
+gdk_pixbuf_xlib_render_to_drawable (GdkPixbuf *pixbuf,
+                                   Drawable drawable, GC gc,
+                                   int src_x, int src_y,
+                                   int dest_x, int dest_y,
+                                   int width, int height,
+                                   XlibRgbDither dither,
+                                   int x_dither, int y_dither)
+{
+       guchar *buf;
+       int rowstride;
+
+       g_return_if_fail (pixbuf != NULL);
+       g_return_if_fail (pixbuf->colorspace == GDK_COLORSPACE_RGB);
+       g_return_if_fail (pixbuf->n_channels == 3 || pixbuf->n_channels == 4);
+       g_return_if_fail (pixbuf->bits_per_sample == 8);
+
+       g_return_if_fail (drawable != 0);
+       g_return_if_fail (gc != 0);
+
+       g_return_if_fail (width >= 0 && height >= 0);
+       g_return_if_fail (src_x >= 0 && src_x + width <= pixbuf->width);
+       g_return_if_fail (src_y >= 0 && src_y + height <= pixbuf->height);
+
+       if (width == 0 || height == 0)
+               return;
+
+       /* This will have to be modified once we support other image types.
+        * Also, GdkRGB does not have gdk_draw_rgb_32_image_dithalign(), so we
+        * have to pack the buffer first.  Sigh.
+        */
+
+       if (pixbuf->has_alpha)
+               buf = remove_alpha (pixbuf, src_x, src_y, width, height, &rowstride);
+       else {
+               buf = pixbuf->pixels + src_y * pixbuf->rowstride + src_x * 3;
+               rowstride = pixbuf->rowstride;
+       }
+
+       xlib_draw_rgb_image_dithalign (drawable, gc,
+                                      dest_x, dest_y,
+                                      width, height,
+                                      dither,
+                                      buf, rowstride,
+                                      x_dither, y_dither);
+
+       if (pixbuf->has_alpha)
+               g_free (buf);
+}
+
+\f
+
+/**
+ * gdk_pixbuf_xlib_render_to_drawable_alpha:
+ * @pixbuf: A pixbuf.
+ * @drawable: Destination drawable.
+ * @src_x: Source X coordinate within pixbuf.
+ * @src_y: Source Y coordinates within pixbuf.
+ * @dest_x: Destination X coordinate within drawable.
+ * @dest_y: Destination Y coordinate within drawable.
+ * @width: Width of region to render, in pixels.
+ * @height: Height of region to render, in pixels.
+ * @alpha_mode: If the image does not have opacity information, this is ignored.
+ * Otherwise, specifies how to handle transparency when rendering.
+ * @alpha_threshold: If the image does have opacity information and @alpha_mode
+ * is GDK_PIXBUF_ALPHA_BILEVEL, specifies the threshold value for opacity
+ * values.
+ * @dither: Dithering mode for XlibRGB.
+ * @x_dither: X offset for dither.
+ * @y_dither: Y offset for dither.
+ *
+ * Renders a rectangular portion of a pixbuf to a drawable.  This is done using
+ * XlibRGB, so the specified drawable must have the XlibRGB visual and colormap.
+ *
+ * When used with #GDK_PIXBUF_ALPHA_BILEVEL, this function has to create a bitmap
+ * out of the thresholded alpha channel of the image and, it has to set this
+ * bitmap as the clipping mask for the GC used for drawing.  This can be a
+ * significant performance penalty depending on the size and the complexity of
+ * the alpha channel of the image.  If performance is crucial, consider handling
+ * the alpha channel yourself (possibly by caching it in your application) and
+ * using gdk_pixbuf_xlib_render_to_drawable() or GdkRGB directly instead.
+ **/
+void
+gdk_pixbuf_xlib_render_to_drawable_alpha (GdkPixbuf *pixbuf, Drawable drawable,
+                                         int src_x, int src_y,
+                                         int dest_x, int dest_y,
+                                         int width, int height,
+                                         GdkPixbufAlphaMode alpha_mode,
+                                         int alpha_threshold,
+                                         XlibRgbDither dither,
+                                         int x_dither, int y_dither)
+{
+       Pixmap bitmap = 0;
+       GC gc;
+       XGCValues gcv;
+
+       g_return_if_fail (pixbuf != NULL);
+       g_return_if_fail (pixbuf->colorspace == GDK_COLORSPACE_RGB);
+       g_return_if_fail (pixbuf->n_channels == 3 || pixbuf->n_channels == 4);
+       g_return_if_fail (pixbuf->bits_per_sample == 8);
+
+       g_return_if_fail (drawable != 0);
+       g_return_if_fail (width >= 0 && height >= 0);
+       g_return_if_fail (src_x >= 0 && src_x + width <= pixbuf->width);
+       g_return_if_fail (src_y >= 0 && src_y + height <= pixbuf->height);
+
+       if (width == 0 || height == 0)
+               return;
+
+       gc = XCreateGC (gdk_pixbuf_dpy, drawable, 0, &gcv);
+
+       if (pixbuf->has_alpha) {
+               /* Right now we only support GDK_PIXBUF_ALPHA_BILEVEL, so we
+                * unconditionally create the clipping mask.
+                */
+
+               bitmap = XCreatePixmap (gdk_pixbuf_dpy,
+                                       RootWindow (gdk_pixbuf_dpy,
+                                                   gdk_pixbuf_screen),
+                                       width, height, 1);
+               gdk_pixbuf_xlib_render_threshold_alpha (pixbuf, bitmap,
+                                                       src_x, src_y,
+                                                       0, 0,
+                                                       width, height,
+                                                       alpha_threshold);
+
+               XSetClipMask (gdk_pixbuf_dpy, gc, bitmap);
+               XSetClipOrigin (gdk_pixbuf_dpy, gc, dest_x, dest_y);
+       }
+
+       gdk_pixbuf_xlib_render_to_drawable (pixbuf, drawable, gc,
+                                           src_x, src_y,
+                                           dest_x, dest_y,
+                                           width, height,
+                                           dither,
+                                           x_dither, y_dither);
+
+       if (bitmap)
+               XFreePixmap (gdk_pixbuf_dpy, bitmap);
+
+       XFreeGC (gdk_pixbuf_dpy, gc);
+}
+
+/**
+ * gdk_pixbuf_xlib_render_pixmap_and_mask:
+ * @pixbuf: A pixbuf.
+ * @pixmap_return: Return value for the created pixmap.
+ * @mask_return: Return value for the created mask.
+ * @alpha_threshold: Threshold value for opacity values.
+ *
+ * Creates a pixmap and a mask bitmap which are returned in the @pixmap_return
+ * and @mask_return arguments, respectively, and renders a pixbuf and its
+ * corresponding tresholded alpha mask to them.  This is merely a convenience
+ * function; applications that need to render pixbufs with dither offsets or to
+ * given drawables should use gdk_pixbuf_xlib_render_to_drawable_alpha() or
+ * gdk_pixbuf_xlib_render_to_drawable(), and
+ * gdk_pixbuf_xlib_render_threshold_alpha().
+ *
+ * If the pixbuf does not have an alpha channel, then *@mask_return will be set
+ * to None.
+ **/
+void
+gdk_pixbuf_xlib_render_pixmap_and_mask (GdkPixbuf *pixbuf,
+                                       Pixmap *pixmap_return,
+                                       Pixmap *mask_return,
+                                       int alpha_threshold)
+{
+        g_return_if_fail (pixbuf != NULL);
+
+       if (pixmap_return) {
+               GC gc;
+               XGCValues gcv;
+
+               *pixmap_return = XCreatePixmap (gdk_pixbuf_dpy,
+                                               RootWindow (gdk_pixbuf_dpy,
+                                                           gdk_pixbuf_screen),
+                                               pixbuf->width,
+                                               pixbuf->height,
+                                               xlib_rgb_get_depth ());
+               gc = XCreateGC (gdk_pixbuf_dpy, *pixmap_return, 0, &gcv);
+               gdk_pixbuf_xlib_render_to_drawable (pixbuf, *pixmap_return, gc,
+                                                   0, 0, 0, 0,
+                                                   pixbuf->width,
+                                                   pixbuf->height,
+                                                   XLIB_RGB_DITHER_NORMAL,
+                                                   0, 0);
+               XFreeGC (gdk_pixbuf_dpy, gc);
+       }
+
+       if (mask_return) {
+               if (pixbuf->has_alpha) {
+                   *mask_return = XCreatePixmap (gdk_pixbuf_dpy,
+                                                 RootWindow (gdk_pixbuf_dpy,
+                                                             gdk_pixbuf_screen),
+                                                 pixbuf->width,
+                                                 pixbuf->height, 1);
+                   gdk_pixbuf_xlib_render_threshold_alpha (pixbuf,
+                                                           *mask_return,
+                                                           0, 0, 0, 0,
+                                                           pixbuf->width,
+                                                           pixbuf->height,
+                                                           alpha_threshold);
+               } else
+                       *mask_return = 0;
+       }
+}
diff --git a/contrib/gdk-pixbuf-xlib/gdk-pixbuf-xlib.c b/contrib/gdk-pixbuf-xlib/gdk-pixbuf-xlib.c
new file mode 100644 (file)
index 0000000..340dd31
--- /dev/null
@@ -0,0 +1,63 @@
+/* GdkPixbuf library - Initialization functions
+ *
+ * Author: John Harper <john@dcs.warwick.ac.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <X11/Xlib.h>
+#include <gdk-pixbuf/gdk-pixbuf-private.h>
+#include "gdk-pixbuf-xlib-private.h"
+
+Display *gdk_pixbuf_dpy = NULL;
+int gdk_pixbuf_screen = -1;
+
+/**
+ * gdk_pixbuf_xlib_init:
+ * @display: X display to use.
+ * @screen_num: Screen number.
+ * 
+ * Initializes the gdk-pixbuf Xlib machinery by calling xlib_rgb_init().  This
+ * function should be called near the beginning of your program, or before using
+ * any of the gdk-pixbuf-xlib functions.
+ **/
+void
+gdk_pixbuf_xlib_init (Display *display, int screen_num)
+{
+    xlib_rgb_init (display, ScreenOfDisplay (display, screen_num));
+    gdk_pixbuf_dpy = display;
+    gdk_pixbuf_screen = screen_num;
+}
+
+/**
+ * gdk_pixbuf_xlib_init_with_depth:
+ * @display: X display to use.
+ * @screen_num: Screen number.
+ * @prefDepth: Preferred depth for XlibRGB.
+ * 
+ * Similar to gdk_pixbuf_xlib_init(), but also lets you specify the preferred
+ * depth for XlibRGB if you do not want it to use the default depth it picks.
+ **/
+void
+gdk_pixbuf_xlib_init_with_depth (Display *display,
+                                int screen_num, int prefDepth)
+{
+    xlib_rgb_init_with_depth (display, ScreenOfDisplay (display, screen_num),
+                             prefDepth);
+    gdk_pixbuf_dpy = display;
+    gdk_pixbuf_screen = screen_num;
+}
diff --git a/contrib/gdk-pixbuf-xlib/gdk-pixbuf-xlib.h b/contrib/gdk-pixbuf-xlib/gdk-pixbuf-xlib.h
new file mode 100644 (file)
index 0000000..b197486
--- /dev/null
@@ -0,0 +1,82 @@
+/* GdkPixbuf library - Xlib header file
+ *
+ * Authors: John Harper <john@dcs.warwick.ac.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GDK_PIXBUF_XLIB_H
+#define GDK_PIXBUF_XLIB_H
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gdk-pixbuf-xlib/gdk-pixbuf-xlibrgb.h>
+#include <X11/Xlib.h>
+
+\f
+
+/* init */
+
+void gdk_pixbuf_xlib_init (Display *display, int screen_num);
+
+void gdk_pixbuf_xlib_init_with_depth (Display *display, int screen_num,
+                                     int prefDepth);
+
+\f
+
+/* render */
+
+void gdk_pixbuf_xlib_render_threshold_alpha (GdkPixbuf *pixbuf, Pixmap bitmap,
+                                            int src_x, int src_y,
+                                            int dest_x, int dest_y,
+                                            int width, int height,
+                                            int alpha_threshold);
+
+void gdk_pixbuf_xlib_render_to_drawable (GdkPixbuf *pixbuf,
+                                        Drawable drawable, GC gc,
+                                        int src_x, int src_y,
+                                        int dest_x, int dest_y,
+                                        int width, int height,
+                                        XlibRgbDither dither,
+                                        int x_dither, int y_dither);
+
+
+void gdk_pixbuf_xlib_render_to_drawable_alpha (GdkPixbuf *pixbuf,
+                                              Drawable drawable,
+                                              int src_x, int src_y,
+                                              int dest_x, int dest_y,
+                                              int width, int height,
+                                              GdkPixbufAlphaMode alpha_mode,
+                                              int alpha_threshold,
+                                              XlibRgbDither dither,
+                                              int x_dither, int y_dither);
+
+void gdk_pixbuf_xlib_render_pixmap_and_mask (GdkPixbuf *pixbuf,
+                                            Pixmap *pixmap_return,
+                                            Pixmap *mask_return,
+                                            int alpha_threshold);
+
+\f
+
+/* drawable */
+
+GdkPixbuf *gdk_pixbuf_xlib_get_from_drawable (GdkPixbuf *dest,
+                                             Drawable src,
+                                             Colormap cmap, Visual *visual,
+                                             int src_x, int src_y,
+                                             int dest_x, int dest_y,
+                                             int width, int height);
+
+#endif /* GDK_PIXBUF_XLIB_H */
diff --git a/contrib/gdk-pixbuf-xlib/gdk-pixbuf-xlibrgb.c b/contrib/gdk-pixbuf-xlib/gdk-pixbuf-xlibrgb.c
new file mode 100644 (file)
index 0000000..97e6d71
--- /dev/null
@@ -0,0 +1,3706 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "MPL"); you may not use this file except in
+ * compliance with the MPL.  You may obtain a copy of the MPL at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the MPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
+ * for the specific language governing rights and limitations under the
+ * MPL.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Library General Public License (the "LGPL"), in
+ * which case the provisions of the LGPL are applicable instead of
+ * those above.  If you wish to allow use of your version of this file
+ * only under the terms of the LGPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the LGPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the LGPL.
+ */
+
+/*
+ * This code is derived from GdkRgb.
+ * For more information on GdkRgb, see http://www.levien.com/gdkrgb/
+ * Raph Levien <raph@acm.org>
+ */
+
+/* Ported by Christopher Blizzard to Xlib.  With permission from the
+ * original authors and the copyright holders of this file, the
+ * contents of this file are also redistributable under the terms of
+ * the Mozilla Public license.  For information about the Mozilla
+ * Public License, please see the license information at
+ * http://www.mozilla.org/MPL/ */
+
+/* This code is copyright the following authors:
+ * Raph Levien          <raph@acm.org>
+ * Manish Singh         <manish@gtk.org>
+ * Tim Janik            <timj@gtk.org>
+ * Peter Mattis         <petm@xcf.berkeley.edu>
+ * Spencer Kimball      <spencer@xcf.berkeley.edu>
+ * Josh MacDonald       <jmacd@xcf.berkeley.edu>
+ * Christopher Blizzard <blizzard@redhat.com>
+ * Owen Taylor          <otaylor@redhat.com>
+ * Shawn T. Amundson    <amundson@gtk.org>
+*/
+
+#include <math.h>
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#  if STDC_HEADERS
+#    include <stdio.h>
+#    include <stdlib.h>
+#    include <string.h>
+#  endif
+#else
+#  include <stdio.h>
+#  include <stdlib.h>
+#endif
+
+#define ENABLE_GRAYSCALE
+
+/* include this before so that we can get endian definitions if
+   they are there... */
+
+#include "gdk-pixbuf-xlibrgb.h"
+
+#ifndef MIN
+#define MIN(a, b)  (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef MAX
+#define MAX(a, b)  (((a) > (b)) ? (a) : (b))
+#endif
+
+typedef enum {
+  LSB_FIRST,
+  MSB_FIRST
+} ByteOrder;
+
+
+typedef struct _XlibRgbInfo   XlibRgbInfo;
+
+typedef void (*XlibRgbConvFunc) (XImage *image,
+                                int ax, int ay,
+                                int width, int height,
+                                unsigned char *buf, int rowstride,
+                                int x_align, int y_align,
+                                XlibRgbCmap *cmap);
+
+/* Some of these fields should go, as they're not being used at all.
+   Globals should generally migrate into here - it's very likely that
+   we'll want to run more than one GdkRgbInfo context at the same time
+   (i.e. some but not all windows have privately installed
+   colormaps). */
+
+struct _XlibRgbInfo
+{
+  Display          *display;
+  Screen           *screen;
+  int               screen_num;
+  XVisualInfo      *x_visual_info;
+  Colormap          cmap;
+  XColor           *cmap_colors;
+  Visual           *default_visualid;
+  Colormap          default_colormap;
+
+  unsigned long    *color_pixels;
+  unsigned long    *gray_pixels;
+  unsigned long    *reserved_pixels;
+
+  unsigned long     red_shift;
+  unsigned long     red_prec;
+  unsigned long     blue_shift;
+  unsigned long     blue_prec;
+  unsigned long     green_shift;
+  unsigned long     green_prec;
+
+  unsigned int      nred_shades;
+  unsigned int      ngreen_shades;
+  unsigned int      nblue_shades;
+  unsigned int      ngray_shades;
+  unsigned int      nreserved;
+
+  unsigned int      bpp;
+  unsigned int      cmap_alloced;
+  double            gamma_val;
+
+  /* Generally, the stage buffer is used to convert 32bit RGB, gray,
+     and indexed images into 24 bit packed RGB. */
+  unsigned char *stage_buf;
+
+  XlibRgbCmap *gray_cmap;
+
+  Bool dith_default;
+
+  Bool bitmap; /* set true if in 1 bit per pixel mode */
+  GC own_gc;
+
+  /* Convert functions */
+  XlibRgbConvFunc conv;
+  XlibRgbConvFunc conv_d;
+
+  XlibRgbConvFunc conv_32;
+  XlibRgbConvFunc conv_32_d;
+
+  XlibRgbConvFunc conv_gray;
+  XlibRgbConvFunc conv_gray_d;
+
+  XlibRgbConvFunc conv_indexed;
+  XlibRgbConvFunc conv_indexed_d;
+};
+
+static Bool xlib_rgb_install_cmap = FALSE;
+static int xlib_rgb_min_colors = 5 * 5 * 5;
+static Bool xlib_rgb_verbose = FALSE;
+
+#define IMAGE_WIDTH 256
+#define STAGE_ROWSTRIDE (IMAGE_WIDTH * 3)
+#define IMAGE_HEIGHT 64
+#define N_IMAGES 6
+
+static XlibRgbInfo *image_info = NULL;
+static XImage *static_image[N_IMAGES];
+static int static_image_idx;
+
+static unsigned char *colorcube;
+static unsigned char *colorcube_d;
+
+static unsigned long
+xlib_get_prec_from_mask(unsigned long val)
+{
+  unsigned long retval = 0;
+  unsigned int cur_bit = 0;
+  /* walk through the number, incrementing the value if
+     the bit in question is set. */
+  while (cur_bit < (sizeof(unsigned long) * 8)) {
+    if ((val >> cur_bit) & 0x1) {
+      retval++;
+    }
+    cur_bit++;
+  }
+  return retval;
+}
+
+static unsigned long
+xlib_get_shift_from_mask(unsigned long val)
+{
+  unsigned long cur_bit = 0;
+  /* walk through the number, looking for the first 1 */
+  while (cur_bit < (sizeof(unsigned long) * 8)) {
+    if ((val >> cur_bit) & 0x1) {
+      return cur_bit;
+    }
+    cur_bit++;
+  }
+  return cur_bit;
+}
+
+
+static int
+xlib_rgb_cmap_fail (const char *msg, Colormap cmap, unsigned long *pixels)
+{
+  unsigned long free_pixels[256];
+  int n_free;
+  int i;
+
+#ifdef VERBOSE
+  printf ("%s", msg);
+#endif
+  n_free = 0;
+  for (i = 0; i < 256; i++)
+    if (pixels[i] < 256)
+      free_pixels[n_free++] = pixels[i];
+  
+  if (n_free)
+    XFreeColors(image_info->display,
+               cmap,
+               free_pixels,
+               n_free,
+               0);
+  return 0;
+}
+
+static void
+xlib_rgb_make_colorcube (unsigned long *pixels, int nr, int ng, int nb)
+{
+  unsigned char rt[16], gt[16], bt[16];
+  int i;
+
+  colorcube = malloc(sizeof(unsigned char) * 4096);
+  memset(colorcube, 0, (sizeof(unsigned char) * 4096));
+  for (i = 0; i < 16; i++)
+    {
+      rt[i] = ng * nb * ((i * 17 * (nr - 1) + 128) >> 8);
+      gt[i] = nb * ((i * 17 * (ng - 1) + 128) >> 8);
+      bt[i] = ((i * 17 * (nb - 1) + 128) >> 8);
+    }
+
+  for (i = 0; i < 4096; i++)
+    {
+      colorcube[i] = pixels[rt[i >> 8] + gt[(i >> 4) & 0x0f] + bt[i & 0x0f]];
+#ifdef VERBOSE
+      printf ("%03x %02x %x %x %x\n", i, colorcube[i], rt[i >> 8], gt[(i >> 4) & 0x0f], bt[i & 0x0f]);
+#endif
+    }
+}
+
+/* this is the colorcube suitable for dithering */
+static void
+xlib_rgb_make_colorcube_d (unsigned long *pixels, int nr, int ng, int nb)
+{
+  int r, g, b;
+  int i;
+
+  colorcube_d = malloc(sizeof(unsigned char) * 512);
+  memset(colorcube_d, 0, (sizeof(unsigned char) * 512));
+  for (i = 0; i < 512; i++)
+    {
+      r = MIN (nr - 1, i >> 6);
+      g = MIN (ng - 1, (i >> 3) & 7);
+      b = MIN (nb - 1, i & 7);
+      colorcube_d[i] = pixels[(r * ng + g) * nb + b];
+    }
+}
+
+/* Try installing a color cube of the specified size.
+   Make the colorcube and return TRUE on success */
+static int
+xlib_rgb_try_colormap (int nr, int ng, int nb)
+{
+  int r, g, b;
+  int ri, gi, bi;
+  int r0, g0, b0;
+  Colormap     cmap;
+  XVisualInfo *visual;
+  XColor      *colors = NULL;
+  XColor       color;
+  unsigned long pixels[256];
+  unsigned long junk[256];
+  int i;
+  int d2;
+  unsigned int colors_needed;
+  int idx;
+  int best[256];
+
+  if (nr * ng * nb < xlib_rgb_min_colors)
+    return FALSE;
+
+  if (image_info->cmap_alloced) {
+    cmap = image_info->cmap;
+    visual = image_info->x_visual_info;
+  }
+  else {
+    cmap = image_info->default_colormap;
+    visual = image_info->x_visual_info;
+  }
+  colors_needed = nr * ng * nb;
+  for (i = 0; i < 256; i++)
+    {
+      best[i] = 192;
+      pixels[i] = 256;
+    }
+
+#ifndef GAMMA
+  if (!xlib_rgb_install_cmap) {
+    /* go out and get the colors for this colormap. */
+    colors = malloc(sizeof(XColor) * visual->colormap_size);
+    for (i=0; i < visual->colormap_size; i++){
+      colors[i].pixel = i;
+    }
+    XQueryColors (image_info->display,
+                 cmap,
+                 colors, visual->colormap_size);
+    /* find color cube colors that are already present */
+    for (i = 0; i < MIN (256, visual->colormap_size); i++)
+      {
+       r = colors[i].red >> 8;
+       g = colors[i].green >> 8;
+       b = colors[i].blue >> 8;
+       ri = (r * (nr - 1) + 128) >> 8;
+       gi = (g * (ng - 1) + 128) >> 8;
+       bi = (b * (nb - 1) + 128) >> 8;
+       r0 = ri * 255 / (nr - 1);
+       g0 = gi * 255 / (ng - 1);
+       b0 = bi * 255 / (nb - 1);
+       idx = ((ri * nr) + gi) * nb + bi;
+       d2 = (r - r0) * (r - r0) + (g - g0) * (g - g0) + (b - b0) * (b - b0);
+       if (d2 < best[idx]) {
+         if (pixels[idx] < 256)
+           XFreeColors(image_info->display,
+                       cmap,
+                       pixels + idx,
+                       1, 0);
+         else
+           colors_needed--;
+         color.pixel = colors[i].pixel;
+         color.red = colors[i].red;
+         color.green = colors[i].green;
+         color.blue = colors[i].blue;
+         color.flags = 0;
+         if (!XAllocColor(image_info->display, cmap, &color))
+           return xlib_rgb_cmap_fail ("error allocating system color\n",
+                                     cmap, pixels);
+         pixels[idx] = color.pixel; /* which is almost certainly i */
+         best[idx] = d2;
+       }
+      }
+  }
+
+#endif
+
+  if (colors_needed)
+    {
+      if (!XAllocColorCells(image_info->display, cmap, 0, NULL, 0, junk, colors_needed))
+       {
+         char tmp_str[80];
+         
+         sprintf (tmp_str,
+                  "%d %d %d colormap failed (in XAllocColorCells)\n",
+                  nr, ng, nb);
+         return xlib_rgb_cmap_fail (tmp_str, cmap, pixels);
+       }
+      XFreeColors(image_info->display, cmap, junk, (int)colors_needed, 0);
+    }
+
+  for (r = 0, i = 0; r < nr; r++)
+    for (g = 0; g < ng; g++)
+      for (b = 0; b < nb; b++, i++)
+       {
+         if (pixels[i] == 256)
+           {
+             color.red = r * 65535 / (nr - 1);
+             color.green = g * 65535 / (ng - 1);
+             color.blue = b * 65535 / (nb - 1);
+
+#ifdef GAMMA
+             color.red = 65535 * pow (color.red / 65535.0, 0.5);
+             color.green = 65535 * pow (color.green / 65535.0, 0.5);
+             color.blue = 65535 * pow (color.blue / 65535.0, 0.5);
+#endif
+
+             /* This should be a raw XAllocColor call */
+             if (!XAllocColor(image_info->display, cmap, &color))
+               {
+                 char tmp_str[80];
+
+                 sprintf (tmp_str, "%d %d %d colormap failed\n",
+                          nr, ng, nb);
+                 return xlib_rgb_cmap_fail (tmp_str,
+                                           cmap, pixels);
+               }
+             pixels[i] = color.pixel;
+           }
+#ifdef VERBOSE
+         printf ("%d: %lx\n", i, pixels[i]);
+#endif
+       }
+
+  image_info->nred_shades = nr;
+  image_info->ngreen_shades = ng;
+  image_info->nblue_shades = nb;
+  xlib_rgb_make_colorcube (pixels, nr, ng, nb);
+  xlib_rgb_make_colorcube_d (pixels, nr, ng, nb);
+  if (colors)
+    free(colors);
+  return TRUE;
+}
+
+/* Return TRUE on success. */
+static Bool
+xlib_rgb_do_colormaps (void)
+{
+  static const int sizes[][3] = {
+    /*    { 6, 7, 6 }, */
+    { 6, 6, 6 }, 
+    { 6, 6, 5 }, 
+    { 6, 6, 4 }, 
+    { 5, 5, 5 }, 
+    { 5, 5, 4 }, 
+    { 4, 4, 4 }, 
+    { 4, 4, 3 }, 
+    { 3, 3, 3 }, 
+    { 2, 2, 2 }
+  };
+  static const int n_sizes = sizeof(sizes) / (3 * sizeof(int));
+  int i;
+  
+  for (i = 0; i < n_sizes; i++)
+    if (xlib_rgb_try_colormap (sizes[i][0], sizes[i][1], sizes[i][2]))
+      return TRUE;
+  return FALSE;
+}
+
+/* Make a 2 x 2 x 2 colorcube */
+static void
+xlib_rgb_colorcube_222 (void)
+{
+  int i;
+  XColor color;
+  Colormap cmap;
+
+  if (image_info->cmap_alloced)
+    cmap = image_info->cmap;
+  else
+    cmap = image_info->default_colormap;
+
+  colorcube_d = malloc(sizeof(unsigned char) * 512);
+
+  for (i = 0; i < 8; i++)
+    {
+      color.red = ((i & 4) >> 2) * 65535;
+      color.green = ((i & 2) >> 1) * 65535;
+      color.blue = (i & 1) * 65535;
+      XAllocColor (image_info->display, cmap, &color);
+      colorcube_d[((i & 4) << 4) | ((i & 2) << 2) | (i & 1)] = color.pixel;
+    }
+}
+
+void
+xlib_rgb_set_verbose (Bool verbose)
+{
+  xlib_rgb_verbose = verbose;
+}
+
+void
+xlib_rgb_set_install (Bool install)
+{
+  xlib_rgb_install_cmap = install;
+}
+
+void
+xlib_rgb_set_min_colors (int min_colors)
+{
+  xlib_rgb_min_colors = min_colors;
+}
+
+/* Return a "score" based on the following criteria (in hex):
+
+   x000 is the quality - 1 is 1bpp, 2 is 4bpp,
+                         4 is 8bpp,
+                        7 is 15bpp truecolor, 8 is 16bpp truecolor,
+                        9 is 24bpp truecolor.
+   0x00 is the speed - 1 is the normal case,
+                       2 means faster than normal
+   00x0 gets a point for being the system visual
+   000x gets a point for being pseudocolor
+
+   A caveat: in the 8bpp modes, being the system visual seems to be
+   quite important. Thus, all of the 8bpp modes should be ranked at
+   the same speed.
+*/
+
+static guint32
+xlib_rgb_score_visual (XVisualInfo *visual)
+{
+  guint32 quality, speed, pseudo, sys;
+  static const char* visual_names[] =
+  {
+    "static gray",
+    "grayscale",
+    "static color",
+    "pseudo color",
+    "true color",
+    "direct color",
+  };
+  
+  
+  quality = 0;
+  speed = 1;
+  sys = 0;
+  if (visual->class == TrueColor ||
+      visual->class == DirectColor)
+    {
+      if (visual->depth == 24)
+       {
+         quality = 9;
+         /* Should test for MSB visual here, and set speed if so. */
+       }
+      else if (visual->depth == 16)
+       quality = 8;
+      else if (visual->depth == 15)
+       quality = 7;
+      else if (visual->depth == 8)
+       quality = 4;
+    }
+  else if (visual->class == PseudoColor ||
+          visual->class == StaticColor)
+    {
+      if (visual->depth == 8)
+       quality = 4;
+      else if (visual->depth == 4)
+       quality = 2;
+      else if (visual->depth == 1)
+       quality = 1;
+    }
+  else if (visual->class == StaticGray
+#ifdef ENABLE_GRAYSCALE
+          || visual->class == GrayScale
+#endif
+          )
+    {
+      if (visual->depth == 8)
+       quality = 4;
+      else if (visual->depth == 4)
+       quality = 2;
+      else if (visual->depth == 1)
+       quality = 1;
+    }
+
+  if (quality == 0)
+    return 0;
+
+  sys = (visual->visualid == image_info->default_visualid->visualid);
+  
+  pseudo = (visual->class == PseudoColor || visual->class == TrueColor);
+
+  if (xlib_rgb_verbose)
+    printf ("Visual 0x%x, type = %s, depth = %d, %ld:%ld:%ld%s; score=%x\n",
+           (int)visual->visualid,
+           visual_names[visual->class],
+           visual->depth,
+           visual->red_mask,
+           visual->green_mask,
+           visual->blue_mask,
+           sys ? " (system)" : "",
+           (quality << 12) | (speed << 8) | (sys << 4) | pseudo);
+  
+  return (quality << 12) | (speed << 8) | (sys << 4) | pseudo;
+}
+
+static void
+xlib_rgb_choose_visual (void)
+{
+  XVisualInfo *visuals;
+  XVisualInfo *visual;
+  XVisualInfo *best_visual;
+  XVisualInfo *final_visual;
+  XVisualInfo template;
+  int num_visuals;
+  guint32 score, best_score;
+  int cur_visual = 1;
+  int i;
+  
+  template.screen = image_info->screen_num;
+  visuals = XGetVisualInfo(image_info->display, VisualScreenMask,
+                          &template, &num_visuals);
+  
+  best_visual = visuals;
+  best_score = xlib_rgb_score_visual (best_visual);
+
+  for (i = cur_visual; i < num_visuals; i++)
+    {
+      visual = &visuals[i];
+      score = xlib_rgb_score_visual  (visual);
+      if (score > best_score)
+       {
+         best_score = score;
+         best_visual = visual;
+       }
+    }
+  /* make a copy of the visual so that we can free
+     the allocated visual list above. */
+  final_visual = malloc(sizeof(XVisualInfo));
+  memcpy(final_visual, best_visual, sizeof(XVisualInfo));
+  image_info->x_visual_info = final_visual;
+  XFree(visuals);
+  /* set up the shift and the precision for the red, green and blue.
+     this only applies to cool visuals like true color and direct color. */
+  if (image_info->x_visual_info->class == TrueColor ||
+      image_info->x_visual_info->class == DirectColor) {
+    image_info->red_shift = xlib_get_shift_from_mask(image_info->x_visual_info->red_mask);
+    image_info->red_prec = xlib_get_prec_from_mask(image_info->x_visual_info->red_mask);
+    image_info->green_shift = xlib_get_shift_from_mask(image_info->x_visual_info->green_mask);
+    image_info->green_prec = xlib_get_prec_from_mask(image_info->x_visual_info->green_mask);
+    image_info->blue_shift = xlib_get_shift_from_mask(image_info->x_visual_info->blue_mask);
+    image_info->blue_prec = xlib_get_prec_from_mask(image_info->x_visual_info->blue_mask);
+  }
+}
+
+static void
+xlib_rgb_choose_visual_for_xprint (int aDepth)
+{
+  XVisualInfo *visuals;
+  XVisualInfo *visual;
+  XVisualInfo *best_visual;
+  XVisualInfo *final_visual;
+  XVisualInfo template;
+  int num_visuals;
+  int cur_visual = 1;
+  int i;
+
+  XWindowAttributes win_att;
+  Status ret_stat;
+  Visual      *root_visual;
+
+  ret_stat = XGetWindowAttributes(image_info->display, 
+                       RootWindow(image_info->display, image_info->screen_num),
+                       &win_att);
+  root_visual = win_att.visual;
+  template.screen = image_info->screen_num;
+  visuals = XGetVisualInfo(image_info->display, VisualScreenMask,
+                          &template, &num_visuals);
+  best_visual = visuals;
+  if (best_visual->visual != root_visual) {
+     for (i = cur_visual; i < num_visuals; i++) {
+        visual = &visuals[i];
+        if (visual->visual == root_visual) {
+           best_visual = visual;
+           break;
+        }
+      }
+   }
+  /* make a copy of the visual so that we can free
+     the allocated visual list above. */
+  final_visual = malloc(sizeof(XVisualInfo));
+  memcpy(final_visual, best_visual, sizeof(XVisualInfo));
+  image_info->x_visual_info = final_visual;
+  XFree(visuals);
+  /* set up the shift and the precision for the red, green and blue.
+     this only applies to cool visuals like true color and direct color. */
+  if (image_info->x_visual_info->class == TrueColor ||
+      image_info->x_visual_info->class == DirectColor) {
+    image_info->red_shift = xlib_get_shift_from_mask(image_info->x_visual_info->red_mask);
+    image_info->red_prec = xlib_get_prec_from_mask(image_info->x_visual_info->red_mask);
+    image_info->green_shift = xlib_get_shift_from_mask(image_info->x_visual_info->green_mask);
+    image_info->green_prec = xlib_get_prec_from_mask(image_info->x_visual_info->green_mask);
+    image_info->blue_shift = xlib_get_shift_from_mask(image_info->x_visual_info->blue_mask);
+    image_info->blue_prec = xlib_get_prec_from_mask(image_info->x_visual_info->blue_mask);
+  }
+}
+
+static void xlib_rgb_select_conv (XImage *image, ByteOrder byte_order);
+
+static void
+xlib_rgb_set_gray_cmap (Colormap cmap)
+{
+  int i;
+  XColor color;
+  int status;
+  unsigned long pixels[256];
+  int r, g, b, gray;
+
+  for (i = 0; i < 256; i++)
+    {
+      color.pixel = i;
+      color.red = i * 257;
+      color.green = i * 257;
+      color.blue = i * 257;
+      status = XAllocColor(image_info->display, cmap, &color);
+      pixels[i] = color.pixel;
+#ifdef VERBOSE
+      printf ("allocating pixel %d, %x %x %x, result %d\n",
+              color.pixel, color.red, color.green, color.blue, status);
+#endif
+    }
+
+  /* Now, we make fake colorcubes - we ultimately just use the pseudocolor
+     methods. */
+
+  colorcube = malloc(sizeof(unsigned char) * 4096);
+
+  for (i = 0; i < 4096; i++)
+    {
+      r = (i >> 4) & 0xf0;
+      r = r | r >> 4;
+      g = i & 0xf0;
+      g = g | g >> 4;
+      b = (i << 4 & 0xf0);
+      b = b | b >> 4;
+      gray = (g + ((r + b) >> 1)) >> 1;
+      colorcube[i] = pixels[gray];
+    }
+}
+
+/**
+ * xlib_rgb_init:
+ * @display: X Display to use.
+ * @screen: Screen to use.
+ * 
+ * Initializes the XlibRGB machinery with the default depth.  If you use this
+ * function XlibRGB will automatically pick the best visual available on your
+ * display.  This function or xlib_rgb_init_with_depth() must be called before
+ * using any of the other functions in XlibRGB.
+ **/
+void
+xlib_rgb_init (Display *display, Screen *screen)
+{
+  int prefDepth = -1;            // let the function do the visual scoring
+  xlib_rgb_init_with_depth(display, screen, prefDepth);
+}
+
+/**
+ * xlib_rgb_init_with_depth:
+ * @display: X display to use.
+ * @screen: Screen to use.
+ * @prefDepth: Visual depth to use for color substitution tables.  This must
+ * be one of the supported visual depths in the specified @display.
+ * 
+ * Initializes the XlibRGB machinery with a particular depth you specify,
+ * instead of automatically picking the best depth in the display.  This
+ * function or xlib_rgb_init() must be called before using any of the other
+ * functions in XlibRGB.
+ **/
+void
+xlib_rgb_init_with_depth (Display *display, Screen *screen, int prefDepth)
+{
+  int i;
+  static const int byte_order[1] = { 1 };
+
+  static int initialized = 0;
+
+  if (initialized)
+  {
+    return;
+  }
+
+  initialized = 1;
+
+  /* check endian sanity */
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+  if (((char *)byte_order)[0] == 1) {
+    printf ("xlib_rgb_init: compiled for big endian, but this is a little endian machine.\n\n");
+    exit(1);
+  }
+#else
+  if (((char *)byte_order)[0] != 1) {
+    printf ("xlib_rgb_init: compiled for little endian, but this is a big endian machine.\n\n");
+    exit(1);
+  }
+#endif
+
+  if (image_info == NULL)
+    {
+      image_info = malloc(sizeof(XlibRgbInfo));
+      memset(image_info, 0, sizeof(XlibRgbInfo));
+
+      image_info->display = display;
+      image_info->screen = screen;
+      image_info->screen_num = XScreenNumberOfScreen(screen);
+      image_info->x_visual_info = NULL;
+      image_info->cmap = 0;
+      image_info->default_visualid = DefaultVisual(display, image_info->screen_num);
+      image_info->default_colormap = DefaultColormap(display, image_info->screen_num);
+
+      image_info->color_pixels = NULL;
+      image_info->gray_pixels = NULL;
+      image_info->reserved_pixels = NULL;
+
+      image_info->nred_shades = 6;
+      image_info->ngreen_shades = 6;
+      image_info->nblue_shades = 4;
+      image_info->ngray_shades = 24;
+      image_info->nreserved = 0;
+
+      image_info->bpp = 0;
+      image_info->cmap_alloced = FALSE;
+      image_info->gamma_val = 1.0;
+
+      image_info->stage_buf = NULL;
+
+      image_info->own_gc = 0;
+      
+      image_info->red_shift = 0;
+      image_info->red_prec = 0;
+      image_info->green_shift = 0;
+      image_info->green_prec = 0;
+      image_info->blue_shift = 0;
+      image_info->blue_prec = 0;
+
+      if (prefDepth != -1)
+        xlib_rgb_choose_visual_for_xprint (prefDepth);
+      else
+        xlib_rgb_choose_visual ();
+
+      if ((image_info->x_visual_info->class == PseudoColor ||
+          image_info->x_visual_info->class == StaticColor) &&
+         image_info->x_visual_info->depth < 8 &&
+         image_info->x_visual_info->depth >= 3)
+       {
+         image_info->cmap = image_info->default_colormap;
+         xlib_rgb_colorcube_222 ();
+       }
+      else if (image_info->x_visual_info->class == PseudoColor)
+       {
+         if (xlib_rgb_install_cmap ||
+             image_info->x_visual_info->visualid != image_info->default_visualid->visualid)
+           {
+             image_info->cmap = XCreateColormap(image_info->display,
+                                                RootWindow(image_info->display, image_info->screen_num),
+                                                image_info->x_visual_info->visual,
+                                                AllocNone);
+             image_info->cmap_alloced = TRUE;
+           }
+         if (!xlib_rgb_do_colormaps ())
+           {
+             image_info->cmap = XCreateColormap(image_info->display,
+                                                RootWindow(image_info->display, image_info->screen_num),
+                                                image_info->x_visual_info->visual,
+                                                AllocNone);
+             image_info->cmap_alloced = TRUE;
+             xlib_rgb_do_colormaps ();
+           }
+         if (xlib_rgb_verbose)
+           printf ("color cube: %d x %d x %d\n",
+                   image_info->nred_shades,
+                   image_info->ngreen_shades,
+                   image_info->nblue_shades);
+
+         if (!image_info->cmap_alloced)
+             image_info->cmap = image_info->default_colormap;
+       }
+#ifdef ENABLE_GRAYSCALE
+      else if (image_info->x_visual_info->class == GrayScale)
+       {
+         image_info->cmap = XCreateColormap(image_info->display,
+                                            RootWindow(image_info->display, image_info->screen_num),
+                                            image_info->x_visual_info->visual,
+                                            AllocNone);
+         xlib_rgb_set_gray_cmap (image_info->cmap);
+         image_info->cmap_alloced = TRUE;
+       }
+#endif
+      else
+       {
+         /* Always install colormap in direct color. */
+         if (image_info->x_visual_info->class != DirectColor && 
+             image_info->x_visual_info->visualid == image_info->default_visualid->visualid)
+           image_info->cmap = image_info->default_colormap;
+         else
+           {
+             image_info->cmap = XCreateColormap(image_info->display,
+                                                RootWindow(image_info->display, image_info->screen_num),
+                                                image_info->x_visual_info->visual,
+                                                AllocNone);
+             image_info->cmap_alloced = TRUE;
+           }
+       }
+
+      image_info->bitmap = (image_info->x_visual_info->depth == 1);
+
+      for (i = 0; i < N_IMAGES; i++) {
+       if (image_info->bitmap) {
+         /* Use malloc() instead of g_malloc since X will free() this mem */
+         static_image[i] = XCreateImage(image_info->display,
+                                        image_info->x_visual_info->visual,
+                                        1,
+                                        XYBitmap,
+                                        0, 0, IMAGE_WIDTH, IMAGE_HEIGHT,
+                                        8,
+                                        0);
+         static_image[i]->data = malloc(IMAGE_WIDTH * IMAGE_HEIGHT >> 3);
+         static_image[i]->bitmap_bit_order = MSBFirst;
+         static_image[i]->byte_order = MSBFirst;
+       }
+       else {
+         static_image[i] = XCreateImage(image_info->display,
+                                        image_info->x_visual_info->visual,
+                                        (unsigned int)image_info->x_visual_info->depth,
+                                        ZPixmap,
+                                        0, 0,
+                                        IMAGE_WIDTH,
+                                        IMAGE_HEIGHT,
+                                        32, 0);
+         /* remove this when we are using shared memory.. */
+         static_image[i]->data = malloc((size_t)IMAGE_WIDTH * IMAGE_HEIGHT * image_info->x_visual_info->depth);
+         static_image[i]->bitmap_bit_order = MSBFirst;
+         static_image[i]->byte_order = MSBFirst;
+       }
+      }
+      /* ok, so apparently, image_info->bpp is actually
+        BYTES per pixel.  What fun! */
+      switch (static_image[0]->bits_per_pixel) {
+      case 1:
+      case 8:
+       image_info->bpp = 1;
+       break;
+      case 16:
+       image_info->bpp = 2;
+       break;
+      case 24:
+       image_info->bpp = 3;
+       break;
+      case 32:
+       image_info->bpp = 4;
+       break;
+      }
+      xlib_rgb_select_conv (static_image[0], MSB_FIRST);
+    }
+}
+
+/**
+ * xlib_rgb_xpixel_from_rgb:
+ * @rgb: 32-bit representation of an RGB value, specified as 0x00RRGGBB.
+ * 
+ * Converts an RGB triplet into the closest color that XlibRGB visual can
+ * handle.
+ * 
+ * Return value: X pixel value that corresponds to the closest color in the
+ * XlibRGB visual and colormap.
+ **/
+unsigned long
+xlib_rgb_xpixel_from_rgb (guint32 rgb)
+{
+  unsigned long pixel = 0;
+
+  if (image_info->bitmap)
+    {
+      return ((rgb & 0xff0000) >> 16) +
+       ((rgb & 0xff00) >> 7) +
+       (rgb & 0xff) > 510;
+    }
+  else if (image_info->x_visual_info->class == PseudoColor)
+    pixel = colorcube[((rgb & 0xf00000) >> 12) |
+                    ((rgb & 0xf000) >> 8) |
+                    ((rgb & 0xf0) >> 4)];
+  else if (image_info->x_visual_info->depth < 8 &&
+          image_info->x_visual_info->class == StaticColor)
+    {
+      pixel = colorcube_d[((rgb & 0x800000) >> 17) |
+                        ((rgb & 0x8000) >> 12) |
+                        ((rgb & 0x80) >> 7)];
+    }
+  else if (image_info->x_visual_info->class == TrueColor ||
+          image_info->x_visual_info->class == DirectColor)
+    {
+#ifdef VERBOSE
+      printf ("shift, prec: r %d %d g %d %d b %d %d\n",
+             image_info->red_shift,
+             image_info->red_prec,
+             image_info->green_shift,
+             image_info->green_prec,
+             image_info->blue_shift,
+             image_info->blue_prec);
+#endif
+
+      pixel = (((((rgb & 0xff0000) >> 16) >>
+                (8 - image_info->red_prec)) <<
+               image_info->red_shift) +
+              ((((rgb & 0xff00) >> 8)  >>
+                (8 - image_info->green_prec)) <<
+               image_info->green_shift) +
+              (((rgb & 0xff) >>
+                (8 - image_info->blue_prec)) <<
+               image_info->blue_shift));
+    }
+  else if (image_info->x_visual_info->class == StaticGray ||
+          image_info->x_visual_info->class == GrayScale)
+    {
+      int gray = ((rgb & 0xff0000) >> 16) +
+       ((rgb & 0xff00) >> 7) +
+       (rgb & 0xff);
+
+      return gray >> (10 - image_info->x_visual_info->depth);
+    }
+
+  return pixel;
+}
+
+/**
+ * xlib_rgb_gc_set_foreground:
+ * @gc: A graphic context.
+ * @rgb: 32-bit representation of an RGB value, specified as 0x00RRGGBB.
+ * 
+ * This is a convenience function to set the foreground of a GC from an RGB
+ * triplet.  It calls xlib_rgb_xpixel_from_rgb() internally and uses the
+ * returned pixel value to set the GC's foreground.
+ **/
+void
+xlib_rgb_gc_set_foreground (GC gc, guint32 rgb)
+{
+  unsigned long color;
+
+  color = xlib_rgb_xpixel_from_rgb (rgb);
+  XSetForeground(image_info->display, gc, color);
+}
+
+/**
+ * xlib_rgb_gc_set_foreground:
+ * @gc: A graphic context.
+ * @rgb: 32-bit representation of an RGB value, specified as 0x00RRGGBB.
+ * 
+ * This is a convenience function to set the background of a GC from an RGB
+ * triplet.  It calls xlib_rgb_xpixel_from_rgb() internally and uses the
+ * returned pixel value to set the GC's background.
+ **/
+void
+xlib_rgb_gc_set_background (GC gc, guint32 rgb)
+{
+  unsigned long color;
+
+  color = xlib_rgb_xpixel_from_rgb (rgb);
+  XSetBackground(image_info->display, gc, color);
+}
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define HAIRY_CONVERT_8
+#endif
+
+#ifdef HAIRY_CONVERT_8
+static void
+xlib_rgb_convert_8 (XImage *image,
+                  int ax, int ay, int width, int height,
+                  unsigned char *buf, int rowstride,
+                  int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  int x, y;
+  int bpl;
+  unsigned char *obuf, *obptr;
+  unsigned char *bptr, *bp2;
+  int r, g, b;
+
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + ax;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      obptr = obuf;
+      if (((unsigned long)obuf | (unsigned long) bp2) & 3)
+       {
+         for (x = 0; x < width; x++)
+           {
+             r = *bp2++;
+             g = *bp2++;
+             b = *bp2++;
+             obptr[0] = colorcube[((r & 0xf0) << 4) |
+                                 (g & 0xf0) |
+                                 (b >> 4)];
+             obptr++;
+           }
+       }
+      else
+       {
+         for (x = 0; x < width - 3; x += 4)
+           {
+             guint32 r1b0g0r0;
+             guint32 g2r2b1g1;
+             guint32 b3g3r3b2;
+
+             r1b0g0r0 = ((guint32 *)bp2)[0];
+             g2r2b1g1 = ((guint32 *)bp2)[1];
+             b3g3r3b2 = ((guint32 *)bp2)[2];
+             ((guint32 *)obptr)[0] =
+               colorcube[((r1b0g0r0 & 0xf0) << 4) | 
+                        ((r1b0g0r0 & 0xf000) >> 8) |
+                        ((r1b0g0r0 & 0xf00000) >> 20)] |
+               (colorcube[((r1b0g0r0 & 0xf0000000) >> 20) |
+                         (g2r2b1g1 & 0xf0) |
+                         ((g2r2b1g1 & 0xf000) >> 12)] << 8) |
+               (colorcube[((g2r2b1g1 & 0xf00000) >> 12) |
+                         ((g2r2b1g1 & 0xf0000000) >> 24) |
+                         ((b3g3r3b2 & 0xf0) >> 4)] << 16) |
+               (colorcube[((b3g3r3b2 & 0xf000) >> 4) |
+                         ((b3g3r3b2 & 0xf00000) >> 16) |
+                         (b3g3r3b2 >> 28)] << 24);
+             bp2 += 12;
+             obptr += 4;
+           }
+         for (; x < width; x++)
+           {
+             r = *bp2++;
+             g = *bp2++;
+             b = *bp2++;
+             obptr[0] = colorcube[((r & 0xf0) << 4) |
+                                 (g & 0xf0) |
+                                 (b >> 4)];
+             obptr++;
+           }
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+#else
+static void
+xlib_rgb_convert_8 (XImage *image,
+                  int ax, int ay, int width, int height,
+                  unsigned char *buf, int rowstride,
+                  int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  int x, y;
+  int bpl;
+  unsigned char *obuf, *obptr;
+  unsigned char *bptr, *bp2;
+  int r, g, b;
+
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + ax;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      obptr = obuf;
+      for (x = 0; x < width; x++)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         obptr[0] = colorcube[((r & 0xf0) << 4) |
+                             (g & 0xf0) |
+                             (b >> 4)];
+         obptr++;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+#endif
+
+#if 1
+
+/* This dither table was generated by Raph Levien using patented
+   technology (US Patent 5,276,535). The dither table itself is in the
+   public domain. */
+
+#define DM_WIDTH 128
+#define DM_WIDTH_SHIFT 7
+#define DM_HEIGHT 128
+static const unsigned char DM[128][128] =
+{
+  { 0, 41, 23, 5, 17, 39, 7, 15, 62, 23, 40, 51, 31, 47, 9, 32, 52, 27, 57, 25, 6, 61, 27, 52, 37, 7, 40, 63, 18, 36, 10, 42, 25, 62, 45, 34, 20, 42, 37, 14, 35, 29, 50, 10, 61, 2, 40, 8, 37, 12, 58, 22, 5, 41, 10, 39, 0, 60, 11, 46, 2, 55, 38, 17, 36, 59, 13, 54, 37, 56, 8, 29, 16, 13, 63, 22, 41, 55, 7, 20, 49, 14, 23, 55, 37, 23, 19, 36, 15, 49, 23, 63, 30, 14, 38, 27, 53, 13, 22, 41, 19, 31, 7, 19, 50, 30, 49, 16, 3, 32, 56, 40, 29, 34, 8, 48, 19, 45, 4, 51, 12, 46, 35, 49, 16, 42, 12, 62 },
+  { 30, 57, 36, 54, 47, 34, 52, 27, 43, 4, 28, 7, 17, 36, 62, 13, 44, 7, 18, 48, 33, 21, 44, 14, 30, 47, 12, 33, 5, 55, 31, 58, 13, 30, 4, 17, 52, 10, 60, 26, 46, 0, 39, 27, 42, 22, 47, 25, 60, 32, 9, 38, 48, 17, 59, 30, 49, 18, 34, 25, 51, 19, 5, 48, 21, 8, 28, 46, 1, 32, 41, 19, 54, 47, 37, 18, 28, 11, 44, 30, 39, 56, 2, 33, 8, 42, 61, 28, 58, 8, 46, 9, 41, 4, 58, 7, 21, 48, 59, 10, 52, 14, 42, 57, 12, 25, 7, 53, 42, 24, 11, 50, 17, 59, 42, 2, 36, 60, 32, 17, 63, 29, 21, 7, 59, 32, 24, 39 },
+  { 22, 8, 16, 32, 3, 25, 13, 57, 18, 45, 58, 39, 55, 20, 5, 42, 23, 34, 63, 1, 51, 10, 58, 4, 60, 23, 53, 27, 44, 21, 3, 48, 8, 50, 43, 54, 27, 32, 5, 55, 21, 58, 12, 53, 6, 36, 14, 50, 17, 29, 53, 15, 24, 52, 7, 36, 13, 42, 4, 53, 9, 35, 61, 26, 56, 32, 49, 15, 62, 23, 6, 60, 2, 31, 4, 48, 58, 38, 15, 61, 5, 25, 47, 28, 50, 15, 7, 40, 3, 32, 33, 52, 25, 50, 35, 42, 61, 3, 28, 36, 23, 63, 4, 33, 46, 62, 36, 23, 60, 6, 54, 28, 4, 37, 23, 55, 25, 8, 42, 54, 14, 6, 56, 38, 19, 52, 4, 46 },
+  { 48, 53, 43, 12, 45, 63, 30, 37, 9, 34, 21, 1, 25, 47, 29, 58, 3, 54, 15, 39, 29, 17, 38, 35, 20, 43, 1, 49, 15, 59, 29, 39, 22, 35, 16, 23, 1, 47, 39, 18, 8, 44, 25, 31, 57, 19, 63, 4, 45, 3, 42, 61, 1, 31, 45, 20, 57, 29, 62, 21, 32, 41, 14, 44, 3, 39, 5, 34, 10, 43, 51, 35, 23, 52, 40, 10, 21, 1, 53, 18, 51, 43, 12, 62, 18, 54, 26, 51, 20, 57, 14, 1, 62, 16, 11, 18, 32, 39, 17, 44, 1, 48, 26, 37, 18, 2, 51, 14, 28, 45, 35, 18, 57, 13, 47, 11, 51, 20, 2, 39, 31, 47, 25, 1, 50, 11, 60, 7 },
+  { 18, 28, 1, 56, 21, 10, 51, 2, 46, 54, 14, 61, 11, 50, 13, 38, 19, 31, 45, 9, 55, 24, 47, 5, 54, 9, 62, 11, 35, 8, 51, 14, 57, 6, 63, 40, 58, 14, 51, 28, 62, 34, 15, 48, 1, 41, 30, 35, 55, 21, 34, 11, 49, 37, 8, 52, 4, 23, 15, 43, 1, 58, 11, 23, 53, 16, 55, 26, 58, 18, 27, 12, 45, 14, 25, 63, 42, 33, 27, 35, 9, 31, 21, 38, 1, 44, 34, 12, 48, 38, 21, 44, 29, 47, 26, 53, 1, 46, 54, 8, 59, 29, 11, 55, 22, 41, 33, 20, 39, 1, 48, 9, 44, 32, 5, 62, 29, 44, 57, 23, 10, 58, 34, 43, 15, 37, 26, 33 },
+  { 51, 38, 59, 24, 35, 42, 19, 60, 5, 32, 41, 26, 43, 33, 7, 53, 48, 11, 59, 23, 42, 2, 61, 30, 16, 40, 32, 24, 56, 41, 19, 33, 37, 26, 47, 9, 31, 22, 2, 45, 9, 54, 4, 37, 21, 52, 11, 23, 7, 57, 16, 25, 55, 18, 63, 27, 46, 39, 56, 10, 50, 37, 29, 47, 19, 63, 24, 9, 46, 2, 39, 60, 9, 57, 30, 7, 49, 11, 59, 3, 45, 57, 5, 60, 29, 22, 5, 60, 30, 9, 59, 18, 40, 6, 57, 36, 30, 12, 24, 34, 15, 40, 52, 6, 49, 9, 58, 4, 63, 12, 26, 61, 22, 53, 38, 16, 35, 14, 28, 50, 42, 17, 5, 28, 62, 20, 54, 12 },
+  { 26, 6, 31, 15, 49, 6, 38, 27, 22, 49, 16, 56, 2, 62, 30, 21, 0, 36, 28, 6, 49, 32, 13, 52, 26, 50, 19, 46, 3, 26, 62, 0, 53, 12, 29, 3, 53, 41, 60, 24, 38, 13, 58, 16, 43, 9, 59, 39, 46, 28, 44, 40, 2, 33, 13, 41, 16, 6, 47, 31, 26, 17, 57, 6, 38, 0, 42, 36, 29, 52, 20, 31, 48, 0, 34, 56, 20, 36, 23, 54, 14, 41, 24, 37, 10, 55, 46, 25, 16, 45, 36, 4, 55, 23, 15, 8, 50, 62, 5, 56, 44, 20, 13, 28, 59, 31, 24, 47, 31, 52, 37, 17, 40, 0, 26, 49, 3, 60, 7, 33, 0, 61, 53, 40, 8, 45, 2, 41 },
+  { 16, 63, 43, 4, 61, 24, 56, 13, 53, 8, 36, 12, 24, 41, 16, 46, 60, 26, 52, 39, 14, 57, 21, 37, 0, 45, 7, 59, 38, 17, 43, 10, 45, 20, 61, 43, 19, 11, 33, 17, 50, 32, 23, 61, 28, 49, 26, 0, 18, 51, 5, 60, 22, 58, 29, 0, 59, 34, 19, 62, 3, 52, 7, 44, 30, 59, 13, 50, 15, 62, 7, 17, 38, 22, 44, 15, 40, 4, 47, 28, 33, 17, 49, 16, 51, 40, 10, 56, 0, 53, 13, 49, 28, 38, 60, 21, 43, 19, 37, 27, 3, 51, 34, 39, 0, 45, 15, 43, 10, 21, 3, 55, 8, 33, 59, 10, 41, 18, 52, 24, 46, 20, 30, 13, 58, 22, 36, 57 },
+  { 50, 34, 11, 47, 29, 17, 44, 0, 33, 63, 28, 46, 52, 5, 57, 10, 42, 18, 4, 63, 20, 8, 44, 10, 56, 34, 14, 29, 5, 54, 23, 59, 32, 49, 7, 34, 49, 27, 56, 0, 42, 7, 46, 3, 40, 6, 54, 32, 62, 13, 36, 10, 47, 8, 35, 49, 24, 51, 12, 40, 22, 35, 60, 12, 22, 51, 33, 4, 40, 25, 43, 55, 5, 54, 12, 61, 26, 51, 8, 62, 0, 53, 7, 63, 2, 32, 19, 34, 42, 24, 31, 63, 2, 10, 45, 33, 0, 48, 9, 61, 22, 47, 8, 62, 18, 56, 7, 54, 27, 57, 46, 30, 50, 19, 45, 30, 56, 36, 22, 47, 11, 38, 3, 51, 32, 48, 18, 9 },
+  { 0, 21, 40, 19, 52, 9, 37, 48, 20, 40, 3, 18, 27, 38, 35, 22, 31, 56, 13, 35, 46, 28, 60, 40, 27, 18, 61, 50, 41, 30, 7, 36, 2, 25, 16, 57, 5, 15, 47, 29, 55, 19, 30, 52, 15, 34, 20, 12, 43, 30, 20, 54, 25, 44, 53, 12, 38, 5, 55, 27, 48, 15, 33, 27, 45, 8, 19, 28, 56, 11, 33, 49, 18, 36, 29, 2, 45, 16, 39, 19, 31, 43, 27, 35, 20, 52, 26, 6, 61, 11, 41, 17, 29, 51, 20, 56, 25, 32, 41, 17, 53, 31, 25, 14, 42, 23, 35, 16, 38, 6, 34, 12, 15, 62, 6, 21, 13, 1, 63, 9, 55, 27, 43, 25, 14, 4, 31, 55 },
+  { 44, 29, 61, 2, 35, 58, 26, 15, 60, 10, 51, 59, 14, 55, 8, 50, 2, 44, 25, 51, 1, 33, 16, 4, 48, 36, 2, 21, 12, 57, 48, 13, 51, 55, 40, 28, 37, 62, 8, 39, 12, 63, 36, 10, 59, 24, 56, 47, 9, 50, 41, 1, 32, 17, 6, 21, 61, 30, 9, 43, 1, 54, 41, 2, 54, 37, 48, 61, 1, 46, 21, 3, 58, 24, 50, 32, 60, 10, 57, 25, 46, 12, 59, 4, 45, 13, 57, 47, 27, 39, 5, 58, 47, 14, 35, 4, 52, 13, 60, 6, 36, 10, 45, 55, 4, 50, 29, 2, 61, 50, 25, 58, 44, 24, 36, 42, 54, 28, 40, 32, 16, 56, 6, 62, 46, 39, 60, 23 },
+  { 7, 48, 14, 54, 23, 40, 4, 45, 30, 22, 42, 32, 1, 44, 20, 29, 58, 8, 37, 19, 41, 54, 24, 58, 9, 53, 25, 46, 34, 16, 23, 38, 27, 11, 18, 1, 52, 21, 35, 22, 48, 5, 25, 45, 18, 38, 2, 27, 35, 4, 57, 15, 62, 39, 57, 28, 42, 16, 36, 60, 24, 18, 10, 63, 20, 5, 16, 23, 37, 14, 59, 27, 41, 8, 13, 42, 21, 35, 6, 50, 3, 38, 15, 48, 30, 39, 17, 3, 49, 14, 53, 33, 24, 7, 61, 44, 11, 39, 23, 49, 19, 58, 1, 32, 36, 12, 60, 41, 20, 13, 41, 4, 39, 1, 48, 8, 18, 51, 14, 44, 5, 37, 21, 34, 1, 26, 10, 37 },
+  { 53, 36, 27, 9, 50, 12, 32, 55, 2, 57, 7, 17, 48, 34, 63, 15, 40, 26, 62, 11, 49, 6, 31, 39, 22, 42, 6, 63, 1, 39, 60, 4, 42, 61, 32, 45, 24, 44, 2, 60, 16, 41, 53, 1, 33, 61, 49, 17, 63, 23, 45, 26, 33, 3, 23, 46, 2, 50, 20, 4, 45, 34, 49, 30, 39, 58, 44, 31, 53, 34, 6, 52, 30, 47, 63, 1, 53, 22, 42, 31, 58, 23, 54, 22, 61, 8, 36, 59, 22, 35, 21, 1, 55, 40, 27, 16, 30, 54, 2, 29, 43, 16, 39, 63, 21, 46, 26, 10, 48, 32, 19, 53, 30, 56, 26, 60, 33, 4, 61, 23, 49, 59, 15, 53, 19, 58, 42, 16 },
+  { 20, 5, 59, 46, 25, 62, 7, 19, 43, 25, 37, 61, 11, 24, 4, 54, 12, 52, 3, 32, 17, 61, 12, 47, 15, 55, 18, 31, 53, 28, 9, 50, 21, 6, 55, 9, 58, 14, 54, 26, 33, 7, 31, 58, 13, 21, 8, 42, 29, 6, 37, 11, 48, 52, 14, 60, 11, 39, 56, 32, 14, 58, 7, 26, 17, 4, 42, 8, 11, 47, 19, 38, 10, 17, 26, 37, 9, 55, 28, 13, 18, 40, 6, 33, 1, 43, 25, 11, 51, 7, 62, 43, 18, 37, 3, 57, 45, 9, 38, 58, 5, 52, 27, 7, 17, 53, 5, 57, 37, 2, 63, 9, 22, 15, 11, 38, 25, 45, 35, 0, 28, 10, 41, 30, 50, 8, 31, 57 },
+  { 49, 33, 16, 38, 1, 42, 51, 34, 53, 14, 28, 49, 30, 56, 36, 23, 43, 20, 38, 56, 22, 45, 28, 0, 62, 35, 26, 44, 11, 19, 52, 35, 44, 15, 30, 38, 10, 31, 40, 4, 46, 50, 20, 40, 27, 44, 51, 14, 56, 53, 19, 59, 7, 29, 41, 19, 35, 25, 8, 52, 22, 44, 13, 53, 50, 32, 61, 24, 56, 25, 63, 0, 45, 57, 33, 59, 16, 46, 4, 62, 50, 11, 60, 37, 52, 19, 55, 29, 37, 46, 13, 26, 48, 10, 50, 34, 21, 63, 26, 13, 42, 33, 22, 55, 35, 28, 43, 15, 24, 51, 27, 34, 46, 49, 58, 3, 52, 9, 57, 19, 48, 55, 3, 35, 12, 45, 24, 3 },
+  { 41, 11, 56, 28, 18, 31, 22, 10, 37, 6, 47, 13, 3, 41, 9, 46, 0, 48, 29, 6, 34, 10, 55, 37, 20, 8, 49, 3, 41, 59, 14, 25, 0, 63, 19, 47, 27, 51, 17, 57, 23, 10, 61, 6, 54, 3, 38, 31, 0, 22, 34, 43, 20, 55, 31, 0, 49, 63, 29, 38, 3, 62, 28, 40, 0, 22, 14, 35, 2, 48, 15, 43, 23, 14, 3, 29, 49, 20, 39, 34, 0, 44, 29, 9, 15, 47, 5, 42, 0, 31, 58, 5, 31, 61, 23, 15, 0, 47, 19, 50, 24, 3, 59, 11, 44, 0, 31, 59, 6, 42, 17, 60, 0, 39, 20, 31, 43, 17, 29, 40, 12, 25, 60, 22, 52, 15, 63, 29 },
+  { 20, 52, 8, 44, 62, 4, 59, 49, 17, 63, 21, 39, 60, 18, 52, 27, 33, 59, 14, 51, 59, 43, 24, 5, 51, 30, 57, 17, 32, 5, 37, 56, 48, 34, 42, 3, 60, 5, 36, 13, 43, 37, 18, 34, 25, 12, 59, 24, 47, 36, 11, 50, 3, 38, 9, 58, 16, 5, 43, 18, 47, 10, 37, 18, 59, 46, 29, 52, 40, 12, 34, 28, 56, 36, 53, 7, 43, 8, 24, 52, 26, 17, 56, 43, 24, 32, 63, 20, 57, 16, 22, 52, 36, 8, 41, 56, 29, 32, 54, 7, 35, 57, 14, 48, 20, 62, 13, 39, 53, 29, 8, 45, 13, 29, 7, 61, 14, 54, 6, 63, 38, 32, 18, 43, 2, 39, 6, 47 },
+  { 0, 58, 23, 35, 13, 46, 12, 39, 0, 31, 55, 24, 5, 35, 15, 61, 17, 5, 39, 25, 18, 2, 50, 33, 41, 13, 39, 23, 62, 46, 29, 12, 22, 8, 56, 25, 20, 49, 32, 62, 0, 56, 11, 46, 63, 42, 9, 16, 55, 5, 60, 15, 62, 26, 45, 21, 36, 51, 13, 57, 31, 24, 55, 6, 35, 9, 57, 5, 20, 60, 7, 51, 5, 19, 40, 25, 61, 32, 56, 12, 36, 48, 21, 2, 58, 12, 39, 28, 9, 50, 40, 12, 44, 18, 25, 49, 6, 38, 11, 62, 18, 46, 30, 9, 40, 25, 49, 19, 10, 36, 55, 22, 33, 52, 41, 18, 37, 27, 49, 21, 2, 46, 7, 53, 33, 61, 27, 35 },
+  { 41, 31, 5, 39, 51, 26, 33, 57, 27, 41, 9, 44, 54, 29, 48, 7, 44, 36, 57, 10, 31, 63, 16, 45, 11, 60, 1, 47, 7, 20, 43, 3, 58, 36, 13, 52, 39, 7, 15, 28, 22, 48, 30, 21, 1, 29, 49, 44, 27, 17, 40, 30, 24, 42, 12, 53, 33, 7, 47, 20, 1, 42, 11, 49, 25, 43, 17, 32, 45, 27, 41, 21, 31, 62, 11, 49, 2, 15, 42, 5, 63, 7, 41, 27, 49, 6, 54, 23, 46, 34, 2, 28, 54, 3, 59, 12, 46, 17, 42, 28, 40, 1, 37, 51, 5, 55, 2, 34, 47, 16, 3, 62, 47, 5, 23, 56, 1, 44, 12, 34, 51, 16, 57, 11, 25, 17, 54, 13 },
+  { 60, 26, 55, 18, 3, 60, 20, 6, 52, 15, 50, 19, 32, 11, 23, 53, 26, 21, 1, 47, 42, 27, 8, 58, 21, 27, 53, 36, 26, 54, 31, 50, 17, 30, 45, 1, 29, 59, 44, 53, 41, 4, 35, 58, 51, 19, 32, 4, 52, 34, 48, 8, 51, 5, 56, 2, 25, 61, 27, 38, 54, 27, 62, 21, 51, 1, 39, 62, 10, 50, 1, 58, 13, 47, 38, 18, 35, 54, 22, 51, 30, 19, 59, 34, 14, 32, 44, 4, 60, 15, 52, 62, 20, 43, 30, 35, 21, 60, 4, 52, 12, 24, 61, 18, 30, 42, 23, 61, 25, 50, 27, 38, 11, 59, 12, 35, 50, 30, 59, 24, 8, 42, 28, 37, 48, 9, 44, 21 },
+  { 10, 47, 15, 50, 30, 43, 8, 45, 29, 2, 36, 59, 1, 58, 41, 3, 63, 31, 54, 20, 13, 55, 35, 38, 4, 44, 15, 9, 61, 2, 14, 38, 61, 10, 23, 54, 18, 12, 24, 2, 14, 55, 16, 8, 38, 14, 41, 60, 10, 23, 1, 58, 32, 17, 28, 37, 41, 15, 3, 60, 15, 33, 4, 36, 16, 59, 28, 14, 23, 55, 37, 18, 44, 28, 2, 57, 30, 10, 27, 46, 14, 38, 3, 53, 21, 61, 17, 35, 10, 41, 26, 7, 33, 9, 57, 1, 53, 37, 26, 20, 56, 48, 9, 33, 58, 16, 37, 7, 45, 1, 57, 15, 32, 26, 42, 23, 7, 20, 4, 54, 31, 62, 22, 1, 59, 30, 4, 51 },
+  { 36, 2, 38, 11, 24, 36, 54, 22, 62, 47, 25, 8, 28, 45, 16, 38, 12, 43, 9, 37, 49, 3, 23, 52, 18, 30, 50, 33, 19, 42, 49, 26, 6, 40, 47, 35, 63, 38, 50, 33, 60, 26, 36, 47, 24, 57, 6, 26, 39, 63, 19, 44, 14, 46, 61, 9, 50, 30, 45, 23, 10, 50, 44, 8, 31, 54, 6, 46, 36, 4, 30, 54, 8, 52, 22, 41, 4, 60, 40, 0, 58, 24, 45, 10, 37, 1, 48, 30, 56, 17, 38, 48, 24, 47, 19, 39, 14, 8, 45, 32, 2, 34, 27, 44, 4, 52, 11, 56, 31, 21, 40, 19, 44, 51, 2, 63, 46, 58, 36, 43, 14, 5, 50, 38, 14, 56, 40, 23 },
+  { 61, 46, 32, 63, 54, 1, 14, 34, 12, 40, 18, 49, 37, 10, 61, 30, 51, 24, 60, 7, 29, 40, 62, 11, 46, 58, 6, 56, 24, 10, 34, 52, 21, 59, 16, 3, 27, 5, 20, 46, 9, 40, 7, 62, 2, 30, 53, 15, 48, 10, 28, 35, 54, 6, 21, 34, 18, 55, 7, 40, 57, 19, 26, 60, 41, 13, 24, 51, 19, 61, 9, 25, 34, 15, 63, 11, 45, 17, 20, 47, 33, 8, 31, 62, 43, 26, 53, 7, 24, 59, 0, 13, 55, 4, 62, 27, 51, 31, 63, 15, 58, 7, 54, 14, 46, 22, 28, 43, 12, 63, 8, 54, 5, 17, 39, 33, 15, 10, 27, 17, 47, 34, 19, 45, 27, 12, 33, 17 },
+  { 5, 28, 21, 7, 17, 48, 42, 58, 23, 4, 63, 14, 55, 21, 34, 5, 19, 0, 45, 17, 52, 15, 25, 32, 0, 22, 40, 13, 45, 62, 18, 0, 43, 11, 33, 55, 30, 42, 57, 19, 51, 31, 22, 43, 18, 45, 34, 0, 43, 31, 56, 3, 23, 40, 59, 0, 44, 13, 48, 35, 2, 32, 46, 0, 21, 48, 35, 3, 40, 32, 43, 59, 0, 48, 33, 26, 53, 36, 55, 12, 51, 16, 55, 5, 18, 29, 11, 39, 51, 19, 45, 31, 42, 21, 35, 6, 22, 47, 10, 38, 23, 50, 20, 36, 0, 60, 38, 4, 50, 35, 48, 34, 24, 57, 9, 53, 28, 48, 61, 0, 56, 24, 53, 3, 63, 6, 42, 57 },
+  { 13, 53, 45, 40, 58, 27, 6, 16, 38, 51, 33, 30, 43, 2, 47, 56, 40, 50, 33, 57, 27, 5, 47, 42, 60, 36, 16, 54, 28, 4, 37, 57, 28, 51, 22, 8, 45, 14, 6, 39, 0, 54, 11, 59, 28, 12, 50, 21, 61, 13, 19, 38, 49, 11, 25, 37, 58, 29, 22, 63, 14, 56, 12, 53, 30, 63, 9, 57, 26, 12, 47, 16, 23, 39, 50, 6, 31, 2, 25, 6, 28, 41, 36, 22, 50, 57, 42, 3, 34, 8, 28, 61, 11, 50, 16, 54, 41, 0, 55, 43, 5, 29, 41, 63, 25, 16, 53, 18, 26, 10, 21, 0, 61, 30, 41, 22, 3, 38, 20, 39, 29, 8, 41, 16, 36, 52, 22, 19 },
+  { 55, 34, 0, 25, 10, 32, 56, 44, 28, 0, 57, 7, 26, 53, 23, 8, 13, 35, 22, 12, 36, 60, 20, 8, 14, 29, 48, 2, 41, 49, 23, 13, 39, 7, 48, 58, 25, 53, 34, 62, 28, 16, 48, 4, 37, 56, 27, 5, 36, 52, 46, 7, 62, 33, 52, 11, 17, 53, 5, 28, 41, 24, 38, 17, 5, 39, 20, 45, 15, 56, 5, 38, 60, 8, 14, 57, 21, 48, 62, 39, 59, 13, 1, 60, 9, 32, 16, 63, 44, 25, 52, 15, 36, 2, 60, 29, 12, 33, 25, 17, 59, 45, 13, 8, 49, 32, 6, 40, 59, 29, 45, 37, 13, 47, 6, 55, 30, 45, 9, 52, 13, 59, 25, 47, 32, 1, 49, 30 },
+  { 9, 39, 14, 61, 49, 37, 3, 20, 50, 13, 41, 19, 46, 17, 38, 59, 28, 62, 4, 44, 54, 1, 34, 51, 55, 7, 63, 32, 21, 8, 56, 31, 62, 19, 36, 1, 41, 17, 24, 12, 42, 35, 25, 52, 20, 8, 44, 59, 25, 2, 22, 42, 16, 29, 4, 46, 20, 36, 43, 9, 51, 8, 49, 26, 58, 33, 54, 1, 37, 29, 52, 20, 27, 45, 19, 35, 42, 16, 10, 32, 20, 49, 46, 27, 40, 4, 47, 22, 13, 55, 4, 47, 26, 44, 23, 40, 58, 19, 48, 13, 31, 2, 57, 34, 42, 19, 61, 32, 14, 55, 5, 51, 26, 19, 58, 16, 49, 14, 62, 5, 33, 44, 21, 7, 60, 26, 11, 41 },
+  { 62, 24, 47, 29, 8, 19, 53, 11, 60, 24, 32, 61, 4, 55, 31, 2, 49, 16, 39, 9, 31, 24, 43, 17, 26, 38, 11, 25, 58, 43, 12, 35, 3, 46, 15, 32, 63, 4, 49, 56, 2, 60, 10, 32, 63, 17, 39, 12, 55, 30, 57, 9, 48, 55, 39, 24, 60, 2, 58, 31, 19, 61, 34, 3, 42, 11, 22, 46, 7, 61, 10, 42, 3, 55, 32, 1, 58, 28, 44, 54, 4, 34, 23, 15, 56, 20, 37, 58, 6, 30, 38, 18, 63, 9, 32, 5, 51, 3, 62, 37, 52, 18, 39, 23, 3, 51, 9, 47, 1, 23, 43, 15, 60, 35, 11, 40, 1, 36, 31, 26, 57, 2, 37, 54, 18, 44, 58, 16 },
+  { 5, 51, 3, 33, 43, 62, 21, 42, 35, 9, 48, 15, 36, 10, 22, 42, 20, 46, 26, 56, 50, 12, 59, 3, 48, 19, 45, 53, 1, 27, 47, 17, 52, 24, 56, 11, 51, 21, 37, 30, 20, 46, 14, 41, 1, 47, 33, 7, 41, 17, 35, 27, 20, 1, 14, 54, 26, 33, 18, 47, 1, 44, 14, 59, 16, 52, 28, 18, 49, 31, 25, 34, 63, 13, 51, 24, 9, 50, 3, 23, 38, 63, 7, 52, 29, 46, 11, 33, 50, 22, 57, 36, 1, 57, 49, 17, 39, 28, 9, 35, 6, 27, 53, 15, 55, 30, 24, 58, 36, 41, 11, 52, 32, 3, 44, 25, 62, 23, 51, 15, 42, 22, 50, 10, 39, 4, 31, 35 },
+  { 46, 22, 57, 17, 12, 39, 26, 5, 31, 59, 1, 45, 27, 62, 52, 7, 58, 33, 6, 18, 39, 22, 33, 41, 57, 5, 35, 18, 40, 16, 60, 5, 29, 42, 7, 39, 27, 44, 9, 47, 8, 26, 54, 22, 51, 29, 24, 49, 15, 61, 4, 51, 31, 63, 43, 6, 50, 8, 39, 12, 53, 37, 23, 30, 40, 6, 62, 43, 14, 53, 2, 49, 7, 36, 17, 41, 61, 37, 18, 56, 11, 18, 44, 35, 2, 19, 61, 0, 41, 14, 8, 30, 43, 12, 24, 46, 14, 54, 42, 21, 44, 61, 10, 46, 37, 11, 44, 7, 18, 63, 20, 29, 7, 49, 28, 54, 8, 43, 4, 48, 18, 63, 12, 29, 48, 24, 59, 20 },
+  { 13, 36, 28, 54, 35, 2, 56, 46, 16, 49, 22, 40, 11, 34, 14, 43, 29, 12, 63, 48, 2, 61, 7, 15, 28, 30, 50, 9, 61, 33, 38, 23, 54, 13, 61, 33, 3, 59, 16, 35, 58, 40, 5, 38, 13, 57, 3, 58, 37, 21, 45, 12, 39, 7, 35, 30, 13, 56, 22, 62, 27, 6, 55, 10, 48, 21, 33, 2, 38, 23, 40, 20, 44, 29, 59, 4, 26, 12, 33, 47, 28, 53, 31, 13, 59, 41, 27, 49, 26, 54, 45, 16, 53, 21, 35, 7, 59, 26, 11, 56, 1, 24, 33, 4, 28, 62, 21, 49, 31, 2, 56, 39, 24, 58, 13, 17, 37, 21, 56, 10, 38, 0, 34, 55, 15, 43, 1, 52 },
+  { 42, 9, 50, 6, 25, 60, 14, 38, 10, 29, 53, 18, 57, 3, 25, 51, 0, 53, 25, 17, 29, 37, 52, 46, 0, 62, 14, 37, 4, 50, 10, 44, 0, 46, 20, 25, 50, 19, 55, 0, 23, 31, 62, 34, 11, 45, 19, 32, 0, 53, 10, 59, 23, 47, 18, 60, 42, 28, 37, 3, 50, 15, 35, 44, 0, 51, 27, 60, 9, 57, 16, 58, 11, 22, 46, 15, 53, 48, 7, 42, 0, 60, 5, 49, 24, 54, 9, 17, 39, 5, 34, 62, 3, 40, 60, 31, 0, 47, 29, 16, 49, 39, 59, 17, 50, 0, 40, 13, 53, 38, 16, 46, 0, 42, 34, 60, 2, 53, 29, 31, 58, 46, 27, 6, 61, 8, 37, 28 },
+  { 0, 63, 21, 40, 45, 18, 51, 23, 63, 34, 6, 43, 28, 38, 55, 19, 40, 35, 8, 41, 54, 10, 21, 32, 39, 23, 53, 26, 55, 28, 22, 63, 30, 34, 9, 48, 6, 38, 29, 43, 49, 6, 18, 52, 27, 61, 9, 43, 28, 42, 33, 26, 56, 3, 51, 23, 0, 48, 16, 45, 32, 25, 63, 20, 57, 17, 42, 12, 35, 47, 5, 31, 39, 56, 6, 30, 34, 21, 61, 25, 14, 40, 22, 38, 15, 6, 36, 56, 20, 60, 25, 12, 51, 27, 10, 56, 42, 20, 36, 63, 32, 6, 21, 41, 12, 34, 60, 26, 5, 48, 27, 10, 62, 19, 6, 47, 39, 14, 45, 7, 24, 17, 41, 32, 23, 51, 19, 56 },
+  { 45, 31, 15, 59, 4, 33, 7, 47, 0, 41, 13, 61, 4, 47, 9, 23, 60, 14, 57, 31, 4, 45, 59, 6, 58, 10, 44, 20, 8, 42, 15, 6, 55, 17, 58, 31, 53, 12, 61, 10, 15, 57, 43, 2, 23, 35, 48, 14, 54, 6, 18, 49, 15, 38, 11, 34, 62, 9, 21, 58, 11, 41, 4, 31, 38, 8, 29, 55, 19, 36, 27, 52, 0, 25, 50, 43, 1, 39, 8, 55, 35, 51, 10, 30, 45, 62, 29, 2, 46, 10, 32, 48, 18, 38, 5, 22, 33, 8, 51, 3, 14, 44, 54, 25, 57, 30, 18, 52, 33, 22, 59, 28, 36, 52, 32, 21, 26, 50, 5, 55, 35, 60, 14, 54, 4, 40, 16, 33 },
+  { 27, 3, 49, 10, 30, 40, 55, 27, 57, 24, 52, 21, 32, 17, 60, 30, 5, 44, 27, 49, 19, 34, 13, 24, 43, 36, 3, 49, 31, 59, 37, 48, 26, 41, 2, 41, 14, 36, 21, 32, 40, 26, 13, 49, 55, 5, 16, 40, 25, 60, 36, 1, 63, 29, 17, 44, 25, 40, 52, 5, 29, 47, 54, 13, 46, 24, 60, 4, 51, 22, 63, 14, 45, 18, 12, 62, 17, 57, 19, 42, 3, 26, 58, 48, 1, 21, 40, 52, 23, 37, 44, 1, 29, 58, 43, 50, 15, 61, 19, 45, 58, 28, 7, 48, 2, 46, 8, 42, 3, 55, 8, 50, 12, 4, 55, 10, 63, 33, 20, 40, 11, 3, 46, 20, 48, 26, 61, 11 },
+  { 44, 56, 24, 36, 53, 19, 12, 37, 16, 44, 7, 36, 49, 54, 11, 37, 48, 21, 15, 1, 62, 25, 47, 56, 16, 18, 51, 12, 40, 1, 24, 11, 52, 16, 23, 59, 28, 1, 45, 53, 4, 60, 37, 21, 39, 30, 63, 20, 52, 10, 30, 45, 8, 41, 54, 4, 57, 7, 34, 55, 36, 18, 23, 59, 2, 48, 11, 32, 44, 1, 41, 8, 33, 54, 38, 23, 30, 46, 6, 29, 62, 18, 32, 16, 55, 34, 14, 11, 61, 7, 55, 16, 53, 13, 23, 2, 55, 37, 26, 10, 33, 23, 36, 16, 38, 22, 56, 15, 24, 43, 35, 17, 44, 40, 25, 46, 16, 1, 57, 25, 49, 36, 28, 62, 9, 35, 7, 53 },
+  { 17, 38, 8, 61, 1, 50, 26, 62, 3, 31, 56, 15, 1, 26, 40, 2, 34, 51, 56, 36, 42, 9, 38, 2, 29, 60, 32, 57, 19, 62, 34, 47, 4, 57, 39, 7, 44, 63, 24, 18, 46, 28, 8, 54, 1, 34, 7, 46, 3, 37, 50, 23, 57, 21, 13, 46, 31, 20, 43, 15, 1, 61, 8, 33, 37, 17, 56, 26, 15, 49, 24, 59, 28, 3, 56, 9, 52, 32, 13, 49, 10, 43, 5, 45, 8, 25, 59, 42, 28, 33, 19, 40, 8, 63, 35, 47, 25, 4, 40, 52, 1, 60, 12, 53, 63, 9, 29, 60, 37, 19, 1, 62, 31, 20, 58, 12, 41, 30, 43, 9, 18, 52, 22, 1, 39, 30, 58, 21 },
+  { 13, 47, 29, 18, 43, 34, 5, 48, 20, 42, 10, 45, 30, 58, 20, 63, 24, 11, 6, 28, 54, 14, 22, 52, 41, 7, 26, 5, 45, 15, 53, 13, 35, 27, 18, 50, 12, 33, 5, 56, 10, 17, 45, 24, 59, 15, 50, 26, 56, 13, 19, 5, 32, 52, 27, 36, 2, 61, 12, 26, 49, 40, 27, 52, 13, 50, 6, 39, 61, 34, 10, 37, 48, 20, 41, 27, 2, 36, 59, 24, 54, 33, 63, 20, 38, 50, 3, 17, 52, 4, 58, 27, 45, 21, 32, 11, 48, 17, 57, 20, 46, 38, 25, 43, 4, 34, 51, 6, 13, 45, 57, 26, 6, 48, 2, 35, 53, 23, 61, 34, 59, 6, 42, 56, 13, 51, 2, 41 },
+  { 32, 5, 55, 23, 58, 14, 22, 52, 29, 15, 61, 25, 51, 8, 43, 13, 53, 41, 46, 20, 3, 33, 63, 11, 48, 21, 54, 38, 28, 3, 30, 43, 21, 62, 9, 31, 55, 22, 51, 29, 37, 62, 32, 12, 42, 29, 41, 9, 33, 44, 62, 28, 43, 1, 59, 19, 48, 30, 51, 39, 24, 4, 58, 19, 42, 29, 22, 43, 3, 18, 53, 5, 13, 50, 16, 60, 45, 21, 7, 40, 15, 0, 26, 53, 13, 31, 43, 24, 47, 31, 15, 49, 2, 41, 6, 59, 29, 42, 9, 30, 14, 7, 49, 18, 31, 47, 20, 39, 49, 32, 11, 41, 54, 15, 61, 18, 7, 38, 4, 13, 44, 28, 15, 32, 45, 19, 27, 49 },
+  { 63, 34, 11, 39, 2, 45, 37, 8, 59, 39, 33, 4, 36, 17, 48, 5, 29, 18, 32, 61, 39, 50, 5, 27, 35, 0, 46, 12, 22, 49, 60, 6, 54, 0, 38, 49, 2, 42, 15, 40, 0, 47, 20, 51, 3, 57, 18, 61, 22, 0, 39, 16, 55, 12, 35, 8, 41, 22, 6, 59, 16, 45, 10, 36, 0, 62, 9, 54, 30, 58, 21, 43, 63, 31, 7, 35, 12, 48, 58, 28, 47, 37, 41, 9, 57, 20, 61, 0, 36, 11, 57, 35, 23, 52, 37, 18, 0, 62, 22, 55, 35, 62, 27, 54, 0, 15, 61, 28, 2, 59, 22, 9, 37, 27, 33, 51, 29, 48, 19, 50, 25, 37, 10, 57, 5, 37, 60, 8 },
+  { 20, 25, 46, 52, 31, 60, 12, 55, 0, 19, 11, 46, 62, 35, 23, 38, 57, 0, 55, 10, 16, 30, 58, 44, 17, 59, 29, 63, 42, 8, 36, 20, 33, 46, 16, 61, 25, 35, 8, 54, 26, 7, 58, 22, 34, 6, 47, 14, 53, 31, 48, 9, 37, 25, 49, 63, 16, 55, 45, 14, 34, 63, 21, 53, 25, 33, 46, 16, 35, 7, 46, 29, 0, 39, 25, 55, 22, 34, 18, 4, 56, 11, 23, 51, 28, 6, 39, 14, 62, 44, 19, 8, 60, 12, 56, 28, 50, 34, 39, 5, 51, 3, 41, 12, 57, 35, 10, 53, 25, 17, 52, 30, 47, 0, 43, 14, 5, 57, 31, 55, 0, 63, 47, 23, 54, 24, 14, 43 },
+  { 0, 57, 16, 6, 26, 19, 35, 28, 49, 42, 54, 26, 21, 1, 59, 27, 9, 47, 26, 44, 50, 22, 13, 40, 8, 37, 10, 34, 17, 56, 25, 58, 13, 27, 44, 9, 20, 58, 31, 17, 60, 36, 10, 41, 53, 25, 36, 39, 4, 24, 58, 17, 60, 4, 22, 38, 10, 32, 0, 50, 31, 7, 28, 47, 12, 57, 5, 26, 52, 23, 14, 40, 57, 17, 47, 5, 53, 1, 44, 31, 19, 60, 46, 2, 35, 48, 30, 54, 22, 5, 51, 39, 25, 31, 4, 43, 14, 9, 45, 16, 24, 44, 19, 29, 40, 23, 44, 7, 38, 42, 4, 63, 12, 54, 23, 59, 22, 42, 8, 15, 40, 21, 8, 34, 3, 41, 30, 50 },
+  { 39, 10, 48, 33, 41, 54, 5, 47, 23, 13, 32, 7, 52, 44, 14, 39, 58, 18, 35, 6, 37, 2, 60, 24, 55, 19, 53, 2, 51, 32, 1, 41, 51, 4, 40, 29, 47, 3, 52, 44, 13, 49, 28, 16, 1, 62, 11, 27, 52, 35, 5, 42, 29, 47, 14, 56, 28, 53, 26, 38, 9, 56, 40, 3, 38, 15, 41, 60, 1, 37, 50, 25, 11, 28, 61, 19, 42, 62, 10, 52, 39, 6, 32, 14, 58, 17, 7, 26, 42, 34, 27, 10, 54, 40, 20, 63, 26, 53, 21, 61, 32, 7, 59, 48, 3, 56, 18, 31, 58, 14, 49, 21, 36, 16, 45, 9, 36, 24, 62, 45, 27, 31, 53, 17, 49, 12, 62, 18 },
+  { 28, 59, 21, 58, 2, 16, 38, 9, 62, 3, 56, 41, 10, 31, 50, 4, 32, 52, 12, 63, 23, 46, 33, 31, 4, 48, 25, 43, 14, 23, 47, 11, 22, 55, 14, 60, 23, 37, 11, 39, 23, 2, 45, 56, 31, 43, 19, 55, 16, 46, 21, 51, 11, 33, 44, 2, 41, 18, 5, 52, 23, 44, 17, 60, 27, 49, 11, 32, 44, 10, 54, 2, 56, 33, 8, 38, 13, 29, 36, 16, 24, 63, 27, 51, 21, 43, 56, 12, 49, 3, 59, 48, 1, 15, 46, 7, 36, 2, 47, 11, 50, 27, 37, 13, 33, 8, 51, 46, 1, 34, 28, 40, 3, 33, 60, 29, 47, 1, 35, 11, 59, 42, 2, 60, 26, 46, 6, 35 },
+  { 4, 43, 9, 29, 36, 63, 24, 44, 20, 50, 30, 17, 60, 22, 16, 43, 25, 3, 42, 19, 51, 15, 8, 54, 42, 15, 61, 5, 39, 57, 18, 61, 31, 48, 34, 2, 50, 19, 57, 5, 63, 33, 19, 38, 13, 27, 48, 7, 32, 61, 2, 26, 58, 6, 24, 50, 13, 61, 42, 20, 62, 2, 35, 20, 51, 4, 62, 18, 23, 58, 20, 31, 43, 15, 51, 45, 26, 50, 4, 55, 45, 3, 35, 9, 38, 1, 32, 61, 20, 45, 17, 33, 24, 57, 29, 51, 22, 58, 38, 30, 15, 1, 54, 21, 63, 43, 26, 12, 24, 56, 8, 60, 50, 19, 5, 52, 13, 54, 17, 50, 4, 16, 36, 12, 32, 56, 22, 54 },
+  { 51, 25, 40, 53, 12, 49, 15, 57, 34, 7, 38, 47, 2, 36, 55, 8, 61, 30, 56, 7, 28, 59, 48, 11, 27, 35, 21, 45, 28, 36, 9, 38, 6, 16, 24, 63, 10, 32, 28, 43, 21, 53, 5, 60, 8, 57, 3, 45, 11, 37, 15, 54, 40, 20, 62, 36, 27, 34, 11, 48, 30, 15, 54, 8, 30, 42, 22, 34, 48, 13, 35, 63, 4, 37, 22, 2, 59, 9, 41, 23, 13, 41, 49, 18, 59, 24, 40, 5, 37, 30, 9, 61, 44, 6, 37, 11, 33, 17, 5, 55, 41, 60, 23, 39, 17, 5, 30, 62, 41, 16, 46, 25, 11, 56, 39, 26, 20, 38, 29, 39, 22, 52, 44, 20, 48, 1, 38, 14 },
+  { 15, 33, 2, 18, 44, 6, 27, 0, 32, 61, 25, 12, 58, 28, 40, 20, 47, 13, 34, 43, 38, 1, 23, 62, 40, 0, 51, 10, 63, 3, 52, 26, 44, 30, 45, 6, 41, 54, 0, 51, 12, 30, 46, 24, 49, 22, 40, 33, 63, 23, 43, 30, 9, 47, 0, 17, 54, 7, 57, 3, 37, 47, 24, 46, 13, 55, 7, 52, 2, 42, 6, 26, 49, 18, 60, 34, 16, 57, 33, 20, 61, 30, 8, 54, 14, 46, 12, 53, 16, 55, 38, 13, 22, 53, 18, 59, 46, 27, 43, 19, 32, 10, 45, 6, 49, 36, 52, 2, 20, 55, 6, 39, 32, 15, 44, 3, 58, 10, 63, 6, 56, 30, 7, 58, 9, 40, 19, 63 },
+  { 10, 47, 61, 23, 55, 31, 52, 42, 17, 45, 4, 51, 27, 6, 15, 53, 0, 49, 26, 10, 56, 18, 36, 6, 20, 58, 32, 30, 13, 49, 19, 56, 0, 59, 12, 53, 27, 17, 38, 25, 48, 9, 15, 36, 14, 30, 59, 17, 0, 50, 8, 58, 18, 56, 31, 45, 21, 41, 29, 19, 60, 6, 32, 59, 0, 36, 29, 39, 19, 59, 46, 12, 55, 30, 10, 47, 24, 3, 28, 48, 0, 55, 44, 27, 33, 4, 63, 29, 49, 0, 26, 50, 34, 2, 42, 14, 0, 62, 9, 56, 3, 52, 28, 34, 58, 9, 20, 48, 37, 32, 22, 53, 0, 62, 27, 49, 34, 46, 21, 33, 41, 14, 25, 37, 53, 29, 31, 45 },
+  { 56, 28, 7, 37, 11, 36, 20, 9, 54, 14, 39, 19, 34, 63, 45, 37, 24, 17, 60, 31, 21, 45, 53, 29, 47, 15, 7, 55, 40, 23, 34, 14, 42, 20, 37, 35, 15, 59, 7, 62, 34, 40, 59, 1, 51, 42, 10, 28, 54, 21, 35, 5, 38, 13, 36, 4, 59, 12, 39, 53, 15, 43, 9, 21, 39, 62, 16, 56, 25, 9, 32, 38, 0, 41, 14, 51, 40, 53, 43, 11, 37, 17, 5, 22, 57, 39, 19, 7, 42, 21, 60, 10, 31, 63, 25, 52, 30, 49, 36, 25, 48, 17, 61, 14, 22, 42, 29, 13, 60, 11, 47, 18, 35, 41, 7, 23, 4, 16, 51, 11, 0, 48, 61, 3, 17, 50, 5, 24 },
+  { 0, 42, 21, 49, 60, 3, 57, 40, 29, 48, 23, 56, 42, 11, 22, 5, 59, 39, 4, 50, 3, 41, 12, 57, 25, 50, 44, 18, 4, 46, 7, 62, 33, 50, 4, 56, 21, 32, 43, 18, 3, 23, 55, 34, 20, 4, 53, 38, 12, 46, 29, 52, 25, 61, 23, 51, 26, 46, 1, 34, 25, 57, 28, 51, 26, 11, 50, 3, 44, 28, 53, 21, 57, 27, 62, 6, 31, 19, 8, 63, 26, 59, 36, 47, 15, 29, 50, 25, 35, 47, 18, 41, 4, 48, 8, 40, 12, 23, 6, 44, 13, 40, 1, 31, 55, 0, 61, 43, 4, 50, 26, 58, 9, 53, 24, 61, 42, 55, 31, 43, 57, 20, 34, 27, 43, 8, 59, 39 },
+  { 18, 51, 30, 13, 26, 16, 46, 22, 2, 59, 8, 30, 1, 48, 33, 51, 29, 9, 46, 16, 62, 14, 33, 2, 38, 9, 27, 60, 37, 26, 53, 17, 28, 10, 24, 46, 2, 49, 8, 57, 29, 45, 6, 26, 62, 44, 18, 25, 61, 3, 42, 14, 49, 10, 43, 6, 17, 32, 63, 10, 49, 4, 40, 14, 45, 33, 22, 37, 12, 61, 5, 17, 43, 7, 23, 37, 15, 58, 49, 13, 39, 21, 10, 52, 1, 62, 9, 56, 12, 2, 58, 28, 36, 16, 56, 28, 56, 35, 20, 63, 24, 37, 51, 8, 45, 25, 16, 33, 27, 38, 2, 44, 13, 30, 17, 36, 12, 26, 5, 18, 28, 47, 13, 60, 23, 45, 13, 33 },
+  { 55, 4, 62, 34, 52, 38, 7, 63, 32, 37, 13, 53, 25, 62, 18, 12, 55, 41, 27, 35, 24, 49, 31, 52, 17, 63, 34, 1, 56, 12, 41, 2, 48, 58, 39, 16, 61, 27, 41, 52, 13, 19, 50, 39, 11, 31, 57, 6, 32, 40, 20, 55, 1, 28, 33, 57, 48, 8, 37, 22, 44, 18, 53, 1, 61, 5, 54, 16, 47, 36, 50, 24, 55, 34, 48, 45, 1, 30, 33, 46, 2, 50, 32, 42, 25, 34, 43, 21, 38, 52, 23, 45, 14, 54, 21, 4, 44, 16, 53, 29, 10, 47, 19, 57, 12, 54, 39, 10, 51, 15, 63, 21, 57, 40, 51, 1, 48, 57, 37, 62, 2, 38, 9, 52, 1, 35, 58, 22 },
+  { 36, 46, 10, 42, 1, 27, 43, 15, 50, 21, 45, 16, 41, 3, 35, 44, 20, 1, 57, 11, 55, 7, 43, 8, 22, 42, 13, 46, 21, 39, 31, 60, 22, 5, 29, 44, 11, 35, 20, 4, 36, 58, 32, 15, 47, 2, 36, 48, 16, 60, 8, 35, 44, 63, 16, 2, 40, 26, 55, 14, 58, 35, 24, 31, 19, 42, 31, 58, 1, 29, 10, 40, 2, 19, 12, 54, 22, 61, 7, 24, 56, 5, 28, 16, 54, 3, 15, 58, 6, 30, 8, 62, 1, 43, 31, 47, 7, 59, 1, 38, 58, 4, 34, 27, 38, 5, 31, 59, 7, 46, 30, 3, 34, 6, 28, 59, 20, 8, 32, 15, 53, 24, 55, 31, 19, 49, 11, 26 },
+  { 2, 24, 16, 58, 19, 55, 5, 35, 10, 61, 4, 28, 57, 24, 58, 7, 31, 47, 22, 38, 19, 28, 61, 36, 54, 5, 59, 29, 6, 52, 15, 11, 43, 36, 8, 54, 52, 1, 62, 25, 47, 9, 1, 60, 28, 53, 24, 14, 46, 27, 51, 22, 12, 24, 38, 53, 20, 11, 51, 3, 29, 7, 48, 63, 8, 49, 9, 21, 52, 14, 63, 32, 46, 60, 35, 4, 41, 16, 52, 35, 18, 42, 59, 7, 36, 61, 45, 27, 33, 51, 19, 39, 34, 11, 61, 18, 33, 41, 28, 15, 54, 22, 42, 3, 49, 21, 47, 18, 36, 23, 55, 19, 48, 24, 45, 10, 33, 44, 50, 40, 7, 35, 15, 41, 63, 6, 40, 54 },
+  { 62, 41, 32, 8, 47, 28, 60, 24, 44, 30, 38, 49, 9, 33, 14, 40, 50, 14, 60, 2, 54, 40, 0, 20, 25, 39, 16, 49, 24, 35, 57, 47, 19, 61, 33, 18, 23, 37, 13, 55, 31, 43, 22, 41, 17, 8, 42, 58, 0, 37, 5, 56, 31, 54, 7, 30, 60, 33, 42, 17, 59, 39, 12, 27, 38, 17, 35, 41, 27, 45, 20, 7, 25, 15, 29, 58, 27, 47, 11, 40, 14, 54, 23, 46, 19, 31, 11, 40, 13, 49, 5, 58, 24, 51, 26, 6, 50, 20, 49, 9, 32, 46, 17, 60, 14, 63, 24, 1, 57, 41, 9, 43, 14, 62, 16, 52, 3, 27, 14, 22, 61, 45, 4, 28, 9, 47, 29, 17 },
+  { 5, 50, 12, 53, 38, 18, 11, 51, 0, 55, 17, 6, 47, 54, 19, 63, 5, 26, 34, 45, 13, 30, 47, 58, 10, 48, 32, 3, 62, 9, 26, 0, 25, 14, 50, 3, 47, 30, 42, 16, 6, 63, 12, 49, 33, 55, 21, 10, 34, 63, 18, 41, 3, 47, 19, 43, 0, 49, 8, 28, 46, 20, 52, 0, 56, 24, 60, 3, 59, 5, 39, 57, 48, 52, 9, 38, 3, 21, 26, 60, 0, 32, 12, 38, 4, 48, 53, 0, 60, 15, 29, 44, 18, 10, 38, 57, 13, 60, 2, 26, 62, 7, 50, 29, 35, 8, 40, 53, 28, 12, 60, 33, 38, 5, 37, 29, 60, 39, 56, 0, 30, 18, 50, 34, 59, 25, 14, 44 },
+  { 20, 31, 60, 22, 3, 49, 33, 25, 40, 13, 34, 59, 22, 36, 0, 28, 37, 56, 8, 18, 51, 16, 4, 45, 27, 12, 53, 42, 18, 44, 51, 31, 55, 40, 28, 58, 7, 60, 10, 51, 27, 37, 24, 56, 5, 26, 44, 29, 50, 23, 45, 11, 34, 15, 59, 27, 13, 23, 62, 37, 4, 57, 15, 32, 42, 6, 47, 11, 30, 43, 23, 13, 0, 36, 18, 44, 63, 51, 37, 29, 49, 20, 57, 27, 62, 9, 24, 35, 23, 53, 37, 3, 42, 55, 0, 36, 23, 39, 31, 43, 17, 37, 24, 11, 52, 43, 19, 32, 5, 50, 26, 0, 56, 21, 54, 11, 19, 6, 47, 25, 59, 42, 12, 54, 21, 3, 38, 57 },
+  { 48, 0, 35, 27, 44, 14, 59, 7, 57, 46, 26, 2, 42, 12, 52, 43, 10, 27, 53, 42, 32, 62, 37, 21, 34, 61, 7, 23, 36, 4, 38, 12, 41, 5, 17, 45, 22, 27, 39, 21, 59, 0, 45, 18, 39, 62, 3, 38, 14, 7, 54, 26, 61, 39, 9, 52, 45, 36, 18, 50, 10, 34, 44, 22, 50, 14, 36, 55, 17, 34, 53, 62, 33, 26, 56, 6, 31, 12, 6, 53, 9, 44, 2, 50, 20, 40, 55, 17, 47, 7, 26, 63, 22, 32, 48, 16, 46, 8, 52, 12, 57, 41, 0, 56, 25, 3, 61, 14, 45, 35, 18, 44, 12, 46, 23, 42, 32, 51, 35, 10, 17, 36, 23, 1, 45, 52, 32, 10 },
+  { 37, 15, 43, 8, 63, 39, 21, 31, 16, 37, 19, 62, 30, 46, 17, 60, 21, 48, 1, 23, 6, 25, 11, 56, 1, 40, 30, 58, 15, 54, 21, 59, 9, 63, 35, 56, 11, 51, 2, 46, 34, 14, 53, 7, 30, 11, 51, 19, 60, 40, 30, 1, 24, 50, 20, 32, 3, 56, 5, 25, 31, 13, 61, 2, 29, 60, 25, 20, 51, 2, 27, 8, 18, 42, 10, 45, 21, 34, 43, 17, 62, 29, 41, 14, 34, 6, 30, 43, 2, 57, 33, 13, 45, 12, 27, 62, 4, 55, 21, 35, 5, 27, 45, 33, 16, 47, 30, 54, 22, 10, 51, 27, 63, 7, 49, 1, 58, 22, 15, 43, 53, 7, 57, 39, 27, 12, 61, 24 },
+  { 56, 51, 26, 56, 19, 2, 41, 54, 5, 52, 9, 48, 6, 23, 39, 4, 32, 15, 63, 35, 59, 49, 43, 15, 52, 19, 50, 9, 46, 33, 1, 29, 48, 20, 32, 1, 38, 33, 19, 54, 9, 32, 24, 48, 58, 35, 16, 48, 4, 52, 13, 57, 33, 5, 45, 59, 15, 29, 41, 55, 47, 39, 23, 53, 9, 40, 4, 57, 10, 44, 48, 40, 50, 14, 61, 24, 55, 1, 59, 22, 33, 8, 51, 25, 58, 46, 11, 59, 20, 41, 17, 51, 6, 56, 35, 25, 42, 30, 15, 58, 48, 18, 61, 9, 58, 39, 13, 2, 37, 59, 40, 2, 31, 16, 34, 41, 8, 30, 62, 3, 29, 48, 33, 5, 63, 16, 41, 7 },
+  { 22, 4, 46, 11, 33, 51, 29, 10, 62, 24, 43, 27, 15, 58, 50, 25, 54, 44, 9, 38, 18, 3, 29, 57, 32, 5, 26, 43, 17, 61, 24, 52, 8, 42, 23, 53, 15, 61, 7, 28, 57, 43, 4, 40, 20, 2, 43, 25, 32, 35, 21, 43, 17, 48, 10, 22, 38, 54, 11, 21, 1, 58, 16, 30, 48, 18, 46, 32, 38, 13, 22, 4, 59, 35, 2, 51, 30, 39, 15, 47, 4, 56, 13, 37, 1, 28, 16, 52, 32, 9, 61, 29, 38, 19, 3, 52, 10, 48, 1, 32, 11, 40, 20, 36, 6, 22, 49, 29, 55, 6, 20, 56, 36, 52, 19, 60, 26, 46, 18, 54, 40, 13, 20, 46, 35, 19, 49, 29 },
+  { 61, 17, 34, 53, 23, 6, 48, 35, 20, 40, 1, 56, 36, 29, 11, 34, 7, 41, 14, 30, 55, 20, 46, 8, 24, 38, 63, 2, 37, 10, 45, 14, 34, 49, 6, 13, 44, 25, 49, 41, 21, 12, 61, 15, 54, 29, 63, 12, 56, 8, 49, 2, 62, 36, 28, 61, 0, 25, 41, 63, 35, 8, 44, 6, 37, 62, 7, 21, 63, 28, 55, 31, 16, 24, 41, 19, 9, 57, 27, 36, 18, 42, 31, 62, 22, 55, 38, 4, 27, 47, 1, 40, 14, 54, 43, 20, 60, 23, 38, 63, 25, 51, 2, 53, 26, 63, 10, 42, 17, 34, 47, 25, 13, 5, 44, 11, 55, 2, 38, 27, 6, 60, 52, 25, 9, 55, 1, 40 },
+  { 8, 30, 58, 3, 42, 61, 17, 38, 13, 59, 32, 10, 54, 3, 51, 20, 61, 26, 57, 2, 46, 33, 12, 60, 41, 13, 48, 29, 55, 20, 39, 27, 57, 18, 62, 29, 55, 2, 31, 16, 37, 50, 26, 36, 6, 46, 9, 41, 27, 57, 23, 39, 26, 6, 51, 12, 31, 46, 7, 16, 27, 52, 19, 56, 26, 12, 33, 53, 1, 41, 8, 57, 46, 7, 54, 32, 47, 5, 49, 11, 60, 23, 5, 48, 10, 43, 19, 63, 35, 24, 49, 21, 59, 5, 31, 37, 14, 44, 7, 42, 6, 30, 46, 13, 44, 32, 19, 50, 4, 58, 8, 30, 62, 38, 28, 53, 21, 36, 13, 50, 21, 33, 15, 2, 44, 31, 14, 47 },
+  { 37, 13, 39, 16, 28, 9, 57, 0, 25, 49, 21, 45, 18, 47, 12, 42, 0, 49, 22, 39, 16, 53, 25, 36, 0, 52, 22, 16, 6, 60, 4, 51, 0, 26, 37, 47, 10, 36, 63, 5, 57, 0, 18, 59, 23, 33, 51, 19, 0, 44, 15, 11, 54, 17, 42, 35, 53, 18, 58, 33, 49, 4, 34, 42, 0, 50, 43, 25, 16, 49, 34, 20, 37, 28, 12, 63, 16, 38, 25, 44, 0, 40, 52, 17, 35, 3, 50, 14, 8, 53, 11, 36, 25, 45, 9, 62, 0, 54, 28, 17, 50, 55, 15, 24, 57, 0, 53, 34, 23, 41, 15, 45, 0, 49, 16, 4, 48, 9, 63, 45, 0, 42, 58, 37, 61, 22, 54, 26 },
+  { 0, 50, 21, 47, 54, 36, 27, 45, 52, 4, 34, 15, 63, 29, 37, 59, 17, 31, 6, 61, 28, 5, 48, 18, 59, 27, 34, 56, 44, 31, 35, 12, 41, 59, 16, 3, 40, 20, 50, 22, 30, 40, 52, 10, 45, 3, 59, 22, 37, 61, 29, 46, 31, 58, 2, 22, 9, 43, 3, 39, 14, 61, 24, 54, 15, 29, 11, 60, 39, 17, 5, 61, 0, 44, 50, 3, 31, 14, 58, 21, 54, 28, 15, 45, 60, 26, 33, 58, 44, 22, 60, 2, 57, 34, 49, 27, 18, 34, 21, 59, 29, 4, 36, 41, 8, 39, 28, 11, 62, 26, 53, 20, 35, 24, 59, 32, 29, 39, 24, 31, 57, 23, 11, 28, 5, 36, 11, 59 },
+  { 44, 32, 63, 5, 20, 12, 41, 7, 30, 61, 42, 8, 39, 5, 33, 8, 24, 53, 45, 11, 37, 58, 7, 44, 10, 50, 3, 40, 8, 22, 53, 19, 46, 9, 33, 52, 24, 58, 8, 44, 13, 47, 8, 34, 38, 30, 14, 47, 7, 34, 4, 55, 9, 19, 40, 49, 56, 26, 60, 21, 30, 45, 10, 19, 40, 58, 23, 36, 3, 52, 45, 23, 54, 13, 22, 42, 53, 45, 7, 33, 10, 36, 57, 6, 29, 12, 41, 0, 30, 15, 41, 30, 17, 7, 16, 53, 40, 56, 2, 39, 12, 61, 10, 52, 31, 60, 16, 45, 1, 37, 7, 61, 40, 10, 43, 17, 58, 7, 54, 14, 4, 51, 39, 49, 18, 56, 42, 20 },
+  { 14, 6, 24, 36, 56, 49, 22, 60, 18, 14, 23, 51, 26, 57, 21, 52, 41, 14, 35, 50, 19, 31, 40, 23, 33, 14, 63, 17, 32, 47, 7, 62, 23, 30, 56, 11, 42, 27, 14, 60, 35, 19, 28, 61, 17, 55, 25, 39, 53, 17, 42, 21, 38, 63, 25, 5, 14, 36, 12, 50, 1, 37, 59, 32, 2, 51, 6, 56, 27, 32, 11, 30, 38, 26, 60, 8, 26, 19, 62, 39, 50, 2, 21, 39, 53, 23, 56, 19, 49, 39, 5, 46, 55, 23, 42, 4, 31, 11, 47, 26, 45, 22, 48, 18, 21, 5, 48, 25, 57, 14, 47, 30, 3, 56, 12, 50, 1, 42, 19, 47, 35, 17, 8, 30, 45, 25, 4, 51 },
+  { 28, 58, 43, 1, 31, 8, 33, 2, 44, 55, 32, 1, 60, 12, 46, 27, 4, 62, 23, 1, 56, 13, 62, 2, 54, 36, 25, 51, 1, 57, 26, 42, 3, 49, 17, 38, 1, 48, 31, 4, 54, 3, 50, 24, 1, 49, 5, 63, 13, 27, 52, 1, 48, 13, 45, 33, 52, 30, 46, 20, 55, 28, 6, 48, 24, 38, 20, 47, 14, 62, 48, 9, 58, 4, 36, 30, 56, 1, 34, 12, 18, 63, 25, 48, 4, 16, 37, 7, 62, 10, 52, 28, 13, 50, 36, 63, 24, 51, 15, 58, 8, 33, 1, 38, 56, 35, 42, 9, 33, 51, 22, 18, 48, 32, 27, 37, 23, 61, 33, 11, 59, 29, 62, 1, 53, 10, 60, 33 },
+  { 12, 39, 17, 52, 26, 46, 53, 38, 25, 11, 48, 36, 16, 43, 2, 35, 55, 17, 39, 29, 43, 9, 28, 45, 20, 5, 46, 12, 42, 28, 13, 52, 36, 6, 60, 22, 54, 17, 62, 39, 25, 42, 15, 55, 44, 20, 31, 10, 35, 57, 24, 32, 29, 6, 59, 18, 7, 62, 3, 41, 10, 44, 16, 54, 13, 62, 31, 9, 41, 1, 21, 43, 18, 47, 15, 40, 11, 49, 28, 55, 46, 30, 8, 43, 32, 61, 28, 47, 25, 34, 21, 61, 32, 1, 20, 9, 46, 6, 35, 19, 41, 54, 27, 63, 14, 3, 51, 20, 62, 2, 38, 55, 8, 21, 63, 6, 46, 9, 26, 51, 3, 24, 43, 34, 16, 41, 18, 48 },
+  { 62, 23, 55, 9, 15, 62, 19, 13, 58, 40, 6, 30, 54, 19, 50, 31, 10, 44, 6, 59, 21, 47, 51, 15, 60, 39, 30, 54, 21, 61, 19, 33, 14, 29, 43, 11, 34, 45, 7, 21, 10, 56, 36, 6, 38, 11, 58, 42, 2, 47, 11, 60, 50, 16, 41, 28, 38, 23, 47, 17, 35, 63, 22, 33, 42, 5, 45, 17, 53, 35, 25, 56, 33, 6, 51, 19, 60, 23, 43, 15, 5, 40, 58, 13, 51, 1, 45, 11, 54, 3, 43, 8, 37, 48, 59, 29, 39, 21, 61, 43, 3, 31, 10, 44, 24, 29, 60, 12, 28, 40, 11, 25, 43, 52, 14, 41, 16, 57, 44, 20, 40, 55, 12, 21, 57, 27, 35, 2 },
+  { 37, 6, 31, 42, 40, 4, 29, 50, 0, 20, 63, 28, 9, 58, 14, 24, 63, 26, 48, 16, 34, 4, 32, 38, 23, 11, 58, 4, 37, 9, 45, 5, 63, 48, 26, 57, 2, 28, 32, 51, 46, 29, 13, 62, 27, 46, 28, 18, 50, 15, 40, 4, 19, 34, 54, 0, 53, 9, 26, 58, 28, 5, 49, 0, 57, 27, 19, 60, 29, 8, 59, 12, 37, 63, 24, 46, 3, 37, 6, 52, 26, 32, 20, 36, 9, 22, 59, 18, 35, 51, 14, 57, 17, 24, 12, 44, 56, 0, 30, 13, 59, 20, 49, 17, 54, 43, 6, 34, 46, 17, 58, 36, 0, 34, 29, 54, 25, 2, 36, 15, 60, 6, 37, 46, 4, 50, 9, 45 },
+  { 19, 59, 48, 3, 24, 60, 44, 22, 34, 51, 15, 45, 41, 5, 33, 47, 0, 37, 12, 55, 25, 54, 8, 57, 0, 47, 18, 34, 49, 15, 55, 24, 40, 20, 8, 35, 53, 13, 41, 18, 0, 59, 22, 33, 4, 52, 8, 60, 24, 36, 31, 56, 45, 26, 10, 43, 15, 56, 36, 4, 51, 14, 39, 30, 12, 55, 36, 2, 39, 49, 4, 44, 17, 0, 32, 13, 53, 35, 59, 17, 62, 0, 55, 24, 52, 38, 31, 6, 42, 19, 29, 40, 4, 54, 33, 5, 16, 27, 52, 37, 23, 55, 7, 37, 0, 39, 23, 49, 4, 53, 31, 15, 59, 10, 50, 4, 60, 34, 48, 7, 31, 49, 27, 14, 62, 22, 53, 29 },
+  { 46, 21, 14, 51, 36, 17, 7, 57, 10, 32, 3, 37, 22, 60, 39, 18, 56, 20, 42, 3, 36, 10, 44, 26, 41, 29, 53, 27, 2, 39, 30, 52, 0, 59, 15, 48, 23, 61, 6, 58, 37, 12, 40, 49, 16, 39, 20, 44, 0, 62, 8, 21, 3, 59, 23, 32, 49, 31, 12, 44, 22, 59, 18, 50, 24, 7, 43, 52, 15, 23, 41, 26, 51, 28, 55, 39, 21, 27, 10, 42, 12, 45, 27, 47, 3, 15, 63, 26, 55, 0, 60, 26, 45, 18, 62, 38, 58, 49, 8, 47, 4, 33, 46, 29, 57, 13, 56, 16, 59, 21, 5, 47, 23, 39, 18, 44, 13, 22, 28, 53, 19, 0, 58, 32, 41, 7, 26, 13 },
+  { 0, 56, 34, 28, 11, 55, 31, 47, 26, 41, 56, 13, 53, 28, 11, 49, 7, 52, 32, 61, 50, 22, 63, 17, 13, 56, 7, 19, 43, 62, 10, 21, 37, 32, 43, 4, 38, 19, 44, 25, 31, 54, 5, 23, 61, 30, 53, 12, 35, 22, 43, 53, 37, 48, 7, 62, 20, 2, 61, 41, 8, 34, 47, 9, 63, 34, 28, 10, 55, 33, 14, 57, 7, 47, 9, 61, 4, 49, 31, 50, 21, 38, 8, 16, 57, 44, 33, 5, 49, 36, 12, 50, 7, 34, 10, 25, 2, 22, 36, 15, 26, 61, 18, 9, 22, 46, 32, 8, 27, 37, 44, 30, 55, 3, 62, 24, 38, 56, 5, 45, 38, 24, 43, 10, 19, 54, 39, 61 },
+  { 41, 30, 8, 63, 43, 23, 38, 3, 62, 19, 8, 49, 25, 1, 58, 30, 23, 40, 9, 28, 18, 40, 6, 38, 49, 22, 35, 59, 8, 27, 50, 5, 56, 17, 11, 50, 30, 9, 55, 2, 51, 19, 34, 47, 9, 41, 6, 26, 48, 57, 14, 28, 17, 12, 39, 13, 37, 46, 25, 19, 54, 27, 1, 37, 16, 45, 20, 60, 1, 48, 20, 38, 31, 22, 42, 15, 19, 44, 1, 61, 6, 34, 56, 40, 29, 10, 20, 46, 13, 22, 41, 23, 59, 42, 30, 51, 45, 13, 63, 53, 42, 12, 51, 38, 62, 2, 26, 41, 50, 1, 61, 10, 19, 42, 31, 8, 49, 32, 12, 63, 9, 52, 16, 56, 36, 2, 31, 16 },
+  { 52, 5, 47, 20, 1, 53, 12, 50, 16, 35, 43, 21, 33, 43, 16, 44, 3, 59, 14, 46, 1, 30, 60, 33, 2, 45, 12, 42, 31, 47, 14, 33, 46, 25, 55, 27, 60, 36, 16, 42, 14, 46, 26, 1, 55, 15, 63, 32, 2, 38, 5, 47, 33, 61, 30, 52, 4, 57, 6, 38, 11, 43, 61, 24, 52, 3, 31, 22, 42, 10, 62, 3, 59, 11, 35, 57, 33, 54, 24, 14, 29, 48, 18, 2, 60, 41, 53, 24, 32, 62, 3, 53, 15, 1, 55, 17, 32, 40, 6, 31, 1, 40, 28, 5, 35, 52, 19, 63, 13, 33, 17, 41, 52, 26, 15, 57, 1, 20, 42, 17, 35, 27, 48, 5, 25, 50, 44, 11 },
+  { 35, 25, 38, 57, 33, 17, 40, 6, 59, 27, 54, 5, 61, 10, 52, 26, 36, 19, 51, 35, 57, 48, 11, 20, 54, 25, 61, 16, 1, 58, 24, 61, 3, 39, 7, 47, 1, 22, 49, 28, 63, 10, 58, 32, 17, 36, 45, 19, 51, 29, 59, 10, 50, 1, 23, 42, 18, 29, 51, 21, 56, 32, 14, 5, 40, 58, 47, 13, 54, 35, 29, 45, 18, 52, 26, 2, 38, 8, 46, 36, 58, 11, 52, 35, 17, 28, 1, 58, 9, 39, 17, 28, 37, 48, 20, 9, 57, 24, 50, 19, 58, 16, 48, 25, 43, 11, 35, 6, 45, 24, 56, 4, 36, 7, 47, 35, 52, 28, 59, 30, 2, 61, 21, 33, 63, 12, 18, 59 },
+  { 3, 49, 15, 10, 27, 61, 25, 45, 30, 0, 14, 47, 31, 38, 17, 62, 7, 55, 27, 4, 15, 24, 42, 52, 10, 34, 5, 51, 36, 18, 41, 11, 35, 21, 62, 13, 33, 57, 8, 35, 5, 40, 21, 43, 52, 3, 24, 56, 11, 16, 33, 25, 41, 20, 55, 8, 60, 35, 15, 48, 2, 57, 30, 49, 18, 25, 6, 39, 17, 57, 7, 25, 43, 5, 49, 16, 62, 22, 55, 4, 25, 43, 23, 7, 50, 11, 37, 48, 14, 51, 33, 57, 7, 27, 39, 46, 4, 29, 11, 43, 34, 56, 7, 60, 20, 54, 30, 57, 22, 49, 9, 33, 54, 14, 63, 23, 6, 43, 10, 40, 50, 13, 44, 8, 38, 33, 46, 23 },
+  { 55, 39, 22, 50, 44, 4, 36, 9, 52, 23, 37, 59, 21, 2, 46, 13, 31, 41, 11, 45, 62, 29, 6, 37, 19, 48, 30, 23, 44, 7, 53, 28, 54, 16, 41, 29, 44, 18, 52, 24, 60, 15, 48, 7, 27, 59, 9, 34, 42, 54, 7, 63, 4, 46, 31, 27, 45, 0, 40, 26, 34, 17, 37, 10, 53, 29, 36, 50, 2, 27, 51, 11, 61, 37, 23, 41, 30, 7, 18, 50, 39, 14, 63, 32, 45, 61, 19, 30, 25, 44, 2, 47, 23, 63, 11, 34, 59, 37, 60, 3, 22, 14, 44, 30, 15, 0, 47, 15, 3, 38, 61, 20, 27, 45, 11, 39, 51, 16, 55, 3, 22, 54, 29, 58, 1, 57, 6, 29 },
+  { 9, 17, 60, 2, 34, 56, 20, 62, 39, 12, 49, 6, 29, 56, 34, 48, 0, 58, 22, 38, 18, 43, 56, 0, 63, 14, 55, 3, 59, 31, 15, 45, 0, 49, 6, 58, 3, 38, 12, 45, 0, 37, 29, 57, 13, 39, 30, 49, 0, 23, 44, 36, 16, 57, 13, 54, 11, 24, 63, 9, 53, 7, 62, 42, 0, 59, 15, 23, 63, 34, 40, 16, 32, 0, 53, 12, 48, 28, 59, 33, 0, 53, 9, 27, 3, 22, 54, 5, 56, 9, 61, 13, 42, 14, 52, 19, 0, 21, 47, 27, 53, 36, 3, 50, 39, 58, 25, 40, 53, 28, 12, 50, 0, 59, 32, 2, 21, 34, 26, 46, 37, 7, 18, 47, 24, 14, 53, 42 },
+  { 61, 32, 13, 54, 29, 7, 46, 13, 28, 57, 18, 41, 53, 15, 9, 39, 24, 49, 33, 3, 53, 9, 26, 32, 40, 28, 46, 39, 25, 9, 56, 21, 63, 37, 26, 22, 51, 27, 17, 56, 31, 53, 4, 43, 22, 46, 12, 18, 60, 40, 20, 26, 50, 21, 39, 5, 49, 33, 16, 44, 22, 46, 20, 32, 24, 45, 8, 43, 12, 46, 4, 48, 56, 20, 29, 58, 3, 40, 10, 42, 31, 21, 47, 41, 56, 38, 15, 42, 36, 27, 20, 33, 55, 3, 26, 44, 31, 54, 12, 35, 9, 63, 28, 10, 21, 32, 9, 60, 17, 8, 43, 29, 40, 16, 36, 48, 60, 7, 57, 14, 62, 31, 42, 15, 36, 40, 20, 26 },
+  { 0, 37, 47, 23, 41, 18, 32, 48, 1, 35, 8, 25, 4, 26, 63, 20, 54, 8, 16, 61, 35, 23, 51, 15, 58, 7, 12, 20, 50, 34, 42, 4, 38, 10, 32, 47, 8, 60, 41, 20, 9, 25, 50, 19, 62, 1, 37, 56, 28, 8, 53, 11, 3, 58, 34, 43, 19, 60, 38, 4, 58, 31, 3, 51, 11, 55, 38, 30, 21, 58, 19, 26, 9, 44, 36, 13, 46, 20, 62, 24, 13, 60, 5, 28, 12, 34, 7, 59, 0, 53, 45, 6, 38, 30, 50, 7, 62, 16, 41, 5, 46, 18, 55, 42, 51, 5, 45, 23, 34, 48, 19, 58, 5, 25, 54, 19, 13, 41, 28, 21, 0, 49, 10, 60, 4, 51, 9, 45 },
+  { 19, 28, 6, 58, 10, 51, 4, 22, 55, 42, 60, 45, 34, 51, 42, 5, 30, 45, 27, 40, 13, 47, 4, 49, 21, 38, 60, 29, 2, 57, 17, 27, 52, 19, 61, 14, 30, 34, 2, 44, 63, 33, 11, 35, 16, 51, 25, 6, 14, 47, 31, 61, 37, 29, 18, 8, 52, 2, 28, 54, 13, 41, 15, 62, 35, 18, 2, 60, 6, 33, 41, 61, 31, 6, 56, 17, 34, 50, 6, 52, 44, 35, 16, 51, 59, 24, 48, 18, 31, 40, 16, 49, 21, 60, 17, 39, 10, 49, 32, 57, 24, 39, 1, 25, 18, 62, 37, 12, 56, 1, 37, 11, 52, 44, 9, 30, 47, 4, 51, 40, 55, 25, 34, 27, 56, 30, 32, 54 },
+  { 63, 40, 49, 15, 43, 26, 63, 38, 16, 20, 30, 12, 57, 14, 19, 60, 36, 12, 59, 2, 57, 17, 42, 31, 1, 44, 16, 35, 47, 11, 32, 48, 13, 43, 1, 39, 51, 12, 57, 23, 6, 40, 53, 3, 55, 31, 39, 60, 35, 44, 5, 15, 45, 1, 62, 41, 26, 14, 47, 22, 36, 27, 50, 9, 26, 47, 52, 28, 54, 16, 1, 13, 51, 39, 23, 63, 1, 30, 15, 26, 2, 57, 19, 37, 1, 44, 21, 50, 13, 63, 8, 24, 56, 1, 35, 25, 58, 20, 2, 28, 14, 51, 33, 59, 13, 30, 4, 49, 31, 24, 63, 26, 33, 3, 58, 38, 62, 24, 32, 8, 17, 45, 5, 48, 18, 3, 43, 11 },
+  { 21, 4, 24, 34, 59, 1, 37, 11, 53, 5, 47, 2, 22, 40, 32, 1, 24, 50, 21, 29, 38, 25, 63, 8, 55, 24, 53, 6, 62, 23, 59, 3, 54, 20, 58, 24, 5, 46, 15, 38, 48, 14, 27, 42, 23, 7, 46, 10, 17, 58, 25, 52, 23, 32, 49, 12, 55, 30, 40, 7, 59, 1, 56, 21, 39, 4, 23, 15, 37, 46, 55, 42, 21, 4, 48, 8, 45, 54, 37, 55, 32, 8, 46, 10, 30, 54, 4, 41, 25, 29, 36, 48, 11, 43, 14, 47, 5, 43, 53, 36, 61, 10, 45, 6, 41, 54, 27, 43, 16, 55, 6, 46, 18, 42, 23, 15, 1, 45, 12, 60, 37, 22, 62, 12, 39, 59, 16, 52 },
+  { 47, 35, 56, 7, 19, 46, 31, 50, 33, 24, 61, 35, 50, 7, 53, 44, 55, 6, 46, 10, 52, 5, 21, 43, 36, 10, 18, 41, 26, 37, 8, 29, 40, 36, 9, 49, 34, 26, 61, 21, 7, 59, 18, 62, 29, 54, 20, 32, 51, 0, 40, 10, 55, 6, 20, 36, 9, 61, 5, 51, 44, 19, 33, 43, 13, 57, 40, 63, 8, 24, 29, 10, 60, 34, 27, 40, 25, 18, 10, 42, 21, 49, 26, 62, 38, 12, 33, 61, 5, 57, 2, 19, 54, 28, 62, 22, 38, 31, 16, 7, 22, 47, 29, 17, 35, 8, 20, 51, 2, 40, 22, 50, 13, 61, 28, 53, 35, 20, 56, 30, 2, 53, 14, 41, 23, 34, 8, 31 },
+  { 12, 2, 42, 29, 52, 13, 21, 8, 55, 14, 41, 17, 28, 58, 23, 11, 17, 36, 31, 62, 17, 34, 50, 14, 28, 61, 33, 52, 2, 51, 17, 45, 7, 25, 62, 30, 18, 55, 0, 42, 30, 35, 45, 1, 12, 48, 3, 63, 21, 36, 30, 48, 19, 59, 43, 27, 46, 17, 34, 25, 12, 29, 53, 6, 48, 31, 11, 34, 49, 3, 36, 50, 19, 47, 14, 61, 11, 36, 58, 4, 60, 14, 39, 22, 6, 52, 15, 35, 17, 46, 31, 42, 9, 34, 3, 52, 12, 60, 26, 56, 40, 2, 53, 23, 57, 38, 62, 14, 36, 59, 10, 31, 39, 6, 49, 9, 41, 26, 5, 48, 43, 27, 33, 58, 1, 50, 25, 57 },
+  { 61, 37, 15, 61, 3, 39, 58, 43, 26, 0, 44, 10, 47, 3, 37, 63, 28, 43, 13, 39, 3, 57, 30, 59, 0, 48, 5, 43, 13, 22, 60, 33, 55, 15, 42, 4, 52, 10, 45, 13, 54, 4, 24, 49, 37, 26, 41, 14, 42, 9, 61, 13, 38, 23, 3, 53, 0, 58, 21, 42, 63, 10, 17, 61, 25, 0, 58, 28, 17, 44, 57, 12, 27, 0, 55, 5, 52, 28, 23, 47, 29, 0, 43, 17, 58, 28, 47, 23, 55, 10, 58, 23, 51, 40, 18, 33, 45, 0, 49, 8, 32, 61, 19, 48, 0, 26, 7, 47, 29, 18, 44, 0, 56, 34, 20, 59, 15, 51, 37, 18, 10, 52, 7, 20, 46, 9, 38, 17 },
+  { 6, 27, 48, 23, 45, 29, 5, 18, 38, 62, 27, 56, 20, 32, 15, 9, 48, 0, 54, 22, 45, 20, 7, 41, 23, 39, 19, 27, 58, 31, 44, 0, 12, 50, 23, 56, 20, 39, 32, 59, 16, 52, 33, 9, 57, 22, 6, 58, 28, 50, 24, 2, 56, 35, 16, 45, 32, 38, 15, 54, 2, 38, 46, 22, 35, 45, 20, 5, 52, 25, 7, 35, 59, 32, 22, 43, 38, 3, 51, 16, 34, 53, 32, 50, 3, 40, 8, 43, 0, 39, 27, 4, 14, 61, 8, 55, 15, 41, 20, 44, 27, 13, 39, 11, 46, 42, 54, 33, 4, 52, 23, 61, 14, 25, 43, 2, 33, 11, 63, 29, 61, 17, 40, 55, 22, 62, 28, 44 },
+  { 20, 54, 8, 56, 35, 10, 63, 31, 52, 12, 48, 6, 59, 41, 52, 33, 19, 58, 25, 49, 11, 37, 47, 12, 54, 15, 56, 35, 7, 47, 16, 53, 28, 34, 5, 37, 28, 8, 48, 3, 28, 38, 18, 61, 16, 43, 53, 32, 4, 17, 47, 27, 44, 8, 63, 10, 25, 49, 6, 37, 24, 52, 32, 3, 50, 12, 41, 56, 38, 14, 62, 20, 40, 16, 53, 31, 18, 63, 41, 9, 59, 7, 13, 25, 57, 20, 63, 26, 53, 18, 48, 62, 30, 46, 21, 25, 58, 29, 36, 4, 55, 34, 6, 60, 31, 16, 21, 12, 58, 38, 9, 29, 47, 7, 52, 30, 57, 44, 22, 0, 35, 45, 3, 31, 14, 36, 0, 51 },
+  { 42, 14, 33, 24, 16, 49, 40, 2, 22, 33, 16, 36, 25, 1, 21, 61, 38, 8, 33, 4, 62, 26, 29, 60, 6, 46, 30, 11, 63, 4, 36, 40, 19, 57, 46, 11, 41, 63, 22, 25, 58, 10, 46, 2, 34, 27, 11, 38, 56, 34, 12, 53, 18, 33, 41, 51, 13, 28, 60, 20, 47, 14, 29, 59, 16, 62, 8, 22, 32, 47, 9, 49, 2, 44, 7, 12, 45, 6, 20, 27, 45, 24, 62, 42, 36, 11, 33, 15, 37, 7, 32, 10, 37, 1, 35, 50, 6, 11, 63, 24, 52, 15, 50, 24, 3, 37, 56, 27, 34, 22, 49, 16, 36, 62, 17, 39, 4, 15, 54, 24, 50, 8, 58, 26, 49, 54, 11, 30 },
+  { 4, 59, 41, 1, 53, 12, 25, 45, 59, 7, 51, 39, 54, 14, 46, 4, 27, 53, 16, 44, 18, 51, 1, 32, 25, 2, 50, 40, 20, 54, 24, 9, 62, 2, 27, 60, 1, 17, 36, 50, 6, 40, 30, 55, 41, 19, 49, 1, 21, 60, 40, 5, 62, 1, 22, 30, 57, 4, 43, 31, 1, 55, 40, 7, 27, 37, 30, 54, 1, 19, 42, 30, 56, 26, 62, 49, 24, 57, 37, 56, 2, 39, 16, 5, 30, 55, 3, 49, 60, 23, 56, 44, 17, 52, 13, 42, 28, 48, 18, 45, 9, 37, 21, 41, 58, 10, 48, 1, 63, 5, 41, 57, 2, 24, 12, 48, 27, 42, 32, 46, 13, 38, 19, 34, 5, 41, 25, 60 },
+  { 39, 28, 21, 46, 32, 57, 36, 9, 19, 42, 4, 29, 11, 43, 30, 49, 13, 42, 35, 56, 9, 39, 15, 52, 36, 61, 18, 26, 45, 14, 31, 48, 21, 43, 14, 33, 49, 54, 14, 44, 21, 62, 13, 23, 8, 62, 15, 51, 44, 7, 30, 37, 20, 42, 56, 7, 39, 18, 50, 11, 61, 9, 19, 43, 57, 2, 48, 11, 39, 60, 28, 4, 37, 17, 35, 1, 33, 11, 31, 14, 48, 19, 35, 51, 46, 21, 44, 29, 12, 41, 2, 22, 58, 26, 54, 4, 59, 38, 2, 33, 57, 1, 63, 13, 28, 51, 15, 40, 18, 45, 8, 30, 43, 37, 54, 19, 8, 59, 21, 6, 60, 29, 55, 10, 63, 15, 47, 17 },
+  { 3, 50, 10, 62, 18, 5, 27, 49, 60, 23, 55, 18, 62, 24, 56, 10, 59, 28, 2, 23, 34, 59, 43, 20, 10, 42, 8, 49, 1, 37, 57, 6, 51, 29, 53, 7, 23, 31, 5, 32, 51, 0, 35, 54, 45, 31, 5, 26, 36, 24, 55, 15, 48, 29, 14, 48, 26, 60, 21, 41, 36, 26, 50, 33, 14, 44, 17, 24, 52, 15, 46, 23, 54, 6, 47, 21, 60, 50, 4, 53, 29, 61, 8, 23, 1, 60, 19, 6, 53, 16, 47, 34, 6, 39, 16, 31, 12, 20, 53, 22, 30, 43, 25, 46, 35, 6, 44, 32, 53, 26, 55, 19, 11, 59, 5, 33, 51, 1, 35, 53, 25, 3, 42, 23, 44, 32, 7, 53 },
+  { 22, 44, 37, 6, 26, 51, 38, 0, 34, 13, 31, 46, 3, 37, 6, 19, 40, 21, 47, 63, 12, 5, 29, 55, 22, 58, 34, 28, 60, 22, 11, 41, 17, 38, 9, 44, 59, 39, 56, 19, 11, 47, 25, 15, 3, 39, 57, 17, 61, 11, 46, 3, 58, 9, 54, 35, 2, 34, 8, 45, 15, 56, 5, 23, 53, 33, 63, 35, 4, 59, 10, 51, 13, 61, 29, 41, 15, 25, 43, 19, 40, 10, 54, 33, 41, 12, 38, 51, 31, 26, 61, 9, 30, 45, 24, 62, 49, 40, 10, 61, 14, 49, 5, 17, 54, 20, 60, 23, 3, 13, 35, 50, 32, 23, 46, 27, 38, 63, 16, 12, 39, 48, 18, 51, 1, 27, 56, 35 },
+  { 63, 15, 30, 55, 43, 14, 57, 17, 53, 44, 7, 48, 26, 50, 32, 60, 0, 53, 14, 31, 50, 24, 46, 0, 38, 13, 4, 52, 16, 45, 30, 59, 0, 25, 55, 35, 16, 10, 26, 42, 58, 29, 60, 38, 50, 22, 28, 47, 0, 50, 28, 19, 33, 39, 11, 44, 16, 52, 24, 59, 3, 38, 27, 51, 0, 21, 7, 42, 26, 34, 21, 40, 33, 18, 39, 3, 54, 38, 8, 59, 0, 44, 27, 15, 58, 28, 57, 9, 43, 0, 36, 50, 20, 59, 8, 34, 0, 27, 47, 7, 36, 19, 56, 32, 0, 38, 11, 29, 62, 47, 6, 61, 0, 41, 14, 56, 10, 23, 45, 31, 57, 8, 36, 13, 58, 38, 11, 19 },
+  { 0, 34, 12, 47, 21, 2, 40, 30, 11, 25, 61, 20, 40, 15, 35, 22, 45, 36, 7, 41, 17, 57, 9, 48, 32, 62, 44, 24, 35, 3, 54, 13, 33, 63, 19, 4, 48, 22, 62, 2, 37, 8, 33, 6, 20, 52, 9, 32, 43, 13, 39, 63, 25, 4, 49, 23, 62, 32, 9, 30, 48, 18, 63, 12, 46, 29, 58, 13, 48, 8, 57, 31, 0, 51, 9, 58, 12, 22, 47, 29, 35, 22, 49, 5, 46, 4, 34, 20, 63, 24, 56, 11, 41, 3, 51, 19, 56, 35, 17, 58, 28, 42, 9, 45, 59, 26, 51, 42, 17, 36, 25, 15, 53, 21, 44, 3, 30, 55, 5, 50, 21, 28, 61, 32, 6, 49, 28, 46 },
+  { 58, 42, 60, 4, 31, 59, 22, 63, 35, 38, 9, 54, 1, 57, 8, 51, 16, 58, 27, 53, 3, 38, 30, 15, 27, 6, 19, 56, 10, 50, 21, 36, 47, 5, 43, 28, 51, 32, 13, 46, 18, 54, 16, 43, 63, 12, 36, 59, 22, 34, 5, 52, 17, 59, 27, 41, 0, 19, 55, 37, 13, 43, 6, 34, 41, 10, 36, 55, 19, 44, 3, 16, 58, 27, 49, 25, 32, 62, 17, 55, 13, 63, 18, 52, 25, 37, 17, 48, 13, 32, 5, 46, 28, 37, 14, 43, 25, 5, 51, 39, 3, 52, 33, 22, 8, 40, 12, 4, 57, 9, 46, 39, 28, 58, 13, 62, 17, 42, 19, 36, 0, 47, 16, 43, 24, 21, 54, 13 },
+  { 25, 9, 23, 50, 36, 8, 45, 14, 3, 51, 16, 28, 44, 12, 42, 29, 4, 26, 10, 47, 22, 61, 18, 54, 51, 39, 46, 13, 41, 26, 58, 7, 18, 39, 12, 57, 15, 1, 52, 27, 41, 23, 48, 1, 27, 45, 18, 2, 57, 26, 55, 8, 43, 31, 6, 58, 14, 51, 40, 5, 61, 31, 24, 54, 17, 60, 22, 1, 39, 30, 53, 45, 36, 13, 43, 5, 45, 2, 37, 6, 34, 42, 2, 39, 10, 62, 7, 54, 40, 18, 60, 15, 52, 21, 63, 8, 55, 46, 15, 30, 23, 13, 62, 16, 50, 24, 58, 31, 48, 21, 34, 2, 49, 7, 31, 37, 26, 48, 9, 61, 40, 11, 52, 2, 60, 40, 4, 37 },
+  { 52, 28, 39, 16, 54, 19, 29, 55, 42, 20, 58, 33, 24, 63, 18, 55, 39, 62, 43, 34, 12, 40, 6, 35, 2, 25, 8, 62, 34, 1, 31, 42, 61, 27, 53, 24, 40, 61, 34, 8, 59, 4, 30, 56, 40, 6, 53, 42, 10, 48, 16, 37, 12, 46, 21, 36, 47, 11, 28, 45, 22, 10, 57, 2, 49, 31, 14, 44, 61, 11, 25, 6, 23, 63, 18, 36, 28, 56, 20, 51, 11, 48, 27, 56, 32, 22, 45, 30, 2, 42, 27, 39, 1, 44, 23, 31, 38, 22, 11, 61, 43, 54, 4, 47, 35, 2, 44, 16, 28, 54, 12, 62, 18, 43, 10, 52, 1, 58, 33, 15, 29, 56, 20, 34, 9, 30, 48, 17 },
+  { 46, 2, 56, 11, 41, 1, 49, 6, 27, 47, 2, 48, 5, 32, 37, 3, 13, 19, 32, 1, 55, 28, 60, 17, 43, 59, 32, 20, 49, 16, 55, 23, 14, 46, 2, 36, 6, 30, 20, 49, 12, 47, 35, 14, 21, 60, 29, 14, 35, 24, 46, 1, 56, 29, 53, 8, 33, 23, 56, 1, 35, 46, 20, 39, 26, 4, 53, 28, 17, 38, 60, 34, 48, 9, 55, 15, 46, 7, 41, 31, 60, 24, 16, 36, 1, 59, 19, 52, 35, 6, 55, 11, 59, 33, 7, 57, 4, 29, 48, 1, 19, 26, 37, 30, 18, 63, 37, 6, 59, 1, 40, 24, 56, 33, 46, 22, 35, 7, 24, 53, 39, 5, 26, 45, 55, 18, 62, 7 },
+  { 20, 60, 29, 34, 20, 62, 33, 52, 10, 36, 13, 60, 41, 21, 50, 27, 56, 49, 8, 51, 21, 45, 11, 48, 8, 23, 53, 3, 29, 44, 5, 52, 9, 32, 50, 17, 43, 56, 3, 38, 24, 10, 62, 25, 51, 9, 33, 49, 61, 7, 30, 62, 22, 19, 2, 42, 63, 5, 49, 18, 60, 15, 52, 7, 43, 56, 23, 50, 5, 50, 2, 20, 41, 30, 1, 52, 22, 61, 14, 26, 3, 43, 53, 7, 47, 28, 11, 14, 23, 58, 33, 25, 47, 13, 50, 17, 40, 54, 34, 60, 41, 6, 59, 14, 50, 7, 25, 55, 20, 42, 51, 8, 27, 4, 16, 60, 28, 50, 44, 3, 22, 49, 63, 12, 33, 1, 43, 31 },
+  { 36, 5, 46, 8, 44, 24, 13, 39, 25, 57, 31, 18, 8, 52, 10, 45, 6, 30, 36, 24, 63, 4, 33, 26, 57, 40, 15, 56, 37, 12, 40, 25, 37, 58, 11, 63, 21, 45, 16, 60, 31, 53, 18, 33, 3, 45, 23, 0, 20, 54, 40, 15, 50, 38, 60, 16, 25, 42, 29, 38, 7, 41, 25, 62, 18, 33, 8, 35, 42, 16, 32, 56, 12, 39, 59, 19, 34, 9, 49, 38, 57, 12, 21, 50, 14, 40, 61, 44, 50, 9, 49, 19, 3, 29, 35, 62, 12, 24, 7, 18, 52, 32, 10, 46, 21, 41, 32, 11, 36, 29, 14, 34, 60, 38, 54, 11, 41, 14, 19, 57, 32, 16, 7, 41, 51, 25, 14, 57 },
+  { 53, 18, 26, 50, 15, 58, 4, 63, 17, 43, 7, 40, 61, 35, 15, 41, 23, 60, 16, 38, 14, 42, 19, 50, 0, 31, 10, 46, 27, 63, 18, 60, 0, 20, 29, 39, 8, 26, 37, 5, 42, 0, 44, 39, 57, 17, 58, 41, 28, 37, 4, 32, 9, 44, 12, 31, 54, 10, 59, 14, 27, 53, 12, 36, 0, 47, 13, 63, 21, 58, 10, 24, 50, 27, 4, 26, 44, 53, 31, 0, 18, 42, 29, 33, 57, 4, 32, 26, 0, 38, 16, 61, 41, 53, 20, 0, 42, 44, 49, 27, 10, 56, 39, 0, 57, 15, 53, 49, 3, 61, 22, 47, 17, 5, 49, 26, 2, 63, 39, 10, 47, 27, 37, 23, 4, 59, 38, 10 },
+  { 23, 39, 61, 3, 37, 28, 48, 31, 0, 34, 51, 23, 2, 26, 58, 0, 53, 11, 46, 1, 57, 29, 52, 14, 37, 61, 21, 35, 2, 49, 7, 34, 47, 55, 4, 33, 54, 13, 58, 52, 19, 50, 22, 7, 13, 29, 36, 11, 51, 17, 60, 25, 55, 4, 34, 51, 0, 35, 20, 48, 32, 3, 51, 30, 59, 28, 40, 3, 46, 29, 54, 43, 7, 62, 47, 11, 39, 4, 23, 46, 55, 8, 63, 5, 25, 37, 18, 46, 21, 56, 31, 5, 36, 8, 45, 58, 26, 15, 2, 36, 47, 21, 29, 44, 25, 34, 3, 27, 43, 10, 52, 0, 45, 30, 24, 36, 43, 18, 34, 59, 0, 52, 61, 15, 44, 19, 30, 49 },
+  { 0, 27, 12, 43, 54, 9, 22, 53, 21, 46, 15, 55, 29, 47, 20, 33, 39, 28, 59, 35, 9, 44, 5, 24, 47, 7, 52, 17, 56, 22, 30, 42, 14, 26, 45, 18, 49, 1, 24, 34, 11, 27, 55, 32, 61, 47, 2, 56, 6, 44, 13, 47, 36, 27, 58, 22, 16, 47, 40, 4, 57, 38, 21, 45, 16, 9, 56, 26, 11, 38, 0, 22, 36, 17, 33, 57, 16, 30, 62, 15, 35, 40, 20, 45, 59, 10, 54, 8, 63, 13, 52, 27, 22, 57, 28, 12, 32, 51, 55, 22, 63, 4, 16, 54, 12, 62, 45, 19, 58, 13, 32, 40, 20, 56, 7, 57, 9, 54, 6, 29, 42, 21, 8, 55, 35, 47, 6, 41 },
+  { 56, 33, 58, 32, 19, 35, 42, 6, 59, 11, 38, 5, 49, 12, 62, 7, 52, 17, 5, 25, 54, 20, 61, 31, 54, 27, 41, 11, 44, 5, 59, 12, 36, 51, 10, 61, 28, 41, 48, 9, 43, 63, 5, 40, 20, 8, 49, 26, 34, 21, 58, 1, 18, 45, 7, 39, 61, 26, 8, 50, 23, 10, 63, 5, 55, 37, 19, 49, 52, 15, 59, 47, 13, 54, 1, 25, 42, 58, 10, 48, 3, 27, 50, 1, 17, 48, 34, 41, 16, 40, 2, 45, 10, 39, 17, 61, 5, 38, 19, 9, 41, 31, 60, 38, 5, 23, 36, 8, 30, 55, 24, 63, 12, 48, 14, 51, 31, 20, 45, 25, 12, 50, 32, 2, 28, 11, 62, 14 },
+  { 44, 16, 7, 48, 1, 62, 16, 50, 27, 33, 61, 25, 17, 44, 31, 14, 22, 43, 32, 48, 18, 40, 8, 36, 3, 16, 33, 62, 23, 38, 25, 53, 2, 21, 41, 6, 22, 15, 59, 29, 16, 37, 26, 15, 52, 42, 23, 15, 54, 39, 10, 30, 53, 11, 49, 24, 2, 43, 55, 17, 34, 44, 15, 31, 24, 44, 2, 32, 7, 35, 25, 5, 40, 45, 29, 51, 6, 21, 37, 52, 24, 60, 13, 31, 53, 23, 2, 28, 49, 24, 31, 60, 20, 51, 1, 34, 48, 14, 59, 33, 50, 1, 18, 33, 48, 60, 17, 51, 39, 6, 38, 2, 35, 29, 40, 23, 1, 62, 15, 53, 37, 17, 46, 57, 40, 51, 24, 22 },
+  { 5, 37, 52, 24, 45, 13, 40, 3, 45, 9, 19, 42, 56, 4, 37, 46, 56, 2, 63, 11, 51, 1, 49, 13, 59, 45, 39, 1, 48, 15, 58, 9, 46, 31, 54, 35, 57, 38, 3, 46, 56, 4, 47, 57, 1, 30, 38, 63, 3, 46, 28, 63, 41, 14, 33, 62, 19, 32, 13, 28, 61, 1, 53, 42, 11, 60, 22, 62, 27, 42, 61, 31, 19, 8, 61, 12, 32, 55, 2, 18, 33, 12, 43, 36, 9, 62, 30, 55, 6, 58, 35, 7, 43, 29, 54, 23, 43, 30, 3, 25, 11, 45, 52, 28, 7, 14, 42, 1, 22, 50, 16, 53, 19, 59, 4, 46, 33, 41, 4, 35, 58, 5, 26, 13, 20, 2, 34, 54 },
+  { 30, 63, 21, 10, 26, 55, 29, 59, 23, 39, 53, 1, 36, 24, 59, 27, 10, 34, 23, 38, 30, 60, 22, 42, 28, 19, 9, 57, 30, 19, 43, 33, 13, 63, 3, 19, 11, 50, 31, 20, 14, 34, 10, 35, 17, 59, 7, 31, 19, 25, 50, 5, 20, 57, 29, 6, 52, 41, 4, 46, 20, 37, 26, 17, 49, 6, 39, 18, 53, 14, 3, 49, 57, 23, 34, 48, 14, 41, 28, 38, 56, 6, 58, 25, 39, 19, 43, 15, 37, 11, 47, 18, 53, 4, 37, 9, 62, 21, 53, 40, 57, 24, 13, 40, 56, 26, 47, 31, 59, 25, 45, 27, 10, 43, 21, 61, 13, 27, 48, 9, 23, 43, 31, 62, 38, 59, 9, 47 },
+  { 25, 4, 40, 60, 34, 6, 18, 36, 8, 57, 12, 30, 49, 14, 6, 54, 41, 16, 50, 6, 43, 15, 34, 4, 53, 24, 50, 35, 4, 51, 7, 55, 28, 24, 39, 44, 60, 7, 25, 62, 42, 53, 24, 61, 28, 45, 52, 12, 48, 37, 9, 35, 43, 3, 37, 48, 12, 58, 30, 52, 9, 59, 6, 57, 33, 29, 48, 4, 37, 45, 20, 34, 10, 39, 0, 60, 22, 45, 8, 63, 21, 42, 14, 49, 3, 56, 11, 46, 21, 61, 0, 42, 25, 13, 63, 17, 36, 8, 46, 16, 6, 35, 63, 0, 21, 37, 4, 57, 9, 34, 5, 61, 48, 32, 8, 37, 54, 17, 56, 30, 60, 0, 50, 16, 7, 29, 42, 17 },
+  { 32, 50, 15, 48, 2, 43, 52, 25, 47, 16, 32, 63, 21, 52, 40, 19, 0, 61, 29, 58, 20, 56, 26, 46, 12, 55, 6, 22, 62, 32, 17, 40, 0, 49, 34, 8, 27, 32, 48, 0, 21, 39, 5, 44, 12, 6, 22, 40, 0, 57, 16, 60, 23, 17, 54, 22, 36, 15, 24, 39, 19, 34, 47, 23, 0, 54, 13, 51, 24, 9, 55, 16, 52, 27, 44, 20, 4, 54, 26, 49, 0, 30, 46, 16, 29, 51, 34, 4, 52, 28, 33, 15, 57, 39, 26, 49, 0, 56, 27, 31, 48, 20, 43, 29, 53, 11, 46, 19, 41, 13, 55, 18, 0, 57, 26, 51, 2, 44, 6, 38, 14, 40, 22, 45, 36, 53, 3, 57 },
+  { 44, 12, 37, 28, 22, 57, 11, 38, 0, 51, 9, 41, 4, 29, 11, 47, 33, 45, 12, 26, 3, 36, 9, 63, 31, 16, 38, 44, 14, 47, 25, 61, 20, 58, 15, 47, 17, 57, 13, 36, 9, 51, 18, 29, 50, 36, 54, 20, 61, 27, 32, 13, 53, 44, 9, 27, 0, 63, 45, 2, 56, 10, 14, 43, 41, 28, 58, 11, 35, 60, 30, 41, 6, 63, 11, 51, 37, 32, 15, 10, 35, 53, 5, 61, 22, 7, 26, 59, 23, 9, 44, 48, 21, 3, 51, 32, 24, 41, 12, 61, 2, 55, 9, 15, 35, 58, 28, 15, 62, 30, 37, 23, 42, 29, 11, 17, 35, 24, 63, 20, 52, 28, 8, 55, 11, 23, 47, 19 },
+  { 0, 56, 8, 53, 14, 31, 61, 20, 55, 28, 62, 18, 35, 60, 25, 57, 7, 23, 39, 54, 47, 17, 43, 0, 40, 59, 29, 2, 56, 10, 37, 5, 43, 11, 29, 52, 1, 23, 54, 41, 59, 30, 55, 1, 62, 15, 33, 4, 43, 10, 47, 39, 1, 31, 40, 60, 49, 33, 7, 55, 26, 50, 31, 61, 8, 18, 21, 32, 44, 1, 25, 47, 18, 36, 30, 23, 59, 7, 40, 59, 27, 19, 38, 32, 44, 54, 40, 17, 38, 60, 27, 6, 35, 55, 10, 14, 44, 5, 50, 17, 38, 26, 42, 50, 18, 3, 44, 52, 2, 49, 7, 52, 15, 46, 62, 39, 55, 10, 31, 48, 3, 58, 33, 18, 61, 34, 13, 59 },
+  { 39, 27, 63, 20, 35, 41, 4, 45, 26, 5, 38, 13, 44, 2, 50, 17, 37, 52, 2, 13, 28, 58, 24, 51, 21, 8, 34, 48, 27, 42, 18, 51, 31, 56, 5, 36, 38, 44, 4, 17, 26, 11, 38, 23, 42, 8, 56, 39, 24, 51, 5, 56, 21, 59, 14, 6, 18, 42, 22, 35, 16, 37, 3, 25, 39, 46, 63, 5, 50, 17, 58, 8, 55, 3, 50, 12, 43, 17, 47, 2, 51, 9, 62, 12, 1, 35, 13, 50, 1, 37, 12, 51, 19, 29, 46, 59, 22, 58, 33, 45, 22, 60, 10, 32, 61, 39, 8, 33, 25, 36, 20, 60, 38, 4, 21, 5, 28, 45, 12, 18, 42, 11, 49, 1, 27, 40, 6, 30 },
+  { 24, 16, 42, 1, 50, 10, 48, 17, 33, 43, 24, 48, 21, 55, 31, 42, 10, 21, 63, 35, 49, 6, 33, 13, 41, 53, 10, 20, 60, 6, 53, 26, 12, 41, 22, 60, 14, 28, 63, 33, 49, 3, 45, 16, 48, 26, 14, 46, 18, 30, 35, 26, 8, 50, 29, 51, 25, 57, 12, 47, 53, 9, 62, 20, 54, 2, 36, 15, 40, 28, 33, 13, 38, 24, 46, 1, 29, 56, 33, 20, 44, 24, 41, 26, 57, 20, 63, 8, 30, 55, 5, 41, 62, 8, 34, 2, 37, 10, 19, 6, 37, 1, 53, 23, 5, 27, 58, 22, 43, 12, 50, 26, 9, 34, 54, 32, 49, 1, 59, 37, 22, 46, 25, 36, 51, 15, 54, 46 },
+  { 52, 7, 45, 33, 26, 58, 14, 60, 7, 54, 3, 58, 8, 34, 14, 5, 59, 30, 18, 44, 8, 22, 48, 62, 3, 26, 55, 38, 23, 16, 39, 1, 62, 24, 49, 9, 53, 19, 46, 7, 19, 60, 31, 58, 2, 34, 53, 7, 59, 2, 62, 42, 46, 19, 36, 11, 44, 4, 38, 28, 1, 43, 32, 51, 12, 29, 56, 22, 52, 2, 62, 49, 22, 60, 14, 35, 63, 5, 25, 57, 14, 53, 4, 46, 18, 31, 42, 22, 47, 20, 58, 31, 16, 43, 23, 54, 30, 42, 52, 57, 29, 49, 30, 13, 45, 48, 16, 55, 6, 63, 1, 44, 14, 58, 19, 47, 15, 24, 51, 34, 6, 55, 5, 63, 20, 41, 21, 9 },
+  { 30, 62, 18, 55, 5, 23, 39, 29, 49, 30, 15, 36, 28, 46, 60, 25, 39, 46, 4, 32, 61, 40, 15, 30, 36, 45, 14, 2, 49, 33, 57, 45, 18, 32, 3, 45, 30, 2, 35, 52, 40, 27, 13, 21, 38, 63, 20, 28, 37, 23, 16, 10, 13, 55, 2, 62, 21, 32, 60, 17, 58, 23, 5, 40, 16, 48, 7, 45, 10, 26, 43, 19, 6, 31, 52, 21, 39, 16, 48, 9, 37, 28, 36, 55, 7, 48, 3, 59, 15, 45, 25, 1, 53, 13, 47, 7, 62, 15, 4, 25, 12, 41, 18, 60, 38, 11, 34, 19, 39, 31, 29, 56, 23, 42, 3, 27, 60, 41, 8, 16, 61, 29, 43, 9, 32, 2, 60, 34 },
+  { 3, 38, 13, 37, 52, 44, 2, 19, 12, 42, 63, 19, 40, 1, 20, 50, 12, 55, 15, 56, 27, 1, 54, 11, 57, 18, 32, 63, 44, 4, 29, 13, 37, 61, 35, 16, 42, 57, 12, 22, 6, 55, 43, 10, 50, 5, 44, 11, 48, 52, 34, 58, 28, 41, 38, 30, 7, 52, 11, 49, 30, 14, 45, 27, 59, 34, 21, 38, 32, 58, 11, 36, 56, 42, 9, 41, 3, 54, 31, 42, 0, 60, 16, 11, 39, 24, 52, 33, 6, 36, 10, 40, 32, 60, 26, 20, 39, 28, 47, 34, 63, 8, 54, 3, 24, 56, 0, 51, 13, 47, 16, 40, 7, 35, 52, 11, 36, 4, 57, 30, 39, 13, 18, 50, 58, 28, 12, 48 },
+  { 57, 24, 49, 21, 10, 31, 61, 36, 56, 0, 22, 53, 11, 56, 32, 7, 36, 27, 41, 9, 46, 19, 34, 42, 25, 7, 50, 9, 28, 21, 54, 8, 50, 7, 27, 59, 10, 25, 48, 62, 37, 0, 33, 58, 25, 18, 32, 61, 0, 15, 45, 5, 50, 3, 23, 55, 47, 17, 40, 6, 60, 34, 53, 8, 41, 0, 61, 13, 54, 4, 46, 28, 0, 17, 48, 27, 58, 13, 23, 61, 33, 21, 50, 30, 62, 8, 14, 29, 56, 27, 61, 49, 17, 2, 44, 11, 51, 0, 59, 17, 40, 20, 32, 47, 36, 21, 42, 28, 60, 4, 54, 10, 59, 17, 30, 62, 21, 43, 26, 48, 0, 56, 36, 25, 8, 44, 39, 17 },
+  { 10, 42, 4, 59, 27, 47, 8, 23, 51, 32, 45, 6, 37, 26, 48, 43, 62, 0, 21, 53, 38, 12, 51, 5, 60, 47, 24, 37, 59, 15, 35, 47, 22, 55, 0, 50, 21, 40, 6, 29, 15, 52, 24, 8, 41, 55, 13, 29, 40, 56, 24, 31, 19, 33, 61, 15, 0, 35, 24, 42, 21, 2, 19, 57, 24, 15, 30, 50, 20, 25, 40, 16, 57, 34, 61, 8, 29, 45, 6, 49, 11, 47, 2, 44, 19, 57, 38, 50, 12, 42, 21, 4, 35, 52, 28, 56, 23, 36, 13, 45, 4, 52, 27, 14, 6, 62, 9, 45, 21, 37, 25, 46, 33, 49, 0, 44, 7, 53, 13, 19, 53, 31, 3, 47, 15, 56, 22, 51 },
+  { 35, 28, 53, 32, 1, 16, 54, 40, 9, 17, 25, 58, 14, 59, 3, 22, 16, 51, 31, 5, 23, 58, 28, 17, 35, 20, 0, 42, 11, 52, 3, 31, 41, 17, 43, 13, 32, 54, 18, 60, 32, 45, 17, 49, 2, 36, 51, 22, 7, 36, 9, 63, 48, 12, 46, 26, 43, 28, 63, 13, 48, 37, 51, 33, 5, 47, 55, 9, 42, 63, 7, 51, 24, 12, 37, 19, 55, 34, 18, 38, 15, 28, 54, 34, 5, 43, 22, 0, 48, 14, 54, 24, 58, 9, 38, 5, 32, 55, 21, 30, 49, 9, 59, 43, 30, 51, 35, 26, 7, 53, 2, 22, 14, 27, 57, 18, 38, 24, 33, 45, 10, 41, 20, 60, 37, 5, 32, 0 },
+  { 63, 19, 15, 40, 62, 35, 14, 28, 46, 61, 4, 49, 35, 10, 29, 54, 33, 8, 45, 62, 37, 1, 43, 55, 10, 52, 61, 30, 19, 40, 25, 62, 11, 38, 27, 58, 36, 3, 46, 8, 39, 4, 62, 28, 47, 20, 4, 54, 47, 27, 43, 1, 21, 38, 8, 58, 10, 54, 4, 56, 9, 26, 12, 39, 60, 27, 18, 37, 1, 31, 35, 5, 45, 50, 2, 43, 26, 1, 59, 23, 56, 40, 7, 26, 58, 17, 32, 63, 25, 39, 7, 31, 45, 19, 63, 15, 48, 8, 37, 61, 16, 34, 1, 56, 18, 3, 15, 58, 49, 32, 63, 41, 55, 5, 40, 22, 50, 6, 59, 2, 63, 23, 52, 11, 26, 61, 44, 23 },
+  { 11, 56, 46, 6, 22, 43, 58, 3, 34, 21, 38, 30, 18, 44, 52, 13, 41, 57, 17, 28, 14, 49, 25, 7, 33, 39, 26, 6, 56, 48, 1, 20, 56, 5, 46, 9, 19, 51, 30, 25, 56, 21, 35, 14, 57, 42, 16, 33, 10, 57, 17, 59, 41, 25, 53, 37, 20, 40, 30, 18, 31, 62, 44, 22, 3, 44, 11, 48, 23, 53, 18, 60, 29, 22, 62, 15, 53, 47, 10, 41, 3, 19, 52, 36, 13, 46, 10, 35, 3, 61, 41, 16, 1, 50, 26, 42, 18, 46, 2, 25, 54, 20, 39, 23, 47, 31, 41, 12, 38, 17, 8, 19, 31, 48, 12, 61, 9, 54, 29, 35, 15, 38, 6, 43, 34, 14, 7, 47 },
+  { 39, 2, 33, 26, 53, 8, 18, 50, 41, 12, 53, 1, 63, 24, 19, 39, 2, 24, 47, 10, 60, 38, 19, 63, 48, 4, 15, 45, 32, 14, 60, 36, 29, 53, 23, 63, 34, 12, 61, 1, 43, 11, 53, 30, 1, 26, 60, 45, 23, 39, 3, 29, 12, 50, 4, 16, 51, 3, 45, 36, 50, 1, 16, 54, 35, 14, 57, 30, 58, 9, 46, 14, 41, 10, 32, 38, 4, 30, 21, 51, 32, 63, 25, 1, 60, 27, 53, 18, 51, 22, 28, 55, 34, 12, 40, 3, 60, 29, 57, 41, 6, 44, 11, 53, 8, 61, 24, 57, 1, 28, 44, 59, 36, 3, 34, 25, 41, 31, 16, 44, 22, 47, 28, 58, 1, 49, 54, 29 },
+  { 58, 25, 50, 13, 38, 30, 60, 24, 6, 57, 27, 42, 9, 45, 6, 61, 30, 50, 4, 34, 29, 3, 46, 13, 22, 42, 58, 28, 9, 39, 23, 44, 7, 15, 44, 2, 40, 15, 47, 41, 23, 37, 7, 59, 38, 11, 34, 6, 62, 14, 52, 35, 55, 19, 32, 61, 33, 24, 57, 6, 22, 59, 29, 7, 49, 25, 40, 3, 17, 39, 27, 52, 0, 55, 16, 57, 24, 61, 36, 6, 29, 12, 48, 39, 20, 44, 6, 40, 33, 5, 48, 10, 57, 36, 22, 51, 33, 9, 24, 12, 62, 29, 50, 35, 14, 43, 5, 33, 47, 52, 13, 23, 10, 51, 56, 16, 46, 1, 49, 4, 61, 9, 52, 18, 31, 21, 36, 17 },
+  { 19, 42, 9, 48, 2, 44, 11, 37, 48, 20, 33, 16, 55, 35, 49, 15, 37, 20, 59, 16, 53, 22, 56, 31, 50, 11, 34, 54, 16, 51, 4, 49, 33, 53, 21, 28, 56, 24, 31, 9, 52, 16, 48, 24, 44, 13, 51, 20, 31, 49, 18, 6, 34, 2, 44, 14, 47, 8, 15, 43, 13, 41, 33, 52, 20, 61, 7, 51, 34, 62, 4, 20, 36, 33, 43, 8, 46, 13, 53, 17, 45, 42, 9, 31, 52, 11, 30, 56, 13, 59, 17, 44, 27, 6, 62, 11, 43, 17, 49, 38, 26, 2, 16, 27, 58, 21, 54, 18, 26, 5, 35, 61, 43, 27, 7, 39, 14, 58, 37, 55, 20, 33, 13, 40, 62, 10, 55, 5 },
+  { 51, 14, 61, 29, 59, 20, 55, 31, 0, 49, 11, 60, 3, 26, 22, 56, 0, 40, 12, 43, 41, 8, 36, 0, 17, 57, 24, 2, 46, 26, 61, 18, 0, 38, 12, 59, 6, 49, 3, 57, 19, 63, 5, 33, 18, 54, 28, 56, 0, 43, 26, 46, 63, 27, 56, 22, 27, 54, 38, 28, 63, 24, 10, 45, 0, 31, 42, 21, 12, 25, 44, 49, 59, 6, 26, 50, 3, 34, 27, 59, 0, 35, 62, 16, 4, 58, 47, 0, 43, 24, 37, 2, 54, 20, 46, 31, 0, 56, 34, 5, 55, 45, 60, 37, 0, 40, 10, 38, 63, 46, 15, 20, 0, 53, 21, 62, 30, 11, 24, 27, 40, 0, 57, 26, 3, 45, 27, 35 },
+};
+
+#else
+#define DM_WIDTH 8
+#define DM_WIDTH_SHIFT 3
+#define DM_HEIGHT 8
+static const unsigned char DM[8][8] =
+{
+  { 0,  32, 8,  40, 2,  34, 10, 42 },
+  { 48, 16, 56, 24, 50, 18, 58, 26 },
+  { 12, 44, 4,  36, 14, 46, 6,  38 },
+  { 60, 28, 52, 20, 62, 30, 54, 22 },
+  { 3,  35, 11, 43, 1,  33, 9,  41 },
+  { 51, 19, 59, 27, 49, 17, 57, 25 },
+  { 15, 47, 7,  39, 13, 45, 5,  37 },
+  { 63, 31, 55, 23, 61, 29, 53, 21 }
+};
+#endif
+
+static guint32 *DM_565 = NULL;
+
+static void
+xlib_rgb_preprocess_dm_565 (void)
+{
+  int i;
+  guint32 dith;
+
+  if (DM_565 == NULL)
+    {
+      DM_565 = malloc(sizeof(guint32) * DM_WIDTH * DM_HEIGHT);
+      for (i = 0; i < DM_WIDTH * DM_HEIGHT; i++)
+       {
+         dith = DM[0][i] >> 3;
+         DM_565[i] = (dith << 20) | dith | (((7 - dith) >> 1) << 10);
+#ifdef VERBOSE
+         printf ("%i %x %x\n", i, dith, DM_565[i]);
+#endif
+       }
+    }
+}
+
+static void
+xlib_rgb_convert_8_d666 (XImage *image,
+                       int ax, int ay, int width, int height,
+                       unsigned char *buf, int rowstride,
+                       int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  int x, y;
+  int bpl;
+  unsigned char *obuf, *obptr;
+  unsigned char *bptr, *bp2;
+  int r, g, b;
+  const unsigned char *dmp;
+  int dith;
+
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + ax;
+  for (y = 0; y < height; y++)
+    {
+      dmp = DM[(y_align + y) & (DM_HEIGHT - 1)];
+      bp2 = bptr;
+      obptr = obuf;
+      for (x = 0; x < width; x++)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         dith = (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) | 7;
+         r = ((r * 5) + dith) >> 8;
+         g = ((g * 5) + (262 - dith)) >> 8;
+         b = ((b * 5) + dith) >> 8;
+         obptr[0] = colorcube_d[(r << 6) | (g << 3) | b];
+         obptr++;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+static void
+xlib_rgb_convert_8_d (XImage *image,
+                    int ax, int ay, int width, int height,
+                    unsigned char *buf, int rowstride,
+                    int x_align, int y_align,
+                    XlibRgbCmap *cmap)
+{
+  int x, y;
+  int bpl;
+  unsigned char *obuf, *obptr;
+  unsigned char *bptr, *bp2;
+  int r, g, b;
+  const unsigned char *dmp;
+  int dith;
+  int rs, gs, bs;
+
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  rs = image_info->nred_shades - 1;
+  gs = image_info->ngreen_shades - 1;
+  bs = image_info->nblue_shades - 1;
+  obuf = ((unsigned char *)image->data) + ay * bpl + ax;
+  for (y = 0; y < height; y++)
+    {
+      dmp = DM[(y_align + y) & (DM_HEIGHT - 1)];
+      bp2 = bptr;
+      obptr = obuf;
+      for (x = 0; x < width; x++)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         dith = (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) | 7;
+         r = ((r * rs) + dith) >> 8;
+         g = ((g * gs) + (262 - dith)) >> 8;
+         b = ((b * bs) + dith) >> 8;
+         obptr[0] = colorcube_d[(r << 6) | (g << 3) | b];
+         obptr++;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+static void
+xlib_rgb_convert_8_indexed (XImage *image,
+                          int ax, int ay, int width, int height,
+                          unsigned char *buf, int rowstride,
+                          int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  int x, y;
+  int bpl;
+  unsigned char *obuf, *obptr;
+  unsigned char *bptr, *bp2;
+  unsigned char c;
+  unsigned char *lut;
+
+  lut = cmap->lut;
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + ax;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      obptr = obuf;
+      for (x = 0; x < width; x++)
+       {
+         c = *bp2++;
+         obptr[0] = lut[c];
+         obptr++;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+static void
+xlib_rgb_convert_gray8 (XImage *image,
+                      int ax, int ay, int width, int height,
+                      unsigned char *buf, int rowstride,
+                      int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  int x, y;
+  int bpl;
+  unsigned char *obuf, *obptr;
+  unsigned char *bptr, *bp2;
+  int r, g, b;
+
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + ax;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      obptr = obuf;
+      for (x = 0; x < width; x++)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         obptr[0] = (g + ((b + r) >> 1)) >> 1;
+         obptr++;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+static void
+xlib_rgb_convert_gray8_gray (XImage *image,
+                           int ax, int ay, int width, int height,
+                           unsigned char *buf, int rowstride,
+                           int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  int y;
+  int bpl;
+  unsigned char *obuf;
+  unsigned char *bptr;
+
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + ax;
+  for (y = 0; y < height; y++)
+    {
+      memcpy (obuf, bptr, (unsigned int)width);
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define HAIRY_CONVERT_565
+#endif
+
+#ifdef HAIRY_CONVERT_565
+/* Render a 24-bit RGB image in buf into the GdkImage, without dithering.
+   This assumes native byte ordering - what should really be done is to
+   check whether static_image->byte_order is consistent with the _ENDIAN
+   config flag, and if not, use a different function.
+
+   This one is even faster than the one below - its inner loop loads 3
+   words (i.e. 4 24-bit pixels), does a lot of shifting and masking,
+   then writes 2 words. */
+static void
+xlib_rgb_convert_565 (XImage *image,
+                    int ax, int ay, int width, int height,
+                    unsigned char *buf, int rowstride,
+                    int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  int x, y;
+  unsigned char *obuf, *obptr;
+  int bpl;
+  unsigned char *bptr, *bp2;
+  unsigned char r, g, b;
+
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + ax * 2;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      obptr = obuf;
+      if (((unsigned long)obuf | (unsigned long) bp2) & 3)
+       {
+         for (x = 0; x < width; x++)
+           {
+             r = *bp2++;
+             g = *bp2++;
+             b = *bp2++;
+             ((guint16 *)obptr)[0] = ((r & 0xf8) << 8) |
+               ((g & 0xfc) << 3) |
+               (b >> 3);
+             obptr += 2;
+           }
+       }
+      else
+       {
+         for (x = 0; x < width - 3; x += 4)
+           {
+             guint32 r1b0g0r0;
+             guint32 g2r2b1g1;
+             guint32 b3g3r3b2;
+
+             r1b0g0r0 = ((guint32 *)bp2)[0];
+             g2r2b1g1 = ((guint32 *)bp2)[1];
+             b3g3r3b2 = ((guint32 *)bp2)[2];
+             ((guint32 *)obptr)[0] =
+               ((r1b0g0r0 & 0xf8) << 8) |
+               ((r1b0g0r0 & 0xfc00) >> 5) |
+               ((r1b0g0r0 & 0xf80000) >> 19) |
+               (r1b0g0r0 & 0xf8000000) |
+               ((g2r2b1g1 & 0xfc) << 19) |
+               ((g2r2b1g1 & 0xf800) << 5);
+             ((guint32 *)obptr)[1] =
+               ((g2r2b1g1 & 0xf80000) >> 8) |
+               ((g2r2b1g1 & 0xfc000000) >> 21) |
+               ((b3g3r3b2 & 0xf8) >> 3) |
+               ((b3g3r3b2 & 0xf800) << 16) |
+               ((b3g3r3b2 & 0xfc0000) << 3) |
+               ((b3g3r3b2 & 0xf8000000) >> 11);
+             bp2 += 12;
+             obptr += 8;
+           }
+         for (; x < width; x++)
+           {
+             r = *bp2++;
+             g = *bp2++;
+             b = *bp2++;
+             ((guint16 *)obptr)[0] = ((r & 0xf8) << 8) |
+               ((g & 0xfc) << 3) |
+               (b >> 3);
+             obptr += 2;
+           }
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+#else
+/* Render a 24-bit RGB image in buf into the GdkImage, without dithering.
+   This assumes native byte ordering - what should really be done is to
+   check whether static_image->byte_order is consistent with the _ENDIAN
+   config flag, and if not, use a different function.
+
+   This routine is faster than the one included with Gtk 1.0 for a number
+   of reasons:
+
+   1. Shifting instead of lookup tables (less memory traffic).
+
+   2. Much less register pressure, especially because shifts are
+   in the code.
+
+   3. A memcpy is avoided (i.e. the transfer function).
+
+   4. On big-endian architectures, byte swapping is avoided.
+
+   That said, it wouldn't be hard to make it even faster - just make an
+   inner loop that reads 3 words (i.e. 4 24-bit pixels), does a lot of
+   shifting and masking, then writes 2 words.
+*/
+static void
+xlib_rgb_convert_565 (XImage *image,
+                    int ax, int ay, int width, int height,
+                    unsigned char *buf, int rowstride,
+                    int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  int x, y;
+  unsigned char *obuf;
+  int bpl;
+  unsigned char *bptr, *bp2;
+  unsigned char r, g, b;
+
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + ax * 2;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      for (x = 0; x < width; x++)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         ((unsigned short *)obuf)[x] = ((r & 0xf8) << 8) |
+           ((g & 0xfc) << 3) |
+           (b >> 3);
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+#endif
+
+#ifdef HAIRY_CONVERT_565
+static void
+xlib_rgb_convert_565_gray (XImage *image,
+                         int ax, int ay, int width, int height,
+                         unsigned char *buf, int rowstride,
+                         int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  int x, y;
+  unsigned char *obuf, *obptr;
+  int bpl;
+  unsigned char *bptr, *bp2;
+  unsigned char g;
+
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + ax * 2;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      obptr = obuf;
+      if (((unsigned long)obuf | (unsigned long) bp2) & 3)
+       {
+         for (x = 0; x < width; x++)
+           {
+             g = *bp2++;
+             ((guint16 *)obptr)[0] = ((g & 0xf8) << 8) |
+               ((g & 0xfc) << 3) |
+               (g >> 3);
+             obptr += 2;
+           }
+       }
+      else
+       {
+         for (x = 0; x < width - 3; x += 4)
+           {
+             guint32 g3g2g1g0;
+
+             g3g2g1g0 = ((guint32 *)bp2)[0];
+             ((guint32 *)obptr)[0] =
+               ((g3g2g1g0 & 0xf8) << 8) |
+               ((g3g2g1g0 & 0xfc) << 3) |
+               ((g3g2g1g0 & 0xf8) >> 3) |
+               (g3g2g1g0 & 0xf800) << 16 |
+               ((g3g2g1g0 & 0xfc00) << 11) |
+               ((g3g2g1g0 & 0xf800) << 5);
+             ((guint32 *)obptr)[1] =
+               ((g3g2g1g0 & 0xf80000) >> 8) |
+               ((g3g2g1g0 & 0xfc0000) >> 13) |
+               ((g3g2g1g0 & 0xf80000) >> 19) |
+               (g3g2g1g0 & 0xf8000000) |
+               ((g3g2g1g0 & 0xfc000000) >> 5) |
+               ((g3g2g1g0 & 0xf8000000) >> 11);
+             bp2 += 4;
+             obptr += 8;
+           }
+         for (; x < width; x++)
+           {
+             g = *bp2++;
+             ((guint16 *)obptr)[0] = ((g & 0xf8) << 8) |
+               ((g & 0xfc) << 3) |
+               (g >> 3);
+             obptr += 2;
+           }
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+#else
+static void
+xlib_rgb_convert_565_gray (XImage *image,
+                         int ax, int ay, int width, int height,
+                         unsigned char *buf, int rowstride,
+                         int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  int x, y;
+  unsigned char *obuf;
+  int bpl;
+  unsigned char *bptr, *bp2;
+  unsigned char g;
+
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + ax * 2;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      for (x = 0; x < width; x++)
+       {
+         g = *bp2++;
+         ((guint16 *)obuf)[x] = ((g & 0xf8) << 8) |
+           ((g & 0xfc) << 3) |
+           (g >> 3);
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+#endif
+
+static void
+xlib_rgb_convert_565_br (XImage *image,
+                        int ax, int ay, int width, int height,
+                        unsigned char *buf, int rowstride,
+                        int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  int x, y;
+  unsigned char *obuf;
+  int bpl;
+  unsigned char *bptr, *bp2;
+  unsigned char r, g, b;
+
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + ax * 2;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      for (x = 0; x < width; x++)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         /* final word is:
+            g4 g3 g2 b7 b6 b5 b4 b3  r7 r6 r5 r4 r3 g7 g6 g5
+          */
+         ((unsigned short *)obuf)[x] = (r & 0xf8) |
+           ((g & 0xe0) >> 5) |
+           ((g & 0x1c) << 11) |
+           ((b & 0xf8) << 5);
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+/* Thanks to Ray Lehtiniemi for a patch that resulted in a ~25% speedup
+   in this mode. */
+#ifdef HAIRY_CONVERT_565
+static void
+xlib_rgb_convert_565_d (XImage *image,
+                    int ax, int ay, int width, int height,
+                    unsigned char *buf, int rowstride,
+                    int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  /* Now this is what I'd call some highly tuned code! */
+  int x, y;
+  unsigned char *obuf, *obptr;
+  int bpl;
+  unsigned char *bptr, *bp2;
+
+  width += x_align;
+  height += y_align;
+  
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + ax * 2;
+  for (y = y_align; y < height; y++)
+    {
+      guint32 *dmp = DM_565 + ((y & (DM_HEIGHT - 1)) << DM_WIDTH_SHIFT);
+      bp2 = bptr;
+      obptr = obuf;
+      if (((unsigned long)obuf | (unsigned long) bp2) & 3)
+       {
+         for (x = x_align; x < width; x++)
+           {
+             gint32 rgb = *bp2++ << 20;
+             rgb += *bp2++ << 10;
+             rgb += *bp2++;
+             rgb += dmp[x & (DM_WIDTH - 1)];
+             rgb += 0x10040100
+               - ((rgb & 0x1e0001e0) >> 5)
+               - ((rgb & 0x00070000) >> 6);
+
+             ((unsigned short *)obptr)[0] =
+               ((rgb & 0x0f800000) >> 12) |
+               ((rgb & 0x0003f000) >> 7) |
+               ((rgb & 0x000000f8) >> 3);
+             obptr += 2;
+           }
+       }
+      else
+       {
+         for (x = x_align; x < width - 3; x += 4)
+           {
+             guint32 r1b0g0r0;
+             guint32 g2r2b1g1;
+             guint32 b3g3r3b2;
+             guint32 rgb02, rgb13;
+
+             r1b0g0r0 = ((guint32 *)bp2)[0];
+             g2r2b1g1 = ((guint32 *)bp2)[1];
+             b3g3r3b2 = ((guint32 *)bp2)[2];
+             rgb02 =
+               ((r1b0g0r0 & 0xff) << 20) +
+               ((r1b0g0r0 & 0xff00) << 2) +
+               ((r1b0g0r0 & 0xff0000) >> 16) +
+               dmp[x & (DM_WIDTH - 1)];
+             rgb02 += 0x10040100
+               - ((rgb02 & 0x1e0001e0) >> 5)
+               - ((rgb02 & 0x00070000) >> 6);
+             rgb13 =
+               ((r1b0g0r0 & 0xff000000) >> 4) +
+               ((g2r2b1g1 & 0xff) << 10) +
+               ((g2r2b1g1 & 0xff00) >> 8) +
+               dmp[(x + 1) & (DM_WIDTH - 1)];
+             rgb13 += 0x10040100
+               - ((rgb13 & 0x1e0001e0) >> 5)
+               - ((rgb13 & 0x00070000) >> 6);
+             ((guint32 *)obptr)[0] =
+               ((rgb02 & 0x0f800000) >> 12) |
+               ((rgb02 & 0x0003f000) >> 7) |
+               ((rgb02 & 0x000000f8) >> 3) |
+               ((rgb13 & 0x0f800000) << 4) |
+               ((rgb13 & 0x0003f000) << 9) |
+               ((rgb13 & 0x000000f8) << 13);
+             rgb02 =
+               ((g2r2b1g1 & 0xff0000) << 4) +
+               ((g2r2b1g1 & 0xff000000) >> 14) +
+               (b3g3r3b2 & 0xff) +
+               dmp[(x + 2) & (DM_WIDTH - 1)];
+             rgb02 += 0x10040100
+               - ((rgb02 & 0x1e0001e0) >> 5)
+               - ((rgb02 & 0x00070000) >> 6);
+             rgb13 =
+               ((b3g3r3b2 & 0xff00) << 12) +
+               ((b3g3r3b2 & 0xff0000) >> 6) +
+               ((b3g3r3b2 & 0xff000000) >> 24) +
+               dmp[(x + 3) & (DM_WIDTH - 1)];
+             rgb13 += 0x10040100
+               - ((rgb13 & 0x1e0001e0) >> 5)
+               - ((rgb13 & 0x00070000) >> 6);
+             ((guint32 *)obptr)[1] =
+               ((rgb02 & 0x0f800000) >> 12) |
+               ((rgb02 & 0x0003f000) >> 7) |
+               ((rgb02 & 0x000000f8) >> 3) |
+               ((rgb13 & 0x0f800000) << 4) |
+               ((rgb13 & 0x0003f000) << 9) |
+               ((rgb13 & 0x000000f8) << 13);
+             bp2 += 12;
+             obptr += 8;
+           }
+         for (; x < width; x++)
+           {
+             gint32 rgb = *bp2++ << 20;
+             rgb += *bp2++ << 10;
+             rgb += *bp2++;
+             rgb += dmp[x & (DM_WIDTH - 1)];
+             rgb += 0x10040100
+               - ((rgb & 0x1e0001e0) >> 5)
+               - ((rgb & 0x00070000) >> 6);
+
+             ((unsigned short *)obptr)[0] =
+               ((rgb & 0x0f800000) >> 12) |
+               ((rgb & 0x0003f000) >> 7) |
+               ((rgb & 0x000000f8) >> 3);
+             obptr += 2;
+           }
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+#else
+static void
+xlib_rgb_convert_565_d (XImage *image,
+                       int ax, int ay, int width, int height,
+                       unsigned char *buf, int rowstride,
+                       int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  int x, y;
+  unsigned char *obuf;
+  int bpl;
+  unsigned char *bptr;
+
+  width += x_align;
+  height += y_align;
+  
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + (ax - x_align) * 2;
+
+  for (y = y_align; y < height; y++)
+    {
+      guint32 *dmp = DM_565 + ((y & (DM_HEIGHT - 1)) << DM_WIDTH_SHIFT);
+      unsigned char *bp2 = bptr;
+
+      for (x = x_align; x < width; x++)
+        {
+          gint32 rgb = *bp2++ << 20;
+          rgb += *bp2++ << 10;
+          rgb += *bp2++;
+         rgb += dmp[x & (DM_WIDTH - 1)];
+          rgb += 0x10040100
+            - ((rgb & 0x1e0001e0) >> 5)
+            - ((rgb & 0x00070000) >> 6);
+
+          ((unsigned short *)obuf)[x] =
+            ((rgb & 0x0f800000) >> 12) |
+            ((rgb & 0x0003f000) >> 7) |
+            ((rgb & 0x000000f8) >> 3);
+        }
+
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+#endif
+
+static void
+xlib_rgb_convert_555 (XImage *image,
+                    int ax, int ay, int width, int height,
+                    unsigned char *buf, int rowstride,
+                    int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  int x, y;
+  unsigned char *obuf;
+  int bpl;
+  unsigned char *bptr, *bp2;
+  unsigned char r, g, b;
+
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + ax * 2;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      for (x = 0; x < width; x++)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         ((unsigned short *)obuf)[x] = ((r & 0xf8) << 7) |
+           ((g & 0xf8) << 2) |
+           (b >> 3);
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+static void
+xlib_rgb_convert_555_br (XImage *image,
+                       int ax, int ay, int width, int height,
+                       unsigned char *buf, int rowstride,
+                       int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  int x, y;
+  unsigned char *obuf;
+  int bpl;
+  unsigned char *bptr, *bp2;
+  unsigned char r, g, b;
+
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + ax * 2;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      for (x = 0; x < width; x++)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         /* final word is:
+            g5 g4 g3 b7 b6 b5 b4 b3  0 r7 r6 r5 r4 r3 g7 g6
+          */
+         ((unsigned short *)obuf)[x] = ((r & 0xf8) >> 1) |
+           ((g & 0xc0) >> 6) |
+           ((g & 0x18) << 10) |
+           ((b & 0xf8) << 5);
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+static void
+xlib_rgb_convert_888_msb (XImage *image,
+                        int ax, int ay, int width, int height,
+                        unsigned char *buf, int rowstride,
+                        int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  int y;
+  unsigned char *obuf;
+  int bpl;
+  unsigned char *bptr;
+
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + ax * 3;
+  for (y = 0; y < height; y++)
+    {
+      memcpy (obuf, bptr, (unsigned int)(width + width + width));
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+/* todo: optimize this */
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define HAIRY_CONVERT_888
+#endif
+
+#ifdef HAIRY_CONVERT_888
+static void
+xlib_rgb_convert_888_lsb (XImage *image,
+                         int ax, int ay, int width, int height,
+                         unsigned char *buf, int rowstride,
+                         int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  int x, y;
+  unsigned char *obuf, *obptr;
+  int bpl;
+  unsigned char *bptr, *bp2;
+  int r, g, b;
+
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + ax * 3;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      obptr = obuf;
+      if (((unsigned long)obuf | (unsigned long) bp2) & 3)
+       {
+         for (x = 0; x < width; x++)
+           {
+             r = bp2[0];
+             g = bp2[1];
+             b = bp2[2];
+             *obptr++ = b;
+             *obptr++ = g;
+             *obptr++ = r;
+             bp2 += 3;
+           }
+       }
+      else
+       {
+         for (x = 0; x < width - 3; x += 4)
+           {
+             guint32 r1b0g0r0;
+             guint32 g2r2b1g1;
+             guint32 b3g3r3b2;
+
+             r1b0g0r0 = ((guint32 *)bp2)[0];
+             g2r2b1g1 = ((guint32 *)bp2)[1];
+             b3g3r3b2 = ((guint32 *)bp2)[2];
+             ((guint32 *)obptr)[0] =
+               (r1b0g0r0 & 0xff00) |
+               ((r1b0g0r0 & 0xff0000) >> 16) |
+               (((g2r2b1g1 & 0xff00) | (r1b0g0r0 & 0xff)) << 16);
+             ((guint32 *)obptr)[1] =
+               (g2r2b1g1 & 0xff0000ff) |
+               ((r1b0g0r0 & 0xff000000) >> 16) |
+               ((b3g3r3b2 & 0xff) << 16);
+             ((guint32 *)obptr)[2] =
+               (((g2r2b1g1 & 0xff0000) | (b3g3r3b2 & 0xff000000)) >> 16) |
+               ((b3g3r3b2 & 0xff00) << 16) |
+               ((b3g3r3b2 & 0xff0000));
+             bp2 += 12;
+             obptr += 12;
+           }
+         for (; x < width; x++)
+           {
+             r = bp2[0];
+             g = bp2[1];
+             b = bp2[2];
+             *obptr++ = b;
+             *obptr++ = g;
+             *obptr++ = r;
+             bp2 += 3;
+           }
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+#else
+static void
+xlib_rgb_convert_888_lsb (XImage *image,
+                        int ax, int ay, int width, int height,
+                        unsigned char *buf, int rowstride,
+                        int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  int x, y;
+  unsigned char *obuf;
+  int bpl;
+  unsigned char *bptr, *bp2;
+  int r, g, b;
+
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + ax * 3;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      for (x = 0; x < width; x++)
+       {
+         r = bp2[0];
+         g = bp2[1];
+         b = bp2[2];
+         obuf[x * 3] = b;
+         obuf[x * 3 + 1] = g;
+         obuf[x * 3 + 2] = r;
+         bp2 += 3;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+#endif
+
+/* convert 24-bit packed to 32-bit unpacked */
+/* todo: optimize this */
+static void
+xlib_rgb_convert_0888 (XImage *image,
+                     int ax, int ay, int width, int height,
+                     unsigned char *buf, int rowstride,
+                     int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  int x, y;
+  unsigned char *obuf;
+  int bpl;
+  unsigned char *bptr, *bp2;
+  int r, g, b;
+
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + ax * 4;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      for (x = 0; x < width; x++)
+       {
+         r = bp2[0];
+         g = bp2[1];
+         b = bp2[2];
+         ((guint32 *)obuf)[x] = (r << 16) | (g << 8) | b;
+         bp2 += 3;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+static void
+xlib_rgb_convert_0888_br (XImage *image,
+                        int ax, int ay, int width, int height,
+                        unsigned char *buf, int rowstride,
+                        int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  int x, y;
+  unsigned char *obuf;
+  int bpl;
+  unsigned char *bptr, *bp2;
+  int r, g, b;
+
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + ax * 4;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      for (x = 0; x < width; x++)
+       {
+         r = bp2[0];
+         g = bp2[1];
+         b = bp2[2];
+         ((guint32 *)obuf)[x] = (b << 24) | (g << 16) | (r << 8);
+         bp2 += 3;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+static void
+xlib_rgb_convert_8880_br (XImage *image,
+                        int ax, int ay, int width, int height,
+                        unsigned char *buf, int rowstride,
+                        int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  int x, y;
+  unsigned char *obuf;
+  int bpl;
+  unsigned char *bptr, *bp2;
+  int r, g, b;
+
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + ax * 4;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      for (x = 0; x < width; x++)
+       {
+         r = bp2[0];
+         g = bp2[1];
+         b = bp2[2];
+         ((guint32 *)obuf)[x] = (b << 16) | (g << 8) | r;
+         bp2 += 3;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+/* Generic truecolor/directcolor conversion function. Slow, but these
+   are oddball modes. */
+static void
+xlib_rgb_convert_truecolor_lsb (XImage *image,
+                              int ax, int ay, int width, int height,
+                              unsigned char *buf, int rowstride,
+                              int x_align, int y_align,
+                              XlibRgbCmap *cmap)
+{
+  int x, y;
+  unsigned char *obuf, *obptr;
+  int bpl;
+  unsigned char *bptr, *bp2;
+  int r, g, b;
+  int r_right, r_left;
+  int g_right, g_left;
+  int b_right, b_left;
+  int bpp;
+  guint32 pixel;
+  int i;
+
+  r_right = 8 - image_info->red_prec;
+  r_left = image_info->red_shift;
+  g_right = 8 - image_info->green_prec;
+  g_left = image_info->green_shift;
+  b_right = 8 - image_info->blue_prec;
+  b_left = image_info->blue_shift;
+  bpp = image_info->bpp;
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + ax * bpp;
+  for (y = 0; y < height; y++)
+    {
+      obptr = obuf;
+      bp2 = bptr;
+      for (x = 0; x < width; x++)
+       {
+         r = bp2[0];
+         g = bp2[1];
+         b = bp2[2];
+         pixel = ((r >> r_right) << r_left) |
+           ((g >> g_right) << g_left) |
+           ((b >> b_right) << b_left);
+         for (i = 0; i < bpp; i++)
+           {
+             *obptr++ = pixel & 0xff;
+             pixel >>= 8;
+           }
+         bp2 += 3;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+static void
+xlib_rgb_convert_truecolor_lsb_d (XImage *image,
+                                int ax, int ay, int width, int height,
+                                unsigned char *buf, int rowstride,
+                                int x_align, int y_align,
+                                XlibRgbCmap *cmap)
+{
+  int x, y;
+  unsigned char *obuf, *obptr;
+  int bpl;
+  unsigned char *bptr, *bp2;
+  int r, g, b;
+  int r_right, r_left, r_prec;
+  int g_right, g_left, g_prec;
+  int b_right, b_left, b_prec;
+  int bpp;
+  guint32 pixel;
+  int i;
+  int dith;
+  int r1, g1, b1;
+  const unsigned char *dmp;
+
+  r_right = 8 - image_info->red_prec;
+  r_left = image_info->red_shift;
+  r_prec = image_info->red_prec;
+  g_right = 8 - image_info->green_prec;
+  g_left = image_info->green_shift;
+  g_prec = image_info->green_prec;
+  b_right = 8 - image_info->blue_prec;
+  b_left = image_info->blue_shift;
+  b_prec = image_info->blue_prec;
+  bpp = image_info->bpp;
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + ax * bpp;
+  for (y = 0; y < height; y++)
+    {
+      dmp = DM[(y_align + y) & (DM_HEIGHT - 1)];
+      obptr = obuf;
+      bp2 = bptr;
+      for (x = 0; x < width; x++)
+       {
+         r = bp2[0];
+         g = bp2[1];
+         b = bp2[2];
+         dith = dmp[(x_align + x) & (DM_WIDTH - 1)] << 2;
+         r1 = r + (dith >> r_prec);
+         g1 = g + ((252 - dith) >> g_prec);
+         b1 = b + (dith >> b_prec);
+         pixel = (((r1 - (r1 >> r_prec)) >> r_right) << r_left) |
+           (((g1 - (g1 >> g_prec)) >> g_right) << g_left) |
+           (((b1 - (b1 >> b_prec)) >> b_right) << b_left);
+         for (i = 0; i < bpp; i++)
+           {
+             *obptr++ = pixel & 0xff;
+             pixel >>= 8;
+           }
+         bp2 += 3;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+static void
+xlib_rgb_convert_truecolor_msb (XImage *image,
+                              int ax, int ay, int width, int height,
+                              unsigned char *buf, int rowstride,
+                              int x_align, int y_align,
+                              XlibRgbCmap *cmap)
+{
+  int x, y;
+  unsigned char *obuf, *obptr;
+  int bpl;
+  unsigned char *bptr, *bp2;
+  int r, g, b;
+  int r_right, r_left;
+  int g_right, g_left;
+  int b_right, b_left;
+  int bpp;
+  guint32 pixel;
+  int shift, shift_init;
+
+  r_right = 8 - image_info->red_prec;
+  r_left = image_info->red_shift;
+  g_right = 8 - image_info->green_prec;
+  g_left = image_info->green_shift;
+  b_right = 8 - image_info->blue_prec;
+  b_left = image_info->blue_shift;
+  bpp = image_info->bpp;
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + ax * bpp;
+  shift_init = (bpp - 1) << 3;
+  for (y = 0; y < height; y++)
+    {
+      obptr = obuf;
+      bp2 = bptr;
+      for (x = 0; x < width; x++)
+       {
+         r = bp2[0];
+         g = bp2[1];
+         b = bp2[2];
+         pixel = ((r >> r_right) << r_left) |
+           ((g >> g_right) << g_left) |
+           ((b >> b_right) << b_left);
+         for (shift = shift_init; shift >= 0; shift -= 8)
+           {
+             *obptr++ = (pixel >> shift) & 0xff;
+           }
+         bp2 += 3;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+static void
+xlib_rgb_convert_truecolor_msb_d (XImage *image,
+                                int ax, int ay, int width, int height,
+                                unsigned char *buf, int rowstride,
+                                int x_align, int y_align,
+                                XlibRgbCmap *cmap)
+{
+  int x, y;
+  unsigned char *obuf, *obptr;
+  int bpl;
+  unsigned char *bptr, *bp2;
+  int r, g, b;
+  int r_right, r_left, r_prec;
+  int g_right, g_left, g_prec;
+  int b_right, b_left, b_prec;
+  int bpp;
+  guint32 pixel;
+  int shift, shift_init;
+  int dith;
+  int r1, g1, b1;
+  const unsigned char *dmp;
+
+  r_right = 8 - image_info->red_prec;
+  r_left = image_info->red_shift;
+  r_prec = image_info->red_prec;
+  g_right = 8 - image_info->green_prec;
+  g_left = image_info->green_shift;
+  g_prec = image_info->green_prec;
+  b_right = 8 - image_info->blue_prec;
+  b_left = image_info->blue_shift;
+  b_prec = image_info->blue_prec;
+  bpp = image_info->bpp;
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + ax * bpp;
+  shift_init = (bpp - 1) << 3;
+  for (y = 0; y < height; y++)
+    {
+      dmp = DM[(y_align + y) & (DM_HEIGHT - 1)];
+      obptr = obuf;
+      bp2 = bptr;
+      for (x = 0; x < width; x++)
+       {
+         r = bp2[0];
+         g = bp2[1];
+         b = bp2[2];
+         dith = dmp[(x_align + x) & (DM_WIDTH - 1)] << 2;
+         r1 = r + (dith >> r_prec);
+         g1 = g + ((252 - dith) >> g_prec);
+         b1 = b + (dith >> b_prec);
+         pixel = (((r1 - (r1 >> r_prec)) >> r_right) << r_left) |
+           (((g1 - (g1 >> g_prec)) >> g_right) << g_left) |
+           (((b1 - (b1 >> b_prec)) >> b_right) << b_left);
+         for (shift = shift_init; shift >= 0; shift -= 8)
+           {
+             *obptr++ = (pixel >> shift) & 0xff;
+           }
+         bp2 += 3;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+/* This actually works for depths from 3 to 7 */
+static void
+xlib_rgb_convert_4 (XImage *image,
+                  int ax, int ay, int width, int height,
+                  unsigned char *buf, int rowstride,
+                  int x_align, int y_align,
+                  XlibRgbCmap *cmap)
+{
+  int x, y;
+  int bpl;
+  unsigned char *obuf, *obptr;
+  unsigned char *bptr, *bp2;
+  int r, g, b;
+  const unsigned char *dmp;
+  int dith;
+
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + ax;
+  for (y = 0; y < height; y++)
+    {
+      dmp = DM[(y_align + y) & (DM_HEIGHT - 1)];
+      bp2 = bptr;
+      obptr = obuf;
+      for (x = 0; x < width; x += 1)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         dith = (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) | 3;
+         obptr[0] = colorcube_d[(((r + dith) & 0x100) >> 2) |
+                               (((g + 258 - dith) & 0x100) >> 5) |
+                               (((b + dith) & 0x100) >> 8)];
+         obptr++;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+/* This actually works for depths from 3 to 7 */
+static void
+xlib_rgb_convert_gray4 (XImage *image,
+                      int ax, int ay, int width, int height,
+                      unsigned char *buf, int rowstride,
+                      int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  int x, y;
+  int bpl;
+  unsigned char *obuf, *obptr;
+  unsigned char *bptr, *bp2;
+  int r, g, b;
+  int shift;
+
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + ax;
+  shift = 9 - image_info->x_visual_info->depth;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      obptr = obuf;
+      for (x = 0; x < width; x++)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         obptr[0] = (g + ((b + r) >> 1)) >> shift;
+         obptr++;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+static void
+xlib_rgb_convert_gray4_pack (XImage *image,
+                           int ax, int ay, int width, int height,
+                           unsigned char *buf, int rowstride,
+                           int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  int x, y;
+  int bpl;
+  unsigned char *obuf, *obptr;
+  unsigned char *bptr, *bp2;
+  int r, g, b;
+  int shift;
+  unsigned char pix0, pix1;
+  /* todo: this is hardcoded to big-endian. Make endian-agile. */
+
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + (ax >> 1);
+  shift = 9 - image_info->x_visual_info->depth;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      obptr = obuf;
+      for (x = 0; x < width; x += 2)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         pix0 = (g + ((b + r) >> 1)) >> shift;
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         pix1 = (g + ((b + r) >> 1)) >> shift;
+         obptr[0] = (pix0 << 4) | pix1;
+         obptr++;
+       }
+      if (width & 1)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         pix0 = (g + ((b + r) >> 1)) >> shift;
+         obptr[0] = (pix0 << 4);
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+/* This actually works for depths from 3 to 7 */
+static void
+xlib_rgb_convert_gray4_d (XImage *image,
+                      int ax, int ay, int width, int height,
+                      unsigned char *buf, int rowstride,
+                      int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  int x, y;
+  int bpl;
+  unsigned char *obuf, *obptr;
+  unsigned char *bptr, *bp2;
+  int r, g, b;
+  const unsigned char *dmp;
+  int prec, right;
+  int gray;
+
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + ax;
+  prec = image_info->x_visual_info->depth;
+  right = 8 - prec;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      obptr = obuf;
+      dmp = DM[(y_align + y) & (DM_HEIGHT - 1)];
+      for (x = 0; x < width; x++)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         gray = (g + ((b + r) >> 1)) >> 1;
+         gray += (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) >> prec;
+         obptr[0] = (gray - (gray >> prec)) >> right;
+         obptr++;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+static void
+xlib_rgb_convert_gray4_d_pack (XImage *image,
+                             int ax, int ay, int width, int height,
+                             unsigned char *buf, int rowstride,
+                             int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  int x, y;
+  int bpl;
+  unsigned char *obuf, *obptr;
+  unsigned char *bptr, *bp2;
+  int r, g, b;
+  const unsigned char *dmp;
+  int prec, right;
+  int gray;
+  unsigned char pix0, pix1;
+  /* todo: this is hardcoded to big-endian. Make endian-agile. */
+
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + (ax >> 1);
+  prec = image_info->x_visual_info->depth;
+  right = 8 - prec;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      obptr = obuf;
+      dmp = DM[(y_align + y) & (DM_HEIGHT - 1)];
+      for (x = 0; x < width; x += 2)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         gray = (g + ((b + r) >> 1)) >> 1;
+         gray += (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) >> prec;
+         pix0 = (gray - (gray >> prec)) >> right;
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         gray = (g + ((b + r) >> 1)) >> 1;
+         gray += (dmp[(x_align + x + 1) & (DM_WIDTH - 1)] << 2) >> prec;
+         pix1 = (gray - (gray >> prec)) >> right;
+         obptr[0] = (pix0 << 4) | pix1;
+         obptr++;
+       }
+      if (width & 1)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         gray = (g + ((b + r) >> 1)) >> 1;
+         gray += (dmp[(x_align + x + 1) & (DM_WIDTH - 1)] << 2) >> prec;
+         pix0 = (gray - (gray >> prec)) >> right;
+         obptr[0] = (pix0 << 4);
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+static void
+xlib_rgb_convert_1 (XImage *image,
+                  int ax, int ay, int width, int height,
+                  unsigned char *buf, int rowstride,
+                  int x_align, int y_align,
+                  XlibRgbCmap *cmap)
+{
+  int x, y;
+  int bpl;
+  unsigned char *obuf, *obptr;
+  unsigned char *bptr, *bp2;
+  int r, g, b;
+  const unsigned char *dmp;
+  int dith;
+  unsigned char byte;
+
+  bptr = buf;
+  bpl = image->bytes_per_line;
+  obuf = ((unsigned char *)image->data) + ay * bpl + (ax >> 3);
+  byte = 0; /* unnecessary, but it keeps gcc from complaining */
+  for (y = 0; y < height; y++)
+    {
+      dmp = DM[(y_align + y) & (DM_HEIGHT - 1)];
+      bp2 = bptr;
+      obptr = obuf;
+      for (x = 0; x < width; x++)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         dith = (dmp[(x_align + x) & (DM_WIDTH - 1)] << 4) | 4;
+         byte += byte + (r + g + g + b + dith > 1020);
+         if ((x & 7) == 7)
+           {
+             obptr[0] = byte;
+             obptr++;
+           }
+       }
+      if (x & 7)
+       obptr[0] = byte << (8 - (x & 7));
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+/* Returns a pointer to the stage buffer. */
+static unsigned char *
+xlib_rgb_ensure_stage (void)
+{
+  if (image_info->stage_buf == NULL)
+    image_info->stage_buf = malloc (IMAGE_HEIGHT * STAGE_ROWSTRIDE);
+  return image_info->stage_buf;
+}
+
+/* This is slow. Speed me up, please. */
+static void
+xlib_rgb_32_to_stage (unsigned char *buf, int rowstride, int width, int height)
+{
+  int x, y;
+  unsigned char *pi_start, *po_start;
+  unsigned char *pi, *po;
+
+  pi_start = buf;
+  po_start = xlib_rgb_ensure_stage ();
+  for (y = 0; y < height; y++)
+    {
+      pi = pi_start;
+      po = po_start;
+      for (x = 0; x < width; x++)
+       {
+         *po++ = *pi++;
+         *po++ = *pi++;
+         *po++ = *pi++;
+         pi++;
+       }
+      pi_start += rowstride;
+      po_start += STAGE_ROWSTRIDE;
+    }
+}
+
+/* Generic 32bit RGB conversion function - convert to 24bit packed, then
+   go from there. */
+static void
+xlib_rgb_convert_32_generic (XImage *image,
+                           int ax, int ay, int width, int height,
+                           unsigned char *buf, int rowstride,
+                           int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  xlib_rgb_32_to_stage (buf, rowstride, width, height);
+
+  (*image_info->conv) (image, ax, ay, width, height,
+                      image_info->stage_buf, STAGE_ROWSTRIDE,
+                      x_align, y_align, cmap);
+}
+
+/* Generic 32bit RGB conversion function - convert to 24bit packed, then
+   go from there. */
+static void
+xlib_rgb_convert_32_generic_d (XImage *image,
+                             int ax, int ay, int width, int height,
+                             unsigned char *buf, int rowstride,
+                             int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  xlib_rgb_32_to_stage (buf, rowstride, width, height);
+
+  (*image_info->conv_d) (image, ax, ay, width, height,
+                        image_info->stage_buf, STAGE_ROWSTRIDE,
+                        x_align, y_align, cmap);
+}
+
+/* This is slow. Speed me up, please. */
+static void
+xlib_rgb_gray_to_stage (unsigned char *buf, int rowstride, int width, int height)
+{
+  int x, y;
+  unsigned char *pi_start, *po_start;
+  unsigned char *pi, *po;
+  unsigned char gray;
+
+  pi_start = buf;
+  po_start = xlib_rgb_ensure_stage ();
+  for (y = 0; y < height; y++)
+    {
+      pi = pi_start;
+      po = po_start;
+      for (x = 0; x < width; x++)
+       {
+         gray = *pi++;
+         *po++ = gray;
+         *po++ = gray;
+         *po++ = gray;
+       }
+      pi_start += rowstride;
+      po_start += STAGE_ROWSTRIDE;
+    }
+}
+
+/* Generic gray conversion function - convert to 24bit packed, then go
+   from there. */
+static void
+xlib_rgb_convert_gray_generic (XImage *image,
+                             int ax, int ay, int width, int height,
+                             unsigned char *buf, int rowstride,
+                             int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  xlib_rgb_gray_to_stage (buf, rowstride, width, height);
+
+  (*image_info->conv) (image, ax, ay, width, height,
+                      image_info->stage_buf, STAGE_ROWSTRIDE,
+                      x_align, y_align, cmap);
+}
+
+static void
+xlib_rgb_convert_gray_generic_d (XImage *image,
+                               int ax, int ay, int width, int height,
+                               unsigned char *buf, int rowstride,
+                               int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  xlib_rgb_gray_to_stage (buf, rowstride, width, height);
+
+  (*image_info->conv_d) (image, ax, ay, width, height,
+                        image_info->stage_buf, STAGE_ROWSTRIDE,
+                        x_align, y_align, cmap);
+}
+
+/* Render grayscale using indexed method. */
+static void
+xlib_rgb_convert_gray_cmap (XImage *image,
+                          int ax, int ay, int width, int height,
+                          unsigned char *buf, int rowstride,
+                          int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  (*image_info->conv_indexed) (image, ax, ay, width, height,
+                              buf, rowstride,
+                              x_align, y_align, image_info->gray_cmap);
+}
+
+#if 0
+static void
+xlib_rgb_convert_gray_cmap_d (XImage *image,
+                               int ax, int ay, int width, int height,
+                               unsigned char *buf, int rowstride,
+                               int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  (*image_info->conv_indexed_d) (image, ax, ay, width, height,
+                                buf, rowstride,
+                                x_align, y_align, image_info->gray_cmap);
+}
+#endif
+
+/* This is slow. Speed me up, please. */
+static void
+xlib_rgb_indexed_to_stage (unsigned char *buf, int rowstride, int width, int height,
+                         XlibRgbCmap *cmap)
+{
+  int x, y;
+  unsigned char *pi_start, *po_start;
+  unsigned char *pi, *po;
+  int rgb;
+
+  pi_start = buf;
+  po_start = xlib_rgb_ensure_stage ();
+  for (y = 0; y < height; y++)
+    {
+      pi = pi_start;
+      po = po_start;
+      for (x = 0; x < width; x++)
+       {
+         rgb = cmap->colors[*pi++];
+         *po++ = rgb >> 16;
+         *po++ = (rgb >> 8) & 0xff;
+         *po++ = rgb & 0xff;
+       }
+      pi_start += rowstride;
+      po_start += STAGE_ROWSTRIDE;
+    }
+}
+
+/* Generic gray conversion function - convert to 24bit packed, then go
+   from there. */
+static void
+xlib_rgb_convert_indexed_generic (XImage *image,
+                                int ax, int ay, int width, int height,
+                                unsigned char *buf, int rowstride,
+                                int x_align, int y_align, XlibRgbCmap *cmap)
+{
+  xlib_rgb_indexed_to_stage (buf, rowstride, width, height, cmap);
+
+  (*image_info->conv) (image, ax, ay, width, height,
+                      image_info->stage_buf, STAGE_ROWSTRIDE,
+                      x_align, y_align, cmap);
+}
+
+static void
+xlib_rgb_convert_indexed_generic_d (XImage *image,
+                                  int ax, int ay, int width, int height,
+                                  unsigned char *buf, int rowstride,
+                                  int x_align, int y_align,
+                                  XlibRgbCmap *cmap)
+{
+  xlib_rgb_indexed_to_stage (buf, rowstride, width, height, cmap);
+
+  (*image_info->conv_d) (image, ax, ay, width, height,
+                        image_info->stage_buf, STAGE_ROWSTRIDE,
+                        x_align, y_align, cmap);
+}
+
+/* Select a conversion function based on the visual and a
+   representative image. */
+static void
+xlib_rgb_select_conv (XImage *image, ByteOrder byte_order)
+{
+  int depth, byterev;
+  int vtype; /* visual type */
+  int bpp; /* bits per pixel - from the visual */
+  guint32 red_mask, green_mask, blue_mask;
+  XlibRgbConvFunc conv, conv_d;
+  XlibRgbConvFunc conv_32, conv_32_d;
+  XlibRgbConvFunc conv_gray, conv_gray_d;
+  XlibRgbConvFunc conv_indexed, conv_indexed_d;
+  Bool mask_rgb, mask_bgr;
+
+  depth = image_info->x_visual_info->depth;
+  bpp = image->bits_per_pixel;
+  if (xlib_rgb_verbose)
+    printf ("Chose visual 0x%x, image bpp=%d, %s first\n",
+           (int)image_info->x_visual_info->visual->visualid,
+           bpp, byte_order == LSB_FIRST ? "lsb" : "msb");
+
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+  byterev = (byte_order == LSB_FIRST);
+#else
+  byterev = (byte_order == MSB_FIRST);
+#endif
+
+  vtype = image_info->x_visual_info->class;
+  if (vtype == DirectColor)
+    vtype = TrueColor;
+
+  red_mask = image_info->x_visual_info->red_mask;
+  green_mask = image_info->x_visual_info->green_mask;
+  blue_mask = image_info->x_visual_info->blue_mask;
+
+  mask_rgb = red_mask == 0xff0000 && green_mask == 0xff00 && blue_mask == 0xff;
+  mask_bgr = red_mask == 0xff && green_mask == 0xff00 && blue_mask == 0xff0000;
+
+  conv = NULL;
+  conv_d = NULL;
+
+  conv_32 = xlib_rgb_convert_32_generic;
+  conv_32_d = xlib_rgb_convert_32_generic_d;
+
+  conv_gray = xlib_rgb_convert_gray_generic;
+  conv_gray_d = xlib_rgb_convert_gray_generic_d;
+
+  conv_indexed = xlib_rgb_convert_indexed_generic;
+  conv_indexed_d = xlib_rgb_convert_indexed_generic_d;
+
+  image_info->dith_default = FALSE;
+
+  if (image_info->bitmap)
+    conv = xlib_rgb_convert_1;
+  else if (bpp == 16 && depth == 16 && !byterev &&
+      red_mask == 0xf800 && green_mask == 0x7e0 && blue_mask == 0x1f)
+    {
+      conv = xlib_rgb_convert_565;
+      conv_d = xlib_rgb_convert_565_d;
+      conv_gray = xlib_rgb_convert_565_gray;
+      xlib_rgb_preprocess_dm_565 ();
+    }
+  else if (bpp == 16 && depth == 16 &&
+          vtype == TrueColor&& byterev &&
+      red_mask == 0xf800 && green_mask == 0x7e0 && blue_mask == 0x1f)
+    conv = xlib_rgb_convert_565_br;
+
+  else if (bpp == 16 && depth == 15 &&
+          vtype == TrueColor && !byterev &&
+      red_mask == 0x7c00 && green_mask == 0x3e0 && blue_mask == 0x1f)
+    conv = xlib_rgb_convert_555;
+
+  else if (bpp == 16 && depth == 15 &&
+          vtype == TrueColor && byterev &&
+      red_mask == 0x7c00 && green_mask == 0x3e0 && blue_mask == 0x1f)
+    conv = xlib_rgb_convert_555_br;
+
+  /* I'm not 100% sure about the 24bpp tests - but testing will show*/
+  else if (bpp == 24 && depth == 24 && vtype == TrueColor &&
+          ((mask_rgb && byte_order == LSB_FIRST) ||
+           (mask_bgr && byte_order == MSB_FIRST)))
+    conv = xlib_rgb_convert_888_lsb;
+  else if (bpp == 24 && depth == 24 && vtype == TrueColor &&
+          ((mask_rgb && byte_order == MSB_FIRST) ||
+           (mask_bgr && byte_order == LSB_FIRST)))
+    conv = xlib_rgb_convert_888_msb;
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+  else if (bpp == 32 && depth == 24 && vtype == TrueColor &&
+          (mask_rgb && byte_order == LSB_FIRST))
+    conv = xlib_rgb_convert_0888_br;
+  else if (bpp == 32 && depth == 24 && vtype == TrueColor &&
+          (mask_rgb && byte_order == MSB_FIRST))
+    conv = xlib_rgb_convert_0888;
+  else if (bpp == 32 && depth == 24 && vtype == TrueColor &&
+          (mask_bgr && byte_order == MSB_FIRST))
+    conv = xlib_rgb_convert_8880_br;
+#else
+  else if (bpp == 32 && depth == 24 && vtype == TrueColor &&
+          (mask_rgb && byte_order == MSB_FIRST))
+    conv = xlib_rgb_convert_0888_br;
+  else if (bpp == 32 && (depth == 32 || depth == 24) && vtype == TrueColor &&
+          (mask_rgb && byte_order == LSB_FIRST))
+    conv = xlib_rgb_convert_0888;
+  else if (bpp == 32 && depth == 24 && vtype == TrueColor &&
+          (mask_bgr && byte_order == LSB_FIRST))
+    conv = xlib_rgb_convert_8880_br;
+#endif
+
+  else if (vtype == TrueColor && byte_order == LSB_FIRST)
+    {
+      conv = xlib_rgb_convert_truecolor_lsb;
+      conv_d = xlib_rgb_convert_truecolor_lsb_d;
+    }
+  else if (vtype == TrueColor && byte_order == MSB_FIRST)
+    {
+      conv = xlib_rgb_convert_truecolor_msb;
+      conv_d = xlib_rgb_convert_truecolor_msb_d;
+    }
+  else if (bpp == 8 && depth == 8 && (vtype == PseudoColor
+#ifdef ENABLE_GRAYSCALE
+                                     || vtype == GrayScale
+#endif
+                                     ))
+    {
+      image_info->dith_default = TRUE;
+      conv = xlib_rgb_convert_8;
+      if (vtype != GrayScale)
+       {
+         if (image_info->nred_shades == 6 &&
+             image_info->ngreen_shades == 6 &&
+             image_info->nblue_shades == 6)
+           conv_d = xlib_rgb_convert_8_d666;
+         else
+           conv_d = xlib_rgb_convert_8_d;
+       }
+      conv_indexed = xlib_rgb_convert_8_indexed;
+      conv_gray = xlib_rgb_convert_gray_cmap;
+    }
+  else if (bpp == 8 && depth == 8 && (vtype == StaticGray
+#ifdef not_ENABLE_GRAYSCALE
+                                     || vtype == GrayScale
+#endif
+                                     ))
+    {
+      conv = xlib_rgb_convert_gray8;
+      conv_gray = xlib_rgb_convert_gray8_gray;
+    }
+  else if (bpp == 8 && depth < 8 && depth >= 2 &&
+          (vtype == StaticGray
+           || vtype == GrayScale))
+    {
+      conv = xlib_rgb_convert_gray4;
+      conv_d = xlib_rgb_convert_gray4_d;
+    }
+  else if (bpp == 8 && depth < 8 && depth >= 3)
+    {
+      conv = xlib_rgb_convert_4;
+    }
+  else if (bpp == 4 && depth <= 4 && depth >= 2 &&
+          (vtype == StaticGray
+           || vtype == GrayScale))
+    {
+      conv = xlib_rgb_convert_gray4_pack;
+      conv_d = xlib_rgb_convert_gray4_d_pack;
+    }
+
+  if (conv_d == NULL)
+    conv_d = conv;
+
+  image_info->conv = conv;
+  image_info->conv_d = conv_d;
+
+  image_info->conv_32 = conv_32;
+  image_info->conv_32_d = conv_32_d;
+
+  image_info->conv_gray = conv_gray;
+  image_info->conv_gray_d = conv_gray_d;
+
+  image_info->conv_indexed = conv_indexed;
+  image_info->conv_indexed_d = conv_indexed_d;
+}
+
+static int horiz_idx;
+static int horiz_y = IMAGE_HEIGHT;
+static int vert_idx;
+static int vert_x = IMAGE_WIDTH;
+static int tile_idx;
+static int tile_x = IMAGE_WIDTH;
+static int tile_y1 = IMAGE_HEIGHT;
+static int tile_y2 = IMAGE_HEIGHT;
+
+#ifdef VERBOSE
+static int sincelast;
+#endif
+
+/* Defining NO_FLUSH can cause inconsistent screen updates, but is useful
+   for performance evaluation. */
+
+#undef NO_FLUSH
+
+static int
+xlib_rgb_alloc_scratch_image (void)
+{
+  if (static_image_idx == N_IMAGES)
+    {
+#ifndef NO_FLUSH
+      XFlush(image_info->display);
+#endif
+#ifdef VERBOSE
+      printf ("flush, %d puts since last flush\n", sincelast);
+      sincelast = 0;
+#endif
+      static_image_idx = 0;
+      horiz_y = IMAGE_HEIGHT;
+      vert_x = IMAGE_WIDTH;
+      tile_x = IMAGE_WIDTH;
+      tile_y1 = tile_y2 = IMAGE_HEIGHT;
+    }
+  return static_image_idx++;
+}
+
+static XImage *
+xlib_rgb_alloc_scratch (int width, int height, int *ax, int *ay)
+{
+  XImage *image;
+  int idx;
+
+  if (width >= (IMAGE_WIDTH >> 1))
+    {
+      if (height >= (IMAGE_HEIGHT >> 1))
+       {
+         idx = xlib_rgb_alloc_scratch_image ();
+         *ax = 0;
+         *ay = 0;
+       }
+      else
+       {
+         if (height + horiz_y > IMAGE_HEIGHT)
+           {
+             horiz_idx = xlib_rgb_alloc_scratch_image ();
+             horiz_y = 0;
+           }
+         idx = horiz_idx;
+         *ax = 0;
+         *ay = horiz_y;
+         horiz_y += height;
+       }
+    }
+  else
+    {
+      if (height >= (IMAGE_HEIGHT >> 1))
+       {
+         if (width + vert_x > IMAGE_WIDTH)
+           {
+             vert_idx = xlib_rgb_alloc_scratch_image ();
+             vert_x = 0;
+           }
+         idx = vert_idx;
+         *ax = vert_x;
+         *ay = 0;
+         /* using 3 and -4 would be slightly more efficient on 32-bit machines
+            with > 1bpp displays */
+         vert_x += (width + 7) & -8;
+       }
+      else
+       {
+         if (width + tile_x > IMAGE_WIDTH)
+           {
+             tile_y1 = tile_y2;
+             tile_x = 0;
+           }
+         if (height + tile_y1 > IMAGE_HEIGHT)
+           {
+             tile_idx = xlib_rgb_alloc_scratch_image ();
+             tile_x = 0;
+             tile_y1 = 0;
+             tile_y2 = 0;
+           }
+         if (height + tile_y1 > tile_y2)
+           tile_y2 = height + tile_y1;
+         idx = tile_idx;
+         *ax = tile_x;
+         *ay = tile_y1;
+         tile_x += (width + 7) & -8;
+       }
+    }
+  image = static_image[idx];
+#ifdef VERBOSE
+  printf ("index %d, x %d, y %d (%d x %d)\n", idx, *ax, *ay, width, height);
+  sincelast++;
+#endif
+  return image;
+}
+
+static void
+xlib_draw_rgb_image_core (Drawable drawable,
+                         GC gc,
+                         int x,
+                         int y,
+                         int width,
+                         int height,
+                         unsigned char *buf,
+                         int pixstride,
+                         int rowstride,
+                         XlibRgbConvFunc conv,
+                         XlibRgbCmap *cmap,
+                         int xdith,
+                         int ydith)
+{
+  int ay, ax;
+  int xs0, ys0;
+  XImage *image;
+  int width1, height1;
+  unsigned char *buf_ptr;
+
+  if (image_info->bitmap)
+    {
+      if (image_info->own_gc == 0)
+       {
+         XColor color;
+
+         image_info->own_gc = XCreateGC(image_info->display,
+                                        drawable,
+                                        0, NULL);
+         color.pixel = WhitePixel(image_info->display,
+                                  image_info->screen_num);
+         XSetForeground(image_info->display, image_info->own_gc, color.pixel);
+         color.pixel = BlackPixel(image_info->display,
+                                  image_info->screen_num);
+         XSetBackground(image_info->display, image_info->own_gc, color.pixel);
+       }
+      gc = image_info->own_gc;
+    }
+  for (ay = 0; ay < height; ay += IMAGE_HEIGHT)
+    {
+      height1 = MIN (height - ay, IMAGE_HEIGHT);
+      for (ax = 0; ax < width; ax += IMAGE_WIDTH)
+       {
+         width1 = MIN (width - ax, IMAGE_WIDTH);
+         buf_ptr = buf + ay * rowstride + ax * pixstride;
+
+         image = xlib_rgb_alloc_scratch (width1, height1, &xs0, &ys0);
+
+         conv (image, xs0, ys0, width1, height1, buf_ptr, rowstride,
+               x + ax + xdith, y + ay + ydith, cmap);
+
+#ifndef DONT_ACTUALLY_DRAW
+         XPutImage(image_info->display, drawable, gc, image,
+                   xs0, ys0, x + ax, y + ay, (unsigned int)width1, (unsigned int)height1);
+#endif
+       }
+    }
+}
+
+
+/**
+ * xlib_draw_rgb_image:
+ * @drawable: Destination drawable.
+ * @gc: A graphic context.
+ * @x: Leftmost coordinate of the destination rectangle.
+ * @y: Upper coordinate of the destination rectangle.
+ * @width: Width of the destination rectangle, in pixels.
+ * @height: Height of the destination rectangle, in pixels.
+ * @dith: Dithering method to use.
+ * @rgb_buf: Pointer to the pixel in the RGB buffer that corresponds to the
+ * upper-left corner of the rectangular region to render.
+ * @rowstride: Offset between pixel rows in the RGB buffer, in bytes.
+ * 
+ * Renders an RGB buffer to a drawable.  Pixels are specified as RGB triplets
+ * with 8 bits per channel.  An image will thus look like an RGBRGBRGBRGB
+ * sequence of 8-bit values.  This function does not let you specify dither
+ * offsets; applications that need to render partial regions of a buffer to
+ * build the final image should use xlib_draw_rgb_image_dithalign() instead.
+ **/
+void
+xlib_draw_rgb_image (Drawable drawable,
+                    GC gc,
+                    int x,
+                    int y,
+                    int width,
+                    int height,
+                    XlibRgbDither dith,
+                    unsigned char *rgb_buf,
+                    int rowstride)
+{
+  if (dith == XLIB_RGB_DITHER_NONE || (dith == XLIB_RGB_DITHER_NORMAL &&
+                                     !image_info->dith_default))
+    xlib_draw_rgb_image_core (drawable, gc, x, y, width, height,
+                             rgb_buf, 3, rowstride, image_info->conv, NULL,
+                             0, 0);
+  else
+    xlib_draw_rgb_image_core (drawable, gc, x, y, width, height,
+                             rgb_buf, 3, rowstride, image_info->conv_d, NULL,
+                             0, 0);
+}
+
+/**
+ * xlib_draw_rgb_image_dithalign:
+ * @drawable: Destination drawable.
+ * @gc: A graphic context.
+ * @x: Leftmost coordinate of the destination rectangle.
+ * @y: Upper coordinate of the destination rectangle.
+ * @width: Width of the destination rectangle, in pixels.
+ * @height: Height of the destination rectangle, in pixels.
+ * @dith: Dithering method to use.
+ * @rgb_buf: Pointer to the pixel in the RGB buffer that corresponds to the
+ * upper-left corner of the rectangular region to render.
+ * @rowstride: Offset between pixel rows in the RGB buffer, in bytes.
+ * @xdith: X offset for the dither mask.
+ * @ydith: Y offset for the dither mask.
+ * 
+ * Renders an RGB buffer to a drawable.  Pixels are specified as RGB triplets
+ * with 8 bits per channel.  An image will thus look like an RGBRGBRGBRGB
+ * sequence of 8-bit values.  This function lets you specify a pair of dither
+ * offsets.  It should be used when you need to render regions of an RGB buffer
+ * separately to form the final image; the dither offsets let you align the
+ * dither mask appropriately.
+ **/
+void
+xlib_draw_rgb_image_dithalign (Drawable drawable,
+                             GC gc,
+                             int x,
+                             int y,
+                             int width,
+                             int height,
+                             XlibRgbDither dith,
+                             unsigned char *rgb_buf,
+                             int rowstride,
+                             int xdith,
+                             int ydith)
+{
+  if (dith == XLIB_RGB_DITHER_NONE || (dith == XLIB_RGB_DITHER_NORMAL &&
+                                      !image_info->dith_default))
+    xlib_draw_rgb_image_core (drawable, gc, x, y, width, height,
+                             rgb_buf, 3, rowstride, image_info->conv, NULL,
+                             xdith, ydith);
+  else
+    xlib_draw_rgb_image_core (drawable, gc, x, y, width, height,
+                             rgb_buf, 3, rowstride, image_info->conv_d, NULL,
+                             xdith, ydith);
+}
+
+/**
+ * xlib_draw_rgb_32_image:
+ * @drawable: Destination drawable.
+ * @gc: A graphic context.
+ * @x: Leftmost coordinate of the destination rectangle.
+ * @y: Upper coordinate of the destination rectangle.
+ * @width: Width of the destination rectangle, in pixels.
+ * @height: Height of the destination rectangle, in pixels.
+ * @dith: Dithering method to use.
+ * @buf: Pointer to the pixel in the RGB buffer that corresponds to the
+ * upper-left corner of the rectangular region to render.
+ * @rowstride: Offset between pixel rows in the RGB buffer, in bytes.
+ * 
+ * This function is analogous to xlib_draw_rgb_image(), but it lets you use
+ * 32-bit RGB buffers with pixels specified as 0xRRGGBB00.  The
+ * least-significant 8 bits are actually discarded.  This function can lead to
+ * faster results than xlib_draw_rgb_image() since the pixels are aligned on
+ * 32-bit boundaries.
+ **/
+void
+xlib_draw_rgb_32_image (Drawable drawable,
+                       GC gc,
+                       int x,
+                       int y,
+                       int width,
+                       int height,
+                       XlibRgbDither dith,
+                       unsigned char *buf,
+                       int rowstride)
+{
+  if (dith == XLIB_RGB_DITHER_NONE || (dith == XLIB_RGB_DITHER_NORMAL &&
+                                      !image_info->dith_default))
+    xlib_draw_rgb_image_core (drawable, gc, x, y, width, height,
+                             buf, 4, rowstride,
+                             image_info->conv_32, NULL, 0, 0);
+  else
+    xlib_draw_rgb_image_core (drawable, gc, x, y, width, height,
+                             buf, 4, rowstride,
+                             image_info->conv_32_d, NULL, 0, 0);
+}
+
+static void
+xlib_rgb_make_gray_cmap (XlibRgbInfo *info)
+{
+  guint32 rgb[256];
+  int i;
+
+  for (i = 0; i < 256; i++)
+    rgb[i] = (i << 16)  | (i << 8) | i;
+  info->gray_cmap = xlib_rgb_cmap_new (rgb, 256);
+}
+
+/**
+ * xlib_draw_gray_image:
+ * @drawable: Destination drawable.
+ * @gc: A graphic context.
+ * @x: Leftmost coordinate of the destination rectangle.
+ * @y: Upper coordinate of the destination rectangle.
+ * @width: Width of the destination rectangle, in pixels.
+ * @height: Height of thd destination rectangle, in pixels.
+ * @dith: Dithering method to use.
+ * @buf: Pointer to the pixel in the grayscale buffer that corresponds to the
+ * upper-left corner of the rectangular region to render.
+ * @rowstride: Offset between pixel rows in the grayscale buffer, in pixels.
+ * 
+ * Renders a grayscale buffer to a drawable.  Pixels are specified as 8-bit
+ * intensity values.  An image will thus look as a GGGGGG sequence of 8-bit
+ * values.
+ **/
+void
+xlib_draw_gray_image (Drawable drawable,
+                     GC gc,
+                     int x,
+                     int y,
+                     int width,
+                     int height,
+                     XlibRgbDither dith,
+                     unsigned char *buf,
+                     int rowstride)
+{
+  if (image_info->bpp == 1 &&
+      image_info->gray_cmap == NULL &&
+      (image_info->x_visual_info->class == PseudoColor ||
+       image_info->x_visual_info->class == GrayScale))
+    xlib_rgb_make_gray_cmap (image_info);
+  
+  if (dith == XLIB_RGB_DITHER_NONE || (dith == XLIB_RGB_DITHER_NORMAL &&
+                                     !image_info->dith_default))
+    xlib_draw_rgb_image_core (drawable, gc, x, y, width, height,
+                             buf, 1, rowstride,
+                             image_info->conv_gray, NULL, 0, 0);
+  else
+    xlib_draw_rgb_image_core (drawable, gc, x, y, width, height,
+                             buf, 1, rowstride,
+                             image_info->conv_gray_d, NULL, 0, 0);
+}
+
+/**
+ * xlib_rgb_cmap_new:
+ * @colors: FIXME
+ * @n_colors: FIXME
+ * 
+ * FIXME
+ * 
+ * Return value: FIXME
+ **/
+XlibRgbCmap *
+xlib_rgb_cmap_new (guint32 *colors, int n_colors)
+{
+  XlibRgbCmap *cmap;
+  int i, j;
+  guint32 rgb;
+
+  if (n_colors < 0)
+    return NULL;
+  if (n_colors > 256)
+    return NULL;
+  cmap = malloc(sizeof(XlibRgbCmap));
+  memcpy (cmap->colors, colors, n_colors * sizeof(guint32));
+  if (image_info->bpp == 1 &&
+      (image_info->x_visual_info->class == PseudoColor ||
+       image_info->x_visual_info->class == GrayScale))
+    for (i = 0; i < n_colors; i++)
+      {
+       rgb = colors[i];
+       j = ((rgb & 0xf00000) >> 12) |
+                  ((rgb & 0xf000) >> 8) |
+                  ((rgb & 0xf0) >> 4);
+#ifdef VERBOSE
+       printf ("%d %x %x %d\n", i, j, colorcube[j]);
+#endif
+       cmap->lut[i] = colorcube[j];
+      }
+  return cmap;
+}
+
+/**
+ * xlib_rgb_cmap_free:
+ * @cmap: An XlibRGB colormap.
+ * 
+ * Frees an XlibRGB colormap.
+ **/
+void
+xlib_rgb_cmap_free (XlibRgbCmap *cmap)
+{
+  free (cmap);
+}
+
+/**
+ * xlib_draw_indexed_image:
+ * @drawable: FIXME
+ * @gc: FIXME
+ * @x: FIXME
+ * @y: FIXME
+ * @width: FIXME
+ * @height: FIXME
+ * @dith: FIXME
+ * @buf: FIXME
+ * @rowstride: FIXME
+ * @cmap: FIXME
+ * 
+ * FIXME
+ **/
+void
+xlib_draw_indexed_image (Drawable drawable,
+                       GC gc,
+                       int x,
+                       int y,
+                       int width,
+                       int height,
+                       XlibRgbDither dith,
+                       unsigned char *buf,
+                       int rowstride,
+                       XlibRgbCmap *cmap)
+{
+  if (dith == XLIB_RGB_DITHER_NONE || (dith == XLIB_RGB_DITHER_NORMAL &&
+                                      !image_info->dith_default))
+    xlib_draw_rgb_image_core (drawable, gc, x, y, width, height,
+                             buf, 1, rowstride,
+                             image_info->conv_indexed, cmap, 0, 0);
+  else
+    xlib_draw_rgb_image_core (drawable, gc, x, y, width, height,
+                             buf, 1, rowstride,
+                             image_info->conv_indexed_d, cmap, 0, 0);
+}
+
+/**
+ * xlib_rgb_ditherable:
+ * 
+ * Queries whether XlibRGB supports dithering for its chosen visual.
+ * 
+ * Return value: TRUE if dithering can be performed for the visual that XlibRGB
+ * is using, FALSE otherwise.
+ **/
+Bool
+xlib_rgb_ditherable (void)
+{
+  return (image_info->conv != image_info->conv_d);
+}
+
+/**
+ * xlib_rgb_get_cmap:
+ * 
+ * Queries the X colormap that XlibRGB is using.
+ * 
+ * Return value: An X colormap.
+ **/
+Colormap
+xlib_rgb_get_cmap (void)
+{
+  /* xlib_rgb_init (); */
+  if (image_info)
+    return image_info->cmap;
+  else
+    return 0;
+}
+
+/**
+ * xlib_rgb_get_visual:
+ * 
+ * Queries the visual that XlibRGB is using.
+ * 
+ * Return value: An X visual.
+ **/
+Visual *
+xlib_rgb_get_visual (void)
+{
+  /* xlib_rgb_init (); */
+  if (image_info)
+    return image_info->x_visual_info->visual;
+  else
+    return 0;
+}
+
+/**
+ * xlib_rgb_get_visual_info:
+ * 
+ * Queries the visual info structure for the visual that XlibRGB is using.
+ * 
+ * Return value: An XVisualInfo structure.
+ **/
+XVisualInfo *
+xlib_rgb_get_visual_info (void)
+{
+  /* xlib_rgb_init (); */
+  if (image_info)
+    return image_info->x_visual_info;
+  else
+    return 0;
+}
+
+/**
+ * xlib_rgb_get_depth:
+ * 
+ * Queries the depth of the visual that XlibRGB is using.
+ * 
+ * Return value: Bit depth.
+ **/
+int
+xlib_rgb_get_depth (void)
+{
+  XVisualInfo * v = xlib_rgb_get_visual_info();
+
+  if (v)
+  {
+    return v->depth;
+  }
+
+  return 0;
+}
+
+/**
+ * xlib_rgb_get_display:
+ * 
+ * Queries the X display that XlibRGB is using.
+ * 
+ * Return value: An X display.
+ **/
+Display *
+xlib_rgb_get_display (void)
+{
+  if (image_info)
+    return image_info->display;
+  
+  return NULL;
+}
+
+/**
+ * xlib_rgb_get_screen:
+ * 
+ * Queries the screen that XlibRGB is using.
+ * 
+ * Return value: An X screen.
+ **/
+Screen *
+xlib_rgb_get_screen (void)
+{
+  if (image_info)
+    return image_info->screen;
+  
+  return NULL;
+}
diff --git a/contrib/gdk-pixbuf-xlib/gdk-pixbuf-xlibrgb.h b/contrib/gdk-pixbuf-xlib/gdk-pixbuf-xlibrgb.h
new file mode 100644 (file)
index 0000000..7d0b92b
--- /dev/null
@@ -0,0 +1,195 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "MPL"); you may not use this file except in
+ * compliance with the MPL.  You may obtain a copy of the MPL at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the MPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
+ * for the specific language governing rights and limitations under the
+ * MPL.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Library General Public License (the "LGPL"), in
+ * which case the provisions of the LGPL are applicable instead of
+ * those above.  If you wish to allow use of your version of this file
+ * only under the terms of the LGPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the LGPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the LGPL.
+ */
+
+/*
+ * This code is derived from GdkRgb.
+ * For more information on GdkRgb, see http://www.levien.com/gdkrgb/
+ * Raph Levien <raph@acm.org>
+ */
+
+/* Ported by Christopher Blizzard to Xlib.  With permission from the
+ * original authors of this file, the contents of this file are also
+ * redistributable under the terms of the Mozilla Public license.  For
+ * information about the Mozilla Public License, please see the
+ * license information at http://www.mozilla.org/MPL/
+ */
+
+/* This code is copyright the following authors:
+ * Raph Levien          <raph@acm.org>
+ * Manish Singh         <manish@gtk.org>
+ * Tim Janik            <timj@gtk.org>
+ * Peter Mattis         <petm@xcf.berkeley.edu>
+ * Spencer Kimball      <spencer@xcf.berkeley.edu>
+ * Josh MacDonald       <jmacd@xcf.berkeley.edu>
+ * Christopher Blizzard <blizzard@redhat.com>
+ * Owen Taylor          <otaylor@redhat.com>
+ * Shawn T. Amundson    <amundson@gtk.org>
+*/
+
+
+#ifndef __XLIB_RGB_H__
+#define __XLIB_RGB_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xos.h>
+#include <X11/Intrinsic.h>
+
+#include <glib.h>
+
+typedef struct _XlibRgbCmap XlibRgbCmap;
+
+struct _XlibRgbCmap {
+  unsigned int colors[256];
+  unsigned char lut[256]; /* for 8-bit modes */
+};
+
+void
+xlib_rgb_init (Display *display, Screen *screen);
+void
+xlib_rgb_init_with_depth (Display *display, Screen *screen, int prefDepth);
+
+unsigned long
+xlib_rgb_xpixel_from_rgb (guint32 rgb);
+
+void
+xlib_rgb_gc_set_foreground (GC gc, guint32 rgb);
+
+void
+xlib_rgb_gc_set_background (GC gc, guint32 rgb);
+
+typedef enum
+{
+  XLIB_RGB_DITHER_NONE,
+  XLIB_RGB_DITHER_NORMAL,
+  XLIB_RGB_DITHER_MAX
+} XlibRgbDither;
+
+void
+xlib_draw_rgb_image (Drawable drawable,
+                    GC gc,
+                    int x,
+                    int y,
+                    int width,
+                    int height,
+                    XlibRgbDither dith,
+                    unsigned char *rgb_buf,
+                    int rowstride);
+
+void
+xlib_draw_rgb_image_dithalign (Drawable drawable,
+                              GC gc,
+                              int x,
+                              int y,
+                              int width,
+                              int height,
+                              XlibRgbDither dith,
+                              unsigned char *rgb_buf,
+                              int rowstride,
+                              int xdith,
+                              int ydith);
+
+void
+xlib_draw_rgb_32_image (Drawable drawable,
+                       GC gc,
+                       int x,
+                       int y,
+                       int width,
+                       int height,
+                       XlibRgbDither dith,
+                       unsigned char *buf,
+                       int rowstride);
+
+void
+xlib_draw_gray_image (Drawable drawable,
+                     GC gc,
+                     int x,
+                     int y,
+                     int width,
+                     int height,
+                     XlibRgbDither dith,
+                     unsigned char *buf,
+                     int rowstride);
+
+XlibRgbCmap *
+xlib_rgb_cmap_new (guint32 *colors, int n_colors);
+
+void
+xlib_rgb_cmap_free (XlibRgbCmap *cmap);
+
+void
+xlib_draw_indexed_image (Drawable drawable,
+                         GC gc,
+                         int x,
+                         int y,
+                         int width,
+                         int height,
+                         XlibRgbDither dith,
+                         unsigned char *buf,
+                         int rowstride,
+                         XlibRgbCmap *cmap);
+
+/* Below are some functions which are primarily useful for debugging
+   and experimentation. */
+Bool
+xlib_rgb_ditherable (void);
+
+void
+xlib_rgb_set_verbose (Bool verbose);
+
+/* experimental colormap stuff */
+void
+xlib_rgb_set_install (Bool install);
+
+void
+xlib_rgb_set_min_colors (int min_colors);
+
+Colormap
+xlib_rgb_get_cmap (void);
+
+Visual *
+xlib_rgb_get_visual (void);
+
+XVisualInfo *
+xlib_rgb_get_visual_info (void);
+
+int
+xlib_rgb_get_depth (void);
+
+Display *
+xlib_rgb_get_display (void);
+
+Screen *
+xlib_rgb_get_screen (void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __XLIB_RGB_H__ */
index c6d5a45c54a3489058edd6654099e9cea2826dbb..f118205e2153c802f4c402839ace0532ce33004a 100644 (file)
@@ -370,7 +370,8 @@ new_testrgb_window (GdkPixbuf *pixbuf, gchar *title)
        GtkWidget *button;
        GtkWidget *drawing_area;
        gint w, h;
+
+        g_return_val_if_fail (pixbuf != NULL, NULL);
        w = gdk_pixbuf_get_width (pixbuf);
        h = gdk_pixbuf_get_height (pixbuf);
 
@@ -427,18 +428,34 @@ static gint
 update_timeout(gpointer data)
 {
         ProgressFileStatus *status = data;
-       gboolean done;
-
-       done = TRUE;
+       gboolean done, error;
+        
+       done = FALSE;
+        error = FALSE;
        if (!feof(status->imagefile)) {
                gint nbytes;
 
                nbytes = fread(status->buf, 1, status->readlen, 
                               status->imagefile);
 
-               done = !gdk_pixbuf_loader_write (GDK_PIXBUF_LOADER (status->loader), status->buf, nbytes);
-                       
-       }
+
+                error = !gdk_pixbuf_loader_write (GDK_PIXBUF_LOADER (status->loader), status->buf, nbytes);
+                if (error) {
+                        G_BREAKPOINT();
+                }
+
+        } else { /* Really done */ 
+
+                GdkPixbuf *pixbuf = gdk_pixbuf_loader_get_pixbuf (status->loader); 
+                new_testrgb_window (pixbuf, "After progressive load"); 
+                done = TRUE; 
+
+        }
+
+        if (error) { 
+                g_warning ("Serious error writing to loader"); 
+                done = TRUE; 
+        } 
 
        if (done) {
                 gtk_widget_queue_draw(*status->rgbwin);
index 7021e4b4f6f97b44cf3d1d05f23cb8c1f40c3979..695d665520751b0895b9e693a2f3611d06842ef4 100644 (file)
@@ -1,3 +1,14 @@
+2000-10-06  Havoc Pennington  <hp@redhat.com>
+
+        * gdk-pixbuf/*.sgml, gdk-pixbuf/tmpl/*.sgml: copy in from 1.0
+       
+       * gdk-pixbuf/gdk-pixbuf-sections.txt: add Xlib sections from 1.0
+       tree
+
+       * gdk-pixbuf/Makefile.am: add stuff from 1.0 tree
+
+       * gdk-pixbuf/compiling.sgml: copy from 1.0 tree
+
 2000-09-26  Havoc Pennington  <hp@redhat.com>
 
        * gtk/tmpl/gtkrc.sgml: Document stock icon stuff
index f5cd156c1292b553dd338f3f06780e035a87a5b3..b399994664a50832d1a2ba4389b6d586f0de0909 100644 (file)
@@ -8,12 +8,13 @@ DOC_MAIN_SGML_FILE=gdk-pixbuf.sgml
 
 # The directory containing the source code (if it contains documentation).
 DOC_SOURCE_DIR=$(GDK_PIXBUF_DIR)/gdk-pixbuf
+SECOND_DOC_SOURCE_DIR=$(top_srcdir)/contrib/gdk-pixbuf-xlib
 
 # Extra options to supply to gtkdoc-fixref
 FIXXREF_OPTIONS=
 
 # Header files to ignore when scanning
-IGNORE_HFILES=pixops.h pixops-internal.h
+IGNORE_HFILES=pixops.h pixops-internal.h gdk-pixbuf-xlib-private.h
 
 # Extra files to add when scanning
 EXTRA_HFILES=                  \
@@ -34,12 +35,17 @@ tmpl_sources =                                      \
        tmpl/module_interface.sgml              \
        tmpl/refcounting.sgml                   \
        tmpl/scaling.sgml                       \
-       tmpl/util.sgml
+       tmpl/util.sgml                          \
+        tmpl/gdk-pixbuf-xlib-from-drawables.sgml        \
+        tmpl/gdk-pixbuf-xlib-init.sgml                  \
+        tmpl/gdk-pixbuf-xlib-rendering.sgml             \
+        tmpl/gdk-pixbuf-xlib-rgb.sgml
 
 # Extra SGML files that are included by DOC_MAIN_SGML_FILE
 content_files =                                \
        compiling.sgml                  \
-       gdk-pixbuf.sgml
+       gdk-pixbuf.sgml                 \
+       porting-from-imlib.sgml
 
 ####################################
 # Everything below here is generic #
@@ -71,14 +77,14 @@ endif
 
 scan:
        -(cd $(srcdir) \
-       && gtkdoc-scan --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --ignore-headers="$(IGNORE_HFILES)" $(EXTRA_HFILES))
+       && gtkdoc-scan --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --source-dir=$(SECOND_DOC_SOURCE_DIR) --ignore-headers="$(IGNORE_HFILES)" $(EXTRA_HFILES))
 
 templates: 
        cd $(srcdir) && gtkdoc-mktmpl --module=$(DOC_MODULE)
 
 sgml:
        cd $(srcdir) \
-       && gtkdoc-mkdb --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR)
+       && gtkdoc-mkdb --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --source-dir=$(SECOND_DOC_SOURCE_DIR)
 
 html:
        test -d $(srcdir)/html || mkdir $(srcdir)/html
index dc335ef6d1f5e4c1c71bfdbd763ef5aa6094299f..6224909f8cbfa1b8f1d7fe8ca08e2e74af59f32e 100644 (file)
@@ -1,25 +1,22 @@
   <appendix id="compiling">
-    <title>Compiling the <application>gdk-pixbuf</application>
-    library</title>
+    <title>Compiling the &gdk-pixbuf; library</title>
 
     <para>
       This appendix describes the special options you can use while
-      compiling the <application>gdk-pixbuf</application> library.
+      compiling the &gdk-pixbuf; library.
     </para>
 
     <sect1 id="building">
       <title>Building the Library</title>
       <para>
-       The <application>gdk-pixbuf</application> library uses the
-       standard GNU build system, using
-       <application>autoconf</application> for package configuration
-       and resolving portability issues,
+       The &gdk-pixbuf; library uses the standard GNU build system,
+       using <application>autoconf</application> for package
+       configuration and resolving portability issues,
        <application>automake</application> for building makefiles
        that comply with the GNU Coding Standards, and
        <application>libtool</application> for building shared
        libraries on multiple platforms.  The normal sequence for
-       compiling and installing the
-       <application>gdk-pixbuf</application> library is thus:
+       compiling and installing the &gdk-pixbuf; library is thus:
 
        <literallayout>
          <userinput>./configure</userinput>
@@ -43,9 +40,8 @@
 
       <para>
        In addition to the normal options, the
-       <command>configure</command> script in the
-       <application>gdk-pixbuf</application> library supports these
-       additional arguments:
+       <command>configure</command> script in the &gdk-pixbuf;
+       library supports these additional arguments:
 
        <cmdsynopsis>
          <command>configure</command>
          <systemitem>--enable-modules</systemitem></title>
 
        <para>
-         Normally <application>gdk-pixbuf</application> will try to
-         build the image file format loaders as little shared
-         libraries that are loaded on demand.  The
-         <systemitem>--disable-modules</systemitem> argument
-         indicates that they should all be built statically into the
-         <application>gdk-pixbuf</application> library instead.  This
-         is useful for people who need to produce statically-linked
-         binaries.  If neither
-         <systemitem>--disable-modules</systemitem> nor
+         Normally &gdk-pixbuf; will try to build the image file
+         format loaders as little shared libraries that are loaded on
+         demand.  The <systemitem>--disable-modules</systemitem>
+         argument indicates that they should all be built statically
+         into the &gdk-pixbuf; library instead.  This is useful for
+         people who need to produce statically-linked binaries.  If
+         neither <systemitem>--disable-modules</systemitem> nor
          <systemitem>--enable-modules</systemitem> is specified, then
          the <command>configure</command> script will try to
          auto-detect whether shared modules work on your system.
          to auto-detect whether the
          <application>gtk-doc</application> package is installed.  If
          it is, then it will use it to extract and build the
-         documentation for the <application>gdk-pixbuf</application>
-         library.  These options can be used to explicitly control
-         whether gtk-doc should be used or not.  If it is not used,
-         the distributed, pre-generated HTML files will be installed
-         instead of building them on your machine.
+         documentation for the &gdk-pixbuf; library.  These options
+         can be used to explicitly control whether gtk-doc should be
+         used or not.  If it is not used, the distributed,
+         pre-generated HTML files will be installed instead of
+         building them on your machine.
        </para>
       </formalpara>
     </sect1>
index 51192a06458f6602490243b009d8fde0906a149d..39fc15ddc680107a88125a845dd85e0bbe51e468 100644 (file)
@@ -140,4 +140,50 @@ GdkPixbufModule
 gdk_pixbuf_get_module
 gdk_pixbuf_get_named_module
 gdk_pixbuf_load_module
-</SECTION>
\ No newline at end of file
+</SECTION>
+
+<SECTION>
+<FILE>gdk-pixbuf-xlib-init</FILE>
+gdk_pixbuf_xlib_init
+gdk_pixbuf_xlib_init_with_depth
+</SECTION>
+
+<SECTION>
+<FILE>gdk-pixbuf-xlib-rendering</FILE>
+gdk_pixbuf_xlib_render_threshold_alpha
+gdk_pixbuf_xlib_render_to_drawable
+gdk_pixbuf_xlib_render_to_drawable_alpha
+gdk_pixbuf_xlib_render_pixmap_and_mask
+</SECTION>
+
+<SECTION>
+<FILE>gdk-pixbuf-xlib-from-drawables</FILE>
+gdk_pixbuf_xlib_get_from_drawable
+</SECTION>
+
+<SECTION>
+<FILE>gdk-pixbuf-xlib-rgb</FILE>
+XlibRgbCmap
+XlibRgbDither
+xlib_rgb_init
+xlib_rgb_init_with_depth
+xlib_rgb_gc_set_foreground
+xlib_rgb_gc_set_background
+xlib_draw_rgb_image
+xlib_draw_rgb_image_dithalign
+xlib_draw_rgb_32_image
+xlib_draw_gray_image
+xlib_rgb_cmap_new
+xlib_rgb_cmap_free
+xlib_draw_indexed_image
+xlib_rgb_ditherable
+xlib_rgb_set_verbose
+xlib_rgb_set_install
+xlib_rgb_set_min_colors
+xlib_rgb_get_cmap
+xlib_rgb_get_visual
+xlib_rgb_get_visual_info
+xlib_rgb_get_depth
+xlib_rgb_get_display
+xlib_rgb_get_screen
+</SECTION>
index 16252c70a8a0d8298354fda1dfe67cc15471a229..60907f135088e5f7e95c8eee3ae946ab46810958 100644 (file)
@@ -1,23 +1,28 @@
-<!doctype book PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
-<!entity gdk-pixbuf-Initialization-and-Versions SYSTEM "sgml/initialization_versions.sgml">
+<!doctype book PUBLIC "-//Davenport//DTD DocBook V3.0//EN"[
+
 <!entity gdk-pixbuf-gdk-pixbuf SYSTEM "sgml/gdk-pixbuf.sgml">
 <!entity gdk-pixbuf-refcounting SYSTEM "sgml/refcounting.sgml">
 <!entity gdk-pixbuf-file-loading SYSTEM "sgml/file-loading.sgml">
 <!entity gdk-pixbuf-creating SYSTEM "sgml/creating.sgml">
-<!entity gdk-pixbuf-rendering SYSTEM "sgml/rendering.sgml">
 <!entity gdk-pixbuf-scaling SYSTEM "sgml/scaling.sgml">
-<!entity gdk-pixbuf-from-drawables SYSTEM "sgml/from-drawables.sgml">
 <!entity gdk-pixbuf-util SYSTEM "sgml/util.sgml">
 <!entity gdk-pixbuf-animation SYSTEM "sgml/animation.sgml">
-<!entity gdk-pixbuf-Module-Interface SYSTEM "sgml/module_interface.sgml">
 <!entity GdkPixbufLoader SYSTEM "sgml/gdk-pixbuf-loader.sgml">
-<!entity GnomeCanvasPixbuf SYSTEM "sgml/gnome-canvas-pixbuf.sgml">
+<!entity gdk-pixbuf-gdk-pixbuf-xlib-init SYSTEM "sgml/gdk-pixbuf-xlib-init.sgml">
+<!entity gdk-pixbuf-gdk-pixbuf-xlib-rendering SYSTEM "sgml/gdk-pixbuf-xlib-rendering.sgml">
+<!entity gdk-pixbuf-gdk-pixbuf-xlib-from-drawables SYSTEM "sgml/gdk-pixbuf-xlib-from-drawables.sgml">
+<!entity gdk-pixbuf-gdk-pixbuf-xlib-rgb SYSTEM "sgml/gdk-pixbuf-xlib-rgb.sgml">
+
+<!entity Porting-From-Imlib SYSTEM "porting-from-imlib.sgml">
 <!entity Compiling SYSTEM "compiling.sgml">
+
+<!entity gdk-pixbuf "<application>gdk-pixbuf</application>">
+<!entity Imlib "<application>Imlib</application>">
 ]>
 
 <book id="index">
   <bookinfo>
-    <title>The <application>gdk-pixbuf</application> Library</title>
+    <title>The &gdk-pixbuf; Library</title>
 
     <authorgroup>
       <author>
     </authorgroup>
 
     <copyright>
-      <year>1999</year>
+      <year>2000</year>
       <holder>The Free Software Foundation</holder>
     </copyright>
+
+    <legalnotice>
+      <para>
+       Permission is granted to copy, distribute and/or modify this
+       document under the terms of the <citetitle>GNU Free
+       Documentation License</citetitle>, Version 1.1 or any later
+       version published by the Free Software Foundation with no
+       Invariant Sections, no Front-Cover Texts, and no Back-Cover
+       Texts. You may obtain a copy of the <citetitle>GNU Free
+       Documentation License</citetitle> from the Free Software
+       Foundation by visiting <ulink type="http"
+       url="http://www.fsf.org">their Web site</ulink> or by writing
+       to:
+
+       <address>
+         The Free Software Foundation, Inc.,
+         <street>59 Temple Place</street> - Suite 330,
+         <city>Boston</city>, <state>MA</state> <postcode>02111-1307</postcode>,
+         <country>USA</country>
+       </address>
+      </para>
+
+      <para>
+       Many of the names used by companies to distinguish their
+       products and services are claimed as trademarks. Where those
+       names appear in any GNOME documentation, and those trademarks
+       are made aware to the members of the GNOME Documentation
+       Project, the names have been printed in caps or initial caps.
+      </para>
+    </legalnotice>
   </bookinfo>
 
-  <reference id="api">
+  <reference>
     <title>API Reference</title>
 
     <partintro>
       <para>
        This part presents the class and function reference for the
-       <application>gdk-pixbuf</application> library.  Classes are
-       described together with their methods; individual functions
-       are grouped by functional group.
+       &gdk-pixbuf; library.  Classes are described together with
+       their methods; individual functions are grouped by functional
+       group.
       </para>
     </partintro>
 
-    &gdk-pixbuf-Initialization-and-Versions;
     &gdk-pixbuf-gdk-pixbuf;
     &gdk-pixbuf-refcounting;
     &gdk-pixbuf-file-loading;
     &gdk-pixbuf-scaling;
     &gdk-pixbuf-util;
     &gdk-pixbuf-animation;
+
     &GdkPixbufLoader;
-    &GnomeCanvasPixbuf;
-  </reference>
 
-  <reference id="internals">
-    <title>Internals</title>
-    &gdk-pixbuf-Module-Interface;
+    &gdk-pixbuf-gdk-pixbuf-xlib-init;
+    &gdk-pixbuf-gdk-pixbuf-xlib-rendering;
+    &gdk-pixbuf-gdk-pixbuf-xlib-from-drawables;
+    &gdk-pixbuf-gdk-pixbuf-xlib-rgb;
   </reference>
 
+  &Porting-From-Imlib;
   &Compiling;
 
+  <!-- License -->
+
+  <appendix id="license">
+    <title>License</title>
+       
+    <para>
+      This library is free software; you can redistribute it and/or
+      modify it under the terms of the <citetitle>GNU Library General
+      Public License</citetitle> as published by the Free Software
+      Foundation; either version 2 of the License, or (at your option)
+      any later version.
+    </para>
+
+    <para>
+      This library is distributed in the hope that it will be useful,
+      but WITHOUT ANY WARRANTY; without even the implied warranty of
+      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+      <citetitle>GNU Library General Public License</citetitle> for
+      more details.
+    </para>
+
+    <para>
+      You may obtain a copy of the <citetitle>GNU Library General
+      Public License</citetitle> from the Free Software Foundation by
+      visiting <ulink type="http" url="http://www.fsf.org">their Web
+      site</ulink> or by writing to:
+
+      <address>
+       Free Software Foundation, Inc.
+       <street>59 Temple Place</street> - Suite 330
+       <city>Boston</city>, <state>MA</state> <postcode>02111-1307</postcode>
+       <country>USA</country>
+      </address>
+    </para>
+  </appendix>
 </book>
diff --git a/docs/reference/gdk-pixbuf/porting-from-imlib.sgml b/docs/reference/gdk-pixbuf/porting-from-imlib.sgml
new file mode 100644 (file)
index 0000000..b736200
--- /dev/null
@@ -0,0 +1,360 @@
+  <appendix>
+    <title>Porting applications from &Imlib; to &gdk-pixbuf;</title>
+
+    <para>
+      This appendix contains the basic steps needed to port an
+      application that uses the &Imlib; library to use &gdk-pixbuf;
+      instead.
+    </para>
+
+    <note>
+      <para>
+       This appendix refers to version 1 of the &Imlib; library; this
+       discussion is not relevant to Imlib 2.  Also, we discuss the
+       gdk_imlib API instead of the Xlib-based API.
+      </para>
+    </note>
+
+    <!-- Introduction -->
+
+    <sect1>
+      <title>Introduction</title>
+
+      <para>
+       Prior to the GNOME 1.2 platform, the &Imlib; library was the
+       preferred way of loading and rendering images in GNOME
+       applications.  Unfortunately, &Imlib; has important design
+       limitations that make it hard to write efficient and highly
+       modular applications.
+      </para>
+
+      <para>
+       The &gdk-pixbuf; library was designed as a solution to
+       &Imlib;'s shortcomings.  It provides a simple, orthogonal API
+       and convenience functions for the most common operations.  In
+       addition, it supports full transparency information for
+       images, or alpha channel.  More importantly, it has
+       well-defined semantics for memory management through the use
+       of reference counting; &Imlib; has an intractably complex
+       memory management mechanism and cache that will make your head
+       spin.
+      </para>
+    </sect1>
+
+    <!-- Differences between Imlib and gdk-pixbuf -->
+
+    <sect1>
+      <title>Differences between &Imlib; and &gdk-pixbuf;</title>
+
+      <para>
+       Generally, applications that use &Imlib; do not have to be
+       changed extensively to use &gdk-pixbuf;; its simple and
+       flexible API makes things easy.  This section describes the
+       differences between &Imlib; and &gdk-pixbuf;; you should take
+       these into account when modifying your applications to use
+       &gdk-pixbuf;.
+      </para>
+
+      <!-- Initialization -->
+
+      <sect2>
+       <title>Initialization</title>
+
+       <para>
+         The &gdk-pixbuf; library does not need to be initialized.
+         However, if you intend to use the rendering functions or
+         anything else from the <application>GdkRGB</application>
+         library, you should call <function>gdk_rgb_init()</function>
+         after calling <function>gtk_init()</function> or
+         <function>gnome_init()</function> in your program.
+       </para>
+
+       <note>
+         <para>
+           In GNOME applications you normally don't need to
+           initialize &Imlib;, as <function>gnome_init()</function>
+           calls <function>gdk_imlib_init()</function> automatically.
+         </para>
+       </note>
+      </sect2>
+
+      <!-- Memory management -->
+
+      <sect2>
+       <title>Memory management</title>
+
+       <para>
+         The &gdk-pixbuf; library provides a simple, well-defined
+         memory management mechanism for images in the form of
+         reference counting.  This makes it very convenient to use
+         for large-scale applications that need to share images
+         between different parts of the program.  In stark contrast,
+         &Imlib; has a terribly complex mechanism of an image and
+         pixmap cache which makes it very hard for applications to
+         share image structures between different parts of the
+         program.  Unfortunately this mechanism makes things very
+         prone to memory leaks and tricky bugs.
+       </para>
+
+       <para>
+         The basic principle in &gdk-pixbuf; is that when you obtain
+         a new <link linkend="GdkPixbuf">GdkPixbuf</link> structure,
+         it is created with an initial reference count of 1.  When
+         another part of the program wants to keep a reference to the
+         pixbuf, it should call <link
+         linkend="gdk-pixbuf-ref">gdk_pixbuf_ref()</link>; this will
+         increase the reference count by 1.  When some part of the
+         program does not need to keep a reference to a pixbuf
+         anymore and wants to release the pixbuf, it should call
+         <link linkend="gdk-pixbuf-unref">gdk_pixbuf_unref()</link>;
+         this will decrease the reference count by 1.  When the
+         reference count drops to zero, the pixbuf gets destroyed or
+         <emphasis>finalized</emphasis> and its memory is freed.
+       </para>
+
+       <para>
+         For applications that need to implement a cache of loaded
+         images, &gdk-pixbuf; provides a way to hook to the last
+         unreference operation of a pixbuf; instead of finalizing the
+         pixbuf, the user-installed hook can decide to keep it around
+         in a cache instead.
+       </para>
+
+       <para>
+         Finally, &gdk-pixbuf; does not provide a cache of rendered
+         pixmaps.  This is unnecessary for most applications, since
+         the scaling and rendering functions are quite fast and
+         applications may need to use subtly different values each
+         time they call these functions, for example, to take into
+         account dithering and zooming offsets.
+       </para>
+
+       <para>
+         Most applications will simply need to call
+         <function>gdk_pixbuf_ref()</function> when they want to keep
+         an extra reference to a pixbuf, and then
+         <function>gdk_pixbuf_unref()</function> when they are done
+         with it.
+       </para>
+      </sect2>
+
+      <!-- The Rendering Process -->
+
+      <sect2>
+       <title>The Rendering Process</title>
+
+       <para>
+         The &gdk-pixbuf; library has the policy of always rendering
+         pixbufs to Gdk drawables you provide; it will not create
+         them for you.  This is in general more flexible than
+         &Imlib;'s policy of always creating a pixmap and making you
+         use that instead.
+       </para>
+
+       <para>
+         The disadvantage of always having a pixmap created for you
+         is that it wastes memory in the X server if you intend to
+         copy that rendered data onto another drawable, for example,
+         the final destination window or a temporary pixmap for
+         drawing.  This is the most common case, unfortunately, so
+         the &Imlib; policy introduces unnecessary copying.
+       </para>
+
+       <para>
+         Also, &Imlib; can only render pixmaps that are the whole
+         size of the source image; you cannot render just a subset
+         region of the image.  This is inconvenient for applications
+         that need to render small portions at a time, such as
+         applications that do scrolling.  Since the whole image must
+         be rendered at a time, this can lead to performance and
+         memory usage problems.
+       </para>
+
+       <para>
+         The &gdk-pixbuf; library lets you render any rectangular
+         region from an image onto any drawable that you provide.
+         This lets the application have fine control the way images
+         are rendered.
+       </para>
+      </sect2>
+    </sect1>
+
+    <!-- Converting Applications to gdk-pixbuf -->
+
+    <sect1>
+      <title>Converting Applications to &gdk-pixbuf;</title>
+
+      <para>
+       This sections describes the actual changes you need to make in
+       an &Imlib; program to make it use &gdk-pixbuf; instead.
+      </para>
+
+      <!-- Image loading and creation -->
+
+      <sect2>
+       <title>Image loading and creation</title>
+
+       <para>
+         The &gdk-pixbuf; library can load image files synchronously
+         (i.e. with a single function call), create images from RGB
+         data in memory, and as a convenience, it can also create
+         images from inline XPM data.
+       </para>
+
+       <para>
+         To load an image file in a single function call, simply use
+         <function>gdk_pixbuf_new_from_file()</function>.  Note that
+         this will make the program block until the whole file has
+         been read.  This function effectively replaces
+         <function>gdk_imlib_load_image()</function>.
+       </para>
+
+       <para>
+         If you have RGB data in memory, you can use
+         <function>gdk_pixbuf_new_from_data()</function> to create a
+         pixbuf out of it; this is a replacement for
+         <function>gdk_imlib_create_image_from_data()</function>.
+         &gdk-pixbuf; does not copy the image data; it is up to you
+         to define the ownership policy by providing a destroy
+         notification function that will be called when the image
+         data needs to be freed.  The function you provide can then
+         free the data or do something else, as appropriate.
+       </para>
+
+       <para>
+         As a convenience, you can use the
+         <function>gdk_pixbuf_new_from_xpm_data()</function> function
+         to create a pixbuf out of inline XPM data that was compiled
+         into your C program.  This is a replacement for
+         <function>gdk_imlib_create_image_from_xpm_data()</function>.
+       </para>
+
+       <para>
+         After you have created a pixbuf, you can manipulate it in
+         any way you please and then finally call
+         <function>gdk_pixbuf_unref()</function> when you are done
+         with it.  This can be thought of as a replacement for
+         <function>gdk_imlib_destroy_image()</function> but with much
+         cleaner semantics.
+       </para>
+      </sect2>
+
+      <!-- Rendering Images -->
+
+      <sect2>
+       <title>Rendering Images</title>
+
+       <para>
+         Applications that use &Imlib; must first call
+         <function>gdk_imlib_render()</function> to render the whole
+         image data onto a pixmap that &Imlib; creates.  Then they
+         must copy that pixmap's data into the final destination for
+         the image.
+       </para>
+
+       <para>
+         In contrast, &gdk-pixbuf; provides convenience functions to
+         render arbitrary rectangular regions of an image onto a
+         drawable that your application provides.  You can use
+         <function>gdk_pixbuf_render_to_drawable()</function> or
+         <function>gdk_pixbuf_render_to_drawable_alpha()</function>
+         to do this; having your application provide the destination
+         drawable and specify an arbitrary region means your
+         application has complete control over the way images are
+         rendered.
+       </para>
+
+       <para>
+         As a convenience, &gdk-pixbuf; also provides the
+         <function>gdk_pixbuf_render_pixmap_and_mask()</function>
+         function; this will create new pixmap and mask drawables for
+         a whole pixbuf and render the image data onto them.  Only
+         trivially simple applications should find a use for this
+         function, since usually you want finer control of how things
+         are rendered.
+       </para>
+      </sect2>
+
+      <!-- Scaling Images -->
+
+      <sect2>
+       <title>Scaling Images</title>
+
+       <para>
+         &Imlib; lets you render scaled image data at the time you
+         call <function>gdk_imlib_render()</function>.  Again, this
+         unfortunately scales and renders the whole image onto a new
+         pixmap.
+       </para>
+
+       <para>
+         &gdk-pixbuf; provides a number of functions that do scaling
+         of arbitrary regions of a source pixbuf onto a destination
+         one.  These functions can also perform compositing
+         operations against the data in the destination pixbuf or
+         against a solid color or a colored checkerboard.
+         <footnote>
+           <para>
+             You can use a colored checkerboard as the background for
+             compositing when you want to provide a visual indication
+             that the image has partially opaque areas.  This is
+             normally used in image editing and viewing programs.
+           </para>
+
+           <para>
+             Compositing against a single solid color is actually a
+             special case of a checkerboard; it simply uses checks of
+             the same color.
+           </para>
+         </footnote>
+       </para>
+
+       <para>
+         Very simple applications may find it sufficient to use
+         <function>gdk_pixbuf_scale_simple()</function> or
+         <function>gdk_pixbuf_composite_color_simple()</function>.
+         These functions scale the whole source image at a time and
+         create a new pixbuf with the result.
+       </para>
+
+       <para>
+         More sophisticated applications will need to use
+         <function>gdk_pixbuf_scale()</function>,
+         <function>gdk_pixbuf_composite()</function>, or
+         <function>gdk_pixbuf_composite_color()</function> instead.
+         These functions let you scale and composite an arbitrary
+         region of the source pixbuf onto a destination pixbuf that
+         you provide.
+       </para>
+      </sect2>
+
+      <!-- Getting Image Data from a Drawable -->
+
+      <sect2>
+       <title>Getting Image Data from a Drawable</title>
+
+       <para>
+         &Imlib; lets you create an image by fetching a drawable's
+         contents from the X server and converting those into RGB
+         data.  This is done with the
+         <function>gdk_imlib_create_image_from_drawable()</function>
+         function.
+       </para>
+
+       <para>
+         &gdk-pixbuf; provides the
+         <function>gdk_pixbuf_get_from_drawable()</function> function
+         instead.  It lets you specify a destination pixbuf instead
+         of always creating a new one for you.
+       </para>
+      </sect2>
+    </sect1>
+  </appendix>
+
+<!--
+Local variables:
+mode: sgml
+sgml-parent-document: ("gdk-pixbuf.sgml" "book" "book" "")
+End:
+-->
+
index 128863b5b736cfb6f956479a8bb76967f4a28c2d..6a64ac85dd53103dc889e64e2fba403e764016c9 100644 (file)
@@ -6,12 +6,11 @@ Animations as multi-frame structures.
 
 <!-- ##### SECTION Long_Description ##### -->
   <para>
-    The <application>gdk-pixbuf</application> library provides a
-    simple mechanism to load and represent animations, primarily
-    animated GIF files.  Animations are represented as lists of
-    #GdkPixbufFrame structures.  Each frame structure contains a
-    #GdkPixbuf structure and information about the frame's overlay
-    mode and duration.
+    The &gdk-pixbuf; library provides a simple mechanism to load and
+    represent animations, primarily animated GIF files.  Animations
+    are represented as lists of #GdkPixbufFrame structures.  Each
+    frame structure contains a #GdkPixbuf structure and information
+    about the frame's overlay mode and duration.
   </para>
 
 <!-- ##### SECTION See_Also ##### -->
index 0a35bd4f4de1d865f1ed64767afe065bb8ae16da..3f00def6c4b0347c0085cbc50e15fe4d4845fd5e 100644 (file)
@@ -6,12 +6,11 @@ Loading a pixbuf from a file.
 
 <!-- ##### SECTION Long_Description ##### -->
   <para>
-    The <application>gdk-pixbuf</application> library provides a
-    simple mechanism for loading an image from a file in synchronous
-    fashion.  This means that the library takes control of the
-    application while the file is being loaded; from the user's point
-    of view, the application will block until the image is done
-    loading.
+    The &gdk-pixbuf; library provides a simple mechanism for loading
+    an image from a file in synchronous fashion.  This means that the
+    library takes control of the application while the file is being
+    loaded; from the user's point of view, the application will block
+    until the image is done loading.
   </para>
 
   <para>
index a8f01a9aa01d6c009f763e71dee12808f5a081cc..094a3a188a210d3dd37a657b4b344c97fe7ad63f 100644 (file)
@@ -31,6 +31,10 @@ Drawables to Pixbufs
   </para>
 
 
+<!-- ##### SECTION ./tmpl/xlib-from-drawables.sgml:Title ##### -->
+X Drawables to Pixbufs
+
+
 <!-- ##### FUNCTION gdk_pixbuf_render_pixmap_and_mask ##### -->
 <para>
 
@@ -46,6 +50,21 @@ sgml-parent-document: ("../gdk-pixbuf.sgml" "book" "refsect2" "")
 End:
 -->
 
+<!-- ##### ARG GnomeCanvasPixbuf:width ##### -->
+  <para>
+    Indicates the width the pixbuf will be scaled to.  This argument
+    will only be used if the <link
+    linkend="GnomeCanvasPixbuf--width-set">width_set</link> argument
+    is %TRUE.  If the <link
+    linkend="GnomeCanvasPixbuf--width-in-pixels">width_in_pixels</link>
+    argument is %FALSE, the width will be taken to be in canvas units,
+    and thus will be scaled along with the canvas item's affine
+    transformation.  If width_in_pixels is %TRUE, the width will be
+    taken to be in pixels, and will visually remain a constant size
+    even if the item's affine transformation changes.
+  </para>
+
+
 <!-- ##### FUNCTION gdk_pixbuf_render_to_drawable ##### -->
 <para>
 
@@ -85,6 +104,43 @@ sgml-parent-document: ("../gdk-pixbuf.sgml" "book" "refsect2" "")
 End:
 -->
 
+<!-- ##### ARG GnomeCanvasPixbuf:x ##### -->
+  <para>
+    Indicates the horizontal translation offset of the pixbuf item's
+    image.  This offset may not actually appear horizontal, since it
+    will be affected by the item's affine transformation.  The default
+    is 0.0.
+  </para>
+
+
+<!-- ##### ARG GnomeCanvasPixbuf:y ##### -->
+  <para>
+    Indicates the vertical translation offset of the pixbuf item's
+    image.  Works in the same way as the <link
+    linkend="GnomeCanvasPixbuf--x">x</link> argument.  The default is
+    0.0.
+  </para>
+
+
+<!-- ##### SECTION ./tmpl/xlib-init.sgml:Short_Description ##### -->
+Initializing the &gdk-pixbuf; Xlib library.
+
+
+<!-- ##### SECTION ./tmpl/xlib-from-drawables.sgml:Long_Description ##### -->
+  <para>
+    The functions in this section allow you to take the image data
+    from an X drawable and dump it into a #GdkPixbuf.  This can be
+    used for screenshots and other special effects.  Note that these
+    operations can be expensive, since the image data has to be
+    transferred from the X server to the client program and converted.
+  </para>
+
+  <para>
+    These functions are analogous to those for the Gdk version of
+    &gdk-pixbuf;.
+  </para>
+
+
 <!-- ##### FUNCTION gdk_pixbuf_new_from_art_pixbuf ##### -->
 <para>
 
@@ -93,16 +149,94 @@ End:
 @art_pixbuf: 
 @Returns: 
 
+<!-- ##### SECTION ./tmpl/xlib-init.sgml:See_Also ##### -->
+  <para>
+    XlibRGB
+  </para>
+
+
+<!-- ##### ARG GnomeCanvasPixbuf:y_in_pixels ##### -->
+  <para>
+    Works in the same way as the <link
+    linkend="GnomeCanvasPixbuf--x-in-pixels">x_in_pixels</link>
+    argument, but controls whether the <link
+    linkend="GnomeCanvasPixbuf--y">y</link> translation offset is
+    scaled or not.  The default is %FALSE.
+  </para>
+
+<!--
+Local variables:
+mode: sgml
+sgml-parent-document: ("../gdk-pixbuf.sgml" "book" "refsect2" "")
+End:
+-->
+
+
+<!-- ##### SECTION ./tmpl/gnome-canvas-pixbuf.sgml:See_Also ##### -->
+  <para>
+    #GnomeCanvas, #GdkPixbuf
+  </para>
+
+
+<!-- ##### ARG GnomeCanvasPixbuf:pixbuf ##### -->
+  <para>
+    Contains a pointer to a #GdkPixbuf structure that will be used by
+    the pixbuf canvas item as an image source.  When a pixbuf is set
+    its reference count is incremented; if the pixbuf item kept a
+    pointer to another #GdkPixbuf structure, the reference count of
+    this structure will be decremented.  Also, the GdkPixbuf's
+    reference count will automatically be decremented when the
+    #GnomeCanvasPixbuf item is destroyed.  When a pixbuf is queried, a
+    reference count will not be added to the return value; you must do
+    this yourself if you intend to keep the pixbuf structure around.
+  </para>
+
+
 <!-- ##### ARG GnomeCanvasPixbuf:y_pixels ##### -->
 <para>
 
 </para>
 
 
+<!-- ##### SECTION ./tmpl/xlib-rgb.sgml:See_Also ##### -->
+  <para>
+    GdkRGB
+  </para>
+
+
+<!-- ##### SECTION ./tmpl/xlib-rendering.sgml:Long_Description ##### -->
+  <para>
+    The &gdk-pixbuf; Xlib library provides several convenience
+    functions to render pixbufs to X drawables.  It uses XlibRGB to
+    render the image data.
+  </para>
+
+  <para>
+    These functions are analogous to those for the Gdk version of
+    &gdk-pixbuf;.
+  </para>
+
+
 <!-- ##### SECTION ./tmpl/gdk-pixbuf-io.sgml:Short_Description ##### -->
 
 
 
+<!-- ##### SECTION ./tmpl/gnome-canvas-pixbuf.sgml:Short_Description ##### -->
+Canvas item to display #GdkPixbuf images.
+
+
+<!-- ##### ARG GnomeCanvasPixbuf:x_in_pixels ##### -->
+  <para>
+    If this argument is %TRUE, the pixbuf's translation with respect
+    to its logical origin in item-relative coordinates will be in
+    pixels, that is, the visible offset will not change even if the
+    item's affine transformation changes.  If it is %FALSE, the
+    pixbuf's translation will be taken to be in canvas units, and thus
+    will change along with the item's affine transformation.  The
+    default is %FALSE.
+  </para>
+
+
 <!-- ##### SECTION ./tmpl/from-drawables.sgml:Long_Description ##### -->
   <para>
     The functions in this section allow you to take the image data
@@ -113,12 +247,36 @@ End:
   </para>
 
 
+<!-- ##### SECTION ./tmpl/xlib-rgb.sgml:Long_Description ##### -->
+  <para>
+    The XlibRGB set of functions is a port of the GdkRGB library to
+    use plain Xlib and X drawables.  You can use these functions to
+    render RGB buffers into drawables very quickly with high-quality
+    dithering.
+  </para>
+
+
+<!-- ##### SECTION ./tmpl/xlib-rgb.sgml:Short_Description ##### -->
+Functions for rendering RGB buffers to X drawables.
+
+
+<!-- ##### MACRO GNOME_CANVAS_PIXBUF ##### -->
+  <para>
+    Casts a #GtkOjbect to a #GnomeCanvasPixbuf.
+  </para>
+
+@obj: A GTK+ object.
+
 <!-- ##### SECTION ./tmpl/gdk-pixbuf-io.sgml:See_Also ##### -->
 <para>
 
 </para>
 
 
+<!-- ##### SECTION ./tmpl/xlib-rendering.sgml:Short_Description ##### -->
+Rendering a pixbuf to an X drawable.
+
+
 <!-- ##### FUNCTION gdk_pixbuf_finalize ##### -->
 <para>
 
@@ -153,6 +311,31 @@ Rendering a pixbuf to a GDK drawable.
   </para>
 
 
+<!-- ##### ARG GnomeCanvasPixbuf:width_in_pixels ##### -->
+  <para>
+    If this argument is %TRUE, then the width of the pixbuf will be
+    considered to be in pixels, that is, it will not be visually
+    scaled even if the item's affine transformation changes.  If this
+    is %FALSE, then the width of the pixbuf will be considered to be
+    in canvas units, and so will be scaled normally by affine
+    transformations.  The default is %FALSE.
+  </para>
+
+
+<!-- ##### SECTION ./tmpl/xlib-init.sgml:Long_Description ##### -->
+  <para>
+    In addition to the normal Gdk-specific functions, the &gdk-pixbuf;
+    package provides a small library that lets Xlib-only applications
+    use #GdkPixbuf structures and render them to X drawables.  The
+    functions in this section are used to initialize the &gdk-pixbuf;
+    Xlib library.  This library must be initialized near the beginning
+    or the program or before calling any of the other &gdk-pixbuf;
+    Xlib functions; it cannot be initialized automatically since
+    Xlib-only applications do not call gdk_rgb_init() like GNOME
+    applications do.
+  </para>
+
+
 <!-- ##### FUNCTION gdk_pixbuf_get_format ##### -->
 <para>
 
@@ -161,6 +344,30 @@ Rendering a pixbuf to a GDK drawable.
 @pixbuf: 
 @Returns: 
 
+<!-- ##### ARG GnomeCanvasPixbuf:height_in_pixels ##### -->
+  <para>
+    Works in the same way as the <link
+    linkend="GnomeCanvasPixbuf--width-in-pixels">width_in_pixels</link>
+    argument.  The default is %FALSE.
+  </para>
+
+
+<!-- ##### SECTION ./tmpl/xlib-rendering.sgml:See_Also ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### ARG GnomeCanvasPixbuf:width_set ##### -->
+  <para>
+    Determines whether the <link
+    linkend="GnomeCanvasPixbuf--width">width</link> argument is taken
+    into account when scaling the pixbuf item.  If this argument is
+    %FALSE, then the width value of the pixbuf will be used instead.
+    This argument is %FALSE by default.
+  </para>
+
+
 <!-- ##### FUNCTION gdk_pixbuf_render_to_drawable_alpha ##### -->
 <para>
 
@@ -180,22 +387,54 @@ Rendering a pixbuf to a GDK drawable.
 @x_dither: 
 @y_dither: 
 
+<!-- ##### SECTION ./tmpl/xlib-init.sgml:Title ##### -->
+&gdk-pixbuf; Xlib initialization
+
+
+<!-- ##### SECTION ./tmpl/xlib-from-drawables.sgml:Short_Description ##### -->
+Getting parts of an X drawable's image data into a pixbuf.
+
+
+<!-- ##### SECTION ./tmpl/xlib-rgb.sgml:Title ##### -->
+XlibRGB
+
+
 <!-- ##### ARG GnomeCanvasPixbuf:x_pixels ##### -->
 <para>
 
 </para>
 
 
+<!-- ##### ARG GnomeCanvasPixbuf:height ##### -->
+  <para>
+    Indicates the height the pixbuf will be scaled to.  This argument
+    will only be used if the <link
+    linkend="GnomeCanvasPixbuf--height-set">height_set</link> argument
+    is %TRUE.  Works in the same way as the <link
+    linkend="GnomeCanvasPixbuf--width">width</link> argument.
+  </para>
+
+
 <!-- ##### SECTION ./tmpl/from-drawables.sgml:See_Also ##### -->
   <para>
     gdk_image_get().
   </para>
 
 
+<!-- ##### SECTION ./tmpl/xlib-from-drawables.sgml:See_Also ##### -->
+<para>
+
+</para>
+
+
 <!-- ##### SECTION ./tmpl/rendering.sgml:Title ##### -->
 Rendering
 
 
+<!-- ##### SECTION ./tmpl/gnome-canvas-pixbuf.sgml:Title ##### -->
+GnomeCanvasPixbuf
+
+
 <!-- ##### MACRO GDK_PIXBUF_LOADER ##### -->
   <para>
     Casts a #GtkObject to a #GdkPixbufLoader.
@@ -216,19 +455,18 @@ Rendering
 
 <!-- ##### SECTION ./tmpl/rendering.sgml:Long_Description ##### -->
   <para>
-    The <application>gdk-pixbuf</application> library provides several
-    convenience functions to render pixbufs to GDK drawables.  It uses
-    the GdkRGB to render the image data.
+    The &gdk-pixbuf; library provides several convenience functions to
+    render pixbufs to GDK drawables.  It uses the GdkRGB to render the
+    image data.
   </para>
 
   <para>
     At this point there is not a standard alpha channel extension for
     the X Window System, so it is not possible to use full opacity
     information when painting images to arbitrary drawables.  The
-    <application>gdk-pixbuf</application> convenience functions will
-    threshold the opacity information to create a bi-level clipping
-    mask (black and white), and use that to draw the image onto a
-    drawable.
+    &gdk-pixbuf; convenience functions will threshold the opacity
+    information to create a bi-level clipping mask (black and white),
+    and use that to draw the image onto a drawable.
   </para>
 
   <important>
@@ -290,6 +528,190 @@ In the future it will do full alpha compositing.
 </para>
 
 
+<!-- ##### SECTION ./tmpl/gnome-canvas-pixbuf.sgml:Long_Description ##### -->
+  <para>
+    This canvas item displays #GdkPixbuf images.  It handles full
+    affine transformations in both GDK and antialiased modes, and also
+    supports the <ulink url="http://www.w3.org">W3C</ulink>'s <ulink
+    url="http://www.w3.org/Graphics/SVG/">SVG</ulink>-like scaling and
+    translation semantics for absolute pixel values.
+  </para>
+
+  <para>
+    #GdkPixbuf structures may be shared among different pixbuf canvas
+    items; the pixbuf item uses #GdkPixbuf's reference counting
+    functions for this.
+  </para>
+
+  <refsect2>
+    <title>Custom Scaling and Translation</title>
+
+    <para>
+      In addition to the normal affine transformations supported by
+      canvas items, the #GnomeCanvasPixbuf item supports independent
+      object arguments for scaling and translation.  This is useful
+      for explicitly setting a size to which the pixbuf's image will
+      be scaled, and for specifying translation offsets that take
+      place in the item's local coordinate system.
+    </para>
+
+    <para>
+      By default, the pixbuf canvas item will attain the size in units
+      of the #GdkPixbuf it contains.  If a #GnomeCanvasPixbuf is
+      configured to use a #GdkPixbuf that has a size of 300 by 200
+      pixels, then the pixbuf item will automatically obtain a size of
+      300 by 200 units in the item's local coordinate system.  If the
+      item is transformed with a scaling transformation of (0.5, 2.0),
+      then the final image size will be of 150 by 400 pixels.
+    </para>
+
+    <para>
+      To set custom width and height values, you must set the <link
+      linkend="GnomeCanvasPixbuf--width-set">width_set</link> or <link
+      linkend="GnomeCanvasPixbuf--height-set">height_set</link>
+      arguments to %TRUE, and then set the <link
+      linkend="GnomeCanvasPixbuf--width">width</link> or <link
+      linkend="GnomeCanvasPixbuf--height">height</link> arguments to
+      the desired values.  The former two arguments control whether
+      the latter two are used when computing the final image's size;
+      they are both %FALSE by default so that the pixbuf item will
+      attain a size in units equal to the size in pixels of the
+      #GdkPixbuf that the item contains.
+    </para>
+
+    <para>
+      The custom translation offsets are controlled by the <link
+      linkend="GnomeCanvasPixbuf--x">x</link> and <link
+      linkend="GnomeCanvasPixbuf--y">y</link> arguments.  The logical
+      upper-left vertex of the image will be translated by the
+      specified distance, aligned with the item's local coordinate
+      system.
+    </para>
+  </refsect2>
+
+  <refsect2>
+    <title>Absolute Pixel Scaling and Translation</title>
+
+    <para>
+      The <ulink url="http://www.w3.org/Graphics/SVG/">Scalable Vector
+      Graphics</ulink> specification (SVG) of the <ulink
+      url="http://www.w3.org">World Wide Web Consortium</ulink> also
+      allows images to be translated and scaled by absolute pixel
+      values that are independent of an item's normal affine
+      transformation.
+    </para>
+
+    <para>
+      Normally, the pixbuf item's translation and scaling arguments
+      are interpreted in units, so they will be modified by the item's
+      affine transformation.  The <link
+      linkend="GnomeCanvasPixbuf--width-in-pixels">width_in_pixels</link>,
+      <link
+      linkend="GnomeCanvasPixbuf--height-in-pixels">height_in_pixels</link>,
+      <link
+      linkend="GnomeCanvasPixbuf--x-in-pixels">x_in_pixels</link>, and
+      <link
+      linkend="GnomeCanvasPixbuf--y-in-pixels">y_in_pixels</link>
+      object arguments can be used to modify this behavior.  If one of
+      these arguments is %TRUE, then the corresponding scaling or
+      translation value will not be affected lengthwise by the pixbuf
+      item's affine transformation.
+    </para>
+
+    <para>
+      For example, consider a pixbuf item whose size is (300, 200).
+      If the item is modified with a scaling transformation of (0.5,
+      2.0) but the <link
+      linkend="GnomeCanvasPixbuf--width-in-pixels">width_in_pixels</link>
+      is set to %TRUE, then the item will appear to be (300, 400)
+      pixels in size.  This means that in this case the item's affine
+      transformation only applies to the height value, while the width
+      value is kept in absolute pixels.
+    </para>
+
+    <para>
+      Likewise, consider a pixbuf item whose (<link
+      linkend="GnomeCanvasPixbuf--x">x</link>, <link
+      linkend="GnomeCanvasPixbuf--y">y</link>) arguments are set to
+      (30, 40).  If the item is then modified by the same scaling
+      transformation of (0.5, 2.0) but the <link
+      linkend="GnomeCanvasPixbuf--y-in-pixels">y_in_pixels</link>
+      argument is set to %TRUE, then the image's upper-left corner
+      will appear to be at position (15, 40).  In this case, the
+      affine transformation is applied only to the x offset, while the
+      y offset is kept in absolute pixels.
+    </para>
+
+    <para>
+      In short, these arguments control whether a particular dimension
+      of a pixbuf item is scaled or not in the normal way by the
+      item's affine transformation.
+    </para>
+  </refsect2>
+
+  <refsect2>
+    <title>Resource Management</title>
+
+    <para>
+      When you set the #GdkPixbuf structure that a #GnomeCanvasPixbuf
+      item will use by setting the <link
+      linkend="GnomeCanvasPixbuf--pixbuf">pixbuf</link> argument, a
+      reference count will be added to that #GdkPixbuf structure.
+      When the pixbuf item no longer needs the #GdkPixbuf structure,
+      such as when the item is destroyed or when a new pixbuf
+      structure is passed to it, then the old #GdkPixbuf structure
+      will be automatically unreferenced.
+    </para>
+
+    <para>
+      This means that if an application just needs to load a pixbuf
+      image and set it into a pixbuf canvas item, it can do the
+      following to &lsquo;forget&rsquo; about the pixbuf structure:
+
+      <programlisting>
+       GdkPixbuf *pixbuf;
+       GnomeCanvasItem *item;
+
+       pixbuf = gdk_pixbuf_new_from_file ("foo.png");
+       g_assert (pixbuf != NULL);
+
+       item = gnome_canvas_item_new (gnome_canvas_root (my_canvas),
+                                     gnome_canvas_pixbuf_get_type (),
+                                     "pixbuf", pixbuf,
+                                     NULL);
+       gdk_pixbuf_unref (pixbuf);
+      </programlisting>
+    </para>
+
+    <para>
+      After this happens, the reference count of the pixbuf structure
+      will be 1:  the gdk_pixbuf_new_from_file() function creates it
+      with a reference count of 1, then setting the <link
+      linkend="GnomeCanvasPixbuf--pixbuf">pixbuf</link> argument of
+      the #GnomeCanvasPixbuf item increases it to 2, and then it is
+      decremented to 1 by the call to gdk_pixbuf_unref().  When the
+      canvas item is destroyed, it will automatically unreference the
+      pixbuf structure again, causing its reference count to drop to
+      zero and thus be freed.
+    </para>
+  </refsect2>
+
+
+<!-- ##### SECTION ./tmpl/xlib-rendering.sgml:Title ##### -->
+Xlib Rendering
+
+
+<!-- ##### ARG GnomeCanvasPixbuf:height_set ##### -->
+  <para>
+    Determines whether the <link
+    linkend="GnomeCanvasPixbuf--height">height</link> argument is
+    taken into account when scaling the pixbuf item.  Works in the
+    same way as the <link
+    linkend="GnomeCanvasPixbuf--width-set">width_set</link> argument.
+    The default is %FALSE.
+  </para>
+
+
 <!-- ##### SECTION ./tmpl/gdk-pixbuf-io.sgml:Title ##### -->
 gdk-pixbuf-io
 
diff --git a/docs/reference/gdk-pixbuf/tmpl/gdk-pixbuf-xlib-from-drawables.sgml b/docs/reference/gdk-pixbuf/tmpl/gdk-pixbuf-xlib-from-drawables.sgml
new file mode 100644 (file)
index 0000000..fd59f2d
--- /dev/null
@@ -0,0 +1,48 @@
+<!-- ##### SECTION Title ##### -->
+X Drawables to Pixbufs
+
+<!-- ##### SECTION Short_Description ##### -->
+Getting parts of an X drawable's image data into a pixbuf.
+
+<!-- ##### SECTION Long_Description ##### -->
+  <para>
+    The functions in this section allow you to take the image data
+    from an X drawable and dump it into a #GdkPixbuf.  This can be
+    used for screenshots and other special effects.  Note that these
+    operations can be expensive, since the image data has to be
+    transferred from the X server to the client program and converted.
+  </para>
+
+  <para>
+    These functions are analogous to those for the Gdk version of
+    &gdk-pixbuf;.
+  </para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### FUNCTION gdk_pixbuf_xlib_get_from_drawable ##### -->
+<para>
+
+</para>
+
+@dest: 
+@src: 
+@cmap: 
+@visual: 
+@src_x: 
+@src_y: 
+@dest_x: 
+@dest_y: 
+@width: 
+@height: 
+@Returns: <!--
+Local variables:
+mode: sgml
+sgml-parent-document: ("../gdk-pixbuf.sgml" "book" "refsect2" "")
+End:
+-->
+
+
diff --git a/docs/reference/gdk-pixbuf/tmpl/gdk-pixbuf-xlib-init.sgml b/docs/reference/gdk-pixbuf/tmpl/gdk-pixbuf-xlib-init.sgml
new file mode 100644 (file)
index 0000000..e841a19
--- /dev/null
@@ -0,0 +1,48 @@
+<!-- ##### SECTION Title ##### -->
+&gdk-pixbuf; Xlib initialization
+
+<!-- ##### SECTION Short_Description ##### -->
+Initializing the &gdk-pixbuf; Xlib library.
+
+<!-- ##### SECTION Long_Description ##### -->
+  <para>
+    In addition to the normal Gdk-specific functions, the &gdk-pixbuf;
+    package provides a small library that lets Xlib-only applications
+    use #GdkPixbuf structures and render them to X drawables.  The
+    functions in this section are used to initialize the &gdk-pixbuf;
+    Xlib library.  This library must be initialized near the beginning
+    or the program or before calling any of the other &gdk-pixbuf;
+    Xlib functions; it cannot be initialized automatically since
+    Xlib-only applications do not call gdk_rgb_init() like GNOME
+    applications do.
+  </para>
+
+<!-- ##### SECTION See_Also ##### -->
+  <para>
+    XlibRGB
+  </para>
+
+<!-- ##### FUNCTION gdk_pixbuf_xlib_init ##### -->
+<para>
+
+</para>
+
+@display: 
+@screen_num: 
+
+
+<!-- ##### FUNCTION gdk_pixbuf_xlib_init_with_depth ##### -->
+<para>
+
+</para>
+
+@display: 
+@screen_num: 
+@prefDepth: <!--
+Local variables:
+mode: sgml
+sgml-parent-document: ("../gdk-pixbuf.sgml" "book" "refsect2" "")
+End:
+-->
+
+
diff --git a/docs/reference/gdk-pixbuf/tmpl/gdk-pixbuf-xlib-rendering.sgml b/docs/reference/gdk-pixbuf/tmpl/gdk-pixbuf-xlib-rendering.sgml
new file mode 100644 (file)
index 0000000..46c6ac0
--- /dev/null
@@ -0,0 +1,94 @@
+<!-- ##### SECTION Title ##### -->
+Xlib Rendering
+
+<!-- ##### SECTION Short_Description ##### -->
+Rendering a pixbuf to an X drawable.
+
+<!-- ##### SECTION Long_Description ##### -->
+  <para>
+    The &gdk-pixbuf; Xlib library provides several convenience
+    functions to render pixbufs to X drawables.  It uses XlibRGB to
+    render the image data.
+  </para>
+
+  <para>
+    These functions are analogous to those for the Gdk version of
+    &gdk-pixbuf;.
+  </para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### FUNCTION gdk_pixbuf_xlib_render_threshold_alpha ##### -->
+<para>
+
+</para>
+
+@pixbuf: 
+@bitmap: 
+@src_x: 
+@src_y: 
+@dest_x: 
+@dest_y: 
+@width: 
+@height: 
+@alpha_threshold: 
+
+
+<!-- ##### FUNCTION gdk_pixbuf_xlib_render_to_drawable ##### -->
+<para>
+
+</para>
+
+@pixbuf: 
+@drawable: 
+@gc: 
+@src_x: 
+@src_y: 
+@dest_x: 
+@dest_y: 
+@width: 
+@height: 
+@dither: 
+@x_dither: 
+@y_dither: 
+
+
+<!-- ##### FUNCTION gdk_pixbuf_xlib_render_to_drawable_alpha ##### -->
+<para>
+
+</para>
+
+@pixbuf: 
+@drawable: 
+@src_x: 
+@src_y: 
+@dest_x: 
+@dest_y: 
+@width: 
+@height: 
+@alpha_mode: 
+@alpha_threshold: 
+@dither: 
+@x_dither: 
+@y_dither: 
+
+
+<!-- ##### FUNCTION gdk_pixbuf_xlib_render_pixmap_and_mask ##### -->
+<para>
+
+</para>
+
+@pixbuf: 
+@pixmap_return: 
+@mask_return: 
+@alpha_threshold: <!--
+Local variables:
+mode: sgml
+sgml-parent-document: ("../gdk-pixbuf.sgml" "book" "refsect2" "")
+End:
+-->
+
+
diff --git a/docs/reference/gdk-pixbuf/tmpl/gdk-pixbuf-xlib-rgb.sgml b/docs/reference/gdk-pixbuf/tmpl/gdk-pixbuf-xlib-rgb.sgml
new file mode 100644 (file)
index 0000000..7ddc621
--- /dev/null
@@ -0,0 +1,268 @@
+<!-- ##### SECTION Title ##### -->
+XlibRGB
+
+<!-- ##### SECTION Short_Description ##### -->
+Functions for rendering RGB buffers to X drawables.
+
+<!-- ##### SECTION Long_Description ##### -->
+  <para>
+    The XlibRGB set of functions is a port of the GdkRGB library to
+    use plain Xlib and X drawables.  You can use these functions to
+    render RGB buffers into drawables very quickly with high-quality
+    dithering.
+  </para>
+
+<!-- ##### SECTION See_Also ##### -->
+  <para>
+    GdkRGB
+  </para>
+
+<!-- ##### STRUCT XlibRgbCmap ##### -->
+  <para>
+    FIXME: Describe this.
+  </para>
+
+@colors: FIXME.
+@lut: FIXME.
+
+<!-- ##### ENUM XlibRgbDither ##### -->
+  <para>
+    These values are used to specify which dithering method should be
+    used.  <symbol>XLIB_RGB_DITHER_NONE</symbol> will use no dithering
+    and simply map the colors in an RGB buffer to the closest colors
+    that the display can provide.
+    <symbol>XLIB_RGB_DITHER_NORMAL</symbol> will provide dithering
+    only on pseudocolor displays.
+    <symbol>XLIB_RGB_DITHER_MAX</symbol> will provide dithering on
+    pseudocolor and 16-bit truecolor or &ldquo;high color&rdquo;
+    displays.
+  </para>
+
+@XLIB_RGB_DITHER_NONE: Specifies no dithering.
+@XLIB_RGB_DITHER_NORMAL: Specifies dithering only on pseudocolor
+displays.
+@XLIB_RGB_DITHER_MAX: Specifies dithering on high color displays.
+
+<!-- ##### FUNCTION xlib_rgb_init ##### -->
+<para>
+
+</para>
+
+@display: 
+@screen: 
+
+
+<!-- ##### FUNCTION xlib_rgb_init_with_depth ##### -->
+<para>
+
+</para>
+
+@display: 
+@screen: 
+@prefDepth: 
+
+
+<!-- ##### FUNCTION xlib_rgb_gc_set_foreground ##### -->
+<para>
+
+</para>
+
+@gc: 
+@rgb: 
+
+
+<!-- ##### FUNCTION xlib_rgb_gc_set_background ##### -->
+<para>
+
+</para>
+
+@gc: 
+@rgb: 
+
+
+<!-- ##### FUNCTION xlib_draw_rgb_image ##### -->
+<para>
+
+</para>
+
+@drawable: 
+@gc: 
+@x: 
+@y: 
+@width: 
+@height: 
+@dith: 
+@rgb_buf: 
+@rowstride: 
+
+
+<!-- ##### FUNCTION xlib_draw_rgb_image_dithalign ##### -->
+<para>
+
+</para>
+
+@drawable: 
+@gc: 
+@x: 
+@y: 
+@width: 
+@height: 
+@dith: 
+@rgb_buf: 
+@rowstride: 
+@xdith: 
+@ydith: 
+
+
+<!-- ##### FUNCTION xlib_draw_rgb_32_image ##### -->
+<para>
+
+</para>
+
+@drawable: 
+@gc: 
+@x: 
+@y: 
+@width: 
+@height: 
+@dith: 
+@buf: 
+@rowstride: 
+
+
+<!-- ##### FUNCTION xlib_draw_gray_image ##### -->
+<para>
+
+</para>
+
+@drawable: 
+@gc: 
+@x: 
+@y: 
+@width: 
+@height: 
+@dith: 
+@buf: 
+@rowstride: 
+
+
+<!-- ##### FUNCTION xlib_rgb_cmap_new ##### -->
+<para>
+
+</para>
+
+@colors: 
+@n_colors: 
+@Returns: 
+
+
+<!-- ##### FUNCTION xlib_rgb_cmap_free ##### -->
+<para>
+
+</para>
+
+@cmap: 
+
+
+<!-- ##### FUNCTION xlib_draw_indexed_image ##### -->
+<para>
+
+</para>
+
+@drawable: 
+@gc: 
+@x: 
+@y: 
+@width: 
+@height: 
+@dith: 
+@buf: 
+@rowstride: 
+@cmap: 
+
+
+<!-- ##### FUNCTION xlib_rgb_ditherable ##### -->
+<para>
+
+</para>
+
+@Returns: 
+
+
+<!-- ##### FUNCTION xlib_rgb_set_verbose ##### -->
+<para>
+
+</para>
+
+@verbose: 
+
+
+<!-- ##### FUNCTION xlib_rgb_set_install ##### -->
+<para>
+
+</para>
+
+@install: 
+
+
+<!-- ##### FUNCTION xlib_rgb_set_min_colors ##### -->
+<para>
+
+</para>
+
+@min_colors: 
+
+
+<!-- ##### FUNCTION xlib_rgb_get_cmap ##### -->
+<para>
+
+</para>
+
+@Returns: 
+
+
+<!-- ##### FUNCTION xlib_rgb_get_visual ##### -->
+<para>
+
+</para>
+
+@Returns: 
+
+
+<!-- ##### FUNCTION xlib_rgb_get_visual_info ##### -->
+<para>
+
+</para>
+
+@Returns: 
+
+
+<!-- ##### FUNCTION xlib_rgb_get_depth ##### -->
+<para>
+
+</para>
+
+@Returns: 
+
+
+<!-- ##### FUNCTION xlib_rgb_get_display ##### -->
+<para>
+
+</para>
+
+@Returns: 
+
+
+<!-- ##### FUNCTION xlib_rgb_get_screen ##### -->
+<para>
+
+</para>
+
+@Returns: <!--
+Local variables:
+mode: sgml
+sgml-parent-document: ("../gdk-pixbuf.sgml" "book" "refsect2" "")
+End:
+-->
+
+
index 9decee1787a283cf89d61cf2af4c8b593aeb75b2..08b549d0fc0578b363f5da57e92cac0e99f79b41 100644 (file)
@@ -18,19 +18,17 @@ Information that describes an image.
 <!-- ##### ENUM GdkColorspace ##### -->
   <para>
     This enumeration defines the color spaces that are supported by
-    the <application>gdk-pixbuf</application> library.  Currently only
-    RGB is supported.
+    the &gdk-pixbuf; library.  Currently only RGB is supported.
   </para>
 
 @GDK_COLORSPACE_RGB: Indicates a red/green/blue additive color space.
 
 <!-- ##### STRUCT GdkPixbuf ##### -->
   <para>
-    This is the main structure in the
-    <application>gdk-pixbuf</application> library.  It is used to
-    represent images.  It contains information about the image's pixel
-    data, its color space, bits per sample, width and height, and the
-    rowstride or number of bytes between rows.
+    This is the main structure in the &gdk-pixbuf; library.  It is
+    used to represent images.  It contains information about the
+    image's pixel data, its color space, bits per sample, width and
+    height, and the rowstride or number of bytes between rows.
   </para>
 
 @parent_instance: 
index b1719b79747abe90298d82a3723ed4fbc9ce5c25..c0a33f2eeeb0829aeccde96a3f805260de36b55e 100644 (file)
@@ -68,6 +68,7 @@ Module Interface
 @stop_load: 
 @load_increment: 
 @load_animation: 
+@save: 
 
 <!-- ##### FUNCTION gdk_pixbuf_get_module ##### -->
 <para>
index 0e4cf95a5698eaf5d1ea32488936bb7ad601d52c..a8d41a1170bdf3cc68f195fc433255627d2421c3 100644 (file)
@@ -6,12 +6,11 @@ Scaling pixbufs and scaling and compositing pixbufs
 
 <!-- ##### SECTION Long_Description ##### -->
   <para>
-    The <application>gdk-pixbuf</application> contains functions to
-    scale pixbufs, to scale pixbufs and composite against an existing
-    image, and to scale pixbufs and composite against a solid color or
-    checkerboard.  Compositing a checkerboard is a common way to show
-    an image with an alpha channel in image-viewing and editing
-    software.
+    The &gdk-pixbuf; contains functions to scale pixbufs, to scale
+    pixbufs and composite against an existing image, and to scale
+    pixbufs and composite against a solid color or checkerboard.
+    Compositing a checkerboard is a common way to show an image with
+    an alpha channel in image-viewing and editing software.
   </para>
 
   <para>
index 0d40604f541f31206df8a32e786997023e742d4c..297dddb11a72f52263972cc47d83f44e5bf695d8 100644 (file)
@@ -2611,6 +2611,31 @@ void
 <RETURNS>void  </RETURNS>
 PangoContext *context,GdkColormap  *colormap
 </FUNCTION>
+<FUNCTION>
+<NAME>gdk_pixbuf_render_threshold_alpha</NAME>
+<RETURNS>void  </RETURNS>
+GdkPixbuf           *pixbuf,GdkBitmap           *bitmap,int                  src_x,int                  src_y,int                  dest_x,int                  dest_y,int                  width,int                  height,int                  alpha_threshold
+</FUNCTION>
+<FUNCTION>
+<NAME>gdk_pixbuf_render_to_drawable</NAME>
+<RETURNS>void  </RETURNS>
+GdkPixbuf           *pixbuf,GdkDrawable         *drawable,GdkGC               *gc,int                  src_x,int                  src_y,int                  dest_x,int                  dest_y,int                  width,int                  height,GdkRgbDither         dither,int                  x_dither,int                  y_dither
+</FUNCTION>
+<FUNCTION>
+<NAME>gdk_pixbuf_render_to_drawable_alpha</NAME>
+<RETURNS>void  </RETURNS>
+GdkPixbuf           *pixbuf,GdkDrawable         *drawable,int                  src_x,int                  src_y,int                  dest_x,int                  dest_y,int                  width,int                  height,GdkPixbufAlphaMode   alpha_mode,int                  alpha_threshold,GdkRgbDither         dither,int                  x_dither,int                  y_dither
+</FUNCTION>
+<FUNCTION>
+<NAME>gdk_pixbuf_render_pixmap_and_mask</NAME>
+<RETURNS>void  </RETURNS>
+GdkPixbuf           *pixbuf,GdkPixmap          **pixmap_return,GdkBitmap          **mask_return,int                  alpha_threshold
+</FUNCTION>
+<FUNCTION>
+<NAME>gdk_pixbuf_get_from_drawable</NAME>
+<RETURNS>GdkPixbuf  *</RETURNS>
+GdkPixbuf   *dest,GdkDrawable *src,GdkColormap *cmap,int          src_x,int          src_y,int          dest_x,int          dest_y,int          width,int          height
+</FUNCTION>
 <STRUCT>
 <NAME>GdkPixmapObject</NAME>
 </STRUCT>
@@ -3359,12 +3384,13 @@ typedef enum
 <NAME>GdkWindowHints</NAME>
 typedef enum
 {
-  GDK_HINT_POS       = 1 << 0,
-  GDK_HINT_MIN_SIZE   = 1 << 1,
-  GDK_HINT_MAX_SIZE   = 1 << 2,
-  GDK_HINT_BASE_SIZE  = 1 << 3,
-  GDK_HINT_ASPECT     = 1 << 4,
-  GDK_HINT_RESIZE_INC = 1 << 5
+  GDK_HINT_POS        = 1 << 0,
+  GDK_HINT_MIN_SIZE    = 1 << 1,
+  GDK_HINT_MAX_SIZE    = 1 << 2,
+  GDK_HINT_BASE_SIZE   = 1 << 3,
+  GDK_HINT_ASPECT      = 1 << 4,
+  GDK_HINT_RESIZE_INC  = 1 << 5,
+  GDK_HINT_WIN_GRAVITY = 1 << 6
 } GdkWindowHints;
 </ENUM>
 <ENUM>
@@ -3392,6 +3418,22 @@ typedef enum
   GDK_FUNC_CLOSE       = 1 << 5
 } GdkWMFunction;
 </ENUM>
+<ENUM>
+<NAME>GdkGravity</NAME>
+typedef enum
+{
+  GDK_GRAVITY_NORTH_WEST = 1,
+  GDK_GRAVITY_NORTH,
+  GDK_GRAVITY_NORTH_EAST,
+  GDK_GRAVITY_WEST,
+  GDK_GRAVITY_CENTER,
+  GDK_GRAVITY_EAST,
+  GDK_GRAVITY_SOUTH_WEST,
+  GDK_GRAVITY_SOUTH,
+  GDK_GRAVITY_SOUTH_EAST,
+  GDK_GRAVITY_STATIC
+} GdkGravity;
+</ENUM>
 <STRUCT>
 <NAME>GdkWindowAttr</NAME>
 struct GdkWindowAttr
@@ -3424,7 +3466,7 @@ struct GdkGeometry {
   gint height_inc;
   gdouble min_aspect;
   gdouble max_aspect;
-  /* GdkGravity gravity; */
+  GdkGravity win_gravity;
 };
 </STRUCT>
 <STRUCT>
@@ -3795,6 +3837,11 @@ GdkWindow          *window,GdkWMFunction    functions
 void
 </FUNCTION>
 <FUNCTION>
+<NAME>gdk_window_iconify</NAME>
+<RETURNS>void  </RETURNS>
+GdkWindow       *window
+</FUNCTION>
+<FUNCTION>
 <NAME>gdk_window_register_dnd</NAME>
 <RETURNS>void  </RETURNS>
 GdkWindow       *window
@@ -3846,36 +3893,3 @@ GdkWindow    *window,gboolean      update_children
 <NAME>GDK_HAVE_WCTYPE_H</NAME>
 #define GDK_HAVE_WCTYPE_H 1
 </MACRO>
-<ENUM>
-<NAME>GdkPixbufAlphaMode</NAME>
-typedef enum
-{
-  GDK_PIXBUF_ALPHA_BILEVEL,
-  GDK_PIXBUF_ALPHA_FULL
-} GdkPixbufAlphaMode;
-</ENUM>
-<FUNCTION>
-<NAME>gdk_pixbuf_render_threshold_alpha</NAME>
-<RETURNS>void  </RETURNS>
-GdkPixbuf           *pixbuf,GdkBitmap           *bitmap,int                  src_x,int                  src_y,int                  dest_x,int                  dest_y,int                  width,int                  height,int                  alpha_threshold
-</FUNCTION>
-<FUNCTION>
-<NAME>gdk_pixbuf_render_to_drawable</NAME>
-<RETURNS>void  </RETURNS>
-GdkPixbuf           *pixbuf,GdkDrawable         *drawable,GdkGC               *gc,int                  src_x,int                  src_y,int                  dest_x,int                  dest_y,int                  width,int                  height,GdkRgbDither         dither,int                  x_dither,int                  y_dither
-</FUNCTION>
-<FUNCTION>
-<NAME>gdk_pixbuf_render_to_drawable_alpha</NAME>
-<RETURNS>void  </RETURNS>
-GdkPixbuf           *pixbuf,GdkDrawable         *drawable,int                  src_x,int                  src_y,int                  dest_x,int                  dest_y,int                  width,int                  height,GdkPixbufAlphaMode   alpha_mode,int                  alpha_threshold,GdkRgbDither         dither,int                  x_dither,int                  y_dither
-</FUNCTION>
-<FUNCTION>
-<NAME>gdk_pixbuf_render_pixmap_and_mask</NAME>
-<RETURNS>void  </RETURNS>
-GdkPixbuf           *pixbuf,GdkPixmap          **pixmap_return,GdkBitmap          **mask_return,int                  alpha_threshold
-</FUNCTION>
-<FUNCTION>
-<NAME>gdk_pixbuf_get_from_drawable</NAME>
-<RETURNS>GdkPixbuf  *</RETURNS>
-GdkPixbuf   *dest,GdkDrawable *src,GdkColormap *cmap,int          src_x,int          src_y,int          dest_x,int          dest_y,int          width,int          height
-</FUNCTION>
index 8da5b437732165d0891324c36a0a2a4c1831befc..51d744473ecccc5eb7cbb51d3a4311dde39119c9 100644 (file)
@@ -25,9 +25,9 @@
 <!entity gdk-Cursors SYSTEM "sgml/cursors.sgml">
 <!entity gdk-Input SYSTEM "sgml/input.sgml">
 <!entity gdk-Drag-and-Drop SYSTEM "sgml/dnd.sgml">
-<!entity gdk-X-Window-System-Interaction SYSTEM
-"sgml/x_interaction.sgml">
+<!entity gdk-X-Window-System-Interaction SYSTEM "sgml/x_interaction.sgml">
 ]>
+
 <book id="index">
   <bookinfo>
     <title>GDK Reference Manual</title>
index 7b727e7c23aa73642eb021eb9902b1e19a158bd5..f455390216a776a3d520ca54cdd827fd7f9cc001 100644 (file)
@@ -110,6 +110,14 @@ configuration information.
 </para>
 
 
+<!-- ##### ENUM GdkPixbufAlphaMode ##### -->
+<para>
+
+</para>
+
+@GDK_PIXBUF_ALPHA_BILEVEL: 
+@GDK_PIXBUF_ALPHA_FULL: 
+
 <!-- ##### FUNCTION gdk_regions_subtract ##### -->
 <para>
 Subtracts one region from another.
index b11da1c1ddc0c956252605d73c5b6016b3629076..a0a8e3e91123e398bc19c5aee52d562889a52a09 100644 (file)
@@ -14,14 +14,6 @@ Pixbufs
 
 </para>
 
-<!-- ##### ENUM GdkPixbufAlphaMode ##### -->
-<para>
-
-</para>
-
-@GDK_PIXBUF_ALPHA_BILEVEL: 
-@GDK_PIXBUF_ALPHA_FULL: 
-
 <!-- ##### FUNCTION gdk_pixbuf_render_threshold_alpha ##### -->
 <para>
 
index 1aa9d0d86a9a46ed1bb696c5294a4c87967786de..8a2a6032e471e9bb0af86ad00b5c9588643c8178 100644 (file)
@@ -86,6 +86,7 @@ Windows
 @GDK_HINT_BASE_SIZE: 
 @GDK_HINT_ASPECT: 
 @GDK_HINT_RESIZE_INC: 
+@GDK_HINT_WIN_GRAVITY: 
 
 <!-- ##### STRUCT GdkGeometry ##### -->
 <para>
@@ -102,6 +103,7 @@ Windows
 @height_inc: 
 @min_aspect: 
 @max_aspect: 
+@win_gravity: 
 
 <!-- ##### FUNCTION gdk_window_new ##### -->
 <para>
index 33cc601f32efd6c41e8b6330919226c1903bde93..321f5ad5829ffcbb9faa748f544f1683a7530443 100644 (file)
@@ -1,3 +1,79 @@
+2000-10-06  Havoc Pennington  <hp@redhat.com>
+
+       * gdk-pixbuf.h: add GdkPixbufAlphaMode
+
+2000-10-06  Havoc Pennington  <hp@redhat.com>
+
+        This entry is a summary of the merged-in changes from 1.0. 
+       Relevant original ChangeLog entries are spliced in after 
+       this entry; the files they refer to are from the 1.0
+       gdk-pixbuf sources.
+       
+       * pixops/pixops.c (pixops_composite_nearest): sync a small fix
+       from 1.0
+
+       * io-xpm.c (xpm_seek_string): add fscanf error check from 1.0
+       Add progressive loader from 1.0
+
+       * io-tiff.c (gdk_pixbuf__tiff_image_begin_load): mem leak fixes
+       from 1.0 tree
+
+       * io-pnm.c: new version from 1.0 tree
+
+       * io-jpeg.c (gdk_pixbuf__jpeg_image_load): sync from 1.0, use 
+       malloc not g_malloc
+
+       * io-gif.c (lzw_read_byte): sync from 1.0, change a g_error to
+       g_warning
+       (gif_get_next_step): return 0 here, sync from 1.0
+
+       * gdk-pixbuf-util.c: sync email address change for Cody
+       Russell
+
+2000-09-11  Jeffrey Stedfast  <fejj@helixcode.com>
+
+       * gdk-pixbuf/io-pnm.c: Pretty much totally rewrote again because
+       last nights code was still "broken". Should now properly handle
+       all error conditions gracefully.
+
+2000-09-10  Jeffrey Stedfast  <fejj@helixcode.com>
+
+       * gdk-pixbuf/io-pnm.c: Rewrote.
+
+2000-09-09  Federico Mena Quintero  <federico@helixcode.com>
+
+       * gdk-pixbuf/pixops/pixops.c (pixops_composite_nearest): Compute
+       the correct dest offset.
+
+2000-08-25  Federico Mena Quintero  <federico@helixcode.com>
+
+       * gdk-pixbuf/io-xpm.c: #include <unistd.h>
+
+2000-08-05  Larry Ewing  <lewing@helixcode.com>
+
+       * gdk-pixbuf/io-tiff.c: stop leaking context->tempname.
+
+       * gdk-pixbuf/io-xpm.c: same as above.
+
+2000-07-26  Michael Meeks  <michael@helixcode.com>
+
+       * gdk-pixbuf/io-jpeg.c (gdk_pixbuf__jpeg_image_load): make
+       g_malloc a malloc.
+
+2000-07-21  Larry Ewing  <lewing@helixcode.com>
+
+       * gdk-pixbuf/io-xpm.c: add a fake progressive loader so that
+       xpm at least supports the progressive interface like the one in
+       io-tiff.c. This should be reimplemented as an actual progressive
+       loader.
+
+2000-07-19  Jonathan Blandford  <jrb@redhat.com>
+
+       * demo/pixbuf-demo.c (update_timeout): changed scaling level to
+       make it look better.
+       * gdk-pixbuf/testpixbuf.c (update_timeout): Patch from michael
+       meeks to handle errors better.
+       
 2000-10-07  Tor Lillqvist  <tml@iki.fi>
 
        * gdk_pixbuf.def
index c6ae8e2f21b3334ed0993d509a04191f68d4cb0d..5f4320f22fffd505a0b64ca098a10a7ef6eed7ac 100644 (file)
@@ -492,14 +492,17 @@ gdk_pixbuf_loader_new_with_type (const char *image_type)
  * gdk_pixbuf_loader_get_pixbuf:
  * @loader: A pixbuf loader.
  *
- * Queries the GdkPixbuf that a pixbuf loader is currently creating.  In general
- * it only makes sense to call this function afer the "area_prepared" signal has
- * been emitted by the loader; this means that enough data has been read to know
- * the size of the image that will be allocated.  If the loader has not received
- * enough data via gdk_pixbuf_loader_write(), then this function returns NULL.
- * The returned pixbuf will be the same in all future calls to the loader, so
- * simply calling gdk_pixbuf_ref() should be sufficient to continue using it.
- *
+ * Queries the GdkPixbuf that a pixbuf loader is currently creating.
+ * In general it only makes sense to call this function afer the
+ * "area_prepared" signal has been emitted by the loader; this means
+ * that enough data has been read to know the size of the image that
+ * will be allocated.  If the loader has not received enough data via
+ * gdk_pixbuf_loader_write(), then this function returns NULL.  The
+ * returned pixbuf will be the same in all future calls to the loader,
+ * so simply calling gdk_pixbuf_ref() should be sufficient to continue
+ * using it.  Additionally, if the loader is an animation, it will
+ * return the first frame of the animation.
+ * 
  * Return value: The GdkPixbuf that the loader is creating, or NULL if not
  * enough data has been read to determine how to create the image buffer.
  **/
@@ -512,6 +515,19 @@ gdk_pixbuf_loader_get_pixbuf (GdkPixbufLoader *loader)
   g_return_val_if_fail (GDK_IS_PIXBUF_LOADER (loader), NULL);
   
   priv = loader->private;
+
+  if (priv->animation)
+    {
+      GList *list;
+      
+      list = gdk_pixbuf_animation_get_frames (priv->animation);
+      if (list != NULL)
+        {
+          GdkPixbufFrame *frame = list->data;
+          
+          return gdk_pixbuf_frame_get_pixbuf (frame);
+        }
+    }
   
   return priv->pixbuf;
 }
index db8ca758e5fc7cc75c81be738a81eef4f0f232f1..36fc2975042995228ef6a80a3194e96fdadf7222 100644 (file)
@@ -3,7 +3,7 @@
  * Copyright (C) 1999 The Free Software Foundation
  *
  * Authors: Federico Mena-Quintero <federico@gimp.org>
- *          Cody Russell  <bratsche@dfw.net>
+ *          Cody Russell  <bratsche@gnome.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
index 82f0551bac90207758639a85ea05ed6b592d1813..a61dc9366046ed737bfd0465f7b88834718c8c12 100644 (file)
@@ -36,6 +36,13 @@ extern "C" {
 
 \f
 
+/* Alpha compositing mode */
+typedef enum
+{
+  GDK_PIXBUF_ALPHA_BILEVEL,
+  GDK_PIXBUF_ALPHA_FULL
+} GdkPixbufAlphaMode;
+
 /* Color spaces; right now only RGB is supported.
  * Note that these values are encoded in inline pixbufs
  * as ints, so don't reorder them
index 57e2af3a3f8ebb9b1cec2a5f79e6bb4a3dfafdbe..681e915da1e8ee674db6b00421d0d1c5781adc75 100644 (file)
@@ -537,7 +537,7 @@ lzw_read_byte (GifContext *context)
                        unsigned char buf[260];
 
                        /*g_error (" DID WE EVER EVER GET HERE\n");*/
-                       g_error ("Unhandled Case.  If you have an image that causes this, let me <jrb@redhat.com> know.\n");
+                       g_warning ("Unhandled Case.  If you have an image that causes this, let me <jrb@redhat.com> know.\n");
 
                        if (ZeroDataBlock) {
                                return -2;
@@ -982,7 +982,7 @@ gif_get_next_step (GifContext *context)
                        /* hmm.  Not 100% sure what to do about this.  Should
                         * i try to return a blank image instead? */
                        context->state = GIF_DONE;
-                       return -2;
+                       return 0;
                }
 
                if (c == '!') {
index 89ca8d2015e1ab4ae06e46b990a947ce6520a2ff..623077738d93724b033bfbc15ff3a74c412c13b9 100644 (file)
@@ -196,7 +196,7 @@ gdk_pixbuf__jpeg_image_load (FILE *f)
        w = cinfo.output_width;
        h = cinfo.output_height;
 
-       pixels = g_malloc (h * w * 3);
+       pixels = malloc (h * w * 3);
        if (!pixels) {
                jpeg_destroy_decompress (&cinfo);
                return NULL;
index aa1b193916463e2a58f85cf39f7cb36876334f2b..c91658cfd43b2b53d7ed8b09406b00c0453d8f08 100644 (file)
@@ -1,20 +1,22 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /* GdkPixbuf library - PNM image loader
  *
  * Copyright (C) 1999 Red Hat, Inc.
  *
- * Authors: Michael Fulbright <drmike@redhat.com>
+ * Authors: Jeffrey Stedfast <fejj@helixcode.com>
+ *          Michael Fulbright <drmike@redhat.com>
  *
  * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
+ * modify it under the terms of the GNU Library General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
+ * Library General Public License for more details.
  *
- * You should have received a copy of the GNU Lesser General Public
+ * You should have received a copy of the GNU Library General Public
  * License along with this library; if not, write to the
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
 #include "gdk-pixbuf-private.h"
 #include "gdk-pixbuf-io.h"
 
-\f
 
 #define PNM_BUF_SIZE 4096
 
-#define PNM_SUSPEND    0
-#define PNM_OK         1
 #define PNM_FATAL_ERR  -1
+#define PNM_SUSPEND     0
+#define PNM_OK          1
 
 typedef enum {
-       PNM_FORMAT_PGM,
+       PNM_FORMAT_PGM = 1,
        PNM_FORMAT_PGM_RAW,
        PNM_FORMAT_PPM,
        PNM_FORMAT_PPM_RAW,
@@ -47,51 +48,54 @@ typedef enum {
 } PnmFormat;
 
 typedef struct {
-       guchar    buffer[PNM_BUF_SIZE];
-       guchar    *next_byte;
-       guint     bytes_left;
+       guchar buffer[PNM_BUF_SIZE];
+       guchar *byte;
+       guint nbytes;
 } PnmIOBuffer;
 
 typedef struct {
-       ModuleUpdatedNotifyFunc  updated_func;
+       ModuleUpdatedNotifyFunc updated_func;
        ModulePreparedNotifyFunc prepared_func;
-       gpointer                 user_data;
+       gpointer user_data;
+       
+       GdkPixbuf *pixbuf;
+       guchar *pixels;        /* incoming pixel data buffer */
+       guchar *dptr;          /* current position in pixbuf */
+       
+       PnmIOBuffer inbuf;
+       
+       guint width;
+       guint height;
+       guint maxval;
+       guint rowstride;
+       PnmFormat type;
+       
+       guint output_row;      /* last row to be completed */
+       guint output_col;
+       gboolean did_prescan;  /* are we in image data yet? */
+       gboolean got_header;   /* have we loaded pnm header? */
+       
+       guint scan_state;
        
-       GdkPixbuf                *pixbuf;
-       guchar                   *pixels; /* incoming pixel data buffer */
-       guchar                   *dptr;   /* current position in pixbuf */
-
-       PnmIOBuffer              inbuf;
-
-       guint                    width;
-       guint                    height;
-       guint                    maxval;
-       guint                    rowstride;
-       PnmFormat                type;
-
-       guint                    output_row;  /* last row to be completed */
-       guint                    output_col;
-       gboolean                 did_prescan;  /* are we in image data yet? */
-       gboolean                 got_header;  /* have we loaded jpeg header? */
 } PnmLoaderContext;
 
-GdkPixbuf *gdk_pixbuf__pnm_image_load (FILE *f);
-gpointer gdk_pixbuf__pnm_image_begin_load (ModulePreparedNotifyFunc func, 
-                                          ModuleUpdatedNotifyFunc func2,
-                                          ModuleFrameDoneNotifyFunc frame_done_func,
-                                          ModuleAnimationDoneNotifyFunc anim_done_func,
-                                          gpointer user_data);
-void gdk_pixbuf__pnm_image_stop_load (gpointer context);
-gboolean gdk_pixbuf__pnm_image_load_increment(gpointer context, guchar *buf, guint size);
+GdkPixbuf   *gdk_pixbuf__pnm_image_load          (FILE *f);
+gpointer    gdk_pixbuf__pnm_image_begin_load     (ModulePreparedNotifyFunc func, 
+                                                 ModuleUpdatedNotifyFunc func2,
+                                                 ModuleFrameDoneNotifyFunc frame_done_func,
+                                                 ModuleAnimationDoneNotifyFunc anim_done_func,
+                                                 gpointer user_data);
+void        gdk_pixbuf__pnm_image_stop_load      (gpointer context);
+gboolean    gdk_pixbuf__pnm_image_load_increment (gpointer context, guchar *buf, guint size);
 
-static void explode_bitmap_into_buf (PnmLoaderContext *context);
-static void explode_gray_into_buf (PnmLoaderContext *context);
+static void explode_bitmap_into_buf              (PnmLoaderContext *context);
+static void explode_gray_into_buf                (PnmLoaderContext *context);
 
 /* Destroy notification function for the pixbuf */
 static void
 free_buffer (guchar *pixels, gpointer data)
 {
-       free (pixels);
+       g_free (pixels);
 }
 
 
@@ -108,33 +112,32 @@ explode_bitmap_into_buf (PnmLoaderContext *context)
        gint bit;
        guchar *dptr;
        gint wid, x, y;
-
+       
        g_return_if_fail (context != NULL);
        g_return_if_fail (context->dptr != NULL);
-
+       
        /* I'm no clever bit-hacker so I'm sure this can be optimized */
        dptr = context->dptr;
        y    = context->output_row;
        wid  = context->width;
-
-       from = dptr + (wid - 1)/8;
+       
+       from = dptr + ((wid - 1) / 8);
        to   = dptr + (wid - 1) * 3;
 /*     bit  = 7 - (((y+1)*wid-1) % 8); */
-       bit  = 7 - ((wid-1) % 8); 
-
+       bit  = 7 - ((wid-1) % 8);
+       
        /* get first byte and align properly */
        data = from[0];
        for (j = 0; j < bit; j++, data >>= 1);
-
+       
        for (x = wid-1; x >= 0; x--) {
-
 /*             g_print ("%c",  (data & 1) ? '*' : ' '); */
-
-               to[0] = to[1] = to[2] = (data & 1) ? 0x00 : 0xff;
-
+               
+               to[0] = to[1] = to[2] = (data & 0x01) ? 0x00 : 0xff;
+               
                to -= 3;
                bit++;
-
+               
                if (bit > 7) {
                        from--;
                        data = from[0];
@@ -143,7 +146,7 @@ explode_bitmap_into_buf (PnmLoaderContext *context)
                        data >>= 1;
                }
        }
-
+       
 /*     g_print ("\n"); */
 }
 
@@ -154,10 +157,10 @@ explode_gray_into_buf (PnmLoaderContext *context)
        gint j;
        guchar *from, *to;
        guint w;
-
+       
        g_return_if_fail (context != NULL);
        g_return_if_fail (context->dptr != NULL);
-
+       
        /* Expand grey->colour.  Expand from the end of the
         * memory down, so we can use the same buffer.
         */
@@ -173,221 +176,203 @@ explode_gray_into_buf (PnmLoaderContext *context)
        }
 }
 
-/* skip over whitespace in file from current pos.                      */
-/* also skips comments                                                 */
-/* returns pointer to first non-whitespace char hit or, or NULL if     */
-/* we ran out of data w/o hitting a whitespace                         */
-/* internal pointer in inbuf isnt moved ahead in this case             */
-static guchar *
-skip_ahead_whitespace (PnmIOBuffer *inbuf)
-{
-       gboolean in_comment;
-       guchar *ptr;
-       guint num_left;
-       
-       g_return_val_if_fail (inbuf != NULL, NULL);
-       g_return_val_if_fail (inbuf->next_byte != NULL, NULL);
-       
-       in_comment = FALSE;
-       num_left = inbuf->bytes_left;
-       ptr      = inbuf->next_byte;
-       while (num_left > 0) {
-               if (in_comment) {
-                       if (*ptr == '\n')
-                               in_comment = FALSE;
-               } else if (*ptr == '#') {
-                       in_comment = TRUE;
-               } else if (!isspace (*ptr)) {
-                       inbuf->bytes_left -= (ptr-inbuf->next_byte);
-                       inbuf->next_byte   = ptr;
-                       return ptr;
-               }
-               ptr ++;
-               num_left--;
-       }
-       return NULL;
-}
-
-/* reads into buffer until we hit whitespace in file from current pos,     */
-/* return NULL if ran out of data                                          */
-/* advances inbuf if successful                                            */
-static guchar *
-read_til_whitespace (PnmIOBuffer *inbuf, guchar *buf, guint size)
+/* skip over whitespace and comments in input buffer */
+static gint
+pnm_skip_whitespace (PnmIOBuffer *inbuf)
 {
-       guchar *p;
-       guchar *ptr;
-       guint num_left;
-
-       g_return_val_if_fail (inbuf != NULL, NULL);
-       g_return_val_if_fail (inbuf->next_byte != NULL, NULL);
-       
-       p = buf;
-       num_left = inbuf->bytes_left;
-       ptr      = inbuf->next_byte;
-       while (num_left > 0 && (p-buf)+1 < size) {
-               if (isspace (*ptr)) {
-                       *p = '\0';
-                       inbuf->bytes_left = num_left;
-                       inbuf->next_byte  = ptr;
-                       return ptr;
-               } else {
-                       *p = *ptr;
-                       p++;
-                       ptr++;
-                       num_left--;
+       register guchar *inptr;
+       guchar *inend;
+       
+       g_return_val_if_fail (inbuf != NULL, PNM_FATAL_ERR);
+       g_return_val_if_fail (inbuf->byte != NULL, PNM_FATAL_ERR);
+       
+       inend = inbuf->byte + inbuf->nbytes;
+       inptr = inbuf->byte;
+       
+       for ( ; inptr < inend; inptr++) {
+               if (*inptr == '#') {
+                       /* in comment - skip to the end of this line */
+                       for ( ; *inptr != '\n' && inptr < inend; inptr++);
+               } else if (!isspace (*inptr)) {
+                       inbuf->byte = inptr;
+                       inbuf->nbytes = (guint) (inend - inptr);
+                       return PNM_OK;
                }
        }
-       return NULL;
+       
+       inbuf->byte = inptr;
+       inbuf->nbytes = (guint) (inend - inptr);
+       
+       return PNM_SUSPEND;
 }
 
-/* read next number from buffer  */
-/* -1 if failed, 0 if successful */
+/* read next number from buffer */
 static gint
-read_next_number (PnmIOBuffer *inbuf, guint *value)
+pnm_read_next_value (PnmIOBuffer *inbuf, guint *value)
 {
-       guchar *tmpptr;
-       guchar *old_next_byte;
-       gchar  *errptr;
-       guint  old_bytes_left;
-       guchar buf[128];
-
-       g_return_val_if_fail (inbuf != NULL, -1);
-       g_return_val_if_fail (inbuf->next_byte != NULL, -1);
-       g_return_val_if_fail (value != NULL, -1);
-
-       old_next_byte  = inbuf->next_byte;
-       old_bytes_left = inbuf->bytes_left;
-
-       if ((tmpptr = skip_ahead_whitespace (inbuf)) == NULL)
-               return -1;
-
-       if ((tmpptr = read_til_whitespace (inbuf, buf, 128)) == NULL) {
-               inbuf->next_byte  = old_next_byte;
-               inbuf->bytes_left = old_bytes_left;
-               return -1;
-       }
+       register guchar *inptr, *word, *p;
+       guchar *inend, buf[128];
+       gchar *endptr;
+       gint retval;
        
-       *value = strtol (buf, &errptr, 10);
-
-       if (*errptr != '\0') {
-               inbuf->next_byte  = old_next_byte;
-               inbuf->bytes_left = old_bytes_left;
-               return -1;
-       }
-
-       return 0;
+       g_return_val_if_fail (inbuf != NULL, PNM_FATAL_ERR);
+       g_return_val_if_fail (inbuf->byte != NULL, PNM_FATAL_ERR);
+       g_return_val_if_fail (value != NULL, PNM_FATAL_ERR);
+       
+       /* skip white space */
+       if ((retval = pnm_skip_whitespace (inbuf)) != PNM_OK)
+               return retval;
+       
+       inend = inbuf->byte + inbuf->nbytes;
+       inptr = inbuf->byte;
+       
+       /* copy this pnm 'word' into a temp buffer */
+       for (p = inptr, word = buf; (p < inend) && !isspace (*p) && (p - inptr < 128); p++, word++)
+               *word = *p;
+       *word = '\0';
+       
+       /* hmmm, there must be more data to this 'word' */
+       if (!isspace (*p))
+               return PNM_SUSPEND;
+       
+       /* get the value */
+       *value = strtol (buf, &endptr, 10);
+       if (*endptr != '\0')
+               return PNM_FATAL_ERR;
+       
+       inbuf->byte = p;
+       inbuf->nbytes = (guint) (inend - p);
+       
+       return PNM_OK;
 }
 
 /* returns PNM_OK, PNM_SUSPEND, or PNM_FATAL_ERR */
 static gint
 pnm_read_header (PnmLoaderContext *context)
 {
-       guchar *old_next_byte;
-       guint  old_bytes_left;
        PnmIOBuffer *inbuf;
-       guint  w, h;
-       gint rc;
-       PnmFormat  type;
-
-       g_return_val_if_fail (context != NULL, PNM_FATAL_ERR);
-
-       inbuf = &context->inbuf;
-       old_bytes_left = inbuf->bytes_left;
-       old_next_byte  = inbuf->next_byte;
+       gint retval;
        
-       /* file must start with a 'P' followed by a numeral */
-       /* so loop till we get enough data to determine type*/
-       if (inbuf->bytes_left < 2)
-               return PNM_SUSPEND;
+       g_return_val_if_fail (context != NULL, PNM_FATAL_ERR);
        
-       if (*inbuf->next_byte != 'P')
-               return PNM_FATAL_ERR;
+       inbuf = &context->inbuf;
        
-       switch (*(inbuf->next_byte+1)) {
-       case '1':
-               type = PNM_FORMAT_PBM;
-               break;
-       case '2':
-               type = PNM_FORMAT_PGM;
-               break;
-       case '3':
-               type = PNM_FORMAT_PPM;
-               break;
-       case '4':
-               type = PNM_FORMAT_PBM_RAW;
-               break;
-       case '5':
-               type = PNM_FORMAT_PGM_RAW;
-               break;
-       case '6':
-               type = PNM_FORMAT_PPM_RAW;
-               break;
-       default:
-               return PNM_FATAL_ERR;
+       if (!context->type) {
+               /* file must start with a 'P' followed by a numeral  */
+               /* so loop till we get enough data to determine type */
+               if (inbuf->nbytes < 2)
+                       return PNM_SUSPEND;
+               
+               if (*inbuf->byte != 'P')
+                       return PNM_FATAL_ERR;
+               
+               inbuf->byte++;
+               inbuf->nbytes--;
+               
+               switch (*inbuf->byte) {
+               case '1':
+                       context->type = PNM_FORMAT_PBM;
+                       break;
+               case '2':
+                       context->type = PNM_FORMAT_PGM;
+                       break;
+               case '3':
+                       context->type = PNM_FORMAT_PPM;
+                       break;
+               case '4':
+                       context->type = PNM_FORMAT_PBM_RAW;
+                       break;
+               case '5':
+                       context->type = PNM_FORMAT_PGM_RAW;
+                       break;
+               case '6':
+                       context->type = PNM_FORMAT_PPM_RAW;
+                       break;
+               default:
+                       return PNM_FATAL_ERR;
+               }
+               
+               if (!inbuf->nbytes)
+                       return PNM_SUSPEND;
+               
+               inbuf->byte++;
+               inbuf->nbytes--;
        }
        
-       context->type = type;
-
-       inbuf->next_byte  += 2;
-       inbuf->bytes_left -= 2;
-       
-       /* now read remainder of header */
-       if ((rc = read_next_number (inbuf, &w))) {
-               inbuf->next_byte = old_next_byte;
-               inbuf->bytes_left = old_bytes_left;
-               return PNM_SUSPEND;
+       if (!context->width) {
+               /* read the pixmap width */
+               guint width = 0;
+               
+               retval = pnm_read_next_value (inbuf, &width);
+               
+               if (retval != PNM_OK)
+                       return retval;
+               
+               if (!width)
+                       return PNM_FATAL_ERR;
+               
+               context->width = width;
        }
        
-       if ((rc = read_next_number (inbuf, &h))) {
-               inbuf->next_byte = old_next_byte;
-               inbuf->bytes_left = old_bytes_left;
-               return PNM_SUSPEND;
+       if (!context->height) {
+               /* read the pixmap height */
+               guint height = 0;
+               
+               retval = pnm_read_next_value (inbuf, &height);
+               
+               if (retval != PNM_OK)
+                       return retval;
+               
+               if (!height)
+                       return PNM_FATAL_ERR;
+               
+               context->height = height;
        }
        
-       context->width  = w;
-       context->height = h;
-       
-       switch (type) {
+       switch (context->type) {
        case PNM_FORMAT_PPM:
        case PNM_FORMAT_PPM_RAW:
        case PNM_FORMAT_PGM:
        case PNM_FORMAT_PGM_RAW:
-               if ((rc = read_next_number (inbuf, &context->maxval)) < 0) {
-                       inbuf->next_byte = old_next_byte;
-                       inbuf->bytes_left = old_bytes_left;
-                       return PNM_SUSPEND;
+               if (!context->maxval) {
+                       retval = pnm_read_next_value (inbuf, &context->maxval);
+                       
+                       if (retval != PNM_OK)
+                               return retval;
+                       
+                       if (context->maxval == 0)
+                               return PNM_FATAL_ERR;
                }
                break;
        default:
                break;
        }
-
+       
        return PNM_OK;
 }
 
-
 static gint
 pnm_read_raw_scanline (PnmLoaderContext *context)
 {
-       guint  numpix;
-       guint  numbytes, offset;
        PnmIOBuffer *inbuf;
-
+       guint numbytes, offset;
+       guint numpix = 0;
+       guchar *dest;
+       guint i;
+       
        g_return_val_if_fail (context != NULL, PNM_FATAL_ERR);
-
-/*G_BREAKPOINT(); */
-
+       
        inbuf = &context->inbuf;
-
+       
        switch (context->type) {
        case PNM_FORMAT_PBM_RAW:
-               numpix = inbuf->bytes_left * 8;
+               numpix = inbuf->nbytes * 8;
                break;
        case PNM_FORMAT_PGM_RAW:
-               numpix = inbuf->bytes_left;
+               numpix = inbuf->nbytes;
                break;
        case PNM_FORMAT_PPM_RAW:
-               numpix = inbuf->bytes_left/3;
+               numpix = inbuf->nbytes / 3;
                break;
        default:
                g_warning ("io-pnm.c: Illegal raw pnm type!\n");
@@ -395,79 +380,100 @@ pnm_read_raw_scanline (PnmLoaderContext *context)
        }
        
        numpix = MIN (numpix, context->width - context->output_col);
-
-       if (numpix == 0)
+       
+       if (!numpix)
                return PNM_SUSPEND;
        
-       context->dptr = context->pixels + 
-               context->output_row * context->rowstride;
+       context->dptr = context->pixels + context->output_row * context->rowstride;
        
        switch (context->type) {
        case PNM_FORMAT_PBM_RAW:
-               numbytes = numpix/8 + ((numpix % 8) ? 1 : 0);
-               offset = context->output_col/8;
+               numbytes = (numpix / 8) + ((numpix % 8) ? 1 : 0);
+               offset = context->output_col / 8;
                break;
        case PNM_FORMAT_PGM_RAW:
                numbytes = numpix;
                offset = context->output_col;
                break;
        case PNM_FORMAT_PPM_RAW:
-               numbytes = numpix*3;
-               offset = context->output_col*3;
+               numbytes = numpix * 3;
+               offset = context->output_col * 3;
                break;
        default:
                g_warning ("io-pnm.c: Illegal raw pnm type!\n");
                return PNM_FATAL_ERR;
        }
        
-       memcpy (context->dptr + offset, inbuf->next_byte, numbytes);
-
-       inbuf->next_byte  += numbytes;
-       inbuf->bytes_left -= numbytes;
-
+       switch (context->type) {
+       case PNM_FORMAT_PBM_RAW:
+               dest = context->dptr + offset;          
+               memcpy (dest, inbuf->byte, numbytes);
+               break;
+       case PNM_FORMAT_PGM_RAW:
+       case PNM_FORMAT_PPM_RAW:
+               dest = context->dptr + offset;
+               
+               if (context->maxval == 255) {
+                       /* special-case optimization */
+                       memcpy (dest, inbuf->byte, numbytes);
+               } else {
+                       for (i = 0; i < numbytes; i++) {
+                               guchar *byte = inbuf->byte + i;
+                               
+                               /* scale the color to an 8-bit color depth */
+                               if (*byte > context->maxval)
+                                       *dest++ = 255;
+                               else
+                                       *dest++ = (guchar) (255 * *byte / context->maxval);
+                       }
+               }
+               break;
+       default:
+               g_warning ("Invalid raw pnm format!");
+       }
+       
+       inbuf->byte += numbytes;
+       inbuf->nbytes -= numbytes;
+       
        context->output_col += numpix;
        if (context->output_col == context->width) {
-               if ( context->type == PNM_FORMAT_PBM_RAW )
-                       explode_bitmap_into_buf(context);
-               else if ( context->type == PNM_FORMAT_PGM_RAW )
+               if (context->type == PNM_FORMAT_PBM_RAW)
+                       explode_bitmap_into_buf (context);
+               else if (context->type == PNM_FORMAT_PGM_RAW)
                        explode_gray_into_buf (context);
                
                context->output_col = 0;
                context->output_row++;
-               
        } else {
                return PNM_SUSPEND;
        }
-
+       
        return PNM_OK;
 }
 
-
 static gint
 pnm_read_ascii_scanline (PnmLoaderContext *context)
 {
-       guint  offset;
-       gint   rc;
-       guint  value, numval, i;
+       PnmIOBuffer *inbuf;
+       guint offset;
+       guint value, numval, i;
        guchar data;
        guchar mask;
-       guchar *old_next_byte, *dptr;
-       guint  old_bytes_left;
-       PnmIOBuffer *inbuf;
-
+       guchar *dptr;
+       gint retval;
+       
        g_return_val_if_fail (context != NULL, PNM_FATAL_ERR);
-
+       
        data = mask = 0;
-
+       
        inbuf = &context->inbuf;
-
-       context->dptr = context->pixels + 
-               context->output_row * context->rowstride;
-
+       
+       context->dptr = context->pixels + context->output_row * context->rowstride;
+       
        switch (context->type) {
        case PNM_FORMAT_PBM:
                numval = MIN (8, context->width - context->output_col);
-               offset = context->output_col/8;
+               offset = context->output_col / 8;
                break;
        case PNM_FORMAT_PGM:
                numval = 1;
@@ -475,32 +481,31 @@ pnm_read_ascii_scanline (PnmLoaderContext *context)
                break;
        case PNM_FORMAT_PPM:
                numval = 3;
-               offset = context->output_col*3;
+               offset = context->output_col * 3;
                break;
                
        default:
                g_warning ("Can't happen\n");
                return PNM_FATAL_ERR;
        }
-
-       dptr = context->dptr + offset;
-
+       
+       dptr = context->dptr + offset + context->scan_state;
+       
        while (TRUE) {
                if (context->type == PNM_FORMAT_PBM) {
                        mask = 0x80;
                        data = 0;
                        numval = MIN (8, context->width - context->output_col);
                }
-
-               old_next_byte  = inbuf->next_byte;
-               old_bytes_left = inbuf->bytes_left;
-               
-               for (i=0; i<numval; i++) {
-                       if ((rc = read_next_number (inbuf, &value))) {
-                               inbuf->next_byte  = old_next_byte;
-                               inbuf->bytes_left = old_bytes_left;
-                               return PNM_SUSPEND;
+               
+               for (i = context->scan_state; i < numval; i++) {
+                       retval = pnm_read_next_value (inbuf, &value);
+                       if (retval != PNM_OK) {
+                               /* save state and return */
+                               context->scan_state = i;
+                               return retval;
                        }
+                       
                        switch (context->type) {
                        case PNM_FORMAT_PBM:
                                if (value)
@@ -509,72 +514,73 @@ pnm_read_ascii_scanline (PnmLoaderContext *context)
                                
                                break;
                        case PNM_FORMAT_PGM:
-                               *dptr++ = (guchar)(255.0*((double)value/(double)context->maxval));
-                               break;
                        case PNM_FORMAT_PPM:
-                               *dptr++ = (guchar)(255.0*((double)value/(double)context->maxval));
+                               /* scale the color to an 8-bit color depth */
+                               if (value > context->maxval)
+                                       *dptr++ = 255;
+                               else
+                                       *dptr++ = (guchar)(255 * value / context->maxval);
                                break;
                        default:
-                               g_warning ("io-pnm.c: Illegal raw pnm type!\n");
+                               g_warning ("io-pnm.c: Illegal ascii pnm type!\n");
                                break;
                        }
                }
                
+               context->scan_state = 0;
+               
                if (context->type == PNM_FORMAT_PBM) {
                        *dptr++ = data;
                        context->output_col += numval;
                } else {
                        context->output_col++;
                }
-
+               
                if (context->output_col == context->width) {
-                       if ( context->type == PNM_FORMAT_PBM )
-                               explode_bitmap_into_buf(context);
-                       else if ( context->type == PNM_FORMAT_PGM )
+                       if (context->type == PNM_FORMAT_PBM)
+                               explode_bitmap_into_buf (context);
+                       else if (context->type == PNM_FORMAT_PGM)
                                explode_gray_into_buf (context);
-
+                       
                        context->output_col = 0;
                        context->output_row++;
                        break;
                }
-
        }
-
+       
        return PNM_OK;
 }
 
-/* returns 1 if a scanline was converted,  0 means we ran out of data */
+/* returns 1 if a scanline was converted, 0 means we ran out of data */
 static gint
 pnm_read_scanline (PnmLoaderContext *context)
 {
-       gint   rc;
-
+       gint retval;
+       
        g_return_val_if_fail (context != NULL, PNM_FATAL_ERR);
-
+       
        /* read in image data */
        /* for raw formats this is trivial */
        switch (context->type) {
        case PNM_FORMAT_PBM_RAW:
        case PNM_FORMAT_PGM_RAW:
        case PNM_FORMAT_PPM_RAW:
-               rc = pnm_read_raw_scanline (context);
-               if (rc == PNM_SUSPEND)
-                       return rc;
+               retval = pnm_read_raw_scanline (context);
+               if (retval != PNM_OK)
+                       return retval;
                break;
-
        case PNM_FORMAT_PBM:
        case PNM_FORMAT_PGM:
        case PNM_FORMAT_PPM:
-               rc = pnm_read_ascii_scanline (context);
-               if (rc == PNM_SUSPEND)
-                       return rc;
+               retval = pnm_read_ascii_scanline (context);
+               if (retval != PNM_OK)
+                       return retval;
                break;
-
        default:
                g_warning ("Cannot load these image types (yet)\n");
                return PNM_FATAL_ERR;
        }
-
+       
        return PNM_OK;
 }
 
@@ -582,99 +588,104 @@ pnm_read_scanline (PnmLoaderContext *context)
 GdkPixbuf *
 gdk_pixbuf__pnm_image_load (FILE *f)
 {
-       gint  nbytes;
-       gint   rc;
-
        PnmLoaderContext context;
        PnmIOBuffer *inbuf;
-
+       gint nbytes;
+       gint retval;
+       
        /* pretend to be doing progressive loading */
        context.updated_func = NULL;
        context.prepared_func = NULL;
        context.user_data = NULL;
-       context.inbuf.bytes_left = 0;
-       context.inbuf.next_byte  = NULL;
+       context.type = 0;
+       context.inbuf.nbytes = 0;
+       context.inbuf.byte = NULL;
+       context.width = 0;
+       context.height = 0;
+       context.maxval = 0;
        context.pixels = NULL;
        context.pixbuf = NULL;
-       context.got_header = context.did_prescan = FALSE;
-
+       context.got_header = FALSE;
+       context.did_prescan = FALSE;
+       context.scan_state = 0;
+       
        inbuf = &context.inbuf;
-
-       while (TRUE) {
-               guint  num_to_read;
-
+       
+       while (!feof (f)) {
+               guint num_to_read;
+               
                /* keep buffer as full as possible */
-               num_to_read = PNM_BUF_SIZE - inbuf->bytes_left;
-
-               if (inbuf->next_byte != NULL && inbuf->bytes_left > 0)
-                       memmove (inbuf->buffer, inbuf->next_byte, 
-                                inbuf->bytes_left);
-
-               nbytes = fread (inbuf->buffer+inbuf->bytes_left, 
-                               1, num_to_read, f);
-               inbuf->bytes_left += nbytes;
-               inbuf->next_byte   = inbuf->buffer;
-
-               /* ran out of data and we haven't exited main loop */
-               if (inbuf->bytes_left == 0) {
+               num_to_read = PNM_BUF_SIZE - inbuf->nbytes;
+               
+               if (inbuf->byte != NULL && inbuf->nbytes > 0)
+                       memmove (inbuf->buffer, inbuf->byte, inbuf->nbytes);
+               
+               nbytes = fread (inbuf->buffer + inbuf->nbytes, 1, num_to_read, f);
+               
+               /* error checking */
+               if (nbytes == 0 && ferror (f)) {
+                       /* we ran out of data? */
                        if (context.pixbuf)
                                gdk_pixbuf_unref (context.pixbuf);
-                       g_warning ("io-pnm.c: Ran out of data...\n");
+                       g_warning ("io-pnm.c: Ran out of data.\n");
                        return NULL;
                }
-
+               
+               inbuf->nbytes += nbytes;
+               inbuf->byte = inbuf->buffer;
+               
                /* get header if needed */
                if (!context.got_header) {
-               
-                       rc = pnm_read_header (&context);
-                       if (rc == PNM_FATAL_ERR)
+                       retval = pnm_read_header (&context);
+                       if (retval == PNM_FATAL_ERR)
                                return NULL;
-                       else if (rc == PNM_SUSPEND)
+                       else if (retval == PNM_SUSPEND)
                                continue;
-
+                       
                        context.got_header = TRUE;
                }
-
+               
                /* scan until we hit image data */
                if (!context.did_prescan) {
-
-                       if (skip_ahead_whitespace (inbuf) == NULL)
+                       retval = pnm_skip_whitespace (inbuf);
+                       if (retval == PNM_FATAL_ERR)
+                               return NULL;
+                       else if (retval == PNM_SUSPEND)
                                continue;
-
+                       
                        context.did_prescan = TRUE;
                        context.output_row = 0;
                        context.output_col = 0;
-
+                       
                        context.rowstride = context.width * 3;
-                       context.pixels = g_malloc (context.height * 
-                                                  context.width  * 3);
+                       context.pixels = g_malloc (context.height * context.width * 3);
+                       
                        if (!context.pixels) {
                                /* Failed to allocate memory */
-                               g_error ("Couldn't allocate pixel buf");
+                               g_warning ("Couldn't allocate pixel buf");
                        }
                }
-
+               
                /* if we got here we're reading image data */
                while (context.output_row < context.height) {
-
-                       rc = pnm_read_scanline (&context);
-
-                       if (rc == PNM_SUSPEND) {
+                       retval = pnm_read_scanline (&context);
+                       
+                       if (retval == PNM_SUSPEND) {
                                break;
-                       } else if (rc == PNM_FATAL_ERR) {
+                       } else if (retval == PNM_FATAL_ERR) {
                                if (context.pixbuf)
                                        gdk_pixbuf_unref (context.pixbuf);
                                g_warning ("io-pnm.c: error reading rows..\n");
                                return NULL;
                        }
                }
-
+               
                if (context.output_row < context.height)
                        continue;
                else
                        break;
        }
-
+       
        return gdk_pixbuf_new_from_data (context.pixels, GDK_COLORSPACE_RGB, FALSE, 8,
                                         context.width, context.height, 
                                         context.width * 3, free_buffer, NULL);
@@ -695,19 +706,23 @@ gdk_pixbuf__pnm_image_begin_load (ModulePreparedNotifyFunc prepared_func,
                                  gpointer user_data)
 {
        PnmLoaderContext *context;
-
+       
        context = g_new0 (PnmLoaderContext, 1);
        context->prepared_func = prepared_func;
        context->updated_func  = updated_func;
        context->user_data = user_data;
+       context->width = 0;
+       context->height = 0;
+       context->maxval = 0;
        context->pixbuf = NULL;
        context->pixels = NULL;
        context->got_header = FALSE;
        context->did_prescan = FALSE;
-
-       context->inbuf.bytes_left = 0;
-       context->inbuf.next_byte  = NULL;
-
+       context->scan_state = 0;
+       
+       context->inbuf.nbytes = 0;
+       context->inbuf.byte  = NULL;
+       
        return (gpointer) context;
 }
 
@@ -720,18 +735,15 @@ void
 gdk_pixbuf__pnm_image_stop_load (gpointer data)
 {
        PnmLoaderContext *context = (PnmLoaderContext *) data;
-
+       
        g_return_if_fail (context != NULL);
-
+       
        if (context->pixbuf)
                gdk_pixbuf_unref (context->pixbuf);
-
+       
        g_free (context);
 }
 
-
-
-
 /*
  * context - from image_begin_load
  * buf - new image data
@@ -743,103 +755,104 @@ gboolean
 gdk_pixbuf__pnm_image_load_increment (gpointer data, guchar *buf, guint size)
 {
        PnmLoaderContext *context = (PnmLoaderContext *)data;
-       PnmIOBuffer      *inbuf;
-
-       guchar *old_next_byte;
-       guint  old_bytes_left;
+       PnmIOBuffer *inbuf;
+       guchar *old_byte;
+       guint old_nbytes;
        guchar *bufhd;
-       guint  num_left, spinguard;
-       gint   rc;
-
+       guint num_left, spinguard;
+       gint retval;
+       
        g_return_val_if_fail (context != NULL, FALSE);
        g_return_val_if_fail (buf != NULL, FALSE);
-
+       
        bufhd = buf;
        inbuf = &context->inbuf;
-       old_bytes_left = inbuf->bytes_left;
-       old_next_byte  = inbuf->next_byte;
-
+       old_nbytes = inbuf->nbytes;
+       old_byte  = inbuf->byte;
+       
        num_left = size;
        spinguard = 0;
        while (TRUE) {
                guint num_to_copy;
-
+               
                /* keep buffer as full as possible */
-               num_to_copy = MIN (PNM_BUF_SIZE - inbuf->bytes_left, num_left);
+               num_to_copy = MIN (PNM_BUF_SIZE - inbuf->nbytes, num_left);
                
                if (num_to_copy == 0)
                        spinguard++;
-
+               
                if (spinguard > 1)
                        return TRUE;
-
-               if (inbuf->next_byte != NULL && inbuf->bytes_left > 0)
-                       memmove (inbuf->buffer, inbuf->next_byte, 
-                                inbuf->bytes_left);
-
-               memcpy (inbuf->buffer + inbuf->bytes_left, bufhd, num_to_copy);
+               
+               if (inbuf->byte != NULL && inbuf->nbytes > 0)
+                       memmove (inbuf->buffer, inbuf->byte, inbuf->nbytes);
+               
+               memcpy (inbuf->buffer + inbuf->nbytes, bufhd, num_to_copy);
                bufhd += num_to_copy;
-               inbuf->bytes_left += num_to_copy;
-               inbuf->next_byte   = inbuf->buffer;
+               inbuf->nbytes += num_to_copy;
+               inbuf->byte = inbuf->buffer;
                num_left -= num_to_copy;
                
                /* ran out of data and we haven't exited main loop */
-               if (inbuf->bytes_left == 0)
+               if (inbuf->nbytes == 0)
                        return TRUE;
-
+               
                /* get header if needed */
                if (!context->got_header) {
-                       rc = pnm_read_header (context);
-                       if (rc == PNM_FATAL_ERR)
+                       retval = pnm_read_header (context);
+                       
+                       if (retval == PNM_FATAL_ERR)
                                return FALSE;
-                       else if (rc == PNM_SUSPEND)
+                       else if (retval == PNM_SUSPEND)
                                continue;
-
+                       
                        context->got_header = TRUE;
                }
-
+               
                /* scan until we hit image data */
                if (!context->did_prescan) {
-                       if (skip_ahead_whitespace (inbuf) == NULL)
+                       retval = pnm_skip_whitespace (inbuf);
+                       
+                       if (retval == PNM_FATAL_ERR)
+                               return FALSE;
+                       else if (retval == PNM_SUSPEND)
                                continue;
-
+                                               
                        context->did_prescan = TRUE;
                        context->output_row = 0;
                        context->output_col = 0;
-
-                       context->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, 
-                                                        FALSE,
-                                                        8, 
-                                                        context->width,
-                                                        context->height);
-
+                       
+                       context->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 
+                                                         FALSE,
+                                                         8, 
+                                                         context->width,
+                                                         context->height);
+                       
                        if (context->pixbuf == NULL) {
                                /* Failed to allocate memory */
                                g_error ("Couldn't allocate gdkpixbuf");
                        }
-
+                       
                        context->pixels = context->pixbuf->pixels;
                        context->rowstride = context->pixbuf->rowstride;
-
+                       
                        /* Notify the client that we are ready to go */
                        (* context->prepared_func) (context->pixbuf,
                                                    context->user_data);
-
                }
-
+               
                /* if we got here we're reading image data */
                while (context->output_row < context->height) {
-                       rc = pnm_read_scanline (context);
-
-                       if (rc == PNM_SUSPEND) {
+                       retval = pnm_read_scanline (context);
+                       
+                       if (retval == PNM_SUSPEND) {
                                break;
-                       } else if (rc == PNM_FATAL_ERR) {
+                       } else if (retval == PNM_FATAL_ERR) {
                                if (context->pixbuf)
                                        gdk_pixbuf_unref (context->pixbuf);
-                               g_warning ("io-pnm.c: error reading rows..\n");
+                               g_warning ("io-pnm.c: error reading rows.\n");
                                return FALSE;
-                       } else if (rc == PNM_OK) {
-
+                       } else if (retval == PNM_OK) {  
                                /* send updated signal */
                                (* context->updated_func) (context->pixbuf,
                                                           0, 
@@ -849,12 +862,12 @@ gdk_pixbuf__pnm_image_load_increment (gpointer data, guchar *buf, guint size)
                                                           context->user_data);
                        }
                }
-
+               
                if (context->output_row < context->height)
                        continue;
                else
                        break;
        }
-
+       
        return TRUE;
 }
index dcc1ea66b210a4f32678891a55193f99dc6e3f9f..fdf5174632cb81112fc1422239b3e5c211fc4bd4 100644 (file)
@@ -171,12 +171,14 @@ gdk_pixbuf__tiff_image_begin_load (ModulePreparedNotifyFunc prepare_func,
        fd = open (context->tempname, O_RDWR);
 #endif
        if (fd < 0) {
+                g_free (context->tempname);
                g_free (context);
                return NULL;
        }
 
        context->file = fdopen (fd, "w");
        if (context->file == NULL) {
+                g_free (context->tempname);
                g_free (context);
                return NULL;
        }
index c946585649c9d8a6c285141a3a3c72b571d565e5..17e2a43f40083685c9c9cf8ea5af430586178f23 100644 (file)
@@ -28,6 +28,7 @@
 #include <string.h>
 #include <glib.h>
 #include "gdk-pixbuf-private.h"
+#include "gdk-pixbuf-io.h"
 
 \f
 
@@ -977,7 +978,8 @@ xpm_seek_string (FILE *infile, const gchar *str, gint skip_comments)
        char instr[1024];
 
        while (!feof (infile)) {
-               fscanf (infile, "%1023s", instr);
+               if (fscanf (infile, "%1023s", instr) < 0)
+                        return FALSE;
                if (skip_comments == TRUE && strcmp (instr, "/*") == 0) {
                        fscanf (infile, "%1023s", instr);
                        while (!feof (infile) && strcmp (instr, "*/") != 0)
@@ -1373,3 +1375,97 @@ gdk_pixbuf__xpm_image_load_xpm_data (const gchar **data)
         
        return pixbuf;
 }
+
+/* Progressive loader */
+typedef struct _XPMContext XPMContext;
+struct _XPMContext
+{
+       ModulePreparedNotifyFunc prepare_func;
+       ModuleUpdatedNotifyFunc update_func;
+       gpointer user_data;
+
+       gchar *tempname;
+       FILE *file;
+       gboolean all_okay;
+};
+
+/*
+ * FIXME xpm loading progressively is not properly implemented.
+ * Instead we will buffer to a file then load that file when done.
+ * This is very broken but it should be relayively simple to fix
+ * in the future.
+ */
+gpointer
+gdk_pixbuf__xpm_image_begin_load (ModulePreparedNotifyFunc prepare_func,
+                                  ModuleUpdatedNotifyFunc update_func,
+                                  ModuleFrameDoneNotifyFunc frame_done_func,
+                                  ModuleAnimationDoneNotifyFunc anim_done_func,
+                                  gpointer user_data)
+{
+       XPMContext *context;
+       gint fd;
+
+       g_warning ("load start");
+       context = g_new (XPMContext, 1);
+       context->prepare_func = prepare_func;
+       context->update_func = update_func;
+       context->user_data = user_data;
+       context->all_okay = TRUE;
+       context->tempname = g_strdup ("/tmp/gdkpixbuf-xpm-tmp.XXXXXX");
+       fd = mkstemp (context->tempname);
+       if (fd < 0) {
+               g_free (context->tempname);
+               g_free (context);
+               return NULL;
+       }
+
+       context->file = fdopen (fd, "w+");
+       if (context->file == NULL) {
+               g_free (context->tempname);
+               g_free (context);
+               return NULL;
+       }
+
+       return context;
+}
+
+void
+gdk_pixbuf__xpm_image_stop_load (gpointer data)
+{
+       XPMContext *context = (XPMContext*) data;
+       GdkPixbuf *pixbuf;
+
+       g_return_if_fail (data != NULL);
+       g_warning ("stopped loading");
+
+       fflush (context->file);
+       rewind (context->file);
+       if (context->all_okay) {
+               pixbuf = gdk_pixbuf__xpm_image_load (context->file);
+
+               (* context->prepare_func) (pixbuf, context->user_data);
+               (* context->update_func) (pixbuf, 0, 0, pixbuf->width, pixbuf->height, context->user_data);
+               gdk_pixbuf_unref (pixbuf);
+       }
+
+       fclose (context->file);
+       unlink (context->tempname);
+       g_free (context->tempname);
+       g_free ((XPMContext *) context);
+}
+
+gboolean
+gdk_pixbuf__xpm_image_load_increment (gpointer data, guchar *buf, guint size)
+{
+       XPMContext *context = (XPMContext *) data;
+
+       g_return_val_if_fail (data != NULL, FALSE);
+       g_warning ("load increment");
+
+       if (fwrite (buf, sizeof (guchar), size, context->file) != size) {
+               context->all_okay = FALSE;
+               return FALSE;
+       }
+
+       return TRUE;
+}
index 6714133a975ec626e0be887de5bd31ca5583aa8d..ea19607153f0299061d11907fdbdb5ef7133e6af 100644 (file)
@@ -160,7 +160,8 @@ pixops_composite_nearest (guchar        *dest_buf,
   for (i = 0; i < (render_y1 - render_y0); i++)
     {
       const guchar *src  = src_buf + (((i + render_y0) * y_step + y_step / 2) >> SCALE_SHIFT) * src_rowstride;
-      guchar       *dest = dest_buf + i * dest_rowstride + render_x0 * dest_channels;
+      /* FIXME Owen needs to look at this */
+      guchar       *dest = dest_buf + i * dest_rowstride;
 
       x = render_x0 * x_step + x_step / 2;
       
index 8a487c448d64f6fda8b32ba92eee61d0322cf8ba..db74d601174d22b96419e5ab45f5ca10581d0d04 100644 (file)
@@ -11,13 +11,6 @@ extern "C" {
 
 /* Rendering to a drawable */
 
-/* Alpha compositing mode */
-typedef enum
-{
-  GDK_PIXBUF_ALPHA_BILEVEL,
-  GDK_PIXBUF_ALPHA_FULL
-} GdkPixbufAlphaMode;
-
 void gdk_pixbuf_render_threshold_alpha   (GdkPixbuf           *pixbuf,
                                          GdkBitmap           *bitmap,
                                          int                  src_x,
index c6ae8e2f21b3334ed0993d509a04191f68d4cb0d..5f4320f22fffd505a0b64ca098a10a7ef6eed7ac 100644 (file)
@@ -492,14 +492,17 @@ gdk_pixbuf_loader_new_with_type (const char *image_type)
  * gdk_pixbuf_loader_get_pixbuf:
  * @loader: A pixbuf loader.
  *
- * Queries the GdkPixbuf that a pixbuf loader is currently creating.  In general
- * it only makes sense to call this function afer the "area_prepared" signal has
- * been emitted by the loader; this means that enough data has been read to know
- * the size of the image that will be allocated.  If the loader has not received
- * enough data via gdk_pixbuf_loader_write(), then this function returns NULL.
- * The returned pixbuf will be the same in all future calls to the loader, so
- * simply calling gdk_pixbuf_ref() should be sufficient to continue using it.
- *
+ * Queries the GdkPixbuf that a pixbuf loader is currently creating.
+ * In general it only makes sense to call this function afer the
+ * "area_prepared" signal has been emitted by the loader; this means
+ * that enough data has been read to know the size of the image that
+ * will be allocated.  If the loader has not received enough data via
+ * gdk_pixbuf_loader_write(), then this function returns NULL.  The
+ * returned pixbuf will be the same in all future calls to the loader,
+ * so simply calling gdk_pixbuf_ref() should be sufficient to continue
+ * using it.  Additionally, if the loader is an animation, it will
+ * return the first frame of the animation.
+ * 
  * Return value: The GdkPixbuf that the loader is creating, or NULL if not
  * enough data has been read to determine how to create the image buffer.
  **/
@@ -512,6 +515,19 @@ gdk_pixbuf_loader_get_pixbuf (GdkPixbufLoader *loader)
   g_return_val_if_fail (GDK_IS_PIXBUF_LOADER (loader), NULL);
   
   priv = loader->private;
+
+  if (priv->animation)
+    {
+      GList *list;
+      
+      list = gdk_pixbuf_animation_get_frames (priv->animation);
+      if (list != NULL)
+        {
+          GdkPixbufFrame *frame = list->data;
+          
+          return gdk_pixbuf_frame_get_pixbuf (frame);
+        }
+    }
   
   return priv->pixbuf;
 }