packaging 2.26.2
authorGraydon, Tracy <tracy.graydon@intel.com>
Sat, 19 May 2012 07:42:06 +0000 (00:42 -0700)
committerGraydon, Tracy <tracy.graydon@intel.com>
Sat, 19 May 2012 07:42:06 +0000 (00:42 -0700)
96 files changed:
gdk-pixbuf/Makefile.am [new file with mode: 0644]
gdk-pixbuf/Makefile.in [new file with mode: 0644]
gdk-pixbuf/abicheck.sh [new file with mode: 0755]
gdk-pixbuf/gdiplus.def [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-animation.c [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-animation.h [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-core.h [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-csource.1 [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-csource.c [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-data.c [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-enum-types.c [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-enum-types.c.template [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-enum-types.h [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-enum-types.h.template [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-features.h [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-features.h.in [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-i18n.h [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-io.c [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-io.h [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-loader.c [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-loader.h [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-marshal.c [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-marshal.h [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-marshal.list [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-pixdata.c [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-private.h [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-scale.c [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-scaled-anim.c [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-scaled-anim.h [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-simple-anim.c [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-simple-anim.h [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-transform.h [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf-util.c [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf.c [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf.h [new file with mode: 0644]
gdk-pixbuf/gdk-pixbuf.symbols [new file with mode: 0644]
gdk-pixbuf/gdk-pixdata.c [new file with mode: 0644]
gdk-pixbuf/gdk-pixdata.h [new file with mode: 0644]
gdk-pixbuf/gdk_pixbuf.def [new file with mode: 0644]
gdk-pixbuf/gdk_pixbuf.rc [new file with mode: 0644]
gdk-pixbuf/gdk_pixbuf.rc.in [new file with mode: 0644]
gdk-pixbuf/gen-color-table.pl [new file with mode: 0755]
gdk-pixbuf/io-ani-animation.c [new file with mode: 0644]
gdk-pixbuf/io-ani-animation.h [new file with mode: 0644]
gdk-pixbuf/io-ani.c [new file with mode: 0644]
gdk-pixbuf/io-bmp.c [new file with mode: 0644]
gdk-pixbuf/io-gdip-animation.c [new file with mode: 0644]
gdk-pixbuf/io-gdip-animation.h [new file with mode: 0644]
gdk-pixbuf/io-gdip-bmp.c [new file with mode: 0644]
gdk-pixbuf/io-gdip-emf.c [new file with mode: 0644]
gdk-pixbuf/io-gdip-gif.c [new file with mode: 0644]
gdk-pixbuf/io-gdip-ico.c [new file with mode: 0644]
gdk-pixbuf/io-gdip-jpeg.c [new file with mode: 0644]
gdk-pixbuf/io-gdip-native.h [new file with mode: 0644]
gdk-pixbuf/io-gdip-propertytags.h [new file with mode: 0644]
gdk-pixbuf/io-gdip-tiff.c [new file with mode: 0644]
gdk-pixbuf/io-gdip-utils.c [new file with mode: 0644]
gdk-pixbuf/io-gdip-utils.h [new file with mode: 0644]
gdk-pixbuf/io-gdip-wmf.c [new file with mode: 0644]
gdk-pixbuf/io-gif-animation.c [new file with mode: 0644]
gdk-pixbuf/io-gif-animation.h [new file with mode: 0644]
gdk-pixbuf/io-gif.c [new file with mode: 0644]
gdk-pixbuf/io-icns.c [new file with mode: 0644]
gdk-pixbuf/io-ico.c [new file with mode: 0644]
gdk-pixbuf/io-jasper.c [new file with mode: 0644]
gdk-pixbuf/io-jpeg.c [new file with mode: 0644]
gdk-pixbuf/io-pcx.c [new file with mode: 0644]
gdk-pixbuf/io-pixdata.c [new file with mode: 0644]
gdk-pixbuf/io-png.c [new file with mode: 0644]
gdk-pixbuf/io-pnm.c [new file with mode: 0644]
gdk-pixbuf/io-qtif.c [new file with mode: 0644]
gdk-pixbuf/io-ras.c [new file with mode: 0644]
gdk-pixbuf/io-tga.c [new file with mode: 0644]
gdk-pixbuf/io-tiff.c [new file with mode: 0644]
gdk-pixbuf/io-wbmp.c [new file with mode: 0644]
gdk-pixbuf/io-xbm.c [new file with mode: 0644]
gdk-pixbuf/io-xpm.c [new file with mode: 0644]
gdk-pixbuf/makefile.msc [new file with mode: 0644]
gdk-pixbuf/pixops/DETAILS [new file with mode: 0644]
gdk-pixbuf/pixops/Makefile.am [new file with mode: 0644]
gdk-pixbuf/pixops/Makefile.in [new file with mode: 0644]
gdk-pixbuf/pixops/README [new file with mode: 0644]
gdk-pixbuf/pixops/composite_line_22_4a4_mmx.S [new file with mode: 0644]
gdk-pixbuf/pixops/composite_line_color_22_4a4_mmx.S [new file with mode: 0644]
gdk-pixbuf/pixops/have_mmx.S [new file with mode: 0644]
gdk-pixbuf/pixops/makefile.msc [new file with mode: 0644]
gdk-pixbuf/pixops/pixbuf-transform-math.ltx [new file with mode: 0644]
gdk-pixbuf/pixops/pixops-internal.h [new file with mode: 0644]
gdk-pixbuf/pixops/pixops.c [new file with mode: 0644]
gdk-pixbuf/pixops/pixops.h [new file with mode: 0644]
gdk-pixbuf/pixops/scale_line_22_33_mmx.S [new file with mode: 0644]
gdk-pixbuf/pixops/timescale.c [new file with mode: 0644]
gdk-pixbuf/queryloaders.c [new file with mode: 0644]
gdk-pixbuf/test-gdk-pixbuf.c [new file with mode: 0644]
gdk-pixbuf/xpm-color-table.h [new file with mode: 0644]
packaging/gdk-pixbuf.changes

diff --git a/gdk-pixbuf/Makefile.am b/gdk-pixbuf/Makefile.am
new file mode 100644 (file)
index 0000000..e5926fe
--- /dev/null
@@ -0,0 +1,796 @@
+include $(top_srcdir)/Makefile.decl
+-include $(INTROSPECTION_MAKEFILE)
+
+INTROSPECTION_GIRS =
+
+SUBDIRS = pixops
+
+if PLATFORM_WIN32
+no_undefined = -no-undefined
+endif
+
+if OS_WIN32
+gdk_pixbuf_def = gdk_pixbuf.def
+gdk_pixbuf_symbols = -export-symbols $(srcdir)/gdk_pixbuf.def
+
+gdk_pixbuf_win32_res = gdk_pixbuf-win32-res.o
+gdk_pixbuf_win32_res_ldflag = -Wl,gdk_pixbuf-win32-res.o
+
+libole32 = -lole32
+
+gdk_pixbuf-win32-res.o : gdk_pixbuf.rc
+       $(WINDRES) gdk_pixbuf.rc $@
+
+install-def-file:
+       $(INSTALL) $(srcdir)/gdk_pixbuf.def $(DESTDIR)$(libdir)/gdk_pixbuf-$(GDK_PIXBUF_API_VERSION).def
+uninstall-def-file:
+       -rm $(DESTDIR)$(libdir)/gdk_pixbuf-$(GDK_PIXBUF_API_VERSION).def
+else
+install-def-file:
+uninstall-def-file:
+endif
+
+if MS_LIB_AVAILABLE
+noinst_DATA = gdk_pixbuf-$(GDK_PIXBUF_API_VERSION).lib
+
+gdk_pixbuf-$(GDK_PIXBUF_API_VERSION).lib: libgdk_pixbuf-$(GDK_PIXBUF_API_VERSION).la gdk_pixbuf.def
+       lib -machine:@LIB_EXE_MACHINE_FLAG@ -name:libgdk_pixbuf-$(GDK_PIXBUF_API_VERSION)-@LT_CURRENT_MINUS_AGE@.dll -def:gdk_pixbuf.def -out:$@
+
+install-ms-lib:
+       $(INSTALL) gdk_pixbuf-$(GDK_PIXBUF_API_VERSION).lib $(DESTDIR)$(libdir)
+
+uninstall-ms-lib:
+       -rm $(DESTDIR)$(libdir)/gdk_pixbuf-$(GDK_PIXBUF_API_VERSION).lib
+else
+install-ms-lib:
+uninstall-ms-lib:
+endif
+
+# This places the generated .def file in srcdir, since it is expected to be there.
+# (The one from a tarball is)
+gdk_pixbuf.def: gdk-pixbuf.symbols
+       (echo -e EXPORTS; $(CPP) -P -DINCLUDE_VARIABLES -DG_OS_WIN32 -DALL_FILES - <$(srcdir)/gdk-pixbuf.symbols | sed -e '/^$$/d' -e 's/^/     /' -e 's/G_GNUC_[^ ]*//g') > $(srcdir)/gdk_pixbuf.def
+
+if OS_LINUX
+TESTS = abicheck.sh
+endif
+
+lib_LTLIBRARIES = libgdk_pixbuf-2.0.la
+
+loaderdir = $(libdir)/gdk-pixbuf-2.0/$(GDK_PIXBUF_BINARY_VERSION)/loaders
+
+module_libs = libgdk_pixbuf-$(GDK_PIXBUF_API_VERSION).la $(GDK_PIXBUF_DEP_LIBS)
+
+#
+# The PNG loader
+#
+libstatic_pixbufloader_png_la_SOURCES = io-png.c
+libpixbufloader_png_la_SOURCES = io-png.c
+libpixbufloader_png_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_png_la_LIBADD = $(LIBPNG) $(module_libs)
+
+#
+# The BMP loader
+#
+libstatic_pixbufloader_bmp_la_SOURCES = io-bmp.c
+libpixbufloader_bmp_la_SOURCES = io-bmp.c
+libpixbufloader_bmp_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_bmp_la_LIBADD = $(module_libs)
+
+#
+# The WBMP loader
+#
+libstatic_pixbufloader_wbmp_la_SOURCES = io-wbmp.c
+libpixbufloader_wbmp_la_SOURCES = io-wbmp.c
+libpixbufloader_wbmp_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_wbmp_la_LIBADD = $(module_libs)
+
+#
+# The GdkPixdata loader, always built in
+#
+libstatic_pixbufloader_pixdata_la_SOURCES = io-pixdata.c
+
+#
+# The GIF loader
+#
+libstatic_pixbufloader_gif_la_SOURCES = io-gif.c io-gif-animation.c io-gif-animation.h
+libpixbufloader_gif_la_SOURCES = io-gif.c io-gif-animation.c io-gif-animation.h
+libpixbufloader_gif_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_gif_la_LIBADD = $(module_libs)
+
+#
+# The ICO loader
+#
+libstatic_pixbufloader_ico_la_SOURCES = io-ico.c
+libpixbufloader_ico_la_SOURCES = io-ico.c
+libpixbufloader_ico_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_ico_la_LIBADD = $(module_libs)
+
+#
+# The ANI loader
+#
+libstatic_pixbufloader_ani_la_SOURCES = io-ani.c io-ani-animation.c io-ani-animation.h
+libpixbufloader_ani_la_SOURCES = io-ani.c io-ani-animation.c io-ani-animation.h
+libpixbufloader_ani_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_ani_la_LIBADD = $(module_libs)
+
+#
+# The JPEG loader
+#
+libstatic_pixbufloader_jpeg_la_SOURCES = io-jpeg.c
+libpixbufloader_jpeg_la_SOURCES = io-jpeg.c
+libpixbufloader_jpeg_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_jpeg_la_LIBADD = $(LIBJPEG) $(module_libs)
+
+#
+# The PNM loader
+#
+libstatic_pixbufloader_pnm_la_SOURCES = io-pnm.c
+libpixbufloader_pnm_la_SOURCES = io-pnm.c
+libpixbufloader_pnm_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_pnm_la_LIBADD = $(module_libs)
+
+#
+# The RAS loader
+#
+libstatic_pixbufloader_ras_la_SOURCES = io-ras.c
+libpixbufloader_ras_la_SOURCES = io-ras.c
+libpixbufloader_ras_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_ras_la_LIBADD = $(module_libs)
+
+#
+# The TIFF loader
+#
+libstatic_pixbufloader_tiff_la_SOURCES = io-tiff.c
+libpixbufloader_tiff_la_SOURCES = io-tiff.c
+libpixbufloader_tiff_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_tiff_la_LIBADD = $(LIBTIFF) $(module_libs)
+
+#
+# The XPM loader
+#
+libstatic_pixbufloader_xpm_la_SOURCES = io-xpm.c
+libpixbufloader_xpm_la_SOURCES = io-xpm.c
+libpixbufloader_xpm_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_xpm_la_LIBADD = $(module_libs)
+
+#
+# The XBM loader
+#
+libstatic_pixbufloader_xbm_la_SOURCES = io-xbm.c
+libpixbufloader_xbm_la_SOURCES = io-xbm.c
+libpixbufloader_xbm_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_xbm_la_LIBADD = $(module_libs)
+
+#
+# The TGA loader
+#
+libstatic_pixbufloader_tga_la_SOURCES = io-tga.c
+libpixbufloader_tga_la_SOURCES = io-tga.c
+libpixbufloader_tga_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_tga_la_LIBADD = $(module_libs)
+
+#
+# The .icns loader
+#
+libstatic_pixbufloader_icns_la_SOURCES = io-icns.c
+libpixbufloader_icns_la_SOURCES = io-icns.c
+libpixbufloader_icns_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_icns_la_LIBADD = $(module_libs)
+
+#
+# The PCX loader
+#
+libstatic_pixbufloader_pcx_la_SOURCES = io-pcx.c
+libpixbufloader_pcx_la_SOURCES = io-pcx.c
+libpixbufloader_pcx_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_pcx_la_LIBADD = $(module_libs)
+
+#
+# The JPEG2000 loader
+#
+libstatic_pixbufloader_jasper_la_SOURCES = io-jasper.c
+libpixbufloader_jasper_la_SOURCES = io-jasper.c
+libpixbufloader_jasper_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_jasper_la_LIBADD = $(LIBJASPER) $(module_libs)
+
+#
+# The QTIF loader
+#
+libstatic_pixbufloader_qtif_la_SOURCES = io-qtif.c
+libpixbufloader_qtif_la_SOURCES = io-qtif.c
+libpixbufloader_qtif_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_qtif_la_LIBADD = $(module_libs)
+
+if BUILD_GDIPLUS_LOADERS
+
+# MinGW doesn't come with any import library for gdiplus.dll, so
+# create a partial one that's enough for our use.
+
+libgdiplus = libgdiplus.dll.a
+gdiplus_ldflag = -Wl,$(libgdiplus)
+
+libgdiplus.dll.a: gdiplus.def
+       $(DLLTOOL) --kill-at --dllname gdiplus.dll --input-def $(srcdir)/gdiplus.def --output-lib $@
+
+if INCLUDE_GDIPLUS
+
+# When building the GDI+ loader statically, we put the "common" objects
+# only in one of the archives to avoid duplicate definitions
+
+STATIC_GDIPLUS_LIBS = \
+       libstatic-pixbufloader-gdip-ico.la \
+       libstatic-pixbufloader-gdip-wmf.la \
+       libstatic-pixbufloader-gdip-emf.la \
+       libstatic-pixbufloader-gdip-bmp.la \
+       libstatic-pixbufloader-gdip-gif.la \
+       libstatic-pixbufloader-gdip-jpeg.la \
+       libstatic-pixbufloader-gdip-tiff.la
+
+libstatic_pixbufloader_gdip_ico_la_SOURCES =   \
+       io-gdip-native.h                \
+       io-gdip-propertytags.h          \
+       io-gdip-utils.h                 \
+       io-gdip-utils.c                 \
+       io-gdip-animation.c             \
+       io-gdip-animation.h             \
+       io-gdip-ico.c
+
+libstatic_pixbufloader_gdip_wmf_la_SOURCES =   \
+       io-gdip-wmf.c
+
+libstatic_pixbufloader_gdip_emf_la_SOURCES =   \
+       io-gdip-emf.c
+
+libstatic_pixbufloader_gdip_bmp_la_SOURCES =   \
+       io-gdip-bmp.c
+
+libstatic_pixbufloader_gdip_gif_la_SOURCES =   \
+       io-gdip-gif.c
+
+libstatic_pixbufloader_gdip_jpeg_la_SOURCES =  \
+       io-gdip-jpeg.c
+
+libstatic_pixbufloader_gdip_tiff_la_SOURCES =  \
+       io-gdip-tiff.c
+
+else
+
+GDIPLUS_LIBS = \
+       libpixbufloader-gdip-ico.la \
+       libpixbufloader-gdip-wmf.la \
+       libpixbufloader-gdip-emf.la \
+       libpixbufloader-gdip-bmp.la \
+       libpixbufloader-gdip-gif.la \
+       libpixbufloader-gdip-jpeg.la \
+       libpixbufloader-gdip-tiff.la
+
+libpixbufloader_gdip_ico_la_LDFLAGS = -avoid-version -module -no-undefined $(gdiplus_ldflag)
+libpixbufloader_gdip_ico_la_SOURCES =  \
+       io-gdip-native.h                \
+       io-gdip-propertytags.h          \
+       io-gdip-utils.h                 \
+       io-gdip-utils.c                 \
+       io-gdip-animation.c             \
+       io-gdip-animation.h             \
+       io-gdip-ico.c
+libpixbufloader_gdip_ico_la_LIBADD = $(module_libs) $(libole32)
+
+libpixbufloader_gdip_wmf_la_LDFLAGS = -avoid-version -module -no-undefined $(gdiplus_ldflag)
+libpixbufloader_gdip_wmf_la_SOURCES =  \
+       io-gdip-native.h                \
+       io-gdip-propertytags.h          \
+       io-gdip-utils.h                 \
+       io-gdip-utils.c                 \
+       io-gdip-animation.c             \
+       io-gdip-animation.h             \
+       io-gdip-wmf.c
+libpixbufloader_gdip_wmf_la_LIBADD = $(module_libs) $(libole32)
+
+libpixbufloader_gdip_emf_la_LDFLAGS = -avoid-version -module -no-undefined $(gdiplus_ldflag)
+libpixbufloader_gdip_emf_la_SOURCES =  \
+       io-gdip-native.h                \
+       io-gdip-propertytags.h          \
+       io-gdip-utils.h                 \
+       io-gdip-utils.c                 \
+       io-gdip-animation.c             \
+       io-gdip-animation.h             \
+       io-gdip-emf.c
+libpixbufloader_gdip_emf_la_LIBADD = $(module_libs) $(libole32)
+
+libpixbufloader_gdip_bmp_la_LDFLAGS = -avoid-version -module -no-undefined $(gdiplus_ldflag)
+libpixbufloader_gdip_bmp_la_SOURCES =  \
+       io-gdip-native.h                \
+       io-gdip-propertytags.h          \
+       io-gdip-utils.h                 \
+       io-gdip-utils.c                 \
+       io-gdip-animation.c             \
+       io-gdip-animation.h             \
+       io-gdip-bmp.c
+libpixbufloader_gdip_bmp_la_LIBADD = $(module_libs) $(libole32)
+
+libpixbufloader_gdip_gif_la_LDFLAGS = -avoid-version -module -no-undefined $(gdiplus_ldflag)
+libpixbufloader_gdip_gif_la_SOURCES =  \
+       io-gdip-native.h                \
+       io-gdip-propertytags.h          \
+       io-gdip-utils.h                 \
+       io-gdip-utils.c                 \
+       io-gdip-animation.c             \
+       io-gdip-animation.h             \
+       io-gdip-gif.c
+libpixbufloader_gdip_gif_la_LIBADD = $(module_libs) $(libole32)
+
+libpixbufloader_gdip_jpeg_la_LDFLAGS = -avoid-version -module -no-undefined $(gdiplus_ldflag)
+libpixbufloader_gdip_jpeg_la_SOURCES =         \
+       io-gdip-native.h                \
+       io-gdip-propertytags.h          \
+       io-gdip-utils.h                 \
+       io-gdip-utils.c                 \
+       io-gdip-animation.c             \
+       io-gdip-animation.h             \
+       io-gdip-jpeg.c
+libpixbufloader_gdip_jpeg_la_LIBADD = $(module_libs) $(libole32)
+
+libpixbufloader_gdip_tiff_la_LDFLAGS = -avoid-version -module -no-undefined $(gdiplus_ldflag)
+libpixbufloader_gdip_tiff_la_SOURCES =         \
+       io-gdip-native.h                \
+       io-gdip-propertytags.h          \
+       io-gdip-utils.h                 \
+       io-gdip-utils.c                 \
+       io-gdip-animation.c             \
+       io-gdip-animation.h             \
+       io-gdip-tiff.c
+libpixbufloader_gdip_tiff_la_LIBADD = $(module_libs) $(libole32)
+
+endif
+
+else
+
+# Loaders that aren't built if we build the GDI+ loader
+
+if INCLUDE_BMP
+STATIC_BMP_LIB = libstatic-pixbufloader-bmp.la
+else
+BMP_LIB = libpixbufloader-bmp.la
+endif
+
+if INCLUDE_GIF
+STATIC_GIF_LIB = libstatic-pixbufloader-gif.la
+else
+GIF_LIB = libpixbufloader-gif.la
+endif
+
+if INCLUDE_ICO
+STATIC_ICO_LIB = libstatic-pixbufloader-ico.la
+else
+ICO_LIB = libpixbufloader-ico.la
+endif
+
+if HAVE_JPEG
+if INCLUDE_JPEG
+STATIC_JPEG_LIB = libstatic-pixbufloader-jpeg.la
+else
+JPEG_LIB = libpixbufloader-jpeg.la
+endif
+endif
+
+if HAVE_TIFF
+if INCLUDE_TIFF
+STATIC_TIFF_LIB = libstatic-pixbufloader-tiff.la
+else
+TIFF_LIB = libpixbufloader-tiff.la
+endif
+endif
+
+# End of loaders not built if building GDI+ loader
+endif
+
+if HAVE_PNG
+if INCLUDE_PNG
+STATIC_PNG_LIB = libstatic-pixbufloader-png.la
+else
+PNG_LIB = libpixbufloader-png.la
+endif
+endif
+
+if INCLUDE_WBMP
+STATIC_WBMP_LIB = libstatic-pixbufloader-wbmp.la
+else
+WBMP_LIB = libpixbufloader-wbmp.la
+endif
+
+if INCLUDE_ANI
+STATIC_ANI_LIB = libstatic-pixbufloader-ani.la
+else
+ANI_LIB = libpixbufloader-ani.la
+endif
+
+if INCLUDE_PNM
+STATIC_PNM_LIB = libstatic-pixbufloader-pnm.la
+else
+PNM_LIB = libpixbufloader-pnm.la
+endif
+
+if INCLUDE_RAS
+STATIC_RAS_LIB = libstatic-pixbufloader-ras.la
+else
+RAS_LIB = libpixbufloader-ras.la
+endif
+
+if INCLUDE_XPM
+STATIC_XPM_LIB = libstatic-pixbufloader-xpm.la
+else
+XPM_LIB = libpixbufloader-xpm.la
+endif
+
+if INCLUDE_XBM
+STATIC_XBM_LIB = libstatic-pixbufloader-xbm.la
+else
+XBM_LIB = libpixbufloader-xbm.la
+endif
+
+if INCLUDE_TGA
+STATIC_TGA_LIB = libstatic-pixbufloader-tga.la
+else
+TGA_LIB = libpixbufloader-tga.la
+endif
+
+if INCLUDE_PCX
+STATIC_PCX_LIB = libstatic-pixbufloader-pcx.la
+else
+PCX_LIB = libpixbufloader-pcx.la
+endif
+
+if INCLUDE_ICNS
+STATIC_ICNS_LIB = libstatic-pixbufloader-icns.la
+else
+ICNS_LIB = libpixbufloader-icns.la
+endif
+
+if HAVE_JASPER
+if INCLUDE_JASPER
+STATIC_JASPER_LIB = libstatic-pixbufloader-jasper.la
+else
+JASPER_LIB = libpixbufloader-jasper.la
+endif
+endif
+
+if INCLUDE_QTIF
+STATIC_QTIF_LIB = libstatic-pixbufloader-qtif.la
+else
+QTIF_LIB = libpixbufloader-qtif.la
+endif
+
+# Always included
+STATIC_PIXDATA_LIB = libstatic-pixbufloader-pixdata.la
+
+if BUILD_DYNAMIC_MODULES
+
+loader_LTLIBRARIES =   \
+       $(PNG_LIB)      \
+       $(BMP_LIB)      \
+       $(WBMP_LIB)     \
+       $(GIF_LIB)      \
+       $(ICO_LIB)      \
+       $(ANI_LIB)      \
+       $(JPEG_LIB)     \
+       $(PNM_LIB)      \
+       $(RAS_LIB)      \
+       $(TIFF_LIB)     \
+       $(XPM_LIB)      \
+       $(XBM_LIB)      \
+       $(TGA_LIB)      \
+       $(ICNS_LIB)     \
+       $(PCX_LIB)      \
+       $(JASPER_LIB)   \
+       $(QTIF_LIB)     \
+       $(GDIPLUS_LIBS)
+
+
+endif
+
+noinst_LTLIBRARIES =           \
+       $(STATIC_PIXDATA_LIB)   \
+       $(STATIC_PNG_LIB)       \
+       $(STATIC_BMP_LIB)       \
+       $(STATIC_WBMP_LIB)      \
+       $(STATIC_GIF_LIB)       \
+       $(STATIC_ICO_LIB)       \
+       $(STATIC_ANI_LIB)       \
+       $(STATIC_JPEG_LIB)      \
+       $(STATIC_PNM_LIB)       \
+       $(STATIC_RAS_LIB)       \
+       $(STATIC_TIFF_LIB)      \
+       $(STATIC_XPM_LIB)       \
+       $(STATIC_XBM_LIB)       \
+       $(STATIC_TGA_LIB)       \
+       $(STATIC_ICNS_LIB)      \
+       $(STATIC_PCX_LIB)       \
+       $(STATIC_JASPER_LIB)    \
+       $(STATIC_QTIF_LIB)      \
+       $(STATIC_GDIPLUS_LIBS)
+
+builtin_objs = @INCLUDED_LOADER_OBJ@ $(STATIC_PIXDATA_LIB)
+
+DEPS = libgdk_pixbuf-$(GDK_PIXBUF_API_VERSION).la
+INCLUDES = \
+       -DG_LOG_DOMAIN=\"GdkPixbuf\"                                    \
+       -DGDK_PIXBUF_COMPILATION                                        \
+       -I$(top_srcdir) -I$(top_builddir)                               \
+       -I$(top_srcdir)/gdk-pixbuf                                      \
+       -I$(top_builddir)/gdk-pixbuf                                    \
+       -DGDK_PIXBUF_LOCALEDIR=\"$(localedir)\"                         \
+       -DGDK_PIXBUF_LIBDIR=\"$(libdir)\"                               \
+       -DGDK_PIXBUF_BINARY_VERSION=\"$(GDK_PIXBUF_BINARY_VERSION)\"    \
+       -DGDK_PIXBUF_PREFIX=\"$(prefix)\"                               \
+       $(INCLUDED_LOADER_DEFINE)                                       \
+       $(GDK_PIXBUF_DEBUG_FLAGS)                                       \
+       $(GDK_PIXBUF_DEP_CFLAGS)                                        \
+       -DGDK_PIXBUF_ENABLE_BACKEND
+
+AM_CPPFLAGS = "-DPIXBUF_LIBDIR=\"$(loaderdir)\"" "-DBUILT_MODULES_DIR=\"$(srcdir)/.libs\""
+LDADDS = libgdk_pixbuf-$(GDK_PIXBUF_API_VERSION).la $(GDK_PIXBUF_DEP_LIBS)
+
+noinst_PROGRAMS = test-gdk-pixbuf
+test_gdk_pixbuf_LDADD = $(LDADDS)
+
+bin_PROGRAMS = gdk-pixbuf-csource gdk-pixbuf-pixdata gdk-pixbuf-query-loaders
+gdk_pixbuf_csource_SOURCES = gdk-pixbuf-csource.c
+gdk_pixbuf_csource_LDADD = $(LDADDS)
+
+gdk_pixbuf_pixdata_SOURCES = gdk-pixbuf-pixdata.c
+gdk_pixbuf_pixdata_LDADD = $(LDADDS)
+
+gdk_pixbuf_query_loaders_DEPENDENCIES = $(DEPS)
+gdk_pixbuf_query_loaders_LDADD = $(LDADDS)
+
+gdk_pixbuf_query_loaders_SOURCES = queryloaders.c
+
+
+#
+# The GdkPixBuf library
+#
+libgdk_pixbufincludedir = $(includedir)/gdk-pixbuf-2.0/gdk-pixbuf
+libgdk_pixbuf_2_0_la_SOURCES =   \
+       gdk-pixbuf-i18n.h        \
+       gdk-pixbuf.c             \
+       gdk-pixbuf-animation.c   \
+       gdk-pixbuf-data.c        \
+       gdk-pixbuf-io.c          \
+       gdk-pixbuf-loader.c      \
+       gdk-pixbuf-scale.c       \
+       gdk-pixbuf-simple-anim.c \
+       gdk-pixbuf-scaled-anim.c \
+       gdk-pixbuf-util.c        \
+       gdk-pixdata.c            \
+       gdk-pixbuf-enum-types.c
+
+libgdk_pixbuf_2_0_la_LDFLAGS = \
+       $(GDK_PIXBUF_LINK_FLAGS)                \
+       $(gdk_pixbuf_win32_res_ldflag)          \
+       -version-info $(LT_VERSION_INFO)        \
+       $(LIBTOOL_EXPORT_OPTIONS)               \
+       $(no_undefined)                         \
+       $(gdk_pixbuf_symbols)                   \
+       $(gdiplus_ldflag)
+
+
+libgdk_pixbuf_2_0_la_LIBADD = pixops/libpixops.la $(builtin_objs) $(GDK_PIXBUF_DEP_LIBS) $(libole32)
+libgdk_pixbuf_2_0_la_DEPENDENCIES = pixops/libpixops.la $(builtin_objs) $(gdk_pixbuf_def) $(gdk_pixbuf_win32_res) $(libgdiplus)
+
+gdk_pixbuf_headers =                   \
+       gdk-pixbuf.h                    \
+       gdk-pixbuf-core.h               \
+       gdk-pixbuf-transform.h          \
+       gdk-pixbuf-io.h                 \
+       gdk-pixbuf-animation.h          \
+       gdk-pixbuf-simple-anim.h        \
+       gdk-pixbuf-loader.h
+
+libgdk_pixbufinclude_HEADERS =         \
+       $(gdk_pixbuf_headers)           \
+       gdk-pixbuf-enum-types.h         \
+       gdk-pixbuf-marshal.h            \
+       gdk-pixbuf-features.h           \
+       gdk-pixdata.h
+
+noinst_HEADERS =               \
+       gdk-pixbuf-private.h    \
+       gdk-pixbuf-scaled-anim.h \
+       xpm-color-table.h
+
+BUILT_SOURCES =                \
+       gdk-pixbuf-enum-types.h \
+       gdk-pixbuf-enum-types.c \
+       gdk-pixbuf-marshal.h    \
+       gdk-pixbuf-marshal.c    \
+       gdk-pixbuf-features.h
+
+CLEANFILES =
+MAINTAINERCLEANFILES =                 \
+       gdk-pixbuf-enum-types.h \
+       gdk-pixbuf-enum-types.c \
+       gdk-pixbuf-marshal.h    \
+       gdk-pixbuf-marshal.c    \
+       loaders.cache
+
+#
+# gdk-pixbuf-enum-types.h
+#
+gdk-pixbuf-enum-types.h: s-enum-types-h
+       @true
+
+s-enum-types-h: @REBUILD@ $(gdk_pixbuf_headers) gdk-pixbuf-enum-types.h.template
+       ( cd $(srcdir) && $(GLIB_MKENUMS) --template gdk-pixbuf-enum-types.h.template \
+               $(gdk_pixbuf_headers) ) > tmp-gdk-pixbuf-enum-types.h \
+       && (cmp -s tmp-gdk-pixbuf-enum-types.h gdk-pixbuf-enum-types.h || cp tmp-gdk-pixbuf-enum-types.h gdk-pixbuf-enum-types.h ) \
+       && rm -f tmp-gdk-pixbuf-enum-types.h \
+       && echo timestamp > $(@F)
+
+CLEANFILES += tmp-gdk-pixbuf-enum-types.h
+MAINTAINERCLEANFILES += s-enum-types-h
+
+#
+# gdk-pixbuf-enum-types.c
+#
+gdk-pixbuf-enum-types.c: @REBUILD@ $(gdk_pixbuf_headers) gdk-pixbuf-enum-types.c.template
+       (cd $(srcdir) && $(GLIB_MKENUMS) --template gdk-pixbuf-enum-types.c.template \
+                 $(gdk_pixbuf_headers)) > gdk-pixbuf-enum-types.c
+
+#
+# gdk-pixbuf-marshal.h
+#
+gdk-pixbuf-marshal.h: @REBUILD@ stamp-gdk-pixbuf-marshal.h
+       @true
+
+stamp-gdk-pixbuf-marshal.h: @REBUILD@ $(srcdir)/gdk-pixbuf-marshal.list
+       echo "#if !defined(GDK_PIXBUF_DISABLE_DEPRECATED) || defined(GDK_PIXBUF_COMPILATION)" > xgen-gmh \
+       && $(GLIB_GENMARSHAL) --prefix=_gdk_pixbuf_marshal $(srcdir)/gdk-pixbuf-marshal.list --header >> xgen-gmh \
+       && echo "#endif /* !GDK_PIXBUF_DISABLE_DEPRECATED || GDK_PIXBUF_COMPILATION */" >> xgen-gmh \
+       && (cmp -s xgen-gmh gdk-pixbuf-marshal.h || cp xgen-gmh gdk-pixbuf-marshal.h) \
+       && rm -f xgen-gmh xgen-gmh~ \
+       && echo timestamp > $(@F)
+
+CLEANFILES += xgen-gmh
+MAINTAINERCLEANFILES += stamp-gdk-pixbuf-marshal.h
+
+#
+# gdk-pixbuf-marshal.c
+#
+$(srcdir)/gdk-pixbuf-marshal.c: @REBUILD@ $(srcdir)/gdk-pixbuf-marshal.list
+       (echo -e "#include <gdk-pixbuf/gdk-pixbuf.h>\n" | $(GLIB_GENMARSHAL) --prefix=_gdk_pixbuf_marshal $(srcdir)/gdk-pixbuf-marshal.list --body ) >> xgen-gmc \
+       && cp xgen-gmc gdk-pixbuf-marshal.c \
+       && rm -f xgen-gmc xgen-gmc~
+
+CLEANFILES += xgen-gmc
+
+# if srcdir!=builddir, clean out maintainer-clean files from builddir
+# this allows dist to pass.
+distclean-local:
+       if test $(srcdir) != .; then \
+         rm -f $(MAINTAINERCLEANFILES); \
+       fi
+
+EXTRA_DIST +=                                  \
+        gdk-pixbuf-csource.1                   \
+       makefile.msc                            \
+       gdk-pixbuf.symbols                      \
+       abicheck.sh                             \
+       gdk_pixbuf.def                          \
+       gdk_pixbuf.rc                           \
+       gdk-pixbuf-marshal.c                    \
+       gdk-pixbuf-marshal.list                 \
+       gdk-pixbuf-enum-types.c.template        \
+       gdk-pixbuf-enum-types.h.template        \
+       gen-color-table.pl                      \
+       gdiplus.def
+       
+dist-hook: ../build/win32/vs9/gdk-pixbuf.vcproj ../build/win32/vs10/gdk-pixbuf.vcxproj ../build/win32/vs10/gdk-pixbuf.vcxproj.filters
+
+../build/win32/vs9/gdk-pixbuf.vcproj: ../build/win32/vs9/gdk-pixbuf.vcprojin
+       for F in $(libgdk_pixbuf_2_0_la_SOURCES); do \
+               case $$F in \
+               *.c) echo '   <File RelativePath="..\..\..\gdk-pixbuf\'$$F'" />' \
+                    ;; \
+               esac; \
+       done >libgdkpixbuf.sourcefiles
+       $(CPP) -P - <$(top_srcdir)/build/win32/vs9/gdk-pixbuf.vcprojin >$@
+       rm libgdkpixbuf.sourcefiles
+       
+../build/win32/vs10/gdk-pixbuf.vcxproj: ../build/win32/vs10/gdk-pixbuf.vcxprojin
+       for F in $(libgdk_pixbuf_2_0_la_SOURCES); do \
+               case $$F in \
+               *.c) echo '    <ClCompile Include="..\..\..\gdk-pixbuf\'$$F'" />' \
+                    ;; \
+               esac; \
+       done >libgdkpixbuf.vs10.sourcefiles
+       $(CPP) -P - <$(top_srcdir)/build/win32/vs10/gdk-pixbuf.vcxprojin >$@
+       rm libgdkpixbuf.vs10.sourcefiles
+       
+../build/win32/vs10/gdk-pixbuf.vcxproj.filters: ../build/win32/vs10/gdk-pixbuf.vcxproj.filtersin
+       for F in $(libgdk_pixbuf_2_0_la_SOURCES); do \
+               case $$F in \
+               *.c) echo '    <ClCompile Include="..\..\..\gdk-pixbuf\'$$F'"><Filter>Source Files</Filter></ClCompile>' \
+                    ;; \
+               esac; \
+       done >libgdkpixbuf.vs10.sourcefiles.filters
+       $(CPP) -P - <$(top_srcdir)/build/win32/vs10/gdk-pixbuf.vcxproj.filtersin >$@
+       rm libgdkpixbuf.vs10.sourcefiles.filters
+
+if HAVE_INTROSPECTION
+
+GdkPixbuf-2.0.gir: libgdk_pixbuf-2.0.la Makefile
+GdkPixbuf_2_0_gir_SCANNERFLAGS = --warn-all --strip-prefix=Gdk --c-include="gdk-pixbuf/gdk-pixbuf.h"
+GdkPixbuf_2_0_gir_EXPORT_PACKAGES = gdk-pixbuf-2.0
+GdkPixbuf_2_0_gir_INCLUDES = GModule-2.0 Gio-2.0
+GdkPixbuf_2_0_gir_LIBS = libgdk_pixbuf-2.0.la
+GdkPixbuf_2_0_gir_CFLAGS = \
+       -DGDK_PIXBUF_COMPILATION                                        \
+       -I$(top_builddir) -I$(top_srcdir)                               \
+       -I$(top_srcdir)/gdk-pixbuf                                      \
+       -I$(top_builddir)/gdk-pixbuf                                    \
+       $(GDK_PIXBUF_DEP_CFLAGS)
+GdkPixbuf_2_0_gir_FILES = \
+    $(libgdk_pixbufinclude_HEADERS) \
+    $(libgdk_pixbuf_2_0_la_SOURCES)
+INTROSPECTION_GIRS += GdkPixbuf-2.0.gir
+
+girdir = $(datadir)/gir-1.0
+gir_DATA = $(INTROSPECTION_GIRS)
+
+typelibsdir = $(libdir)/girepository-1.0
+typelibs_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
+
+CLEANFILES += $(gir_DATA) $(typelibs_DATA)
+endif
+
+if CROSS_COMPILING
+RUN_QUERY_LOADER_TEST=false
+else
+RUN_QUERY_LOADER_TEST=test -z "$(DESTDIR)"
+endif
+
+# Running this if cross compiling or if DESTDIR is set is going to
+# not work at all, so skip it
+# We use install-data-hook here to workaround a bug in automake and/or libtool
+# that makes the install target for the loader libraries a dependency on
+# install-data-am, and not install-exec-am. We need to ensure this gets run
+# after the libraries are installed in their final locations.
+install-data-hook: install-ms-lib install-def-file
+       @if $(RUN_QUERY_LOADER_TEST) ; then \
+         $(mkinstalldirs) $(DESTDIR)$(libdir)/gdk-pixbuf-2.0/$(GDK_PIXBUF_BINARY_VERSION) ; \
+         $(top_builddir)/gdk-pixbuf/gdk-pixbuf-query-loaders > $(DESTDIR)$(libdir)/gdk-pixbuf-2.0/$(GDK_PIXBUF_BINARY_VERSION)/loaders.cache ; \
+       else \
+         echo "***" ; \
+         echo "*** Warning: loaders.cache not built" ; \
+         echo "***" ; \
+         echo "*** Generate this file manually on host" ; \
+         echo "*** system using gdk-pixbuf-query-loaders" ; \
+         echo "***" ; \
+       fi
+
+uninstall-local: uninstall-ms-lib uninstall-def-file
+       rm -f $(DESTDIR)$(libdir)/gdk-pixbuf-2.0/$(GDK_PIXBUF_BINARY_VERSION)/loaders.cache
+
+if CROSS_COMPILING
+else
+all-local: loaders.cache
+endif
+
+if BUILD_DYNAMIC_MODULES
+loaders.cache: $(loader_LTLIBRARIES) gdk-pixbuf-query-loaders$(EXEEXT)
+       LOADERS=`echo libpixbufloader-*.la` ; \
+       if test "x$$LOADERS" != 'xlibpixbufloader-*.la' ; then \
+          echo "Writing a loaders.cache file to use when running examples before installing gdk-pixbuf."; \
+         $(top_builddir)/gdk-pixbuf/gdk-pixbuf-query-loaders $$LOADERS > ./loaders.cache ;\
+       else \
+          echo "No dynamic modules found; will use only static modules for uninstalled example programs."; \
+         touch loaders.cache; \
+       fi
+else
+loaders.cache:
+       echo "No dynamic modules found; will use only static modules for uninstalled example programs."; \
+       touch loaders.cache;
+endif
+
+-include $(top_srcdir)/git.mk
diff --git a/gdk-pixbuf/Makefile.in b/gdk-pixbuf/Makefile.in
new file mode 100644 (file)
index 0000000..1ef1e52
--- /dev/null
@@ -0,0 +1,2495 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# GTK+ - The GIMP Toolkit
+
+
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+DIST_COMMON = $(libgdk_pixbufinclude_HEADERS) $(noinst_HEADERS) \
+       $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+       $(srcdir)/gdk-pixbuf-features.h.in $(srcdir)/gdk_pixbuf.rc.in \
+       $(top_srcdir)/Makefile.decl
+noinst_PROGRAMS = test-gdk-pixbuf$(EXEEXT)
+bin_PROGRAMS = gdk-pixbuf-csource$(EXEEXT) gdk-pixbuf-pixdata$(EXEEXT) \
+       gdk-pixbuf-query-loaders$(EXEEXT)
+@HAVE_INTROSPECTION_TRUE@am__append_1 = GdkPixbuf-2.0.gir
+@HAVE_INTROSPECTION_TRUE@am__append_2 = $(gir_DATA) $(typelibs_DATA)
+subdir = gdk-pixbuf
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \
+       $(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \
+       $(top_srcdir)/m4/intlmacosx.m4 \
+       $(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
+       $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+       $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+       $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+       $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+       $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+       $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = gdk_pixbuf.rc gdk-pixbuf-features.h
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(loaderdir)" \
+       "$(DESTDIR)$(bindir)" "$(DESTDIR)$(girdir)" \
+       "$(DESTDIR)$(typelibsdir)" \
+       "$(DESTDIR)$(libgdk_pixbufincludedir)"
+LTLIBRARIES = $(lib_LTLIBRARIES) $(loader_LTLIBRARIES) \
+       $(noinst_LTLIBRARIES)
+am__DEPENDENCIES_1 = $(STATIC_PIXDATA_LIB)
+am__DEPENDENCIES_2 =
+am_libgdk_pixbuf_2_0_la_OBJECTS = gdk-pixbuf.lo \
+       gdk-pixbuf-animation.lo gdk-pixbuf-data.lo gdk-pixbuf-io.lo \
+       gdk-pixbuf-loader.lo gdk-pixbuf-scale.lo \
+       gdk-pixbuf-simple-anim.lo gdk-pixbuf-scaled-anim.lo \
+       gdk-pixbuf-util.lo gdk-pixdata.lo gdk-pixbuf-enum-types.lo
+libgdk_pixbuf_2_0_la_OBJECTS = $(am_libgdk_pixbuf_2_0_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+libgdk_pixbuf_2_0_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(libgdk_pixbuf_2_0_la_LDFLAGS) \
+       $(LDFLAGS) -o $@
+am__DEPENDENCIES_3 = libgdk_pixbuf-$(GDK_PIXBUF_API_VERSION).la \
+       $(am__DEPENDENCIES_2)
+libpixbufloader_ani_la_DEPENDENCIES = $(am__DEPENDENCIES_3)
+am_libpixbufloader_ani_la_OBJECTS = io-ani.lo io-ani-animation.lo
+libpixbufloader_ani_la_OBJECTS = $(am_libpixbufloader_ani_la_OBJECTS)
+libpixbufloader_ani_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(libpixbufloader_ani_la_LDFLAGS) \
+       $(LDFLAGS) -o $@
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_ANI_FALSE@am_libpixbufloader_ani_la_rpath =  \
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_ANI_FALSE@        -rpath \
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_ANI_FALSE@        $(loaderdir)
+libpixbufloader_bmp_la_DEPENDENCIES = $(am__DEPENDENCIES_3)
+am_libpixbufloader_bmp_la_OBJECTS = io-bmp.lo
+libpixbufloader_bmp_la_OBJECTS = $(am_libpixbufloader_bmp_la_OBJECTS)
+libpixbufloader_bmp_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(libpixbufloader_bmp_la_LDFLAGS) \
+       $(LDFLAGS) -o $@
+@BUILD_DYNAMIC_MODULES_TRUE@@BUILD_GDIPLUS_LOADERS_FALSE@@INCLUDE_BMP_FALSE@am_libpixbufloader_bmp_la_rpath = -rpath \
+@BUILD_DYNAMIC_MODULES_TRUE@@BUILD_GDIPLUS_LOADERS_FALSE@@INCLUDE_BMP_FALSE@   $(loaderdir)
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@libpixbufloader_gdip_bmp_la_DEPENDENCIES = $(am__DEPENDENCIES_3) \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    $(am__DEPENDENCIES_2)
+am__libpixbufloader_gdip_bmp_la_SOURCES_DIST = io-gdip-native.h \
+       io-gdip-propertytags.h io-gdip-utils.h io-gdip-utils.c \
+       io-gdip-animation.c io-gdip-animation.h io-gdip-bmp.c
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@am_libpixbufloader_gdip_bmp_la_OBJECTS = io-gdip-utils.lo \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-animation.lo \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-bmp.lo
+libpixbufloader_gdip_bmp_la_OBJECTS =  \
+       $(am_libpixbufloader_gdip_bmp_la_OBJECTS)
+libpixbufloader_gdip_bmp_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(libpixbufloader_gdip_bmp_la_LDFLAGS) \
+       $(LDFLAGS) -o $@
+@BUILD_DYNAMIC_MODULES_TRUE@@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@am_libpixbufloader_gdip_bmp_la_rpath = -rpath \
+@BUILD_DYNAMIC_MODULES_TRUE@@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@        $(loaderdir)
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@libpixbufloader_gdip_emf_la_DEPENDENCIES = $(am__DEPENDENCIES_3) \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    $(am__DEPENDENCIES_2)
+am__libpixbufloader_gdip_emf_la_SOURCES_DIST = io-gdip-native.h \
+       io-gdip-propertytags.h io-gdip-utils.h io-gdip-utils.c \
+       io-gdip-animation.c io-gdip-animation.h io-gdip-emf.c
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@am_libpixbufloader_gdip_emf_la_OBJECTS = io-gdip-utils.lo \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-animation.lo \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-emf.lo
+libpixbufloader_gdip_emf_la_OBJECTS =  \
+       $(am_libpixbufloader_gdip_emf_la_OBJECTS)
+libpixbufloader_gdip_emf_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(libpixbufloader_gdip_emf_la_LDFLAGS) \
+       $(LDFLAGS) -o $@
+@BUILD_DYNAMIC_MODULES_TRUE@@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@am_libpixbufloader_gdip_emf_la_rpath = -rpath \
+@BUILD_DYNAMIC_MODULES_TRUE@@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@        $(loaderdir)
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@libpixbufloader_gdip_gif_la_DEPENDENCIES = $(am__DEPENDENCIES_3) \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    $(am__DEPENDENCIES_2)
+am__libpixbufloader_gdip_gif_la_SOURCES_DIST = io-gdip-native.h \
+       io-gdip-propertytags.h io-gdip-utils.h io-gdip-utils.c \
+       io-gdip-animation.c io-gdip-animation.h io-gdip-gif.c
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@am_libpixbufloader_gdip_gif_la_OBJECTS = io-gdip-utils.lo \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-animation.lo \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-gif.lo
+libpixbufloader_gdip_gif_la_OBJECTS =  \
+       $(am_libpixbufloader_gdip_gif_la_OBJECTS)
+libpixbufloader_gdip_gif_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(libpixbufloader_gdip_gif_la_LDFLAGS) \
+       $(LDFLAGS) -o $@
+@BUILD_DYNAMIC_MODULES_TRUE@@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@am_libpixbufloader_gdip_gif_la_rpath = -rpath \
+@BUILD_DYNAMIC_MODULES_TRUE@@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@        $(loaderdir)
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@libpixbufloader_gdip_ico_la_DEPENDENCIES = $(am__DEPENDENCIES_3) \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    $(am__DEPENDENCIES_2)
+am__libpixbufloader_gdip_ico_la_SOURCES_DIST = io-gdip-native.h \
+       io-gdip-propertytags.h io-gdip-utils.h io-gdip-utils.c \
+       io-gdip-animation.c io-gdip-animation.h io-gdip-ico.c
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@am_libpixbufloader_gdip_ico_la_OBJECTS = io-gdip-utils.lo \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-animation.lo \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-ico.lo
+libpixbufloader_gdip_ico_la_OBJECTS =  \
+       $(am_libpixbufloader_gdip_ico_la_OBJECTS)
+libpixbufloader_gdip_ico_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(libpixbufloader_gdip_ico_la_LDFLAGS) \
+       $(LDFLAGS) -o $@
+@BUILD_DYNAMIC_MODULES_TRUE@@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@am_libpixbufloader_gdip_ico_la_rpath = -rpath \
+@BUILD_DYNAMIC_MODULES_TRUE@@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@        $(loaderdir)
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@libpixbufloader_gdip_jpeg_la_DEPENDENCIES = $(am__DEPENDENCIES_3) \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    $(am__DEPENDENCIES_2)
+am__libpixbufloader_gdip_jpeg_la_SOURCES_DIST = io-gdip-native.h \
+       io-gdip-propertytags.h io-gdip-utils.h io-gdip-utils.c \
+       io-gdip-animation.c io-gdip-animation.h io-gdip-jpeg.c
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@am_libpixbufloader_gdip_jpeg_la_OBJECTS = io-gdip-utils.lo \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-animation.lo \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-jpeg.lo
+libpixbufloader_gdip_jpeg_la_OBJECTS =  \
+       $(am_libpixbufloader_gdip_jpeg_la_OBJECTS)
+libpixbufloader_gdip_jpeg_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(libpixbufloader_gdip_jpeg_la_LDFLAGS) \
+       $(LDFLAGS) -o $@
+@BUILD_DYNAMIC_MODULES_TRUE@@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@am_libpixbufloader_gdip_jpeg_la_rpath = -rpath \
+@BUILD_DYNAMIC_MODULES_TRUE@@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@        $(loaderdir)
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@libpixbufloader_gdip_tiff_la_DEPENDENCIES = $(am__DEPENDENCIES_3) \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    $(am__DEPENDENCIES_2)
+am__libpixbufloader_gdip_tiff_la_SOURCES_DIST = io-gdip-native.h \
+       io-gdip-propertytags.h io-gdip-utils.h io-gdip-utils.c \
+       io-gdip-animation.c io-gdip-animation.h io-gdip-tiff.c
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@am_libpixbufloader_gdip_tiff_la_OBJECTS = io-gdip-utils.lo \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-animation.lo \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-tiff.lo
+libpixbufloader_gdip_tiff_la_OBJECTS =  \
+       $(am_libpixbufloader_gdip_tiff_la_OBJECTS)
+libpixbufloader_gdip_tiff_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(libpixbufloader_gdip_tiff_la_LDFLAGS) \
+       $(LDFLAGS) -o $@
+@BUILD_DYNAMIC_MODULES_TRUE@@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@am_libpixbufloader_gdip_tiff_la_rpath = -rpath \
+@BUILD_DYNAMIC_MODULES_TRUE@@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@        $(loaderdir)
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@libpixbufloader_gdip_wmf_la_DEPENDENCIES = $(am__DEPENDENCIES_3) \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    $(am__DEPENDENCIES_2)
+am__libpixbufloader_gdip_wmf_la_SOURCES_DIST = io-gdip-native.h \
+       io-gdip-propertytags.h io-gdip-utils.h io-gdip-utils.c \
+       io-gdip-animation.c io-gdip-animation.h io-gdip-wmf.c
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@am_libpixbufloader_gdip_wmf_la_OBJECTS = io-gdip-utils.lo \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-animation.lo \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-wmf.lo
+libpixbufloader_gdip_wmf_la_OBJECTS =  \
+       $(am_libpixbufloader_gdip_wmf_la_OBJECTS)
+libpixbufloader_gdip_wmf_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(libpixbufloader_gdip_wmf_la_LDFLAGS) \
+       $(LDFLAGS) -o $@
+@BUILD_DYNAMIC_MODULES_TRUE@@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@am_libpixbufloader_gdip_wmf_la_rpath = -rpath \
+@BUILD_DYNAMIC_MODULES_TRUE@@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@        $(loaderdir)
+libpixbufloader_gif_la_DEPENDENCIES = $(am__DEPENDENCIES_3)
+am_libpixbufloader_gif_la_OBJECTS = io-gif.lo io-gif-animation.lo
+libpixbufloader_gif_la_OBJECTS = $(am_libpixbufloader_gif_la_OBJECTS)
+libpixbufloader_gif_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(libpixbufloader_gif_la_LDFLAGS) \
+       $(LDFLAGS) -o $@
+@BUILD_DYNAMIC_MODULES_TRUE@@BUILD_GDIPLUS_LOADERS_FALSE@@INCLUDE_GIF_FALSE@am_libpixbufloader_gif_la_rpath = -rpath \
+@BUILD_DYNAMIC_MODULES_TRUE@@BUILD_GDIPLUS_LOADERS_FALSE@@INCLUDE_GIF_FALSE@   $(loaderdir)
+libpixbufloader_icns_la_DEPENDENCIES = $(am__DEPENDENCIES_3)
+am_libpixbufloader_icns_la_OBJECTS = io-icns.lo
+libpixbufloader_icns_la_OBJECTS =  \
+       $(am_libpixbufloader_icns_la_OBJECTS)
+libpixbufloader_icns_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(libpixbufloader_icns_la_LDFLAGS) \
+       $(LDFLAGS) -o $@
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_ICNS_FALSE@am_libpixbufloader_icns_la_rpath =  \
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_ICNS_FALSE@       -rpath \
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_ICNS_FALSE@       $(loaderdir)
+libpixbufloader_ico_la_DEPENDENCIES = $(am__DEPENDENCIES_3)
+am_libpixbufloader_ico_la_OBJECTS = io-ico.lo
+libpixbufloader_ico_la_OBJECTS = $(am_libpixbufloader_ico_la_OBJECTS)
+libpixbufloader_ico_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(libpixbufloader_ico_la_LDFLAGS) \
+       $(LDFLAGS) -o $@
+@BUILD_DYNAMIC_MODULES_TRUE@@BUILD_GDIPLUS_LOADERS_FALSE@@INCLUDE_ICO_FALSE@am_libpixbufloader_ico_la_rpath = -rpath \
+@BUILD_DYNAMIC_MODULES_TRUE@@BUILD_GDIPLUS_LOADERS_FALSE@@INCLUDE_ICO_FALSE@   $(loaderdir)
+libpixbufloader_jasper_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \
+       $(am__DEPENDENCIES_3)
+am_libpixbufloader_jasper_la_OBJECTS = io-jasper.lo
+libpixbufloader_jasper_la_OBJECTS =  \
+       $(am_libpixbufloader_jasper_la_OBJECTS)
+libpixbufloader_jasper_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(libpixbufloader_jasper_la_LDFLAGS) \
+       $(LDFLAGS) -o $@
+@BUILD_DYNAMIC_MODULES_TRUE@@HAVE_JASPER_TRUE@@INCLUDE_JASPER_FALSE@am_libpixbufloader_jasper_la_rpath = -rpath \
+@BUILD_DYNAMIC_MODULES_TRUE@@HAVE_JASPER_TRUE@@INCLUDE_JASPER_FALSE@   $(loaderdir)
+libpixbufloader_jpeg_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \
+       $(am__DEPENDENCIES_3)
+am_libpixbufloader_jpeg_la_OBJECTS = io-jpeg.lo
+libpixbufloader_jpeg_la_OBJECTS =  \
+       $(am_libpixbufloader_jpeg_la_OBJECTS)
+libpixbufloader_jpeg_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(libpixbufloader_jpeg_la_LDFLAGS) \
+       $(LDFLAGS) -o $@
+@BUILD_DYNAMIC_MODULES_TRUE@@BUILD_GDIPLUS_LOADERS_FALSE@@HAVE_JPEG_TRUE@@INCLUDE_JPEG_FALSE@am_libpixbufloader_jpeg_la_rpath = -rpath \
+@BUILD_DYNAMIC_MODULES_TRUE@@BUILD_GDIPLUS_LOADERS_FALSE@@HAVE_JPEG_TRUE@@INCLUDE_JPEG_FALSE@  $(loaderdir)
+libpixbufloader_pcx_la_DEPENDENCIES = $(am__DEPENDENCIES_3)
+am_libpixbufloader_pcx_la_OBJECTS = io-pcx.lo
+libpixbufloader_pcx_la_OBJECTS = $(am_libpixbufloader_pcx_la_OBJECTS)
+libpixbufloader_pcx_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(libpixbufloader_pcx_la_LDFLAGS) \
+       $(LDFLAGS) -o $@
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_PCX_FALSE@am_libpixbufloader_pcx_la_rpath =  \
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_PCX_FALSE@        -rpath \
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_PCX_FALSE@        $(loaderdir)
+libpixbufloader_png_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \
+       $(am__DEPENDENCIES_3)
+am_libpixbufloader_png_la_OBJECTS = io-png.lo
+libpixbufloader_png_la_OBJECTS = $(am_libpixbufloader_png_la_OBJECTS)
+libpixbufloader_png_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(libpixbufloader_png_la_LDFLAGS) \
+       $(LDFLAGS) -o $@
+@BUILD_DYNAMIC_MODULES_TRUE@@HAVE_PNG_TRUE@@INCLUDE_PNG_FALSE@am_libpixbufloader_png_la_rpath = -rpath \
+@BUILD_DYNAMIC_MODULES_TRUE@@HAVE_PNG_TRUE@@INCLUDE_PNG_FALSE@ $(loaderdir)
+libpixbufloader_pnm_la_DEPENDENCIES = $(am__DEPENDENCIES_3)
+am_libpixbufloader_pnm_la_OBJECTS = io-pnm.lo
+libpixbufloader_pnm_la_OBJECTS = $(am_libpixbufloader_pnm_la_OBJECTS)
+libpixbufloader_pnm_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(libpixbufloader_pnm_la_LDFLAGS) \
+       $(LDFLAGS) -o $@
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_PNM_FALSE@am_libpixbufloader_pnm_la_rpath =  \
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_PNM_FALSE@        -rpath \
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_PNM_FALSE@        $(loaderdir)
+libpixbufloader_qtif_la_DEPENDENCIES = $(am__DEPENDENCIES_3)
+am_libpixbufloader_qtif_la_OBJECTS = io-qtif.lo
+libpixbufloader_qtif_la_OBJECTS =  \
+       $(am_libpixbufloader_qtif_la_OBJECTS)
+libpixbufloader_qtif_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(libpixbufloader_qtif_la_LDFLAGS) \
+       $(LDFLAGS) -o $@
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_QTIF_FALSE@am_libpixbufloader_qtif_la_rpath =  \
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_QTIF_FALSE@       -rpath \
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_QTIF_FALSE@       $(loaderdir)
+libpixbufloader_ras_la_DEPENDENCIES = $(am__DEPENDENCIES_3)
+am_libpixbufloader_ras_la_OBJECTS = io-ras.lo
+libpixbufloader_ras_la_OBJECTS = $(am_libpixbufloader_ras_la_OBJECTS)
+libpixbufloader_ras_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(libpixbufloader_ras_la_LDFLAGS) \
+       $(LDFLAGS) -o $@
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_RAS_FALSE@am_libpixbufloader_ras_la_rpath =  \
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_RAS_FALSE@        -rpath \
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_RAS_FALSE@        $(loaderdir)
+libpixbufloader_tga_la_DEPENDENCIES = $(am__DEPENDENCIES_3)
+am_libpixbufloader_tga_la_OBJECTS = io-tga.lo
+libpixbufloader_tga_la_OBJECTS = $(am_libpixbufloader_tga_la_OBJECTS)
+libpixbufloader_tga_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(libpixbufloader_tga_la_LDFLAGS) \
+       $(LDFLAGS) -o $@
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_TGA_FALSE@am_libpixbufloader_tga_la_rpath =  \
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_TGA_FALSE@        -rpath \
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_TGA_FALSE@        $(loaderdir)
+libpixbufloader_tiff_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \
+       $(am__DEPENDENCIES_3)
+am_libpixbufloader_tiff_la_OBJECTS = io-tiff.lo
+libpixbufloader_tiff_la_OBJECTS =  \
+       $(am_libpixbufloader_tiff_la_OBJECTS)
+libpixbufloader_tiff_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(libpixbufloader_tiff_la_LDFLAGS) \
+       $(LDFLAGS) -o $@
+@BUILD_DYNAMIC_MODULES_TRUE@@BUILD_GDIPLUS_LOADERS_FALSE@@HAVE_TIFF_TRUE@@INCLUDE_TIFF_FALSE@am_libpixbufloader_tiff_la_rpath = -rpath \
+@BUILD_DYNAMIC_MODULES_TRUE@@BUILD_GDIPLUS_LOADERS_FALSE@@HAVE_TIFF_TRUE@@INCLUDE_TIFF_FALSE@  $(loaderdir)
+libpixbufloader_wbmp_la_DEPENDENCIES = $(am__DEPENDENCIES_3)
+am_libpixbufloader_wbmp_la_OBJECTS = io-wbmp.lo
+libpixbufloader_wbmp_la_OBJECTS =  \
+       $(am_libpixbufloader_wbmp_la_OBJECTS)
+libpixbufloader_wbmp_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(libpixbufloader_wbmp_la_LDFLAGS) \
+       $(LDFLAGS) -o $@
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_WBMP_FALSE@am_libpixbufloader_wbmp_la_rpath =  \
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_WBMP_FALSE@       -rpath \
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_WBMP_FALSE@       $(loaderdir)
+libpixbufloader_xbm_la_DEPENDENCIES = $(am__DEPENDENCIES_3)
+am_libpixbufloader_xbm_la_OBJECTS = io-xbm.lo
+libpixbufloader_xbm_la_OBJECTS = $(am_libpixbufloader_xbm_la_OBJECTS)
+libpixbufloader_xbm_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(libpixbufloader_xbm_la_LDFLAGS) \
+       $(LDFLAGS) -o $@
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_XBM_FALSE@am_libpixbufloader_xbm_la_rpath =  \
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_XBM_FALSE@        -rpath \
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_XBM_FALSE@        $(loaderdir)
+libpixbufloader_xpm_la_DEPENDENCIES = $(am__DEPENDENCIES_3)
+am_libpixbufloader_xpm_la_OBJECTS = io-xpm.lo
+libpixbufloader_xpm_la_OBJECTS = $(am_libpixbufloader_xpm_la_OBJECTS)
+libpixbufloader_xpm_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(libpixbufloader_xpm_la_LDFLAGS) \
+       $(LDFLAGS) -o $@
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_XPM_FALSE@am_libpixbufloader_xpm_la_rpath =  \
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_XPM_FALSE@        -rpath \
+@BUILD_DYNAMIC_MODULES_TRUE@@INCLUDE_XPM_FALSE@        $(loaderdir)
+libstatic_pixbufloader_ani_la_LIBADD =
+am_libstatic_pixbufloader_ani_la_OBJECTS = io-ani.lo \
+       io-ani-animation.lo
+libstatic_pixbufloader_ani_la_OBJECTS =  \
+       $(am_libstatic_pixbufloader_ani_la_OBJECTS)
+@INCLUDE_ANI_TRUE@am_libstatic_pixbufloader_ani_la_rpath =
+libstatic_pixbufloader_bmp_la_LIBADD =
+am_libstatic_pixbufloader_bmp_la_OBJECTS = io-bmp.lo
+libstatic_pixbufloader_bmp_la_OBJECTS =  \
+       $(am_libstatic_pixbufloader_bmp_la_OBJECTS)
+@BUILD_GDIPLUS_LOADERS_FALSE@@INCLUDE_BMP_TRUE@am_libstatic_pixbufloader_bmp_la_rpath =
+libstatic_pixbufloader_gdip_bmp_la_LIBADD =
+am__libstatic_pixbufloader_gdip_bmp_la_SOURCES_DIST = io-gdip-bmp.c
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@am_libstatic_pixbufloader_gdip_bmp_la_OBJECTS = io-gdip-bmp.lo
+libstatic_pixbufloader_gdip_bmp_la_OBJECTS =  \
+       $(am_libstatic_pixbufloader_gdip_bmp_la_OBJECTS)
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@am_libstatic_pixbufloader_gdip_bmp_la_rpath =
+libstatic_pixbufloader_gdip_emf_la_LIBADD =
+am__libstatic_pixbufloader_gdip_emf_la_SOURCES_DIST = io-gdip-emf.c
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@am_libstatic_pixbufloader_gdip_emf_la_OBJECTS = io-gdip-emf.lo
+libstatic_pixbufloader_gdip_emf_la_OBJECTS =  \
+       $(am_libstatic_pixbufloader_gdip_emf_la_OBJECTS)
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@am_libstatic_pixbufloader_gdip_emf_la_rpath =
+libstatic_pixbufloader_gdip_gif_la_LIBADD =
+am__libstatic_pixbufloader_gdip_gif_la_SOURCES_DIST = io-gdip-gif.c
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@am_libstatic_pixbufloader_gdip_gif_la_OBJECTS = io-gdip-gif.lo
+libstatic_pixbufloader_gdip_gif_la_OBJECTS =  \
+       $(am_libstatic_pixbufloader_gdip_gif_la_OBJECTS)
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@am_libstatic_pixbufloader_gdip_gif_la_rpath =
+libstatic_pixbufloader_gdip_ico_la_LIBADD =
+am__libstatic_pixbufloader_gdip_ico_la_SOURCES_DIST =  \
+       io-gdip-native.h io-gdip-propertytags.h io-gdip-utils.h \
+       io-gdip-utils.c io-gdip-animation.c io-gdip-animation.h \
+       io-gdip-ico.c
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@am_libstatic_pixbufloader_gdip_ico_la_OBJECTS = io-gdip-utils.lo \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@     io-gdip-animation.lo \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@     io-gdip-ico.lo
+libstatic_pixbufloader_gdip_ico_la_OBJECTS =  \
+       $(am_libstatic_pixbufloader_gdip_ico_la_OBJECTS)
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@am_libstatic_pixbufloader_gdip_ico_la_rpath =
+libstatic_pixbufloader_gdip_jpeg_la_LIBADD =
+am__libstatic_pixbufloader_gdip_jpeg_la_SOURCES_DIST = io-gdip-jpeg.c
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@am_libstatic_pixbufloader_gdip_jpeg_la_OBJECTS = io-gdip-jpeg.lo
+libstatic_pixbufloader_gdip_jpeg_la_OBJECTS =  \
+       $(am_libstatic_pixbufloader_gdip_jpeg_la_OBJECTS)
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@am_libstatic_pixbufloader_gdip_jpeg_la_rpath =
+libstatic_pixbufloader_gdip_tiff_la_LIBADD =
+am__libstatic_pixbufloader_gdip_tiff_la_SOURCES_DIST = io-gdip-tiff.c
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@am_libstatic_pixbufloader_gdip_tiff_la_OBJECTS = io-gdip-tiff.lo
+libstatic_pixbufloader_gdip_tiff_la_OBJECTS =  \
+       $(am_libstatic_pixbufloader_gdip_tiff_la_OBJECTS)
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@am_libstatic_pixbufloader_gdip_tiff_la_rpath =
+libstatic_pixbufloader_gdip_wmf_la_LIBADD =
+am__libstatic_pixbufloader_gdip_wmf_la_SOURCES_DIST = io-gdip-wmf.c
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@am_libstatic_pixbufloader_gdip_wmf_la_OBJECTS = io-gdip-wmf.lo
+libstatic_pixbufloader_gdip_wmf_la_OBJECTS =  \
+       $(am_libstatic_pixbufloader_gdip_wmf_la_OBJECTS)
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@am_libstatic_pixbufloader_gdip_wmf_la_rpath =
+libstatic_pixbufloader_gif_la_LIBADD =
+am_libstatic_pixbufloader_gif_la_OBJECTS = io-gif.lo \
+       io-gif-animation.lo
+libstatic_pixbufloader_gif_la_OBJECTS =  \
+       $(am_libstatic_pixbufloader_gif_la_OBJECTS)
+@BUILD_GDIPLUS_LOADERS_FALSE@@INCLUDE_GIF_TRUE@am_libstatic_pixbufloader_gif_la_rpath =
+libstatic_pixbufloader_icns_la_LIBADD =
+am_libstatic_pixbufloader_icns_la_OBJECTS = io-icns.lo
+libstatic_pixbufloader_icns_la_OBJECTS =  \
+       $(am_libstatic_pixbufloader_icns_la_OBJECTS)
+@INCLUDE_ICNS_TRUE@am_libstatic_pixbufloader_icns_la_rpath =
+libstatic_pixbufloader_ico_la_LIBADD =
+am_libstatic_pixbufloader_ico_la_OBJECTS = io-ico.lo
+libstatic_pixbufloader_ico_la_OBJECTS =  \
+       $(am_libstatic_pixbufloader_ico_la_OBJECTS)
+@BUILD_GDIPLUS_LOADERS_FALSE@@INCLUDE_ICO_TRUE@am_libstatic_pixbufloader_ico_la_rpath =
+libstatic_pixbufloader_jasper_la_LIBADD =
+am_libstatic_pixbufloader_jasper_la_OBJECTS = io-jasper.lo
+libstatic_pixbufloader_jasper_la_OBJECTS =  \
+       $(am_libstatic_pixbufloader_jasper_la_OBJECTS)
+@HAVE_JASPER_TRUE@@INCLUDE_JASPER_TRUE@am_libstatic_pixbufloader_jasper_la_rpath =
+libstatic_pixbufloader_jpeg_la_LIBADD =
+am_libstatic_pixbufloader_jpeg_la_OBJECTS = io-jpeg.lo
+libstatic_pixbufloader_jpeg_la_OBJECTS =  \
+       $(am_libstatic_pixbufloader_jpeg_la_OBJECTS)
+@BUILD_GDIPLUS_LOADERS_FALSE@@HAVE_JPEG_TRUE@@INCLUDE_JPEG_TRUE@am_libstatic_pixbufloader_jpeg_la_rpath =
+libstatic_pixbufloader_pcx_la_LIBADD =
+am_libstatic_pixbufloader_pcx_la_OBJECTS = io-pcx.lo
+libstatic_pixbufloader_pcx_la_OBJECTS =  \
+       $(am_libstatic_pixbufloader_pcx_la_OBJECTS)
+@INCLUDE_PCX_TRUE@am_libstatic_pixbufloader_pcx_la_rpath =
+libstatic_pixbufloader_pixdata_la_LIBADD =
+am_libstatic_pixbufloader_pixdata_la_OBJECTS = io-pixdata.lo
+libstatic_pixbufloader_pixdata_la_OBJECTS =  \
+       $(am_libstatic_pixbufloader_pixdata_la_OBJECTS)
+libstatic_pixbufloader_png_la_LIBADD =
+am_libstatic_pixbufloader_png_la_OBJECTS = io-png.lo
+libstatic_pixbufloader_png_la_OBJECTS =  \
+       $(am_libstatic_pixbufloader_png_la_OBJECTS)
+@HAVE_PNG_TRUE@@INCLUDE_PNG_TRUE@am_libstatic_pixbufloader_png_la_rpath =
+libstatic_pixbufloader_pnm_la_LIBADD =
+am_libstatic_pixbufloader_pnm_la_OBJECTS = io-pnm.lo
+libstatic_pixbufloader_pnm_la_OBJECTS =  \
+       $(am_libstatic_pixbufloader_pnm_la_OBJECTS)
+@INCLUDE_PNM_TRUE@am_libstatic_pixbufloader_pnm_la_rpath =
+libstatic_pixbufloader_qtif_la_LIBADD =
+am_libstatic_pixbufloader_qtif_la_OBJECTS = io-qtif.lo
+libstatic_pixbufloader_qtif_la_OBJECTS =  \
+       $(am_libstatic_pixbufloader_qtif_la_OBJECTS)
+@INCLUDE_QTIF_TRUE@am_libstatic_pixbufloader_qtif_la_rpath =
+libstatic_pixbufloader_ras_la_LIBADD =
+am_libstatic_pixbufloader_ras_la_OBJECTS = io-ras.lo
+libstatic_pixbufloader_ras_la_OBJECTS =  \
+       $(am_libstatic_pixbufloader_ras_la_OBJECTS)
+@INCLUDE_RAS_TRUE@am_libstatic_pixbufloader_ras_la_rpath =
+libstatic_pixbufloader_tga_la_LIBADD =
+am_libstatic_pixbufloader_tga_la_OBJECTS = io-tga.lo
+libstatic_pixbufloader_tga_la_OBJECTS =  \
+       $(am_libstatic_pixbufloader_tga_la_OBJECTS)
+@INCLUDE_TGA_TRUE@am_libstatic_pixbufloader_tga_la_rpath =
+libstatic_pixbufloader_tiff_la_LIBADD =
+am_libstatic_pixbufloader_tiff_la_OBJECTS = io-tiff.lo
+libstatic_pixbufloader_tiff_la_OBJECTS =  \
+       $(am_libstatic_pixbufloader_tiff_la_OBJECTS)
+@BUILD_GDIPLUS_LOADERS_FALSE@@HAVE_TIFF_TRUE@@INCLUDE_TIFF_TRUE@am_libstatic_pixbufloader_tiff_la_rpath =
+libstatic_pixbufloader_wbmp_la_LIBADD =
+am_libstatic_pixbufloader_wbmp_la_OBJECTS = io-wbmp.lo
+libstatic_pixbufloader_wbmp_la_OBJECTS =  \
+       $(am_libstatic_pixbufloader_wbmp_la_OBJECTS)
+@INCLUDE_WBMP_TRUE@am_libstatic_pixbufloader_wbmp_la_rpath =
+libstatic_pixbufloader_xbm_la_LIBADD =
+am_libstatic_pixbufloader_xbm_la_OBJECTS = io-xbm.lo
+libstatic_pixbufloader_xbm_la_OBJECTS =  \
+       $(am_libstatic_pixbufloader_xbm_la_OBJECTS)
+@INCLUDE_XBM_TRUE@am_libstatic_pixbufloader_xbm_la_rpath =
+libstatic_pixbufloader_xpm_la_LIBADD =
+am_libstatic_pixbufloader_xpm_la_OBJECTS = io-xpm.lo
+libstatic_pixbufloader_xpm_la_OBJECTS =  \
+       $(am_libstatic_pixbufloader_xpm_la_OBJECTS)
+@INCLUDE_XPM_TRUE@am_libstatic_pixbufloader_xpm_la_rpath =
+PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS)
+am_gdk_pixbuf_csource_OBJECTS = gdk-pixbuf-csource.$(OBJEXT)
+gdk_pixbuf_csource_OBJECTS = $(am_gdk_pixbuf_csource_OBJECTS)
+gdk_pixbuf_csource_DEPENDENCIES = $(am__DEPENDENCIES_3)
+am_gdk_pixbuf_pixdata_OBJECTS = gdk-pixbuf-pixdata.$(OBJEXT)
+gdk_pixbuf_pixdata_OBJECTS = $(am_gdk_pixbuf_pixdata_OBJECTS)
+gdk_pixbuf_pixdata_DEPENDENCIES = $(am__DEPENDENCIES_3)
+am_gdk_pixbuf_query_loaders_OBJECTS = queryloaders.$(OBJEXT)
+gdk_pixbuf_query_loaders_OBJECTS =  \
+       $(am_gdk_pixbuf_query_loaders_OBJECTS)
+test_gdk_pixbuf_SOURCES = test-gdk-pixbuf.c
+test_gdk_pixbuf_OBJECTS = test-gdk-pixbuf.$(OBJEXT)
+test_gdk_pixbuf_DEPENDENCIES = $(am__DEPENDENCIES_3)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+       $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+       $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC    " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+       $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD  " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN   " $@;
+SOURCES = $(libgdk_pixbuf_2_0_la_SOURCES) \
+       $(libpixbufloader_ani_la_SOURCES) \
+       $(libpixbufloader_bmp_la_SOURCES) \
+       $(libpixbufloader_gdip_bmp_la_SOURCES) \
+       $(libpixbufloader_gdip_emf_la_SOURCES) \
+       $(libpixbufloader_gdip_gif_la_SOURCES) \
+       $(libpixbufloader_gdip_ico_la_SOURCES) \
+       $(libpixbufloader_gdip_jpeg_la_SOURCES) \
+       $(libpixbufloader_gdip_tiff_la_SOURCES) \
+       $(libpixbufloader_gdip_wmf_la_SOURCES) \
+       $(libpixbufloader_gif_la_SOURCES) \
+       $(libpixbufloader_icns_la_SOURCES) \
+       $(libpixbufloader_ico_la_SOURCES) \
+       $(libpixbufloader_jasper_la_SOURCES) \
+       $(libpixbufloader_jpeg_la_SOURCES) \
+       $(libpixbufloader_pcx_la_SOURCES) \
+       $(libpixbufloader_png_la_SOURCES) \
+       $(libpixbufloader_pnm_la_SOURCES) \
+       $(libpixbufloader_qtif_la_SOURCES) \
+       $(libpixbufloader_ras_la_SOURCES) \
+       $(libpixbufloader_tga_la_SOURCES) \
+       $(libpixbufloader_tiff_la_SOURCES) \
+       $(libpixbufloader_wbmp_la_SOURCES) \
+       $(libpixbufloader_xbm_la_SOURCES) \
+       $(libpixbufloader_xpm_la_SOURCES) \
+       $(libstatic_pixbufloader_ani_la_SOURCES) \
+       $(libstatic_pixbufloader_bmp_la_SOURCES) \
+       $(libstatic_pixbufloader_gdip_bmp_la_SOURCES) \
+       $(libstatic_pixbufloader_gdip_emf_la_SOURCES) \
+       $(libstatic_pixbufloader_gdip_gif_la_SOURCES) \
+       $(libstatic_pixbufloader_gdip_ico_la_SOURCES) \
+       $(libstatic_pixbufloader_gdip_jpeg_la_SOURCES) \
+       $(libstatic_pixbufloader_gdip_tiff_la_SOURCES) \
+       $(libstatic_pixbufloader_gdip_wmf_la_SOURCES) \
+       $(libstatic_pixbufloader_gif_la_SOURCES) \
+       $(libstatic_pixbufloader_icns_la_SOURCES) \
+       $(libstatic_pixbufloader_ico_la_SOURCES) \
+       $(libstatic_pixbufloader_jasper_la_SOURCES) \
+       $(libstatic_pixbufloader_jpeg_la_SOURCES) \
+       $(libstatic_pixbufloader_pcx_la_SOURCES) \
+       $(libstatic_pixbufloader_pixdata_la_SOURCES) \
+       $(libstatic_pixbufloader_png_la_SOURCES) \
+       $(libstatic_pixbufloader_pnm_la_SOURCES) \
+       $(libstatic_pixbufloader_qtif_la_SOURCES) \
+       $(libstatic_pixbufloader_ras_la_SOURCES) \
+       $(libstatic_pixbufloader_tga_la_SOURCES) \
+       $(libstatic_pixbufloader_tiff_la_SOURCES) \
+       $(libstatic_pixbufloader_wbmp_la_SOURCES) \
+       $(libstatic_pixbufloader_xbm_la_SOURCES) \
+       $(libstatic_pixbufloader_xpm_la_SOURCES) \
+       $(gdk_pixbuf_csource_SOURCES) $(gdk_pixbuf_pixdata_SOURCES) \
+       $(gdk_pixbuf_query_loaders_SOURCES) test-gdk-pixbuf.c
+DIST_SOURCES = $(libgdk_pixbuf_2_0_la_SOURCES) \
+       $(libpixbufloader_ani_la_SOURCES) \
+       $(libpixbufloader_bmp_la_SOURCES) \
+       $(am__libpixbufloader_gdip_bmp_la_SOURCES_DIST) \
+       $(am__libpixbufloader_gdip_emf_la_SOURCES_DIST) \
+       $(am__libpixbufloader_gdip_gif_la_SOURCES_DIST) \
+       $(am__libpixbufloader_gdip_ico_la_SOURCES_DIST) \
+       $(am__libpixbufloader_gdip_jpeg_la_SOURCES_DIST) \
+       $(am__libpixbufloader_gdip_tiff_la_SOURCES_DIST) \
+       $(am__libpixbufloader_gdip_wmf_la_SOURCES_DIST) \
+       $(libpixbufloader_gif_la_SOURCES) \
+       $(libpixbufloader_icns_la_SOURCES) \
+       $(libpixbufloader_ico_la_SOURCES) \
+       $(libpixbufloader_jasper_la_SOURCES) \
+       $(libpixbufloader_jpeg_la_SOURCES) \
+       $(libpixbufloader_pcx_la_SOURCES) \
+       $(libpixbufloader_png_la_SOURCES) \
+       $(libpixbufloader_pnm_la_SOURCES) \
+       $(libpixbufloader_qtif_la_SOURCES) \
+       $(libpixbufloader_ras_la_SOURCES) \
+       $(libpixbufloader_tga_la_SOURCES) \
+       $(libpixbufloader_tiff_la_SOURCES) \
+       $(libpixbufloader_wbmp_la_SOURCES) \
+       $(libpixbufloader_xbm_la_SOURCES) \
+       $(libpixbufloader_xpm_la_SOURCES) \
+       $(libstatic_pixbufloader_ani_la_SOURCES) \
+       $(libstatic_pixbufloader_bmp_la_SOURCES) \
+       $(am__libstatic_pixbufloader_gdip_bmp_la_SOURCES_DIST) \
+       $(am__libstatic_pixbufloader_gdip_emf_la_SOURCES_DIST) \
+       $(am__libstatic_pixbufloader_gdip_gif_la_SOURCES_DIST) \
+       $(am__libstatic_pixbufloader_gdip_ico_la_SOURCES_DIST) \
+       $(am__libstatic_pixbufloader_gdip_jpeg_la_SOURCES_DIST) \
+       $(am__libstatic_pixbufloader_gdip_tiff_la_SOURCES_DIST) \
+       $(am__libstatic_pixbufloader_gdip_wmf_la_SOURCES_DIST) \
+       $(libstatic_pixbufloader_gif_la_SOURCES) \
+       $(libstatic_pixbufloader_icns_la_SOURCES) \
+       $(libstatic_pixbufloader_ico_la_SOURCES) \
+       $(libstatic_pixbufloader_jasper_la_SOURCES) \
+       $(libstatic_pixbufloader_jpeg_la_SOURCES) \
+       $(libstatic_pixbufloader_pcx_la_SOURCES) \
+       $(libstatic_pixbufloader_pixdata_la_SOURCES) \
+       $(libstatic_pixbufloader_png_la_SOURCES) \
+       $(libstatic_pixbufloader_pnm_la_SOURCES) \
+       $(libstatic_pixbufloader_qtif_la_SOURCES) \
+       $(libstatic_pixbufloader_ras_la_SOURCES) \
+       $(libstatic_pixbufloader_tga_la_SOURCES) \
+       $(libstatic_pixbufloader_tiff_la_SOURCES) \
+       $(libstatic_pixbufloader_wbmp_la_SOURCES) \
+       $(libstatic_pixbufloader_xbm_la_SOURCES) \
+       $(libstatic_pixbufloader_xpm_la_SOURCES) \
+       $(gdk_pixbuf_csource_SOURCES) $(gdk_pixbuf_pixdata_SOURCES) \
+       $(gdk_pixbuf_query_loaders_SOURCES) test-gdk-pixbuf.c
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+       html-recursive info-recursive install-data-recursive \
+       install-dvi-recursive install-exec-recursive \
+       install-html-recursive install-info-recursive \
+       install-pdf-recursive install-ps-recursive install-recursive \
+       installcheck-recursive installdirs-recursive pdf-recursive \
+       ps-recursive uninstall-recursive
+DATA = $(gir_DATA) $(noinst_DATA) $(typelibs_DATA)
+HEADERS = $(libgdk_pixbufinclude_HEADERS) $(noinst_HEADERS)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive        \
+  distclean-recursive maintainer-clean-recursive
+AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
+       $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
+       distdir
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors = \
+red=; grn=; lgn=; blu=; std=
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+  dir0=`pwd`; \
+  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+  sed_rest='s,^[^/]*/*,,'; \
+  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+  sed_butlast='s,/*[^/]*$$,,'; \
+  while test -n "$$dir1"; do \
+    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+    if test "$$first" != "."; then \
+      if test "$$first" = ".."; then \
+        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+      else \
+        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+        if test "$$first2" = "$$first"; then \
+          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+        else \
+          dir2="../$$dir2"; \
+        fi; \
+        dir0="$$dir0"/"$$first"; \
+      fi; \
+    fi; \
+    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+  done; \
+  reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BASE_DEPENDENCIES_CFLAGS = @BASE_DEPENDENCIES_CFLAGS@
+BASE_DEPENDENCIES_LIBS = @BASE_DEPENDENCIES_LIBS@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DB2HTML = @DB2HTML@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXE_MANIFEST_ARCHITECTURE = @EXE_MANIFEST_ARCHITECTURE@
+FGREP = @FGREP@
+GDK_PIXBUF_API_VERSION = @GDK_PIXBUF_API_VERSION@
+GDK_PIXBUF_BINARY_VERSION = @GDK_PIXBUF_BINARY_VERSION@
+GDK_PIXBUF_CSOURCE = @GDK_PIXBUF_CSOURCE@
+GDK_PIXBUF_DEP_CFLAGS = @GDK_PIXBUF_DEP_CFLAGS@
+GDK_PIXBUF_DEP_LIBS = @GDK_PIXBUF_DEP_LIBS@
+GDK_PIXBUF_EXTRA_CFLAGS = @GDK_PIXBUF_EXTRA_CFLAGS@
+GDK_PIXBUF_EXTRA_LIBS = @GDK_PIXBUF_EXTRA_LIBS@
+GDK_PIXBUF_LINK_FLAGS = @GDK_PIXBUF_LINK_FLAGS@
+GDK_PIXBUF_MAJOR = @GDK_PIXBUF_MAJOR@
+GDK_PIXBUF_MICRO = @GDK_PIXBUF_MICRO@
+GDK_PIXBUF_MINOR = @GDK_PIXBUF_MINOR@
+GDK_PIXBUF_PACKAGES = @GDK_PIXBUF_PACKAGES@
+GDK_PIXBUF_VERSION = @GDK_PIXBUF_VERSION@
+GDK_PIXBUF_XLIB_DEP_CFLAGS = @GDK_PIXBUF_XLIB_DEP_CFLAGS@
+GDK_PIXBUF_XLIB_DEP_LIBS = @GDK_PIXBUF_XLIB_DEP_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_COMPILE_RESOURCES = @GLIB_COMPILE_RESOURCES@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GREP = @GREP@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+GTK_UPDATE_ICON_CACHE = @GTK_UPDATE_ICON_CACHE@
+HTML_DIR = @HTML_DIR@
+INCLUDED_LOADER_DEFINE = @INCLUDED_LOADER_DEFINE@
+INCLUDED_LOADER_OBJ = @INCLUDED_LOADER_OBJ@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
+INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
+INTROSPECTION_GENERATE = @INTROSPECTION_GENERATE@
+INTROSPECTION_GIRDIR = @INTROSPECTION_GIRDIR@
+INTROSPECTION_LIBS = @INTROSPECTION_LIBS@
+INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@
+INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@
+INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBJASPER = @LIBJASPER@
+LIBJPEG = @LIBJPEG@
+LIBOBJS = @LIBOBJS@
+LIBPNG = @LIBPNG@
+LIBS = @LIBS@
+LIBTIFF = @LIBTIFF@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_EXPORT_OPTIONS = @LIBTOOL_EXPORT_OPTIONS@
+LIB_EXE_MACHINE_FLAG = @LIB_EXE_MACHINE_FLAG@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+LT_CURRENT_MINUS_AGE = @LT_CURRENT_MINUS_AGE@
+LT_VERSION_INFO = @LT_VERSION_INFO@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MATH_LIB = @MATH_LIB@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PNG_DEP_CFLAGS_PACKAGES = @PNG_DEP_CFLAGS_PACKAGES@
+POSUB = @POSUB@
+RANLIB = @RANLIB@
+REBUILD = @REBUILD@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+WINDRES = @WINDRES@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+XSLTPROC = @XSLTPROC@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+ms_librarian = @ms_librarian@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+GTESTER = gtester              # in $PATH for non-GLIB packages
+GTESTER_REPORT = gtester-report                # in $PATH for non-GLIB packages
+
+# initialize variables for unconditional += appending
+EXTRA_DIST = gdk-pixbuf-csource.1 makefile.msc gdk-pixbuf.symbols \
+       abicheck.sh gdk_pixbuf.def gdk_pixbuf.rc gdk-pixbuf-marshal.c \
+       gdk-pixbuf-marshal.list gdk-pixbuf-enum-types.c.template \
+       gdk-pixbuf-enum-types.h.template gen-color-table.pl \
+       gdiplus.def
+TEST_PROGS = 
+
+### testing rules
+
+# Xvfb based test rules
+XVFB = Xvfb -ac -noreset -screen 0 800x600x16
+XIDS = 101 102 103 104 105 106 107 197 199 211 223 227 293 307 308 309 310 311 \
+   491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 \
+   991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 \
+  1008 1009 4703 4721 4723 4729 4733 4751 9973 9974 9975 9976 9977 9978 9979 \
+  9980 9981 9982 9983 9984 9985 9986 9987 9988 9989 9990 9991 9992 9993 9994 \
+  9995 9996 9997 9998 9999
+
+SKIP_GDKTARGET = \
+       test "$(gdktarget)" != "x11" \
+       && echo "Gtk+Tests:INFO: Skipping GUI tests for non-X11 target."
+
+XVFB_START = \
+       ${XVFB} -help 2>/dev/null 1>&2 \
+       && XID=`for id in $(XIDS) ; do test -e /tmp/.X$$id-lock || { echo $$id; exit 0; }; done; exit 1` \
+       && { ${XVFB} :$$XID -screen 0 800x600x16 -nolisten tcp -auth /dev/null >/dev/null 2>&1 & \
+              trap "kill -15 $$! " 0 HUP INT QUIT TRAP USR1 PIPE TERM ; } \
+       || { echo "Gtk+Tests:ERROR: Failed to start Xvfb environment for X11 target tests."; exit 1; } \
+       && DISPLAY=:$$XID && export DISPLAY
+
+INTROSPECTION_GIRS = $(am__append_1)
+SUBDIRS = pixops
+@PLATFORM_WIN32_TRUE@no_undefined = -no-undefined
+@OS_WIN32_TRUE@gdk_pixbuf_def = gdk_pixbuf.def
+@OS_WIN32_TRUE@gdk_pixbuf_symbols = -export-symbols $(srcdir)/gdk_pixbuf.def
+@OS_WIN32_TRUE@gdk_pixbuf_win32_res = gdk_pixbuf-win32-res.o
+@OS_WIN32_TRUE@gdk_pixbuf_win32_res_ldflag = -Wl,gdk_pixbuf-win32-res.o
+@OS_WIN32_TRUE@libole32 = -lole32
+@MS_LIB_AVAILABLE_TRUE@noinst_DATA = gdk_pixbuf-$(GDK_PIXBUF_API_VERSION).lib
+@OS_LINUX_TRUE@TESTS = abicheck.sh
+lib_LTLIBRARIES = libgdk_pixbuf-2.0.la
+loaderdir = $(libdir)/gdk-pixbuf-2.0/$(GDK_PIXBUF_BINARY_VERSION)/loaders
+module_libs = libgdk_pixbuf-$(GDK_PIXBUF_API_VERSION).la $(GDK_PIXBUF_DEP_LIBS)
+
+#
+# The PNG loader
+#
+libstatic_pixbufloader_png_la_SOURCES = io-png.c
+libpixbufloader_png_la_SOURCES = io-png.c
+libpixbufloader_png_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_png_la_LIBADD = $(LIBPNG) $(module_libs)
+
+#
+# The BMP loader
+#
+libstatic_pixbufloader_bmp_la_SOURCES = io-bmp.c
+libpixbufloader_bmp_la_SOURCES = io-bmp.c
+libpixbufloader_bmp_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_bmp_la_LIBADD = $(module_libs)
+
+#
+# The WBMP loader
+#
+libstatic_pixbufloader_wbmp_la_SOURCES = io-wbmp.c
+libpixbufloader_wbmp_la_SOURCES = io-wbmp.c
+libpixbufloader_wbmp_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_wbmp_la_LIBADD = $(module_libs)
+
+#
+# The GdkPixdata loader, always built in
+#
+libstatic_pixbufloader_pixdata_la_SOURCES = io-pixdata.c
+
+#
+# The GIF loader
+#
+libstatic_pixbufloader_gif_la_SOURCES = io-gif.c io-gif-animation.c io-gif-animation.h
+libpixbufloader_gif_la_SOURCES = io-gif.c io-gif-animation.c io-gif-animation.h
+libpixbufloader_gif_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_gif_la_LIBADD = $(module_libs)
+
+#
+# The ICO loader
+#
+libstatic_pixbufloader_ico_la_SOURCES = io-ico.c
+libpixbufloader_ico_la_SOURCES = io-ico.c
+libpixbufloader_ico_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_ico_la_LIBADD = $(module_libs)
+
+#
+# The ANI loader
+#
+libstatic_pixbufloader_ani_la_SOURCES = io-ani.c io-ani-animation.c io-ani-animation.h
+libpixbufloader_ani_la_SOURCES = io-ani.c io-ani-animation.c io-ani-animation.h
+libpixbufloader_ani_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_ani_la_LIBADD = $(module_libs)
+
+#
+# The JPEG loader
+#
+libstatic_pixbufloader_jpeg_la_SOURCES = io-jpeg.c
+libpixbufloader_jpeg_la_SOURCES = io-jpeg.c
+libpixbufloader_jpeg_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_jpeg_la_LIBADD = $(LIBJPEG) $(module_libs)
+
+#
+# The PNM loader
+#
+libstatic_pixbufloader_pnm_la_SOURCES = io-pnm.c
+libpixbufloader_pnm_la_SOURCES = io-pnm.c
+libpixbufloader_pnm_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_pnm_la_LIBADD = $(module_libs)
+
+#
+# The RAS loader
+#
+libstatic_pixbufloader_ras_la_SOURCES = io-ras.c
+libpixbufloader_ras_la_SOURCES = io-ras.c
+libpixbufloader_ras_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_ras_la_LIBADD = $(module_libs)
+
+#
+# The TIFF loader
+#
+libstatic_pixbufloader_tiff_la_SOURCES = io-tiff.c
+libpixbufloader_tiff_la_SOURCES = io-tiff.c
+libpixbufloader_tiff_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_tiff_la_LIBADD = $(LIBTIFF) $(module_libs)
+
+#
+# The XPM loader
+#
+libstatic_pixbufloader_xpm_la_SOURCES = io-xpm.c
+libpixbufloader_xpm_la_SOURCES = io-xpm.c
+libpixbufloader_xpm_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_xpm_la_LIBADD = $(module_libs)
+
+#
+# The XBM loader
+#
+libstatic_pixbufloader_xbm_la_SOURCES = io-xbm.c
+libpixbufloader_xbm_la_SOURCES = io-xbm.c
+libpixbufloader_xbm_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_xbm_la_LIBADD = $(module_libs)
+
+#
+# The TGA loader
+#
+libstatic_pixbufloader_tga_la_SOURCES = io-tga.c
+libpixbufloader_tga_la_SOURCES = io-tga.c
+libpixbufloader_tga_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_tga_la_LIBADD = $(module_libs)
+
+#
+# The .icns loader
+#
+libstatic_pixbufloader_icns_la_SOURCES = io-icns.c
+libpixbufloader_icns_la_SOURCES = io-icns.c
+libpixbufloader_icns_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_icns_la_LIBADD = $(module_libs)
+
+#
+# The PCX loader
+#
+libstatic_pixbufloader_pcx_la_SOURCES = io-pcx.c
+libpixbufloader_pcx_la_SOURCES = io-pcx.c
+libpixbufloader_pcx_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_pcx_la_LIBADD = $(module_libs)
+
+#
+# The JPEG2000 loader
+#
+libstatic_pixbufloader_jasper_la_SOURCES = io-jasper.c
+libpixbufloader_jasper_la_SOURCES = io-jasper.c
+libpixbufloader_jasper_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_jasper_la_LIBADD = $(LIBJASPER) $(module_libs)
+
+#
+# The QTIF loader
+#
+libstatic_pixbufloader_qtif_la_SOURCES = io-qtif.c
+libpixbufloader_qtif_la_SOURCES = io-qtif.c
+libpixbufloader_qtif_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_qtif_la_LIBADD = $(module_libs)
+
+# MinGW doesn't come with any import library for gdiplus.dll, so
+# create a partial one that's enough for our use.
+@BUILD_GDIPLUS_LOADERS_TRUE@libgdiplus = libgdiplus.dll.a
+@BUILD_GDIPLUS_LOADERS_TRUE@gdiplus_ldflag = -Wl,$(libgdiplus)
+
+# When building the GDI+ loader statically, we put the "common" objects
+# only in one of the archives to avoid duplicate definitions
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@STATIC_GDIPLUS_LIBS = \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@     libstatic-pixbufloader-gdip-ico.la \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@     libstatic-pixbufloader-gdip-wmf.la \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@     libstatic-pixbufloader-gdip-emf.la \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@     libstatic-pixbufloader-gdip-bmp.la \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@     libstatic-pixbufloader-gdip-gif.la \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@     libstatic-pixbufloader-gdip-jpeg.la \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@     libstatic-pixbufloader-gdip-tiff.la
+
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@libstatic_pixbufloader_gdip_ico_la_SOURCES = \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@     io-gdip-native.h                \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@     io-gdip-propertytags.h          \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@     io-gdip-utils.h                 \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@     io-gdip-utils.c                 \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@     io-gdip-animation.c             \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@     io-gdip-animation.h             \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@     io-gdip-ico.c
+
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@libstatic_pixbufloader_gdip_wmf_la_SOURCES = \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@     io-gdip-wmf.c
+
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@libstatic_pixbufloader_gdip_emf_la_SOURCES = \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@     io-gdip-emf.c
+
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@libstatic_pixbufloader_gdip_bmp_la_SOURCES = \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@     io-gdip-bmp.c
+
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@libstatic_pixbufloader_gdip_gif_la_SOURCES = \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@     io-gdip-gif.c
+
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@libstatic_pixbufloader_gdip_jpeg_la_SOURCES = \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@     io-gdip-jpeg.c
+
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@libstatic_pixbufloader_gdip_tiff_la_SOURCES = \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_TRUE@     io-gdip-tiff.c
+
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@GDIPLUS_LIBS = \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    libpixbufloader-gdip-ico.la \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    libpixbufloader-gdip-wmf.la \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    libpixbufloader-gdip-emf.la \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    libpixbufloader-gdip-bmp.la \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    libpixbufloader-gdip-gif.la \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    libpixbufloader-gdip-jpeg.la \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    libpixbufloader-gdip-tiff.la
+
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@libpixbufloader_gdip_ico_la_LDFLAGS = -avoid-version -module -no-undefined $(gdiplus_ldflag)
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@libpixbufloader_gdip_ico_la_SOURCES = \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-native.h                \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-propertytags.h          \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-utils.h                 \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-utils.c                 \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-animation.c             \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-animation.h             \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-ico.c
+
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@libpixbufloader_gdip_ico_la_LIBADD = $(module_libs) $(libole32)
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@libpixbufloader_gdip_wmf_la_LDFLAGS = -avoid-version -module -no-undefined $(gdiplus_ldflag)
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@libpixbufloader_gdip_wmf_la_SOURCES = \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-native.h                \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-propertytags.h          \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-utils.h                 \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-utils.c                 \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-animation.c             \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-animation.h             \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-wmf.c
+
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@libpixbufloader_gdip_wmf_la_LIBADD = $(module_libs) $(libole32)
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@libpixbufloader_gdip_emf_la_LDFLAGS = -avoid-version -module -no-undefined $(gdiplus_ldflag)
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@libpixbufloader_gdip_emf_la_SOURCES = \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-native.h                \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-propertytags.h          \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-utils.h                 \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-utils.c                 \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-animation.c             \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-animation.h             \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-emf.c
+
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@libpixbufloader_gdip_emf_la_LIBADD = $(module_libs) $(libole32)
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@libpixbufloader_gdip_bmp_la_LDFLAGS = -avoid-version -module -no-undefined $(gdiplus_ldflag)
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@libpixbufloader_gdip_bmp_la_SOURCES = \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-native.h                \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-propertytags.h          \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-utils.h                 \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-utils.c                 \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-animation.c             \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-animation.h             \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-bmp.c
+
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@libpixbufloader_gdip_bmp_la_LIBADD = $(module_libs) $(libole32)
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@libpixbufloader_gdip_gif_la_LDFLAGS = -avoid-version -module -no-undefined $(gdiplus_ldflag)
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@libpixbufloader_gdip_gif_la_SOURCES = \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-native.h                \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-propertytags.h          \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-utils.h                 \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-utils.c                 \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-animation.c             \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-animation.h             \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-gif.c
+
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@libpixbufloader_gdip_gif_la_LIBADD = $(module_libs) $(libole32)
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@libpixbufloader_gdip_jpeg_la_LDFLAGS = -avoid-version -module -no-undefined $(gdiplus_ldflag)
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@libpixbufloader_gdip_jpeg_la_SOURCES = \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-native.h                \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-propertytags.h          \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-utils.h                 \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-utils.c                 \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-animation.c             \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-animation.h             \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-jpeg.c
+
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@libpixbufloader_gdip_jpeg_la_LIBADD = $(module_libs) $(libole32)
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@libpixbufloader_gdip_tiff_la_LDFLAGS = -avoid-version -module -no-undefined $(gdiplus_ldflag)
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@libpixbufloader_gdip_tiff_la_SOURCES = \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-native.h                \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-propertytags.h          \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-utils.h                 \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-utils.c                 \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-animation.c             \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-animation.h             \
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@    io-gdip-tiff.c
+
+@BUILD_GDIPLUS_LOADERS_TRUE@@INCLUDE_GDIPLUS_FALSE@libpixbufloader_gdip_tiff_la_LIBADD = $(module_libs) $(libole32)
+
+# Loaders that aren't built if we build the GDI+ loader
+@BUILD_GDIPLUS_LOADERS_FALSE@@INCLUDE_BMP_TRUE@STATIC_BMP_LIB = libstatic-pixbufloader-bmp.la
+@BUILD_GDIPLUS_LOADERS_FALSE@@INCLUDE_BMP_FALSE@BMP_LIB = libpixbufloader-bmp.la
+@BUILD_GDIPLUS_LOADERS_FALSE@@INCLUDE_GIF_TRUE@STATIC_GIF_LIB = libstatic-pixbufloader-gif.la
+@BUILD_GDIPLUS_LOADERS_FALSE@@INCLUDE_GIF_FALSE@GIF_LIB = libpixbufloader-gif.la
+@BUILD_GDIPLUS_LOADERS_FALSE@@INCLUDE_ICO_TRUE@STATIC_ICO_LIB = libstatic-pixbufloader-ico.la
+@BUILD_GDIPLUS_LOADERS_FALSE@@INCLUDE_ICO_FALSE@ICO_LIB = libpixbufloader-ico.la
+@BUILD_GDIPLUS_LOADERS_FALSE@@HAVE_JPEG_TRUE@@INCLUDE_JPEG_TRUE@STATIC_JPEG_LIB = libstatic-pixbufloader-jpeg.la
+@BUILD_GDIPLUS_LOADERS_FALSE@@HAVE_JPEG_TRUE@@INCLUDE_JPEG_FALSE@JPEG_LIB = libpixbufloader-jpeg.la
+@BUILD_GDIPLUS_LOADERS_FALSE@@HAVE_TIFF_TRUE@@INCLUDE_TIFF_TRUE@STATIC_TIFF_LIB = libstatic-pixbufloader-tiff.la
+@BUILD_GDIPLUS_LOADERS_FALSE@@HAVE_TIFF_TRUE@@INCLUDE_TIFF_FALSE@TIFF_LIB = libpixbufloader-tiff.la
+
+# End of loaders not built if building GDI+ loader
+@HAVE_PNG_TRUE@@INCLUDE_PNG_TRUE@STATIC_PNG_LIB = libstatic-pixbufloader-png.la
+@HAVE_PNG_TRUE@@INCLUDE_PNG_FALSE@PNG_LIB = libpixbufloader-png.la
+@INCLUDE_WBMP_TRUE@STATIC_WBMP_LIB = libstatic-pixbufloader-wbmp.la
+@INCLUDE_WBMP_FALSE@WBMP_LIB = libpixbufloader-wbmp.la
+@INCLUDE_ANI_TRUE@STATIC_ANI_LIB = libstatic-pixbufloader-ani.la
+@INCLUDE_ANI_FALSE@ANI_LIB = libpixbufloader-ani.la
+@INCLUDE_PNM_TRUE@STATIC_PNM_LIB = libstatic-pixbufloader-pnm.la
+@INCLUDE_PNM_FALSE@PNM_LIB = libpixbufloader-pnm.la
+@INCLUDE_RAS_TRUE@STATIC_RAS_LIB = libstatic-pixbufloader-ras.la
+@INCLUDE_RAS_FALSE@RAS_LIB = libpixbufloader-ras.la
+@INCLUDE_XPM_TRUE@STATIC_XPM_LIB = libstatic-pixbufloader-xpm.la
+@INCLUDE_XPM_FALSE@XPM_LIB = libpixbufloader-xpm.la
+@INCLUDE_XBM_TRUE@STATIC_XBM_LIB = libstatic-pixbufloader-xbm.la
+@INCLUDE_XBM_FALSE@XBM_LIB = libpixbufloader-xbm.la
+@INCLUDE_TGA_TRUE@STATIC_TGA_LIB = libstatic-pixbufloader-tga.la
+@INCLUDE_TGA_FALSE@TGA_LIB = libpixbufloader-tga.la
+@INCLUDE_PCX_TRUE@STATIC_PCX_LIB = libstatic-pixbufloader-pcx.la
+@INCLUDE_PCX_FALSE@PCX_LIB = libpixbufloader-pcx.la
+@INCLUDE_ICNS_TRUE@STATIC_ICNS_LIB = libstatic-pixbufloader-icns.la
+@INCLUDE_ICNS_FALSE@ICNS_LIB = libpixbufloader-icns.la
+@HAVE_JASPER_TRUE@@INCLUDE_JASPER_TRUE@STATIC_JASPER_LIB = libstatic-pixbufloader-jasper.la
+@HAVE_JASPER_TRUE@@INCLUDE_JASPER_FALSE@JASPER_LIB = libpixbufloader-jasper.la
+@INCLUDE_QTIF_TRUE@STATIC_QTIF_LIB = libstatic-pixbufloader-qtif.la
+@INCLUDE_QTIF_FALSE@QTIF_LIB = libpixbufloader-qtif.la
+
+# Always included
+STATIC_PIXDATA_LIB = libstatic-pixbufloader-pixdata.la
+@BUILD_DYNAMIC_MODULES_TRUE@loader_LTLIBRARIES = \
+@BUILD_DYNAMIC_MODULES_TRUE@   $(PNG_LIB)      \
+@BUILD_DYNAMIC_MODULES_TRUE@   $(BMP_LIB)      \
+@BUILD_DYNAMIC_MODULES_TRUE@   $(WBMP_LIB)     \
+@BUILD_DYNAMIC_MODULES_TRUE@   $(GIF_LIB)      \
+@BUILD_DYNAMIC_MODULES_TRUE@   $(ICO_LIB)      \
+@BUILD_DYNAMIC_MODULES_TRUE@   $(ANI_LIB)      \
+@BUILD_DYNAMIC_MODULES_TRUE@   $(JPEG_LIB)     \
+@BUILD_DYNAMIC_MODULES_TRUE@   $(PNM_LIB)      \
+@BUILD_DYNAMIC_MODULES_TRUE@   $(RAS_LIB)      \
+@BUILD_DYNAMIC_MODULES_TRUE@   $(TIFF_LIB)     \
+@BUILD_DYNAMIC_MODULES_TRUE@   $(XPM_LIB)      \
+@BUILD_DYNAMIC_MODULES_TRUE@   $(XBM_LIB)      \
+@BUILD_DYNAMIC_MODULES_TRUE@   $(TGA_LIB)      \
+@BUILD_DYNAMIC_MODULES_TRUE@   $(ICNS_LIB)     \
+@BUILD_DYNAMIC_MODULES_TRUE@   $(PCX_LIB)      \
+@BUILD_DYNAMIC_MODULES_TRUE@   $(JASPER_LIB)   \
+@BUILD_DYNAMIC_MODULES_TRUE@   $(QTIF_LIB)     \
+@BUILD_DYNAMIC_MODULES_TRUE@   $(GDIPLUS_LIBS)
+
+noinst_LTLIBRARIES = \
+       $(STATIC_PIXDATA_LIB)   \
+       $(STATIC_PNG_LIB)       \
+       $(STATIC_BMP_LIB)       \
+       $(STATIC_WBMP_LIB)      \
+       $(STATIC_GIF_LIB)       \
+       $(STATIC_ICO_LIB)       \
+       $(STATIC_ANI_LIB)       \
+       $(STATIC_JPEG_LIB)      \
+       $(STATIC_PNM_LIB)       \
+       $(STATIC_RAS_LIB)       \
+       $(STATIC_TIFF_LIB)      \
+       $(STATIC_XPM_LIB)       \
+       $(STATIC_XBM_LIB)       \
+       $(STATIC_TGA_LIB)       \
+       $(STATIC_ICNS_LIB)      \
+       $(STATIC_PCX_LIB)       \
+       $(STATIC_JASPER_LIB)    \
+       $(STATIC_QTIF_LIB)      \
+       $(STATIC_GDIPLUS_LIBS)
+
+builtin_objs = @INCLUDED_LOADER_OBJ@ $(STATIC_PIXDATA_LIB)
+DEPS = libgdk_pixbuf-$(GDK_PIXBUF_API_VERSION).la
+INCLUDES = \
+       -DG_LOG_DOMAIN=\"GdkPixbuf\"                                    \
+       -DGDK_PIXBUF_COMPILATION                                        \
+       -I$(top_srcdir) -I$(top_builddir)                               \
+       -I$(top_srcdir)/gdk-pixbuf                                      \
+       -I$(top_builddir)/gdk-pixbuf                                    \
+       -DGDK_PIXBUF_LOCALEDIR=\"$(localedir)\"                         \
+       -DGDK_PIXBUF_LIBDIR=\"$(libdir)\"                               \
+       -DGDK_PIXBUF_BINARY_VERSION=\"$(GDK_PIXBUF_BINARY_VERSION)\"    \
+       -DGDK_PIXBUF_PREFIX=\"$(prefix)\"                               \
+       $(INCLUDED_LOADER_DEFINE)                                       \
+       $(GDK_PIXBUF_DEBUG_FLAGS)                                       \
+       $(GDK_PIXBUF_DEP_CFLAGS)                                        \
+       -DGDK_PIXBUF_ENABLE_BACKEND
+
+AM_CPPFLAGS = "-DPIXBUF_LIBDIR=\"$(loaderdir)\"" "-DBUILT_MODULES_DIR=\"$(srcdir)/.libs\""
+LDADDS = libgdk_pixbuf-$(GDK_PIXBUF_API_VERSION).la $(GDK_PIXBUF_DEP_LIBS)
+test_gdk_pixbuf_LDADD = $(LDADDS)
+gdk_pixbuf_csource_SOURCES = gdk-pixbuf-csource.c
+gdk_pixbuf_csource_LDADD = $(LDADDS)
+gdk_pixbuf_pixdata_SOURCES = gdk-pixbuf-pixdata.c
+gdk_pixbuf_pixdata_LDADD = $(LDADDS)
+gdk_pixbuf_query_loaders_DEPENDENCIES = $(DEPS)
+gdk_pixbuf_query_loaders_LDADD = $(LDADDS)
+gdk_pixbuf_query_loaders_SOURCES = queryloaders.c
+
+#
+# The GdkPixBuf library
+#
+libgdk_pixbufincludedir = $(includedir)/gdk-pixbuf-2.0/gdk-pixbuf
+libgdk_pixbuf_2_0_la_SOURCES = \
+       gdk-pixbuf-i18n.h        \
+       gdk-pixbuf.c             \
+       gdk-pixbuf-animation.c   \
+       gdk-pixbuf-data.c        \
+       gdk-pixbuf-io.c          \
+       gdk-pixbuf-loader.c      \
+       gdk-pixbuf-scale.c       \
+       gdk-pixbuf-simple-anim.c \
+       gdk-pixbuf-scaled-anim.c \
+       gdk-pixbuf-util.c        \
+       gdk-pixdata.c            \
+       gdk-pixbuf-enum-types.c
+
+libgdk_pixbuf_2_0_la_LDFLAGS = \
+       $(GDK_PIXBUF_LINK_FLAGS)                \
+       $(gdk_pixbuf_win32_res_ldflag)          \
+       -version-info $(LT_VERSION_INFO)        \
+       $(LIBTOOL_EXPORT_OPTIONS)               \
+       $(no_undefined)                         \
+       $(gdk_pixbuf_symbols)                   \
+       $(gdiplus_ldflag)
+
+libgdk_pixbuf_2_0_la_LIBADD = pixops/libpixops.la $(builtin_objs) $(GDK_PIXBUF_DEP_LIBS) $(libole32)
+libgdk_pixbuf_2_0_la_DEPENDENCIES = pixops/libpixops.la $(builtin_objs) $(gdk_pixbuf_def) $(gdk_pixbuf_win32_res) $(libgdiplus)
+gdk_pixbuf_headers = \
+       gdk-pixbuf.h                    \
+       gdk-pixbuf-core.h               \
+       gdk-pixbuf-transform.h          \
+       gdk-pixbuf-io.h                 \
+       gdk-pixbuf-animation.h          \
+       gdk-pixbuf-simple-anim.h        \
+       gdk-pixbuf-loader.h
+
+libgdk_pixbufinclude_HEADERS = \
+       $(gdk_pixbuf_headers)           \
+       gdk-pixbuf-enum-types.h         \
+       gdk-pixbuf-marshal.h            \
+       gdk-pixbuf-features.h           \
+       gdk-pixdata.h
+
+noinst_HEADERS = \
+       gdk-pixbuf-private.h    \
+       gdk-pixbuf-scaled-anim.h \
+       xpm-color-table.h
+
+BUILT_SOURCES = \
+       gdk-pixbuf-enum-types.h \
+       gdk-pixbuf-enum-types.c \
+       gdk-pixbuf-marshal.h    \
+       gdk-pixbuf-marshal.c    \
+       gdk-pixbuf-features.h
+
+CLEANFILES = tmp-gdk-pixbuf-enum-types.h xgen-gmh xgen-gmc \
+       $(am__append_2)
+MAINTAINERCLEANFILES = gdk-pixbuf-enum-types.h gdk-pixbuf-enum-types.c \
+       gdk-pixbuf-marshal.h gdk-pixbuf-marshal.c loaders.cache \
+       s-enum-types-h stamp-gdk-pixbuf-marshal.h
+@HAVE_INTROSPECTION_TRUE@GdkPixbuf_2_0_gir_SCANNERFLAGS = --warn-all --strip-prefix=Gdk --c-include="gdk-pixbuf/gdk-pixbuf.h"
+@HAVE_INTROSPECTION_TRUE@GdkPixbuf_2_0_gir_EXPORT_PACKAGES = gdk-pixbuf-2.0
+@HAVE_INTROSPECTION_TRUE@GdkPixbuf_2_0_gir_INCLUDES = GModule-2.0 Gio-2.0
+@HAVE_INTROSPECTION_TRUE@GdkPixbuf_2_0_gir_LIBS = libgdk_pixbuf-2.0.la
+@HAVE_INTROSPECTION_TRUE@GdkPixbuf_2_0_gir_CFLAGS = \
+@HAVE_INTROSPECTION_TRUE@      -DGDK_PIXBUF_COMPILATION                                        \
+@HAVE_INTROSPECTION_TRUE@      -I$(top_builddir) -I$(top_srcdir)                               \
+@HAVE_INTROSPECTION_TRUE@      -I$(top_srcdir)/gdk-pixbuf                                      \
+@HAVE_INTROSPECTION_TRUE@      -I$(top_builddir)/gdk-pixbuf                                    \
+@HAVE_INTROSPECTION_TRUE@      $(GDK_PIXBUF_DEP_CFLAGS)
+
+@HAVE_INTROSPECTION_TRUE@GdkPixbuf_2_0_gir_FILES = \
+@HAVE_INTROSPECTION_TRUE@    $(libgdk_pixbufinclude_HEADERS) \
+@HAVE_INTROSPECTION_TRUE@    $(libgdk_pixbuf_2_0_la_SOURCES)
+
+@HAVE_INTROSPECTION_TRUE@girdir = $(datadir)/gir-1.0
+@HAVE_INTROSPECTION_TRUE@gir_DATA = $(INTROSPECTION_GIRS)
+@HAVE_INTROSPECTION_TRUE@typelibsdir = $(libdir)/girepository-1.0
+@HAVE_INTROSPECTION_TRUE@typelibs_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
+@CROSS_COMPILING_FALSE@RUN_QUERY_LOADER_TEST = test -z "$(DESTDIR)"
+@CROSS_COMPILING_TRUE@RUN_QUERY_LOADER_TEST = false
+all: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/Makefile.decl $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+               && { if test -f $@; then exit 0; else break; fi; }; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign gdk-pixbuf/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --foreign gdk-pixbuf/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+$(top_srcdir)/Makefile.decl:
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+gdk_pixbuf.rc: $(top_builddir)/config.status $(srcdir)/gdk_pixbuf.rc.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+gdk-pixbuf-features.h: $(top_builddir)/config.status $(srcdir)/gdk-pixbuf-features.h.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+       @$(NORMAL_INSTALL)
+       test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
+       @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+       list2=; for p in $$list; do \
+         if test -f $$p; then \
+           list2="$$list2 $$p"; \
+         else :; fi; \
+       done; \
+       test -z "$$list2" || { \
+         echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+         $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+       }
+
+uninstall-libLTLIBRARIES:
+       @$(NORMAL_UNINSTALL)
+       @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+       for p in $$list; do \
+         $(am__strip_dir) \
+         echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+         $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+       done
+
+clean-libLTLIBRARIES:
+       -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+       @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+         dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+         test "$$dir" != "$$p" || dir=.; \
+         echo "rm -f \"$${dir}/so_locations\""; \
+         rm -f "$${dir}/so_locations"; \
+       done
+install-loaderLTLIBRARIES: $(loader_LTLIBRARIES)
+       @$(NORMAL_INSTALL)
+       test -z "$(loaderdir)" || $(MKDIR_P) "$(DESTDIR)$(loaderdir)"
+       @list='$(loader_LTLIBRARIES)'; test -n "$(loaderdir)" || list=; \
+       list2=; for p in $$list; do \
+         if test -f $$p; then \
+           list2="$$list2 $$p"; \
+         else :; fi; \
+       done; \
+       test -z "$$list2" || { \
+         echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(loaderdir)'"; \
+         $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(loaderdir)"; \
+       }
+
+uninstall-loaderLTLIBRARIES:
+       @$(NORMAL_UNINSTALL)
+       @list='$(loader_LTLIBRARIES)'; test -n "$(loaderdir)" || list=; \
+       for p in $$list; do \
+         $(am__strip_dir) \
+         echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(loaderdir)/$$f'"; \
+         $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(loaderdir)/$$f"; \
+       done
+
+clean-loaderLTLIBRARIES:
+       -test -z "$(loader_LTLIBRARIES)" || rm -f $(loader_LTLIBRARIES)
+       @list='$(loader_LTLIBRARIES)'; for p in $$list; do \
+         dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+         test "$$dir" != "$$p" || dir=.; \
+         echo "rm -f \"$${dir}/so_locations\""; \
+         rm -f "$${dir}/so_locations"; \
+       done
+
+clean-noinstLTLIBRARIES:
+       -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+       @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+         dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+         test "$$dir" != "$$p" || dir=.; \
+         echo "rm -f \"$${dir}/so_locations\""; \
+         rm -f "$${dir}/so_locations"; \
+       done
+libgdk_pixbuf-2.0.la: $(libgdk_pixbuf_2_0_la_OBJECTS) $(libgdk_pixbuf_2_0_la_DEPENDENCIES) $(EXTRA_libgdk_pixbuf_2_0_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(libgdk_pixbuf_2_0_la_LINK) -rpath $(libdir) $(libgdk_pixbuf_2_0_la_OBJECTS) $(libgdk_pixbuf_2_0_la_LIBADD) $(LIBS)
+libpixbufloader-ani.la: $(libpixbufloader_ani_la_OBJECTS) $(libpixbufloader_ani_la_DEPENDENCIES) $(EXTRA_libpixbufloader_ani_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(libpixbufloader_ani_la_LINK) $(am_libpixbufloader_ani_la_rpath) $(libpixbufloader_ani_la_OBJECTS) $(libpixbufloader_ani_la_LIBADD) $(LIBS)
+libpixbufloader-bmp.la: $(libpixbufloader_bmp_la_OBJECTS) $(libpixbufloader_bmp_la_DEPENDENCIES) $(EXTRA_libpixbufloader_bmp_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(libpixbufloader_bmp_la_LINK) $(am_libpixbufloader_bmp_la_rpath) $(libpixbufloader_bmp_la_OBJECTS) $(libpixbufloader_bmp_la_LIBADD) $(LIBS)
+libpixbufloader-gdip-bmp.la: $(libpixbufloader_gdip_bmp_la_OBJECTS) $(libpixbufloader_gdip_bmp_la_DEPENDENCIES) $(EXTRA_libpixbufloader_gdip_bmp_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(libpixbufloader_gdip_bmp_la_LINK) $(am_libpixbufloader_gdip_bmp_la_rpath) $(libpixbufloader_gdip_bmp_la_OBJECTS) $(libpixbufloader_gdip_bmp_la_LIBADD) $(LIBS)
+libpixbufloader-gdip-emf.la: $(libpixbufloader_gdip_emf_la_OBJECTS) $(libpixbufloader_gdip_emf_la_DEPENDENCIES) $(EXTRA_libpixbufloader_gdip_emf_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(libpixbufloader_gdip_emf_la_LINK) $(am_libpixbufloader_gdip_emf_la_rpath) $(libpixbufloader_gdip_emf_la_OBJECTS) $(libpixbufloader_gdip_emf_la_LIBADD) $(LIBS)
+libpixbufloader-gdip-gif.la: $(libpixbufloader_gdip_gif_la_OBJECTS) $(libpixbufloader_gdip_gif_la_DEPENDENCIES) $(EXTRA_libpixbufloader_gdip_gif_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(libpixbufloader_gdip_gif_la_LINK) $(am_libpixbufloader_gdip_gif_la_rpath) $(libpixbufloader_gdip_gif_la_OBJECTS) $(libpixbufloader_gdip_gif_la_LIBADD) $(LIBS)
+libpixbufloader-gdip-ico.la: $(libpixbufloader_gdip_ico_la_OBJECTS) $(libpixbufloader_gdip_ico_la_DEPENDENCIES) $(EXTRA_libpixbufloader_gdip_ico_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(libpixbufloader_gdip_ico_la_LINK) $(am_libpixbufloader_gdip_ico_la_rpath) $(libpixbufloader_gdip_ico_la_OBJECTS) $(libpixbufloader_gdip_ico_la_LIBADD) $(LIBS)
+libpixbufloader-gdip-jpeg.la: $(libpixbufloader_gdip_jpeg_la_OBJECTS) $(libpixbufloader_gdip_jpeg_la_DEPENDENCIES) $(EXTRA_libpixbufloader_gdip_jpeg_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(libpixbufloader_gdip_jpeg_la_LINK) $(am_libpixbufloader_gdip_jpeg_la_rpath) $(libpixbufloader_gdip_jpeg_la_OBJECTS) $(libpixbufloader_gdip_jpeg_la_LIBADD) $(LIBS)
+libpixbufloader-gdip-tiff.la: $(libpixbufloader_gdip_tiff_la_OBJECTS) $(libpixbufloader_gdip_tiff_la_DEPENDENCIES) $(EXTRA_libpixbufloader_gdip_tiff_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(libpixbufloader_gdip_tiff_la_LINK) $(am_libpixbufloader_gdip_tiff_la_rpath) $(libpixbufloader_gdip_tiff_la_OBJECTS) $(libpixbufloader_gdip_tiff_la_LIBADD) $(LIBS)
+libpixbufloader-gdip-wmf.la: $(libpixbufloader_gdip_wmf_la_OBJECTS) $(libpixbufloader_gdip_wmf_la_DEPENDENCIES) $(EXTRA_libpixbufloader_gdip_wmf_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(libpixbufloader_gdip_wmf_la_LINK) $(am_libpixbufloader_gdip_wmf_la_rpath) $(libpixbufloader_gdip_wmf_la_OBJECTS) $(libpixbufloader_gdip_wmf_la_LIBADD) $(LIBS)
+libpixbufloader-gif.la: $(libpixbufloader_gif_la_OBJECTS) $(libpixbufloader_gif_la_DEPENDENCIES) $(EXTRA_libpixbufloader_gif_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(libpixbufloader_gif_la_LINK) $(am_libpixbufloader_gif_la_rpath) $(libpixbufloader_gif_la_OBJECTS) $(libpixbufloader_gif_la_LIBADD) $(LIBS)
+libpixbufloader-icns.la: $(libpixbufloader_icns_la_OBJECTS) $(libpixbufloader_icns_la_DEPENDENCIES) $(EXTRA_libpixbufloader_icns_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(libpixbufloader_icns_la_LINK) $(am_libpixbufloader_icns_la_rpath) $(libpixbufloader_icns_la_OBJECTS) $(libpixbufloader_icns_la_LIBADD) $(LIBS)
+libpixbufloader-ico.la: $(libpixbufloader_ico_la_OBJECTS) $(libpixbufloader_ico_la_DEPENDENCIES) $(EXTRA_libpixbufloader_ico_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(libpixbufloader_ico_la_LINK) $(am_libpixbufloader_ico_la_rpath) $(libpixbufloader_ico_la_OBJECTS) $(libpixbufloader_ico_la_LIBADD) $(LIBS)
+libpixbufloader-jasper.la: $(libpixbufloader_jasper_la_OBJECTS) $(libpixbufloader_jasper_la_DEPENDENCIES) $(EXTRA_libpixbufloader_jasper_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(libpixbufloader_jasper_la_LINK) $(am_libpixbufloader_jasper_la_rpath) $(libpixbufloader_jasper_la_OBJECTS) $(libpixbufloader_jasper_la_LIBADD) $(LIBS)
+libpixbufloader-jpeg.la: $(libpixbufloader_jpeg_la_OBJECTS) $(libpixbufloader_jpeg_la_DEPENDENCIES) $(EXTRA_libpixbufloader_jpeg_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(libpixbufloader_jpeg_la_LINK) $(am_libpixbufloader_jpeg_la_rpath) $(libpixbufloader_jpeg_la_OBJECTS) $(libpixbufloader_jpeg_la_LIBADD) $(LIBS)
+libpixbufloader-pcx.la: $(libpixbufloader_pcx_la_OBJECTS) $(libpixbufloader_pcx_la_DEPENDENCIES) $(EXTRA_libpixbufloader_pcx_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(libpixbufloader_pcx_la_LINK) $(am_libpixbufloader_pcx_la_rpath) $(libpixbufloader_pcx_la_OBJECTS) $(libpixbufloader_pcx_la_LIBADD) $(LIBS)
+libpixbufloader-png.la: $(libpixbufloader_png_la_OBJECTS) $(libpixbufloader_png_la_DEPENDENCIES) $(EXTRA_libpixbufloader_png_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(libpixbufloader_png_la_LINK) $(am_libpixbufloader_png_la_rpath) $(libpixbufloader_png_la_OBJECTS) $(libpixbufloader_png_la_LIBADD) $(LIBS)
+libpixbufloader-pnm.la: $(libpixbufloader_pnm_la_OBJECTS) $(libpixbufloader_pnm_la_DEPENDENCIES) $(EXTRA_libpixbufloader_pnm_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(libpixbufloader_pnm_la_LINK) $(am_libpixbufloader_pnm_la_rpath) $(libpixbufloader_pnm_la_OBJECTS) $(libpixbufloader_pnm_la_LIBADD) $(LIBS)
+libpixbufloader-qtif.la: $(libpixbufloader_qtif_la_OBJECTS) $(libpixbufloader_qtif_la_DEPENDENCIES) $(EXTRA_libpixbufloader_qtif_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(libpixbufloader_qtif_la_LINK) $(am_libpixbufloader_qtif_la_rpath) $(libpixbufloader_qtif_la_OBJECTS) $(libpixbufloader_qtif_la_LIBADD) $(LIBS)
+libpixbufloader-ras.la: $(libpixbufloader_ras_la_OBJECTS) $(libpixbufloader_ras_la_DEPENDENCIES) $(EXTRA_libpixbufloader_ras_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(libpixbufloader_ras_la_LINK) $(am_libpixbufloader_ras_la_rpath) $(libpixbufloader_ras_la_OBJECTS) $(libpixbufloader_ras_la_LIBADD) $(LIBS)
+libpixbufloader-tga.la: $(libpixbufloader_tga_la_OBJECTS) $(libpixbufloader_tga_la_DEPENDENCIES) $(EXTRA_libpixbufloader_tga_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(libpixbufloader_tga_la_LINK) $(am_libpixbufloader_tga_la_rpath) $(libpixbufloader_tga_la_OBJECTS) $(libpixbufloader_tga_la_LIBADD) $(LIBS)
+libpixbufloader-tiff.la: $(libpixbufloader_tiff_la_OBJECTS) $(libpixbufloader_tiff_la_DEPENDENCIES) $(EXTRA_libpixbufloader_tiff_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(libpixbufloader_tiff_la_LINK) $(am_libpixbufloader_tiff_la_rpath) $(libpixbufloader_tiff_la_OBJECTS) $(libpixbufloader_tiff_la_LIBADD) $(LIBS)
+libpixbufloader-wbmp.la: $(libpixbufloader_wbmp_la_OBJECTS) $(libpixbufloader_wbmp_la_DEPENDENCIES) $(EXTRA_libpixbufloader_wbmp_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(libpixbufloader_wbmp_la_LINK) $(am_libpixbufloader_wbmp_la_rpath) $(libpixbufloader_wbmp_la_OBJECTS) $(libpixbufloader_wbmp_la_LIBADD) $(LIBS)
+libpixbufloader-xbm.la: $(libpixbufloader_xbm_la_OBJECTS) $(libpixbufloader_xbm_la_DEPENDENCIES) $(EXTRA_libpixbufloader_xbm_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(libpixbufloader_xbm_la_LINK) $(am_libpixbufloader_xbm_la_rpath) $(libpixbufloader_xbm_la_OBJECTS) $(libpixbufloader_xbm_la_LIBADD) $(LIBS)
+libpixbufloader-xpm.la: $(libpixbufloader_xpm_la_OBJECTS) $(libpixbufloader_xpm_la_DEPENDENCIES) $(EXTRA_libpixbufloader_xpm_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(libpixbufloader_xpm_la_LINK) $(am_libpixbufloader_xpm_la_rpath) $(libpixbufloader_xpm_la_OBJECTS) $(libpixbufloader_xpm_la_LIBADD) $(LIBS)
+libstatic-pixbufloader-ani.la: $(libstatic_pixbufloader_ani_la_OBJECTS) $(libstatic_pixbufloader_ani_la_DEPENDENCIES) $(EXTRA_libstatic_pixbufloader_ani_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) $(am_libstatic_pixbufloader_ani_la_rpath) $(libstatic_pixbufloader_ani_la_OBJECTS) $(libstatic_pixbufloader_ani_la_LIBADD) $(LIBS)
+libstatic-pixbufloader-bmp.la: $(libstatic_pixbufloader_bmp_la_OBJECTS) $(libstatic_pixbufloader_bmp_la_DEPENDENCIES) $(EXTRA_libstatic_pixbufloader_bmp_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) $(am_libstatic_pixbufloader_bmp_la_rpath) $(libstatic_pixbufloader_bmp_la_OBJECTS) $(libstatic_pixbufloader_bmp_la_LIBADD) $(LIBS)
+libstatic-pixbufloader-gdip-bmp.la: $(libstatic_pixbufloader_gdip_bmp_la_OBJECTS) $(libstatic_pixbufloader_gdip_bmp_la_DEPENDENCIES) $(EXTRA_libstatic_pixbufloader_gdip_bmp_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) $(am_libstatic_pixbufloader_gdip_bmp_la_rpath) $(libstatic_pixbufloader_gdip_bmp_la_OBJECTS) $(libstatic_pixbufloader_gdip_bmp_la_LIBADD) $(LIBS)
+libstatic-pixbufloader-gdip-emf.la: $(libstatic_pixbufloader_gdip_emf_la_OBJECTS) $(libstatic_pixbufloader_gdip_emf_la_DEPENDENCIES) $(EXTRA_libstatic_pixbufloader_gdip_emf_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) $(am_libstatic_pixbufloader_gdip_emf_la_rpath) $(libstatic_pixbufloader_gdip_emf_la_OBJECTS) $(libstatic_pixbufloader_gdip_emf_la_LIBADD) $(LIBS)
+libstatic-pixbufloader-gdip-gif.la: $(libstatic_pixbufloader_gdip_gif_la_OBJECTS) $(libstatic_pixbufloader_gdip_gif_la_DEPENDENCIES) $(EXTRA_libstatic_pixbufloader_gdip_gif_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) $(am_libstatic_pixbufloader_gdip_gif_la_rpath) $(libstatic_pixbufloader_gdip_gif_la_OBJECTS) $(libstatic_pixbufloader_gdip_gif_la_LIBADD) $(LIBS)
+libstatic-pixbufloader-gdip-ico.la: $(libstatic_pixbufloader_gdip_ico_la_OBJECTS) $(libstatic_pixbufloader_gdip_ico_la_DEPENDENCIES) $(EXTRA_libstatic_pixbufloader_gdip_ico_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) $(am_libstatic_pixbufloader_gdip_ico_la_rpath) $(libstatic_pixbufloader_gdip_ico_la_OBJECTS) $(libstatic_pixbufloader_gdip_ico_la_LIBADD) $(LIBS)
+libstatic-pixbufloader-gdip-jpeg.la: $(libstatic_pixbufloader_gdip_jpeg_la_OBJECTS) $(libstatic_pixbufloader_gdip_jpeg_la_DEPENDENCIES) $(EXTRA_libstatic_pixbufloader_gdip_jpeg_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) $(am_libstatic_pixbufloader_gdip_jpeg_la_rpath) $(libstatic_pixbufloader_gdip_jpeg_la_OBJECTS) $(libstatic_pixbufloader_gdip_jpeg_la_LIBADD) $(LIBS)
+libstatic-pixbufloader-gdip-tiff.la: $(libstatic_pixbufloader_gdip_tiff_la_OBJECTS) $(libstatic_pixbufloader_gdip_tiff_la_DEPENDENCIES) $(EXTRA_libstatic_pixbufloader_gdip_tiff_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) $(am_libstatic_pixbufloader_gdip_tiff_la_rpath) $(libstatic_pixbufloader_gdip_tiff_la_OBJECTS) $(libstatic_pixbufloader_gdip_tiff_la_LIBADD) $(LIBS)
+libstatic-pixbufloader-gdip-wmf.la: $(libstatic_pixbufloader_gdip_wmf_la_OBJECTS) $(libstatic_pixbufloader_gdip_wmf_la_DEPENDENCIES) $(EXTRA_libstatic_pixbufloader_gdip_wmf_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) $(am_libstatic_pixbufloader_gdip_wmf_la_rpath) $(libstatic_pixbufloader_gdip_wmf_la_OBJECTS) $(libstatic_pixbufloader_gdip_wmf_la_LIBADD) $(LIBS)
+libstatic-pixbufloader-gif.la: $(libstatic_pixbufloader_gif_la_OBJECTS) $(libstatic_pixbufloader_gif_la_DEPENDENCIES) $(EXTRA_libstatic_pixbufloader_gif_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) $(am_libstatic_pixbufloader_gif_la_rpath) $(libstatic_pixbufloader_gif_la_OBJECTS) $(libstatic_pixbufloader_gif_la_LIBADD) $(LIBS)
+libstatic-pixbufloader-icns.la: $(libstatic_pixbufloader_icns_la_OBJECTS) $(libstatic_pixbufloader_icns_la_DEPENDENCIES) $(EXTRA_libstatic_pixbufloader_icns_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) $(am_libstatic_pixbufloader_icns_la_rpath) $(libstatic_pixbufloader_icns_la_OBJECTS) $(libstatic_pixbufloader_icns_la_LIBADD) $(LIBS)
+libstatic-pixbufloader-ico.la: $(libstatic_pixbufloader_ico_la_OBJECTS) $(libstatic_pixbufloader_ico_la_DEPENDENCIES) $(EXTRA_libstatic_pixbufloader_ico_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) $(am_libstatic_pixbufloader_ico_la_rpath) $(libstatic_pixbufloader_ico_la_OBJECTS) $(libstatic_pixbufloader_ico_la_LIBADD) $(LIBS)
+libstatic-pixbufloader-jasper.la: $(libstatic_pixbufloader_jasper_la_OBJECTS) $(libstatic_pixbufloader_jasper_la_DEPENDENCIES) $(EXTRA_libstatic_pixbufloader_jasper_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) $(am_libstatic_pixbufloader_jasper_la_rpath) $(libstatic_pixbufloader_jasper_la_OBJECTS) $(libstatic_pixbufloader_jasper_la_LIBADD) $(LIBS)
+libstatic-pixbufloader-jpeg.la: $(libstatic_pixbufloader_jpeg_la_OBJECTS) $(libstatic_pixbufloader_jpeg_la_DEPENDENCIES) $(EXTRA_libstatic_pixbufloader_jpeg_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) $(am_libstatic_pixbufloader_jpeg_la_rpath) $(libstatic_pixbufloader_jpeg_la_OBJECTS) $(libstatic_pixbufloader_jpeg_la_LIBADD) $(LIBS)
+libstatic-pixbufloader-pcx.la: $(libstatic_pixbufloader_pcx_la_OBJECTS) $(libstatic_pixbufloader_pcx_la_DEPENDENCIES) $(EXTRA_libstatic_pixbufloader_pcx_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) $(am_libstatic_pixbufloader_pcx_la_rpath) $(libstatic_pixbufloader_pcx_la_OBJECTS) $(libstatic_pixbufloader_pcx_la_LIBADD) $(LIBS)
+libstatic-pixbufloader-pixdata.la: $(libstatic_pixbufloader_pixdata_la_OBJECTS) $(libstatic_pixbufloader_pixdata_la_DEPENDENCIES) $(EXTRA_libstatic_pixbufloader_pixdata_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK)  $(libstatic_pixbufloader_pixdata_la_OBJECTS) $(libstatic_pixbufloader_pixdata_la_LIBADD) $(LIBS)
+libstatic-pixbufloader-png.la: $(libstatic_pixbufloader_png_la_OBJECTS) $(libstatic_pixbufloader_png_la_DEPENDENCIES) $(EXTRA_libstatic_pixbufloader_png_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) $(am_libstatic_pixbufloader_png_la_rpath) $(libstatic_pixbufloader_png_la_OBJECTS) $(libstatic_pixbufloader_png_la_LIBADD) $(LIBS)
+libstatic-pixbufloader-pnm.la: $(libstatic_pixbufloader_pnm_la_OBJECTS) $(libstatic_pixbufloader_pnm_la_DEPENDENCIES) $(EXTRA_libstatic_pixbufloader_pnm_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) $(am_libstatic_pixbufloader_pnm_la_rpath) $(libstatic_pixbufloader_pnm_la_OBJECTS) $(libstatic_pixbufloader_pnm_la_LIBADD) $(LIBS)
+libstatic-pixbufloader-qtif.la: $(libstatic_pixbufloader_qtif_la_OBJECTS) $(libstatic_pixbufloader_qtif_la_DEPENDENCIES) $(EXTRA_libstatic_pixbufloader_qtif_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) $(am_libstatic_pixbufloader_qtif_la_rpath) $(libstatic_pixbufloader_qtif_la_OBJECTS) $(libstatic_pixbufloader_qtif_la_LIBADD) $(LIBS)
+libstatic-pixbufloader-ras.la: $(libstatic_pixbufloader_ras_la_OBJECTS) $(libstatic_pixbufloader_ras_la_DEPENDENCIES) $(EXTRA_libstatic_pixbufloader_ras_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) $(am_libstatic_pixbufloader_ras_la_rpath) $(libstatic_pixbufloader_ras_la_OBJECTS) $(libstatic_pixbufloader_ras_la_LIBADD) $(LIBS)
+libstatic-pixbufloader-tga.la: $(libstatic_pixbufloader_tga_la_OBJECTS) $(libstatic_pixbufloader_tga_la_DEPENDENCIES) $(EXTRA_libstatic_pixbufloader_tga_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) $(am_libstatic_pixbufloader_tga_la_rpath) $(libstatic_pixbufloader_tga_la_OBJECTS) $(libstatic_pixbufloader_tga_la_LIBADD) $(LIBS)
+libstatic-pixbufloader-tiff.la: $(libstatic_pixbufloader_tiff_la_OBJECTS) $(libstatic_pixbufloader_tiff_la_DEPENDENCIES) $(EXTRA_libstatic_pixbufloader_tiff_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) $(am_libstatic_pixbufloader_tiff_la_rpath) $(libstatic_pixbufloader_tiff_la_OBJECTS) $(libstatic_pixbufloader_tiff_la_LIBADD) $(LIBS)
+libstatic-pixbufloader-wbmp.la: $(libstatic_pixbufloader_wbmp_la_OBJECTS) $(libstatic_pixbufloader_wbmp_la_DEPENDENCIES) $(EXTRA_libstatic_pixbufloader_wbmp_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) $(am_libstatic_pixbufloader_wbmp_la_rpath) $(libstatic_pixbufloader_wbmp_la_OBJECTS) $(libstatic_pixbufloader_wbmp_la_LIBADD) $(LIBS)
+libstatic-pixbufloader-xbm.la: $(libstatic_pixbufloader_xbm_la_OBJECTS) $(libstatic_pixbufloader_xbm_la_DEPENDENCIES) $(EXTRA_libstatic_pixbufloader_xbm_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) $(am_libstatic_pixbufloader_xbm_la_rpath) $(libstatic_pixbufloader_xbm_la_OBJECTS) $(libstatic_pixbufloader_xbm_la_LIBADD) $(LIBS)
+libstatic-pixbufloader-xpm.la: $(libstatic_pixbufloader_xpm_la_OBJECTS) $(libstatic_pixbufloader_xpm_la_DEPENDENCIES) $(EXTRA_libstatic_pixbufloader_xpm_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) $(am_libstatic_pixbufloader_xpm_la_rpath) $(libstatic_pixbufloader_xpm_la_OBJECTS) $(libstatic_pixbufloader_xpm_la_LIBADD) $(LIBS)
+install-binPROGRAMS: $(bin_PROGRAMS)
+       @$(NORMAL_INSTALL)
+       test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+       @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+       for p in $$list; do echo "$$p $$p"; done | \
+       sed 's/$(EXEEXT)$$//' | \
+       while read p p1; do if test -f $$p || test -f $$p1; \
+         then echo "$$p"; echo "$$p"; else :; fi; \
+       done | \
+       sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
+           -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+       sed 'N;N;N;s,\n, ,g' | \
+       $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+         { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+           if ($$2 == $$4) files[d] = files[d] " " $$1; \
+           else { print "f", $$3 "/" $$4, $$1; } } \
+         END { for (d in files) print "f", d, files[d] }' | \
+       while read type dir files; do \
+           if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+           test -z "$$files" || { \
+           echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+           $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+           } \
+       ; done
+
+uninstall-binPROGRAMS:
+       @$(NORMAL_UNINSTALL)
+       @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+       files=`for p in $$list; do echo "$$p"; done | \
+         sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+             -e 's/$$/$(EXEEXT)/' `; \
+       test -n "$$list" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+       @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+       echo " rm -f" $$list; \
+       rm -f $$list || exit $$?; \
+       test -n "$(EXEEXT)" || exit 0; \
+       list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+       echo " rm -f" $$list; \
+       rm -f $$list
+
+clean-noinstPROGRAMS:
+       @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+       echo " rm -f" $$list; \
+       rm -f $$list || exit $$?; \
+       test -n "$(EXEEXT)" || exit 0; \
+       list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+       echo " rm -f" $$list; \
+       rm -f $$list
+gdk-pixbuf-csource$(EXEEXT): $(gdk_pixbuf_csource_OBJECTS) $(gdk_pixbuf_csource_DEPENDENCIES) $(EXTRA_gdk_pixbuf_csource_DEPENDENCIES) 
+       @rm -f gdk-pixbuf-csource$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(gdk_pixbuf_csource_OBJECTS) $(gdk_pixbuf_csource_LDADD) $(LIBS)
+gdk-pixbuf-pixdata$(EXEEXT): $(gdk_pixbuf_pixdata_OBJECTS) $(gdk_pixbuf_pixdata_DEPENDENCIES) $(EXTRA_gdk_pixbuf_pixdata_DEPENDENCIES) 
+       @rm -f gdk-pixbuf-pixdata$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(gdk_pixbuf_pixdata_OBJECTS) $(gdk_pixbuf_pixdata_LDADD) $(LIBS)
+gdk-pixbuf-query-loaders$(EXEEXT): $(gdk_pixbuf_query_loaders_OBJECTS) $(gdk_pixbuf_query_loaders_DEPENDENCIES) $(EXTRA_gdk_pixbuf_query_loaders_DEPENDENCIES) 
+       @rm -f gdk-pixbuf-query-loaders$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(gdk_pixbuf_query_loaders_OBJECTS) $(gdk_pixbuf_query_loaders_LDADD) $(LIBS)
+test-gdk-pixbuf$(EXEEXT): $(test_gdk_pixbuf_OBJECTS) $(test_gdk_pixbuf_DEPENDENCIES) $(EXTRA_test_gdk_pixbuf_DEPENDENCIES) 
+       @rm -f test-gdk-pixbuf$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(test_gdk_pixbuf_OBJECTS) $(test_gdk_pixbuf_LDADD) $(LIBS)
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT)
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdk-pixbuf-animation.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdk-pixbuf-csource.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdk-pixbuf-data.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdk-pixbuf-enum-types.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdk-pixbuf-io.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdk-pixbuf-loader.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdk-pixbuf-pixdata.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdk-pixbuf-scale.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdk-pixbuf-scaled-anim.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdk-pixbuf-simple-anim.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdk-pixbuf-util.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdk-pixbuf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdk-pixdata.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-ani-animation.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-ani.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-bmp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-gdip-animation.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-gdip-bmp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-gdip-emf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-gdip-gif.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-gdip-ico.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-gdip-jpeg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-gdip-tiff.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-gdip-utils.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-gdip-wmf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-gif-animation.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-gif.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-icns.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-ico.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-jasper.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-jpeg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-pcx.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-pixdata.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-png.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-pnm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-qtif.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-ras.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-tga.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-tiff.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-wbmp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-xbm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io-xpm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/queryloaders.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-gdk-pixbuf.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+install-girDATA: $(gir_DATA)
+       @$(NORMAL_INSTALL)
+       test -z "$(girdir)" || $(MKDIR_P) "$(DESTDIR)$(girdir)"
+       @list='$(gir_DATA)'; test -n "$(girdir)" || list=; \
+       for p in $$list; do \
+         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+         echo "$$d$$p"; \
+       done | $(am__base_list) | \
+       while read files; do \
+         echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(girdir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(girdir)" || exit $$?; \
+       done
+
+uninstall-girDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(gir_DATA)'; test -n "$(girdir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       dir='$(DESTDIR)$(girdir)'; $(am__uninstall_files_from_dir)
+install-typelibsDATA: $(typelibs_DATA)
+       @$(NORMAL_INSTALL)
+       test -z "$(typelibsdir)" || $(MKDIR_P) "$(DESTDIR)$(typelibsdir)"
+       @list='$(typelibs_DATA)'; test -n "$(typelibsdir)" || list=; \
+       for p in $$list; do \
+         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+         echo "$$d$$p"; \
+       done | $(am__base_list) | \
+       while read files; do \
+         echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(typelibsdir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(typelibsdir)" || exit $$?; \
+       done
+
+uninstall-typelibsDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(typelibs_DATA)'; test -n "$(typelibsdir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       dir='$(DESTDIR)$(typelibsdir)'; $(am__uninstall_files_from_dir)
+install-libgdk_pixbufincludeHEADERS: $(libgdk_pixbufinclude_HEADERS)
+       @$(NORMAL_INSTALL)
+       test -z "$(libgdk_pixbufincludedir)" || $(MKDIR_P) "$(DESTDIR)$(libgdk_pixbufincludedir)"
+       @list='$(libgdk_pixbufinclude_HEADERS)'; test -n "$(libgdk_pixbufincludedir)" || list=; \
+       for p in $$list; do \
+         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+         echo "$$d$$p"; \
+       done | $(am__base_list) | \
+       while read files; do \
+         echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(libgdk_pixbufincludedir)'"; \
+         $(INSTALL_HEADER) $$files "$(DESTDIR)$(libgdk_pixbufincludedir)" || exit $$?; \
+       done
+
+uninstall-libgdk_pixbufincludeHEADERS:
+       @$(NORMAL_UNINSTALL)
+       @list='$(libgdk_pixbufinclude_HEADERS)'; test -n "$(libgdk_pixbufincludedir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       dir='$(DESTDIR)$(libgdk_pixbufincludedir)'; $(am__uninstall_files_from_dir)
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+#     (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+       @fail= failcom='exit 1'; \
+       for f in x $$MAKEFLAGS; do \
+         case $$f in \
+           *=* | --[!k]*);; \
+           *k*) failcom='fail=yes';; \
+         esac; \
+       done; \
+       dot_seen=no; \
+       target=`echo $@ | sed s/-recursive//`; \
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         echo "Making $$target in $$subdir"; \
+         if test "$$subdir" = "."; then \
+           dot_seen=yes; \
+           local_target="$$target-am"; \
+         else \
+           local_target="$$target"; \
+         fi; \
+         ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+         || eval $$failcom; \
+       done; \
+       if test "$$dot_seen" = "no"; then \
+         $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+       fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+       @fail= failcom='exit 1'; \
+       for f in x $$MAKEFLAGS; do \
+         case $$f in \
+           *=* | --[!k]*);; \
+           *k*) failcom='fail=yes';; \
+         esac; \
+       done; \
+       dot_seen=no; \
+       case "$@" in \
+         distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+         *) list='$(SUBDIRS)' ;; \
+       esac; \
+       rev=''; for subdir in $$list; do \
+         if test "$$subdir" = "."; then :; else \
+           rev="$$subdir $$rev"; \
+         fi; \
+       done; \
+       rev="$$rev ."; \
+       target=`echo $@ | sed s/-recursive//`; \
+       for subdir in $$rev; do \
+         echo "Making $$target in $$subdir"; \
+         if test "$$subdir" = "."; then \
+           local_target="$$target-am"; \
+         else \
+           local_target="$$target"; \
+         fi; \
+         ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+         || eval $$failcom; \
+       done && test -z "$$fail"
+tags-recursive:
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+       done
+ctags-recursive:
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+       done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+       list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       set x; \
+       here=`pwd`; \
+       if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+         include_option=--etags-include; \
+         empty_fix=.; \
+       else \
+         include_option=--include; \
+         empty_fix=; \
+       fi; \
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         if test "$$subdir" = .; then :; else \
+           test ! -f $$subdir/TAGS || \
+             set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+         fi; \
+       done; \
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       shift; \
+       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+         test -n "$$unique" || unique=$$empty_fix; \
+         if test $$# -gt 0; then \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             "$$@" $$unique; \
+         else \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             $$unique; \
+         fi; \
+       fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       test -z "$(CTAGS_ARGS)$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+            $$unique
+
+GTAGS:
+       here=`$(am__cd) $(top_builddir) && pwd` \
+         && $(am__cd) $(top_srcdir) \
+         && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+       @failed=0; all=0; xfail=0; xpass=0; skip=0; \
+       srcdir=$(srcdir); export srcdir; \
+       list=' $(TESTS) '; \
+       $(am__tty_colors); \
+       if test -n "$$list"; then \
+         for tst in $$list; do \
+           if test -f ./$$tst; then dir=./; \
+           elif test -f $$tst; then dir=; \
+           else dir="$(srcdir)/"; fi; \
+           if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+             all=`expr $$all + 1`; \
+             case " $(XFAIL_TESTS) " in \
+             *[\ \     ]$$tst[\ \      ]*) \
+               xpass=`expr $$xpass + 1`; \
+               failed=`expr $$failed + 1`; \
+               col=$$red; res=XPASS; \
+             ;; \
+             *) \
+               col=$$grn; res=PASS; \
+             ;; \
+             esac; \
+           elif test $$? -ne 77; then \
+             all=`expr $$all + 1`; \
+             case " $(XFAIL_TESTS) " in \
+             *[\ \     ]$$tst[\ \      ]*) \
+               xfail=`expr $$xfail + 1`; \
+               col=$$lgn; res=XFAIL; \
+             ;; \
+             *) \
+               failed=`expr $$failed + 1`; \
+               col=$$red; res=FAIL; \
+             ;; \
+             esac; \
+           else \
+             skip=`expr $$skip + 1`; \
+             col=$$blu; res=SKIP; \
+           fi; \
+           echo "$${col}$$res$${std}: $$tst"; \
+         done; \
+         if test "$$all" -eq 1; then \
+           tests="test"; \
+           All=""; \
+         else \
+           tests="tests"; \
+           All="All "; \
+         fi; \
+         if test "$$failed" -eq 0; then \
+           if test "$$xfail" -eq 0; then \
+             banner="$$All$$all $$tests passed"; \
+           else \
+             if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+             banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
+           fi; \
+         else \
+           if test "$$xpass" -eq 0; then \
+             banner="$$failed of $$all $$tests failed"; \
+           else \
+             if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+             banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+           fi; \
+         fi; \
+         dashes="$$banner"; \
+         skipped=""; \
+         if test "$$skip" -ne 0; then \
+           if test "$$skip" -eq 1; then \
+             skipped="($$skip test was not run)"; \
+           else \
+             skipped="($$skip tests were not run)"; \
+           fi; \
+           test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+             dashes="$$skipped"; \
+         fi; \
+         report=""; \
+         if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+           report="Please report to $(PACKAGE_BUGREPORT)"; \
+           test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+             dashes="$$report"; \
+         fi; \
+         dashes=`echo "$$dashes" | sed s/./=/g`; \
+         if test "$$failed" -eq 0; then \
+           col="$$grn"; \
+         else \
+           col="$$red"; \
+         fi; \
+         echo "$${col}$$dashes$${std}"; \
+         echo "$${col}$$banner$${std}"; \
+         test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \
+         test -z "$$report" || echo "$${col}$$report$${std}"; \
+         echo "$${col}$$dashes$${std}"; \
+         test "$$failed" -eq 0; \
+       else :; fi
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d "$(distdir)/$$file"; then \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+         else \
+           test -f "$(distdir)/$$file" \
+           || cp -p $$d/$$file "$(distdir)/$$file" \
+           || exit 1; \
+         fi; \
+       done
+       @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+         if test "$$subdir" = .; then :; else \
+           test -d "$(distdir)/$$subdir" \
+           || $(MKDIR_P) "$(distdir)/$$subdir" \
+           || exit 1; \
+         fi; \
+       done
+       @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+         if test "$$subdir" = .; then :; else \
+           dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+           $(am__relativize); \
+           new_distdir=$$reldir; \
+           dir1=$$subdir; dir2="$(top_distdir)"; \
+           $(am__relativize); \
+           new_top_distdir=$$reldir; \
+           echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+           echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+           ($(am__cd) $$subdir && \
+             $(MAKE) $(AM_MAKEFLAGS) \
+               top_distdir="$$new_top_distdir" \
+               distdir="$$new_distdir" \
+               am__remove_distdir=: \
+               am__skip_length_check=: \
+               am__skip_mode_fix=: \
+               distdir) \
+             || exit 1; \
+         fi; \
+       done
+       $(MAKE) $(AM_MAKEFLAGS) \
+         top_distdir="$(top_distdir)" distdir="$(distdir)" \
+         dist-hook
+check-am: all-am
+       $(MAKE) $(AM_MAKEFLAGS) check-TESTS check-local
+check: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) check-recursive
+@CROSS_COMPILING_TRUE@all-local:
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS) \
+               all-local
+install-binPROGRAMS: install-libLTLIBRARIES
+
+installdirs: installdirs-recursive
+installdirs-am:
+       for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(loaderdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(girdir)" "$(DESTDIR)$(typelibsdir)" "$(DESTDIR)$(libgdk_pixbufincludedir)"; do \
+         test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+       done
+install: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+       if test -z '$(STRIP)'; then \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+             install; \
+       else \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+       fi
+mostlyclean-generic:
+
+clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-recursive
+
+clean-am: clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \
+       clean-libtool clean-loaderLTLIBRARIES clean-noinstLTLIBRARIES \
+       clean-noinstPROGRAMS mostlyclean-am
+
+distclean: distclean-recursive
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+       distclean-local distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-girDATA install-libgdk_pixbufincludeHEADERS \
+       install-loaderLTLIBRARIES install-typelibsDATA
+       @$(NORMAL_INSTALL)
+       $(MAKE) $(AM_MAKEFLAGS) install-data-hook
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS install-libLTLIBRARIES
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+       mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-girDATA \
+       uninstall-libLTLIBRARIES uninstall-libgdk_pixbufincludeHEADERS \
+       uninstall-loaderLTLIBRARIES uninstall-local \
+       uninstall-typelibsDATA
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all check \
+       check-am ctags-recursive install install-am install-data-am \
+       install-strip tags-recursive
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+       all all-am all-local check check-TESTS check-am check-local \
+       clean clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \
+       clean-libtool clean-loaderLTLIBRARIES clean-noinstLTLIBRARIES \
+       clean-noinstPROGRAMS ctags ctags-recursive dist-hook distclean \
+       distclean-compile distclean-generic distclean-libtool \
+       distclean-local distclean-tags distdir dvi dvi-am html html-am \
+       info info-am install install-am install-binPROGRAMS \
+       install-data install-data-am install-data-hook install-dvi \
+       install-dvi-am install-exec install-exec-am install-girDATA \
+       install-html install-html-am install-info install-info-am \
+       install-libLTLIBRARIES install-libgdk_pixbufincludeHEADERS \
+       install-loaderLTLIBRARIES install-man install-pdf \
+       install-pdf-am install-ps install-ps-am install-strip \
+       install-typelibsDATA installcheck installcheck-am installdirs \
+       installdirs-am maintainer-clean maintainer-clean-generic \
+       mostlyclean mostlyclean-compile mostlyclean-generic \
+       mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \
+       uninstall uninstall-am uninstall-binPROGRAMS uninstall-girDATA \
+       uninstall-libLTLIBRARIES uninstall-libgdk_pixbufincludeHEADERS \
+       uninstall-loaderLTLIBRARIES uninstall-local \
+       uninstall-typelibsDATA
+
+# call as: $(XVFB_START) && someprogram
+
+# test: run all tests in cwd and subdirs
+test:  ${TEST_PROGS}
+       @$(SKIP_GDKTARGET) || test -z "${TEST_PROGS}" || { \
+         $(XVFB_START) && { set -e; ${GTESTER} --verbose ${TEST_PROGS}; }; \
+       }
+       @ for subdir in $(SUBDIRS) ; do \
+           test "$$subdir" = "." -o "$$subdir" = "po" -o "$$subdir" = "po-properties" || \
+           ( cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $@ ) || exit $? ; \
+         done
+# test-report: run tests in subdirs and generate report
+# perf-report: run tests in subdirs with -m perf and generate report
+# full-report: like test-report: with -m perf and -m slow
+test-report perf-report full-report:   ${TEST_PROGS}
+       @ ignore_logdir=true ; \
+         if test -z "$$GTESTER_LOGDIR" ; then \
+           GTESTER_LOGDIR=`mktemp -d "\`pwd\`/.testlogs-XXXXXX"`; export GTESTER_LOGDIR ; \
+           ignore_logdir=false ; \
+         fi ; \
+         for subdir in $(SUBDIRS) ; do \
+           test "$$subdir" = "." -o "$$subdir" = "po" -o "$$subdir" = "po-properties" || \
+           ( cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $@ ) || exit $? ; \
+         done ; \
+         $(SKIP_GDKTARGET) || test -z "${TEST_PROGS}" || { \
+           case $@ in \
+           test-report) test_options="-k";; \
+           perf-report) test_options="-k -m=perf";; \
+           full-report) test_options="-k -m=perf -m=slow";; \
+           esac ; \
+           $(XVFB_START) && { \
+             set -e; \
+             if test -z "$$GTESTER_LOGDIR" ; then \
+               ${GTESTER} --verbose $$test_options -o test-report.xml ${TEST_PROGS} ; \
+             elif test -n "${TEST_PROGS}" ; then \
+               ${GTESTER} --verbose $$test_options -o `mktemp "$$GTESTER_LOGDIR/log-XXXXXX"` ${TEST_PROGS} ; \
+             fi ; \
+           }; \
+         }; \
+         $$ignore_logdir || { \
+           echo '<?xml version="1.0"?>' > $@.xml ; \
+           echo '<report-collection>'  >> $@.xml ; \
+           for lf in `ls -L "$$GTESTER_LOGDIR"/.` ; do \
+             sed '1,1s/^<?xml\b[^>?]*?>//' <"$$GTESTER_LOGDIR"/"$$lf" >> $@.xml ; \
+           done ; \
+           echo >> $@.xml ; \
+           echo '</report-collection>' >> $@.xml ; \
+           rm -rf "$$GTESTER_LOGDIR"/ ; \
+           ${GTESTER_REPORT} --version 2>/dev/null 1>&2 ; test "$$?" != 0 || ${GTESTER_REPORT} $@.xml >$@.html ; \
+         }
+.PHONY: test test-report perf-report full-report
+# run make test as part of make check
+check-local: test
+-include $(INTROSPECTION_MAKEFILE)
+
+@OS_WIN32_TRUE@gdk_pixbuf-win32-res.o : gdk_pixbuf.rc
+@OS_WIN32_TRUE@        $(WINDRES) gdk_pixbuf.rc $@
+
+@OS_WIN32_TRUE@install-def-file:
+@OS_WIN32_TRUE@        $(INSTALL) $(srcdir)/gdk_pixbuf.def $(DESTDIR)$(libdir)/gdk_pixbuf-$(GDK_PIXBUF_API_VERSION).def
+@OS_WIN32_TRUE@uninstall-def-file:
+@OS_WIN32_TRUE@        -rm $(DESTDIR)$(libdir)/gdk_pixbuf-$(GDK_PIXBUF_API_VERSION).def
+@OS_WIN32_FALSE@install-def-file:
+@OS_WIN32_FALSE@uninstall-def-file:
+
+@MS_LIB_AVAILABLE_TRUE@gdk_pixbuf-$(GDK_PIXBUF_API_VERSION).lib: libgdk_pixbuf-$(GDK_PIXBUF_API_VERSION).la gdk_pixbuf.def
+@MS_LIB_AVAILABLE_TRUE@        lib -machine:@LIB_EXE_MACHINE_FLAG@ -name:libgdk_pixbuf-$(GDK_PIXBUF_API_VERSION)-@LT_CURRENT_MINUS_AGE@.dll -def:gdk_pixbuf.def -out:$@
+
+@MS_LIB_AVAILABLE_TRUE@install-ms-lib:
+@MS_LIB_AVAILABLE_TRUE@        $(INSTALL) gdk_pixbuf-$(GDK_PIXBUF_API_VERSION).lib $(DESTDIR)$(libdir)
+
+@MS_LIB_AVAILABLE_TRUE@uninstall-ms-lib:
+@MS_LIB_AVAILABLE_TRUE@        -rm $(DESTDIR)$(libdir)/gdk_pixbuf-$(GDK_PIXBUF_API_VERSION).lib
+@MS_LIB_AVAILABLE_FALSE@install-ms-lib:
+@MS_LIB_AVAILABLE_FALSE@uninstall-ms-lib:
+
+# This places the generated .def file in srcdir, since it is expected to be there.
+# (The one from a tarball is)
+gdk_pixbuf.def: gdk-pixbuf.symbols
+       (echo -e EXPORTS; $(CPP) -P -DINCLUDE_VARIABLES -DG_OS_WIN32 -DALL_FILES - <$(srcdir)/gdk-pixbuf.symbols | sed -e '/^$$/d' -e 's/^/     /' -e 's/G_GNUC_[^ ]*//g') > $(srcdir)/gdk_pixbuf.def
+
+@BUILD_GDIPLUS_LOADERS_TRUE@libgdiplus.dll.a: gdiplus.def
+@BUILD_GDIPLUS_LOADERS_TRUE@   $(DLLTOOL) --kill-at --dllname gdiplus.dll --input-def $(srcdir)/gdiplus.def --output-lib $@
+
+#
+# gdk-pixbuf-enum-types.h
+#
+gdk-pixbuf-enum-types.h: s-enum-types-h
+       @true
+
+s-enum-types-h: @REBUILD@ $(gdk_pixbuf_headers) gdk-pixbuf-enum-types.h.template
+       ( cd $(srcdir) && $(GLIB_MKENUMS) --template gdk-pixbuf-enum-types.h.template \
+               $(gdk_pixbuf_headers) ) > tmp-gdk-pixbuf-enum-types.h \
+       && (cmp -s tmp-gdk-pixbuf-enum-types.h gdk-pixbuf-enum-types.h || cp tmp-gdk-pixbuf-enum-types.h gdk-pixbuf-enum-types.h ) \
+       && rm -f tmp-gdk-pixbuf-enum-types.h \
+       && echo timestamp > $(@F)
+
+#
+# gdk-pixbuf-enum-types.c
+#
+gdk-pixbuf-enum-types.c: @REBUILD@ $(gdk_pixbuf_headers) gdk-pixbuf-enum-types.c.template
+       (cd $(srcdir) && $(GLIB_MKENUMS) --template gdk-pixbuf-enum-types.c.template \
+                 $(gdk_pixbuf_headers)) > gdk-pixbuf-enum-types.c
+
+#
+# gdk-pixbuf-marshal.h
+#
+gdk-pixbuf-marshal.h: @REBUILD@ stamp-gdk-pixbuf-marshal.h
+       @true
+
+stamp-gdk-pixbuf-marshal.h: @REBUILD@ $(srcdir)/gdk-pixbuf-marshal.list
+       echo "#if !defined(GDK_PIXBUF_DISABLE_DEPRECATED) || defined(GDK_PIXBUF_COMPILATION)" > xgen-gmh \
+       && $(GLIB_GENMARSHAL) --prefix=_gdk_pixbuf_marshal $(srcdir)/gdk-pixbuf-marshal.list --header >> xgen-gmh \
+       && echo "#endif /* !GDK_PIXBUF_DISABLE_DEPRECATED || GDK_PIXBUF_COMPILATION */" >> xgen-gmh \
+       && (cmp -s xgen-gmh gdk-pixbuf-marshal.h || cp xgen-gmh gdk-pixbuf-marshal.h) \
+       && rm -f xgen-gmh xgen-gmh~ \
+       && echo timestamp > $(@F)
+
+#
+# gdk-pixbuf-marshal.c
+#
+$(srcdir)/gdk-pixbuf-marshal.c: @REBUILD@ $(srcdir)/gdk-pixbuf-marshal.list
+       (echo -e "#include <gdk-pixbuf/gdk-pixbuf.h>\n" | $(GLIB_GENMARSHAL) --prefix=_gdk_pixbuf_marshal $(srcdir)/gdk-pixbuf-marshal.list --body ) >> xgen-gmc \
+       && cp xgen-gmc gdk-pixbuf-marshal.c \
+       && rm -f xgen-gmc xgen-gmc~
+
+# if srcdir!=builddir, clean out maintainer-clean files from builddir
+# this allows dist to pass.
+distclean-local:
+       if test $(srcdir) != .; then \
+         rm -f $(MAINTAINERCLEANFILES); \
+       fi
+
+dist-hook: ../build/win32/vs9/gdk-pixbuf.vcproj ../build/win32/vs10/gdk-pixbuf.vcxproj ../build/win32/vs10/gdk-pixbuf.vcxproj.filters
+
+../build/win32/vs9/gdk-pixbuf.vcproj: ../build/win32/vs9/gdk-pixbuf.vcprojin
+       for F in $(libgdk_pixbuf_2_0_la_SOURCES); do \
+               case $$F in \
+               *.c) echo '   <File RelativePath="..\..\..\gdk-pixbuf\'$$F'" />' \
+                    ;; \
+               esac; \
+       done >libgdkpixbuf.sourcefiles
+       $(CPP) -P - <$(top_srcdir)/build/win32/vs9/gdk-pixbuf.vcprojin >$@
+       rm libgdkpixbuf.sourcefiles
+
+../build/win32/vs10/gdk-pixbuf.vcxproj: ../build/win32/vs10/gdk-pixbuf.vcxprojin
+       for F in $(libgdk_pixbuf_2_0_la_SOURCES); do \
+               case $$F in \
+               *.c) echo '    <ClCompile Include="..\..\..\gdk-pixbuf\'$$F'" />' \
+                    ;; \
+               esac; \
+       done >libgdkpixbuf.vs10.sourcefiles
+       $(CPP) -P - <$(top_srcdir)/build/win32/vs10/gdk-pixbuf.vcxprojin >$@
+       rm libgdkpixbuf.vs10.sourcefiles
+
+../build/win32/vs10/gdk-pixbuf.vcxproj.filters: ../build/win32/vs10/gdk-pixbuf.vcxproj.filtersin
+       for F in $(libgdk_pixbuf_2_0_la_SOURCES); do \
+               case $$F in \
+               *.c) echo '    <ClCompile Include="..\..\..\gdk-pixbuf\'$$F'"><Filter>Source Files</Filter></ClCompile>' \
+                    ;; \
+               esac; \
+       done >libgdkpixbuf.vs10.sourcefiles.filters
+       $(CPP) -P - <$(top_srcdir)/build/win32/vs10/gdk-pixbuf.vcxproj.filtersin >$@
+       rm libgdkpixbuf.vs10.sourcefiles.filters
+
+@HAVE_INTROSPECTION_TRUE@GdkPixbuf-2.0.gir: libgdk_pixbuf-2.0.la Makefile
+
+# Running this if cross compiling or if DESTDIR is set is going to
+# not work at all, so skip it
+# We use install-data-hook here to workaround a bug in automake and/or libtool
+# that makes the install target for the loader libraries a dependency on
+# install-data-am, and not install-exec-am. We need to ensure this gets run
+# after the libraries are installed in their final locations.
+install-data-hook: install-ms-lib install-def-file
+       @if $(RUN_QUERY_LOADER_TEST) ; then \
+         $(mkinstalldirs) $(DESTDIR)$(libdir)/gdk-pixbuf-2.0/$(GDK_PIXBUF_BINARY_VERSION) ; \
+         $(top_builddir)/gdk-pixbuf/gdk-pixbuf-query-loaders > $(DESTDIR)$(libdir)/gdk-pixbuf-2.0/$(GDK_PIXBUF_BINARY_VERSION)/loaders.cache ; \
+       else \
+         echo "***" ; \
+         echo "*** Warning: loaders.cache not built" ; \
+         echo "***" ; \
+         echo "*** Generate this file manually on host" ; \
+         echo "*** system using gdk-pixbuf-query-loaders" ; \
+         echo "***" ; \
+       fi
+
+uninstall-local: uninstall-ms-lib uninstall-def-file
+       rm -f $(DESTDIR)$(libdir)/gdk-pixbuf-2.0/$(GDK_PIXBUF_BINARY_VERSION)/loaders.cache
+
+@CROSS_COMPILING_FALSE@all-local: loaders.cache
+
+@BUILD_DYNAMIC_MODULES_TRUE@loaders.cache: $(loader_LTLIBRARIES) gdk-pixbuf-query-loaders$(EXEEXT)
+@BUILD_DYNAMIC_MODULES_TRUE@   LOADERS=`echo libpixbufloader-*.la` ; \
+@BUILD_DYNAMIC_MODULES_TRUE@   if test "x$$LOADERS" != 'xlibpixbufloader-*.la' ; then \
+@BUILD_DYNAMIC_MODULES_TRUE@          echo "Writing a loaders.cache file to use when running examples before installing gdk-pixbuf."; \
+@BUILD_DYNAMIC_MODULES_TRUE@     $(top_builddir)/gdk-pixbuf/gdk-pixbuf-query-loaders $$LOADERS > ./loaders.cache ;\
+@BUILD_DYNAMIC_MODULES_TRUE@   else \
+@BUILD_DYNAMIC_MODULES_TRUE@          echo "No dynamic modules found; will use only static modules for uninstalled example programs."; \
+@BUILD_DYNAMIC_MODULES_TRUE@     touch loaders.cache; \
+@BUILD_DYNAMIC_MODULES_TRUE@   fi
+@BUILD_DYNAMIC_MODULES_FALSE@loaders.cache:
+@BUILD_DYNAMIC_MODULES_FALSE@  echo "No dynamic modules found; will use only static modules for uninstalled example programs."; \
+@BUILD_DYNAMIC_MODULES_FALSE@  touch loaders.cache;
+
+-include $(top_srcdir)/git.mk
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/gdk-pixbuf/abicheck.sh b/gdk-pixbuf/abicheck.sh
new file mode 100755 (executable)
index 0000000..4b21da5
--- /dev/null
@@ -0,0 +1,5 @@
+#! /bin/sh
+
+cpp -DINCLUDE_VARIABLES -P -DALL_FILES ${srcdir:-.}/gdk-pixbuf.symbols | sed -e '/^$/d' -e 's/ G_GNUC.*$//' -e 's/ PRIVATE$//' | sort > expected-abi
+nm -D -g --defined-only .libs/libgdk_pixbuf-2.0.so | cut -d ' ' -f 3 | egrep -v '^(__bss_start|_edata|_end)' | sort > actual-abi
+diff -u expected-abi actual-abi && rm -f expected-abi actual-abi
diff --git a/gdk-pixbuf/gdiplus.def b/gdk-pixbuf/gdiplus.def
new file mode 100644 (file)
index 0000000..bf8aa01
--- /dev/null
@@ -0,0 +1,59 @@
+EXPORTS
+; this is not a real def file for gdiplus library
+; it is only a def file with symbols strictly neede
+; to make link gdk-pixbuf with gdiplus.dll on systems
+; where the import library does not exit and it contains
+; symbols for both win32 and win64 compilations in 
+; the same def file, since win32 uses __stdcall calling
+; convention and win64 uses __cdecl convention; the symbols
+; are nevertheless the same
+       GdipBitmapGetPixel
+       GdipBitmapGetPixel@16
+       GdipBitmapSetPixel
+       GdipBitmapSetPixel@16
+       GdipBitmapSetResolution
+       GdipBitmapSetResolution@12
+       GdipCreateBitmapFromScan0
+       GdipCreateBitmapFromScan0@24
+       GdipCreateBitmapFromStream
+       GdipCreateBitmapFromStream@8
+       GdipDeleteGraphics
+       GdipDeleteGraphics@4
+       GdipDisposeImage
+       GdipDisposeImage@4
+       GdipDrawImageI
+       GdipDrawImageI@16
+       GdipFlush
+       GdipFlush@8
+       GdipGetImageEncoders
+       GdipGetImageEncoders@12
+       GdipGetImageEncodersSize
+       GdipGetImageEncodersSize@8
+       GdipGetImageFlags
+       GdipGetImageFlags@8
+       GdipGetImageGraphicsContext
+       GdipGetImageGraphicsContext@8
+       GdipGetImageHeight
+       GdipGetImageHeight@8
+       GdipGetImageHorizontalResolution
+       GdipGetImageHorizontalResolution@8
+       GdipGetImageVerticalResolution
+       GdipGetImageVerticalResolution@8
+       GdipGetImageWidth
+       GdipGetImageWidth@8
+       GdipGetPropertyItem
+       GdipGetPropertyItem@16
+       GdipGetPropertyItemSize
+       GdipGetPropertyItemSize@12
+       GdipGraphicsClear
+       GdipGraphicsClear@8
+       GdipImageGetFrameCount
+       GdipImageGetFrameCount@12
+       GdipImageSelectActiveFrame
+       GdipImageSelectActiveFrame@12
+       GdipLoadImageFromStream
+       GdipLoadImageFromStream@8
+       GdiplusStartup
+       GdiplusStartup@12
+       GdipSaveImageToStream
+       GdipSaveImageToStream@16
diff --git a/gdk-pixbuf/gdk-pixbuf-animation.c b/gdk-pixbuf/gdk-pixbuf-animation.c
new file mode 100644 (file)
index 0000000..ff22799
--- /dev/null
@@ -0,0 +1,744 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* GdkPixbuf library - Simple animation support
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Authors: Jonathan Blandford <jrb@redhat.com>
+ *          Havoc Pennington <hp@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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 <errno.h>
+#include "gdk-pixbuf-private.h"
+#include "gdk-pixbuf-animation.h"
+
+#include <glib/gstdio.h>
+
+/**
+ * SECTION:animation
+ * @Short_description: Animated images.
+ * @Title: Animations
+ * @See_also: #GdkPixbufLoader.
+ * 
+ * The &gdk-pixbuf; library provides a simple mechanism to load and represent
+ * animations. An animation is conceptually a series of frames to be displayed
+ * over time. Each frame is the same size. The animation may not be represented
+ * as a series of frames internally; for example, it may be stored as a 
+ * sprite and instructions for moving the sprite around a background. To display 
+ * an animation you don't need to understand its representation, however; you just
+ * ask &gdk-pixbuf; what should be displayed at a given point in time. 
+ * 
+ */
+
+typedef struct _GdkPixbufNonAnim GdkPixbufNonAnim;
+typedef struct _GdkPixbufNonAnimClass GdkPixbufNonAnimClass;
+
+#define GDK_TYPE_PIXBUF_NON_ANIM              (gdk_pixbuf_non_anim_get_type ())
+#define GDK_PIXBUF_NON_ANIM(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_NON_ANIM, GdkPixbufNonAnim))
+#define GDK_IS_PIXBUF_NON_ANIM(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_NON_ANIM))
+
+#define GDK_PIXBUF_NON_ANIM_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_NON_ANIM, GdkPixbufNonAnimClass))
+#define GDK_IS_PIXBUF_NON_ANIM_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_NON_ANIM))
+#define GDK_PIXBUF_NON_ANIM_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_NON_ANIM, GdkPixbufNonAnimClass))
+
+/* Private part of the GdkPixbufNonAnim structure */
+struct _GdkPixbufNonAnim {
+        GdkPixbufAnimation parent_instance;
+
+        GdkPixbuf *pixbuf;
+};
+
+struct _GdkPixbufNonAnimClass {
+        GdkPixbufAnimationClass parent_class;
+        
+};
+
+
+typedef struct _GdkPixbufNonAnimIter GdkPixbufNonAnimIter;
+typedef struct _GdkPixbufNonAnimIterClass GdkPixbufNonAnimIterClass;
+
+
+#define GDK_TYPE_PIXBUF_NON_ANIM_ITER              (gdk_pixbuf_non_anim_iter_get_type ())
+#define GDK_PIXBUF_NON_ANIM_ITER(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_NON_ANIM_ITER, GdkPixbufNonAnimIter))
+#define GDK_IS_PIXBUF_NON_ANIM_ITER(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_NON_ANIM_ITER))
+
+#define GDK_PIXBUF_NON_ANIM_ITER_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_NON_ANIM_ITER, GdkPixbufNonAnimIterClass))
+#define GDK_IS_PIXBUF_NON_ANIM_ITER_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_NON_ANIM_ITER))
+#define GDK_PIXBUF_NON_ANIM_ITER_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_NON_ANIM_ITER, GdkPixbufNonAnimIterClass))
+
+struct _GdkPixbufNonAnimIter {
+        GdkPixbufAnimationIter parent_instance;
+
+        GdkPixbufNonAnim   *non_anim;
+};
+
+struct _GdkPixbufNonAnimIterClass {
+        GdkPixbufAnimationIterClass parent_class;
+
+};
+
+static GType gdk_pixbuf_non_anim_iter_get_type (void) G_GNUC_CONST;
+
+G_DEFINE_TYPE (GdkPixbufAnimation, gdk_pixbuf_animation, G_TYPE_OBJECT);
+
+static void
+gdk_pixbuf_animation_class_init (GdkPixbufAnimationClass *klass)
+{
+}
+
+static void
+gdk_pixbuf_animation_init (GdkPixbufAnimation *animation)
+{
+}
+
+/**
+ * gdk_pixbuf_animation_new_from_file:
+ * @filename: Name of file to load, in the GLib file name encoding
+ * @error: return location for error
+ *
+ * Creates a new animation by loading it from a file.  The file format is
+ * detected automatically.  If the file's format does not support multi-frame
+ * images, then an animation with a single frame will be created. Possible errors
+ * are in the #GDK_PIXBUF_ERROR and #G_FILE_ERROR domains.
+ *
+ * Return value: A newly-created animation with a reference count of 1, or %NULL
+ * if any of several error conditions ocurred:  the file could not be opened,
+ * there was no loader for the file's format, there was not enough memory to
+ * allocate the image buffer, or the image file contained invalid data.
+ **/
+GdkPixbufAnimation *
+gdk_pixbuf_animation_new_from_file (const char *filename,
+                                    GError    **error)
+{
+       GdkPixbufAnimation *animation;
+       int size;
+       FILE *f;
+       guchar buffer [1024];
+       GdkPixbufModule *image_module;
+        gchar *display_name;
+        gboolean locked = FALSE;
+
+       g_return_val_if_fail (filename != NULL, NULL);
+        g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+        display_name = g_filename_display_name (filename);
+       f = g_fopen (filename, "rb");
+       if (!f) {
+                gint save_errno = errno;
+                g_set_error (error,
+                             G_FILE_ERROR,
+                             g_file_error_from_errno (save_errno),
+                             _("Failed to open file '%s': %s"),
+                             display_name,
+                             g_strerror (save_errno));
+                g_free (display_name);
+               return NULL;
+        }
+
+       size = fread (&buffer, 1, sizeof (buffer), f);
+
+       if (size == 0) {
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                             _("Image file '%s' contains no data"),
+                             display_name);
+                g_free (display_name);
+               fclose (f);
+               return NULL;
+       }
+
+       image_module = _gdk_pixbuf_get_module (buffer, size, filename, error);
+       if (!image_module) {
+                g_free (display_name);
+               fclose (f);
+               return NULL;
+       }
+
+       if (image_module->module == NULL)
+                if (!_gdk_pixbuf_load_module (image_module, error)) {
+                        g_free (display_name);
+                        fclose (f);
+                        return NULL;
+                }
+
+       if (image_module->load_animation == NULL) {
+               GdkPixbuf *pixbuf;
+
+               /* Keep this logic in sync with gdk_pixbuf_new_from_file() */
+
+               fseek (f, 0, SEEK_SET);
+               pixbuf = _gdk_pixbuf_generic_image_load (image_module, f, error);
+               fclose (f);
+
+                if (pixbuf == NULL && error != NULL && *error == NULL) {
+                        /* I don't trust these crufty longjmp()'ing image libs
+                         * to maintain proper error invariants, and I don't
+                         * want user code to segfault as a result. We need to maintain
+                         * the invariant that error gets set if NULL is returned.
+                         */
+                        
+                        g_warning ("Bug! gdk-pixbuf loader '%s' didn't set an error on failure.",
+                                   image_module->module_name);
+                        g_set_error (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_FAILED,
+                                     _("Failed to load image '%s': reason not known, probably a corrupt image file"),
+                                     display_name);
+                }
+                
+               if (pixbuf == NULL) {
+                        g_free (display_name);
+                        animation = NULL;
+                        goto out_unlock;
+                }
+
+                animation = gdk_pixbuf_non_anim_new (pixbuf);
+
+                g_object_unref (pixbuf);
+       } else {
+                locked = _gdk_pixbuf_lock (image_module);
+
+               fseek (f, 0, SEEK_SET);
+               animation = (* image_module->load_animation) (f, error);
+
+                if (animation == NULL && error != NULL && *error == NULL) {
+                        /* I don't trust these crufty longjmp()'ing
+                         * image libs to maintain proper error
+                         * invariants, and I don't want user code to
+                         * segfault as a result. We need to maintain
+                         * the invariant that error gets set if NULL
+                         * is returned.
+                         */
+                        
+                        g_warning ("Bug! gdk-pixbuf loader '%s' didn't set an error on failure.",
+                                   image_module->module_name);
+                        g_set_error (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_FAILED,
+                                     _("Failed to load animation '%s': reason not known, probably a corrupt animation file"),
+                                     display_name);
+                }
+                
+               fclose (f);
+       }
+
+        g_free (display_name);
+
+ out_unlock:
+        if (locked)
+                _gdk_pixbuf_unlock (image_module);
+       return animation;
+}
+
+#ifdef G_OS_WIN32
+
+#undef gdk_pixbuf_animation_new_from_file
+
+GdkPixbufAnimation *
+gdk_pixbuf_animation_new_from_file (const char *filename,
+                                    GError    **error)
+{
+       gchar *utf8_filename =
+               g_locale_to_utf8 (filename, -1, NULL, NULL, error);
+       GdkPixbufAnimation *retval;
+
+       if (utf8_filename == NULL)
+               return NULL;
+
+       retval = gdk_pixbuf_animation_new_from_file_utf8 (utf8_filename, error);
+
+       g_free (utf8_filename);
+
+       return retval;
+}
+
+#endif
+
+/**
+ * gdk_pixbuf_animation_ref: (skip)
+ * @animation: An animation.
+ *
+ * Adds a reference to an animation.
+ *
+ * Return value: The same as the @animation argument.
+ *
+ * Deprecated: 2.0: Use g_object_ref().
+ **/
+GdkPixbufAnimation *
+gdk_pixbuf_animation_ref (GdkPixbufAnimation *animation)
+{
+        return (GdkPixbufAnimation*) g_object_ref (animation);
+}
+
+/**
+ * gdk_pixbuf_animation_unref: (skip)
+ * @animation: An animation.
+ *
+ * Removes a reference from an animation.
+ *
+ * Deprecated: 2.0: Use g_object_unref().
+ **/
+void
+gdk_pixbuf_animation_unref (GdkPixbufAnimation *animation)
+{
+        g_object_unref (animation);
+}
+
+/**
+ * gdk_pixbuf_animation_is_static_image:
+ * @animation: a #GdkPixbufAnimation
+ * 
+ * If you load a file with gdk_pixbuf_animation_new_from_file() and it turns
+ * out to be a plain, unanimated image, then this function will return
+ * %TRUE. Use gdk_pixbuf_animation_get_static_image() to retrieve
+ * the image.
+ * 
+ * Return value: %TRUE if the "animation" was really just an image
+ **/
+gboolean
+gdk_pixbuf_animation_is_static_image (GdkPixbufAnimation *animation)
+{
+       g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), FALSE);
+
+        return GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->is_static_image (animation);
+}
+
+/**
+ * gdk_pixbuf_animation_get_static_image:
+ * @animation: a #GdkPixbufAnimation
+ * 
+ * If an animation is really just a plain image (has only one frame),
+ * this function returns that image. If the animation is an animation,
+ * this function returns a reasonable thing to display as a static
+ * unanimated image, which might be the first frame, or something more
+ * sophisticated. If an animation hasn't loaded any frames yet, this
+ * function will return %NULL.
+ * 
+ * Return value: (transfer none): unanimated image representing the animation
+ **/
+GdkPixbuf*
+gdk_pixbuf_animation_get_static_image (GdkPixbufAnimation *animation)
+{
+       g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), NULL);
+        
+        return GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_static_image (animation);
+}
+
+/**
+ * gdk_pixbuf_animation_get_width:
+ * @animation: An animation.
+ *
+ * Queries the width of the bounding box of a pixbuf animation.
+ * 
+ * Return value: Width of the bounding box of the animation.
+ **/
+int
+gdk_pixbuf_animation_get_width (GdkPixbufAnimation *animation)
+{
+        int width;
+        
+       g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), 0);
+
+        width = 0;
+        GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_size (animation,
+                                                              &width, NULL);
+        
+
+       return width;
+}
+
+/**
+ * gdk_pixbuf_animation_get_height:
+ * @animation: An animation.
+ *
+ * Queries the height of the bounding box of a pixbuf animation.
+ * 
+ * Return value: Height of the bounding box of the animation.
+ **/
+int
+gdk_pixbuf_animation_get_height (GdkPixbufAnimation *animation)
+{
+        int height;
+        
+       g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), 0);
+
+        height = 0;
+        GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_size (animation,
+                                                              NULL, &height);
+        
+
+       return height;
+}
+
+
+/**
+ * gdk_pixbuf_animation_get_iter:
+ * @animation: a #GdkPixbufAnimation
+ * @start_time: time when the animation starts playing
+ * 
+ * Get an iterator for displaying an animation. The iterator provides
+ * the frames that should be displayed at a given time.
+ * It should be freed after use with g_object_unref().
+ * 
+ * @start_time would normally come from g_get_current_time(), and
+ * marks the beginning of animation playback. After creating an
+ * iterator, you should immediately display the pixbuf returned by
+ * gdk_pixbuf_animation_iter_get_pixbuf(). Then, you should install a
+ * timeout (with g_timeout_add()) or by some other mechanism ensure
+ * that you'll update the image after
+ * gdk_pixbuf_animation_iter_get_delay_time() milliseconds. Each time
+ * the image is updated, you should reinstall the timeout with the new,
+ * possibly-changed delay time.
+ *
+ * As a shortcut, if @start_time is %NULL, the result of
+ * g_get_current_time() will be used automatically.
+ *
+ * To update the image (i.e. possibly change the result of
+ * gdk_pixbuf_animation_iter_get_pixbuf() to a new frame of the animation),
+ * call gdk_pixbuf_animation_iter_advance().
+ *
+ * If you're using #GdkPixbufLoader, in addition to updating the image
+ * after the delay time, you should also update it whenever you
+ * receive the area_updated signal and
+ * gdk_pixbuf_animation_iter_on_currently_loading_frame() returns
+ * %TRUE. In this case, the frame currently being fed into the loader
+ * has received new data, so needs to be refreshed. The delay time for
+ * a frame may also be modified after an area_updated signal, for
+ * example if the delay time for a frame is encoded in the data after
+ * the frame itself. So your timeout should be reinstalled after any
+ * area_updated signal.
+ *
+ * A delay time of -1 is possible, indicating "infinite."
+ * 
+ * Return value: (transfer full): an iterator to move over the animation
+ **/
+GdkPixbufAnimationIter*
+gdk_pixbuf_animation_get_iter (GdkPixbufAnimation *animation,
+                               const GTimeVal     *start_time)
+{
+        GTimeVal val;
+        
+        g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), NULL);
+
+
+        if (start_time)
+                val = *start_time;
+        else
+                g_get_current_time (&val);
+        
+        return GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_iter (animation, &val);
+}
+
+G_DEFINE_TYPE (GdkPixbufAnimationIter, gdk_pixbuf_animation_iter, G_TYPE_OBJECT);
+
+static void
+gdk_pixbuf_animation_iter_class_init (GdkPixbufAnimationIterClass *klass)
+{
+}
+
+static void
+gdk_pixbuf_animation_iter_init (GdkPixbufAnimationIter *iter)
+{
+}
+
+/**
+ * gdk_pixbuf_animation_iter_get_delay_time:
+ * @iter: an animation iterator
+ *
+ * Gets the number of milliseconds the current pixbuf should be displayed,
+ * or -1 if the current pixbuf should be displayed forever. g_timeout_add()
+ * conveniently takes a timeout in milliseconds, so you can use a timeout
+ * to schedule the next update.
+ *
+ * Return value: delay time in milliseconds (thousandths of a second)
+ **/
+int
+gdk_pixbuf_animation_iter_get_delay_time (GdkPixbufAnimationIter *iter)
+{
+        g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), -1);
+        g_return_val_if_fail (GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->get_delay_time, -1);
+
+        return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->get_delay_time (iter);
+}
+
+/**
+ * gdk_pixbuf_animation_iter_get_pixbuf:
+ * @iter: an animation iterator
+ * 
+ * Gets the current pixbuf which should be displayed; the pixbuf will
+ * be the same size as the animation itself
+ * (gdk_pixbuf_animation_get_width(), gdk_pixbuf_animation_get_height()). 
+ * This pixbuf should be displayed for 
+ * gdk_pixbuf_animation_iter_get_delay_time() milliseconds.  The caller
+ * of this function does not own a reference to the returned pixbuf;
+ * the returned pixbuf will become invalid when the iterator advances
+ * to the next frame, which may happen anytime you call
+ * gdk_pixbuf_animation_iter_advance(). Copy the pixbuf to keep it
+ * (don't just add a reference), as it may get recycled as you advance
+ * the iterator.
+ *
+ * Return value: (transfer none): the pixbuf to be displayed
+ **/
+GdkPixbuf*
+gdk_pixbuf_animation_iter_get_pixbuf (GdkPixbufAnimationIter *iter)
+{
+        g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), NULL);
+        g_return_val_if_fail (GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->get_pixbuf, NULL);
+
+        return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->get_pixbuf (iter);
+}
+
+/**
+ * gdk_pixbuf_animation_iter_on_currently_loading_frame:
+ * @iter: a #GdkPixbufAnimationIter
+ *
+ * Used to determine how to respond to the area_updated signal on
+ * #GdkPixbufLoader when loading an animation. area_updated is emitted
+ * for an area of the frame currently streaming in to the loader. So if
+ * you're on the currently loading frame, you need to redraw the screen for
+ * the updated area.
+ *
+ * Return value: %TRUE if the frame we're on is partially loaded, or the last frame
+ **/
+gboolean
+gdk_pixbuf_animation_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter)
+{
+        g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), FALSE);
+        g_return_val_if_fail (GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->on_currently_loading_frame, FALSE);
+
+        return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->on_currently_loading_frame (iter);
+}
+
+/**
+ * gdk_pixbuf_animation_iter_advance:
+ * @iter: a #GdkPixbufAnimationIter
+ * @current_time: current time
+ *
+ * Possibly advances an animation to a new frame. Chooses the frame based
+ * on the start time passed to gdk_pixbuf_animation_get_iter().
+ *
+ * @current_time would normally come from g_get_current_time(), and
+ * must be greater than or equal to the time passed to
+ * gdk_pixbuf_animation_get_iter(), and must increase or remain
+ * unchanged each time gdk_pixbuf_animation_iter_get_pixbuf() is
+ * called. That is, you can't go backward in time; animations only
+ * play forward.
+ *
+ * As a shortcut, pass %NULL for the current time and g_get_current_time()
+ * will be invoked on your behalf. So you only need to explicitly pass
+ * @current_time if you're doing something odd like playing the animation
+ * at double speed.
+ *
+ * If this function returns %FALSE, there's no need to update the animation
+ * display, assuming the display had been rendered prior to advancing;
+ * if %TRUE, you need to call gdk_animation_iter_get_pixbuf() and update the
+ * display with the new pixbuf.
+ *
+ * Returns: %TRUE if the image may need updating
+ * 
+ **/
+gboolean
+gdk_pixbuf_animation_iter_advance (GdkPixbufAnimationIter *iter,
+                                   const GTimeVal         *current_time)
+{
+        GTimeVal val;
+
+        g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), FALSE);
+        g_return_val_if_fail (GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->advance, FALSE);
+
+        if (current_time)
+                val = *current_time;
+        else
+                g_get_current_time (&val);
+
+        return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->advance (iter, &val);
+}
+
+static void                    gdk_pixbuf_non_anim_finalize         (GObject            *object);
+static gboolean                gdk_pixbuf_non_anim_is_static_image  (GdkPixbufAnimation *animation);
+static GdkPixbuf*              gdk_pixbuf_non_anim_get_static_image (GdkPixbufAnimation *animation);
+static void                    gdk_pixbuf_non_anim_get_size         (GdkPixbufAnimation *anim,
+                                                                     int                *width,
+                                                                     int                *height);
+static GdkPixbufAnimationIter* gdk_pixbuf_non_anim_get_iter         (GdkPixbufAnimation *anim,
+                                                                     const GTimeVal     *start_time);
+
+G_DEFINE_TYPE (GdkPixbufNonAnim, gdk_pixbuf_non_anim, GDK_TYPE_PIXBUF_ANIMATION);
+
+static void
+gdk_pixbuf_non_anim_class_init (GdkPixbufNonAnimClass *klass)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+        GdkPixbufAnimationClass *anim_class = GDK_PIXBUF_ANIMATION_CLASS (klass);
+        
+        object_class->finalize = gdk_pixbuf_non_anim_finalize;
+
+        anim_class->is_static_image = gdk_pixbuf_non_anim_is_static_image;
+        anim_class->get_static_image = gdk_pixbuf_non_anim_get_static_image;
+        anim_class->get_size = gdk_pixbuf_non_anim_get_size;
+        anim_class->get_iter = gdk_pixbuf_non_anim_get_iter;
+}
+
+static void
+gdk_pixbuf_non_anim_init (GdkPixbufNonAnim *non_anim)
+{
+}
+
+static void
+gdk_pixbuf_non_anim_finalize (GObject *object)
+{
+        GdkPixbufNonAnim *non_anim = GDK_PIXBUF_NON_ANIM (object);
+
+        if (non_anim->pixbuf)
+                g_object_unref (non_anim->pixbuf);
+        
+        G_OBJECT_CLASS (gdk_pixbuf_non_anim_parent_class)->finalize (object);
+}
+
+GdkPixbufAnimation*
+gdk_pixbuf_non_anim_new (GdkPixbuf *pixbuf)
+{
+        GdkPixbufNonAnim *non_anim;
+
+        non_anim = g_object_new (GDK_TYPE_PIXBUF_NON_ANIM, NULL);
+
+        non_anim->pixbuf = pixbuf;
+
+        if (pixbuf)
+                g_object_ref (pixbuf);
+
+        return GDK_PIXBUF_ANIMATION (non_anim);
+}
+
+static gboolean
+gdk_pixbuf_non_anim_is_static_image  (GdkPixbufAnimation *animation)
+{
+
+        return TRUE;
+}
+
+static GdkPixbuf*
+gdk_pixbuf_non_anim_get_static_image (GdkPixbufAnimation *animation)
+{
+        GdkPixbufNonAnim *non_anim;
+
+        non_anim = GDK_PIXBUF_NON_ANIM (animation);
+
+        return non_anim->pixbuf;
+}
+
+static void
+gdk_pixbuf_non_anim_get_size (GdkPixbufAnimation *anim,
+                              int                *width,
+                              int                *height)
+{
+        GdkPixbufNonAnim *non_anim;
+
+        non_anim = GDK_PIXBUF_NON_ANIM (anim);
+
+        if (width)
+                *width = gdk_pixbuf_get_width (non_anim->pixbuf);
+
+        if (height)
+                *height = gdk_pixbuf_get_height (non_anim->pixbuf);
+}
+
+static GdkPixbufAnimationIter*
+gdk_pixbuf_non_anim_get_iter (GdkPixbufAnimation *anim,
+                              const GTimeVal     *start_time)
+{
+        GdkPixbufNonAnimIter *iter;
+
+        iter = g_object_new (GDK_TYPE_PIXBUF_NON_ANIM_ITER, NULL);
+
+        iter->non_anim = GDK_PIXBUF_NON_ANIM (anim);
+
+        g_object_ref (iter->non_anim);
+        
+        return GDK_PIXBUF_ANIMATION_ITER (iter);
+}
+
+static void       gdk_pixbuf_non_anim_iter_finalize                   (GObject                *object);
+static int        gdk_pixbuf_non_anim_iter_get_delay_time             (GdkPixbufAnimationIter *iter);
+static GdkPixbuf* gdk_pixbuf_non_anim_iter_get_pixbuf                 (GdkPixbufAnimationIter *iter);
+static gboolean   gdk_pixbuf_non_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter);
+static gboolean   gdk_pixbuf_non_anim_iter_advance                    (GdkPixbufAnimationIter *iter,
+                                                                       const GTimeVal         *current_time);
+
+G_DEFINE_TYPE (GdkPixbufNonAnimIter,
+               gdk_pixbuf_non_anim_iter,
+               GDK_TYPE_PIXBUF_ANIMATION_ITER);
+
+static void
+gdk_pixbuf_non_anim_iter_class_init (GdkPixbufNonAnimIterClass *klass)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+        GdkPixbufAnimationIterClass *anim_iter_class =
+                GDK_PIXBUF_ANIMATION_ITER_CLASS (klass);
+        
+        object_class->finalize = gdk_pixbuf_non_anim_iter_finalize;
+
+        anim_iter_class->get_delay_time = gdk_pixbuf_non_anim_iter_get_delay_time;
+        anim_iter_class->get_pixbuf = gdk_pixbuf_non_anim_iter_get_pixbuf;
+        anim_iter_class->on_currently_loading_frame = gdk_pixbuf_non_anim_iter_on_currently_loading_frame;
+        anim_iter_class->advance = gdk_pixbuf_non_anim_iter_advance;
+}
+
+static void
+gdk_pixbuf_non_anim_iter_init (GdkPixbufNonAnimIter *non_iter)
+{
+}
+
+static void
+gdk_pixbuf_non_anim_iter_finalize (GObject *object)
+{
+        GdkPixbufNonAnimIter *iter = GDK_PIXBUF_NON_ANIM_ITER (object);
+
+        g_object_unref (iter->non_anim);
+        
+        G_OBJECT_CLASS (gdk_pixbuf_non_anim_iter_parent_class)->finalize (object);
+}
+
+static int
+gdk_pixbuf_non_anim_iter_get_delay_time (GdkPixbufAnimationIter *iter)
+{
+        return -1; /* show only frame forever */
+}
+
+static GdkPixbuf*
+gdk_pixbuf_non_anim_iter_get_pixbuf (GdkPixbufAnimationIter *iter)
+{
+        return GDK_PIXBUF_NON_ANIM_ITER (iter)->non_anim->pixbuf;
+}
+
+
+static gboolean
+gdk_pixbuf_non_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter)
+{
+        return TRUE;
+}
+        
+static gboolean
+gdk_pixbuf_non_anim_iter_advance (GdkPixbufAnimationIter *iter,
+                                  const GTimeVal         *current_time)
+{
+
+        /* Advancing never requires a refresh */
+        return FALSE;
+}
diff --git a/gdk-pixbuf/gdk-pixbuf-animation.h b/gdk-pixbuf/gdk-pixbuf-animation.h
new file mode 100644 (file)
index 0000000..8213e94
--- /dev/null
@@ -0,0 +1,195 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* GdkPixbuf library - Animation support
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Authors: Mark Crichton <crichton@gimp.org>
+ *          Miguel de Icaza <miguel@gnu.org>
+ *          Federico Mena-Quintero <federico@gimp.org>
+ *          Havoc Pennington <hp@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#if defined(GDK_PIXBUF_DISABLE_SINGLE_INCLUDES) && !defined (GDK_PIXBUF_H_INSIDE) && !defined (GDK_PIXBUF_COMPILATION)
+#error "Only <gdk-pixbuf/gdk-pixbuf.h> can be included directly."
+#endif
+
+#ifndef GDK_PIXBUF_ANIMATION_H
+#define GDK_PIXBUF_ANIMATION_H
+
+#include <glib-object.h>
+#include <gdk-pixbuf/gdk-pixbuf-core.h>
+
+G_BEGIN_DECLS
+
+/* Animation support */
+
+/**
+ * GdkPixbufAnimation:
+ * 
+ * An opaque struct representing an animation.
+ */
+typedef struct _GdkPixbufAnimation GdkPixbufAnimation;
+
+
+/**
+ * GdkPixbufAnimationIter:
+ * 
+ * An opaque struct representing an iterator which points to a
+ * certain position in an animation.
+ */
+typedef struct _GdkPixbufAnimationIter GdkPixbufAnimationIter;
+
+#define GDK_TYPE_PIXBUF_ANIMATION              (gdk_pixbuf_animation_get_type ())
+#define GDK_PIXBUF_ANIMATION(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_ANIMATION, GdkPixbufAnimation))
+#define GDK_IS_PIXBUF_ANIMATION(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_ANIMATION))
+
+#define GDK_TYPE_PIXBUF_ANIMATION_ITER              (gdk_pixbuf_animation_iter_get_type ())
+#define GDK_PIXBUF_ANIMATION_ITER(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_ANIMATION_ITER, GdkPixbufAnimationIter))
+#define GDK_IS_PIXBUF_ANIMATION_ITER(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_ANIMATION_ITER))
+
+GType               gdk_pixbuf_animation_get_type        (void) G_GNUC_CONST;
+
+#ifndef __GTK_DOC_IGNORE__
+#ifdef G_OS_WIN32
+#define gdk_pixbuf_animation_new_from_file gdk_pixbuf_animation_new_from_file_utf8
+#endif
+#endif
+
+GdkPixbufAnimation *gdk_pixbuf_animation_new_from_file   (const char         *filename,
+                                                          GError            **error);
+
+#ifndef GDK_PIXBUF_DISABLE_DEPRECATED
+G_DEPRECATED_FOR(g_object_ref)
+GdkPixbufAnimation *gdk_pixbuf_animation_ref             (GdkPixbufAnimation *animation);
+G_DEPRECATED_FOR(g_object_unref)
+void                gdk_pixbuf_animation_unref           (GdkPixbufAnimation *animation);
+#endif
+
+int                 gdk_pixbuf_animation_get_width       (GdkPixbufAnimation *animation);
+int                 gdk_pixbuf_animation_get_height      (GdkPixbufAnimation *animation);
+gboolean            gdk_pixbuf_animation_is_static_image  (GdkPixbufAnimation *animation);
+GdkPixbuf          *gdk_pixbuf_animation_get_static_image (GdkPixbufAnimation *animation);
+
+GdkPixbufAnimationIter *gdk_pixbuf_animation_get_iter                        (GdkPixbufAnimation     *animation,
+                                                                              const GTimeVal         *start_time);
+GType                   gdk_pixbuf_animation_iter_get_type                   (void) G_GNUC_CONST;
+int                     gdk_pixbuf_animation_iter_get_delay_time             (GdkPixbufAnimationIter *iter);
+GdkPixbuf              *gdk_pixbuf_animation_iter_get_pixbuf                 (GdkPixbufAnimationIter *iter);
+gboolean                gdk_pixbuf_animation_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter);
+gboolean                gdk_pixbuf_animation_iter_advance                    (GdkPixbufAnimationIter *iter,
+                                                                              const GTimeVal         *current_time);
+
+
+#ifdef GDK_PIXBUF_ENABLE_BACKEND
+
+\f
+
+/**
+ * GdkPixbufAnimationClass:
+ * @parent_class: the parent class
+ * @is_static_image: returns whether the given animation is just a static image.
+ * @get_static_image: returns a static image representing the given animation.
+ * @get_size: fills @width and @height with the frame size of the animation.
+ * @get_iter: returns an iterator for the given animation.
+ * 
+ * Modules supporting animations must derive a type from 
+ * #GdkPixbufAnimation, providing suitable implementations of the 
+ * virtual functions.
+ */
+typedef struct _GdkPixbufAnimationClass GdkPixbufAnimationClass;
+
+#define GDK_PIXBUF_ANIMATION_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_ANIMATION, GdkPixbufAnimationClass))
+#define GDK_IS_PIXBUF_ANIMATION_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_ANIMATION))
+#define GDK_PIXBUF_ANIMATION_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_ANIMATION, GdkPixbufAnimationClass))
+
+/* Private part of the GdkPixbufAnimation structure */
+struct _GdkPixbufAnimation {
+        GObject parent_instance;
+
+};
+
+struct _GdkPixbufAnimationClass {
+        GObjectClass parent_class;
+
+        /*< public >*/
+
+        gboolean                (*is_static_image)  (GdkPixbufAnimation *anim);
+
+        GdkPixbuf*              (*get_static_image) (GdkPixbufAnimation *anim);
+        
+        void                    (*get_size) (GdkPixbufAnimation *anim,
+                                             int                 *width,
+                                             int                 *height);
+        
+        GdkPixbufAnimationIter* (*get_iter) (GdkPixbufAnimation *anim,
+                                             const GTimeVal     *start_time);
+
+};
+
+\f
+
+/**
+ * GdkPixbufAnimationIterClass:
+ * @parent_class: the parent class
+ * @get_delay_time: returns the time in milliseconds that the current frame 
+ *  should be shown.
+ * @get_pixbuf: returns the current frame.
+ * @on_currently_loading_frame: returns whether the current frame of @iter is 
+ *  being loaded.
+ * @advance: advances the iterator to @current_time, possibly changing the 
+ *  current frame.
+ * 
+ * Modules supporting animations must derive a type from 
+ * #GdkPixbufAnimationIter, providing suitable implementations of the 
+ * virtual functions.
+ */
+typedef struct _GdkPixbufAnimationIterClass GdkPixbufAnimationIterClass;
+
+#define GDK_PIXBUF_ANIMATION_ITER_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_ANIMATION_ITER, GdkPixbufAnimationIterClass))
+#define GDK_IS_PIXBUF_ANIMATION_ITER_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_ANIMATION_ITER))
+#define GDK_PIXBUF_ANIMATION_ITER_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_ANIMATION_ITER, GdkPixbufAnimationIterClass))
+
+struct _GdkPixbufAnimationIter {
+        GObject parent_instance;
+
+};
+
+struct _GdkPixbufAnimationIterClass {
+        GObjectClass parent_class;
+
+        /*< public >*/
+
+        int        (*get_delay_time)   (GdkPixbufAnimationIter *iter);
+
+        GdkPixbuf* (*get_pixbuf)       (GdkPixbufAnimationIter *iter);
+
+        gboolean   (*on_currently_loading_frame) (GdkPixbufAnimationIter *iter);
+
+        gboolean   (*advance)          (GdkPixbufAnimationIter *iter,
+                                        const GTimeVal         *current_time);
+};
+      
+
+GType               gdk_pixbuf_non_anim_get_type (void) G_GNUC_CONST;
+GdkPixbufAnimation* gdk_pixbuf_non_anim_new (GdkPixbuf *pixbuf);
+
+#endif /* GDK_PIXBUF_ENABLE_BACKEND */
+
+G_END_DECLS
+
+#endif /* GDK_PIXBUF_ANIMATION_H */
diff --git a/gdk-pixbuf/gdk-pixbuf-core.h b/gdk-pixbuf/gdk-pixbuf-core.h
new file mode 100644 (file)
index 0000000..d777286
--- /dev/null
@@ -0,0 +1,481 @@
+/* GdkPixbuf library - GdkPixbuf data structure
+ *
+ * Copyright (C) 2003 The Free Software Foundation
+ *
+ * Authors: Mark Crichton <crichton@gimp.org>
+ *          Miguel de Icaza <miguel@gnu.org>
+ *          Federico Mena-Quintero <federico@gimp.org>
+ *          Havoc Pennington <hp@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#if defined(GDK_PIXBUF_DISABLE_SINGLE_INCLUDES) && !defined (GDK_PIXBUF_H_INSIDE) && !defined (GDK_PIXBUF_COMPILATION)
+#error "Only <gdk-pixbuf/gdk-pixbuf.h> can be included directly."
+#endif
+
+#ifndef GDK_PIXBUF_CORE_H
+#define GDK_PIXBUF_CORE_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+/**
+ * SECTION:gdk-pixbuf
+ * @Short_description: Information that describes an image.
+ * @Title: The GdkPixbuf Structure
+ * 
+ * 
+ * The #GdkPixbuf structure contains
+ * information that describes an image in memory.
+ * 
+ * 
+ * <section id="image-data">
+ * <title>Image Data</title>
+ * <para>
+ * Image data in a pixbuf is stored in memory in uncompressed,
+ * packed format.  Rows in the image are stored top to bottom, and
+ * in each row pixels are stored from left to right.  There may be
+ * padding at the end of a row.  The "rowstride" value of a pixbuf,
+ * as returned by gdk_pixbuf_get_rowstride(), indicates the number
+ * of bytes between rows.
+ * 
+ * 
+ * <example id="put-pixel">
+ * <title>put_pixel(<!-- -->) example</title>
+ * <para>
+ * 
+ * The following code illustrates a simple put_pixel(<!-- -->)
+ * function for RGB pixbufs with 8 bits per channel with an alpha
+ * channel.  It is not included in the gdk-pixbuf library for
+ * performance reasons; rather than making several function calls
+ * for each pixel, your own code can take shortcuts.
+ * 
+ * 
+ * <programlisting>
+ * static void
+ * put_pixel (GdkPixbuf *pixbuf, int x, int y, guchar red, guchar green, guchar blue, guchar alpha)
+ * {
+ *   int width, height, rowstride, n_channels;
+ *   guchar *pixels, *p;
+ * 
+ *   n_channels = gdk_pixbuf_get_n_channels (pixbuf);
+ * 
+ *   g_assert (gdk_pixbuf_get_colorspace (pixbuf) == GDK_COLORSPACE_RGB);
+ *   g_assert (gdk_pixbuf_get_bits_per_sample (pixbuf) == 8);
+ *   g_assert (gdk_pixbuf_get_has_alpha (pixbuf));
+ *   g_assert (n_channels == 4);
+ * 
+ *   width = gdk_pixbuf_get_width (pixbuf);
+ *   height = gdk_pixbuf_get_height (pixbuf);
+ * 
+ *   g_assert (x >= 0 && x < width);
+ *   g_assert (y >= 0 && y < height);
+ * 
+ *   rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ *   pixels = gdk_pixbuf_get_pixels (pixbuf);
+ * 
+ *   p = pixels + y * rowstride + x * n_channels;
+ *   p[0] = red;
+ *   p[1] = green;
+ *   p[2] = blue;
+ *   p[3] = alpha;
+ * }
+ * </programlisting>
+ * 
+ * This function will not work for pixbufs with images that are
+ * other than 8 bits per sample or channel, but it will work for
+ * most of the pixbufs that GTK+ uses.
+ * </para>
+ * </example>
+ * 
+ * <note>
+ * If you are doing memcpy() of raw pixbuf data, note that the
+ * last row in the pixbuf may not be as wide as the full
+ * rowstride, but rather just as wide as the pixel data needs to
+ * be.  That is, it is unsafe to do <literal>memcpy (dest,
+ * pixels, rowstride * height)</literal> to copy a whole pixbuf.
+ * Use gdk_pixbuf_copy() instead, or compute the width in bytes
+ * of the last row as <literal>width * ((n_channels *
+ * bits_per_sample + 7) / 8)</literal>.
+ * </note>
+ * </para>
+ * </section>
+ */
+
+
+/**
+ * GdkPixbufAlphaMode:
+ * @GDK_PIXBUF_ALPHA_BILEVEL: A bilevel clipping mask (black and white)
+ *  will be created and used to draw the image.  Pixels below 0.5 opacity
+ *  will be considered fully transparent, and all others will be
+ *  considered fully opaque.
+ * @GDK_PIXBUF_ALPHA_FULL: For now falls back to #GDK_PIXBUF_ALPHA_BILEVEL.
+ *  In the future it will do full alpha compositing.
+ * 
+ * These values can be passed to
+ * gdk_pixbuf_render_to_drawable_alpha() to control how the alpha
+ * channel of an image should be handled.  This function can create a
+ * bilevel clipping mask (black and white) and use it while painting
+ * the image.  In the future, when the X Window System gets an alpha
+ * channel extension, it will be possible to do full alpha
+ * compositing onto arbitrary drawables.  For now both cases fall
+ * back to a bilevel clipping mask.
+ */
+typedef enum
+{
+        GDK_PIXBUF_ALPHA_BILEVEL,
+        GDK_PIXBUF_ALPHA_FULL
+} GdkPixbufAlphaMode;
+
+/**
+ * GdkColorspace:
+ * @GDK_COLORSPACE_RGB: Indicates a red/green/blue additive color space.
+ * 
+ * This enumeration defines the color spaces that are supported by
+ * the &gdk-pixbuf; library.  Currently only RGB is supported.
+ */
+/* Note that these values are encoded in inline pixbufs
+ * as ints, so don't reorder them
+ */
+typedef enum {
+       GDK_COLORSPACE_RGB
+} GdkColorspace;
+
+/* All of these are opaque structures */
+
+/**
+ * GdkPixbuf:
+ * 
+ * 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 (the number of bytes between the start of
+ * one row and the start of the next). 
+ */
+typedef struct _GdkPixbuf GdkPixbuf;
+
+#define GDK_TYPE_PIXBUF              (gdk_pixbuf_get_type ())
+#define GDK_PIXBUF(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF, GdkPixbuf))
+#define GDK_IS_PIXBUF(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF))
+
+
+/**
+ * GdkPixbufDestroyNotify:
+ * @pixels: (array) (element-type guint8): The pixel array of the pixbuf
+ *   that is being finalized.
+ * @data: (closure): User closure data.
+ * 
+ * A function of this type is responsible for freeing the pixel array
+ * of a pixbuf.  The gdk_pixbuf_new_from_data() function lets you
+ * pass in a pre-allocated pixel array so that a pixbuf can be
+ * created from it; in this case you will need to pass in a function
+ * of #GdkPixbufDestroyNotify so that the pixel data can be freed
+ * when the pixbuf is finalized.
+ */
+typedef void (* GdkPixbufDestroyNotify) (guchar *pixels, gpointer data);
+
+/**
+ * GDK_PIXBUF_ERROR:
+ * 
+ * Error domain used for pixbuf operations. Indicates that the error code
+ * will be in the #GdkPixbufError enumeration. See #GError for
+ * information on error domains and error codes.
+ */
+#define GDK_PIXBUF_ERROR gdk_pixbuf_error_quark ()
+
+/**
+ * GdkPixbufError:
+ * @GDK_PIXBUF_ERROR_CORRUPT_IMAGE: An image file was broken somehow.
+ * @GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY: Not enough memory.
+ * @GDK_PIXBUF_ERROR_BAD_OPTION: A bad option was passed to a pixbuf save module.
+ * @GDK_PIXBUF_ERROR_UNKNOWN_TYPE: Unknown image type.
+ * @GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION: Don't know how to perform the
+ *  given operation on the type of image at hand.
+ * @GDK_PIXBUF_ERROR_FAILED: Generic failure code, something went wrong.
+ * 
+ * An error code in the #GDK_PIXBUF_ERROR domain. Many &gdk-pixbuf;
+ * operations can cause errors in this domain, or in the #G_FILE_ERROR
+ * domain.
+ */
+typedef enum {
+        /* image data hosed */
+        GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+        /* no mem to load image */
+        GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+        /* bad option passed to save routine */
+        GDK_PIXBUF_ERROR_BAD_OPTION,
+        /* unsupported image type (sort of an ENOSYS) */
+        GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+        /* unsupported operation (load, save) for image type */
+        GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
+        GDK_PIXBUF_ERROR_FAILED
+} GdkPixbufError;
+
+GQuark gdk_pixbuf_error_quark (void);
+
+\f
+
+GType gdk_pixbuf_get_type (void) G_GNUC_CONST;
+
+/* Reference counting */
+
+#ifndef GDK_PIXBUF_DISABLE_DEPRECATED
+G_DEPRECATED_FOR(g_object_ref)
+GdkPixbuf *gdk_pixbuf_ref      (GdkPixbuf *pixbuf);
+G_DEPRECATED_FOR(g_object_unref)
+void       gdk_pixbuf_unref    (GdkPixbuf *pixbuf);
+#endif
+
+/* GdkPixbuf accessors */
+
+GdkColorspace gdk_pixbuf_get_colorspace      (const GdkPixbuf *pixbuf);
+int           gdk_pixbuf_get_n_channels      (const GdkPixbuf *pixbuf);
+gboolean      gdk_pixbuf_get_has_alpha       (const GdkPixbuf *pixbuf);
+int           gdk_pixbuf_get_bits_per_sample (const GdkPixbuf *pixbuf);
+guchar       *gdk_pixbuf_get_pixels          (const GdkPixbuf *pixbuf);
+int           gdk_pixbuf_get_width           (const GdkPixbuf *pixbuf);
+int           gdk_pixbuf_get_height          (const GdkPixbuf *pixbuf);
+int           gdk_pixbuf_get_rowstride       (const GdkPixbuf *pixbuf);
+gsize         gdk_pixbuf_get_byte_length     (const GdkPixbuf *pixbuf);
+
+guchar       *gdk_pixbuf_get_pixels_with_length (const GdkPixbuf *pixbuf,
+                                                 guint           *length);
+
+
+\f
+
+/* Create a blank pixbuf with an optimal rowstride and a new buffer */
+GdkPixbuf *gdk_pixbuf_new (GdkColorspace colorspace, gboolean has_alpha, int bits_per_sample,
+                          int width, int height);
+
+/* Copy a pixbuf */
+
+GdkPixbuf *gdk_pixbuf_copy (const GdkPixbuf *pixbuf);
+
+/* Create a pixbuf which points to the pixels of another pixbuf */
+GdkPixbuf *gdk_pixbuf_new_subpixbuf (GdkPixbuf *src_pixbuf,
+                                     int        src_x,
+                                     int        src_y,
+                                     int        width,
+                                     int        height);
+
+/* Simple loading */
+
+#ifndef __GTK_DOC_IGNORE__
+#ifdef G_OS_WIN32
+/* DLL ABI stability hack. */
+#define gdk_pixbuf_new_from_file gdk_pixbuf_new_from_file_utf8
+#define gdk_pixbuf_new_from_file_at_size gdk_pixbuf_new_from_file_at_size_utf8
+#define gdk_pixbuf_new_from_file_at_scale gdk_pixbuf_new_from_file_at_scale_utf8
+#endif
+#endif
+
+GdkPixbuf *gdk_pixbuf_new_from_file (const char *filename,
+                                     GError    **error);
+GdkPixbuf *gdk_pixbuf_new_from_file_at_size (const char *filename,
+                                            int         width, 
+                                            int         height,
+                                            GError    **error);
+GdkPixbuf *gdk_pixbuf_new_from_file_at_scale (const char *filename,
+                                             int         width, 
+                                             int         height,
+                                             gboolean    preserve_aspect_ratio,
+                                             GError    **error);
+GdkPixbuf *gdk_pixbuf_new_from_resource (const char *resource_path,
+                                        GError    **error);
+GdkPixbuf *gdk_pixbuf_new_from_resource_at_scale (const char *resource_path,
+                                                 int         width,
+                                                 int         height,
+                                                 gboolean    preserve_aspect_ratio,
+                                                 GError    **error);
+
+GdkPixbuf *gdk_pixbuf_new_from_data (const guchar *data,
+                                    GdkColorspace colorspace,
+                                    gboolean has_alpha,
+                                    int bits_per_sample,
+                                    int width, int height,
+                                    int rowstride,
+                                    GdkPixbufDestroyNotify destroy_fn,
+                                    gpointer destroy_fn_data);
+
+GdkPixbuf *gdk_pixbuf_new_from_xpm_data (const char **data);
+GdkPixbuf* gdk_pixbuf_new_from_inline  (gint          data_length,
+                                        const guint8 *data,
+                                        gboolean      copy_pixels,
+                                        GError      **error);
+       
+/* Mutations */
+void       gdk_pixbuf_fill              (GdkPixbuf    *pixbuf,
+                                         guint32       pixel);
+
+/* Saving */
+
+#ifndef __GTK_DOC_IGNORE__
+#ifdef G_OS_WIN32
+/* DLL ABI stability hack. */
+#define gdk_pixbuf_save gdk_pixbuf_save_utf8
+#define gdk_pixbuf_savev gdk_pixbuf_savev_utf8
+#endif
+#endif
+
+gboolean gdk_pixbuf_save           (GdkPixbuf  *pixbuf, 
+                                    const char *filename, 
+                                    const char *type, 
+                                    GError    **error,
+                                    ...) G_GNUC_NULL_TERMINATED;
+
+gboolean gdk_pixbuf_savev          (GdkPixbuf  *pixbuf, 
+                                    const char *filename, 
+                                    const char *type,
+                                    char      **option_keys,
+                                    char      **option_values,
+                                    GError    **error);
+
+/* Saving to a callback function */
+
+
+/**
+ * GdkPixbufSaveFunc:
+ * @buf: (array length=count) (element-type guint8): bytes to be written.
+ * @count: number of bytes in @buf. 
+ * @error: (out): A location to return an error.
+ * @data: (closure): user data passed to gdk_pixbuf_save_to_callback(). 
+ * 
+ * Specifies the type of the function passed to
+ * gdk_pixbuf_save_to_callback().  It is called once for each block of
+ * bytes that is "written" by gdk_pixbuf_save_to_callback().  If
+ * successful it should return %TRUE.  If an error occurs it should set
+ * @error and return %FALSE, in which case gdk_pixbuf_save_to_callback()
+ * will fail with the same error.
+ * 
+ * Since: 2.4
+ * Returns: %TRUE if successful, %FALSE (with @error set) if failed.
+ */
+
+typedef gboolean (*GdkPixbufSaveFunc)   (const gchar *buf,
+                                        gsize count,
+                                        GError **error,
+                                        gpointer data);
+
+gboolean gdk_pixbuf_save_to_callback    (GdkPixbuf  *pixbuf,
+                                        GdkPixbufSaveFunc save_func,
+                                        gpointer user_data,
+                                        const char *type, 
+                                        GError    **error,
+                                        ...) G_GNUC_NULL_TERMINATED;
+
+gboolean gdk_pixbuf_save_to_callbackv   (GdkPixbuf  *pixbuf, 
+                                        GdkPixbufSaveFunc save_func,
+                                        gpointer user_data,
+                                        const char *type,
+                                        char      **option_keys,
+                                        char      **option_values,
+                                        GError    **error);
+
+/* Saving into a newly allocated char array */
+
+gboolean gdk_pixbuf_save_to_buffer      (GdkPixbuf  *pixbuf,
+                                        gchar     **buffer,
+                                        gsize      *buffer_size,
+                                        const char *type, 
+                                        GError    **error,
+                                        ...) G_GNUC_NULL_TERMINATED;
+
+gboolean gdk_pixbuf_save_to_bufferv     (GdkPixbuf  *pixbuf,
+                                        gchar     **buffer,
+                                        gsize      *buffer_size,
+                                        const char *type, 
+                                        char      **option_keys,
+                                        char      **option_values,
+                                        GError    **error);
+
+GdkPixbuf *gdk_pixbuf_new_from_stream   (GInputStream   *stream,
+                                        GCancellable   *cancellable,
+                                         GError        **error);
+
+void gdk_pixbuf_new_from_stream_async (GInputStream        *stream,
+                                      GCancellable        *cancellable,
+                                      GAsyncReadyCallback  callback,
+                                      gpointer             user_data);
+
+GdkPixbuf *gdk_pixbuf_new_from_stream_finish (GAsyncResult  *async_result,
+                                             GError       **error);
+
+GdkPixbuf *gdk_pixbuf_new_from_stream_at_scale   (GInputStream   *stream,
+                                                  gint            width,
+                                                  gint            height,
+                                                  gboolean        preserve_aspect_ratio,
+                                                 GCancellable   *cancellable,
+                                                  GError        **error);
+
+void gdk_pixbuf_new_from_stream_at_scale_async (GInputStream        *stream,
+                                               gint                 width,
+                                               gint                 height,
+                                               gboolean             preserve_aspect_ratio,
+                                               GCancellable        *cancellable,
+                                               GAsyncReadyCallback  callback,
+                                               gpointer             user_data);
+
+gboolean   gdk_pixbuf_save_to_stream    (GdkPixbuf      *pixbuf,
+                                         GOutputStream  *stream,
+                                         const char     *type,
+                                        GCancellable   *cancellable,
+                                         GError        **error,
+                                         ...);
+
+void gdk_pixbuf_save_to_stream_async (GdkPixbuf           *pixbuf,
+                                     GOutputStream       *stream,
+                                     const gchar         *type,
+                                     GCancellable        *cancellable,
+                                     GAsyncReadyCallback  callback,
+                                     gpointer             user_data,
+                                     ...);
+
+gboolean gdk_pixbuf_save_to_stream_finish (GAsyncResult  *async_result,
+                                          GError       **error);
+
+/* Adding an alpha channel */
+GdkPixbuf *gdk_pixbuf_add_alpha (const GdkPixbuf *pixbuf, gboolean substitute_color,
+                                guchar r, guchar g, guchar b);
+
+/* Copy an area of a pixbuf onto another one */
+void gdk_pixbuf_copy_area (const GdkPixbuf *src_pixbuf,
+                          int src_x, int src_y,
+                          int width, int height,
+                          GdkPixbuf *dest_pixbuf,
+                          int dest_x, int dest_y);
+
+/* Brighten/darken and optionally make it pixelated-looking */
+void gdk_pixbuf_saturate_and_pixelate (const GdkPixbuf *src,
+                                       GdkPixbuf       *dest,
+                                       gfloat           saturation,
+                                       gboolean         pixelate);
+
+/* Transform an image to agree with its embedded orientation option / tag */
+GdkPixbuf *gdk_pixbuf_apply_embedded_orientation (GdkPixbuf *src);
+
+const gchar * gdk_pixbuf_get_option (GdkPixbuf   *pixbuf,
+                                              const gchar *key);
+
+
+G_END_DECLS
+
+
+#endif /* GDK_PIXBUF_CORE_H */
diff --git a/gdk-pixbuf/gdk-pixbuf-csource.1 b/gdk-pixbuf/gdk-pixbuf-csource.1
new file mode 100644 (file)
index 0000000..d992921
--- /dev/null
@@ -0,0 +1,91 @@
+.TH GDK-PIXBUF-CSOURCE 1 "04 Sep 2001"
+.SH NAME
+gdk-pixbuf-csource \- C code generation utility for GdkPixbuf images
+.SH SYNOPSIS
+
+\fBgdk-pixbuf-csource\fP [\fIoptions\fP] [\fIimage\fP]
+.br
+\fBgdk-pixbuf-csource\fP [\fIoptions\fP] \fI--build-list\fP [[\fIname image\fP]...]
+
+.SH DESCRIPTION
+\fBgdk-pixbuf-csource\fP is a small utility that generates C code containing
+images, useful for compiling images directly into programs.
+
+.SH INVOCATION
+
+\fBgdk-pixbuf-csource\fP either takes as input one image file name to generate code
+for, or, using the \fI--build-list\fP option, a list of (\fIname\fP, \fIimage\fP)
+pairs to generate code for a list of images into named variables.
+
+.SS Options
+.TP
+\fI--stream
+Generate pixbuf data stream (a single string containing a serialized
+GdkPixdata structure in network byte order).
+
+.TP
+\fI--struct
+Generate GdkPixdata structure (needs the GdkPixdata structure definition from
+gdk-pixdata.h).
+
+.TP
+\fI--macros
+Generate *_ROWSTRIDE, *_WIDTH, *_HEIGHT, *_BYTES_PER_PIXEL and
+*_RLE_PIXEL_DATA or *_PIXEL_DATA macro definitions for the image.
+
+.TP
+\fI--rle
+Enables run-length encoding for the generated pixel data (default).
+
+.TP
+\fI--raw
+Disables run-length encoding for the generated pixel data.
+
+.TP
+\fI--extern
+Generate extern symbols.
+
+.TP
+\fI--static
+Generate static symbols (default).
+
+.TP
+\fI--decoder
+Provide a *_RUN_LENGTH_DECODE(image_buf, rle_data, size, bpp) macro definition
+to decode run-length encoded image data.
+
+.TP
+\fI--name=identifier
+Specifies the identifier name (prefix) for the generated variables or
+macros (useful only if \fI--build-list\fP was not specified).
+
+.TP
+\fI--build-list
+Enables (\fIname\fP, \fIimage\fP) pair parsing mode.
+
+.TP
+\fI-h, --help\fP 
+Print brief help and exit.
+
+.TP
+\fI-v, --version\fP
+Print version and exit.
+
+.TP
+\fI--g-fatal-warnings
+Make warnings fatal (causes the program to abort).
+
+.PP
+
+.SH SEE ALSO
+The \fIGdkPixbuf\fP documentation, shipped with the \fIGtk+\fP distribution,
+available from \fIhttp://www.gtk.org\fP.
+
+.SH BUGS 
+None known yet.
+
+.SH AUTHOR
+.B gdk-pixbuf-csource
+was written by Tim Janik <timj@gtk.org>.
+.PP
+This manual page was provided by Tim Janik <timj@gtk.org>.
diff --git a/gdk-pixbuf/gdk-pixbuf-csource.c b/gdk-pixbuf/gdk-pixbuf-csource.c
new file mode 100644 (file)
index 0000000..78af373
--- /dev/null
@@ -0,0 +1,301 @@
+/* Gdk-Pixbuf-CSource - GdkPixbuf based image CSource generator
+ * Copyright (C) 1999, 2001 Tim Janik
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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 "gdk-pixbuf.h"
+#include "gdk-pixdata.h"
+#include <glib/gprintf.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/* --- defines --- */
+#undef G_LOG_DOMAIN
+#define        G_LOG_DOMAIN    "Gdk-Pixbuf-CSource"
+#define PRG_NAME        "gdk-pixbuf-csource-3.0"
+#define PKG_NAME        "gdk-pixbuf"
+#define PKG_HTTP_HOME   "http://www.gtk.org"
+
+
+/* --- prototypes --- */
+static void    parse_args      (gint    *argc_p,
+                                gchar ***argv_p);
+static void    print_blurb     (FILE    *bout,
+                                gboolean print_help);
+
+
+/* --- variables --- */
+static guint    gen_type = GDK_PIXDATA_DUMP_PIXDATA_STREAM;
+static guint    gen_ctype = GDK_PIXDATA_DUMP_GTYPES | GDK_PIXDATA_DUMP_STATIC | GDK_PIXDATA_DUMP_CONST;
+static gboolean use_rle = TRUE;
+static gboolean with_decoder = FALSE;
+static gchar   *image_name = "my_pixbuf";
+static gboolean        build_list = FALSE;
+
+
+/* --- functions --- */
+static void
+print_csource (FILE *f_out,
+              GdkPixbuf *pixbuf)
+{
+  GdkPixdata pixdata;
+  gpointer free_me;
+  GString *gstring;
+
+  free_me = gdk_pixdata_from_pixbuf (&pixdata, pixbuf, use_rle);
+  gstring = gdk_pixdata_to_csource (&pixdata, image_name,
+                                   gen_type | gen_ctype |
+                                   (with_decoder ? GDK_PIXDATA_DUMP_RLE_DECODER : 0));
+
+  g_fprintf (f_out, "%s\n", gstring->str);
+
+  g_free (free_me);
+}
+
+int
+main (int   argc,
+      char *argv[])
+{
+  GdkPixbuf *pixbuf;
+  GError *error = NULL;
+  gchar *infilename;
+
+  /* initialize glib/GdkPixbuf */
+  g_type_init ();
+
+  /* parse args and do fast exits */
+  parse_args (&argc, &argv);
+
+  if (!build_list)
+    {
+      if (argc != 2)
+       {
+         print_blurb (stderr, TRUE);
+         return 1;
+       }
+      
+#ifdef G_OS_WIN32
+      infilename = g_locale_to_utf8 (argv[1], -1, NULL, NULL, NULL);
+#else
+      infilename = argv[1];
+#endif
+
+      pixbuf = gdk_pixbuf_new_from_file (infilename, &error);
+      if (!pixbuf)
+       {
+         g_fprintf (stderr, "failed to load \"%s\": %s\n",
+                  argv[1],
+                  error->message);
+         g_error_free (error);
+         return 1;
+       }
+      
+      print_csource (stdout, pixbuf);
+      g_object_unref (pixbuf);
+    }
+  else /* parse name, file pairs */
+    {
+      gchar **p = argv + 1;
+      guint j = argc - 1;
+      gboolean toggle = FALSE;
+
+      while (j--)
+       {
+#ifdef G_OS_WIN32
+         infilename = g_locale_to_utf8 (*p, -1, NULL, NULL, NULL);
+#else
+         infilename = *p;
+#endif
+
+         if (!toggle)
+           {
+             image_name = infilename;
+             p++;
+           }
+         else
+           {
+             pixbuf = gdk_pixbuf_new_from_file (infilename, &error);
+             if (!pixbuf)
+               {
+                 g_fprintf (stderr, "failed to load \"%s\": %s\n",
+                          *p,
+                          error->message);
+                 g_error_free (error);
+                 return 1;
+               }
+             print_csource (stdout, pixbuf);
+             g_object_unref (pixbuf);
+             p++;
+           }
+         toggle = !toggle;
+       }
+    }
+  
+  return 0;
+}
+
+static void
+parse_args (gint    *argc_p,
+           gchar ***argv_p)
+{
+  guint argc = *argc_p;
+  gchar **argv = *argv_p;
+  guint i, e;
+
+  for (i = 1; i < argc; i++)
+    {
+      if (strcmp ("--macros", argv[i]) == 0)
+       {
+         gen_type = GDK_PIXDATA_DUMP_MACROS;
+         argv[i] = NULL;
+       }
+      else if (strcmp ("--struct", argv[i]) == 0)
+       {
+         gen_type = GDK_PIXDATA_DUMP_PIXDATA_STRUCT;
+         argv[i] = NULL;
+       }
+      else if (strcmp ("--stream", argv[i]) == 0)
+       {
+         gen_type = GDK_PIXDATA_DUMP_PIXDATA_STREAM;
+         argv[i] = NULL;
+       }
+      else if (strcmp ("--rle", argv[i]) == 0)
+       {
+         use_rle = TRUE;
+         argv[i] = NULL;
+       }
+      else if (strcmp ("--raw", argv[i]) == 0)
+       {
+         use_rle = FALSE;
+         argv[i] = NULL;
+       }
+      else if (strcmp ("--extern", argv[i]) == 0)
+       {
+         gen_ctype &= ~GDK_PIXDATA_DUMP_STATIC;
+         argv[i] = NULL;
+       }
+      else if (strcmp ("--static", argv[i]) == 0)
+       {
+         gen_ctype |= GDK_PIXDATA_DUMP_STATIC;
+         argv[i] = NULL;
+       }
+      else if (strcmp ("--decoder", argv[i]) == 0)
+       {
+         with_decoder = TRUE;
+         argv[i] = NULL;
+       }
+      else if ((strcmp ("--name", argv[i]) == 0) ||
+              (strncmp ("--name=", argv[i], 7) == 0))
+       {
+         gchar *equal = argv[i] + 6;
+
+         if (*equal == '=')
+           image_name = g_strdup (equal + 1);
+         else if (i + 1 < argc)
+           {
+             image_name = g_strdup (argv[i + 1]);
+             argv[i] = NULL;
+             i += 1;
+           }
+         argv[i] = NULL;
+       }
+      else if (strcmp ("--build-list", argv[i]) == 0)
+       {
+         build_list = TRUE;
+         argv[i] = NULL;
+       }
+      else if (strcmp ("-h", argv[i]) == 0 ||
+              strcmp ("--help", argv[i]) == 0)
+       {
+         print_blurb (stderr, TRUE);
+         argv[i] = NULL;
+         exit (0);
+       }
+      else if (strcmp ("-v", argv[i]) == 0 ||
+              strcmp ("--version", argv[i]) == 0)
+       {
+         print_blurb (stderr, FALSE);
+         argv[i] = NULL;
+         exit (0);
+       }
+      else if (strcmp (argv[i], "--g-fatal-warnings") == 0)
+       {
+         GLogLevelFlags fatal_mask;
+
+         fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
+         fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
+         g_log_set_always_fatal (fatal_mask);
+
+         argv[i] = NULL;
+       }
+    }
+
+  e = 0;
+  for (i = 1; i < argc; i++)
+    {
+      if (e)
+       {
+         if (argv[i])
+           {
+             argv[e++] = argv[i];
+             argv[i] = NULL;
+           }
+       }
+      else if (!argv[i])
+       e = i;
+    }
+  if (e)
+    *argc_p = e;
+}
+
+static void
+print_blurb (FILE    *bout,
+            gboolean print_help)
+{
+  if (!print_help)
+    {
+      g_fprintf (bout, "%s version ", PRG_NAME);
+      g_fprintf (bout, "%s", GDK_PIXBUF_VERSION);
+      g_fprintf (bout, "\n");
+      g_fprintf (bout, "%s comes with ABSOLUTELY NO WARRANTY.\n", PRG_NAME);
+      g_fprintf (bout, "You may redistribute copies of %s under the terms of\n", PRG_NAME);
+      g_fprintf (bout, "the GNU Lesser General Public License which can be found in the\n");
+      g_fprintf (bout, "%s source package. Sources, examples and contact\n", PKG_NAME);
+      g_fprintf (bout, "information are available at %s\n", PKG_HTTP_HOME);
+    }
+  else
+    {
+      g_fprintf (bout, "Usage: %s [options] [image]\n", PRG_NAME);
+      g_fprintf (bout, "       %s [options] --build-list [[name image]...]\n", PRG_NAME);
+      g_fprintf (bout, "  --stream                   generate pixbuf data stream\n");
+      g_fprintf (bout, "  --struct                   generate GdkPixdata structure\n");
+      g_fprintf (bout, "  --macros                   generate image size/pixel macros\n");
+      g_fprintf (bout, "  --rle                      use one byte run-length-encoding\n");
+      g_fprintf (bout, "  --raw                      provide raw image data copy\n");
+      g_fprintf (bout, "  --extern                   generate extern symbols\n");
+      g_fprintf (bout, "  --static                   generate static symbols\n");
+      g_fprintf (bout, "  --decoder                  provide rle decoder\n");
+      g_fprintf (bout, "  --name=identifier          C macro/variable name\n");
+      g_fprintf (bout, "  --build-list               parse (name, image) pairs\n");
+      g_fprintf (bout, "  -h, --help                 show this help message\n");
+      g_fprintf (bout, "  -v, --version              print version informations\n");
+      g_fprintf (bout, "  --g-fatal-warnings         make warnings fatal (abort)\n");
+    }
+}
+
diff --git a/gdk-pixbuf/gdk-pixbuf-data.c b/gdk-pixbuf/gdk-pixbuf-data.c
new file mode 100644 (file)
index 0000000..a9334e8
--- /dev/null
@@ -0,0 +1,79 @@
+/* GdkPixbuf library - Image creation from in-memory buffers
+ *
+ * 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 Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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 "gdk-pixbuf.h"
+#include "gdk-pixbuf-private.h"
+#include <stdlib.h>
+#include <string.h>
+
+\f
+
+/**
+ * gdk_pixbuf_new_from_data:
+ * @data: (array): Image data in 8-bit/sample packed format
+ * @colorspace: Colorspace for the image data
+ * @has_alpha: Whether the data has an opacity channel
+ * @bits_per_sample: Number of bits per sample
+ * @width: Width of the image in pixels, must be > 0
+ * @height: Height of the image in pixels, must be > 0
+ * @rowstride: Distance in bytes between row starts
+ * @destroy_fn: (scope async) (allow-none): Function used to free the data when the pixbuf's reference count
+ * drops to zero, or %NULL if the data should not be freed
+ * @destroy_fn_data: (closure): Closure data to pass to the destroy notification function
+ * 
+ * Creates a new #GdkPixbuf out of in-memory image data.  Currently only RGB
+ * images with 8 bits per sample are supported.
+ * 
+ * Return value: (transfer full): A newly-created #GdkPixbuf structure with a reference count of 1.
+ **/
+GdkPixbuf *
+gdk_pixbuf_new_from_data (const guchar *data, GdkColorspace colorspace, gboolean has_alpha,
+                         int bits_per_sample, int width, int height, int rowstride,
+         GdkPixbufDestroyNotify destroy_fn, gpointer destroy_fn_data)
+{
+       GdkPixbuf *pixbuf;
+
+       /* Only 8-bit/sample RGB buffers are supported for now */
+
+       g_return_val_if_fail (data != NULL, NULL);
+       g_return_val_if_fail (colorspace == GDK_COLORSPACE_RGB, NULL);
+       g_return_val_if_fail (bits_per_sample == 8, NULL);
+       g_return_val_if_fail (width > 0, NULL);
+       g_return_val_if_fail (height > 0, NULL);
+
+       pixbuf = g_object_new (GDK_TYPE_PIXBUF, 
+                              "colorspace", colorspace,
+                              "n-channels", has_alpha ? 4 : 3,
+                              "bits-per-sample", bits_per_sample,
+                              "has-alpha", has_alpha ? TRUE : FALSE,
+                              "width", width,
+                              "height", height,
+                              "rowstride", rowstride,
+                              "pixels", data,
+                              NULL);
+        
+       pixbuf->destroy_fn = destroy_fn;
+       pixbuf->destroy_fn_data = destroy_fn_data;
+
+       return pixbuf;
+}
diff --git a/gdk-pixbuf/gdk-pixbuf-enum-types.c b/gdk-pixbuf/gdk-pixbuf-enum-types.c
new file mode 100644 (file)
index 0000000..b056e75
--- /dev/null
@@ -0,0 +1,97 @@
+
+/* Generated data (by glib-mkenums) */
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+/* enumerations from "gdk-pixbuf-core.h" */
+GType
+gdk_pixbuf_alpha_mode_get_type (void)
+{
+    static GType etype = 0;
+
+    if (G_UNLIKELY(etype == 0)) {
+        static const GEnumValue values[] = {
+            { GDK_PIXBUF_ALPHA_BILEVEL, "GDK_PIXBUF_ALPHA_BILEVEL", "bilevel" },
+            { GDK_PIXBUF_ALPHA_FULL, "GDK_PIXBUF_ALPHA_FULL", "full" },
+            { 0, NULL, NULL }
+        };
+        etype = g_enum_register_static (g_intern_static_string ("GdkPixbufAlphaMode"), values);
+    }
+    return etype;
+}
+
+GType
+gdk_colorspace_get_type (void)
+{
+    static GType etype = 0;
+
+    if (G_UNLIKELY(etype == 0)) {
+        static const GEnumValue values[] = {
+            { GDK_COLORSPACE_RGB, "GDK_COLORSPACE_RGB", "rgb" },
+            { 0, NULL, NULL }
+        };
+        etype = g_enum_register_static (g_intern_static_string ("GdkColorspace"), values);
+    }
+    return etype;
+}
+
+GType
+gdk_pixbuf_error_get_type (void)
+{
+    static GType etype = 0;
+
+    if (G_UNLIKELY(etype == 0)) {
+        static const GEnumValue values[] = {
+            { GDK_PIXBUF_ERROR_CORRUPT_IMAGE, "GDK_PIXBUF_ERROR_CORRUPT_IMAGE", "corrupt-image" },
+            { GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, "GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY", "insufficient-memory" },
+            { GDK_PIXBUF_ERROR_BAD_OPTION, "GDK_PIXBUF_ERROR_BAD_OPTION", "bad-option" },
+            { GDK_PIXBUF_ERROR_UNKNOWN_TYPE, "GDK_PIXBUF_ERROR_UNKNOWN_TYPE", "unknown-type" },
+            { GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION, "GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION", "unsupported-operation" },
+            { GDK_PIXBUF_ERROR_FAILED, "GDK_PIXBUF_ERROR_FAILED", "failed" },
+            { 0, NULL, NULL }
+        };
+        etype = g_enum_register_static (g_intern_static_string ("GdkPixbufError"), values);
+    }
+    return etype;
+}
+
+/* enumerations from "gdk-pixbuf-transform.h" */
+GType
+gdk_interp_type_get_type (void)
+{
+    static GType etype = 0;
+
+    if (G_UNLIKELY(etype == 0)) {
+        static const GEnumValue values[] = {
+            { GDK_INTERP_NEAREST, "GDK_INTERP_NEAREST", "nearest" },
+            { GDK_INTERP_TILES, "GDK_INTERP_TILES", "tiles" },
+            { GDK_INTERP_BILINEAR, "GDK_INTERP_BILINEAR", "bilinear" },
+            { GDK_INTERP_HYPER, "GDK_INTERP_HYPER", "hyper" },
+            { 0, NULL, NULL }
+        };
+        etype = g_enum_register_static (g_intern_static_string ("GdkInterpType"), values);
+    }
+    return etype;
+}
+
+GType
+gdk_pixbuf_rotation_get_type (void)
+{
+    static GType etype = 0;
+
+    if (G_UNLIKELY(etype == 0)) {
+        static const GEnumValue values[] = {
+            { GDK_PIXBUF_ROTATE_NONE, "GDK_PIXBUF_ROTATE_NONE", "none" },
+            { GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE, "GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE", "counterclockwise" },
+            { GDK_PIXBUF_ROTATE_UPSIDEDOWN, "GDK_PIXBUF_ROTATE_UPSIDEDOWN", "upsidedown" },
+            { GDK_PIXBUF_ROTATE_CLOCKWISE, "GDK_PIXBUF_ROTATE_CLOCKWISE", "clockwise" },
+            { 0, NULL, NULL }
+        };
+        etype = g_enum_register_static (g_intern_static_string ("GdkPixbufRotation"), values);
+    }
+    return etype;
+}
+
+
+/* Generated data ends here */
+
diff --git a/gdk-pixbuf/gdk-pixbuf-enum-types.c.template b/gdk-pixbuf/gdk-pixbuf-enum-types.c.template
new file mode 100644 (file)
index 0000000..9c7a972
--- /dev/null
@@ -0,0 +1,35 @@
+/*** BEGIN file-header ***/
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+/* enumerations from "@filename@" */
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType
+@enum_name@_get_type (void)
+{
+    static GType etype = 0;
+
+    if (G_UNLIKELY(etype == 0)) {
+        static const G@Type@Value values[] = {
+/*** END value-header ***/
+
+/*** BEGIN value-production ***/
+            { @VALUENAME@, "@VALUENAME@", "@valuenick@" },
+/*** END value-production ***/
+
+/*** BEGIN value-tail ***/
+            { 0, NULL, NULL }
+        };
+        etype = g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
+    }
+    return etype;
+}
+
+/*** END value-tail ***/
+
+/*** BEGIN file-tail ***/
+/*** END file-tail ***/
diff --git a/gdk-pixbuf/gdk-pixbuf-enum-types.h b/gdk-pixbuf/gdk-pixbuf-enum-types.h
new file mode 100644 (file)
index 0000000..3f7e3cd
--- /dev/null
@@ -0,0 +1,33 @@
+
+/* Generated data (by glib-mkenums) */
+
+#if defined(GDK_PIXBUF_DISABLE_SINGLE_INCLUDES) && !defined (GDK_PIXBUF_H_INSIDE) && !defined (GDK_PIXBUF_COMPILATION)
+#error "Only <gdk-pixbuf/gdk-pixbuf.h> can be included directly."
+#endif
+
+#ifndef __GDK_PIXBUF_ENUM_TYPES_H__
+#define __GDK_PIXBUF_ENUM_TYPES_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/* enumerations from "gdk-pixbuf-core.h" */
+GType gdk_pixbuf_alpha_mode_get_type (void) G_GNUC_CONST;
+#define GDK_TYPE_PIXBUF_ALPHA_MODE (gdk_pixbuf_alpha_mode_get_type ())
+GType gdk_colorspace_get_type (void) G_GNUC_CONST;
+#define GDK_TYPE_COLORSPACE (gdk_colorspace_get_type ())
+GType gdk_pixbuf_error_get_type (void) G_GNUC_CONST;
+#define GDK_TYPE_PIXBUF_ERROR (gdk_pixbuf_error_get_type ())
+
+/* enumerations from "gdk-pixbuf-transform.h" */
+GType gdk_interp_type_get_type (void) G_GNUC_CONST;
+#define GDK_TYPE_INTERP_TYPE (gdk_interp_type_get_type ())
+GType gdk_pixbuf_rotation_get_type (void) G_GNUC_CONST;
+#define GDK_TYPE_PIXBUF_ROTATION (gdk_pixbuf_rotation_get_type ())
+G_END_DECLS
+
+#endif /* __GDK_PIXBUF_ENUM_TYPES_H__ */
+
+/* Generated data ends here */
+
diff --git a/gdk-pixbuf/gdk-pixbuf-enum-types.h.template b/gdk-pixbuf/gdk-pixbuf-enum-types.h.template
new file mode 100644 (file)
index 0000000..4ecb716
--- /dev/null
@@ -0,0 +1,28 @@
+/*** BEGIN file-header ***/
+#if defined(GDK_PIXBUF_DISABLE_SINGLE_INCLUDES) && !defined (GDK_PIXBUF_H_INSIDE) && !defined (GDK_PIXBUF_COMPILATION)
+#error "Only <gdk-pixbuf/gdk-pixbuf.h> can be included directly."
+#endif
+
+#ifndef __GDK_PIXBUF_ENUM_TYPES_H__
+#define __GDK_PIXBUF_ENUM_TYPES_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+
+/* enumerations from "@filename@" */
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType @enum_name@_get_type (void) G_GNUC_CONST;
+#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ())
+/*** END value-header ***/
+
+/*** BEGIN file-tail ***/
+G_END_DECLS
+
+#endif /* __GDK_PIXBUF_ENUM_TYPES_H__ */
+/*** END file-tail ***/
diff --git a/gdk-pixbuf/gdk-pixbuf-features.h b/gdk-pixbuf/gdk-pixbuf-features.h
new file mode 100644 (file)
index 0000000..be8325a
--- /dev/null
@@ -0,0 +1,120 @@
+#if defined(GDK_PIXBUF_DISABLE_SINGLE_INCLUDES) && !defined (GDK_PIXBUF_H_INSIDE) && !defined (GDK_PIXBUF_COMPILATION)
+#error "Only <gdk-pixbuf/gdk-pixbuf.h> can be included directly."
+#endif
+
+#ifndef GDK_PIXBUF_FEATURES_H
+#define GDK_PIXBUF_FEATURES_H 1
+
+#include <glib.h>
+
+/**
+ * SECTION:initialization_versions
+ * @Short_description: 
+Library version numbers.
+ * @Title: Initialization and Versions
+ * 
+ * These macros and variables let you check the version of &gdk-pixbuf;
+ * you're linking against.
+ */
+
+/**
+ * GDK_PIXBUF_MAJOR:
+ * 
+ * Major version of &gdk-pixbuf; library, that is the first "0" in
+ * "0.8.0" for example.
+ */
+/**
+ * GDK_PIXBUF_MINOR:
+ * 
+ * Minor version of &gdk-pixbuf; library, that is the "8" in
+ * "0.8.0" for example.
+ */
+/**
+ * GDK_PIXBUF_MICRO:
+ * 
+ * Micro version of &gdk-pixbuf; library, that is the last "0" in
+ * "0.8.0" for example.
+ */
+/**
+ * GDK_PIXBUF_VERSION:
+ * 
+ * Contains the full version of the &gdk-pixbuf; header as a string.
+ * This is the version being compiled against; contrast with
+ * #gdk_pixbuf_version.
+ */
+
+#define GDK_PIXBUF_MAJOR (2)
+#define GDK_PIXBUF_MINOR (26)
+#define GDK_PIXBUF_MICRO (1)
+#define GDK_PIXBUF_VERSION "2.26.1"
+
+/* We prefix variable declarations so they can
+ * properly get exported/imported from Windows DLLs.
+ */
+#ifdef G_PLATFORM_WIN32
+#  ifdef GDK_PIXBUF_STATIC_COMPILATION
+#    define GDK_PIXBUF_VAR extern
+#  else /* !GDK_PIXBUF_STATIC_COMPILATION */
+#    ifdef GDK_PIXBUF_C_COMPILATION
+#      ifdef DLL_EXPORT
+#        define GDK_PIXBUF_VAR __declspec(dllexport)
+#      else /* !DLL_EXPORT */
+#        define GDK_PIXBUF_VAR extern
+#      endif /* !DLL_EXPORT */
+#    else /* !GDK_PIXBUF_C_COMPILATION */
+#      define GDK_PIXBUF_VAR extern __declspec(dllimport)
+#    endif /* !GDK_PIXBUF_C_COMPILATION */
+#  endif /* !GDK_PIXBUF_STATIC_COMPILATION */
+#else /* !G_PLATFORM_WIN32 */
+#  define GDK_PIXBUF_VAR extern
+#endif /* !G_PLATFORM_WIN32 */
+
+/**
+ * gdk_pixbuf_major_version:
+ * 
+ * The major version number of the &gdk-pixbuf; library.  (e.g. in 
+ * &gdk-pixbuf; version 1.2.5 this is 1.) 
+ * 
+ * 
+ * This variable is in the library, so represents the
+ * &gdk-pixbuf; library you have linked against. Contrast with the
+ * #GDK_PIXBUF_MAJOR macro, which represents the major version of the
+ * &gdk-pixbuf; headers you have included.
+ */
+/**
+ * gdk_pixbuf_minor_version:
+ * 
+ * The minor version number of the &gdk-pixbuf; library.  (e.g. in 
+ * &gdk-pixbuf; version 1.2.5 this is 2.) 
+ * 
+ * 
+ * This variable is in the library, so represents the
+ * &gdk-pixbuf; library you have linked against. Contrast with the
+ * #GDK_PIXBUF_MINOR macro, which represents the minor version of the
+ * &gdk-pixbuf; headers you have included.
+ */
+/**
+ * gdk_pixbuf_micro_version:
+ * 
+ * The micro version number of the &gdk-pixbuf; library.  (e.g. in 
+ * &gdk-pixbuf; version 1.2.5 this is 5.) 
+ * 
+ * 
+ * This variable is in the library, so represents the
+ * &gdk-pixbuf; library you have linked against. Contrast with the
+ * #GDK_PIXBUF_MICRO macro, which represents the micro version of the
+ * &gdk-pixbuf; headers you have included.
+ */
+/**
+ * gdk_pixbuf_version:
+ * 
+ * Contains the full version of the &gdk-pixbuf; library as a string.
+ * This is the version currently in use by a running program.
+ */
+
+GDK_PIXBUF_VAR const guint gdk_pixbuf_major_version;
+GDK_PIXBUF_VAR const guint gdk_pixbuf_minor_version;
+GDK_PIXBUF_VAR const guint gdk_pixbuf_micro_version;
+GDK_PIXBUF_VAR const char *gdk_pixbuf_version;
+
+#endif /* GDK_PIXBUF_FEATURES_H */
diff --git a/gdk-pixbuf/gdk-pixbuf-features.h.in b/gdk-pixbuf/gdk-pixbuf-features.h.in
new file mode 100644 (file)
index 0000000..9c31aa3
--- /dev/null
@@ -0,0 +1,120 @@
+#if defined(GDK_PIXBUF_DISABLE_SINGLE_INCLUDES) && !defined (GDK_PIXBUF_H_INSIDE) && !defined (GDK_PIXBUF_COMPILATION)
+#error "Only <gdk-pixbuf/gdk-pixbuf.h> can be included directly."
+#endif
+
+#ifndef GDK_PIXBUF_FEATURES_H
+#define GDK_PIXBUF_FEATURES_H 1
+
+#include <glib.h>
+
+/**
+ * SECTION:initialization_versions
+ * @Short_description: 
+Library version numbers.
+ * @Title: Initialization and Versions
+ * 
+ * These macros and variables let you check the version of &gdk-pixbuf;
+ * you're linking against.
+ */
+
+/**
+ * GDK_PIXBUF_MAJOR:
+ * 
+ * Major version of &gdk-pixbuf; library, that is the first "0" in
+ * "0.8.0" for example.
+ */
+/**
+ * GDK_PIXBUF_MINOR:
+ * 
+ * Minor version of &gdk-pixbuf; library, that is the "8" in
+ * "0.8.0" for example.
+ */
+/**
+ * GDK_PIXBUF_MICRO:
+ * 
+ * Micro version of &gdk-pixbuf; library, that is the last "0" in
+ * "0.8.0" for example.
+ */
+/**
+ * GDK_PIXBUF_VERSION:
+ * 
+ * Contains the full version of the &gdk-pixbuf; header as a string.
+ * This is the version being compiled against; contrast with
+ * #gdk_pixbuf_version.
+ */
+
+#define GDK_PIXBUF_MAJOR (@GDK_PIXBUF_MAJOR@)
+#define GDK_PIXBUF_MINOR (@GDK_PIXBUF_MINOR@)
+#define GDK_PIXBUF_MICRO (@GDK_PIXBUF_MICRO@)
+#define GDK_PIXBUF_VERSION "@GDK_PIXBUF_VERSION@"
+
+/* We prefix variable declarations so they can
+ * properly get exported/imported from Windows DLLs.
+ */
+#ifdef G_PLATFORM_WIN32
+#  ifdef GDK_PIXBUF_STATIC_COMPILATION
+#    define GDK_PIXBUF_VAR extern
+#  else /* !GDK_PIXBUF_STATIC_COMPILATION */
+#    ifdef GDK_PIXBUF_C_COMPILATION
+#      ifdef DLL_EXPORT
+#        define GDK_PIXBUF_VAR __declspec(dllexport)
+#      else /* !DLL_EXPORT */
+#        define GDK_PIXBUF_VAR extern
+#      endif /* !DLL_EXPORT */
+#    else /* !GDK_PIXBUF_C_COMPILATION */
+#      define GDK_PIXBUF_VAR extern __declspec(dllimport)
+#    endif /* !GDK_PIXBUF_C_COMPILATION */
+#  endif /* !GDK_PIXBUF_STATIC_COMPILATION */
+#else /* !G_PLATFORM_WIN32 */
+#  define GDK_PIXBUF_VAR extern
+#endif /* !G_PLATFORM_WIN32 */
+
+/**
+ * gdk_pixbuf_major_version:
+ * 
+ * The major version number of the &gdk-pixbuf; library.  (e.g. in 
+ * &gdk-pixbuf; version 1.2.5 this is 1.) 
+ * 
+ * 
+ * This variable is in the library, so represents the
+ * &gdk-pixbuf; library you have linked against. Contrast with the
+ * #GDK_PIXBUF_MAJOR macro, which represents the major version of the
+ * &gdk-pixbuf; headers you have included.
+ */
+/**
+ * gdk_pixbuf_minor_version:
+ * 
+ * The minor version number of the &gdk-pixbuf; library.  (e.g. in 
+ * &gdk-pixbuf; version 1.2.5 this is 2.) 
+ * 
+ * 
+ * This variable is in the library, so represents the
+ * &gdk-pixbuf; library you have linked against. Contrast with the
+ * #GDK_PIXBUF_MINOR macro, which represents the minor version of the
+ * &gdk-pixbuf; headers you have included.
+ */
+/**
+ * gdk_pixbuf_micro_version:
+ * 
+ * The micro version number of the &gdk-pixbuf; library.  (e.g. in 
+ * &gdk-pixbuf; version 1.2.5 this is 5.) 
+ * 
+ * 
+ * This variable is in the library, so represents the
+ * &gdk-pixbuf; library you have linked against. Contrast with the
+ * #GDK_PIXBUF_MICRO macro, which represents the micro version of the
+ * &gdk-pixbuf; headers you have included.
+ */
+/**
+ * gdk_pixbuf_version:
+ * 
+ * Contains the full version of the &gdk-pixbuf; library as a string.
+ * This is the version currently in use by a running program.
+ */
+
+GDK_PIXBUF_VAR const guint gdk_pixbuf_major_version;
+GDK_PIXBUF_VAR const guint gdk_pixbuf_minor_version;
+GDK_PIXBUF_VAR const guint gdk_pixbuf_micro_version;
+GDK_PIXBUF_VAR const char *gdk_pixbuf_version;
+
+#endif /* GDK_PIXBUF_FEATURES_H */
diff --git a/gdk-pixbuf/gdk-pixbuf-i18n.h b/gdk-pixbuf/gdk-pixbuf-i18n.h
new file mode 100644 (file)
index 0000000..3b0e64e
--- /dev/null
@@ -0,0 +1,39 @@
+/* GdkPixbuf library - Internationalization
+ *
+ * Copyright (C) 2000 Havoc Pennington
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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 __GDKPIXBUFINTL_H__
+#define __GDKPIXBUFINTL_H__
+
+#include "config.h"
+#include <glib.h>
+
+#ifdef ENABLE_NLS
+#define _(String) gdk_pixbuf_gettext(String)
+#define P_(String) gdk_pixbuf_gettext(String)
+#define N_(String) (String)
+#else
+#define _(String) (String)
+#define P_(String) (String)
+#define N_(String) (String)
+#endif
+
+const gchar *
+gdk_pixbuf_gettext (const gchar *msgid) G_GNUC_FORMAT(1);
+
+#endif
diff --git a/gdk-pixbuf/gdk-pixbuf-io.c b/gdk-pixbuf/gdk-pixbuf-io.c
new file mode 100644 (file)
index 0000000..4e82df5
--- /dev/null
@@ -0,0 +1,3202 @@
+/* -*- mode: C; c-file-style: "linux" -*- */
+/* GdkPixbuf library - Main loading interface.
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Authors: Miguel de Icaza <miguel@gnu.org>
+ *          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 Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#include "gdk-pixbuf-private.h"
+#include "gdk-pixbuf-loader.h"
+#include "gdk-pixdata.h"
+
+#include <glib/gstdio.h>
+
+#ifdef G_OS_WIN32
+#define STRICT
+#include <windows.h>
+#undef STRICT
+#endif
+
+#define SNIFF_BUFFER_SIZE 4096
+#define LOAD_BUFFER_SIZE 65536
+
+/**
+ * SECTION:file-loading
+ * @Short_description: Loading a pixbuf from a file.
+ * @Title: File Loading
+ * @See_also: #GdkPixbufLoader.
+ * 
+ * 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.
+ * 
+ * 
+ * This interface can be used by applications in which blocking is
+ * acceptable while an image is being loaded.  It can also be used to
+ * load small images in general.  Applications that need progressive
+ * loading can use the #GdkPixbufLoader functionality instead.
+ */
+
+/**
+ * SECTION:file-saving
+ * @Short_description: Saving a pixbuf to a file.
+ * @Title: File saving
+ * 
+ * These functions allow to save a #GdkPixbuf in a number of 
+ * file formats. The formatted data can be written to a file
+ * or to a memory buffer. &gdk-pixbuf; can also call a user-defined
+ * callback on the data, which allows to e.g. write the image 
+ * to a socket or store it in a database.
+ */
+
+/**
+ * SECTION:module_interface
+ * @Short_description: Extending &gdk-pixbuf;
+ * @Title: Module Interface
+ * 
+ * If &gdk-pixbuf; has been compiled with GModule support, it can be extended by
+ * modules which can load (and perhaps also save) new image and animation
+ * formats. Each loadable module must export a
+ * #GdkPixbufModuleFillInfoFunc function named <function>fill_info</function> and
+ * a #GdkPixbufModuleFillVtableFunc function named
+ * <function>fill_vtable</function>.
+ * 
+ * 
+ * In order to make format-checking work before actually loading the modules
+ * (which may require dlopening image libraries), modules export their 
+ * signatures (and other information) via the <function>fill_info</function>
+ * function. An external utility, <command>gdk-pixbuf-query-loaders</command>, 
+ * uses this to create a text file containing a list of all available loaders and 
+ * their signatures. This file is then read at runtime by &gdk-pixbuf; to obtain
+ * the list of available loaders and their signatures. 
+ * 
+ * 
+ * Modules may only implement a subset of the functionality available via
+ * #GdkPixbufModule. If a particular functionality is not implemented, the
+ * <function>fill_vtable</function> function will simply not set the corresponding
+ * function pointers of the #GdkPixbufModule structure. If a module supports
+ * incremental loading (i.e. provides #begin_load, #stop_load and
+ * #load_increment), it doesn't have to implement #load, since &gdk-pixbuf; can 
+ * supply a generic #load implementation wrapping the incremental loading. 
+ * 
+ * 
+ * Installing a module is a two-step process:
+ * <itemizedlist>
+ * <listitem><para>copy the module file(s) to the loader directory (normally
+ * <filename><replaceable>libdir</replaceable>/gtk-2.0/<replaceable>version</replaceable>/loaders</filename>,
+ * unless overridden by the environment variable
+ * <envar>GDK_PIXBUF_MODULEDIR</envar>) 
+ * </para></listitem>
+ * <listitem><para>call <command>gdk-pixbuf-query-loaders</command> to update the
+ * module file (normally
+ * <filename><replaceable>sysconfdir</replaceable>/gtk-2.0/gdk-pixbuf.loaders</filename>,
+ * unless overridden by the environment variable
+ * <envar>GDK_PIXBUF_MODULE_FILE</envar>)
+ * </para></listitem>
+ * </itemizedlist>
+ * 
+ * 
+ * The &gdk-pixbuf; interfaces needed for implementing modules are contained in 
+ * <filename>gdk-pixbuf-io.h</filename> (and
+ * <filename>gdk-pixbuf-animation.h</filename> if the module supports animations).
+ * They are not covered by the same stability guarantees as the regular 
+ * &gdk-pixbuf; API. To underline this fact, they are protected by 
+ * <literal>#ifdef GDK_PIXBUF_ENABLE_BACKEND</literal>.
+ */
+
+
+static gint 
+format_check (GdkPixbufModule *module, guchar *buffer, int size)
+{
+        int i, j;
+        gchar m;
+        GdkPixbufModulePattern *pattern;
+        gboolean anchored;
+        guchar *prefix;
+        gchar *mask;
+
+        for (pattern = module->info->signature; pattern->prefix; pattern++) {
+                if (pattern->mask && pattern->mask[0] == '*') {
+                        prefix = (guchar *)pattern->prefix + 1;
+                        mask = pattern->mask + 1;
+                        anchored = FALSE;
+                }
+                else {
+                        prefix = (guchar *)pattern->prefix;
+                        mask = pattern->mask;
+                        anchored = TRUE;
+                }
+                for (i = 0; i < size; i++) {
+                        for (j = 0; i + j < size && prefix[j] != 0; j++) {
+                                m = mask ? mask[j] : ' ';
+                                if (m == ' ') {
+                                        if (buffer[i + j] != prefix[j])
+                                                break;
+                                }
+                                else if (m == '!') {
+                                        if (buffer[i + j] == prefix[j])
+                                                break;
+                                }
+                                else if (m == 'z') {
+                                        if (buffer[i + j] != 0)
+                                                break;
+                                }
+                                else if (m == 'n') {
+                                        if (buffer[i + j] == 0)
+                                                break;
+                                }
+                        } 
+
+                        if (prefix[j] == 0) 
+                                return pattern->relevance;
+
+                        if (anchored)
+                                break;
+                }
+        }
+        return 0;
+}
+
+G_LOCK_DEFINE_STATIC (init_lock);
+G_LOCK_DEFINE_STATIC (threadunsafe_loader_lock);
+
+gboolean
+_gdk_pixbuf_lock (GdkPixbufModule *image_module)
+{
+        if (g_threads_got_initialized &&
+            !(image_module->info->flags & GDK_PIXBUF_FORMAT_THREADSAFE)) {
+                G_LOCK (threadunsafe_loader_lock);
+
+                return TRUE;
+        }
+
+        return FALSE;
+}
+void
+_gdk_pixbuf_unlock (GdkPixbufModule *image_module)
+{
+        if (!(image_module->info->flags & GDK_PIXBUF_FORMAT_THREADSAFE)) {
+                G_UNLOCK (threadunsafe_loader_lock);
+        }
+}
+
+static GSList *file_formats = NULL;
+
+static void gdk_pixbuf_io_init (void);
+
+static GSList *
+get_file_formats (void)
+{
+        G_LOCK (init_lock);
+        if (file_formats == NULL)
+                gdk_pixbuf_io_init ();
+        G_UNLOCK (init_lock);
+        
+        return file_formats;
+}
+
+#ifdef G_OS_WIN32
+
+/* DllMain function needed to tuck away the gdk-pixbuf DLL handle */
+
+static HMODULE gdk_pixbuf_dll;
+
+BOOL WINAPI
+DllMain (HINSTANCE hinstDLL,
+         DWORD     fdwReason,
+         LPVOID    lpvReserved)
+{
+        switch (fdwReason) {
+        case DLL_PROCESS_ATTACH:
+                gdk_pixbuf_dll = (HMODULE) hinstDLL;
+                break;
+        }
+
+  return TRUE;
+}
+
+char *
+_gdk_pixbuf_win32_get_toplevel (void)
+{
+  static char *toplevel = NULL;
+
+  if (toplevel == NULL)
+          toplevel = g_win32_get_package_installation_directory_of_module (gdk_pixbuf_dll);
+
+  return toplevel;
+}
+#endif
+
+
+#ifdef USE_GMODULE 
+
+static gboolean
+scan_string (const char **pos, GString *out)
+{
+        const char *p = *pos, *q = *pos;
+        char *tmp, *tmp2;
+        gboolean quoted;
+        
+        while (g_ascii_isspace (*p))
+                p++;
+        
+        if (!*p)
+                return FALSE;
+        else if (*p == '"') {
+                p++;
+                quoted = FALSE;
+                for (q = p; (*q != '"') || quoted; q++) {
+                        if (!*q)
+                                return FALSE;
+                        quoted = (*q == '\\') && !quoted;
+                }
+                
+                tmp = g_strndup (p, q - p);
+                tmp2 = g_strcompress (tmp);
+                g_string_truncate (out, 0);
+                g_string_append (out, tmp2);
+                g_free (tmp);
+                g_free (tmp2);
+        }
+        
+        q++;
+        *pos = q;
+        
+        return TRUE;
+}
+
+static gboolean
+scan_int (const char **pos, int *out)
+{
+        int i = 0;
+        char buf[32];
+        const char *p = *pos;
+        
+        while (g_ascii_isspace (*p))
+                p++;
+        
+        if (*p < '0' || *p > '9')
+                return FALSE;
+        
+        while ((*p >= '0') && (*p <= '9') && i < sizeof (buf)) {
+                buf[i] = *p;
+                i++;
+                p++;
+        }
+        
+        if (i == sizeof (buf))
+                return FALSE;
+        else
+                buf[i] = '\0';
+        
+        *out = atoi (buf);
+        
+        *pos = p;
+
+        return TRUE;
+}
+
+static gboolean
+skip_space (const char **pos)
+{
+        const char *p = *pos;
+        
+        while (g_ascii_isspace (*p))
+                p++;
+  
+        *pos = p;
+        
+        return !(*p == '\0');
+}
+  
+#ifdef G_OS_WIN32
+
+static char *
+get_libdir (void)
+{
+  static char *libdir = NULL;
+
+  if (libdir == NULL)
+          libdir = g_build_filename (_gdk_pixbuf_win32_get_toplevel (), "lib", NULL);
+
+  return libdir;
+}
+
+#undef GDK_PIXBUF_LIBDIR
+#define GDK_PIXBUF_LIBDIR get_libdir()
+
+static void
+correct_prefix (gchar **path)
+{
+  if (strncmp (*path, GDK_PIXBUF_PREFIX "/", strlen (GDK_PIXBUF_PREFIX "/")) == 0 ||
+      strncmp (*path, GDK_PIXBUF_PREFIX "\\", strlen (GDK_PIXBUF_PREFIX "\\")) == 0)
+    {
+          gchar *tem = NULL;
+      if (strlen(*path) > 5 && strncmp (*path - 5, ".libs", 5) == 0)
+        {
+          /* We are being run from inside the build tree, and shouldn't mess about. */
+          return;
+        }
+
+      /* This is an entry put there by gdk-pixbuf-query-loaders on the
+       * packager's system. On Windows a prebuilt gdk-pixbuf package can be
+       * installed in a random location. The gdk-pixbuf.loaders file
+       * distributed in such a package contains paths from the package
+       * builder's machine. Replace the build-time prefix with the
+       * installation prefix on this machine.
+       */
+      tem = *path;
+      *path = g_strconcat (_gdk_pixbuf_win32_get_toplevel (), tem + strlen (GDK_PIXBUF_PREFIX), NULL);
+      g_free (tem);
+    }
+}
+
+#endif  /* G_OS_WIN32 */
+
+static gchar *
+gdk_pixbuf_get_module_file (void)
+{
+  gchar *result = g_strdup (g_getenv ("GDK_PIXBUF_MODULE_FILE"));
+
+  if (!result)
+          result = g_build_filename (GDK_PIXBUF_LIBDIR, "gdk-pixbuf-2.0", GDK_PIXBUF_BINARY_VERSION, "loaders.cache", NULL);
+
+  return result;
+}
+
+#endif  /* USE_GMODULE */
+
+
+static gboolean
+gdk_pixbuf_load_module_unlocked (GdkPixbufModule *image_module,
+                                 GError         **error);
+
+static void 
+gdk_pixbuf_io_init (void)
+{
+#ifdef USE_GMODULE
+        GIOChannel *channel;
+        gchar *line_buf;
+        gsize term;
+        GString *tmp_buf = g_string_new (NULL);
+        gboolean have_error = FALSE;
+        GdkPixbufModule *module = NULL;
+        gchar *filename = gdk_pixbuf_get_module_file ();
+        int flags;
+        int n_patterns = 0;
+        GdkPixbufModulePattern *pattern;
+        GError *error = NULL;
+#endif
+        GdkPixbufModule *builtin_module ;
+
+        /*  initialize on separate line to avoid compiler warnings in the
+         *  common case of no compiled-in modules.
+         */
+        builtin_module = NULL;
+
+#define load_one_builtin_module(format)                                 \
+        builtin_module = g_new0 (GdkPixbufModule, 1);                   \
+        builtin_module->module_name = #format;                          \
+        if (gdk_pixbuf_load_module_unlocked (builtin_module, NULL))             \
+                file_formats = g_slist_prepend (file_formats, builtin_module);\
+        else                                                            \
+                g_free (builtin_module)
+
+       /* Always include GdkPixdata format */
+        load_one_builtin_module (pixdata);
+
+#ifdef INCLUDE_ani
+        load_one_builtin_module (ani);
+#endif
+#ifdef INCLUDE_png
+        load_one_builtin_module (png);
+#endif
+#ifdef INCLUDE_bmp
+        load_one_builtin_module (bmp);
+#endif
+#ifdef INCLUDE_wbmp
+        load_one_builtin_module (wbmp);
+#endif
+#ifdef INCLUDE_gif
+        load_one_builtin_module (gif);
+#endif
+#ifdef INCLUDE_ico
+        load_one_builtin_module (ico);
+#endif
+#ifdef INCLUDE_jpeg
+        load_one_builtin_module (jpeg);
+#endif
+#ifdef INCLUDE_pnm
+        load_one_builtin_module (pnm);
+#endif
+#ifdef INCLUDE_ras
+        load_one_builtin_module (ras);
+#endif
+#ifdef INCLUDE_tiff
+        load_one_builtin_module (tiff);
+#endif
+#ifdef INCLUDE_xpm
+        load_one_builtin_module (xpm);
+#endif
+#ifdef INCLUDE_xbm
+        load_one_builtin_module (xbm);
+#endif
+#ifdef INCLUDE_tga
+        load_one_builtin_module (tga);
+#endif
+#ifdef INCLUDE_pcx
+        load_one_builtin_module (pcx);
+#endif
+#ifdef INCLUDE_icns
+        load_one_builtin_module (icns);
+#endif
+#ifdef INCLUDE_jasper
+        load_one_builtin_module (jasper);
+#endif
+#ifdef INCLUDE_qtif
+        load_one_builtin_module (qtif);
+#endif
+#ifdef INCLUDE_gdiplus
+        /* We don't bother having the GDI+ loaders individually selectable
+         * for building in or not.
+         */
+        load_one_builtin_module (ico);
+        load_one_builtin_module (wmf);
+        load_one_builtin_module (emf);
+        load_one_builtin_module (bmp);
+        load_one_builtin_module (gif);
+        load_one_builtin_module (jpeg);
+        load_one_builtin_module (tiff);
+#endif
+#ifdef INCLUDE_gdip_png
+        /* Except the gdip-png loader which normally isn't built at all even */
+        load_one_builtin_module (png);
+#endif
+
+#undef load_one_builtin_module
+
+#ifdef USE_GMODULE
+        channel = g_io_channel_new_file (filename, "r",  &error);
+        if (!channel) {
+                /* Don't bother warning if we have some built-in loaders */
+                if (file_formats == NULL)
+                        g_warning ("Cannot open pixbuf loader module file '%s': %s",
+                                   filename, error->message);
+                g_string_free (tmp_buf, TRUE);
+                g_free (filename);
+                return;
+        }
+        
+        while (!have_error && g_io_channel_read_line (channel, &line_buf, NULL, &term, NULL) == G_IO_STATUS_NORMAL) {
+                const char *p;
+                
+                p = line_buf;
+
+                line_buf[term] = 0;
+
+                if (!skip_space (&p)) {
+                                /* Blank line marking the end of a module
+                                 */
+                        if (module && *p != '#') {
+#ifdef G_OS_WIN32
+                                correct_prefix (&module->module_path);
+#endif
+                                file_formats = g_slist_prepend (file_formats, module);
+                                module = NULL;
+                        }
+                        
+                        goto next_line;
+                }
+
+                if (*p == '#') 
+                        goto next_line;
+                
+                if (!module) {
+                                /* Read a module location
+                                 */
+                        module = g_new0 (GdkPixbufModule, 1);
+                        n_patterns = 0;
+                        
+                        if (!scan_string (&p, tmp_buf)) {
+                                g_warning ("Error parsing loader info in '%s'\n  %s", 
+                                           filename, line_buf);
+                                have_error = TRUE;
+                        }
+                        module->module_path = g_strdup (tmp_buf->str);
+                }
+                else if (!module->module_name) {
+                        module->info = g_new0 (GdkPixbufFormat, 1);
+                        if (!scan_string (&p, tmp_buf)) {
+                                g_warning ("Error parsing loader info in '%s'\n  %s", 
+                                           filename, line_buf);
+                                have_error = TRUE;
+                        }
+                        module->info->name =  g_strdup (tmp_buf->str);
+                        module->module_name = module->info->name;
+
+                        if (!scan_int (&p, &flags)) {
+                                g_warning ("Error parsing loader info in '%s'\n  %s", 
+                                           filename, line_buf);
+                                have_error = TRUE;
+                        }
+                        module->info->flags = flags;
+                        
+                        if (!scan_string (&p, tmp_buf)) {
+                                g_warning ("Error parsing loader info in '%s'\n  %s", 
+                                           filename, line_buf);
+                                have_error = TRUE;
+                        }                       
+                        if (tmp_buf->str[0] != 0)
+                                module->info->domain = g_strdup (tmp_buf->str);
+
+                        if (!scan_string (&p, tmp_buf)) {
+                                g_warning ("Error parsing loader info in '%s'\n  %s", 
+                                           filename, line_buf);
+                                have_error = TRUE;
+                        }                       
+                        module->info->description = g_strdup (tmp_buf->str);
+
+                        if (scan_string (&p, tmp_buf)) {
+                                module->info->license = g_strdup (tmp_buf->str);
+                        }
+                }
+                else if (!module->info->mime_types) {
+                        int n = 1;
+                        module->info->mime_types = g_new0 (gchar*, 1);
+                        while (scan_string (&p, tmp_buf)) {
+                                if (tmp_buf->str[0] != 0) {
+                                        module->info->mime_types =
+                                                g_realloc (module->info->mime_types, (n + 1) * sizeof (gchar*));
+                                        module->info->mime_types[n - 1] = g_strdup (tmp_buf->str);
+                                        module->info->mime_types[n] = NULL;
+                                        n++;
+                                }
+                        }
+                }
+                else if (!module->info->extensions) {
+                        int n = 1;
+                        module->info->extensions = g_new0 (gchar*, 1);
+                        while (scan_string (&p, tmp_buf)) {
+                                if (tmp_buf->str[0] != 0) {
+                                        module->info->extensions =
+                                                g_realloc (module->info->extensions, (n + 1) * sizeof (gchar*));
+                                        module->info->extensions[n - 1] = g_strdup (tmp_buf->str);
+                                        module->info->extensions[n] = NULL;
+                                        n++;
+                                }
+                        }
+                }
+                else {
+                        n_patterns++;
+                        module->info->signature = (GdkPixbufModulePattern *)
+                                g_realloc (module->info->signature, (n_patterns + 1) * sizeof (GdkPixbufModulePattern));
+                        pattern = module->info->signature + n_patterns;
+                        pattern->prefix = NULL;
+                        pattern->mask = NULL;
+                        pattern->relevance = 0;
+                        pattern--;
+                        if (!scan_string (&p, tmp_buf))
+                                goto context_error;
+                        pattern->prefix = g_strdup (tmp_buf->str);
+                        
+                        if (!scan_string (&p, tmp_buf))
+                                goto context_error;
+                        if (*tmp_buf->str)
+                                pattern->mask = g_strdup (tmp_buf->str);
+                        else
+                                pattern->mask = NULL;
+                        
+                        if (!scan_int (&p, &pattern->relevance))
+                                goto context_error;
+                        
+                        goto next_line;
+
+                context_error:
+                        g_free (pattern->prefix);
+                        g_free (pattern->mask);
+                        g_free (pattern);
+                        g_warning ("Error parsing loader info in '%s'\n  %s", 
+                                   filename, line_buf);
+                        have_error = TRUE;
+                }
+        next_line:
+                g_free (line_buf);
+        }
+        g_string_free (tmp_buf, TRUE);
+        g_io_channel_unref (channel);
+        g_free (filename);
+#endif
+}
+
+
+#define module(type) \
+  extern void _gdk_pixbuf__##type##_fill_info   (GdkPixbufFormat *info);   \
+  extern void _gdk_pixbuf__##type##_fill_vtable (GdkPixbufModule *module)
+
+module (pixdata);
+module (png);
+module (jpeg);
+module (gif);
+module (ico);
+module (ani);
+module (ras);
+module (xpm);
+module (tiff);
+module (pnm);
+module (bmp);
+module (wbmp);
+module (xbm);
+module (tga);
+module (pcx);
+module (icns);
+module (jasper);
+module (qtif);
+module (gdip_ico);
+module (gdip_wmf);
+module (gdip_emf);
+module (gdip_bmp);
+module (gdip_gif);
+module (gdip_jpeg);
+module (gdip_png);
+module (gdip_tiff);
+
+#undef module
+
+/* actually load the image handler - gdk_pixbuf_get_module only get a */
+/* reference to the module to load, it doesn't actually load it       */
+/* perhaps these actions should be combined in one function           */
+static gboolean
+gdk_pixbuf_load_module_unlocked (GdkPixbufModule *image_module,
+                                 GError         **error)
+{
+        GdkPixbufModuleFillInfoFunc fill_info = NULL;
+        GdkPixbufModuleFillVtableFunc fill_vtable = NULL;
+                
+        if (image_module->module != NULL)
+               return TRUE;
+
+#define try_module(format,id)                                           \
+        if (fill_info == NULL &&                                        \
+            strcmp (image_module->module_name, #format) == 0) {         \
+                fill_info = _gdk_pixbuf__##id##_fill_info;              \
+                fill_vtable = _gdk_pixbuf__##id##_fill_vtable;  \
+        }
+
+        try_module (pixdata,pixdata);
+
+#ifdef INCLUDE_png      
+        try_module (png,png);
+#endif
+#ifdef INCLUDE_bmp
+        try_module (bmp,bmp);
+#endif
+#ifdef INCLUDE_wbmp
+        try_module (wbmp,wbmp);
+#endif
+#ifdef INCLUDE_gif
+        try_module (gif,gif);
+#endif
+#ifdef INCLUDE_ico
+        try_module (ico,ico);
+#endif
+#ifdef INCLUDE_ani
+        try_module (ani,ani);
+#endif
+#ifdef INCLUDE_jpeg
+        try_module (jpeg,jpeg);
+#endif
+#ifdef INCLUDE_pnm
+        try_module (pnm,pnm);
+#endif
+#ifdef INCLUDE_ras
+        try_module (ras,ras);
+#endif
+#ifdef INCLUDE_tiff
+        try_module (tiff,tiff);
+#endif
+#ifdef INCLUDE_xpm
+        try_module (xpm,xpm);
+#endif
+#ifdef INCLUDE_xbm
+        try_module (xbm,xbm);
+#endif
+#ifdef INCLUDE_tga
+        try_module (tga,tga);
+#endif
+#ifdef INCLUDE_pcx
+        try_module (pcx,pcx);
+#endif
+#ifdef INCLUDE_icns
+        try_module (icns,icns);
+#endif
+#ifdef INCLUDE_jasper
+        try_module (jasper,jasper);
+#endif
+#ifdef INCLUDE_qtif
+        try_module (qtif,qtif);
+#endif
+#ifdef INCLUDE_gdiplus
+        try_module (ico,gdip_ico);
+        try_module (wmf,gdip_wmf);
+        try_module (emf,gdip_emf);
+        try_module (bmp,gdip_bmp);
+        try_module (gif,gdip_gif);
+        try_module (jpeg,gdip_jpeg);
+        try_module (tiff,gdip_tiff);
+#endif
+#ifdef INCLUDE_gdip_png
+        try_module (png,gdip_png);
+#endif
+
+#undef try_module
+        
+        if (fill_vtable) {
+                image_module->module = (void *) 1;
+                (* fill_vtable) (image_module);
+                if (image_module->info == NULL) {
+                        image_module->info = g_new0 (GdkPixbufFormat, 1);
+                        (* fill_info) (image_module->info);
+                }
+                return TRUE;
+        }
+        else 
+#ifdef USE_GMODULE
+        {
+                char *path;
+                GModule *module;
+                gpointer sym;
+
+                path = image_module->module_path;
+                module = g_module_open (path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
+
+                if (!module) {
+                        g_set_error (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_FAILED,
+                                     _("Unable to load image-loading module: %s: %s"),
+                                     path, g_module_error ());
+                        return FALSE;
+                }
+
+                image_module->module = module;        
+        
+                if (g_module_symbol (module, "fill_vtable", &sym)) {
+                        fill_vtable = (GdkPixbufModuleFillVtableFunc) sym;
+                        (* fill_vtable) (image_module);
+                        return TRUE;
+                } else {
+                        g_set_error (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_FAILED,
+                                     _("Image-loading module %s does not export the proper interface; perhaps it's from a different gdk-pixbuf version?"),
+                                     path);
+                        return FALSE;
+                }
+        }
+#else
+        g_set_error (error,
+                     GDK_PIXBUF_ERROR,
+                     GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+                     _("Image type '%s' is not supported"),
+                     image_module->module_name);
+        return FALSE;
+#endif  /* !USE_GMODULE */
+}
+
+
+gboolean
+_gdk_pixbuf_load_module (GdkPixbufModule *image_module,
+                         GError         **error)
+{
+        gboolean ret;
+        gboolean locked = FALSE;
+
+        /* be extra careful, maybe the module initializes
+         * the thread system
+         */
+        if (g_threads_got_initialized) {
+                G_LOCK (init_lock);
+                locked = TRUE;
+        }
+
+        ret = gdk_pixbuf_load_module_unlocked (image_module, error);
+
+        if (locked)
+                G_UNLOCK (init_lock);
+
+        return ret;
+}
+
+\f
+
+GdkPixbufModule *
+_gdk_pixbuf_get_named_module (const char *name,
+                              GError **error)
+{
+        GSList *modules;
+
+        for (modules = get_file_formats (); modules; modules = g_slist_next (modules)) {
+                GdkPixbufModule *module = (GdkPixbufModule *)modules->data;
+
+                if (module->info->disabled)
+                        continue;
+
+                if (!strcmp (name, module->module_name))
+                        return module;
+        }
+
+        g_set_error (error,
+                     GDK_PIXBUF_ERROR,
+                     GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+                     _("Image type '%s' is not supported"),
+                     name);
+        
+        return NULL;
+}
+
+GdkPixbufModule *
+_gdk_pixbuf_get_module (guchar *buffer, guint size,
+                        const gchar *filename,
+                        GError **error)
+{
+        GSList *modules;
+
+        GdkPixbufModule *selected = NULL;
+        gchar *display_name = NULL;
+#ifdef GDK_PIXBUF_USE_GIO_MIME
+        gchar *mime_type;
+        gchar **mimes;
+        gchar *type;
+        gint j;
+        gboolean uncertain;
+
+        mime_type = g_content_type_guess (NULL, buffer, size, &uncertain);
+        if (uncertain)
+                mime_type = g_content_type_guess (filename, buffer, size, NULL);
+
+        for (modules = get_file_formats (); modules; modules = g_slist_next (modules)) {
+                GdkPixbufModule *module = (GdkPixbufModule *)modules->data;
+                GdkPixbufFormat *info = module->info;
+
+                if (info->disabled)
+                        continue;
+
+                mimes = info->mime_types;
+                for (j = 0; mimes[j] != NULL; j++) {
+                        type = g_content_type_from_mime_type (mimes[j]);
+                        if (g_content_type_equals (type, mime_type)) {
+                                g_free (type);
+                                selected = module;
+                                break;
+                        }
+                        g_free (type);
+                }
+
+               /* Make sure the builtin GdkPixdata support works even without mime sniffing */
+               if (strcmp (info->name, "GdkPixdata") == 0 &&
+                   format_check (module, buffer, size) == 100) {
+                       selected = module;
+                       break;
+               }
+        }
+        g_free (mime_type);
+#else
+        gint score, best = 0;
+
+        for (modules = get_file_formats (); modules; modules = g_slist_next (modules)) {
+                GdkPixbufModule *module = (GdkPixbufModule *)modules->data;
+
+                if (module->info->disabled)
+                        continue;
+
+                score = format_check (module, buffer, size);
+                if (score > best) {
+                        best = score; 
+                        selected = module;
+                }
+                if (score >= 100) 
+                        break;
+        }
+#endif
+
+        if (selected != NULL)
+                return selected;
+
+        if (filename)
+        {
+                display_name = g_filename_display_name (filename);
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+                             _("Couldn't recognize the image file format for file '%s'"),
+                             display_name);
+                g_free (display_name);
+        }
+        else
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+                                     _("Unrecognized image file format"));
+
+
+        return NULL;
+}
+
+
+static void
+prepared_notify (GdkPixbuf *pixbuf, 
+                 GdkPixbufAnimation *anim, 
+                 gpointer user_data)
+{
+        if (pixbuf != NULL)
+                g_object_ref (pixbuf);
+        *((GdkPixbuf **)user_data) = pixbuf;
+}
+
+GdkPixbuf *
+_gdk_pixbuf_generic_image_load (GdkPixbufModule *module,
+                                FILE *f,
+                                GError **error)
+{
+        guchar buffer[LOAD_BUFFER_SIZE];
+        size_t length;
+        GdkPixbuf *pixbuf = NULL;
+        GdkPixbufAnimation *animation = NULL;
+        gpointer context;
+        gboolean locked;
+
+        locked = _gdk_pixbuf_lock (module);
+
+        if (module->load != NULL) {
+                pixbuf = (* module->load) (f, error);
+        } else if (module->begin_load != NULL) {
+                
+                context = module->begin_load (NULL, prepared_notify, NULL, &pixbuf, error);
+        
+                if (!context)
+                        goto out;
+                
+                while (!feof (f) && !ferror (f)) {
+                        length = fread (buffer, 1, sizeof (buffer), f);
+                        if (length > 0)
+                                if (!module->load_increment (context, buffer, length, error)) {
+                                        module->stop_load (context, NULL);
+                                        if (pixbuf != NULL) {
+                                                g_object_unref (pixbuf);
+                                                pixbuf = NULL;
+                                        }
+                                        goto out;
+                                }
+                }
+                
+                if (!module->stop_load (context, error)) {
+                        if (pixbuf != NULL) {
+                                g_object_unref (pixbuf);
+                                pixbuf = NULL;
+                        }
+                }
+        } else if (module->load_animation != NULL) {
+                animation = (* module->load_animation) (f, error);
+                if (animation != NULL) {
+                        pixbuf = gdk_pixbuf_animation_get_static_image (animation);
+
+                        g_object_ref (pixbuf);
+                        g_object_unref (animation);
+                }
+        }
+
+ out:
+        if (locked)
+                _gdk_pixbuf_unlock (module);
+        return pixbuf;
+}
+
+/**
+ * gdk_pixbuf_new_from_file:
+ * @filename: Name of file to load, in the GLib file name encoding
+ * @error: Return location for an error
+ *
+ * Creates a new pixbuf by loading an image from a file.  The file format is
+ * detected automatically. If %NULL is returned, then @error will be set.
+ * Possible errors are in the #GDK_PIXBUF_ERROR and #G_FILE_ERROR domains.
+ *
+ * Return value: A newly-created pixbuf with a reference count of 1, or %NULL if
+ * any of several error conditions occurred:  the file could not be opened,
+ * there was no loader for the file's format, there was not enough memory to
+ * allocate the image buffer, or the image file contained invalid data.
+ **/
+GdkPixbuf *
+gdk_pixbuf_new_from_file (const char *filename,
+                          GError    **error)
+{
+        GdkPixbuf *pixbuf;
+        int size;
+        FILE *f;
+        guchar buffer[SNIFF_BUFFER_SIZE];
+        GdkPixbufModule *image_module;
+        gchar *display_name;
+
+        g_return_val_if_fail (filename != NULL, NULL);
+        g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+        
+        display_name = g_filename_display_name (filename);      
+
+        f = g_fopen (filename, "rb");
+        if (!f) {
+                gint save_errno = errno;
+                g_set_error (error,
+                             G_FILE_ERROR,
+                             g_file_error_from_errno (save_errno),
+                             _("Failed to open file '%s': %s"),
+                             display_name,
+                             g_strerror (save_errno));
+                g_free (display_name);
+                return NULL;
+        }
+
+        size = fread (&buffer, 1, sizeof (buffer), f);
+        if (size == 0) {
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                             _("Image file '%s' contains no data"),
+                             display_name);
+                g_free (display_name);
+                fclose (f);
+                return NULL;
+        }
+
+        image_module = _gdk_pixbuf_get_module (buffer, size, filename, error);
+        if (image_module == NULL) {
+                g_free (display_name);
+                fclose (f);
+                return NULL;
+        }
+
+        if (!_gdk_pixbuf_load_module (image_module, error)) {
+                g_free (display_name);
+                fclose (f);
+                return NULL;
+        }
+
+        fseek (f, 0, SEEK_SET);
+        pixbuf = _gdk_pixbuf_generic_image_load (image_module, f, error);
+        fclose (f);
+
+        if (pixbuf == NULL && error != NULL && *error == NULL) {
+
+                /* I don't trust these crufty longjmp()'ing image libs
+                 * to maintain proper error invariants, and I don't
+                 * want user code to segfault as a result. We need to maintain
+                 * the invariant that error gets set if NULL is returned.
+                 */
+
+                g_warning ("Bug! gdk-pixbuf loader '%s' didn't set an error on failure.", image_module->module_name);
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_FAILED,
+                             _("Failed to load image '%s': reason not known, probably a corrupt image file"),
+                             display_name);
+        } else if (error != NULL && *error != NULL) {
+
+          /* Add the filename to the error message */
+          GError *e = *error;
+          gchar  *old;
+
+          old = e->message;
+          e->message = g_strdup_printf (_("Failed to load image '%s': %s"),
+                                        display_name,
+                                        old);
+          g_free (old);
+        }
+
+        g_free (display_name);
+        return pixbuf;
+}
+
+#ifdef G_OS_WIN32
+
+#undef gdk_pixbuf_new_from_file
+GdkPixbuf *
+gdk_pixbuf_new_from_file (const char *filename,
+                          GError    **error)
+{
+        gchar *utf8_filename =
+                g_locale_to_utf8 (filename, -1, NULL, NULL, error);
+        GdkPixbuf *retval;
+
+        if (utf8_filename == NULL)
+                return NULL;
+
+        retval = gdk_pixbuf_new_from_file_utf8 (utf8_filename, error);
+
+        g_free (utf8_filename);
+
+        return retval;
+}
+#endif
+
+
+/**
+ * gdk_pixbuf_new_from_file_at_size:
+ * @filename: Name of file to load, in the GLib file name encoding
+ * @width: The width the image should have or -1 to not constrain the width
+ * @height: The height the image should have or -1 to not constrain the height
+ * @error: Return location for an error
+ *
+ * Creates a new pixbuf by loading an image from a file.  
+ * The file format is detected automatically. If %NULL is returned, then 
+ * @error will be set. Possible errors are in the #GDK_PIXBUF_ERROR and 
+ * #G_FILE_ERROR domains.
+ *
+ * The image will be scaled to fit in the requested size, preserving
+ * the image's aspect ratio. Note that the returned pixbuf may be smaller
+ * than @width x @height, if the aspect ratio requires it. To load
+ * and image at the requested size, regardless of aspect ratio, use
+ * gdk_pixbuf_new_from_file_at_scale().
+ *
+ * Return value: A newly-created pixbuf with a reference count of 1, or 
+ * %NULL if any of several error conditions occurred:  the file could not 
+ * be opened, there was no loader for the file's format, there was not 
+ * enough memory to allocate the image buffer, or the image file contained 
+ * invalid data.
+ *
+ * Since: 2.4
+ **/
+GdkPixbuf *
+gdk_pixbuf_new_from_file_at_size (const char *filename,
+                                  int         width, 
+                                  int         height,
+                                  GError    **error)
+{
+        return gdk_pixbuf_new_from_file_at_scale (filename, 
+                                                  width, height, 
+                                                  TRUE, error);
+}
+
+#ifdef G_OS_WIN32
+
+#undef gdk_pixbuf_new_from_file_at_size
+
+GdkPixbuf *
+gdk_pixbuf_new_from_file_at_size (const char *filename,
+                                  int         width, 
+                                  int         height,
+                                  GError    **error)
+{
+        gchar *utf8_filename =
+                g_locale_to_utf8 (filename, -1, NULL, NULL, error);
+        GdkPixbuf *retval;
+
+        if (utf8_filename == NULL)
+                return NULL;
+
+        retval = gdk_pixbuf_new_from_file_at_size_utf8 (utf8_filename,
+                                                        width, height,
+                                                        error);
+
+        g_free (utf8_filename);
+
+        return retval;
+}
+#endif
+
+typedef struct {
+        gint width;
+        gint height;
+        gboolean preserve_aspect_ratio;
+} AtScaleData; 
+
+static void
+at_scale_data_async_data_free (AtScaleData *data)
+{
+       g_slice_free (AtScaleData, data);
+}
+
+static void
+at_scale_size_prepared_cb (GdkPixbufLoader *loader, 
+                           int              width,
+                           int              height,
+                           gpointer         data)
+{
+        AtScaleData *info = data;
+
+        g_return_if_fail (width > 0 && height > 0);
+
+        if (info->preserve_aspect_ratio && 
+            (info->width > 0 || info->height > 0)) {
+                if (info->width < 0)
+                {
+                        width = width * (double)info->height/(double)height;
+                        height = info->height;
+                }
+                else if (info->height < 0)
+                {
+                        height = height * (double)info->width/(double)width;
+                        width = info->width;
+                }
+                else if ((double)height * (double)info->width >
+                         (double)width * (double)info->height) {
+                        width = 0.5 + (double)width * (double)info->height / (double)height;
+                        height = info->height;
+                } else {
+                        height = 0.5 + (double)height * (double)info->width / (double)width;
+                        width = info->width;
+                }
+        } else {
+                if (info->width > 0)
+                        width = info->width;
+                if (info->height > 0)
+                        height = info->height;
+        }
+        
+        width = MAX (width, 1);
+        height = MAX (height, 1);
+
+        gdk_pixbuf_loader_set_size (loader, width, height);
+}
+
+/**
+ * gdk_pixbuf_new_from_file_at_scale:
+ * @filename: Name of file to load, in the GLib file name encoding
+ * @width: The width the image should have or -1 to not constrain the width
+ * @height: The height the image should have or -1 to not constrain the height
+ * @preserve_aspect_ratio: %TRUE to preserve the image's aspect ratio
+ * @error: Return location for an error
+ *
+ * Creates a new pixbuf by loading an image from a file.  The file format is
+ * detected automatically. If %NULL is returned, then @error will be set.
+ * Possible errors are in the #GDK_PIXBUF_ERROR and #G_FILE_ERROR domains.
+ * The image will be scaled to fit in the requested size, optionally preserving
+ * the image's aspect ratio. 
+ *
+ * When preserving the aspect ratio, a @width of -1 will cause the image
+ * to be scaled to the exact given height, and a @height of -1 will cause
+ * the image to be scaled to the exact given width. When not preserving
+ * aspect ratio, a @width or @height of -1 means to not scale the image 
+ * at all in that dimension. Negative values for @width and @height are 
+ * allowed since 2.8.
+ *
+ * Return value: A newly-created pixbuf with a reference count of 1, or %NULL 
+ * if any of several error conditions occurred:  the file could not be opened,
+ * there was no loader for the file's format, there was not enough memory to
+ * allocate the image buffer, or the image file contained invalid data.
+ *
+ * Since: 2.6
+ **/
+GdkPixbuf *
+gdk_pixbuf_new_from_file_at_scale (const char *filename,
+                                   int         width, 
+                                   int         height,
+                                   gboolean    preserve_aspect_ratio,
+                                   GError    **error)
+{
+
+        GdkPixbufLoader *loader;
+        GdkPixbuf       *pixbuf;
+        guchar buffer[LOAD_BUFFER_SIZE];
+        int length;
+        FILE *f;
+        AtScaleData info;
+        GdkPixbufAnimation *animation;
+        GdkPixbufAnimationIter *iter;
+        gboolean has_frame;
+
+        g_return_val_if_fail (filename != NULL, NULL);
+        g_return_val_if_fail (width > 0 || width == -1, NULL);
+        g_return_val_if_fail (height > 0 || height == -1, NULL);
+
+        f = g_fopen (filename, "rb");
+        if (!f) {
+                gint save_errno = errno;
+                gchar *display_name = g_filename_display_name (filename);
+                g_set_error (error,
+                             G_FILE_ERROR,
+                             g_file_error_from_errno (save_errno),
+                             _("Failed to open file '%s': %s"),
+                             display_name,
+                             g_strerror (save_errno));
+                g_free (display_name);
+                return NULL;
+        }
+
+        loader = gdk_pixbuf_loader_new ();
+
+        info.width = width;
+        info.height = height;
+        info.preserve_aspect_ratio = preserve_aspect_ratio;
+
+        g_signal_connect (loader, "size-prepared", 
+                          G_CALLBACK (at_scale_size_prepared_cb), &info);
+
+        has_frame = FALSE;
+        while (!has_frame && !feof (f) && !ferror (f)) {
+                length = fread (buffer, 1, sizeof (buffer), f);
+                if (length > 0)
+                        if (!gdk_pixbuf_loader_write (loader, buffer, length, error)) {
+                                gdk_pixbuf_loader_close (loader, NULL);
+                                fclose (f);
+                                g_object_unref (loader);
+                                return NULL;
+                        }
+                
+                animation = gdk_pixbuf_loader_get_animation (loader);
+                if (animation) {
+                        iter = gdk_pixbuf_animation_get_iter (animation, NULL);
+                        if (!gdk_pixbuf_animation_iter_on_currently_loading_frame (iter)) {
+                                has_frame = TRUE;
+                        }
+                        g_object_unref (iter);
+                }
+        }
+
+        fclose (f);
+
+        if (!gdk_pixbuf_loader_close (loader, error) && !has_frame) {
+                g_object_unref (loader);
+                return NULL;
+        }
+
+        pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+
+        if (!pixbuf) {
+                gchar *display_name = g_filename_display_name (filename);
+                g_object_unref (loader);
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_FAILED,
+                             _("Failed to load image '%s': reason not known, probably a corrupt image file"),
+                             display_name);
+                g_free (display_name);
+                return NULL;
+        }
+
+        g_object_ref (pixbuf);
+
+        g_object_unref (loader);
+
+        return pixbuf;
+}
+
+#ifdef G_OS_WIN32
+
+#undef gdk_pixbuf_new_from_file_at_scale
+
+GdkPixbuf *
+gdk_pixbuf_new_from_file_at_scale (const char *filename,
+                                   int         width, 
+                                   int         height,
+                                   gboolean    preserve_aspect_ratio,
+                                   GError    **error)
+{
+        gchar *utf8_filename =
+                g_locale_to_utf8 (filename, -1, NULL, NULL, error);
+        GdkPixbuf *retval;
+
+        if (utf8_filename == NULL)
+                return NULL;
+
+        retval = gdk_pixbuf_new_from_file_at_scale_utf8 (utf8_filename,
+                                                         width, height,
+                                                         preserve_aspect_ratio,
+                                                         error);
+
+        g_free (utf8_filename);
+
+        return retval;
+}
+#endif
+
+
+static GdkPixbuf *
+load_from_stream (GdkPixbufLoader  *loader,
+                  GInputStream     *stream,
+                  GCancellable     *cancellable,
+                  GError          **error)
+{
+        GdkPixbuf *pixbuf;
+        gssize n_read;
+        guchar buffer[LOAD_BUFFER_SIZE];
+        gboolean res;
+
+        res = TRUE;
+        while (1) { 
+                n_read = g_input_stream_read (stream, 
+                                              buffer, 
+                                              sizeof (buffer), 
+                                              cancellable, 
+                                              error);
+                if (n_read < 0) {
+                        res = FALSE;
+                        error = NULL; /* Ignore further errors */
+                        break;
+                }
+
+                if (n_read == 0)
+                        break;
+
+                if (!gdk_pixbuf_loader_write (loader, 
+                                              buffer, 
+                                              n_read, 
+                                              error)) {
+                        res = FALSE;
+                        error = NULL;
+                        break;
+                }
+        }
+
+        if (!gdk_pixbuf_loader_close (loader, error)) {
+                res = FALSE;
+                error = NULL;
+        }
+
+        pixbuf = NULL;
+        if (res) {
+                pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+                if (pixbuf)
+                        g_object_ref (pixbuf);
+        }
+
+        return pixbuf;
+}
+
+
+/**
+ * gdk_pixbuf_new_from_stream_at_scale:
+ * @stream:  a #GInputStream to load the pixbuf from
+ * @width: The width the image should have or -1 to not constrain the width
+ * @height: The height the image should have or -1 to not constrain the height
+ * @preserve_aspect_ratio: %TRUE to preserve the image's aspect ratio
+ * @cancellable: optional #GCancellable object, %NULL to ignore
+ * @error: Return location for an error
+ *
+ * Creates a new pixbuf by loading an image from an input stream.  
+ *
+ * The file format is detected automatically. If %NULL is returned, then 
+ * @error will be set. The @cancellable can be used to abort the operation
+ * from another thread. If the operation was cancelled, the error 
+ * %GIO_ERROR_CANCELLED will be returned. Other possible errors are in 
+ * the #GDK_PIXBUF_ERROR and %G_IO_ERROR domains. 
+ *
+ * The image will be scaled to fit in the requested size, optionally 
+ * preserving the image's aspect ratio. When preserving the aspect ratio, 
+ * a @width of -1 will cause the image to be scaled to the exact given 
+ * height, and a @height of -1 will cause the image to be scaled to the 
+ * exact given width. When not preserving aspect ratio, a @width or 
+ * @height of -1 means to not scale the image at all in that dimension.
+ *
+ * The stream is not closed.
+ *
+ * Return value: A newly-created pixbuf, or %NULL if any of several error 
+ * conditions occurred: the file could not be opened, the image format is 
+ * not supported, there was not enough memory to allocate the image buffer, 
+ * the stream contained invalid data, or the operation was cancelled.
+ *
+ * Since: 2.14
+ */
+GdkPixbuf *
+gdk_pixbuf_new_from_stream_at_scale (GInputStream  *stream,
+                                     gint           width,
+                                     gint           height,
+                                     gboolean       preserve_aspect_ratio,
+                                     GCancellable  *cancellable,
+                                     GError       **error)
+{
+        GdkPixbufLoader *loader;
+        GdkPixbuf *pixbuf;
+        AtScaleData info;
+
+        loader = gdk_pixbuf_loader_new ();
+
+        info.width = width;
+        info.height = height;
+        info.preserve_aspect_ratio = preserve_aspect_ratio;
+
+        g_signal_connect (loader, "size-prepared", 
+                          G_CALLBACK (at_scale_size_prepared_cb), &info);
+
+        pixbuf = load_from_stream (loader, stream, cancellable, error);
+        g_object_unref (loader);
+
+        return pixbuf;
+}
+
+static void
+new_from_stream_thread (GSimpleAsyncResult *result,
+                       GInputStream       *stream,
+                       GCancellable       *cancellable)
+{
+       GdkPixbuf *pixbuf;
+       AtScaleData *data;
+       GError *error = NULL;
+
+       /* If data != NULL, we're scaling the pixbuf while loading it */
+       data = g_simple_async_result_get_op_res_gpointer (result);
+       if (data != NULL)
+               pixbuf = gdk_pixbuf_new_from_stream_at_scale (stream, data->width, data->height, data->preserve_aspect_ratio, cancellable, &error);
+       else
+               pixbuf = gdk_pixbuf_new_from_stream (stream, cancellable, &error);
+
+       g_simple_async_result_set_op_res_gpointer (result, NULL, NULL);
+
+       /* Set the new pixbuf as the result, or error out */
+       if (pixbuf == NULL) {
+               g_simple_async_result_take_error (result, error);
+       } else {
+               g_simple_async_result_set_op_res_gpointer (result, g_object_ref (pixbuf), g_object_unref);
+       }
+}
+
+/**
+ * gdk_pixbuf_new_from_stream_at_scale_async:
+ * @stream: a #GInputStream from which to load the pixbuf
+ * @width: the width the image should have or -1 to not constrain the width
+ * @height: the height the image should have or -1 to not constrain the height
+ * @preserve_aspect_ratio: %TRUE to preserve the image's aspect ratio
+ * @cancellable: optional #GCancellable object, %NULL to ignore
+ * @callback: a #GAsyncReadyCallback to call when the the pixbuf is loaded
+ * @user_data: the data to pass to the callback function
+ *
+ * Creates a new pixbuf by asynchronously loading an image from an input stream.
+ *
+ * For more details see gdk_pixbuf_new_from_stream_at_scale(), which is the synchronous
+ * version of this function.
+ *
+ * When the operation is finished, @callback will be called in the main thread.
+ * You can then call gdk_pixbuf_new_from_stream_finish() to get the result of the operation.
+ *
+ * Since: 2.24
+ **/
+void
+gdk_pixbuf_new_from_stream_at_scale_async (GInputStream        *stream,
+                                          gint                 width,
+                                          gint                 height,
+                                          gboolean             preserve_aspect_ratio,
+                                          GCancellable        *cancellable,
+                                          GAsyncReadyCallback  callback,
+                                          gpointer             user_data)
+{
+       GSimpleAsyncResult *result;
+       AtScaleData *data;
+
+       g_return_if_fail (G_IS_INPUT_STREAM (stream));
+       g_return_if_fail (callback != NULL);
+       g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+       data = g_slice_new (AtScaleData);
+       data->width = width;
+       data->height = height;
+       data->preserve_aspect_ratio = preserve_aspect_ratio;
+
+       result = g_simple_async_result_new (G_OBJECT (stream), callback, user_data, gdk_pixbuf_new_from_stream_at_scale_async);
+       g_simple_async_result_set_op_res_gpointer (result, data, (GDestroyNotify) at_scale_data_async_data_free);
+       g_simple_async_result_run_in_thread (result, (GSimpleAsyncThreadFunc) new_from_stream_thread, G_PRIORITY_DEFAULT, cancellable);
+       g_object_unref (result);
+}
+
+/**
+ * gdk_pixbuf_new_from_stream:
+ * @stream:  a #GInputStream to load the pixbuf from
+ * @cancellable: optional #GCancellable object, %NULL to ignore
+ * @error: Return location for an error
+ *
+ * Creates a new pixbuf by loading an image from an input stream.  
+ *
+ * The file format is detected automatically. If %NULL is returned, then 
+ * @error will be set. The @cancellable can be used to abort the operation
+ * from another thread. If the operation was cancelled, the error 
+ * %GIO_ERROR_CANCELLED will be returned. Other possible errors are in 
+ * the #GDK_PIXBUF_ERROR and %G_IO_ERROR domains. 
+ *
+ * The stream is not closed.
+ *
+ * Return value: A newly-created pixbuf, or %NULL if any of several error 
+ * conditions occurred: the file could not be opened, the image format is 
+ * not supported, there was not enough memory to allocate the image buffer, 
+ * the stream contained invalid data, or the operation was cancelled.
+ *
+ * Since: 2.14
+ **/
+GdkPixbuf *
+gdk_pixbuf_new_from_stream (GInputStream  *stream,
+                            GCancellable  *cancellable,
+                            GError       **error)
+{
+        GdkPixbuf *pixbuf;
+        GdkPixbufLoader *loader;
+
+        loader = gdk_pixbuf_loader_new ();
+        pixbuf = load_from_stream (loader, stream, cancellable, error);
+        g_object_unref (loader);
+
+        return pixbuf;
+}
+
+/**
+ * gdk_pixbuf_new_from_resource:
+ * @resource_path: the path of the resource file
+ * @error: Return location for an error
+ *
+ * Creates a new pixbuf by loading an image from an resource.
+ *
+ * The file format is detected automatically. If %NULL is returned, then
+ * @error will be set.
+ *
+ * Return value: A newly-created pixbuf, or %NULL if any of several error
+ * conditions occurred: the file could not be opened, the image format is
+ * not supported, there was not enough memory to allocate the image buffer,
+ * the stream contained invalid data, or the operation was cancelled.
+ *
+ * Since: 2.26
+ **/
+GdkPixbuf *
+gdk_pixbuf_new_from_resource (const char *resource_path,
+                             GError    **error)
+{
+       GInputStream *stream;
+       GdkPixbuf *pixbuf;
+       guint32 flags;
+       gsize data_size;
+       GBytes *bytes;
+
+       /* We specialize uncompressed GdkPixdata files, making these a reference to the
+          compiled-in resource data */
+       if (g_resources_get_info  (resource_path, 0, &data_size, &flags, NULL) &&
+           (flags & G_RESOURCE_FLAGS_COMPRESSED) == 0 &&
+           data_size >= GDK_PIXDATA_HEADER_LENGTH &&
+           (bytes = g_resources_lookup_data (resource_path, 0, NULL)) != NULL) {
+               GdkPixbuf*pixbuf = NULL;
+               const guint8 *stream = g_bytes_get_data (bytes, NULL);
+               GdkPixdata pixdata;
+               guint32 magic;
+
+               magic = (stream[0] << 24) + (stream[1] << 16) + (stream[2] << 8) + stream[3];
+               if (magic == GDK_PIXBUF_MAGIC_NUMBER &&
+                   gdk_pixdata_deserialize (&pixdata, data_size, stream, NULL)) {
+                       pixbuf = gdk_pixbuf_from_pixdata (&pixdata, FALSE, NULL);
+               }
+
+               if (pixbuf) {
+                       /* Free the GBytes with the pixbuf */
+                       g_object_set_data_full (G_OBJECT (pixbuf), "gdk-pixbuf-resource-bytes", bytes, (GDestroyNotify) g_bytes_unref);
+                       return pixbuf;
+               } else {
+                       g_bytes_unref (bytes);
+               }
+       }
+
+       stream = g_resources_open_stream (resource_path, 0, error);
+       if (stream == NULL)
+               return NULL;
+
+       pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, error);
+       g_object_unref (stream);
+       return pixbuf;
+}
+
+/**
+ * gdk_pixbuf_new_from_resource_at_scale:
+ * @resource_path: the path of the resource file
+ * @width: The width the image should have or -1 to not constrain the width
+ * @height: The height the image should have or -1 to not constrain the height
+ * @preserve_aspect_ratio: %TRUE to preserve the image's aspect ratio
+ * @error: Return location for an error
+ *
+ * Creates a new pixbuf by loading an image from an resource.
+ *
+ * The file format is detected automatically. If %NULL is returned, then
+ * @error will be set.
+ *
+ * The image will be scaled to fit in the requested size, optionally
+ * preserving the image's aspect ratio. When preserving the aspect ratio,
+ * a @width of -1 will cause the image to be scaled to the exact given
+ * height, and a @height of -1 will cause the image to be scaled to the
+ * exact given width. When not preserving aspect ratio, a @width or
+ * @height of -1 means to not scale the image at all in that dimension.
+ *
+ * The stream is not closed.
+ *
+ * Return value: A newly-created pixbuf, or %NULL if any of several error
+ * conditions occurred: the file could not be opened, the image format is
+ * not supported, there was not enough memory to allocate the image buffer,
+ * the stream contained invalid data, or the operation was cancelled.
+ *
+ * Since: 2.26
+ */
+GdkPixbuf *
+gdk_pixbuf_new_from_resource_at_scale (const char *resource_path,
+                                      int         width,
+                                      int         height,
+                                      gboolean    preserve_aspect_ratio,
+                                      GError    **error)
+{
+       GInputStream *stream;
+       GdkPixbuf *pixbuf;
+
+       stream = g_resources_open_stream (resource_path, 0, error);
+       if (stream == NULL)
+               return NULL;
+
+       pixbuf = gdk_pixbuf_new_from_stream_at_scale (stream, width, height, preserve_aspect_ratio, NULL, error);
+       g_object_unref (stream);
+       return pixbuf;
+}
+
+/**
+ * gdk_pixbuf_new_from_stream_async:
+ * @stream: a #GInputStream from which to load the pixbuf
+ * @cancellable: optional #GCancellable object, %NULL to ignore
+ * @callback: a #GAsyncReadyCallback to call when the the pixbuf is loaded
+ * @user_data: the data to pass to the callback function
+ *
+ * Creates a new pixbuf by asynchronously loading an image from an input stream.
+ *
+ * For more details see gdk_pixbuf_new_from_stream(), which is the synchronous
+ * version of this function.
+ *
+ * When the operation is finished, @callback will be called in the main thread.
+ * You can then call gdk_pixbuf_new_from_stream_finish() to get the result of the operation.
+ *
+ * Since: 2.24
+ **/
+void
+gdk_pixbuf_new_from_stream_async (GInputStream        *stream,
+                                 GCancellable        *cancellable,
+                                 GAsyncReadyCallback  callback,
+                                 gpointer             user_data)
+{
+       GSimpleAsyncResult *result;
+
+       g_return_if_fail (G_IS_INPUT_STREAM (stream));
+       g_return_if_fail (callback != NULL);
+       g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+       result = g_simple_async_result_new (G_OBJECT (stream), callback, user_data, gdk_pixbuf_new_from_stream_async);
+       g_simple_async_result_run_in_thread (result, (GSimpleAsyncThreadFunc) new_from_stream_thread, G_PRIORITY_DEFAULT, cancellable);
+       g_object_unref (result);
+}
+
+/**
+ * gdk_pixbuf_new_from_stream_finish:
+ * @async_result: a #GAsyncResult
+ * @error: a #GError, or %NULL
+ *
+ * Finishes an asynchronous pixbuf creation operation started with
+ * gdk_pixbuf_new_from_stream_async().
+ *
+ * Return value: a #GdkPixbuf or %NULL on error. Free the returned
+ * object with g_object_unref().
+ *
+ * Since: 2.24
+ **/
+GdkPixbuf *
+gdk_pixbuf_new_from_stream_finish (GAsyncResult  *async_result,
+                                  GError       **error)
+{
+       GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (async_result);
+
+       g_return_val_if_fail (G_IS_ASYNC_RESULT (async_result), NULL);
+       g_return_val_if_fail (!error || (error && !*error), NULL);
+       g_warn_if_fail (g_simple_async_result_get_source_tag (result) == gdk_pixbuf_new_from_stream_async ||
+                       g_simple_async_result_get_source_tag (result) == gdk_pixbuf_new_from_stream_at_scale_async);
+
+       if (g_simple_async_result_propagate_error (result, error))
+               return NULL;
+
+       return g_simple_async_result_get_op_res_gpointer (result);
+}
+
+static void
+info_cb (GdkPixbufLoader *loader, 
+         int              width,
+         int              height,
+         gpointer         data)
+{
+        struct {
+                GdkPixbufFormat *format;
+                int width;
+                int height;
+        } *info = data;
+
+        g_return_if_fail (width > 0 && height > 0);
+
+        info->format = gdk_pixbuf_loader_get_format (loader);
+        info->width = width;
+        info->height = height;
+
+        gdk_pixbuf_loader_set_size (loader, 0, 0);
+}
+
+/**
+ * gdk_pixbuf_get_file_info:
+ * @filename: The name of the file to identify.
+ * @width: (out): Return location for the width of the image, or %NULL
+ * @height: (out): Return location for the height of the image, or %NULL
+ * 
+ * Parses an image file far enough to determine its format and size.
+ * 
+ * Returns: (transfer none): A #GdkPixbufFormat describing the image
+ *    format of the file or %NULL if the image format wasn't
+ *    recognized. The return value is owned by GdkPixbuf and should
+ *    not be freed.
+ *
+ * Since: 2.4
+ **/
+GdkPixbufFormat *
+gdk_pixbuf_get_file_info (const gchar  *filename,
+                          gint         *width, 
+                          gint         *height)
+{
+        GdkPixbufLoader *loader;
+        guchar buffer[SNIFF_BUFFER_SIZE];
+        int length;
+        FILE *f;
+        struct {
+                GdkPixbufFormat *format;
+                gint width;
+                gint height;
+        } info;
+
+        g_return_val_if_fail (filename != NULL, NULL);
+
+        f = g_fopen (filename, "rb");
+        if (!f)
+                return NULL;
+
+        loader = gdk_pixbuf_loader_new ();
+
+        info.format = NULL;
+        info.width = -1;
+        info.height = -1;
+                
+        g_signal_connect (loader, "size-prepared", G_CALLBACK (info_cb), &info);
+
+        while (!feof (f) && !ferror (f)) {
+                length = fread (buffer, 1, sizeof (buffer), f);
+                if (length > 0) {
+                        if (!gdk_pixbuf_loader_write (loader, buffer, length, NULL))
+                                break;
+                }
+                if (info.format != NULL)
+                        break;
+        }
+
+        fclose (f);
+        gdk_pixbuf_loader_close (loader, NULL);
+        g_object_unref (loader);
+
+        if (width) 
+                *width = info.width;
+        if (height) 
+                *height = info.height;
+
+        return info.format;
+}
+
+/**
+ * gdk_pixbuf_new_from_xpm_data:
+ * @data: Pointer to inline XPM data.
+ *
+ * Creates a new pixbuf by parsing XPM data in memory.  This data is commonly
+ * the result of including an XPM file into a program's C source.
+ *
+ * Return value: A newly-created pixbuf with a reference count of 1.
+ **/
+GdkPixbuf *
+gdk_pixbuf_new_from_xpm_data (const char **data)
+{
+        GdkPixbuf *(* load_xpm_data) (const char **data);
+        GdkPixbuf *pixbuf;
+        GError *error = NULL;
+        GdkPixbufModule *xpm_module;
+        gboolean locked;
+
+        g_return_val_if_fail (data != NULL, NULL);
+
+        xpm_module = _gdk_pixbuf_get_named_module ("xpm", &error);
+        if (xpm_module == NULL) {
+                g_warning ("Error loading XPM image loader: %s", error->message);
+                g_error_free (error);
+                return NULL;
+        }
+
+        if (!_gdk_pixbuf_load_module (xpm_module, &error)) {
+                g_warning ("Error loading XPM image loader: %s", error->message);
+                g_error_free (error);
+                return NULL;
+        }
+
+        locked = _gdk_pixbuf_lock (xpm_module);
+
+        if (xpm_module->load_xpm_data == NULL) {
+                g_warning ("gdk-pixbuf XPM module lacks XPM data capability");
+                pixbuf = NULL;
+        } else {
+                load_xpm_data = xpm_module->load_xpm_data;
+                pixbuf = (* load_xpm_data) (data);
+        }
+        
+        if (locked)
+                _gdk_pixbuf_unlock (xpm_module);
+        return pixbuf;
+}
+
+static void
+collect_save_options (va_list   opts,
+                      gchar  ***keys,
+                      gchar  ***vals)
+{
+  gchar *key;
+  gchar *val;
+  gchar *next;
+  gint count;
+
+  count = 0;
+  *keys = NULL;
+  *vals = NULL;
+  
+  next = va_arg (opts, gchar*);
+  while (next)
+    {
+      key = next;
+      val = va_arg (opts, gchar*);
+
+      ++count;
+
+      /* woo, slow */
+      *keys = g_realloc (*keys, sizeof(gchar*) * (count + 1));
+      *vals = g_realloc (*vals, sizeof(gchar*) * (count + 1));
+      
+      (*keys)[count-1] = g_strdup (key);
+      (*vals)[count-1] = g_strdup (val);
+
+      (*keys)[count] = NULL;
+      (*vals)[count] = NULL;
+      
+      next = va_arg (opts, gchar*);
+    }
+}
+
+static gboolean
+save_to_file_callback (const gchar *buf,
+                       gsize        count,
+                       GError     **error,
+                       gpointer     data)
+{
+        FILE *filehandle = data;
+        gsize n;
+
+        n = fwrite (buf, 1, count, filehandle);
+        if (n != count) {
+                gint save_errno = errno;
+                g_set_error (error,
+                             G_FILE_ERROR,
+                             g_file_error_from_errno (save_errno),
+                             _("Error writing to image file: %s"),
+                             g_strerror (save_errno));
+                return FALSE;
+        }
+        return TRUE;
+}
+
+static gboolean
+gdk_pixbuf_real_save (GdkPixbuf     *pixbuf, 
+                      FILE          *filehandle, 
+                      const char    *type, 
+                      gchar        **keys,
+                      gchar        **values,
+                      GError       **error)
+{
+        gboolean ret;
+        GdkPixbufModule *image_module = NULL;       
+        gboolean locked;
+
+        image_module = _gdk_pixbuf_get_named_module (type, error);
+
+        if (image_module == NULL)
+                return FALSE;
+       
+        if (!_gdk_pixbuf_load_module (image_module, error))
+                return FALSE;
+
+        locked = _gdk_pixbuf_lock (image_module);
+
+        if (image_module->save) {
+                /* save normally */
+                ret = (* image_module->save) (filehandle, pixbuf,
+                                              keys, values,
+                                              error);
+        } else if (image_module->save_to_callback) {
+                /* save with simple callback */
+                ret = (* image_module->save_to_callback) (save_to_file_callback,
+                                                          filehandle, pixbuf,
+                                                          keys, values,
+                                                          error);
+        } else {
+                /* can't save */
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
+                             _("This build of gdk-pixbuf does not support saving the image format: %s"),
+                             type);
+                ret = FALSE;
+        }
+
+        if (locked)
+                _gdk_pixbuf_unlock (image_module);
+        return ret;
+}
+
+#define TMP_FILE_BUF_SIZE 4096
+
+static gboolean
+save_to_callback_with_tmp_file (GdkPixbufModule   *image_module,
+                                GdkPixbuf         *pixbuf,
+                                GdkPixbufSaveFunc  save_func,
+                                gpointer           user_data,
+                                gchar            **keys,
+                                gchar            **values,
+                                GError           **error)
+{
+        int fd;
+        FILE *f = NULL;
+        gboolean retval = FALSE;
+        gchar *buf = NULL;
+        gsize n;
+        gchar *filename = NULL;
+        gboolean locked;
+
+        buf = g_try_malloc (TMP_FILE_BUF_SIZE);
+        if (buf == NULL) {
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                     _("Insufficient memory to save image to callback"));
+                goto end;
+        }
+
+        fd = g_file_open_tmp ("gdkpixbuf-save-tmp.XXXXXX", &filename, error);
+        if (fd == -1)
+                goto end;
+        f = fdopen (fd, "wb+");
+        if (f == NULL) {
+                gint save_errno = errno;
+                g_set_error_literal (error,
+                                     G_FILE_ERROR,
+                                     g_file_error_from_errno (save_errno),
+                                     _("Failed to open temporary file"));
+                goto end;
+        }
+
+        locked = _gdk_pixbuf_lock (image_module);
+        retval = (image_module->save) (f, pixbuf, keys, values, error);
+        if (locked)
+                _gdk_pixbuf_unlock (image_module);
+        if (!retval)
+                goto end;
+
+        rewind (f);
+        for (;;) {
+                n = fread (buf, 1, TMP_FILE_BUF_SIZE, f);
+                if (n > 0) {
+                        if (!save_func (buf, n, error, user_data))
+                                goto end;
+                }
+                if (n != TMP_FILE_BUF_SIZE) 
+                        break;
+        }
+        if (ferror (f)) {
+                gint save_errno = errno;
+                g_set_error_literal (error,
+                                     G_FILE_ERROR,
+                                     g_file_error_from_errno (save_errno),
+                                     _("Failed to read from temporary file"));
+                goto end;
+        }
+        retval = TRUE;
+
+ end:
+        /* cleanup and return retval */
+        if (f)
+                fclose (f);
+        if (filename) {
+                g_unlink (filename);
+                g_free (filename);
+        }
+        g_free (buf);
+
+        return retval;
+}
+
+static gboolean
+gdk_pixbuf_real_save_to_callback (GdkPixbuf         *pixbuf,
+                                  GdkPixbufSaveFunc  save_func,
+                                  gpointer           user_data,
+                                  const char        *type, 
+                                  gchar            **keys,
+                                  gchar            **values,
+                                  GError           **error)
+{
+        gboolean ret;
+        GdkPixbufModule *image_module = NULL;       
+        gboolean locked;
+
+        image_module = _gdk_pixbuf_get_named_module (type, error);
+
+        if (image_module == NULL)
+                return FALSE;
+       
+        if (!_gdk_pixbuf_load_module (image_module, error))
+                return FALSE;
+
+        locked = _gdk_pixbuf_lock (image_module);
+
+        if (image_module->save_to_callback) {
+                /* save normally */
+                ret = (* image_module->save_to_callback) (save_func, user_data, 
+                                                          pixbuf, keys, values,
+                                                          error);
+        } else if (image_module->save) {
+                /* use a temporary file */
+                ret = save_to_callback_with_tmp_file (image_module, pixbuf,
+                                                      save_func, user_data, 
+                                                      keys, values,
+                                                      error);
+        } else {
+                /* can't save */
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
+                             _("This build of gdk-pixbuf does not support saving the image format: %s"),
+                             type);
+                ret = FALSE;
+        }
+
+        if (locked)
+                _gdk_pixbuf_unlock (image_module);
+        return ret;
+}
+
+/**
+ * gdk_pixbuf_save:
+ * @pixbuf: a #GdkPixbuf.
+ * @filename: name of file to save.
+ * @type: name of file format.
+ * @error: (allow-none): return location for error, or %NULL
+ * @Varargs: list of key-value save options
+ *
+ * Saves pixbuf to a file in format @type. By default, "jpeg", "png", "ico" 
+ * and "bmp" are possible file formats to save in, but more formats may be
+ * installed. The list of all writable formats can be determined in the 
+ * following way:
+ *
+ * |[
+ * void add_if_writable (GdkPixbufFormat *data, GSList **list)
+ * {
+ *   if (gdk_pixbuf_format_is_writable (data))
+ *     *list = g_slist_prepend (*list, data);
+ * }
+ * 
+ * GSList *formats = gdk_pixbuf_get_formats ();
+ * GSList *writable_formats = NULL;
+ * g_slist_foreach (formats, add_if_writable, &writable_formats);
+ * g_slist_free (formats);
+ * ]|
+ *
+ * If @error is set, %FALSE will be returned. Possible errors include 
+ * those in the #GDK_PIXBUF_ERROR domain and those in the #G_FILE_ERROR domain.
+ *
+ * The variable argument list should be %NULL-terminated; if not empty,
+ * it should contain pairs of strings that modify the save
+ * parameters. For example:
+ * <informalexample><programlisting>
+ * gdk_pixbuf_save (pixbuf, handle, "jpeg", &amp;error,
+ *                  "quality", "100", NULL);
+ * </programlisting></informalexample>
+ *
+ * Currently only few parameters exist. JPEG images can be saved with a
+ * "quality" parameter; its value should be in the range [0,100].
+ *
+ * Text chunks can be attached to PNG images by specifying parameters of
+ * the form "tEXt::key", where key is an ASCII string of length 1-79.
+ * The values are UTF-8 encoded strings. The PNG compression level can
+ * be specified using the "compression" parameter; it's value is in an
+ * integer in the range of [0,9].
+ *
+ * ICC color profiles can also be embedded into PNG and TIFF images.
+ * The "icc-profile" value should be the complete ICC profile encoded
+ * into base64.
+ *
+ * <informalexample><programlisting>
+ * gchar *contents;
+ * gchar *contents_encode;
+ * gsize length;
+ * g_file_get_contents ("/home/hughsie/.color/icc/L225W.icm", &contents, &length, NULL);
+ * contents_encode = g_base64_encode ((const guchar *) contents, length);
+ * gdk_pixbuf_save (pixbuf, handle, "png", &amp;error,
+ *                  "icc-profile", contents_encode,
+ *                  NULL);
+ * </programlisting></informalexample>
+ *
+ * TIFF images recognize a "compression" option which acceps an integer value.
+ * Among the codecs are 1 None, 2 Huffman, 5 LZW, 7 JPEG and 8 Deflate, see
+ * the libtiff documentation and tiff.h for all supported codec values.
+ *
+ * ICO images can be saved in depth 16, 24, or 32, by using the "depth"
+ * parameter. When the ICO saver is given "x_hot" and "y_hot" parameters,
+ * it produces a CUR instead of an ICO.
+ *
+ * Return value: whether an error was set
+ **/
+
+gboolean
+gdk_pixbuf_save (GdkPixbuf  *pixbuf, 
+                 const char *filename, 
+                 const char *type, 
+                 GError    **error,
+                 ...)
+{
+        gchar **keys = NULL;
+        gchar **values = NULL;
+        va_list args;
+        gboolean result;
+
+        g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+        
+        va_start (args, error);
+        
+        collect_save_options (args, &keys, &values);
+        
+        va_end (args);
+
+        result = gdk_pixbuf_savev (pixbuf, filename, type,
+                                   keys, values,
+                                   error);
+
+        g_strfreev (keys);
+        g_strfreev (values);
+
+        return result;
+}
+
+#ifdef G_OS_WIN32
+
+#undef gdk_pixbuf_save
+
+gboolean
+gdk_pixbuf_save (GdkPixbuf  *pixbuf, 
+                 const char *filename, 
+                 const char *type, 
+                 GError    **error,
+                 ...)
+{
+        char *utf8_filename;
+        gchar **keys = NULL;
+        gchar **values = NULL;
+        va_list args;
+        gboolean result;
+
+        g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+        
+        utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, error);
+
+        if (utf8_filename == NULL)
+                return FALSE;
+
+        va_start (args, error);
+        
+        collect_save_options (args, &keys, &values);
+        
+        va_end (args);
+
+        result = gdk_pixbuf_savev_utf8 (pixbuf, utf8_filename, type,
+                                        keys, values,
+                                        error);
+
+        g_free (utf8_filename);
+
+        g_strfreev (keys);
+        g_strfreev (values);
+
+        return result;
+}
+
+#endif
+
+/**
+ * gdk_pixbuf_savev:
+ * @pixbuf: a #GdkPixbuf.
+ * @filename: name of file to save.
+ * @type: name of file format.
+ * @option_keys: (array zero-terminated=1): name of options to set, %NULL-terminated
+ * @option_values: (array zero-terminated=1): values for named options
+ * @error: (allow-none): return location for error, or %NULL
+ *
+ * Saves pixbuf to a file in @type, which is currently "jpeg", "png", "tiff", "ico" or "bmp".
+ * If @error is set, %FALSE will be returned. 
+ * See gdk_pixbuf_save () for more details.
+ *
+ * Return value: whether an error was set
+ **/
+
+gboolean
+gdk_pixbuf_savev (GdkPixbuf  *pixbuf, 
+                  const char *filename, 
+                  const char *type,
+                  char      **option_keys,
+                  char      **option_values,
+                  GError    **error)
+{
+        FILE *f = NULL;
+        gboolean result;
+       
+        g_return_val_if_fail (filename != NULL, FALSE);
+        g_return_val_if_fail (type != NULL, FALSE);
+        g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+       
+        f = g_fopen (filename, "wb");
+        
+        if (f == NULL) {
+                gint save_errno = errno;
+                gchar *display_name = g_filename_display_name (filename);
+                g_set_error (error,
+                             G_FILE_ERROR,
+                             g_file_error_from_errno (save_errno),
+                             _("Failed to open '%s' for writing: %s"),
+                             display_name,
+                             g_strerror (save_errno));
+                g_free (display_name);
+                return FALSE;
+        }
+
+       
+       result = gdk_pixbuf_real_save (pixbuf, f, type,
+                                      option_keys, option_values,
+                                      error);
+       
+       
+       if (!result) {
+               g_return_val_if_fail (error == NULL || *error != NULL, FALSE);
+               fclose (f);
+               g_unlink (filename);
+               return FALSE;
+       }
+
+       if (fclose (f) < 0) {
+               gint save_errno = errno;
+               gchar *display_name = g_filename_display_name (filename);
+               g_set_error (error,
+                            G_FILE_ERROR,
+                            g_file_error_from_errno (save_errno),
+                            _("Failed to close '%s' while writing image, all data may not have been saved: %s"),
+                            display_name,
+                            g_strerror (save_errno));
+               g_free (display_name);
+               return FALSE;
+       }
+       
+       return TRUE;
+}
+
+#ifdef G_OS_WIN32
+
+#undef gdk_pixbuf_savev
+
+gboolean
+gdk_pixbuf_savev (GdkPixbuf  *pixbuf, 
+                  const char *filename, 
+                  const char *type,
+                  char      **option_keys,
+                  char      **option_values,
+                  GError    **error)
+{
+        char *utf8_filename;
+        gboolean retval;
+
+        g_return_val_if_fail (filename != NULL, FALSE);
+       
+        utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, error);
+
+        if (utf8_filename == NULL)
+                return FALSE;
+
+        retval = gdk_pixbuf_savev_utf8 (pixbuf, utf8_filename, type,
+                                        option_keys, option_values, error);
+
+        g_free (utf8_filename);
+
+        return retval;
+}
+
+#endif
+
+/**
+ * gdk_pixbuf_save_to_callback:
+ * @pixbuf: a #GdkPixbuf.
+ * @save_func: (scope call): a function that is called to save each block of data that
+ *   the save routine generates.
+ * @user_data: user data to pass to the save function.
+ * @type: name of file format.
+ * @error: (allow-none): return location for error, or %NULL
+ * @Varargs: list of key-value save options
+ *
+ * Saves pixbuf in format @type by feeding the produced data to a 
+ * callback. Can be used when you want to store the image to something 
+ * other than a file, such as an in-memory buffer or a socket.  
+ * If @error is set, %FALSE will be returned. Possible errors
+ * include those in the #GDK_PIXBUF_ERROR domain and whatever the save
+ * function generates.
+ *
+ * See gdk_pixbuf_save() for more details.
+ *
+ * Return value: whether an error was set
+ *
+ * Since: 2.4
+ **/
+gboolean
+gdk_pixbuf_save_to_callback    (GdkPixbuf  *pixbuf,
+                                GdkPixbufSaveFunc save_func,
+                                gpointer user_data,
+                                const char *type, 
+                                GError    **error,
+                                ...)
+{
+        gchar **keys = NULL;
+        gchar **values = NULL;
+        va_list args;
+        gboolean result;
+        
+        g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+        
+        va_start (args, error);
+        
+        collect_save_options (args, &keys, &values);
+        
+        va_end (args);
+
+        result = gdk_pixbuf_save_to_callbackv (pixbuf, save_func, user_data,
+                                               type, keys, values,
+                                               error);
+
+        g_strfreev (keys);
+        g_strfreev (values);
+
+        return result;
+}
+
+/**
+ * gdk_pixbuf_save_to_callbackv:
+ * @pixbuf: a #GdkPixbuf.
+ * @save_func: (scope call): a function that is called to save each block of data that
+ *   the save routine generates.
+ * @user_data: (closure): user data to pass to the save function.
+ * @type: name of file format.
+ * @option_keys: (array zero-terminated=1) (element-type utf8): name of options to set, %NULL-terminated
+ * @option_values: (array zero-terminated=1) (element-type utf8): values for named options
+ * @error: (allow-none): return location for error, or %NULL
+ *
+ * Saves pixbuf to a callback in format @type, which is currently "jpeg",
+ * "png", "tiff", "ico" or "bmp".  If @error is set, %FALSE will be returned. See
+ * gdk_pixbuf_save_to_callback () for more details.
+ *
+ * Return value: whether an error was set
+ *
+ * Since: 2.4
+ **/
+gboolean
+gdk_pixbuf_save_to_callbackv   (GdkPixbuf  *pixbuf, 
+                                GdkPixbufSaveFunc save_func,
+                                gpointer user_data,
+                                const char *type,
+                                char      **option_keys,
+                                char      **option_values,
+                                GError    **error)
+{
+        gboolean result;
+        
+       
+        g_return_val_if_fail (save_func != NULL, FALSE);
+        g_return_val_if_fail (type != NULL, FALSE);
+        g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+       
+       result = gdk_pixbuf_real_save_to_callback (pixbuf,
+                                                  save_func, user_data, type,
+                                                  option_keys, option_values,
+                                                  error);
+       
+       if (!result) {
+               g_return_val_if_fail (error == NULL || *error != NULL, FALSE);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+/**
+ * gdk_pixbuf_save_to_buffer:
+ * @pixbuf: a #GdkPixbuf.
+ * @buffer: (array length=buffer_size): location to receive a pointer
+ *   to the new buffer.
+ * @buffer_size: location to receive the size of the new buffer.
+ * @type: name of file format.
+ * @error: (allow-none): return location for error, or %NULL
+ * @Varargs: list of key-value save options
+ *
+ * Saves pixbuf to a new buffer in format @type, which is currently "jpeg",
+ * "png", "tiff", "ico" or "bmp".  This is a convenience function that uses
+ * gdk_pixbuf_save_to_callback() to do the real work. Note that the buffer 
+ * is not nul-terminated and may contain embedded  nuls.
+ * If @error is set, %FALSE will be returned and @buffer will be set to
+ * %NULL. Possible errors include those in the #GDK_PIXBUF_ERROR
+ * domain.
+ *
+ * See gdk_pixbuf_save() for more details.
+ *
+ * Return value: whether an error was set
+ *
+ * Since: 2.4
+ **/
+gboolean
+gdk_pixbuf_save_to_buffer      (GdkPixbuf  *pixbuf,
+                                gchar     **buffer,
+                                gsize      *buffer_size,
+                                const char *type, 
+                                GError    **error,
+                                ...)
+{
+        gchar **keys = NULL;
+        gchar **values = NULL;
+        va_list args;
+        gboolean result;
+        
+        g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+        
+        va_start (args, error);
+        
+        collect_save_options (args, &keys, &values);
+        
+        va_end (args);
+
+        result = gdk_pixbuf_save_to_bufferv (pixbuf, buffer, buffer_size,
+                                             type, keys, values,
+                                             error);
+
+        g_strfreev (keys);
+        g_strfreev (values);
+
+        return result;
+}
+
+struct SaveToBufferData {
+        gchar *buffer;
+        gsize len, max;
+};
+
+static gboolean
+save_to_buffer_callback (const gchar *data,
+                         gsize count,
+                         GError **error,
+                         gpointer user_data)
+{
+        struct SaveToBufferData *sdata = user_data;
+        gchar *new_buffer;
+        gsize new_max;
+
+        if (sdata->len + count > sdata->max) {
+                new_max = MAX (sdata->max*2, sdata->len + count);
+                new_buffer = g_try_realloc (sdata->buffer, new_max);
+                if (!new_buffer) {
+                        g_set_error_literal (error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                             _("Insufficient memory to save image into a buffer"));
+                        return FALSE;
+                }
+                sdata->buffer = new_buffer;
+                sdata->max = new_max;
+        }
+        memcpy (sdata->buffer + sdata->len, data, count);
+        sdata->len += count;
+        return TRUE;
+}
+
+/**
+ * gdk_pixbuf_save_to_bufferv:
+ * @pixbuf: a #GdkPixbuf.
+ * @buffer: (array length=buffer_size) (out) (element-type guint8):
+ *   location to receive a pointer to the new buffer.
+ * @buffer_size: location to receive the size of the new buffer.
+ * @type: name of file format.
+ * @option_keys: (array zero-terminated=1): name of options to set, %NULL-terminated
+ * @option_values: (array zero-terminated=1): values for named options
+ * @error: (allow-none): return location for error, or %NULL
+ *
+ * Saves pixbuf to a new buffer in format @type, which is currently "jpeg",
+ * "tiff", "png", "ico" or "bmp".  See gdk_pixbuf_save_to_buffer() 
+ * for more details.
+ *
+ * Return value: whether an error was set
+ *
+ * Since: 2.4
+ **/
+gboolean
+gdk_pixbuf_save_to_bufferv     (GdkPixbuf  *pixbuf,
+                                gchar     **buffer,
+                                gsize      *buffer_size,
+                                const char *type, 
+                                char      **option_keys,
+                                char      **option_values,
+                                GError    **error)
+{
+        static const gint initial_max = 1024;
+        struct SaveToBufferData sdata;
+
+        *buffer = NULL;
+        *buffer_size = 0;
+
+        sdata.buffer = g_try_malloc (initial_max);
+        sdata.max = initial_max;
+        sdata.len = 0;
+        if (!sdata.buffer) {
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                     _("Insufficient memory to save image into a buffer"));
+                return FALSE;
+        }
+
+        if (!gdk_pixbuf_save_to_callbackv (pixbuf,
+                                           save_to_buffer_callback, &sdata,
+                                           type, option_keys, option_values,
+                                           error)) {
+                g_free (sdata.buffer);
+                return FALSE;
+        }
+
+        *buffer = sdata.buffer;
+        *buffer_size = sdata.len;
+        return TRUE;
+}
+
+typedef struct {
+        GOutputStream *stream;
+        GCancellable  *cancellable;
+} SaveToStreamData;
+
+static gboolean
+save_to_stream (const gchar  *buffer,
+                gsize         count,
+                GError      **error,
+                gpointer      data)
+{
+        SaveToStreamData *sdata = (SaveToStreamData *)data;
+        gsize remaining;
+        gssize written;
+        GError *my_error = NULL;
+
+        remaining = count;
+        written = 0;
+        while (remaining > 0) {
+                buffer += written;
+                remaining -= written;
+                written = g_output_stream_write (sdata->stream, 
+                                                 buffer, remaining, 
+                                                 sdata->cancellable, 
+                                                 &my_error);
+                if (written < 0) {
+                        if (!my_error) {
+                                g_set_error_literal (error,
+                                                     G_IO_ERROR, 0,
+                                                     _("Error writing to image stream"));
+                        }
+                        else {
+                                g_propagate_error (error, my_error);
+                        }
+                        return FALSE;
+                }
+        }
+
+        return TRUE;
+}
+
+/** 
+ * gdk_pixbuf_save_to_stream:
+ * @pixbuf: a #GdkPixbuf
+ * @stream: a #GOutputStream to save the pixbuf to
+ * @type: name of file format
+ * @cancellable: optional #GCancellable object, %NULL to ignore
+ * @error: (allow-none): return location for error, or %NULL
+ * @Varargs: list of key-value save options
+ *
+ * Saves @pixbuf to an output stream.
+ *
+ * Supported file formats are currently "jpeg", "tiff", "png", "ico" or 
+ * "bmp". See gdk_pixbuf_save_to_buffer() for more details.
+ *
+ * The @cancellable can be used to abort the operation from another 
+ * thread. If the operation was cancelled, the error %GIO_ERROR_CANCELLED 
+ * will be returned. Other possible errors are in the #GDK_PIXBUF_ERROR 
+ * and %G_IO_ERROR domains. 
+ *
+ * The stream is not closed.
+ *
+ * Returns: %TRUE if the pixbuf was saved successfully, %FALSE if an
+ *     error was set.
+ *
+ * Since: 2.14
+ */
+gboolean
+gdk_pixbuf_save_to_stream (GdkPixbuf      *pixbuf,
+                           GOutputStream  *stream,
+                           const char     *type,
+                           GCancellable   *cancellable,
+                           GError        **error,
+                           ...)
+{
+        gboolean res;
+        gchar **keys = NULL;
+        gchar **values = NULL;
+        va_list args;
+        SaveToStreamData data;
+
+        va_start (args, error);
+        collect_save_options (args, &keys, &values);
+        va_end (args);
+
+        data.stream = stream;
+        data.cancellable = cancellable;
+
+        res = gdk_pixbuf_save_to_callbackv (pixbuf, save_to_stream, 
+                                            &data, type, 
+                                            keys, values, 
+                                            error);
+
+        g_strfreev (keys);
+        g_strfreev (values);
+
+        return res;
+}
+
+typedef struct {
+       GOutputStream *stream;
+       gchar *type;
+       gchar **keys;
+       gchar **values;
+} SaveToStreamAsyncData;
+
+static void
+save_to_stream_async_data_free (SaveToStreamAsyncData *data)
+{
+       if (data->stream)
+               g_object_unref (data->stream);
+       g_strfreev (data->keys);
+       g_strfreev (data->values);
+       g_free (data->type);
+       g_slice_free (SaveToStreamAsyncData, data);
+}
+
+static void
+save_to_stream_thread (GSimpleAsyncResult *result,
+                      GdkPixbuf          *pixbuf,
+                      GCancellable       *cancellable)
+{
+       SaveToStreamAsyncData *data;
+       SaveToStreamData sync_data;
+       gboolean retval;
+       GError *error = NULL;
+
+       data = g_simple_async_result_get_op_res_gpointer (result);
+       sync_data.stream = data->stream;
+       sync_data.cancellable = cancellable;
+
+       retval = gdk_pixbuf_save_to_callbackv (pixbuf, save_to_stream,
+                                              &sync_data, data->type,
+                                              data->keys, data->values,
+                                              &error);
+
+       /* Set the new pixbuf as the result, or error out */
+       if (retval == FALSE) {
+               g_simple_async_result_take_error (result, error);
+       } else {
+               g_simple_async_result_set_op_res_gboolean (result, TRUE);
+       }
+}
+
+/**
+ * gdk_pixbuf_save_to_stream_async:
+ * @pixbuf: a #GdkPixbuf
+ * @stream: a #GOutputStream to which to save the pixbuf
+ * @type: name of file format
+ * @cancellable: optional #GCancellable object, %NULL to ignore
+ * @callback: a #GAsyncReadyCallback to call when the the pixbuf is loaded
+ * @user_data: the data to pass to the callback function
+ * @Varargs: list of key-value save options
+ *
+ * Saves @pixbuf to an output stream asynchronously.
+ *
+ * For more details see gdk_pixbuf_save_to_stream(), which is the synchronous
+ * version of this function.
+ *
+ * When the operation is finished, @callback will be called in the main thread.
+ * You can then call gdk_pixbuf_save_to_stream_finish() to get the result of the operation.
+ *
+ * Since: 2.24
+ **/
+void
+gdk_pixbuf_save_to_stream_async (GdkPixbuf           *pixbuf,
+                                GOutputStream       *stream,
+                                const gchar         *type,
+                                GCancellable        *cancellable,
+                                GAsyncReadyCallback  callback,
+                                gpointer             user_data,
+                                ...)
+{
+       GSimpleAsyncResult *result;
+       gchar **keys = NULL;
+       gchar **values = NULL;
+       va_list args;
+       SaveToStreamAsyncData *data;
+
+       g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
+       g_return_if_fail (G_IS_OUTPUT_STREAM (stream));
+       g_return_if_fail (type != NULL);
+       g_return_if_fail (callback != NULL);
+       g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+       va_start (args, user_data);
+       collect_save_options (args, &keys, &values);
+       va_end (args);
+
+       data = g_slice_new (SaveToStreamAsyncData);
+       data->stream = g_object_ref (stream);
+       data->type = g_strdup (type);
+       data->keys = keys;
+       data->values = values;
+
+       result = g_simple_async_result_new (G_OBJECT (pixbuf), callback, user_data, gdk_pixbuf_save_to_stream_async);
+       g_simple_async_result_set_op_res_gpointer (result, data, (GDestroyNotify) save_to_stream_async_data_free);
+       g_simple_async_result_run_in_thread (result, (GSimpleAsyncThreadFunc) save_to_stream_thread, G_PRIORITY_DEFAULT, cancellable);
+       g_object_unref (result);
+}
+
+/**
+ * gdk_pixbuf_save_to_stream_finish:
+ * @async_result: a #GAsyncResult
+ * @error: a #GError, or %NULL
+ *
+ * Finishes an asynchronous pixbuf save operation started with
+ * gdk_pixbuf_save_to_stream_async().
+ *
+ * Return value: %TRUE if the pixbuf was saved successfully, %FALSE if an error was set.
+ *
+ * Since: 2.24
+ **/
+gboolean
+gdk_pixbuf_save_to_stream_finish (GAsyncResult  *async_result,
+                                 GError       **error)
+{
+       GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (async_result);
+
+       g_return_val_if_fail (G_IS_ASYNC_RESULT (async_result), FALSE);
+       g_return_val_if_fail (!error || (error && !*error), FALSE);
+       g_warn_if_fail (g_simple_async_result_get_source_tag (result) == gdk_pixbuf_save_to_stream_async);
+
+       if (g_simple_async_result_propagate_error (result, error))
+               return FALSE;
+
+       return g_simple_async_result_get_op_res_gboolean (result);
+}
+
+/**
+ * gdk_pixbuf_format_get_name:
+ * @format: a #GdkPixbufFormat
+ *
+ * Returns the name of the format.
+ * 
+ * Return value: the name of the format. 
+ *
+ * Since: 2.2
+ */
+gchar *
+gdk_pixbuf_format_get_name (GdkPixbufFormat *format)
+{
+        g_return_val_if_fail (format != NULL, NULL);
+
+        return g_strdup (format->name);
+}
+
+/**
+ * gdk_pixbuf_format_get_description:
+ * @format: a #GdkPixbufFormat
+ *
+ * Returns a description of the format.
+ * 
+ * Return value: a description of the format.
+ *
+ * Since: 2.2
+ */
+gchar *
+gdk_pixbuf_format_get_description (GdkPixbufFormat *format)
+{
+        gchar *domain;
+        const gchar *description;
+        g_return_val_if_fail (format != NULL, NULL);
+
+        if (format->domain != NULL) 
+                domain = format->domain;
+        else 
+                domain = GETTEXT_PACKAGE;
+        description = g_dgettext (domain, format->description);
+
+        return g_strdup (description);
+}
+
+/**
+ * gdk_pixbuf_format_get_mime_types:
+ * @format: a #GdkPixbufFormat
+ *
+ * Returns the mime types supported by the format.
+ * 
+ * Return value: (transfer full): a %NULL-terminated array of mime types which must be freed with 
+ * g_strfreev() when it is no longer needed.
+ *
+ * Since: 2.2
+ */
+gchar **
+gdk_pixbuf_format_get_mime_types (GdkPixbufFormat *format)
+{
+        g_return_val_if_fail (format != NULL, NULL);
+
+        return g_strdupv (format->mime_types);
+}
+
+/**
+ * gdk_pixbuf_format_get_extensions:
+ * @format: a #GdkPixbufFormat
+ *
+ * Returns the filename extensions typically used for files in the 
+ * given format.
+ * 
+ * Return value: (transfer full): a %NULL-terminated array of filename extensions which must be
+ * freed with g_strfreev() when it is no longer needed.
+ *
+ * Since: 2.2
+ */
+gchar **
+gdk_pixbuf_format_get_extensions (GdkPixbufFormat *format)
+{
+        g_return_val_if_fail (format != NULL, NULL);
+
+        return g_strdupv (format->extensions);
+}
+
+/**
+ * gdk_pixbuf_format_is_writable:
+ * @format: a #GdkPixbufFormat
+ *
+ * Returns whether pixbufs can be saved in the given format.
+ * 
+ * Return value: whether pixbufs can be saved in the given format.
+ *
+ * Since: 2.2
+ */
+gboolean
+gdk_pixbuf_format_is_writable (GdkPixbufFormat *format)
+{
+        g_return_val_if_fail (format != NULL, FALSE);
+
+        return (format->flags & GDK_PIXBUF_FORMAT_WRITABLE) != 0;
+}
+
+/**
+ * gdk_pixbuf_format_is_scalable:
+ * @format: a #GdkPixbufFormat
+ *
+ * Returns whether this image format is scalable. If a file is in a 
+ * scalable format, it is preferable to load it at the desired size, 
+ * rather than loading it at the default size and scaling the 
+ * resulting pixbuf to the desired size.
+ * 
+ * Return value: whether this image format is scalable.
+ *
+ * Since: 2.6
+ */
+gboolean
+gdk_pixbuf_format_is_scalable (GdkPixbufFormat *format)
+{
+        g_return_val_if_fail (format != NULL, FALSE);
+
+        return (format->flags & GDK_PIXBUF_FORMAT_SCALABLE) != 0;
+}
+
+/**
+ * gdk_pixbuf_format_is_disabled:
+ * @format: a #GdkPixbufFormat
+ *
+ * Returns whether this image format is disabled. See
+ * gdk_pixbuf_format_set_disabled().
+ * 
+ * Return value: whether this image format is disabled.
+ *
+ * Since: 2.6
+ */
+gboolean   
+gdk_pixbuf_format_is_disabled (GdkPixbufFormat *format)
+{
+        g_return_val_if_fail (format != NULL, FALSE);
+
+        return format->disabled;        
+}
+
+/**
+ * gdk_pixbuf_format_set_disabled:
+ * @format: a #GdkPixbufFormat
+ * @disabled: %TRUE to disable the format @format
+ *
+ * Disables or enables an image format. If a format is disabled, 
+ * gdk-pixbuf won't use the image loader for this format to load 
+ * images. Applications can use this to avoid using image loaders 
+ * with an inappropriate license, see gdk_pixbuf_format_get_license().
+ *
+ * Since: 2.6
+ */
+void 
+gdk_pixbuf_format_set_disabled (GdkPixbufFormat *format,
+                                gboolean         disabled)
+{
+        g_return_if_fail (format != NULL);
+        
+        format->disabled = disabled != FALSE;
+}
+
+/**
+ * gdk_pixbuf_format_get_license:
+ * @format: a #GdkPixbufFormat
+ *
+ * Returns information about the license of the image loader for the format. The
+ * returned string should be a shorthand for a wellknown license, e.g. "LGPL",
+ * "GPL", "QPL", "GPL/QPL", or "other" to indicate some other license.  This
+ * string should be freed with g_free() when it's no longer needed.
+ *
+ * Returns: a string describing the license of @format. 
+ *
+ * Since: 2.6
+ */
+gchar*
+gdk_pixbuf_format_get_license (GdkPixbufFormat *format)
+{
+        g_return_val_if_fail (format != NULL, NULL);
+
+        return g_strdup (format->license);
+}
+
+GdkPixbufFormat *
+_gdk_pixbuf_get_format (GdkPixbufModule *module)
+{
+        g_return_val_if_fail (module != NULL, NULL);
+
+        return module->info;
+}
+
+/**
+ * gdk_pixbuf_get_formats:
+ *
+ * Obtains the available information about the image formats supported
+ * by GdkPixbuf.
+ *
+ * Returns: (transfer container) (element-type GdkPixbufFormat): A list of
+ * #GdkPixbufFormat<!-- -->s describing the supported
+ * image formats.  The list should be freed when it is no longer needed,
+ * but the structures themselves are owned by #GdkPixbuf and should not be
+ * freed.
+ *
+ * Since: 2.2
+ */
+GSList *
+gdk_pixbuf_get_formats (void)
+{
+        GSList *result = NULL;
+        GSList *modules;
+
+        for (modules = get_file_formats (); modules; modules = g_slist_next (modules)) {
+                GdkPixbufModule *module = (GdkPixbufModule *)modules->data;
+                GdkPixbufFormat *info = _gdk_pixbuf_get_format (module);
+                result = g_slist_prepend (result, info);
+        }
+
+        return result;
+}
+
+/**
+ * gdk_pixbuf_format_copy:
+ * @format: a #GdkPixbufFormat
+ *
+ * Creates a copy of @format
+ *
+ * Return value: the newly allocated copy of a #GdkPixbufFormat. Use
+ *   gdk_pixbuf_format_free() to free the resources when done
+ *
+ * Since: 2.22
+ */
+GdkPixbufFormat *
+gdk_pixbuf_format_copy (const GdkPixbufFormat *format)
+{
+        if (G_LIKELY (format != NULL))
+                return g_slice_dup (GdkPixbufFormat, format);
+
+        return NULL;
+}
+
+/**
+ * gdk_pixbuf_format_free:
+ * @format: a #GdkPixbufFormat
+ *
+ * Frees the resources allocated when copying a #GdkPixbufFormat
+ * using gdk_pixbuf_format_copy()
+ *
+ * Since: 2.22
+ */
+void
+gdk_pixbuf_format_free (GdkPixbufFormat *format)
+{
+        if (G_LIKELY (format != NULL))
+                g_slice_free (GdkPixbufFormat, format);
+}
+
+G_DEFINE_BOXED_TYPE (GdkPixbufFormat, gdk_pixbuf_format,
+                    gdk_pixbuf_format_copy,
+                    gdk_pixbuf_format_free)
diff --git a/gdk-pixbuf/gdk-pixbuf-io.h b/gdk-pixbuf/gdk-pixbuf-io.h
new file mode 100644 (file)
index 0000000..41a99e4
--- /dev/null
@@ -0,0 +1,346 @@
+/* GdkPixbuf library - Io handling.  This is an internal header for 
+ * GdkPixbuf. You should never use it unless you are doing development for 
+ * GdkPixbuf itself.
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Authors: Mark Crichton <crichton@gimp.org>
+ *          Miguel de Icaza <miguel@gnu.org>
+ *          Federico Mena-Quintero <federico@gimp.org>
+ *          Jonathan Blandford <jrb@redhat.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
+ * 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.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#if defined(GDK_PIXBUF_DISABLE_SINGLE_INCLUDES) && !defined (GDK_PIXBUF_H_INSIDE) && !defined (GDK_PIXBUF_COMPILATION)
+#error "Only <gdk-pixbuf/gdk-pixbuf.h> can be included directly."
+#endif
+
+#ifndef GDK_PIXBUF_IO_H
+#define GDK_PIXBUF_IO_H
+
+#include <stdio.h>
+#include <glib.h>
+#include <gmodule.h>
+#include <gdk-pixbuf/gdk-pixbuf-core.h>
+#include <gdk-pixbuf/gdk-pixbuf-animation.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GdkPixbufFormat GdkPixbufFormat;
+GType gdk_pixbuf_format_get_type (void) G_GNUC_CONST;
+
+GSList    *gdk_pixbuf_get_formats            (void);
+gchar     *gdk_pixbuf_format_get_name        (GdkPixbufFormat *format);
+gchar     *gdk_pixbuf_format_get_description (GdkPixbufFormat *format);
+gchar    **gdk_pixbuf_format_get_mime_types  (GdkPixbufFormat *format);
+gchar    **gdk_pixbuf_format_get_extensions  (GdkPixbufFormat *format);
+gboolean   gdk_pixbuf_format_is_writable     (GdkPixbufFormat *format);
+gboolean   gdk_pixbuf_format_is_scalable     (GdkPixbufFormat *format);
+gboolean   gdk_pixbuf_format_is_disabled     (GdkPixbufFormat *format);
+void       gdk_pixbuf_format_set_disabled    (GdkPixbufFormat *format,
+                                             gboolean         disabled);
+gchar     *gdk_pixbuf_format_get_license     (GdkPixbufFormat *format);
+
+GdkPixbufFormat *gdk_pixbuf_get_file_info    (const gchar     *filename,
+                                             gint            *width, 
+                                             gint            *height);
+
+GdkPixbufFormat *gdk_pixbuf_format_copy (const GdkPixbufFormat *format);
+void             gdk_pixbuf_format_free (GdkPixbufFormat       *format);
+
+#ifdef GDK_PIXBUF_ENABLE_BACKEND
+
+\f
+
+/**
+ * GdkPixbufModuleSizeFunc:
+ * @width: pointer to a location containing the current image width
+ * @height: pointer to a location containing the current image height
+ * @user_data: the loader.
+ * 
+ * Defines the type of the function that gets called once the size 
+ * of the loaded image is known.
+ * 
+ * The function is expected to set @width and @height to the desired
+ * size to which the image should be scaled. If a module has no efficient 
+ * way to achieve the desired scaling during the loading of the image, it may
+ * either ignore the size request, or only approximate it -- &gdk-pixbuf; will
+ * then perform the required scaling on the completely loaded image. 
+ * 
+ * If the function sets @width or @height to zero, the module should interpret
+ * this as a hint that it will be closed soon and shouldn't allocate further 
+ * resources. This convention is used to implement gdk_pixbuf_get_file_info()
+ * efficiently.
+ * 
+ * Since: 2.2
+ */
+typedef void (* GdkPixbufModuleSizeFunc)           (gint *width, 
+                                                   gint *height, 
+                                                   gpointer user_data);
+
+/**
+ * GdkPixbufModulePreparedFunc:
+ * @pixbuf: the #GdkPixbuf that is currently being loaded.
+ * @anim: if an animation is being loaded, the #GdkPixbufAnimation, else %NULL.
+ * @user_data: the loader.
+ * 
+ * Defines the type of the function that gets called once the initial 
+ * setup of @pixbuf is done.
+ * 
+ * #GdkPixbufLoader uses a function of this type to emit the 
+ * "<link linkend="GdkPixbufLoader-area-prepared">area_prepared</link>"
+ * signal.
+ * 
+ * Since: 2.2
+ */
+typedef void (* GdkPixbufModulePreparedFunc) (GdkPixbuf          *pixbuf,
+                                             GdkPixbufAnimation *anim,
+                                             gpointer            user_data);
+
+/**
+ * GdkPixbufModuleUpdatedFunc:
+ * @pixbuf: the #GdkPixbuf that is currently being loaded.
+ * @x: the X origin of the updated area.
+ * @y: the Y origin of the updated area.
+ * @width: the width of the updated area.
+ * @height: the height of the updated area.
+ * @user_data: the loader.
+ * 
+ * Defines the type of the function that gets called every time a region
+ * of @pixbuf is updated.
+ * 
+ * #GdkPixbufLoader uses a function of this type to emit the 
+ * "<link linkend="GdkPixbufLoader-area-updated">area_updated</link>"
+ * signal.
+ * 
+ * Since: 2.2
+ */
+typedef void (* GdkPixbufModuleUpdatedFunc)  (GdkPixbuf *pixbuf,
+                                             int        x,
+                                             int        y,
+                                             int        width,
+                                             int        height,
+                                             gpointer   user_data);
+
+/**
+ * GdkPixbufModulePattern:
+ * @prefix: the prefix for this pattern
+ * @mask: mask containing bytes which modify how the prefix is matched against
+ *  test data
+ * @relevance: relevance of this pattern
+ * 
+ * The signature of a module is a set of prefixes. Prefixes are encoded as
+ * pairs of ordinary strings, where the second string, called the mask, if 
+ * not %NULL, must be of the same length as the first one and may contain 
+ * ' ', '!', 'x', 'z', and 'n' to indicate bytes that must be matched, 
+ * not matched, "don't-care"-bytes, zeros and non-zeros. 
+ * Each prefix has an associated integer that describes the relevance of 
+ * the prefix, with 0 meaning a mismatch and 100 a "perfect match".
+ * 
+ * Starting with &gdk-pixbuf; 2.8, the first byte of the mask may be '*', 
+ * indicating an unanchored pattern that matches not only at the beginning, 
+ * but also in the middle. Versions prior to 2.8 will interpret the '*'
+ * like an 'x'. 
+ * 
+ * The signature of a module is stored as an array of 
+ * #GdkPixbufModulePattern<!-- -->s. The array is terminated by a pattern
+ * where the @prefix is %NULL.
+ * 
+ * 
+ * <informalexample><programlisting>
+ * GdkPixbufModulePattern *signature[] = {
+ *   { "abcdx", " !x z", 100 },
+ *   { "bla", NULL,  90 },
+ *   { NULL, NULL, 0 }
+ * };
+ * </programlisting>
+ * The example matches e.g. "auud\0" with relevance 100, and "blau" with 
+ * relevance 90.</informalexample>
+ * 
+ * Since: 2.2
+ */
+typedef struct _GdkPixbufModulePattern GdkPixbufModulePattern;
+struct _GdkPixbufModulePattern {
+       char *prefix;
+       char *mask;
+       int relevance;
+};
+
+/**
+ * GdkPixbufModule:
+ * @module_name: the name of the module, usually the same as the
+ *  usual file extension for images of this type, eg. "xpm", "jpeg" or "png".
+ * @module_path: the path from which the module is loaded.
+ * @module: the loaded #GModule.
+ * @info: a #GdkPixbufFormat holding information about the module.
+ * @load: loads an image from a file.
+ * @load_xpm_data: loads an image from data in memory.
+ * @begin_load: begins an incremental load.
+ * @stop_load: stops an incremental load.
+ * @load_increment: continues an incremental load.
+ * @load_animation: loads an animation from a file.
+ * @save: saves a #GdkPixbuf to a file.
+ * @save_to_callback: saves a #GdkPixbuf by calling the given #GdkPixbufSaveFunc.
+ * 
+ * A #GdkPixbufModule contains the necessary functions to load and save 
+ * images in a certain file format. 
+ * 
+ * A #GdkPixbufModule can be loaded dynamically from a #GModule.
+ * Each loadable module must contain a #GdkPixbufModuleFillVtableFunc function 
+ * named <function>fill_vtable</function>, which will get called when the module
+ * is loaded and must set the function pointers of the #GdkPixbufModule. 
+ */
+typedef struct _GdkPixbufModule GdkPixbufModule;
+struct _GdkPixbufModule {
+       char *module_name;
+       char *module_path;
+       GModule *module;
+       GdkPixbufFormat *info;
+       
+        GdkPixbuf *(* load) (FILE    *f,
+                             GError **error);
+        GdkPixbuf *(* load_xpm_data) (const char **data);
+
+        /* Incremental loading */
+
+        gpointer (* begin_load)     (GdkPixbufModuleSizeFunc size_func,
+                                     GdkPixbufModulePreparedFunc prepare_func,
+                                     GdkPixbufModuleUpdatedFunc update_func,
+                                     gpointer user_data,
+                                     GError **error);
+        gboolean (* stop_load)      (gpointer context,
+                                     GError **error);
+        gboolean (* load_increment) (gpointer      context,
+                                     const guchar *buf,
+                                     guint         size,
+                                     GError      **error);
+
+       /* Animation loading */
+       GdkPixbufAnimation *(* load_animation) (FILE    *f,
+                                                GError **error);
+
+        /* Saving */
+        gboolean (* save) (FILE      *f,
+                           GdkPixbuf *pixbuf,
+                           gchar    **param_keys,
+                           gchar    **param_values,
+                           GError   **error);
+
+        gboolean (*save_to_callback) (GdkPixbufSaveFunc save_func,
+                                     gpointer user_data,
+                                     GdkPixbuf *pixbuf,
+                                     gchar **option_keys,
+                                     gchar **option_values,
+                                     GError **error);
+  
+  /*< private >*/
+       void (*_reserved1) (void); 
+       void (*_reserved2) (void); 
+       void (*_reserved3) (void); 
+       void (*_reserved4) (void); 
+       void (*_reserved5) (void); 
+
+};
+
+/**
+ * GdkPixbufModuleFillVtableFunc:
+ * @module: a #GdkPixbufModule.
+ * 
+ * Defines the type of the function used to set the vtable of a 
+ * #GdkPixbufModule when it is loaded. 
+ * 
+ * Since: 2.2
+ */
+
+typedef void (* GdkPixbufModuleFillVtableFunc) (GdkPixbufModule *module);
+
+/**
+ * GdkPixbufModuleFillInfoFunc:
+ * @info: a #GdkPixbufFormat.
+ * 
+ * Defines the type of the function used to fill a 
+ * #GdkPixbufFormat structure with information about a module.
+ * 
+ * Since: 2.2
+ */
+typedef void (* GdkPixbufModuleFillInfoFunc) (GdkPixbufFormat *info);
+
+/*  key/value pairs that can be attached by the pixbuf loader  */
+
+gboolean gdk_pixbuf_set_option  (GdkPixbuf   *pixbuf,
+                                 const gchar *key,
+                                 const gchar *value);
+
+/**
+ * GdkPixbufFormatFlags:
+ * @GDK_PIXBUF_FORMAT_WRITABLE: the module can write out images in the format.
+ * @GDK_PIXBUF_FORMAT_SCALABLE: the image format is scalable
+ * @GDK_PIXBUF_FORMAT_THREADSAFE: the module is threadsafe. If this flag is not
+ *  set, &gdk-pixbuf; will use a lock to prevent multiple threads from using
+ *  this module at the same time. (Since 2.6)
+ * 
+ * Flags which allow a module to specify further details about the supported
+ * operations.
+ * 
+ * Since: 2.2
+ */
+typedef enum /*< skip >*/
+{
+  GDK_PIXBUF_FORMAT_WRITABLE = 1 << 0,
+  GDK_PIXBUF_FORMAT_SCALABLE = 1 << 1,
+  GDK_PIXBUF_FORMAT_THREADSAFE = 1 << 2
+} GdkPixbufFormatFlags;
+
+/**
+ * GdkPixbufFormat:
+ * @name: the name of the image format.
+ * @signature: the signature of the module.
+ * @domain: the message domain for the @description.
+ * @description: a description of the image format.
+ * @mime_types: a %NULL-terminated array of MIME types for the image format.
+ * @extensions: a %NULL-terminated array of typical filename extensions for the
+ *  image format.
+ * @flags: a combination of #GdkPixbufFormatFlags.
+ * @disabled: a boolean determining whether the loader is disabled.
+ * @license: a string containing license information, typically set to 
+ *  shorthands like "GPL", "LGPL", etc.
+ * 
+ * A #GdkPixbufFormat contains information about the image format accepted by a
+ * module. Only modules should access the fields directly, applications should
+ * use the <function>gdk_pixbuf_format_*</function> functions.
+ * 
+ * Since: 2.2
+ */
+struct _GdkPixbufFormat {
+  gchar *name;
+  GdkPixbufModulePattern *signature;
+  gchar *domain;
+  gchar *description;
+  gchar **mime_types;
+  gchar **extensions;
+  guint32 flags;
+  gboolean disabled;
+  gchar *license;
+};
+
+#endif /* GDK_PIXBUF_ENABLE_BACKEND */
+
+G_END_DECLS
+
+#endif /* GDK_PIXBUF_IO_H */
diff --git a/gdk-pixbuf/gdk-pixbuf-loader.c b/gdk-pixbuf/gdk-pixbuf-loader.c
new file mode 100644 (file)
index 0000000..c2d2d90
--- /dev/null
@@ -0,0 +1,848 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* GdkPixbuf library - Progressive loader object
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Authors: Mark Crichton <crichton@gimp.org>
+ *          Miguel de Icaza <miguel@gnu.org>
+ *          Federico Mena-Quintero <federico@gimp.org>
+ *          Jonathan Blandford <jrb@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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 <string.h>
+
+#include "gdk-pixbuf-private.h"
+#include "gdk-pixbuf-animation.h"
+#include "gdk-pixbuf-scaled-anim.h"
+#include "gdk-pixbuf-loader.h"
+#include "gdk-pixbuf-marshal.h"
+
+/**
+ * SECTION:gdk-pixbuf-loader
+ * @Short_description: Application-driven progressive image loading.
+ * @Title: GdkPixbufLoader
+ * @See_also: gdk_pixbuf_new_from_file(), gdk_pixbuf_animation_new_from_file()
+ * 
+ * #GdkPixbufLoader provides a way for applications to drive the
+ * process of loading an image, by letting them send the image data
+ * directly to the loader instead of having the loader read the data
+ * from a file.  Applications can use this functionality instead of
+ * gdk_pixbuf_new_from_file() or gdk_pixbuf_animation_new_from_file() 
+ * when they need to parse image data in
+ * small chunks.  For example, it should be used when reading an
+ * image from a (potentially) slow network connection, or when
+ * loading an extremely large file.
+ * 
+ * 
+ * To use #GdkPixbufLoader to load an image, just create a new one,
+ * and call gdk_pixbuf_loader_write() to send the data to it.  When
+ * done, gdk_pixbuf_loader_close() should be called to end the stream
+ * and finalize everything.  The loader will emit three important
+ * signals throughout the process.  The first, "<link
+ * linkend="GdkPixbufLoader-size-prepared">size_prepared</link>",
+ * will be called as soon as the image has enough information to
+ * determine the size of the image to be used. If you want to scale
+ * the image while loading it, you can call gdk_pixbuf_loader_set_size()
+ * in response to this signal.
+ * 
+ * 
+ * The second signal, "<link
+ * linkend="GdkPixbufLoader-area-prepared">area_prepared</link>",
+ * will be called as soon as the pixbuf of the desired has been 
+ * allocated.  You can obtain it by calling gdk_pixbuf_loader_get_pixbuf(). 
+ * If you want to use it, simply ref it.  
+ * In addition, no actual information will be passed in yet, so the
+ * pixbuf can be safely filled with any temporary graphics (or an
+ * initial color) as needed.  You can also call
+ * gdk_pixbuf_loader_get_pixbuf() later and get the same pixbuf.
+ * 
+ * 
+ * The last signal, "<link
+ * linkend="GdkPixbufLoader-area-updated">area_updated</link>" gets
+ * called every time a region is updated.  This way you can update a
+ * partially completed image.  Note that you do not know anything
+ * about the completeness of an image from the area updated.  For
+ * example, in an interlaced image, you need to make several passes
+ * before the image is done loading.
+ * 
+ * 
+ * <refsect2>
+ * <title>Loading an animation</title>
+ * <para>
+ * Loading an animation is almost as easy as loading an
+ * image. Once the first "<link
+ * linkend="GdkPixbufLoader-area-prepared">area_prepared</link>" signal
+ * has been emitted, you can call gdk_pixbuf_loader_get_animation()
+ * to get the #GdkPixbufAnimation struct and gdk_pixbuf_animation_get_iter()
+ * to get an #GdkPixbufAnimationIter for displaying it. 
+ * </para>
+ * </refsect2>
+ */
+
+
+enum {
+        SIZE_PREPARED,
+        AREA_PREPARED,
+        AREA_UPDATED,
+        CLOSED,
+        LAST_SIGNAL
+};
+
+
+static void gdk_pixbuf_loader_finalize (GObject *loader);
+
+static guint    pixbuf_loader_signals[LAST_SIGNAL] = { 0 };
+
+/* Internal data */
+
+#define LOADER_HEADER_SIZE 1024
+
+typedef struct
+{
+        GdkPixbufAnimation *animation;
+        gboolean closed;
+        gboolean holds_threadlock;
+        guchar header_buf[LOADER_HEADER_SIZE];
+        gint header_buf_offset;
+        GdkPixbufModule *image_module;
+        gpointer context;
+        gint width;
+        gint height;
+        gboolean size_fixed;
+        gboolean needs_scale;
+} GdkPixbufLoaderPrivate;
+
+G_DEFINE_TYPE (GdkPixbufLoader, gdk_pixbuf_loader, G_TYPE_OBJECT)
+
+static void
+gdk_pixbuf_loader_class_init (GdkPixbufLoaderClass *class)
+{
+        GObjectClass *object_class;
+  
+        object_class = (GObjectClass *) class;
+  
+        object_class->finalize = gdk_pixbuf_loader_finalize;
+
+        /**
+         * GdkPixbufLoader::size-prepared:
+         * @loader: the object which received the signal.
+         * @width: the original width of the image
+         * @height: the original height of the image
+         *
+         * This signal is emitted when the pixbuf loader has been fed the
+         * initial amount of data that is required to figure out the size
+         * of the image that it will create.  Applications can call  
+         * gdk_pixbuf_loader_set_size() in response to this signal to set
+         * the desired size to which the image should be scaled.
+         */
+        pixbuf_loader_signals[SIZE_PREPARED] =
+                g_signal_new ("size-prepared",
+                              G_TYPE_FROM_CLASS (object_class),
+                              G_SIGNAL_RUN_LAST,
+                              G_STRUCT_OFFSET (GdkPixbufLoaderClass, size_prepared),
+                              NULL, NULL,
+                              _gdk_pixbuf_marshal_VOID__INT_INT,
+                              G_TYPE_NONE, 2, 
+                              G_TYPE_INT,
+                              G_TYPE_INT);
+  
+        /**
+         * GdkPixbufLoader::area-prepared:
+         * @loader: the object which received the signal.
+         *
+         * This signal is emitted when the pixbuf loader has allocated the 
+         * pixbuf in the desired size.  After this signal is emitted, 
+         * applications can call gdk_pixbuf_loader_get_pixbuf() to fetch 
+         * the partially-loaded pixbuf.
+         */
+        pixbuf_loader_signals[AREA_PREPARED] =
+                g_signal_new ("area-prepared",
+                              G_TYPE_FROM_CLASS (object_class),
+                              G_SIGNAL_RUN_LAST,
+                              G_STRUCT_OFFSET (GdkPixbufLoaderClass, area_prepared),
+                              NULL, NULL,
+                              _gdk_pixbuf_marshal_VOID__VOID,
+                              G_TYPE_NONE, 0);
+
+        /**
+         * GdkPixbufLoader::area-updated:
+         * @loader: the object which received the signal.
+         * @x: X offset of upper-left corner of the updated area.
+         * @y: Y offset of upper-left corner of the updated area.
+         * @width: Width of updated area.
+         * @height: Height of updated area.
+         *
+         * This signal is emitted when a significant area of the image being
+         * loaded has been updated.  Normally it means that a complete
+         * scanline has been read in, but it could be a different area as
+         * well.  Applications can use this signal to know when to repaint
+         * areas of an image that is being loaded.
+         */
+        pixbuf_loader_signals[AREA_UPDATED] =
+                g_signal_new ("area-updated",
+                              G_TYPE_FROM_CLASS (object_class),
+                              G_SIGNAL_RUN_LAST,
+                              G_STRUCT_OFFSET (GdkPixbufLoaderClass, area_updated),
+                              NULL, NULL,
+                              _gdk_pixbuf_marshal_VOID__INT_INT_INT_INT,
+                              G_TYPE_NONE, 4,
+                              G_TYPE_INT,
+                              G_TYPE_INT,
+                              G_TYPE_INT,
+                              G_TYPE_INT);
+  
+        /**
+         * GdkPixbufLoader::closed:
+         * @loader: the object which received the signal.
+         *
+         * This signal is emitted when gdk_pixbuf_loader_close() is called.
+         * It can be used by different parts of an application to receive
+         * notification when an image loader is closed by the code that
+         * drives it.
+         */
+        pixbuf_loader_signals[CLOSED] =
+                g_signal_new ("closed",
+                              G_TYPE_FROM_CLASS (object_class),
+                              G_SIGNAL_RUN_LAST,
+                              G_STRUCT_OFFSET (GdkPixbufLoaderClass, closed),
+                              NULL, NULL,
+                              _gdk_pixbuf_marshal_VOID__VOID,
+                              G_TYPE_NONE, 0);
+}
+
+static void
+gdk_pixbuf_loader_init (GdkPixbufLoader *loader)
+{
+        GdkPixbufLoaderPrivate *priv;
+  
+        priv = g_new0 (GdkPixbufLoaderPrivate, 1);
+        priv->width = -1;
+        priv->height = -1;
+
+        loader->priv = priv;
+}
+
+static void
+gdk_pixbuf_loader_finalize (GObject *object)
+{
+        GdkPixbufLoader *loader;
+        GdkPixbufLoaderPrivate *priv = NULL;
+  
+        loader = GDK_PIXBUF_LOADER (object);
+        priv = loader->priv;
+
+        if (!priv->closed) {
+                g_warning ("GdkPixbufLoader finalized without calling gdk_pixbuf_loader_close() - this is not allowed. You must explicitly end the data stream to the loader before dropping the last reference.");
+                if (priv->holds_threadlock) {
+                        _gdk_pixbuf_unlock (priv->image_module);
+                }
+        }
+        if (priv->animation)
+                g_object_unref (priv->animation);
+  
+        g_free (priv);
+  
+        G_OBJECT_CLASS (gdk_pixbuf_loader_parent_class)->finalize (object);
+}
+
+/**
+ * gdk_pixbuf_loader_set_size:
+ * @loader: A pixbuf loader.
+ * @width: The desired width of the image being loaded.
+ * @height: The desired height of the image being loaded.
+ *
+ * Causes the image to be scaled while it is loaded. The desired
+ * image size can be determined relative to the original size of
+ * the image by calling gdk_pixbuf_loader_set_size() from a
+ * signal handler for the ::size-prepared signal.
+ *
+ * Attempts to set the desired image size  are ignored after the 
+ * emission of the ::size-prepared signal.
+ *
+ * Since: 2.2
+ */
+void 
+gdk_pixbuf_loader_set_size (GdkPixbufLoader *loader,
+                           gint             width,
+                           gint             height)
+{
+        GdkPixbufLoaderPrivate *priv;
+
+        g_return_if_fail (GDK_IS_PIXBUF_LOADER (loader));
+        g_return_if_fail (width >= 0 && height >= 0);
+
+        priv = GDK_PIXBUF_LOADER (loader)->priv;
+
+        if (!priv->size_fixed) 
+                {
+                        priv->width = width;
+                        priv->height = height;
+                }
+}
+
+static void
+gdk_pixbuf_loader_size_func (gint *width, gint *height, gpointer loader)
+{
+        GdkPixbufLoaderPrivate *priv = GDK_PIXBUF_LOADER (loader)->priv;
+
+        /* allow calling gdk_pixbuf_loader_set_size() before the signal */
+        if (priv->width == -1 && priv->height == -1) 
+                {
+                        priv->width = *width;
+                        priv->height = *height;
+                }
+
+        g_signal_emit (loader, pixbuf_loader_signals[SIZE_PREPARED], 0, *width, *height);
+        priv->size_fixed = TRUE;
+
+        *width = priv->width;
+        *height = priv->height;
+}
+
+static void
+gdk_pixbuf_loader_prepare (GdkPixbuf          *pixbuf,
+                           GdkPixbufAnimation *anim,
+                          gpointer            loader)
+{
+        GdkPixbufLoaderPrivate *priv = GDK_PIXBUF_LOADER (loader)->priv;
+        g_return_if_fail (pixbuf != NULL);
+
+        if (!priv->size_fixed) 
+                {
+                        /* Defend against lazy loaders which don't call size_func */
+                        gint width = gdk_pixbuf_get_width (pixbuf);
+                        gint height = gdk_pixbuf_get_height (pixbuf);
+                        
+                        gdk_pixbuf_loader_size_func (&width, &height, loader);
+                }
+
+        priv->needs_scale = FALSE;
+        if (priv->width > 0 && priv->height > 0 &&
+            (priv->width != gdk_pixbuf_get_width (pixbuf) ||
+             priv->height != gdk_pixbuf_get_height (pixbuf)))
+                priv->needs_scale = TRUE;
+
+        if (anim)
+                g_object_ref (anim);
+        else
+                anim = gdk_pixbuf_non_anim_new (pixbuf);
+  
+       if (priv->needs_scale) {
+               priv->animation  = GDK_PIXBUF_ANIMATION (_gdk_pixbuf_scaled_anim_new (anim,
+                                         (double) priv->width / gdk_pixbuf_get_width (pixbuf),
+                                         (double) priv->height / gdk_pixbuf_get_height (pixbuf),
+                                         1.0));
+                       g_object_unref (anim);
+       }
+       else
+               priv->animation = anim;
+  
+        if (!priv->needs_scale)
+                g_signal_emit (loader, pixbuf_loader_signals[AREA_PREPARED], 0);
+}
+
+static void
+gdk_pixbuf_loader_update (GdkPixbuf *pixbuf,
+                         gint       x,
+                         gint       y,
+                         gint       width,
+                         gint       height,
+                         gpointer   loader)
+{
+        GdkPixbufLoaderPrivate *priv = GDK_PIXBUF_LOADER (loader)->priv;
+  
+        if (!priv->needs_scale)
+                g_signal_emit (loader,
+                               pixbuf_loader_signals[AREA_UPDATED],
+                               0,
+                               x, y,
+                               /* sanity check in here.  Defend against an errant loader */
+                               MIN (width, gdk_pixbuf_animation_get_width (priv->animation)),
+                               MIN (height, gdk_pixbuf_animation_get_height (priv->animation)));
+}
+
+/* Defense against broken loaders; DO NOT take this as a GError example! */
+static void
+gdk_pixbuf_loader_ensure_error (GdkPixbufLoader *loader,
+                                GError         **error)
+{ 
+        GdkPixbufLoaderPrivate *priv = loader->priv;
+
+        if (error == NULL || *error != NULL)
+                return;
+
+        g_warning ("Bug! loader '%s' didn't set an error on failure",
+                   priv->image_module->module_name);
+        g_set_error (error,
+                     GDK_PIXBUF_ERROR,
+                     GDK_PIXBUF_ERROR_FAILED,
+                     _("Internal error: Image loader module '%s' failed to"
+                       " complete an operation, but didn't give a reason for"
+                       " the failure"),
+                     priv->image_module->module_name);
+}
+
+static gint
+gdk_pixbuf_loader_load_module (GdkPixbufLoader *loader,
+                               const char      *image_type,
+                               GError         **error)
+{
+        GdkPixbufLoaderPrivate *priv = loader->priv;
+
+        if (image_type)
+                {
+                        priv->image_module = _gdk_pixbuf_get_named_module (image_type,
+                                                                           error);
+                }
+        else
+                {
+                        priv->image_module = _gdk_pixbuf_get_module (priv->header_buf,
+                                                                     priv->header_buf_offset,
+                                                                     NULL,
+                                                                     error);
+                }
+  
+        if (priv->image_module == NULL)
+                return 0;
+  
+        if (!_gdk_pixbuf_load_module (priv->image_module, error))
+                return 0;
+  
+        if (priv->image_module->module == NULL)
+                return 0;
+  
+        if ((priv->image_module->begin_load == NULL) ||
+            (priv->image_module->stop_load == NULL) ||
+            (priv->image_module->load_increment == NULL))
+                {
+                        g_set_error (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
+                                     _("Incremental loading of image type '%s' is not supported"),
+                                     priv->image_module->module_name);
+
+                        return 0;
+                }
+
+       if (!priv->holds_threadlock) {
+                priv->holds_threadlock = _gdk_pixbuf_lock (priv->image_module);
+        }
+
+        priv->context = priv->image_module->begin_load (gdk_pixbuf_loader_size_func,
+                                                        gdk_pixbuf_loader_prepare,
+                                                        gdk_pixbuf_loader_update,
+                                                        loader,
+                                                        error);
+  
+        if (priv->context == NULL)
+                {
+                        gdk_pixbuf_loader_ensure_error (loader, error);
+                        return 0;
+                }
+  
+        if (priv->header_buf_offset
+            && priv->image_module->load_increment (priv->context, priv->header_buf, priv->header_buf_offset, error))
+                return priv->header_buf_offset;
+  
+        return 0;
+}
+
+static int
+gdk_pixbuf_loader_eat_header_write (GdkPixbufLoader *loader,
+                                   const guchar    *buf,
+                                   gsize            count,
+                                    GError         **error)
+{
+        gint n_bytes;
+        GdkPixbufLoaderPrivate *priv = loader->priv;
+  
+        n_bytes = MIN(LOADER_HEADER_SIZE - priv->header_buf_offset, count);
+        memcpy (priv->header_buf + priv->header_buf_offset, buf, n_bytes);
+  
+        priv->header_buf_offset += n_bytes;
+  
+        if (priv->header_buf_offset >= LOADER_HEADER_SIZE)
+                {
+                        if (gdk_pixbuf_loader_load_module (loader, NULL, error) == 0)
+                                return 0;
+                }
+  
+        return n_bytes;
+}
+
+/**
+ * gdk_pixbuf_loader_write:
+ * @loader: A pixbuf loader.
+ * @buf: (array length=count): Pointer to image data.
+ * @count: Length of the @buf buffer in bytes.
+ * @error: return location for errors
+ *
+ * This will cause a pixbuf loader to parse the next @count bytes of
+ * an image.  It will return %TRUE if the data was loaded successfully,
+ * and %FALSE if an error occurred.  In the latter case, the loader
+ * will be closed, and will not accept further writes. If %FALSE is
+ * returned, @error will be set to an error from the #GDK_PIXBUF_ERROR
+ * or #G_FILE_ERROR domains.
+ *
+ * Return value: %TRUE if the write was successful, or %FALSE if the loader
+ * cannot parse the buffer.
+ **/
+gboolean
+gdk_pixbuf_loader_write (GdkPixbufLoader *loader,
+                        const guchar    *buf,
+                        gsize            count,
+                         GError         **error)
+{
+        GdkPixbufLoaderPrivate *priv;
+  
+        g_return_val_if_fail (GDK_IS_PIXBUF_LOADER (loader), FALSE);
+  
+        g_return_val_if_fail (buf != NULL, FALSE);
+        g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+  
+        priv = loader->priv;
+
+        /* we expect it's not to be closed */
+        g_return_val_if_fail (priv->closed == FALSE, FALSE);
+  
+        if (count > 0 && priv->image_module == NULL)
+                {
+                        gint eaten;
+      
+                        eaten = gdk_pixbuf_loader_eat_header_write (loader, buf, count, error);
+                        if (eaten <= 0)
+                               goto fail; 
+      
+                        count -= eaten;
+                        buf += eaten;
+                }
+  
+        if (count > 0 && priv->image_module->load_increment)
+                {
+                        if (!priv->image_module->load_increment (priv->context, buf, count,
+                                                                 error))
+                               goto fail;
+                }
+      
+        return TRUE;
+
+ fail:
+        gdk_pixbuf_loader_ensure_error (loader, error);
+        gdk_pixbuf_loader_close (loader, NULL);
+
+        return FALSE;
+}
+
+/**
+ * gdk_pixbuf_loader_new:
+ *
+ * Creates a new pixbuf loader object.
+ *
+ * Return value: A newly-created pixbuf loader.
+ **/
+GdkPixbufLoader *
+gdk_pixbuf_loader_new (void)
+{
+        return g_object_new (GDK_TYPE_PIXBUF_LOADER, NULL);
+}
+
+/**
+ * gdk_pixbuf_loader_new_with_type:
+ * @image_type: name of the image format to be loaded with the image
+ * @error: (allow-none): return location for an allocated #GError, or %NULL to ignore errors
+ *
+ * Creates a new pixbuf loader object that always attempts to parse
+ * image data as if it were an image of type @image_type, instead of
+ * identifying the type automatically. Useful if you want an error if
+ * the image isn't the expected type, for loading image formats
+ * that can't be reliably identified by looking at the data, or if
+ * the user manually forces a specific type.
+ *
+ * The list of supported image formats depends on what image loaders
+ * are installed, but typically "png", "jpeg", "gif", "tiff" and 
+ * "xpm" are among the supported formats. To obtain the full list of
+ * supported image formats, call gdk_pixbuf_format_get_name() on each 
+ * of the #GdkPixbufFormat structs returned by gdk_pixbuf_get_formats().
+ *
+ * Return value: A newly-created pixbuf loader.
+ **/
+GdkPixbufLoader *
+gdk_pixbuf_loader_new_with_type (const char *image_type,
+                                 GError    **error)
+{
+        GdkPixbufLoader *retval;
+        GError *tmp;
+        g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+  
+        retval = g_object_new (GDK_TYPE_PIXBUF_LOADER, NULL);
+
+        tmp = NULL;
+        gdk_pixbuf_loader_load_module (retval, image_type, &tmp);
+        if (tmp != NULL)
+                {
+                        g_propagate_error (error, tmp);
+                        gdk_pixbuf_loader_close (retval, NULL);
+                        g_object_unref (retval);
+                        return NULL;
+                }
+
+        return retval;
+}
+
+/**
+ * gdk_pixbuf_loader_new_with_mime_type:
+ * @mime_type: the mime type to be loaded 
+ * @error: (allow-none): return location for an allocated #GError, or %NULL to ignore errors
+ *
+ * Creates a new pixbuf loader object that always attempts to parse
+ * image data as if it were an image of mime type @mime_type, instead of
+ * identifying the type automatically. Useful if you want an error if
+ * the image isn't the expected mime type, for loading image formats
+ * that can't be reliably identified by looking at the data, or if
+ * the user manually forces a specific mime type.
+ *
+ * The list of supported mime types depends on what image loaders
+ * are installed, but typically "image/png", "image/jpeg", "image/gif", 
+ * "image/tiff" and "image/x-xpixmap" are among the supported mime types. 
+ * To obtain the full list of supported mime types, call 
+ * gdk_pixbuf_format_get_mime_types() on each of the #GdkPixbufFormat 
+ * structs returned by gdk_pixbuf_get_formats().
+ *
+ * Return value: A newly-created pixbuf loader.
+ * Since: 2.4
+ **/
+GdkPixbufLoader *
+gdk_pixbuf_loader_new_with_mime_type (const char *mime_type,
+                                      GError    **error)
+{
+        const char * image_type = NULL;
+        char ** mimes;
+
+        GdkPixbufLoader *retval;
+        GError *tmp;
+  
+        GSList * formats;
+        GdkPixbufFormat *info;
+        int i, j, length;
+
+        formats = gdk_pixbuf_get_formats ();
+        length = g_slist_length (formats);
+
+        for (i = 0; i < length && image_type == NULL; i++) {
+                info = (GdkPixbufFormat *)g_slist_nth_data (formats, i);
+                mimes = info->mime_types;
+                
+                for (j = 0; mimes[j] != NULL; j++)
+                        if (g_ascii_strcasecmp (mimes[j], mime_type) == 0) {
+                                image_type = info->name;
+                                break;
+                        }
+        }
+
+        g_slist_free (formats);
+
+        retval = g_object_new (GDK_TYPE_PIXBUF_LOADER, NULL);
+
+        tmp = NULL;
+        gdk_pixbuf_loader_load_module (retval, image_type, &tmp);
+        if (tmp != NULL)
+                {
+                        g_propagate_error (error, tmp);
+                        gdk_pixbuf_loader_close (retval, NULL);
+                        g_object_unref (retval);
+                        return NULL;
+                }
+
+        return retval;
+}
+
+/**
+ * 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 after 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 g_object_ref() should be sufficient to continue
+ * using it.  Additionally, if the loader is an animation, it will
+ * return the "static image" of the animation
+ * (see gdk_pixbuf_animation_get_static_image()).
+ * 
+ * Return value: (transfer none): The #GdkPixbuf that the loader is creating, or %NULL if not
+ * enough data has been read to determine how to create the image buffer.
+ **/
+GdkPixbuf *
+gdk_pixbuf_loader_get_pixbuf (GdkPixbufLoader *loader)
+{
+        GdkPixbufLoaderPrivate *priv;
+  
+        g_return_val_if_fail (GDK_IS_PIXBUF_LOADER (loader), NULL);
+  
+        priv = loader->priv;
+
+        if (priv->animation)
+                return gdk_pixbuf_animation_get_static_image (priv->animation);
+        else
+                return NULL;
+}
+
+/**
+ * gdk_pixbuf_loader_get_animation:
+ * @loader: A pixbuf loader
+ *
+ * Queries the #GdkPixbufAnimation that a pixbuf loader is currently creating.
+ * In general it only makes sense to call this function after the "area-prepared"
+ * signal has been emitted by the loader. If the loader doesn't have enough
+ * bytes yet (hasn't emitted the "area-prepared" signal) this function will 
+ * return %NULL.
+ *
+ * Return value: (transfer none): The #GdkPixbufAnimation that the loader is loading, or %NULL if
+ not enough data has been read to determine the information.
+**/
+GdkPixbufAnimation *
+gdk_pixbuf_loader_get_animation (GdkPixbufLoader *loader)
+{
+        GdkPixbufLoaderPrivate *priv;
+  
+        g_return_val_if_fail (GDK_IS_PIXBUF_LOADER (loader), NULL);
+  
+        priv = loader->priv;
+  
+        return priv->animation;
+}
+
+/**
+ * gdk_pixbuf_loader_close:
+ * @loader: A pixbuf loader.
+ * @error: (allow-none): return location for a #GError, or %NULL to ignore errors
+ *
+ * Informs a pixbuf loader that no further writes with
+ * gdk_pixbuf_loader_write() will occur, so that it can free its
+ * internal loading structures. Also, tries to parse any data that
+ * hasn't yet been parsed; if the remaining data is partial or
+ * corrupt, an error will be returned.  If %FALSE is returned, @error
+ * will be set to an error from the #GDK_PIXBUF_ERROR or #G_FILE_ERROR
+ * domains. If you're just cancelling a load rather than expecting it
+ * to be finished, passing %NULL for @error to ignore it is
+ * reasonable.
+ *
+ * Remember that this does not unref the loader, so if you plan not to
+ * use it anymore, please g_object_unref() it.
+ *
+ * Returns: %TRUE if all image data written so far was successfully
+            passed out via the update_area signal
+ **/
+gboolean
+gdk_pixbuf_loader_close (GdkPixbufLoader *loader,
+                         GError         **error)
+{
+        GdkPixbufLoaderPrivate *priv;
+        gboolean retval = TRUE;
+  
+        g_return_val_if_fail (GDK_IS_PIXBUF_LOADER (loader), TRUE);
+        g_return_val_if_fail (error == NULL || *error == NULL, TRUE);
+  
+        priv = loader->priv;
+  
+        if (priv->closed)
+                return TRUE;
+  
+        /* We have less the LOADER_HEADER_SIZE bytes in the image.  
+         * Flush it, and keep going. 
+         */
+        if (priv->image_module == NULL)
+                {
+                        GError *tmp = NULL;
+                        gdk_pixbuf_loader_load_module (loader, NULL, &tmp);
+                        if (tmp != NULL)
+                                {
+                                        g_propagate_error (error, tmp);
+                                        retval = FALSE;
+                                }
+                }  
+
+        if (priv->image_module && priv->image_module->stop_load && priv->context) 
+                {
+                        GError *tmp = NULL;
+                        if (!priv->image_module->stop_load (priv->context, &tmp) || tmp)
+                                {
+                                       /* don't call gdk_pixbuf_loader_ensure_error()
+                                        * here, since we might not get an error in the
+                                        * gdk_pixbuf_get_file_info() case
+                                        */
+                                       if (tmp) {
+                                               if (error && *error == NULL)
+                                                       g_propagate_error (error, tmp);
+                                               else
+                                                       g_error_free (tmp);
+                                       }
+                                        retval = FALSE;
+                                }
+                }
+  
+        priv->closed = TRUE;
+       if (priv->image_module && priv->holds_threadlock) {
+                _gdk_pixbuf_unlock (priv->image_module);
+                priv->holds_threadlock = FALSE;
+        }
+
+        if (priv->needs_scale) 
+                {
+
+                        g_signal_emit (loader, pixbuf_loader_signals[AREA_PREPARED], 0);
+                        g_signal_emit (loader, pixbuf_loader_signals[AREA_UPDATED], 0, 
+                                       0, 0, priv->width, priv->height);
+                }
+
+        
+        g_signal_emit (loader, pixbuf_loader_signals[CLOSED], 0);
+
+        return retval;
+}
+
+/**
+ * gdk_pixbuf_loader_get_format:
+ * @loader: A pixbuf loader.
+ *
+ * Obtains the available information about the format of the 
+ * currently loading image file.
+ *
+ * Returns: (transfer none): A #GdkPixbufFormat or %NULL. The return
+ * value is owned by GdkPixbuf and should not be freed.
+ * 
+ * Since: 2.2
+ */
+GdkPixbufFormat *
+gdk_pixbuf_loader_get_format (GdkPixbufLoader *loader)
+{
+        GdkPixbufLoaderPrivate *priv;
+  
+        g_return_val_if_fail (GDK_IS_PIXBUF_LOADER (loader), NULL);
+  
+        priv = loader->priv;
+
+        if (priv->image_module)
+                return _gdk_pixbuf_get_format (priv->image_module);
+        else
+                return NULL;
+}
diff --git a/gdk-pixbuf/gdk-pixbuf-loader.h b/gdk-pixbuf/gdk-pixbuf-loader.h
new file mode 100644 (file)
index 0000000..f9743ee
--- /dev/null
@@ -0,0 +1,107 @@
+/* GdkPixbuf library - Progressive loader object
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Authors: Mark Crichton <crichton@gimp.org>
+ *          Miguel de Icaza <miguel@gnu.org>
+ *          Federico Mena-Quintero <federico@gimp.org>
+ *          Jonathan Blandford <jrb@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#if defined(GDK_PIXBUF_DISABLE_SINGLE_INCLUDES) && !defined (GDK_PIXBUF_H_INSIDE) && !defined (GDK_PIXBUF_COMPILATION)
+#error "Only <gdk-pixbuf/gdk-pixbuf.h> can be included directly."
+#endif
+
+#ifndef GDK_PIXBUF_LOADER_H
+#define GDK_PIXBUF_LOADER_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gdk-pixbuf/gdk-pixbuf-core.h>
+#include <gdk-pixbuf/gdk-pixbuf-animation.h>
+#include <gdk-pixbuf/gdk-pixbuf-io.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_PIXBUF_LOADER            (gdk_pixbuf_loader_get_type ())
+#define GDK_PIXBUF_LOADER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_PIXBUF_LOADER, GdkPixbufLoader))
+#define GDK_PIXBUF_LOADER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_LOADER, GdkPixbufLoaderClass))
+#define GDK_IS_PIXBUF_LOADER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_PIXBUF_LOADER))
+#define GDK_IS_PIXBUF_LOADER_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_LOADER))
+#define GDK_PIXBUF_LOADER_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_LOADER, GdkPixbufLoaderClass))
+
+/**
+ * GdkPixbufLoader:
+ * 
+ * The <structname>GdkPixbufLoader</structname> struct contains only private
+ * fields. 
+ */
+typedef struct _GdkPixbufLoader GdkPixbufLoader;
+struct _GdkPixbufLoader
+{
+  GObject parent_instance;
+  
+  /*< private >*/
+  gpointer priv;
+};
+
+typedef struct _GdkPixbufLoaderClass GdkPixbufLoaderClass;
+struct _GdkPixbufLoaderClass
+{
+  GObjectClass parent_class;
+
+  void (*size_prepared)      (GdkPixbufLoader *loader, 
+                             int              width,
+                             int              height);
+
+  void (*area_prepared)      (GdkPixbufLoader *loader);
+
+  /* Last known frame needs a redraw for x, y, width, height */
+  void (*area_updated)       (GdkPixbufLoader *loader,
+                              int              x,
+                              int              y,
+                             int              width,
+                             int              height);
+
+  void (*closed)             (GdkPixbufLoader *loader);
+};
+
+GType                gdk_pixbuf_loader_get_type      (void) G_GNUC_CONST;
+GdkPixbufLoader *    gdk_pixbuf_loader_new           (void);
+GdkPixbufLoader *    gdk_pixbuf_loader_new_with_type (const char *image_type,
+                                                      GError    **error);
+GdkPixbufLoader *    gdk_pixbuf_loader_new_with_mime_type (const char *mime_type,
+                                                          GError    **error);
+void                 gdk_pixbuf_loader_set_size (GdkPixbufLoader  *loader,
+                                                 int               width,
+                                                int               height);
+gboolean             gdk_pixbuf_loader_write         (GdkPixbufLoader *loader,
+                                                     const guchar    *buf,
+                                                     gsize            count,
+                                                      GError         **error);
+GdkPixbuf *          gdk_pixbuf_loader_get_pixbuf    (GdkPixbufLoader *loader);
+GdkPixbufAnimation * gdk_pixbuf_loader_get_animation (GdkPixbufLoader *loader);
+gboolean             gdk_pixbuf_loader_close         (GdkPixbufLoader *loader,
+                                                      GError         **error);
+GdkPixbufFormat     *gdk_pixbuf_loader_get_format    (GdkPixbufLoader *loader);
+
+G_END_DECLS
+
+#endif
+
+
diff --git a/gdk-pixbuf/gdk-pixbuf-marshal.c b/gdk-pixbuf/gdk-pixbuf-marshal.c
new file mode 100644 (file)
index 0000000..5381d9a
--- /dev/null
@@ -0,0 +1,133 @@
+
+#include       <glib-object.h>
+
+
+#ifdef G_ENABLE_DEBUG
+#define g_marshal_value_peek_boolean(v)  g_value_get_boolean (v)
+#define g_marshal_value_peek_char(v)     g_value_get_schar (v)
+#define g_marshal_value_peek_uchar(v)    g_value_get_uchar (v)
+#define g_marshal_value_peek_int(v)      g_value_get_int (v)
+#define g_marshal_value_peek_uint(v)     g_value_get_uint (v)
+#define g_marshal_value_peek_long(v)     g_value_get_long (v)
+#define g_marshal_value_peek_ulong(v)    g_value_get_ulong (v)
+#define g_marshal_value_peek_int64(v)    g_value_get_int64 (v)
+#define g_marshal_value_peek_uint64(v)   g_value_get_uint64 (v)
+#define g_marshal_value_peek_enum(v)     g_value_get_enum (v)
+#define g_marshal_value_peek_flags(v)    g_value_get_flags (v)
+#define g_marshal_value_peek_float(v)    g_value_get_float (v)
+#define g_marshal_value_peek_double(v)   g_value_get_double (v)
+#define g_marshal_value_peek_string(v)   (char*) g_value_get_string (v)
+#define g_marshal_value_peek_param(v)    g_value_get_param (v)
+#define g_marshal_value_peek_boxed(v)    g_value_get_boxed (v)
+#define g_marshal_value_peek_pointer(v)  g_value_get_pointer (v)
+#define g_marshal_value_peek_object(v)   g_value_get_object (v)
+#define g_marshal_value_peek_variant(v)  g_value_get_variant (v)
+#else /* !G_ENABLE_DEBUG */
+/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
+ *          Do not access GValues directly in your code. Instead, use the
+ *          g_value_get_*() functions
+ */
+#define g_marshal_value_peek_boolean(v)  (v)->data[0].v_int
+#define g_marshal_value_peek_char(v)     (v)->data[0].v_int
+#define g_marshal_value_peek_uchar(v)    (v)->data[0].v_uint
+#define g_marshal_value_peek_int(v)      (v)->data[0].v_int
+#define g_marshal_value_peek_uint(v)     (v)->data[0].v_uint
+#define g_marshal_value_peek_long(v)     (v)->data[0].v_long
+#define g_marshal_value_peek_ulong(v)    (v)->data[0].v_ulong
+#define g_marshal_value_peek_int64(v)    (v)->data[0].v_int64
+#define g_marshal_value_peek_uint64(v)   (v)->data[0].v_uint64
+#define g_marshal_value_peek_enum(v)     (v)->data[0].v_long
+#define g_marshal_value_peek_flags(v)    (v)->data[0].v_ulong
+#define g_marshal_value_peek_float(v)    (v)->data[0].v_float
+#define g_marshal_value_peek_double(v)   (v)->data[0].v_double
+#define g_marshal_value_peek_string(v)   (v)->data[0].v_pointer
+#define g_marshal_value_peek_param(v)    (v)->data[0].v_pointer
+#define g_marshal_value_peek_boxed(v)    (v)->data[0].v_pointer
+#define g_marshal_value_peek_pointer(v)  (v)->data[0].v_pointer
+#define g_marshal_value_peek_object(v)   (v)->data[0].v_pointer
+#define g_marshal_value_peek_variant(v)  (v)->data[0].v_pointer
+#endif /* !G_ENABLE_DEBUG */
+
+
+/* VOID:VOID (./gdk-pixbuf-marshal.list:25) */
+
+/* VOID:INT,INT (./gdk-pixbuf-marshal.list:26) */
+void
+_gdk_pixbuf_marshal_VOID__INT_INT (GClosure     *closure,
+                                   GValue       *return_value G_GNUC_UNUSED,
+                                   guint         n_param_values,
+                                   const GValue *param_values,
+                                   gpointer      invocation_hint G_GNUC_UNUSED,
+                                   gpointer      marshal_data)
+{
+  typedef void (*GMarshalFunc_VOID__INT_INT) (gpointer     data1,
+                                              gint         arg_1,
+                                              gint         arg_2,
+                                              gpointer     data2);
+  register GMarshalFunc_VOID__INT_INT callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values == 3);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_VOID__INT_INT) (marshal_data ? marshal_data : cc->callback);
+
+  callback (data1,
+            g_marshal_value_peek_int (param_values + 1),
+            g_marshal_value_peek_int (param_values + 2),
+            data2);
+}
+
+/* VOID:INT,INT,INT,INT (./gdk-pixbuf-marshal.list:27) */
+void
+_gdk_pixbuf_marshal_VOID__INT_INT_INT_INT (GClosure     *closure,
+                                           GValue       *return_value G_GNUC_UNUSED,
+                                           guint         n_param_values,
+                                           const GValue *param_values,
+                                           gpointer      invocation_hint G_GNUC_UNUSED,
+                                           gpointer      marshal_data)
+{
+  typedef void (*GMarshalFunc_VOID__INT_INT_INT_INT) (gpointer     data1,
+                                                      gint         arg_1,
+                                                      gint         arg_2,
+                                                      gint         arg_3,
+                                                      gint         arg_4,
+                                                      gpointer     data2);
+  register GMarshalFunc_VOID__INT_INT_INT_INT callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values == 5);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_VOID__INT_INT_INT_INT) (marshal_data ? marshal_data : cc->callback);
+
+  callback (data1,
+            g_marshal_value_peek_int (param_values + 1),
+            g_marshal_value_peek_int (param_values + 2),
+            g_marshal_value_peek_int (param_values + 3),
+            g_marshal_value_peek_int (param_values + 4),
+            data2);
+}
+
+/* VOID:POINTER (./gdk-pixbuf-marshal.list:28) */
+
diff --git a/gdk-pixbuf/gdk-pixbuf-marshal.h b/gdk-pixbuf/gdk-pixbuf-marshal.h
new file mode 100644 (file)
index 0000000..8273c5a
--- /dev/null
@@ -0,0 +1,36 @@
+#if !defined(GDK_PIXBUF_DISABLE_DEPRECATED) || defined(GDK_PIXBUF_COMPILATION)
+
+#ifndef ___gdk_pixbuf_marshal_MARSHAL_H__
+#define ___gdk_pixbuf_marshal_MARSHAL_H__
+
+#include       <glib-object.h>
+
+G_BEGIN_DECLS
+
+/* VOID:VOID (./gdk-pixbuf-marshal.list:25) */
+#define _gdk_pixbuf_marshal_VOID__VOID g_cclosure_marshal_VOID__VOID
+
+/* VOID:INT,INT (./gdk-pixbuf-marshal.list:26) */
+extern void _gdk_pixbuf_marshal_VOID__INT_INT (GClosure     *closure,
+                                               GValue       *return_value,
+                                               guint         n_param_values,
+                                               const GValue *param_values,
+                                               gpointer      invocation_hint,
+                                               gpointer      marshal_data);
+
+/* VOID:INT,INT,INT,INT (./gdk-pixbuf-marshal.list:27) */
+extern void _gdk_pixbuf_marshal_VOID__INT_INT_INT_INT (GClosure     *closure,
+                                                       GValue       *return_value,
+                                                       guint         n_param_values,
+                                                       const GValue *param_values,
+                                                       gpointer      invocation_hint,
+                                                       gpointer      marshal_data);
+
+/* VOID:POINTER (./gdk-pixbuf-marshal.list:28) */
+#define _gdk_pixbuf_marshal_VOID__POINTER      g_cclosure_marshal_VOID__POINTER
+
+G_END_DECLS
+
+#endif /* ___gdk_pixbuf_marshal_MARSHAL_H__ */
+
+#endif /* !GDK_PIXBUF_DISABLE_DEPRECATED || GDK_PIXBUF_COMPILATION */
diff --git a/gdk-pixbuf/gdk-pixbuf-marshal.list b/gdk-pixbuf/gdk-pixbuf-marshal.list
new file mode 100644 (file)
index 0000000..a43f7ce
--- /dev/null
@@ -0,0 +1,28 @@
+# see glib-genmarshal(1) for a detailed description of the file format,
+# possible parameter types are:
+#   VOID        indicates   no   return   type,  or  no  extra
+#               parameters. if VOID is used as  the  parameter
+#               list, no additional parameters may be present.
+#   BOOLEAN     for boolean types (gboolean)
+#   CHAR        for signed char types (gchar)
+#   UCHAR       for unsigned char types (guchar)
+#   INT         for signed integer types (gint)
+#   UINT        for unsigned integer types (guint)
+#   LONG        for signed long integer types (glong)
+#   ULONG       for unsigned long integer types (gulong)
+#   ENUM        for enumeration types (gint)
+#   FLAGS       for flag enumeration types (guint)
+#   FLOAT       for single-precision float types (gfloat)
+#   DOUBLE      for double-precision float types (gdouble)
+#   STRING      for string types (gchar*)
+#   PARAM       for GParamSpec or derived types  (GParamSpec*)
+#   BOXED       for boxed (anonymous but reference counted) types (GBoxed*)
+#   POINTER     for anonymous pointer types (gpointer)
+#   OBJECT      for GObject or derived types (GObject*)
+#   NONE        deprecated alias for VOID
+#   BOOL        deprecated alias for BOOLEAN
+
+VOID:VOID
+VOID:INT,INT
+VOID:INT,INT,INT,INT
+VOID:POINTER
diff --git a/gdk-pixbuf/gdk-pixbuf-pixdata.c b/gdk-pixbuf/gdk-pixbuf-pixdata.c
new file mode 100644 (file)
index 0000000..df76272
--- /dev/null
@@ -0,0 +1,192 @@
+/* Gdk-Pixbuf-Pixdata - GdkPixbuf to GdkPixdata
+ * Copyright (C) 1999, 2001 Tim Janik
+ * Copyright (C) 2012 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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 "gdk-pixbuf.h"
+#include "gdk-pixdata.h"
+#include <glib/gprintf.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/* --- defines --- */
+#undef G_LOG_DOMAIN
+#define        G_LOG_DOMAIN    "Gdk-Pixbuf-Pixdata"
+#define PRG_NAME        "gdk-pixbuf-pixdata-3.0"
+#define PKG_NAME        "gdk-pixbuf"
+#define PKG_HTTP_HOME   "http://www.gtk.org"
+
+static gboolean use_rle = FALSE;
+
+/* --- prototypes --- */
+static void    parse_args      (gint    *argc_p,
+                                gchar ***argv_p);
+static void    print_blurb     (FILE    *bout,
+                                gboolean print_help);
+
+
+int
+main (int   argc,
+      char *argv[])
+{
+  GdkPixbuf *pixbuf;
+  GError *error = NULL;
+  gchar *infilename;
+  gchar *outfilename;
+  gpointer free_me;
+  GdkPixdata pixdata;
+  guint8 *data;
+  guint data_len;
+
+  /* initialize glib/GdkPixbuf */
+  g_type_init ();
+
+  /* parse args and do fast exits */
+  parse_args (&argc, &argv);
+
+  if (argc != 3)
+    {
+      print_blurb (stderr, TRUE);
+      return 1;
+    }
+
+#ifdef G_OS_WIN32
+  infilename = g_locale_to_utf8 (argv[1], -1, NULL, NULL, NULL);
+#else
+  infilename = argv[1];
+#endif
+
+#ifdef G_OS_WIN32
+  outfilename = g_locale_to_utf8 (argv[2], -1, NULL, NULL, NULL);
+#else
+  outfilename = argv[2];
+#endif
+
+  pixbuf = gdk_pixbuf_new_from_file (infilename, &error);
+  if (!pixbuf)
+    {
+      g_printerr ("failed to load \"%s\": %s\n",
+                 argv[1],
+                 error->message);
+      g_error_free (error);
+      return 1;
+    }
+
+  free_me = gdk_pixdata_from_pixbuf (&pixdata, pixbuf, use_rle);
+  data = gdk_pixdata_serialize (&pixdata, &data_len);
+
+  if (!g_file_set_contents (outfilename, (char *)data, data_len, &error))
+    {
+      g_printerr ("failed to load \"%s\": %s\n",
+                 argv[1],
+                 error->message);
+      g_error_free (error);
+      return 1;
+    }
+
+  g_free (data);
+  g_free (free_me);
+  g_object_unref (pixbuf);
+
+  return 0;
+}
+
+static void
+parse_args (gint    *argc_p,
+           gchar ***argv_p)
+{
+  guint argc = *argc_p;
+  gchar **argv = *argv_p;
+  guint i, e;
+
+  for (i = 1; i < argc; i++)
+    {
+      if (strcmp ("--rle", argv[i]) == 0)
+       {
+         use_rle = TRUE;
+         argv[i] = NULL;
+       }
+      else if (strcmp ("-h", argv[i]) == 0 ||
+         strcmp ("--help", argv[i]) == 0)
+       {
+         print_blurb (stderr, TRUE);
+         argv[i] = NULL;
+         exit (0);
+       }
+      else if (strcmp ("-v", argv[i]) == 0 ||
+              strcmp ("--version", argv[i]) == 0)
+       {
+         print_blurb (stderr, FALSE);
+         argv[i] = NULL;
+         exit (0);
+       }
+      else if (strcmp (argv[i], "--g-fatal-warnings") == 0)
+       {
+         GLogLevelFlags fatal_mask;
+
+         fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
+         fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
+         g_log_set_always_fatal (fatal_mask);
+
+         argv[i] = NULL;
+       }
+    }
+
+  e = 0;
+  for (i = 1; i < argc; i++)
+    {
+      if (e)
+       {
+         if (argv[i])
+           {
+             argv[e++] = argv[i];
+             argv[i] = NULL;
+           }
+       }
+      else if (!argv[i])
+       e = i;
+    }
+  if (e)
+    *argc_p = e;
+}
+
+static void
+print_blurb (FILE    *bout,
+            gboolean print_help)
+{
+  if (!print_help)
+    {
+      g_fprintf (bout, "%s version ", PRG_NAME);
+      g_fprintf (bout, "%s", GDK_PIXBUF_VERSION);
+      g_fprintf (bout, "\n");
+      g_fprintf (bout, "%s comes with ABSOLUTELY NO WARRANTY.\n", PRG_NAME);
+      g_fprintf (bout, "You may redistribute copies of %s under the terms of\n", PRG_NAME);
+      g_fprintf (bout, "the GNU Lesser General Public License which can be found in the\n");
+      g_fprintf (bout, "%s source package. Sources, examples and contact\n", PKG_NAME);
+      g_fprintf (bout, "information are available at %s\n", PKG_HTTP_HOME);
+    }
+  else
+    {
+      g_fprintf (bout, "Usage: %s [options] [input-file] [output-file]\n", PRG_NAME);
+      g_fprintf (bout, "  -h, --help                 show this help message\n");
+      g_fprintf (bout, "  -v, --version              print version informations\n");
+      g_fprintf (bout, "  --g-fatal-warnings         make warnings fatal (abort)\n");
+    }
+}
diff --git a/gdk-pixbuf/gdk-pixbuf-private.h b/gdk-pixbuf/gdk-pixbuf-private.h
new file mode 100644 (file)
index 0000000..c060bd7
--- /dev/null
@@ -0,0 +1,106 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* GdkPixbuf library - Private declarations
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Authors: Mark Crichton <crichton@gimp.org>
+ *          Miguel de Icaza <miguel@gnu.org>
+ *          Federico Mena-Quintero <federico@gimp.org>
+ *          Havoc Pennington <hp@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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_PRIVATE_H
+#define GDK_PIXBUF_PRIVATE_H
+
+#include <stdio.h>
+
+#include <glib-object.h>
+
+#include "gdk-pixbuf-core.h"
+#include "gdk-pixbuf-io.h"
+#include "gdk-pixbuf-i18n.h"
+
+\f
+
+typedef struct _GdkPixbufClass GdkPixbufClass;
+
+#define GDK_PIXBUF_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF, GdkPixbufClass))
+#define GDK_IS_PIXBUF_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF))
+#define GDK_PIXBUF_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF, GdkPixbufClass))
+
+/* Private part of the GdkPixbuf structure */
+struct _GdkPixbuf {
+        GObject parent_instance;
+
+       /* Color space */
+       GdkColorspace colorspace;
+
+       /* Number of channels, alpha included */
+       int n_channels;
+
+       /* Bits per channel */
+       int bits_per_sample;
+
+       /* Size */
+       int width, height;
+
+       /* Offset between rows */
+       int rowstride;
+
+       /* The pixel array */
+       guchar *pixels;
+
+       /* Destroy notification function; it is supposed to free the pixel array */
+       GdkPixbufDestroyNotify destroy_fn;
+
+       /* User data for the destroy notification function */
+       gpointer destroy_fn_data;
+
+       /* Do we have an alpha channel? */
+       guint has_alpha : 1;
+};
+
+struct _GdkPixbufClass {
+        GObjectClass parent_class;
+
+};
+
+#ifdef GDK_PIXBUF_ENABLE_BACKEND
+
+gboolean _gdk_pixbuf_lock (GdkPixbufModule *image_module);
+void _gdk_pixbuf_unlock (GdkPixbufModule *image_module);
+
+GdkPixbufModule *_gdk_pixbuf_get_module (guchar *buffer, guint size,
+                                         const gchar *filename,
+                                         GError **error);
+GdkPixbufModule *_gdk_pixbuf_get_named_module (const char *name,
+                                               GError **error);
+gboolean _gdk_pixbuf_load_module (GdkPixbufModule *image_module,
+                                  GError **error);
+
+GdkPixbuf *_gdk_pixbuf_generic_image_load (GdkPixbufModule *image_module,
+                                          FILE *f,
+                                          GError **error);
+
+GdkPixbufFormat *_gdk_pixbuf_get_format (GdkPixbufModule *image_module);
+
+#endif /* GDK_PIXBUF_ENABLE_BACKEND */
+
+#endif /* GDK_PIXBUF_PRIVATE_H */
+
+
diff --git a/gdk-pixbuf/gdk-pixbuf-scale.c b/gdk-pixbuf/gdk-pixbuf-scale.c
new file mode 100644 (file)
index 0000000..6dbe18b
--- /dev/null
@@ -0,0 +1,532 @@
+/* GdkPixbuf library - Scaling and compositing functions
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Author: Owen Taylor <otaylor@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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 <math.h>
+#include <string.h>
+#include "gdk-pixbuf-transform.h"
+#include "gdk-pixbuf-private.h"
+#include "pixops/pixops.h"
+
+/**
+ * SECTION:scaling
+ * @Short_description: Scaling pixbufs and scaling and compositing pixbufs
+ * @Title: Scaling
+ * @See_also:    <link linkend="gdk-GdkRGB">GdkRGB</link>.
+ * 
+ * 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.
+ * 
+ * 
+ * Since the full-featured functions (gdk_pixbuf_scale(),
+ * gdk_pixbuf_composite(), and gdk_pixbuf_composite_color()) are
+ * rather complex to use and have many arguments, two simple
+ * convenience functions are provided, gdk_pixbuf_scale_simple() and
+ * gdk_pixbuf_composite_color_simple() which create a new pixbuf of a
+ * given size, scale an original image to fit, and then return the
+ * new pixbuf.
+ * 
+ * 
+ * Scaling and compositing functions take advantage of MMX hardware
+ * acceleration on systems where MMX is supported.  If gdk-pixbuf is built
+ * with the Sun mediaLib library, these functions are instead accelerated
+ * using mediaLib, which provides hardware acceleration on Intel, AMD,
+ * and Sparc chipsets.  If desired, mediaLib support can be turned off by
+ * setting the GDK_DISABLE_MEDIALIB environment variable.  
+ * 
+ * 
+ * The following example demonstrates handling an expose event by
+ * rendering the appropriate area of a source image (which is scaled
+ * to fit the widget) onto the widget's window.  The source image is
+ * rendered against a checkerboard, which provides a visual
+ * representation of the alpha channel if the image has one. If the
+ * image doesn't have an alpha channel, calling
+ * gdk_pixbuf_composite_color() function has exactly the same effect
+ * as calling gdk_pixbuf_scale().
+ * 
+ * 
+ * <example>
+ * <title>Handling an expose event.</title>
+ * <para>
+ * <programlisting>
+ * gboolean
+ * expose_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data)
+ * {
+ *   GdkPixbuf *dest;
+ * 
+ *   dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, event->area.width, event->area.height);
+ * 
+ *   gdk_pixbuf_composite_color (pixbuf, dest,
+ *                               0, 0, event->area.width, event->area.height,
+ *                               -event->area.x, -event->area.y,
+ *                               (double) widget->allocation.width / gdk_pixbuf_get_width (pixbuf),
+ *                               (double) widget->allocation.height / gdk_pixbuf_get_height (pixbuf),
+ *                               GDK_INTERP_BILINEAR, 255,
+ *                               event->area.x, event->area.y, 16, 0xaaaaaa, 0x555555);
+ * 
+ *   gdk_draw_pixbuf (widget->window, widget->style->fg_gc[GTK_STATE_NORMAL], dest,
+ *                    0, 0, event->area.x, event->area.y,
+ *                    event->area.width, event->area.height,
+ *                    GDK_RGB_DITHER_NORMAL, event->area.x, event->area.y);
+ *   
+ *   gdk_pixbuf_unref (dest);
+ *   
+ *   return TRUE;
+ * }
+ * </programlisting>
+ * </para>
+ * </example>
+ */
+\f
+
+/**
+ * gdk_pixbuf_scale:
+ * @src: a #GdkPixbuf
+ * @dest: the #GdkPixbuf into which to render the results
+ * @dest_x: the left coordinate for region to render
+ * @dest_y: the top coordinate for region to render
+ * @dest_width: the width of the region to render
+ * @dest_height: the height of the region to render
+ * @offset_x: the offset in the X direction (currently rounded to an integer)
+ * @offset_y: the offset in the Y direction (currently rounded to an integer)
+ * @scale_x: the scale factor in the X direction
+ * @scale_y: the scale factor in the Y direction
+ * @interp_type: the interpolation type for the transformation.
+ * 
+ * Creates a transformation of the source image @src by scaling by
+ * @scale_x and @scale_y then translating by @offset_x and @offset_y,
+ * then renders the rectangle (@dest_x, @dest_y, @dest_width,
+ * @dest_height) of the resulting image onto the destination image
+ * replacing the previous contents.
+ *
+ * Try to use gdk_pixbuf_scale_simple() first, this function is
+ * the industrial-strength power tool you can fall back to if
+ * gdk_pixbuf_scale_simple() isn't powerful enough.
+ *
+ * If the source rectangle overlaps the destination rectangle on the
+ * same pixbuf, it will be overwritten during the scaling which
+ * results in rendering artifacts.
+ **/
+void
+gdk_pixbuf_scale (const GdkPixbuf *src,
+                 GdkPixbuf       *dest,
+                 int              dest_x,
+                 int              dest_y,
+                 int              dest_width,
+                 int              dest_height,
+                 double           offset_x,
+                 double           offset_y,
+                 double           scale_x,
+                 double           scale_y,
+                 GdkInterpType    interp_type)
+{
+  g_return_if_fail (GDK_IS_PIXBUF (src));
+  g_return_if_fail (GDK_IS_PIXBUF (dest));
+  g_return_if_fail (dest_x >= 0 && dest_x + dest_width <= dest->width);
+  g_return_if_fail (dest_y >= 0 && dest_y + dest_height <= dest->height);
+
+  offset_x = floor (offset_x + 0.5);
+  offset_y = floor (offset_y + 0.5);
+
+  _pixops_scale (dest->pixels, dest->width, dest->height, dest->rowstride,
+                 dest->n_channels, dest->has_alpha, src->pixels, src->width,
+                 src->height, src->rowstride, src->n_channels, src->has_alpha,
+                 dest_x, dest_y, dest_width, dest_height, offset_x, offset_y,
+                 scale_x, scale_y, (PixopsInterpType)interp_type);
+}
+
+/**
+ * gdk_pixbuf_composite:
+ * @src: a #GdkPixbuf
+ * @dest: the #GdkPixbuf into which to render the results
+ * @dest_x: the left coordinate for region to render
+ * @dest_y: the top coordinate for region to render
+ * @dest_width: the width of the region to render
+ * @dest_height: the height of the region to render
+ * @offset_x: the offset in the X direction (currently rounded to an integer)
+ * @offset_y: the offset in the Y direction (currently rounded to an integer)
+ * @scale_x: the scale factor in the X direction
+ * @scale_y: the scale factor in the Y direction
+ * @interp_type: the interpolation type for the transformation.
+ * @overall_alpha: overall alpha for source image (0..255)
+ * 
+ * Creates a transformation of the source image @src by scaling by
+ * @scale_x and @scale_y then translating by @offset_x and @offset_y.
+ * This gives an image in the coordinates of the destination pixbuf.
+ * The rectangle (@dest_x, @dest_y, @dest_width, @dest_height)
+ * is then composited onto the corresponding rectangle of the
+ * original destination image.
+ * 
+ * When the destination rectangle contains parts not in the source 
+ * image, the data at the edges of the source image is replicated
+ * to infinity. 
+ *
+ * <figure id="pixbuf-composite-diagram">
+ *   <title>Compositing of pixbufs</title>
+ *   <graphic fileref="composite.png" format="PNG"/>
+ * </figure>
+ **/
+void
+gdk_pixbuf_composite (const GdkPixbuf *src,
+                     GdkPixbuf       *dest,
+                     int              dest_x,
+                     int              dest_y,
+                     int              dest_width,
+                     int              dest_height,
+                     double           offset_x,
+                     double           offset_y,
+                     double           scale_x,
+                     double           scale_y,
+                     GdkInterpType    interp_type,
+                     int              overall_alpha)
+{
+  g_return_if_fail (GDK_IS_PIXBUF (src));
+  g_return_if_fail (GDK_IS_PIXBUF (dest));
+  g_return_if_fail (dest_x >= 0 && dest_x + dest_width <= dest->width);
+  g_return_if_fail (dest_y >= 0 && dest_y + dest_height <= dest->height);
+  g_return_if_fail (overall_alpha >= 0 && overall_alpha <= 255);
+
+  offset_x = floor (offset_x + 0.5);
+  offset_y = floor (offset_y + 0.5);
+
+  _pixops_composite (dest->pixels, dest->width, dest->height, dest->rowstride,
+                     dest->n_channels, dest->has_alpha, src->pixels,
+                     src->width, src->height, src->rowstride, src->n_channels,
+                     src->has_alpha, dest_x, dest_y, dest_width, dest_height,
+                     offset_x, offset_y, scale_x, scale_y,
+                     (PixopsInterpType)interp_type, overall_alpha);
+}
+
+/**
+ * gdk_pixbuf_composite_color:
+ * @src: a #GdkPixbuf
+ * @dest: the #GdkPixbuf into which to render the results
+ * @dest_x: the left coordinate for region to render
+ * @dest_y: the top coordinate for region to render
+ * @dest_width: the width of the region to render
+ * @dest_height: the height of the region to render
+ * @offset_x: the offset in the X direction (currently rounded to an integer)
+ * @offset_y: the offset in the Y direction (currently rounded to an integer)
+ * @scale_x: the scale factor in the X direction
+ * @scale_y: the scale factor in the Y direction
+ * @interp_type: the interpolation type for the transformation.
+ * @overall_alpha: overall alpha for source image (0..255)
+ * @check_x: the X offset for the checkboard (origin of checkboard is at -@check_x, -@check_y)
+ * @check_y: the Y offset for the checkboard 
+ * @check_size: the size of checks in the checkboard (must be a power of two)
+ * @color1: the color of check at upper left
+ * @color2: the color of the other check
+ * 
+ * Creates a transformation of the source image @src by scaling by
+ * @scale_x and @scale_y then translating by @offset_x and @offset_y,
+ * then composites the rectangle (@dest_x ,@dest_y, @dest_width,
+ * @dest_height) of the resulting image with a checkboard of the
+ * colors @color1 and @color2 and renders it onto the destination
+ * image.
+ *
+ * See gdk_pixbuf_composite_color_simple() for a simpler variant of this
+ * function suitable for many tasks.
+ * 
+ **/
+void
+gdk_pixbuf_composite_color (const GdkPixbuf *src,
+                           GdkPixbuf       *dest,
+                           int              dest_x,
+                           int              dest_y,
+                           int              dest_width,
+                           int              dest_height,
+                           double           offset_x,
+                           double           offset_y,
+                           double           scale_x,
+                           double           scale_y,
+                           GdkInterpType    interp_type,
+                           int              overall_alpha,
+                           int              check_x,
+                           int              check_y,
+                           int              check_size,
+                           guint32          color1,
+                           guint32          color2)
+{
+  g_return_if_fail (GDK_IS_PIXBUF (src));
+  g_return_if_fail (GDK_IS_PIXBUF (dest));
+  g_return_if_fail (dest_x >= 0 && dest_x + dest_width <= dest->width);
+  g_return_if_fail (dest_y >= 0 && dest_y + dest_height <= dest->height);
+  g_return_if_fail (overall_alpha >= 0 && overall_alpha <= 255);
+
+  offset_x = floor (offset_x + 0.5);
+  offset_y = floor (offset_y + 0.5);
+  
+  _pixops_composite_color (dest->pixels, dest_width, dest_height,
+                          dest->rowstride, dest->n_channels, dest->has_alpha,
+                          src->pixels, src->width, src->height,
+                          src->rowstride, src->n_channels, src->has_alpha,
+                          dest_x, dest_y, dest_width, dest_height, offset_x,
+                          offset_y, scale_x, scale_y,
+                          (PixopsInterpType)interp_type, overall_alpha,
+                          check_x, check_y, check_size, color1, color2);
+}
+
+/**
+ * gdk_pixbuf_scale_simple:
+ * @src: a #GdkPixbuf
+ * @dest_width: the width of destination image
+ * @dest_height: the height of destination image
+ * @interp_type: the interpolation type for the transformation.
+ *
+ * Create a new #GdkPixbuf containing a copy of @src scaled to
+ * @dest_width x @dest_height. Leaves @src unaffected.  @interp_type
+ * should be #GDK_INTERP_NEAREST if you want maximum speed (but when
+ * scaling down #GDK_INTERP_NEAREST is usually unusably ugly).  The
+ * default @interp_type should be #GDK_INTERP_BILINEAR which offers
+ * reasonable quality and speed.
+ *
+ * You can scale a sub-portion of @src by creating a sub-pixbuf
+ * pointing into @src; see gdk_pixbuf_new_subpixbuf().
+ *
+ * For more complicated scaling/compositing see gdk_pixbuf_scale()
+ * and gdk_pixbuf_composite().
+ * 
+ * Return value: (transfer full): the new #GdkPixbuf, or %NULL if not enough memory could be
+ * allocated for it.
+ **/
+GdkPixbuf *
+gdk_pixbuf_scale_simple (const GdkPixbuf *src,
+                        int              dest_width,
+                        int              dest_height,
+                        GdkInterpType    interp_type)
+{
+  GdkPixbuf *dest;
+
+  g_return_val_if_fail (GDK_IS_PIXBUF (src), NULL);
+  g_return_val_if_fail (dest_width > 0, NULL);
+  g_return_val_if_fail (dest_height > 0, NULL);
+
+  dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB, src->has_alpha, 8, dest_width, dest_height);
+  if (!dest)
+    return NULL;
+
+  gdk_pixbuf_scale (src, dest,  0, 0, dest_width, dest_height, 0, 0,
+                   (double) dest_width / src->width,
+                   (double) dest_height / src->height,
+                   interp_type);
+
+  return dest;
+}
+
+/**
+ * gdk_pixbuf_composite_color_simple:
+ * @src: a #GdkPixbuf
+ * @dest_width: the width of destination image
+ * @dest_height: the height of destination image
+ * @interp_type: the interpolation type for the transformation.
+ * @overall_alpha: overall alpha for source image (0..255)
+ * @check_size: the size of checks in the checkboard (must be a power of two)
+ * @color1: the color of check at upper left
+ * @color2: the color of the other check
+ * 
+ * Creates a new #GdkPixbuf by scaling @src to @dest_width x
+ * @dest_height and compositing the result with a checkboard of colors
+ * @color1 and @color2.
+ * 
+ * Return value: (transfer full): the new #GdkPixbuf, or %NULL if not enough memory could be
+ * allocated for it.
+ **/
+GdkPixbuf *
+gdk_pixbuf_composite_color_simple (const GdkPixbuf *src,
+                                  int              dest_width,
+                                  int              dest_height,
+                                  GdkInterpType    interp_type,
+                                  int              overall_alpha,
+                                  int              check_size,
+                                  guint32          color1,
+                                  guint32          color2)
+{
+  GdkPixbuf *dest;
+
+  g_return_val_if_fail (GDK_IS_PIXBUF (src), NULL);
+  g_return_val_if_fail (dest_width > 0, NULL);
+  g_return_val_if_fail (dest_height > 0, NULL);
+  g_return_val_if_fail (overall_alpha >= 0 && overall_alpha <= 255, NULL);
+
+  dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB, src->has_alpha, 8, dest_width, dest_height);
+  if (!dest)
+    return NULL;
+
+  gdk_pixbuf_composite_color (src, dest, 0, 0, dest_width, dest_height, 0, 0,
+                             (double) dest_width / src->width,
+                             (double) dest_height / src->height,
+                             interp_type, overall_alpha, 0, 0, check_size, color1, color2);
+
+  return dest;
+}
+
+#define OFFSET(pb, x, y) ((x) * (pb)->n_channels + (y) * (pb)->rowstride)
+
+/**
+ * gdk_pixbuf_rotate_simple:
+ * @src: a #GdkPixbuf
+ * @angle: the angle to rotate by
+ *
+ * Rotates a pixbuf by a multiple of 90 degrees, and returns the
+ * result in a new pixbuf.
+ *
+ * Returns: (transfer full): the new #GdkPixbuf, or %NULL if not enough memory could be
+ * allocated for it.
+ *
+ * Since: 2.6
+ */
+GdkPixbuf *
+gdk_pixbuf_rotate_simple (const GdkPixbuf   *src,
+                         GdkPixbufRotation  angle)
+{
+  GdkPixbuf *dest;
+  guchar *p, *q;
+  gint x, y;
+
+  switch (angle % 360)
+    {
+    case 0:
+      dest = gdk_pixbuf_copy (src);
+      break;
+    case 90:
+      dest = gdk_pixbuf_new (src->colorspace, 
+                            src->has_alpha, 
+                            src->bits_per_sample, 
+                            src->height, 
+                            src->width);
+      if (!dest)
+       return NULL;
+
+      for (y = 0; y < src->height; y++) 
+       { 
+         for (x = 0; x < src->width; x++) 
+           { 
+             p = src->pixels + OFFSET (src, x, y); 
+             q = dest->pixels + OFFSET (dest, y, src->width - x - 1); 
+             memcpy (q, p, dest->n_channels);
+           }
+       } 
+      break;
+    case 180:
+      dest = gdk_pixbuf_new (src->colorspace, 
+                            src->has_alpha, 
+                            src->bits_per_sample, 
+                            src->width, 
+                            src->height);
+      if (!dest)
+       return NULL;
+
+      for (y = 0; y < src->height; y++) 
+       { 
+         for (x = 0; x < src->width; x++) 
+           { 
+             p = src->pixels + OFFSET (src, x, y); 
+             q = dest->pixels + OFFSET (dest, src->width - x - 1, src->height - y - 1); 
+             memcpy (q, p, dest->n_channels);
+           }
+       } 
+      break;
+    case 270:
+      dest = gdk_pixbuf_new (src->colorspace, 
+                            src->has_alpha, 
+                            src->bits_per_sample, 
+                            src->height, 
+                            src->width);
+      if (!dest)
+       return NULL;
+
+      for (y = 0; y < src->height; y++) 
+       { 
+         for (x = 0; x < src->width; x++) 
+           { 
+             p = src->pixels + OFFSET (src, x, y); 
+             q = dest->pixels + OFFSET (dest, src->height - y - 1, x); 
+             memcpy (q, p, dest->n_channels);
+           }
+       } 
+      break;
+    default:
+      dest = NULL;
+      g_warning ("gdk_pixbuf_rotate_simple() can only rotate "
+                "by multiples of 90 degrees");
+      g_assert_not_reached ();
+  } 
+
+  return dest;
+}
+
+/**
+ * gdk_pixbuf_flip:
+ * @src: a #GdkPixbuf
+ * @horizontal: %TRUE to flip horizontally, %FALSE to flip vertically
+ *
+ * Flips a pixbuf horizontally or vertically and returns the
+ * result in a new pixbuf.
+ *
+ * Returns: (transfer full): the new #GdkPixbuf, or %NULL if not enough memory could be
+ * allocated for it.
+ *
+ * Since: 2.6
+ */
+GdkPixbuf *
+gdk_pixbuf_flip (const GdkPixbuf *src,
+                gboolean         horizontal)
+{
+  GdkPixbuf *dest;
+  guchar *p, *q;
+  gint x, y;
+
+  dest = gdk_pixbuf_new (src->colorspace, 
+                        src->has_alpha, 
+                        src->bits_per_sample, 
+                        src->width, 
+                        src->height);
+  if (!dest)
+    return NULL;
+
+  if (!horizontal) /* flip vertical */
+    {
+      for (y = 0; y < dest->height; y++)
+       {
+         p = src->pixels + OFFSET (src, 0, y);
+         q = dest->pixels + OFFSET (dest, 0, dest->height - y - 1);
+         memcpy (q, p, dest->rowstride);
+       }
+    }
+  else /* flip horizontal */
+    {
+      for (y = 0; y < dest->height; y++)
+       {
+         for (x = 0; x < dest->width; x++)
+           {
+             p = src->pixels + OFFSET (src, x, y);
+             q = dest->pixels + OFFSET (dest, dest->width - x - 1, y);
+             memcpy (q, p, dest->n_channels);
+           }
+       }
+    }
+
+  return dest;
+}
diff --git a/gdk-pixbuf/gdk-pixbuf-scaled-anim.c b/gdk-pixbuf/gdk-pixbuf-scaled-anim.c
new file mode 100644 (file)
index 0000000..f365590
--- /dev/null
@@ -0,0 +1,282 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* GdkPixbuf library - Simple transformations of animations
+ *
+ * Copyright (C) Red Hat, Inc
+ *
+ * Authors: Matthias Clasen <mclasen@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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 <glib.h>
+
+#include "gdk-pixbuf.h"
+#include "gdk-pixbuf-io.h"
+#include "gdk-pixbuf-scaled-anim.h"
+
+
+struct _GdkPixbufScaledAnimClass
+{
+        GdkPixbufAnimationClass parent_class;
+};
+
+struct _GdkPixbufScaledAnim
+{
+       GdkPixbufAnimation parent_instance;
+
+       GdkPixbufAnimation *anim;
+       gdouble xscale;
+       gdouble yscale;
+       gdouble tscale;
+
+       GdkPixbuf *current;
+};
+
+struct _GdkPixbufScaledAnimIterClass
+{
+        GdkPixbufAnimationClass parent_class;
+};
+
+struct _GdkPixbufScaledAnimIter
+{
+       GdkPixbufAnimationIter parent_instance;
+
+       GdkPixbufScaledAnim *scaled;
+        GdkPixbufAnimationIter *iter;
+};
+
+typedef struct _GdkPixbufScaledAnimIter GdkPixbufScaledAnimIter;
+typedef struct _GdkPixbufScaledAnimIterClass GdkPixbufScaledAnimIterClass;
+
+GdkPixbufScaledAnim *
+_gdk_pixbuf_scaled_anim_new (GdkPixbufAnimation *anim,
+                             gdouble             xscale,
+                             gdouble             yscale,
+                             gdouble             tscale)
+{
+       GdkPixbufScaledAnim *scaled;
+
+       scaled = g_object_new (GDK_TYPE_PIXBUF_SCALED_ANIM, NULL);
+
+       scaled->anim = g_object_ref (anim);
+       scaled->xscale = xscale;
+       scaled->yscale = yscale;
+       scaled->tscale = tscale;
+
+       return scaled;
+}
+
+G_DEFINE_TYPE (GdkPixbufScaledAnim, gdk_pixbuf_scaled_anim, GDK_TYPE_PIXBUF_ANIMATION);
+
+static void
+gdk_pixbuf_scaled_anim_init (GdkPixbufScaledAnim *scaled)
+{
+       scaled->xscale = 1.0;
+       scaled->yscale = 1.0;
+       scaled->tscale = 1.0;
+}
+
+static void
+gdk_pixbuf_scaled_anim_finalize (GObject *object)
+{
+       GdkPixbufScaledAnim *scaled = (GdkPixbufScaledAnim *)object;
+
+       if (scaled->anim) {
+               g_object_unref (scaled->anim);
+               scaled->anim = NULL;
+       }
+
+       if (scaled->current) {
+               g_object_unref (scaled->current);
+               scaled->current = NULL;
+       }
+
+       G_OBJECT_CLASS (gdk_pixbuf_scaled_anim_parent_class)->finalize (object);
+}
+
+static gboolean
+is_static_image (GdkPixbufAnimation *anim)
+{
+       GdkPixbufScaledAnim *scaled = (GdkPixbufScaledAnim *)anim;
+
+       return gdk_pixbuf_animation_is_static_image (scaled->anim);
+}      
+
+static GdkPixbuf *
+get_scaled_pixbuf (GdkPixbufScaledAnim *scaled, 
+                   GdkPixbuf           *pixbuf)
+{
+       GQuark  quark;
+       gchar **options;
+
+       if (scaled->current) 
+               g_object_unref (scaled->current);
+
+       /* Preserve the options associated with the original pixbuf 
+          (if present), mostly so that client programs can use the
+          "orientation" option (if present) to rotate the image 
+          appropriately. gdk_pixbuf_scale_simple (and most other
+           gdk transform operations) does not preserve the attached
+           options when returning a new pixbuf. */
+
+       quark = g_quark_from_static_string ("gdk_pixbuf_options");
+       options = g_object_get_qdata (G_OBJECT (pixbuf), quark);
+
+       /* Get a new scaled pixbuf */
+       scaled->current  = gdk_pixbuf_scale_simple (pixbuf, 
+                       (int) (gdk_pixbuf_get_width (pixbuf) * scaled->xscale + .5),
+                       (int) (gdk_pixbuf_get_height (pixbuf) * scaled->yscale + .5),
+                       GDK_INTERP_BILINEAR);
+
+       /* Copy the original pixbuf options to the scaled pixbuf */
+        if (options && scaled->current)
+                 g_object_set_qdata_full (G_OBJECT (scaled->current), quark, 
+                                           g_strdupv (options), (GDestroyNotify) g_strfreev);
+
+       return scaled->current;
+}
+
+static GdkPixbuf *
+get_static_image (GdkPixbufAnimation *anim)
+{
+       GdkPixbufScaledAnim *scaled = (GdkPixbufScaledAnim *)anim;
+       GdkPixbuf *pixbuf;
+       
+       pixbuf = gdk_pixbuf_animation_get_static_image (scaled->anim);
+       return get_scaled_pixbuf (scaled, pixbuf);
+}
+
+static void
+get_size (GdkPixbufAnimation *anim,
+         int                *width,
+         int                *height)
+{
+       GdkPixbufScaledAnim *scaled = (GdkPixbufScaledAnim *)anim;
+
+        GDK_PIXBUF_ANIMATION_GET_CLASS (scaled->anim)->get_size (scaled->anim, width, height);
+       if (width) 
+               *width = (int)(*width * scaled->xscale + .5);
+       if (height)
+               *height = (int)(*height * scaled->yscale + .5);
+}
+
+static GdkPixbufAnimationIter *
+get_iter (GdkPixbufAnimation *anim,
+          const GTimeVal     *start_time)
+{
+       GdkPixbufScaledAnim *scaled = (GdkPixbufScaledAnim *)anim;
+       GdkPixbufScaledAnimIter *iter;
+
+       iter = g_object_new (GDK_TYPE_PIXBUF_SCALED_ANIM_ITER, NULL);
+
+       iter->scaled = g_object_ref (scaled);
+       iter->iter = gdk_pixbuf_animation_get_iter (scaled->anim, start_time);
+       
+       return (GdkPixbufAnimationIter*)iter;
+}
+
+static void
+gdk_pixbuf_scaled_anim_class_init (GdkPixbufScaledAnimClass *klass)
+{
+        GObjectClass *object_class;
+        GdkPixbufAnimationClass *anim_class;
+
+        object_class = G_OBJECT_CLASS (klass);
+        anim_class = GDK_PIXBUF_ANIMATION_CLASS (klass);
+        
+        object_class->finalize = gdk_pixbuf_scaled_anim_finalize;
+        
+        anim_class->is_static_image = is_static_image;
+        anim_class->get_static_image = get_static_image;
+        anim_class->get_size = get_size;
+        anim_class->get_iter = get_iter;
+}
+
+
+G_DEFINE_TYPE (GdkPixbufScaledAnimIter, gdk_pixbuf_scaled_anim_iter, GDK_TYPE_PIXBUF_ANIMATION_ITER);
+
+static void
+gdk_pixbuf_scaled_anim_iter_init (GdkPixbufScaledAnimIter *iter)
+{
+}
+
+static int
+get_delay_time (GdkPixbufAnimationIter *iter)
+{
+       GdkPixbufScaledAnimIter *scaled = (GdkPixbufScaledAnimIter *)iter;
+       int delay;
+
+       delay = gdk_pixbuf_animation_iter_get_delay_time (scaled->iter);
+       delay = (int)(delay * scaled->scaled->tscale);
+
+       return delay;
+}
+
+static GdkPixbuf *
+get_pixbuf (GdkPixbufAnimationIter *iter)
+{
+       GdkPixbufScaledAnimIter *scaled = (GdkPixbufScaledAnimIter *)iter;
+       GdkPixbuf *pixbuf;
+
+       pixbuf = gdk_pixbuf_animation_iter_get_pixbuf (scaled->iter);
+       return get_scaled_pixbuf (scaled->scaled, pixbuf);
+}
+
+static gboolean 
+on_currently_loading_frame (GdkPixbufAnimationIter *iter)
+{
+       GdkPixbufScaledAnimIter *scaled = (GdkPixbufScaledAnimIter *)iter;
+
+       return gdk_pixbuf_animation_iter_on_currently_loading_frame (scaled->iter);
+}
+
+static gboolean
+advance (GdkPixbufAnimationIter *iter,
+        const GTimeVal         *current_time)
+{
+       GdkPixbufScaledAnimIter *scaled = (GdkPixbufScaledAnimIter *)iter;
+
+       return gdk_pixbuf_animation_iter_advance (scaled->iter, current_time);
+}
+
+static void
+gdk_pixbuf_scaled_anim_iter_finalize (GObject *object)
+{
+        GdkPixbufScaledAnimIter *iter = (GdkPixbufScaledAnimIter *)object;
+        
+       g_object_unref (iter->iter);
+       g_object_unref (iter->scaled);
+
+       G_OBJECT_CLASS (gdk_pixbuf_scaled_anim_iter_parent_class)->finalize (object);
+}
+
+static void
+gdk_pixbuf_scaled_anim_iter_class_init (GdkPixbufScaledAnimIterClass *klass)
+{
+        GObjectClass *object_class;
+        GdkPixbufAnimationIterClass *anim_iter_class;
+
+        object_class = G_OBJECT_CLASS (klass);
+        anim_iter_class = GDK_PIXBUF_ANIMATION_ITER_CLASS (klass);
+        
+        object_class->finalize = gdk_pixbuf_scaled_anim_iter_finalize;
+        
+        anim_iter_class->get_delay_time = get_delay_time;
+        anim_iter_class->get_pixbuf = get_pixbuf;
+        anim_iter_class->on_currently_loading_frame = on_currently_loading_frame;
+        anim_iter_class->advance = advance;
+}
diff --git a/gdk-pixbuf/gdk-pixbuf-scaled-anim.h b/gdk-pixbuf/gdk-pixbuf-scaled-anim.h
new file mode 100644 (file)
index 0000000..58c38c5
--- /dev/null
@@ -0,0 +1,47 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* GdkPixbuf library - Simple transformations of animations
+ *
+ * Copyright (C) 2007 Red Hat, Inc
+ *
+ * Authors: Matthias Clasen <mclasen@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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_SCALED_ANIM_H
+#define GDK_PIXBUF_SCALED_ANIM_H
+
+#include <gdk-pixbuf/gdk-pixbuf-animation.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_PIXBUF_SCALED_ANIM              (gdk_pixbuf_scaled_anim_get_type ())
+#define GDK_TYPE_PIXBUF_SCALED_ANIM_ITER         (gdk_pixbuf_scaled_anim_iter_get_type ())
+
+typedef struct _GdkPixbufScaledAnim GdkPixbufScaledAnim;
+typedef struct _GdkPixbufScaledAnimClass GdkPixbufScaledAnimClass;
+
+GType gdk_pixbuf_scaled_anim_get_type (void) G_GNUC_CONST;
+GType gdk_pixbuf_scaled_anim_iter_get_type (void) G_GNUC_CONST;
+
+GdkPixbufScaledAnim *_gdk_pixbuf_scaled_anim_new (GdkPixbufAnimation *anim,
+                                                  gdouble             xscale, 
+                                                  gdouble             yscale,
+                                                  gdouble             tscale);
+
+G_END_DECLS
+
+#endif  /* GDK_PIXBUF_SCALED_ANIM_H */
diff --git a/gdk-pixbuf/gdk-pixbuf-simple-anim.c b/gdk-pixbuf/gdk-pixbuf-simple-anim.c
new file mode 100644 (file)
index 0000000..b52dfbd
--- /dev/null
@@ -0,0 +1,548 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* GdkPixbuf library - Simple frame-based animations
+ *
+ * Copyright (C) Dom Lachowicz
+ *
+ * Authors: Dom Lachowicz <cinamod@hotmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ *
+ * Based on code originally by:
+ *          Jonathan Blandford <jrb@redhat.com>
+ *          Havoc Pennington <hp@redhat.com>
+ */
+
+#include "config.h"
+#include <glib.h>
+
+#define GDK_PIXBUF_C_COMPILATION
+#include "gdk-pixbuf.h"
+#include "gdk-pixbuf-private.h"
+#include "gdk-pixbuf-simple-anim.h"
+
+struct _GdkPixbufSimpleAnimClass
+{
+        GdkPixbufAnimationClass parent_class;
+};
+
+/* Private part of the GdkPixbufSimpleAnim structure */
+struct _GdkPixbufSimpleAnim
+{
+        GdkPixbufAnimation parent_instance;
+        
+        gint n_frames;
+        
+        gfloat rate;
+        gint total_time;
+        
+        GList *frames;
+        
+        gint width;
+        gint height;
+        
+        gboolean loop;
+};
+
+
+typedef struct _GdkPixbufSimpleAnimIter GdkPixbufSimpleAnimIter;
+typedef struct _GdkPixbufSimpleAnimIterClass GdkPixbufSimpleAnimIterClass;
+
+#define GDK_TYPE_PIXBUF_SIMPLE_ANIM_ITER              (gdk_pixbuf_simple_anim_iter_get_type ())
+#define GDK_PIXBUF_SIMPLE_ANIM_ITER(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_SIMPLE_ANIM_ITER, GdkPixbufSimpleAnimIter))
+#define GDK_IS_PIXBUF_SIMPLE_ANIM_ITER(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_SIMPLE_ANIM_ITER))
+
+#define GDK_PIXBUF_SIMPLE_ANIM_ITER_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_SIMPLE_ANIM_ITER, GdkPixbufSimpleAnimIterClass))
+#define GDK_IS_PIXBUF_SIMPLE_ANIM_ITER_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_SIMPLE_ANIM_ITER))
+#define GDK_PIXBUF_SIMPLE_ANIM_ITER_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_SIMPLE_ANIM_ITER, GdkPixbufSimpleAnimIterClass))
+
+GType gdk_pixbuf_simple_anim_iter_get_type (void) G_GNUC_CONST;
+
+
+struct _GdkPixbufSimpleAnimIterClass
+{
+        GdkPixbufAnimationIterClass parent_class;
+};
+
+struct _GdkPixbufSimpleAnimIter
+{
+        GdkPixbufAnimationIter parent_instance;
+        
+        GdkPixbufSimpleAnim *simple_anim;
+        
+        GTimeVal start_time;
+        GTimeVal current_time;
+        
+        gint position;
+        
+        GList *current_frame;
+};
+
+typedef struct _GdkPixbufFrame GdkPixbufFrame;
+struct _GdkPixbufFrame
+{
+        GdkPixbuf *pixbuf;
+        gint delay_time;
+        gint elapsed;
+};
+
+static void gdk_pixbuf_simple_anim_finalize (GObject *object);
+
+static gboolean   is_static_image  (GdkPixbufAnimation *animation);
+static GdkPixbuf *get_static_image (GdkPixbufAnimation *animation);
+
+static void       get_size         (GdkPixbufAnimation *anim,
+                                    gint               *width, 
+                                    gint               *height);
+static GdkPixbufAnimationIter *get_iter (GdkPixbufAnimation *anim,
+                                         const GTimeVal     *start_time);
+
+
+static void gdk_pixbuf_simple_anim_set_property (GObject        *object,
+                                                 guint           prop_id,
+                                                 const GValue   *value,
+                                                 GParamSpec     *pspec);
+static void gdk_pixbuf_simple_anim_get_property (GObject        *object,
+                                                 guint           prop_id,
+                                                 GValue         *value,
+                                                 GParamSpec     *pspec);
+
+enum
+{
+        PROP_0,
+        PROP_LOOP
+};
+
+G_DEFINE_TYPE (GdkPixbufSimpleAnim, gdk_pixbuf_simple_anim, GDK_TYPE_PIXBUF_ANIMATION)
+
+static void
+gdk_pixbuf_simple_anim_init (GdkPixbufSimpleAnim *anim)
+{
+}
+
+static void
+gdk_pixbuf_simple_anim_class_init (GdkPixbufSimpleAnimClass *klass)
+{
+        GObjectClass *object_class;
+        GdkPixbufAnimationClass *anim_class;
+
+        object_class = G_OBJECT_CLASS (klass);
+        anim_class = GDK_PIXBUF_ANIMATION_CLASS (klass);
+
+        object_class->set_property = gdk_pixbuf_simple_anim_set_property;
+        object_class->get_property = gdk_pixbuf_simple_anim_get_property;
+        object_class->finalize = gdk_pixbuf_simple_anim_finalize;
+        
+        anim_class->is_static_image = is_static_image;
+        anim_class->get_static_image = get_static_image;
+        anim_class->get_size = get_size;
+        anim_class->get_iter = get_iter;
+
+        /**
+         * GdkPixbufSimpleAnim:loop:
+         *
+         * Whether the animation should loop when it reaches the end.
+         *
+         * Since: 2.18
+         */
+        g_object_class_install_property (object_class,
+                                         PROP_LOOP,
+                                         g_param_spec_boolean ("loop",
+                                                               P_("Loop"),
+                                                               P_("Whether the animation should loop when it reaches the end"),
+                                                               FALSE,
+                                                               G_PARAM_READWRITE));
+}
+
+static void
+gdk_pixbuf_simple_anim_finalize (GObject *object)
+{
+        GdkPixbufSimpleAnim *anim;
+        GList *l;
+        GdkPixbufFrame *frame;
+        
+        anim = GDK_PIXBUF_SIMPLE_ANIM (object);        
+        
+        for (l = anim->frames; l; l = l->next) {
+                frame = l->data;
+                g_object_unref (frame->pixbuf);
+                g_free (frame);
+        }
+        
+        g_list_free (anim->frames);
+        
+        G_OBJECT_CLASS (gdk_pixbuf_simple_anim_parent_class)->finalize (object);
+}
+
+static gboolean
+is_static_image (GdkPixbufAnimation *animation)
+{
+        GdkPixbufSimpleAnim *anim;
+        
+        anim = GDK_PIXBUF_SIMPLE_ANIM (animation);
+
+        return (anim->frames != NULL && anim->frames->next == NULL);
+}
+
+static GdkPixbuf *
+get_static_image (GdkPixbufAnimation *animation)
+{
+        GdkPixbufSimpleAnim *anim;
+        
+        anim = GDK_PIXBUF_SIMPLE_ANIM (animation);
+        
+        if (anim->frames == NULL)
+                return NULL;
+        else
+                return ((GdkPixbufFrame *)anim->frames->data)->pixbuf;
+}
+
+static void
+get_size (GdkPixbufAnimation *animation,
+          gint               *width, 
+          gint               *height)
+{
+        GdkPixbufSimpleAnim *anim;
+
+        anim = GDK_PIXBUF_SIMPLE_ANIM (animation);
+        
+        if (width)
+                *width = anim->width;
+        
+        if (height)
+                *height = anim->height;
+}
+
+static void
+iter_clear (GdkPixbufSimpleAnimIter *iter)
+{
+        iter->current_frame = NULL;
+}
+
+static void
+iter_restart (GdkPixbufSimpleAnimIter *iter)
+{
+        iter_clear (iter);
+        
+        iter->current_frame = iter->simple_anim->frames;
+}
+
+static GdkPixbufAnimationIter *
+get_iter (GdkPixbufAnimation *anim,
+          const GTimeVal    *start_time)
+{
+        GdkPixbufSimpleAnimIter *iter;
+        
+        iter = g_object_new (GDK_TYPE_PIXBUF_SIMPLE_ANIM_ITER, NULL);
+
+        iter->simple_anim = GDK_PIXBUF_SIMPLE_ANIM (anim);
+
+        g_object_ref (iter->simple_anim);
+        
+        iter_restart (iter);
+        
+        iter->start_time = *start_time;
+        iter->current_time = *start_time;
+        
+        return GDK_PIXBUF_ANIMATION_ITER (iter);
+}
+
+static void gdk_pixbuf_simple_anim_iter_finalize (GObject *object);
+
+static gint       get_delay_time             (GdkPixbufAnimationIter *iter);
+static GdkPixbuf *get_pixbuf                 (GdkPixbufAnimationIter *iter);
+static gboolean   on_currently_loading_frame (GdkPixbufAnimationIter *iter);
+static gboolean   advance                    (GdkPixbufAnimationIter *iter,
+                                              const GTimeVal         *current_time);
+
+G_DEFINE_TYPE (GdkPixbufSimpleAnimIter, gdk_pixbuf_simple_anim_iter, GDK_TYPE_PIXBUF_ANIMATION_ITER)
+
+static void
+gdk_pixbuf_simple_anim_iter_init (GdkPixbufSimpleAnimIter *iter)
+{
+}
+
+static void
+gdk_pixbuf_simple_anim_iter_class_init (GdkPixbufSimpleAnimIterClass *klass)
+{
+        GObjectClass *object_class;
+        GdkPixbufAnimationIterClass *anim_iter_class;
+
+        object_class = G_OBJECT_CLASS (klass);
+        anim_iter_class = GDK_PIXBUF_ANIMATION_ITER_CLASS (klass);
+        
+        object_class->finalize = gdk_pixbuf_simple_anim_iter_finalize;
+        
+        anim_iter_class->get_delay_time = get_delay_time;
+        anim_iter_class->get_pixbuf = get_pixbuf;
+        anim_iter_class->on_currently_loading_frame = on_currently_loading_frame;
+        anim_iter_class->advance = advance;
+}
+
+static void
+gdk_pixbuf_simple_anim_iter_finalize (GObject *object)
+{
+        GdkPixbufSimpleAnimIter *iter;
+        
+        iter = GDK_PIXBUF_SIMPLE_ANIM_ITER (object);
+        iter_clear (iter);
+        
+        g_object_unref (iter->simple_anim);
+        
+        G_OBJECT_CLASS (gdk_pixbuf_simple_anim_iter_parent_class)->finalize (object);
+}
+
+static gboolean
+advance (GdkPixbufAnimationIter *anim_iter,
+         const GTimeVal         *current_time)
+{
+        GdkPixbufSimpleAnimIter *iter;
+        gint elapsed;
+        gint loop_count;
+        GList *tmp;
+        GList *old;
+        
+        iter = GDK_PIXBUF_SIMPLE_ANIM_ITER (anim_iter);
+        
+        iter->current_time = *current_time;
+        
+        /* We use milliseconds for all times */
+        elapsed = (((iter->current_time.tv_sec - iter->start_time.tv_sec) * G_USEC_PER_SEC +
+                    iter->current_time.tv_usec - iter->start_time.tv_usec)) / 1000;
+        
+        if (elapsed < 0) {
+                /* Try to compensate; probably the system clock
+                 * was set backwards
+                 */
+                iter->start_time = iter->current_time;
+                elapsed = 0;
+        }
+        
+        g_assert (iter->simple_anim->total_time > 0);
+        
+        /* See how many times we've already played the full animation,
+         * and subtract time for that.
+         */
+        loop_count = elapsed / iter->simple_anim->total_time;
+        elapsed = elapsed % iter->simple_anim->total_time;
+        
+        iter->position = elapsed;
+        
+        /* Now move to the proper frame */
+        if (loop_count < 1 || iter->simple_anim->loop)
+                tmp = iter->simple_anim->frames;
+        else
+                tmp = NULL;
+        
+        while (tmp != NULL) {
+                GdkPixbufFrame *frame = tmp->data;
+                
+                if (iter->position >= frame->elapsed &&
+                    iter->position < (frame->elapsed + frame->delay_time))
+                        break;
+                
+                tmp = tmp->next;
+        }
+        
+        old = iter->current_frame;
+        
+        iter->current_frame = tmp;
+        
+        return iter->current_frame != old;
+}
+
+static gint
+get_delay_time (GdkPixbufAnimationIter *anim_iter)
+{
+        GdkPixbufFrame *frame;
+        GdkPixbufSimpleAnimIter *iter;
+
+        iter = GDK_PIXBUF_SIMPLE_ANIM_ITER (anim_iter);
+        
+        if (iter->current_frame) {
+                frame = iter->current_frame->data;
+                return frame->delay_time - (iter->position - frame->elapsed);
+        }
+        else {
+                return -1;             /* show last frame forever */
+        }
+}
+
+static GdkPixbuf *
+get_pixbuf (GdkPixbufAnimationIter *anim_iter)
+{
+        GdkPixbufSimpleAnimIter *iter;
+        GdkPixbufFrame *frame;
+        
+        iter = GDK_PIXBUF_SIMPLE_ANIM_ITER (anim_iter);
+        
+        if (iter->current_frame)
+                frame = iter->current_frame->data;
+        else if (g_list_length (iter->simple_anim->frames) > 0)
+                frame = g_list_last (iter->simple_anim->frames)->data;
+        else
+                frame = NULL;
+
+        if (frame == NULL)
+                return NULL;
+        
+        return frame->pixbuf;
+}
+
+static gboolean
+on_currently_loading_frame (GdkPixbufAnimationIter *anim_iter)
+{
+  GdkPixbufSimpleAnimIter *iter;
+
+  iter = GDK_PIXBUF_SIMPLE_ANIM_ITER (anim_iter);
+
+  return iter->current_frame == NULL || iter->current_frame->next == NULL;
+}
+
+/**
+ * gdk_pixbuf_simple_anim_new:
+ * @width: the width of the animation
+ * @height: the height of the animation
+ * @rate: the speed of the animation, in frames per second
+ *
+ * Creates a new, empty animation.
+ *
+ * Returns: a newly allocated #GdkPixbufSimpleAnim 
+ *
+ * Since: 2.8
+ */
+GdkPixbufSimpleAnim *
+gdk_pixbuf_simple_anim_new (gint   width, 
+                            gint   height, 
+                            gfloat rate)
+{
+  GdkPixbufSimpleAnim *anim;
+
+  anim = g_object_new (GDK_TYPE_PIXBUF_SIMPLE_ANIM, NULL);
+  anim->width = width;
+  anim->height = height;
+  anim->rate = rate;
+
+  return anim;
+}
+
+/**
+ * gdk_pixbuf_simple_anim_add_frame:
+ * @animation: a #GdkPixbufSimpleAnim
+ * @pixbuf: the pixbuf to add 
+ *
+ * Adds a new frame to @animation. The @pixbuf must
+ * have the dimensions specified when the animation 
+ * was constructed.
+ *
+ * Since: 2.8
+ */
+void
+gdk_pixbuf_simple_anim_add_frame (GdkPixbufSimpleAnim *animation,
+                                  GdkPixbuf           *pixbuf)
+{
+  GdkPixbufFrame *frame;
+  int nframe = 0;
+  
+  g_return_if_fail (GDK_IS_PIXBUF_SIMPLE_ANIM (animation));
+  g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
+  
+  nframe = g_list_length (animation->frames);
+  
+  frame = g_new0 (GdkPixbufFrame, 1);
+  frame->delay_time = (gint) (1000 / animation->rate);
+  frame->elapsed = (gint) (frame->delay_time * nframe);
+  animation->total_time += frame->delay_time;
+  frame->pixbuf = g_object_ref (pixbuf);
+
+  animation->frames = g_list_append (animation->frames, frame);
+}
+
+static void
+gdk_pixbuf_simple_anim_get_property (GObject         *object,
+                                     guint            prop_id,
+                                     GValue          *value,
+                                     GParamSpec      *pspec)
+{
+        GdkPixbufSimpleAnim *animation = GDK_PIXBUF_SIMPLE_ANIM (object);
+
+        switch (prop_id) {
+        case PROP_LOOP:
+                g_value_set_boolean (value,
+                                     gdk_pixbuf_simple_anim_get_loop (animation));
+                break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static void
+gdk_pixbuf_simple_anim_set_property (GObject         *object,
+                                     guint            prop_id,
+                                     const GValue    *value,
+                                     GParamSpec      *pspec)
+{
+        GdkPixbufSimpleAnim *animation = GDK_PIXBUF_SIMPLE_ANIM (object);
+
+        switch (prop_id) {
+        case PROP_LOOP:
+                gdk_pixbuf_simple_anim_set_loop (animation,
+                                                 g_value_get_boolean (value));
+                break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+/**
+ * gdk_pixbuf_simple_anim_set_loop:
+ * @animation: a #GdkPixbufSimpleAnim
+ * @loop: whether to loop the animation
+ *
+ * Sets whether @animation should loop indefinitely when it reaches the end.
+ *
+ * Since: 2.18
+ **/
+void
+gdk_pixbuf_simple_anim_set_loop (GdkPixbufSimpleAnim *animation,
+                                 gboolean             loop)
+{
+        g_return_if_fail (GDK_IS_PIXBUF_SIMPLE_ANIM (animation));
+
+        if (loop != animation->loop) {
+                animation->loop = loop;
+                g_object_notify (G_OBJECT (animation), "loop");
+        }
+}
+
+/**
+ * gdk_pixbuf_simple_anim_get_loop:
+ * @animation: a #GdkPixbufSimpleAnim
+ *
+ * Gets whether @animation should loop indefinitely when it reaches the end.
+ *
+ * Returns: %TRUE if the animation loops forever, %FALSE otherwise
+ *
+ * Since: 2.18
+ **/
+gboolean
+gdk_pixbuf_simple_anim_get_loop (GdkPixbufSimpleAnim *animation)
+{
+        g_return_val_if_fail (GDK_IS_PIXBUF_SIMPLE_ANIM (animation), FALSE);
+
+        return animation->loop;
+}
diff --git a/gdk-pixbuf/gdk-pixbuf-simple-anim.h b/gdk-pixbuf/gdk-pixbuf-simple-anim.h
new file mode 100644 (file)
index 0000000..496688f
--- /dev/null
@@ -0,0 +1,66 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* GdkPixbuf library - Simple frame-based animations
+ *
+ * Copyright (C) 2004 Dom Lachowicz
+ *
+ * Authors: Dom Lachowicz <cinamod@hotmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#if defined(GDK_PIXBUF_DISABLE_SINGLE_INCLUDES) && !defined (GDK_PIXBUF_H_INSIDE) && !defined (GDK_PIXBUF_COMPILATION)
+#error "Only <gdk-pixbuf/gdk-pixbuf.h> can be included directly."
+#endif
+
+#ifndef GDK_PIXBUF_SIMPLE_ANIM_H
+#define GDK_PIXBUF_SIMPLE_ANIM_H
+
+#include <gdk-pixbuf/gdk-pixbuf-animation.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GdkPixbufSimpleAnim:
+ * 
+ * An opaque struct representing a simple animation.
+ */
+typedef struct _GdkPixbufSimpleAnim GdkPixbufSimpleAnim;
+typedef struct _GdkPixbufSimpleAnimClass GdkPixbufSimpleAnimClass;
+
+#define GDK_TYPE_PIXBUF_SIMPLE_ANIM              (gdk_pixbuf_simple_anim_get_type ())
+#define GDK_PIXBUF_SIMPLE_ANIM(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_SIMPLE_ANIM, GdkPixbufSimpleAnim))
+#define GDK_IS_PIXBUF_SIMPLE_ANIM(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_SIMPLE_ANIM))
+
+#define GDK_PIXBUF_SIMPLE_ANIM_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_SIMPLE_ANIM, GdkPixbufSimpleAnimClass))
+#define GDK_IS_PIXBUF_SIMPLE_ANIM_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_SIMPLE_ANIM))
+#define GDK_PIXBUF_SIMPLE_ANIM_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_SIMPLE_ANIM, GdkPixbufSimpleAnimClass))
+
+GType gdk_pixbuf_simple_anim_get_type (void) G_GNUC_CONST;
+GType gdk_pixbuf_simple_anim_iter_get_type (void) G_GNUC_CONST;
+
+GdkPixbufSimpleAnim *gdk_pixbuf_simple_anim_new           (gint   width, 
+                                                           gint   height,
+                                                           gfloat rate);
+void                 gdk_pixbuf_simple_anim_add_frame     (GdkPixbufSimpleAnim *animation,
+                                                           GdkPixbuf           *pixbuf);
+void                 gdk_pixbuf_simple_anim_set_loop      (GdkPixbufSimpleAnim *animation,
+                                                           gboolean             loop);
+gboolean             gdk_pixbuf_simple_anim_get_loop      (GdkPixbufSimpleAnim *animation);
+
+G_END_DECLS
+
+
+#endif  /* GDK_PIXBUF_SIMPLE_ANIM_H */
diff --git a/gdk-pixbuf/gdk-pixbuf-transform.h b/gdk-pixbuf/gdk-pixbuf-transform.h
new file mode 100644 (file)
index 0000000..d4757ff
--- /dev/null
@@ -0,0 +1,160 @@
+/* GdkPixbuf library - transformations
+ *
+ * Copyright (C) 2003 The Free Software Foundation
+ *
+ * Authors: Mark Crichton <crichton@gimp.org>
+ *          Miguel de Icaza <miguel@gnu.org>
+ *          Federico Mena-Quintero <federico@gimp.org>
+ *          Havoc Pennington <hp@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#if defined(GDK_PIXBUF_DISABLE_SINGLE_INCLUDES) && !defined (GDK_PIXBUF_H_INSIDE) && !defined (GDK_PIXBUF_COMPILATION)
+#error "Only <gdk-pixbuf/gdk-pixbuf.h> can be included directly."
+#endif
+
+#ifndef GDK_PIXBUF_TRANSFORM_H
+#define GDK_PIXBUF_TRANSFORM_H
+
+#include <glib.h>
+#include <gdk-pixbuf/gdk-pixbuf-core.h>
+
+
+G_BEGIN_DECLS
+
+/* Scaling */
+
+/**
+ * GdkInterpType:
+ * @GDK_INTERP_NEAREST: Nearest neighbor sampling; this is the fastest
+ *  and lowest quality mode. Quality is normally unacceptable when scaling 
+ *  down, but may be OK when scaling up.
+ * @GDK_INTERP_TILES: This is an accurate simulation of the PostScript
+ *  image operator without any interpolation enabled.  Each pixel is
+ *  rendered as a tiny parallelogram of solid color, the edges of which
+ *  are implemented with antialiasing.  It resembles nearest neighbor for
+ *  enlargement, and bilinear for reduction.
+ * @GDK_INTERP_BILINEAR: Best quality/speed balance; use this mode by
+ *  default. Bilinear interpolation.  For enlargement, it is
+ *  equivalent to point-sampling the ideal bilinear-interpolated image.
+ *  For reduction, it is equivalent to laying down small tiles and
+ *  integrating over the coverage area.
+ * @GDK_INTERP_HYPER: This is the slowest and highest quality
+ *  reconstruction function. It is derived from the hyperbolic filters in
+ *  Wolberg's "Digital Image Warping", and is formally defined as the
+ *  hyperbolic-filter sampling the ideal hyperbolic-filter interpolated
+ *  image (the filter is designed to be idempotent for 1:1 pixel mapping).
+ * 
+ *  This enumeration describes the different interpolation modes that
+ *  can be used with the scaling functions. @GDK_INTERP_NEAREST is 
+ *  the fastest scaling method, but has horrible quality when 
+ *  scaling down. @GDK_INTERP_BILINEAR is the best choice if you 
+ *  aren't sure what to choose, it has a good speed/quality balance.
+ * 
+ *  <note>
+ *     Cubic filtering is missing from the list; hyperbolic
+ *     interpolation is just as fast and results in higher quality.
+ *  </note>
+ */
+typedef enum {
+       GDK_INTERP_NEAREST,
+       GDK_INTERP_TILES,
+       GDK_INTERP_BILINEAR,
+       GDK_INTERP_HYPER
+} GdkInterpType;
+
+/**
+ * GdkPixbufRotation:
+ * @GDK_PIXBUF_ROTATE_NONE: No rotation.
+ * @GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE: Rotate by 90 degrees.
+ * @GDK_PIXBUF_ROTATE_UPSIDEDOWN: Rotate by 180 degrees.
+ * @GDK_PIXBUF_ROTATE_CLOCKWISE: Rotate by 270 degrees.
+ * 
+ * The possible rotations which can be passed to gdk_pixbuf_rotate_simple().
+ * To make them easier to use, their numerical values are the actual degrees.
+ */
+typedef enum {
+       GDK_PIXBUF_ROTATE_NONE             =   0,
+       GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE =  90,
+       GDK_PIXBUF_ROTATE_UPSIDEDOWN       = 180,
+       GDK_PIXBUF_ROTATE_CLOCKWISE        = 270
+} GdkPixbufRotation;
+
+void gdk_pixbuf_scale           (const GdkPixbuf *src,
+                                GdkPixbuf       *dest,
+                                int              dest_x,
+                                int              dest_y,
+                                int              dest_width,
+                                int              dest_height,
+                                double           offset_x,
+                                double           offset_y,
+                                double           scale_x,
+                                double           scale_y,
+                                GdkInterpType    interp_type);
+void gdk_pixbuf_composite       (const GdkPixbuf *src,
+                                GdkPixbuf       *dest,
+                                int              dest_x,
+                                int              dest_y,
+                                int              dest_width,
+                                int              dest_height,
+                                double           offset_x,
+                                double           offset_y,
+                                double           scale_x,
+                                double           scale_y,
+                                GdkInterpType    interp_type,
+                                int              overall_alpha);
+void gdk_pixbuf_composite_color (const GdkPixbuf *src,
+                                GdkPixbuf       *dest,
+                                int              dest_x,
+                                int              dest_y,
+                                int              dest_width,
+                                int              dest_height,
+                                double           offset_x,
+                                double           offset_y,
+                                double           scale_x,
+                                double           scale_y,
+                                GdkInterpType    interp_type,
+                                int              overall_alpha,
+                                int              check_x,
+                                int              check_y,
+                                int              check_size,
+                                guint32          color1,
+                                guint32          color2);
+
+GdkPixbuf *gdk_pixbuf_scale_simple           (const GdkPixbuf *src,
+                                             int              dest_width,
+                                             int              dest_height,
+                                             GdkInterpType    interp_type);
+
+GdkPixbuf *gdk_pixbuf_composite_color_simple (const GdkPixbuf *src,
+                                             int              dest_width,
+                                             int              dest_height,
+                                             GdkInterpType    interp_type,
+                                             int              overall_alpha,
+                                             int              check_size,
+                                             guint32          color1,
+                                             guint32          color2);
+
+GdkPixbuf *gdk_pixbuf_rotate_simple          (const GdkPixbuf   *src,
+                                             GdkPixbufRotation  angle);
+GdkPixbuf *gdk_pixbuf_flip                   (const GdkPixbuf   *src,
+                                             gboolean           horizontal);
+                                    
+G_END_DECLS
+
+
+#endif  /* GDK_PIXBUF_TRANSFORM_H */
diff --git a/gdk-pixbuf/gdk-pixbuf-util.c b/gdk-pixbuf/gdk-pixbuf-util.c
new file mode 100644 (file)
index 0000000..f2e889b
--- /dev/null
@@ -0,0 +1,387 @@
+/* GdkPixbuf library - Utilities and miscellaneous convenience functions
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Authors: Federico Mena-Quintero <federico@gimp.org>
+ *          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
+ * 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.
+ *
+ * You should have received a copy of the GNU Lesser 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 <string.h>
+#include <libintl.h>
+
+#include "gdk-pixbuf-transform.h"
+#include "gdk-pixbuf-private.h"
+
+/**
+ * SECTION:util
+ * @Short_description: Utility and miscellaneous convenience functions.
+ * @Title: Utilities
+ * @See_also: #GdkPixbuf
+ * 
+ * These functions provide miscellaneous utilities for manipulating
+ * pixbufs.  The pixel data in pixbufs may of course be manipulated
+ * directly by applications, but several common operations can be
+ * performed by these functions instead.
+ */
+\f
+
+/**
+ * gdk_pixbuf_add_alpha:
+ * @pixbuf: A #GdkPixbuf.
+ * @substitute_color: Whether to set a color to zero opacity.  If this
+ * is %FALSE, then the (@r, @g, @b) arguments will be ignored.
+ * @r: Red value to substitute.
+ * @g: Green value to substitute.
+ * @b: Blue value to substitute.
+ *
+ * Takes an existing pixbuf and adds an alpha channel to it.
+ * If the existing pixbuf already had an alpha channel, the channel
+ * values are copied from the original; otherwise, the alpha channel
+ * is initialized to 255 (full opacity).
+ * 
+ * If @substitute_color is %TRUE, then the color specified by (@r, @g, @b) will be
+ * assigned zero opacity. That is, if you pass (255, 255, 255) for the
+ * substitute color, all white pixels will become fully transparent.
+ *
+ * Return value: (transfer full): A newly-created pixbuf with a reference count of 1.
+ **/
+GdkPixbuf *
+gdk_pixbuf_add_alpha (const GdkPixbuf *pixbuf,
+                     gboolean substitute_color, guchar r, guchar g, guchar b)
+{
+       GdkPixbuf *new_pixbuf;
+       int x, y;
+
+       g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
+       g_return_val_if_fail (pixbuf->colorspace == GDK_COLORSPACE_RGB, NULL);
+       g_return_val_if_fail (pixbuf->n_channels == 3 || pixbuf->n_channels == 4, NULL);
+       g_return_val_if_fail (pixbuf->bits_per_sample == 8, NULL);
+
+       if (pixbuf->has_alpha) {
+               new_pixbuf = gdk_pixbuf_copy (pixbuf);
+               if (!new_pixbuf)
+                       return NULL;
+
+                if (!substitute_color)
+                        return new_pixbuf;
+       } else {
+                new_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, pixbuf->width, pixbuf->height);
+        }
+        
+       if (!new_pixbuf)
+               return NULL;
+
+       for (y = 0; y < pixbuf->height; y++) {
+               guchar *src, *dest;
+               guchar tr, tg, tb;
+
+               src = pixbuf->pixels + y * pixbuf->rowstride;
+               dest = new_pixbuf->pixels + y * new_pixbuf->rowstride;
+                
+                if (pixbuf->has_alpha) {
+                        /* Just subst color, we already copied everything else */
+                        for (x = 0; x < pixbuf->width; x++) {
+                                if (src[0] == r && src[1] == g && src[2] == b)
+                                        dest[3] = 0;
+                                src += 4;
+                                dest += 4;
+                        }
+                } else {                        
+                        for (x = 0; x < pixbuf->width; x++) {
+                                tr = *dest++ = *src++;
+                                tg = *dest++ = *src++;
+                                tb = *dest++ = *src++;
+                                
+                                if (substitute_color && tr == r && tg == g && tb == b)
+                                        *dest++ = 0;
+                                else
+                                        *dest++ = 255;
+                        }
+               }
+       }
+
+       return new_pixbuf;
+}
+
+/**
+ * gdk_pixbuf_copy_area:
+ * @src_pixbuf: Source pixbuf.
+ * @src_x: Source X coordinate within @src_pixbuf.
+ * @src_y: Source Y coordinate within @src_pixbuf.
+ * @width: Width of the area to copy.
+ * @height: Height of the area to copy.
+ * @dest_pixbuf: Destination pixbuf.
+ * @dest_x: X coordinate within @dest_pixbuf.
+ * @dest_y: Y coordinate within @dest_pixbuf.
+ *
+ * Copies a rectangular area from @src_pixbuf to @dest_pixbuf.  Conversion of
+ * pixbuf formats is done automatically.
+ *
+ * If the source rectangle overlaps the destination rectangle on the
+ * same pixbuf, it will be overwritten during the copy operation.
+ * Therefore, you can not use this function to scroll a pixbuf.
+ **/
+void
+gdk_pixbuf_copy_area (const GdkPixbuf *src_pixbuf,
+                     int src_x, int src_y,
+                     int width, int height,
+                     GdkPixbuf *dest_pixbuf,
+                     int dest_x, int dest_y)
+{
+       g_return_if_fail (src_pixbuf != NULL);
+       g_return_if_fail (dest_pixbuf != NULL);
+
+       g_return_if_fail (src_x >= 0 && src_x + width <= src_pixbuf->width);
+       g_return_if_fail (src_y >= 0 && src_y + height <= src_pixbuf->height);
+
+       g_return_if_fail (dest_x >= 0 && dest_x + width <= dest_pixbuf->width);
+       g_return_if_fail (dest_y >= 0 && dest_y + height <= dest_pixbuf->height);
+
+        g_return_if_fail (!(gdk_pixbuf_get_has_alpha (src_pixbuf) && !gdk_pixbuf_get_has_alpha (dest_pixbuf)));
+        
+       /* This will perform format conversions automatically */
+
+       gdk_pixbuf_scale (src_pixbuf,
+                         dest_pixbuf,
+                         dest_x, dest_y,
+                         width, height,
+                         (double) (dest_x - src_x),
+                         (double) (dest_y - src_y),
+                         1.0, 1.0,
+                         GDK_INTERP_NEAREST);
+}
+
+
+
+/**
+ * gdk_pixbuf_saturate_and_pixelate:
+ * @src: source image
+ * @dest: place to write modified version of @src
+ * @saturation: saturation factor
+ * @pixelate: whether to pixelate
+ *
+ * Modifies saturation and optionally pixelates @src, placing the result in
+ * @dest. @src and @dest may be the same pixbuf with no ill effects.  If
+ * @saturation is 1.0 then saturation is not changed. If it's less than 1.0,
+ * saturation is reduced (the image turns toward grayscale); if greater than
+ * 1.0, saturation is increased (the image gets more vivid colors). If @pixelate
+ * is %TRUE, then pixels are faded in a checkerboard pattern to create a
+ * pixelated image. @src and @dest must have the same image format, size, and
+ * rowstride.
+ * 
+ **/
+void
+gdk_pixbuf_saturate_and_pixelate(const GdkPixbuf *src,
+                                 GdkPixbuf *dest,
+                                 gfloat saturation,
+                                 gboolean pixelate)
+{
+        /* NOTE that src and dest MAY be the same pixbuf! */
+  
+        g_return_if_fail (GDK_IS_PIXBUF (src));
+        g_return_if_fail (GDK_IS_PIXBUF (dest));
+        g_return_if_fail (gdk_pixbuf_get_height (src) == gdk_pixbuf_get_height (dest));
+        g_return_if_fail (gdk_pixbuf_get_width (src) == gdk_pixbuf_get_width (dest));
+        g_return_if_fail (gdk_pixbuf_get_has_alpha (src) == gdk_pixbuf_get_has_alpha (dest));
+        g_return_if_fail (gdk_pixbuf_get_colorspace (src) == gdk_pixbuf_get_colorspace (dest));
+  
+        if (saturation == 1.0 && !pixelate) {
+                if (dest != src)
+                        gdk_pixbuf_copy_area (src, 0, 0, 
+                                              gdk_pixbuf_get_width (src),
+                                              gdk_pixbuf_get_height (src),
+                                              dest, 0, 0);
+        } else {
+                int i, j, t;
+                int width, height, has_alpha, src_rowstride, dest_rowstride, bytes_per_pixel;
+               guchar *src_line;
+               guchar *dest_line;
+                guchar *src_pixel;
+               guchar *dest_pixel;
+                guchar intensity;
+
+                has_alpha = gdk_pixbuf_get_has_alpha (src);
+               bytes_per_pixel = has_alpha ? 4 : 3;
+                width = gdk_pixbuf_get_width (src);
+                height = gdk_pixbuf_get_height (src);
+                src_rowstride = gdk_pixbuf_get_rowstride (src);
+                dest_rowstride = gdk_pixbuf_get_rowstride (dest);
+                
+                src_line = gdk_pixbuf_get_pixels (src);
+                dest_line = gdk_pixbuf_get_pixels (dest);
+               
+#define DARK_FACTOR 0.7
+#define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
+#define CLAMP_UCHAR(v) (t = (v), CLAMP (t, 0, 255))
+#define SATURATE(v) ((1.0 - saturation) * intensity + saturation * (v))
+
+               for (i = 0 ; i < height ; i++) {
+                       src_pixel = src_line;
+                       src_line += src_rowstride;
+                       dest_pixel = dest_line;
+                       dest_line += dest_rowstride;
+
+                       for (j = 0 ; j < width ; j++) {
+                                intensity = INTENSITY (src_pixel[0], src_pixel[1], src_pixel[2]);
+                                if (pixelate && (i + j) % 2 == 0) {
+                                        dest_pixel[0] = intensity / 2 + 127;
+                                        dest_pixel[1] = intensity / 2 + 127;
+                                        dest_pixel[2] = intensity / 2 + 127;
+                                } else if (pixelate) {
+                                        dest_pixel[0] = CLAMP_UCHAR ((SATURATE (src_pixel[0])) * DARK_FACTOR);
+                                       dest_pixel[1] = CLAMP_UCHAR ((SATURATE (src_pixel[1])) * DARK_FACTOR);
+                                        dest_pixel[2] = CLAMP_UCHAR ((SATURATE (src_pixel[2])) * DARK_FACTOR);
+                                } else {
+                                        dest_pixel[0] = CLAMP_UCHAR (SATURATE (src_pixel[0]));
+                                        dest_pixel[1] = CLAMP_UCHAR (SATURATE (src_pixel[1]));
+                                        dest_pixel[2] = CLAMP_UCHAR (SATURATE (src_pixel[2]));
+                                }
+                               
+                                if (has_alpha)
+                                        dest_pixel[3] = src_pixel[3];
+
+                               src_pixel += bytes_per_pixel;
+                               dest_pixel += bytes_per_pixel;
+                       }
+                }
+        }
+}
+
+
+/**
+ * gdk_pixbuf_apply_embedded_orientation:
+ * @src: A #GdkPixbuf.
+ *
+ * Takes an existing pixbuf and checks for the presence of an
+ * associated "orientation" option, which may be provided by the 
+ * jpeg loader (which reads the exif orientation tag) or the 
+ * tiff loader (which reads the tiff orientation tag, and
+ * compensates it for the partial transforms performed by 
+ * libtiff). If an orientation option/tag is present, the
+ * appropriate transform will be performed so that the pixbuf
+ * is oriented correctly.
+ *
+ * Return value: (transfer full): A newly-created pixbuf, or a reference to the
+ * input pixbuf (with an increased reference count).
+ *
+ * Since: 2.12
+ **/
+GdkPixbuf *
+gdk_pixbuf_apply_embedded_orientation (GdkPixbuf *src)
+{
+       const gchar *orientation_string;
+       int          transform = 0;
+       GdkPixbuf   *temp;
+       GdkPixbuf   *dest;
+
+       g_return_val_if_fail (GDK_IS_PIXBUF (src), NULL);
+
+       /* Read the orientation option associated with the pixbuf */
+       orientation_string = gdk_pixbuf_get_option (src, "orientation");        
+
+       if (orientation_string) {
+               /* If an orientation option was found, convert the 
+                  orientation string into an integer. */
+               transform = (int) g_ascii_strtoll (orientation_string, NULL, 10);
+       }
+
+       /* Apply the actual transforms, which involve rotations and flips. 
+          The meaning of orientation values 1-8 and the required transforms
+          are defined by the TIFF and EXIF (for JPEGs) standards. */
+        switch (transform) {
+        case 1:
+                dest = src;
+                g_object_ref (dest);
+                break;
+        case 2:
+                dest = gdk_pixbuf_flip (src, TRUE);
+                break;
+        case 3:
+                dest = gdk_pixbuf_rotate_simple (src, GDK_PIXBUF_ROTATE_UPSIDEDOWN);
+                break;
+        case 4:
+                dest = gdk_pixbuf_flip (src, FALSE);
+                break;
+        case 5:
+                temp = gdk_pixbuf_rotate_simple (src, GDK_PIXBUF_ROTATE_CLOCKWISE);
+                dest = gdk_pixbuf_flip (temp, TRUE);
+                g_object_unref (temp);
+                break;
+        case 6:
+                dest = gdk_pixbuf_rotate_simple (src, GDK_PIXBUF_ROTATE_CLOCKWISE);
+                break;
+        case 7:
+                temp = gdk_pixbuf_rotate_simple (src, GDK_PIXBUF_ROTATE_CLOCKWISE);
+                dest = gdk_pixbuf_flip (temp, FALSE);
+                g_object_unref (temp);
+                break;
+        case 8:
+                dest = gdk_pixbuf_rotate_simple (src, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE);
+                break;
+        default:
+               /* if no orientation tag was present */
+                dest = src;
+                g_object_ref (dest);
+                break;
+        }
+
+        return dest;
+}
+
+#ifdef G_OS_WIN32
+
+static const gchar *
+get_localedir (void)
+{
+    gchar *temp;
+    gchar *retval;
+    
+    /* In gdk-pixbuf-io.c */
+    extern char *_gdk_pixbuf_win32_get_toplevel (void);
+
+    temp = g_build_filename (_gdk_pixbuf_win32_get_toplevel (), "share/locale", NULL);
+
+    /* The localedir is passed to bindtextdomain() which isn't
+     * UTF-8-aware.
+     */
+    retval = g_win32_locale_filename_from_utf8 (temp);
+    g_free (temp);
+    return retval;
+}
+
+#undef GDK_PIXBUF_LOCALEDIR
+#define GDK_PIXBUF_LOCALEDIR get_localedir ()
+
+#endif
+
+const gchar *
+gdk_pixbuf_gettext (const gchar *msgid)
+{
+        static gsize gettext_initialized = FALSE;
+
+        if (G_UNLIKELY (g_once_init_enter (&gettext_initialized))) {
+                bindtextdomain (GETTEXT_PACKAGE, GDK_PIXBUF_LOCALEDIR);
+#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
+                bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+                g_once_init_leave (&gettext_initialized, TRUE);
+        }
+
+        return g_dgettext (GETTEXT_PACKAGE, msgid);
+}
diff --git a/gdk-pixbuf/gdk-pixbuf.c b/gdk-pixbuf/gdk-pixbuf.c
new file mode 100644 (file)
index 0000000..284ab32
--- /dev/null
@@ -0,0 +1,892 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* GdkPixbuf library - Basic memory management
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Authors: Mark Crichton <crichton@gimp.org>
+ *          Miguel de Icaza <miguel@gnu.org>
+ *          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 Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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 <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define GDK_PIXBUF_C_COMPILATION
+#include "gdk-pixbuf-private.h"
+#include "gdk-pixbuf-features.h"
+#include "gdk-pixbuf-enum-types.h"
+
+/* Include the marshallers */
+#include <glib-object.h>
+#include <gio/gio.h>
+#include "gdk-pixbuf-marshal.c"
+
+/**
+ * SECTION:creating
+ * @Short_description: Creating a pixbuf from image data that is already in memory.
+ * @Title: Image Data in Memory
+ * @See_also: gdk_pixbuf_finalize().
+ * 
+ * The most basic way to create a pixbuf is to wrap an existing pixel
+ * buffer with a #GdkPixbuf structure.  You can use the
+ * gdk_pixbuf_new_from_data() function to do this You need to specify
+ * the destroy notification function that will be called when the
+ * data buffer needs to be freed; this will happen when a #GdkPixbuf
+ * is finalized by the reference counting functions If you have a
+ * chunk of static data compiled into your application, you can pass
+ * in %NULL as the destroy notification function so that the data
+ * will not be freed.
+ * 
+ * 
+ * The gdk_pixbuf_new() function can be used as a convenience to
+ * create a pixbuf with an empty buffer.  This is equivalent to
+ * allocating a data buffer using <function>malloc()</function> and 
+ * then wrapping it with gdk_pixbuf_new_from_data(). The gdk_pixbuf_new() 
+ * function will compute an optimal rowstride so that rendering can be 
+ * performed with an efficient algorithm.
+ * 
+ * 
+ * As a special case, you can use the gdk_pixbuf_new_from_xpm_data()
+ * function to create a pixbuf from inline XPM image data.
+ * 
+ * 
+ * You can also copy an existing pixbuf with the gdk_pixbuf_copy()
+ * function.  This is not the same as just doing a g_object_ref()
+ * on the old pixbuf; the copy function will actually duplicate the
+ * pixel data in memory and create a new #GdkPixbuf structure for it.
+ */
+
+/**
+ * SECTION:refcounting
+ * @Short_description: Functions for reference counting and memory management on pixbufs.
+ * @Title: Reference Counting and Memory Mangement
+ * @See_also: #GdkPixbuf, gdk_pixbuf_new_from_data().
+ * 
+ * #GdkPixbuf structures are reference counted.  This means that an
+ * application can share a single pixbuf among many parts of the
+ * code.  When a piece of the program needs to keep a pointer to a
+ * pixbuf, it should add a reference to it by calling g_object_ref().
+ * When it no longer needs the pixbuf, it should subtract a reference
+ * by calling g_object_unref().  The pixbuf will be destroyed when
+ * its reference count drops to zero.  Newly-created #GdkPixbuf
+ * structures start with a reference count of one.
+ * 
+ * 
+ * <note>
+ * As #GdkPixbuf is derived from #GObject now, gdk_pixbuf_ref() and
+ * gdk_pixbuf_unref() are deprecated in favour of g_object_ref()
+ * and g_object_unref () resp.
+ * </note>
+ * 
+ * <emphasis>Finalizing</emphasis> a pixbuf means to free its pixel
+ * data and to free the #GdkPixbuf structure itself.  Most of the
+ * library functions that create #GdkPixbuf structures create the
+ * pixel data by themselves and define the way it should be freed;
+ * you do not need to worry about those.  The only function that lets
+ * you specify how to free the pixel data is
+ * gdk_pixbuf_new_from_data().  Since you pass it a pre-allocated
+ * pixel buffer, you must also specify a way to free that data.  This
+ * is done with a function of type #GdkPixbufDestroyNotify.  When a
+ * pixbuf created with gdk_pixbuf_new_from_data() is finalized, your
+ * destroy notification function will be called, and it is its
+ * responsibility to free the pixel array.
+ */
+
+static void gdk_pixbuf_finalize     (GObject        *object);
+static void gdk_pixbuf_set_property (GObject        *object,
+                                    guint           prop_id,
+                                    const GValue   *value,
+                                    GParamSpec     *pspec);
+static void gdk_pixbuf_get_property (GObject        *object,
+                                    guint           prop_id,
+                                    GValue         *value,
+                                    GParamSpec     *pspec);
+
+\f
+enum 
+{
+  PROP_0,
+  PROP_COLORSPACE,
+  PROP_N_CHANNELS,
+  PROP_HAS_ALPHA,
+  PROP_BITS_PER_SAMPLE,
+  PROP_WIDTH,
+  PROP_HEIGHT,
+  PROP_ROWSTRIDE,
+  PROP_PIXELS
+};
+
+static void gdk_pixbuf_icon_iface_init (GIconIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GdkPixbuf, gdk_pixbuf, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_ICON,
+                                                gdk_pixbuf_icon_iface_init))
+
+static void 
+gdk_pixbuf_init (GdkPixbuf *pixbuf)
+{
+}
+
+static void
+gdk_pixbuf_class_init (GdkPixbufClass *klass)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+        
+        object_class->finalize = gdk_pixbuf_finalize;
+        object_class->set_property = gdk_pixbuf_set_property;
+        object_class->get_property = gdk_pixbuf_get_property;
+
+#define PIXBUF_PARAM_FLAGS G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY|\
+                           G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
+        /**
+         * GdkPixbuf:n-channels:
+         *
+         * The number of samples per pixel. 
+         * Currently, only 3 or 4 samples per pixel are supported.
+         */
+        g_object_class_install_property (object_class,
+                                         PROP_N_CHANNELS,
+                                         g_param_spec_int ("n-channels",
+                                                           P_("Number of Channels"),
+                                                           P_("The number of samples per pixel"),
+                                                           0,
+                                                           G_MAXINT,
+                                                           3,
+                                                           PIXBUF_PARAM_FLAGS));
+
+        g_object_class_install_property (object_class,
+                                         PROP_COLORSPACE,
+                                         g_param_spec_enum ("colorspace",
+                                                            P_("Colorspace"),
+                                                            P_("The colorspace in which the samples are interpreted"),
+                                                            GDK_TYPE_COLORSPACE,
+                                                            GDK_COLORSPACE_RGB,
+                                                            PIXBUF_PARAM_FLAGS));
+
+        g_object_class_install_property (object_class,
+                                         PROP_HAS_ALPHA,
+                                         g_param_spec_boolean ("has-alpha",
+                                                               P_("Has Alpha"),
+                                                               P_("Whether the pixbuf has an alpha channel"),
+                                                               FALSE,
+                                                               PIXBUF_PARAM_FLAGS));
+
+        /**
+         * GdkPixbuf:bits-per-sample:
+         *
+         * The number of bits per sample. 
+         * Currently only 8 bit per sample are supported.
+         */
+        g_object_class_install_property (object_class,
+                                         PROP_BITS_PER_SAMPLE,
+                                         g_param_spec_int ("bits-per-sample",
+                                                           P_("Bits per Sample"),
+                                                           P_("The number of bits per sample"),
+                                                           1,
+                                                           16,
+                                                           8,
+                                                           PIXBUF_PARAM_FLAGS));
+
+        g_object_class_install_property (object_class,
+                                         PROP_WIDTH,
+                                         g_param_spec_int ("width",
+                                                           P_("Width"),
+                                                           P_("The number of columns of the pixbuf"),
+                                                           1,
+                                                           G_MAXINT,
+                                                           1,
+                                                           PIXBUF_PARAM_FLAGS));
+
+        g_object_class_install_property (object_class,
+                                         PROP_HEIGHT,
+                                         g_param_spec_int ("height",
+                                                           P_("Height"),
+                                                           P_("The number of rows of the pixbuf"),
+                                                           1,
+                                                           G_MAXINT,
+                                                           1,
+                                                           PIXBUF_PARAM_FLAGS));
+
+        /**
+         * GdkPixbuf:rowstride:
+         *
+         * The number of bytes between the start of a row and 
+         * the start of the next row. This number must (obviously)
+         * be at least as large as the width of the pixbuf.
+         */
+        g_object_class_install_property (object_class,
+                                         PROP_ROWSTRIDE,
+                                         g_param_spec_int ("rowstride",
+                                                           P_("Rowstride"),
+                                                           P_("The number of bytes between the start of a row and the start of the next row"),
+                                                           1,
+                                                           G_MAXINT,
+                                                           1,
+                                                           PIXBUF_PARAM_FLAGS));
+
+        g_object_class_install_property (object_class,
+                                         PROP_PIXELS,
+                                         g_param_spec_pointer ("pixels",
+                                                               P_("Pixels"),
+                                                               P_("A pointer to the pixel data of the pixbuf"),
+                                                               PIXBUF_PARAM_FLAGS));
+}
+
+static void
+gdk_pixbuf_finalize (GObject *object)
+{
+        GdkPixbuf *pixbuf = GDK_PIXBUF (object);
+        
+        if (pixbuf->destroy_fn)
+                (* pixbuf->destroy_fn) (pixbuf->pixels, pixbuf->destroy_fn_data);
+        
+        G_OBJECT_CLASS (gdk_pixbuf_parent_class)->finalize (object);
+}
+
+
+/**
+ * gdk_pixbuf_ref: (skip)
+ * @pixbuf: A pixbuf.
+ *
+ * Adds a reference to a pixbuf.
+ *
+ * Return value: The same as the @pixbuf argument.
+ *
+ * Deprecated: 2.0: Use g_object_ref().
+ **/
+GdkPixbuf *
+gdk_pixbuf_ref (GdkPixbuf *pixbuf)
+{
+        return (GdkPixbuf *) g_object_ref (pixbuf);
+}
+
+/**
+ * gdk_pixbuf_unref: (skip)
+ * @pixbuf: A pixbuf.
+ *
+ * Removes a reference from a pixbuf.
+ *
+ * Deprecated: 2.0: Use g_object_unref().
+ **/
+void
+gdk_pixbuf_unref (GdkPixbuf *pixbuf)
+{
+        g_object_unref (pixbuf);
+}
+
+static void
+gdk_pixbuf_icon_iface_init (GIconIface *iface)
+{
+        iface->hash = (guint (*) (GIcon *)) g_direct_hash;
+        iface->equal = (gboolean (*) (GIcon *, GIcon *)) g_direct_equal;
+}
+
+/* Used as the destroy notification function for gdk_pixbuf_new() */
+static void
+free_buffer (guchar *pixels, gpointer data)
+{
+       g_free (pixels);
+}
+
+/**
+ * gdk_pixbuf_new:
+ * @colorspace: Color space for image
+ * @has_alpha: Whether the image should have transparency information
+ * @bits_per_sample: Number of bits per color sample
+ * @width: Width of image in pixels, must be > 0
+ * @height: Height of image in pixels, must be > 0
+ *
+ * Creates a new #GdkPixbuf structure and allocates a buffer for it.  The 
+ * buffer has an optimal rowstride.  Note that the buffer is not cleared;
+ * you will have to fill it completely yourself.
+ *
+ * Return value: A newly-created #GdkPixbuf with a reference count of 1, or 
+ * %NULL if not enough memory could be allocated for the image buffer.
+ **/
+GdkPixbuf *
+gdk_pixbuf_new (GdkColorspace colorspace, 
+                gboolean      has_alpha,
+                int           bits_per_sample,
+                int           width,
+                int           height)
+{
+       guchar *buf;
+       int channels;
+       int rowstride;
+        gsize bytes;
+
+       g_return_val_if_fail (colorspace == GDK_COLORSPACE_RGB, NULL);
+       g_return_val_if_fail (bits_per_sample == 8, NULL);
+       g_return_val_if_fail (width > 0, NULL);
+       g_return_val_if_fail (height > 0, NULL);
+
+       channels = has_alpha ? 4 : 3;
+        rowstride = width * channels;
+        if (rowstride / channels != width || rowstride + 3 < 0) /* overflow */
+                return NULL;
+        
+       /* Always align rows to 32-bit boundaries */
+       rowstride = (rowstride + 3) & ~3;
+
+        bytes = height * rowstride;
+        if (bytes / rowstride !=  height) /* overflow */
+                return NULL;
+            
+       buf = g_try_malloc (bytes);
+       if (!buf)
+               return NULL;
+
+       return gdk_pixbuf_new_from_data (buf, colorspace, has_alpha, bits_per_sample,
+                                        width, height, rowstride,
+                                        free_buffer, NULL);
+}
+
+/**
+ * gdk_pixbuf_copy:
+ * @pixbuf: A pixbuf.
+ * 
+ * Creates a new #GdkPixbuf with a copy of the information in the specified
+ * @pixbuf.
+ * 
+ * Return value: (transfer full): A newly-created pixbuf with a reference count of 1, or %NULL if
+ * not enough memory could be allocated.
+ **/
+GdkPixbuf *
+gdk_pixbuf_copy (const GdkPixbuf *pixbuf)
+{
+       guchar *buf;
+       int size;
+
+       g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
+
+       /* Calculate a semi-exact size.  Here we copy with full rowstrides;
+        * maybe we should copy each row individually with the minimum
+        * rowstride?
+        */
+
+       size = gdk_pixbuf_get_byte_length (pixbuf);
+
+       buf = g_try_malloc (size * sizeof (guchar));
+       if (!buf)
+               return NULL;
+
+       memcpy (buf, pixbuf->pixels, size);
+
+       return gdk_pixbuf_new_from_data (buf,
+                                        pixbuf->colorspace, pixbuf->has_alpha,
+                                        pixbuf->bits_per_sample,
+                                        pixbuf->width, pixbuf->height,
+                                        pixbuf->rowstride,
+                                        free_buffer,
+                                        NULL);
+}
+
+/**
+ * gdk_pixbuf_new_subpixbuf:
+ * @src_pixbuf: a #GdkPixbuf
+ * @src_x: X coord in @src_pixbuf
+ * @src_y: Y coord in @src_pixbuf
+ * @width: width of region in @src_pixbuf
+ * @height: height of region in @src_pixbuf
+ * 
+ * Creates a new pixbuf which represents a sub-region of
+ * @src_pixbuf. The new pixbuf shares its pixels with the
+ * original pixbuf, so writing to one affects both.
+ * The new pixbuf holds a reference to @src_pixbuf, so
+ * @src_pixbuf will not be finalized until the new pixbuf
+ * is finalized.
+ * 
+ * Return value: (transfer full): a new pixbuf 
+ **/
+GdkPixbuf*
+gdk_pixbuf_new_subpixbuf (GdkPixbuf *src_pixbuf,
+                          int        src_x,
+                          int        src_y,
+                          int        width,
+                          int        height)
+{
+        guchar *pixels;
+        GdkPixbuf *sub;
+
+        g_return_val_if_fail (GDK_IS_PIXBUF (src_pixbuf), NULL);
+        g_return_val_if_fail (src_x >= 0 && src_x + width <= src_pixbuf->width, NULL);
+        g_return_val_if_fail (src_y >= 0 && src_y + height <= src_pixbuf->height, NULL);
+
+        pixels = (gdk_pixbuf_get_pixels (src_pixbuf)
+                  + src_y * src_pixbuf->rowstride
+                  + src_x * src_pixbuf->n_channels);
+
+        sub = gdk_pixbuf_new_from_data (pixels,
+                                        src_pixbuf->colorspace,
+                                        src_pixbuf->has_alpha,
+                                        src_pixbuf->bits_per_sample,
+                                        width, height,
+                                        src_pixbuf->rowstride,
+                                        NULL, NULL);
+
+        /* Keep a reference to src_pixbuf */
+        g_object_ref (src_pixbuf);
+  
+        g_object_set_qdata_full (G_OBJECT (sub),
+                                 g_quark_from_static_string ("gdk-pixbuf-subpixbuf-src"),
+                                 src_pixbuf,
+                                 (GDestroyNotify) g_object_unref);
+
+        return sub;
+}
+
+\f
+
+/* Accessors */
+
+/**
+ * gdk_pixbuf_get_colorspace:
+ * @pixbuf: A pixbuf.
+ *
+ * Queries the color space of a pixbuf.
+ *
+ * Return value: Color space.
+ **/
+GdkColorspace
+gdk_pixbuf_get_colorspace (const GdkPixbuf *pixbuf)
+{
+       g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), GDK_COLORSPACE_RGB);
+
+       return pixbuf->colorspace;
+}
+
+/**
+ * gdk_pixbuf_get_n_channels:
+ * @pixbuf: A pixbuf.
+ *
+ * Queries the number of channels of a pixbuf.
+ *
+ * Return value: Number of channels.
+ **/
+int
+gdk_pixbuf_get_n_channels (const GdkPixbuf *pixbuf)
+{
+       g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), -1);
+
+       return pixbuf->n_channels;
+}
+
+/**
+ * gdk_pixbuf_get_has_alpha:
+ * @pixbuf: A pixbuf.
+ *
+ * Queries whether a pixbuf has an alpha channel (opacity information).
+ *
+ * Return value: %TRUE if it has an alpha channel, %FALSE otherwise.
+ **/
+gboolean
+gdk_pixbuf_get_has_alpha (const GdkPixbuf *pixbuf)
+{
+       g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), FALSE);
+
+       return pixbuf->has_alpha ? TRUE : FALSE;
+}
+
+/**
+ * gdk_pixbuf_get_bits_per_sample:
+ * @pixbuf: A pixbuf.
+ *
+ * Queries the number of bits per color sample in a pixbuf.
+ *
+ * Return value: Number of bits per color sample.
+ **/
+int
+gdk_pixbuf_get_bits_per_sample (const GdkPixbuf *pixbuf)
+{
+       g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), -1);
+
+       return pixbuf->bits_per_sample;
+}
+
+/**
+ * gdk_pixbuf_get_pixels:
+ * @pixbuf: A pixbuf.
+ *
+ * Queries a pointer to the pixel data of a pixbuf.
+ *
+ * Return value: (array): A pointer to the pixbuf's pixel data.
+ * Please see <xref linkend="image-data"/> for information about how
+ * the pixel data is stored in memory.
+ **/
+guchar *
+gdk_pixbuf_get_pixels (const GdkPixbuf *pixbuf)
+{
+       g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
+
+       return pixbuf->pixels;
+}
+
+/**
+ * gdk_pixbuf_get_pixels_with_length:
+ * @pixbuf: A pixbuf.
+ * @length: (out): The length of the binary data.
+ *
+ * Queries a pointer to the pixel data of a pixbuf.
+ *
+ * Return value: (array length=length): A pointer to the pixbuf's
+ * pixel data.  Please see <xref linkend="image-data"/>
+ * for information about how the pixel data is stored in
+ * memory.
+ *
+ * Rename to: gdk_pixbuf_get_pixels
+ *
+ * Since: 2.26
+ */
+guchar *
+gdk_pixbuf_get_pixels_with_length (const GdkPixbuf *pixbuf,
+                                   guint           *length)
+{
+       g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
+
+        if (length)
+                *length = gdk_pixbuf_get_byte_length (pixbuf);
+
+       return pixbuf->pixels;
+}
+
+/**
+ * gdk_pixbuf_get_width:
+ * @pixbuf: A pixbuf.
+ *
+ * Queries the width of a pixbuf.
+ *
+ * Return value: Width in pixels.
+ **/
+int
+gdk_pixbuf_get_width (const GdkPixbuf *pixbuf)
+{
+       g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), -1);
+
+       return pixbuf->width;
+}
+
+/**
+ * gdk_pixbuf_get_height:
+ * @pixbuf: A pixbuf.
+ *
+ * Queries the height of a pixbuf.
+ *
+ * Return value: Height in pixels.
+ **/
+int
+gdk_pixbuf_get_height (const GdkPixbuf *pixbuf)
+{
+       g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), -1);
+
+       return pixbuf->height;
+}
+
+/**
+ * gdk_pixbuf_get_rowstride:
+ * @pixbuf: A pixbuf.
+ *
+ * Queries the rowstride of a pixbuf, which is the number of bytes between the start of a row
+ * and the start of the next row.
+ *
+ * Return value: Distance between row starts.
+ **/
+int
+gdk_pixbuf_get_rowstride (const GdkPixbuf *pixbuf)
+{
+       g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), -1);
+
+       return pixbuf->rowstride;
+}
+
+/**
+ * gdk_pixbuf_get_byte_length:
+ * @pixbuf: A pixbuf
+ *
+ * Returns the length of the pixel data, in bytes.
+ *
+ * Return value: The length of the pixel data.
+ *
+ * Since: 2.26
+ */
+gsize
+gdk_pixbuf_get_byte_length (const GdkPixbuf *pixbuf)
+{
+       g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), -1);
+
+        return ((pixbuf->height - 1) * pixbuf->rowstride +
+                pixbuf->width * ((pixbuf->n_channels * pixbuf->bits_per_sample + 7) / 8));
+}
+
+\f
+
+/* General initialization hooks */
+const guint gdk_pixbuf_major_version = GDK_PIXBUF_MAJOR;
+const guint gdk_pixbuf_minor_version = GDK_PIXBUF_MINOR;
+const guint gdk_pixbuf_micro_version = GDK_PIXBUF_MICRO;
+
+const char *gdk_pixbuf_version = GDK_PIXBUF_VERSION;
+
+/* Error quark */
+GQuark
+gdk_pixbuf_error_quark (void)
+{
+  return g_quark_from_static_string ("gdk-pixbuf-error-quark");
+}
+
+/**
+ * gdk_pixbuf_fill:
+ * @pixbuf: a #GdkPixbuf
+ * @pixel: RGBA pixel to clear to
+ *         (0xffffffff is opaque white, 0x00000000 transparent black)
+ *
+ * Clears a pixbuf to the given RGBA value, converting the RGBA value into
+ * the pixbuf's pixel format. The alpha will be ignored if the pixbuf
+ * doesn't have an alpha channel.
+ * 
+ **/
+void
+gdk_pixbuf_fill (GdkPixbuf *pixbuf,
+                 guint32    pixel)
+{
+        guchar *pixels;
+        guint r, g, b, a;
+        guchar *p;
+        guint w, h;
+
+        g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
+
+        if (pixbuf->width == 0 || pixbuf->height == 0)
+                return;
+
+        pixels = pixbuf->pixels;
+
+        r = (pixel & 0xff000000) >> 24;
+        g = (pixel & 0x00ff0000) >> 16;
+        b = (pixel & 0x0000ff00) >> 8;
+        a = (pixel & 0x000000ff);
+
+        h = pixbuf->height;
+        
+        while (h--) {
+                w = pixbuf->width;
+                p = pixels;
+
+                switch (pixbuf->n_channels) {
+                case 3:
+                        while (w--) {
+                                p[0] = r;
+                                p[1] = g;
+                                p[2] = b;
+                                p += 3;
+                        }
+                        break;
+                case 4:
+                        while (w--) {
+                                p[0] = r;
+                                p[1] = g;
+                                p[2] = b;
+                                p[3] = a;
+                                p += 4;
+                        }
+                        break;
+                default:
+                        break;
+                }
+                
+                pixels += pixbuf->rowstride;
+        }
+}
+
+\f
+
+/**
+ * gdk_pixbuf_get_option:
+ * @pixbuf: a #GdkPixbuf
+ * @key: a nul-terminated string.
+ * 
+ * Looks up @key in the list of options that may have been attached to the
+ * @pixbuf when it was loaded, or that may have been attached by another
+ * function using gdk_pixbuf_set_option().
+ *
+ * For instance, the ANI loader provides "Title" and "Artist" options. 
+ * The ICO, XBM, and XPM loaders provide "x_hot" and "y_hot" hot-spot 
+ * options for cursor definitions. The PNG loader provides the tEXt ancillary
+ * chunk key/value pairs as options. Since 2.12, the TIFF and JPEG loaders
+ * return an "orientation" option string that corresponds to the embedded 
+ * TIFF/Exif orientation tag (if present).
+ * 
+ * Return value: the value associated with @key. This is a nul-terminated 
+ * string that should not be freed or %NULL if @key was not found.
+ **/
+const gchar *
+gdk_pixbuf_get_option (GdkPixbuf   *pixbuf,
+                       const gchar *key)
+{
+        gchar **options;
+        gint i;
+
+        g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
+        g_return_val_if_fail (key != NULL, NULL);
+  
+        options = g_object_get_qdata (G_OBJECT (pixbuf), 
+                                      g_quark_from_static_string ("gdk_pixbuf_options"));
+        if (options) {
+                for (i = 0; options[2*i]; i++) {
+                        if (strcmp (options[2*i], key) == 0)
+                                return options[2*i+1];
+                }
+        }
+        
+        return NULL;
+}
+
+/**
+ * gdk_pixbuf_set_option:
+ * @pixbuf: a #GdkPixbuf
+ * @key: a nul-terminated string.
+ * @value: a nul-terminated string.
+ * 
+ * Attaches a key/value pair as an option to a #GdkPixbuf. If %key already
+ * exists in the list of options attached to @pixbuf, the new value is 
+ * ignored and %FALSE is returned.
+ *
+ * Return value: %TRUE on success.
+ *
+ * Since: 2.2
+ **/
+gboolean
+gdk_pixbuf_set_option (GdkPixbuf   *pixbuf,
+                       const gchar *key,
+                       const gchar *value)
+{
+        GQuark  quark;
+        gchar **options;
+        gint n = 0;
+        g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), FALSE);
+        g_return_val_if_fail (key != NULL, FALSE);
+        g_return_val_if_fail (value != NULL, FALSE);
+
+        quark = g_quark_from_static_string ("gdk_pixbuf_options");
+
+        options = g_object_get_qdata (G_OBJECT (pixbuf), quark);
+
+        if (options) {
+                for (n = 0; options[2*n]; n++) {
+                        if (strcmp (options[2*n], key) == 0)
+                                return FALSE;
+                }
+
+                g_object_steal_qdata (G_OBJECT (pixbuf), quark);
+                options = g_renew (gchar *, options, 2*(n+1) + 1);
+        } else {
+                options = g_new (gchar *, 3);
+        }
+        
+        options[2*n]   = g_strdup (key);
+        options[2*n+1] = g_strdup (value);
+        options[2*n+2] = NULL;
+
+        g_object_set_qdata_full (G_OBJECT (pixbuf), quark,
+                                 options, (GDestroyNotify) g_strfreev);
+        
+        return TRUE;
+}
+
+static void
+gdk_pixbuf_set_property (GObject         *object,
+                        guint            prop_id,
+                        const GValue    *value,
+                        GParamSpec      *pspec)
+{
+  GdkPixbuf *pixbuf = GDK_PIXBUF (object);
+
+  switch (prop_id)
+          {
+          case PROP_COLORSPACE:
+                  pixbuf->colorspace = g_value_get_enum (value);
+                  break;
+          case PROP_N_CHANNELS:
+                  pixbuf->n_channels = g_value_get_int (value);
+                  break;
+          case PROP_HAS_ALPHA:
+                  pixbuf->has_alpha = g_value_get_boolean (value);
+                  break;
+          case PROP_BITS_PER_SAMPLE:
+                  pixbuf->bits_per_sample = g_value_get_int (value);
+                  break;
+          case PROP_WIDTH:
+                  pixbuf->width = g_value_get_int (value);
+                  break;
+          case PROP_HEIGHT:
+                  pixbuf->height = g_value_get_int (value);
+                  break;
+          case PROP_ROWSTRIDE:
+                  pixbuf->rowstride = g_value_get_int (value);
+                  break;
+          case PROP_PIXELS:
+                  pixbuf->pixels = (guchar *) g_value_get_pointer (value);
+                  break;
+          default:
+                  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                  break;
+          }
+}
+
+static void
+gdk_pixbuf_get_property (GObject         *object,
+                        guint            prop_id,
+                        GValue          *value,
+                        GParamSpec      *pspec)
+{
+  GdkPixbuf *pixbuf = GDK_PIXBUF (object);
+  
+  switch (prop_id)
+          {
+          case PROP_COLORSPACE:
+                  g_value_set_enum (value, gdk_pixbuf_get_colorspace (pixbuf));
+                  break;
+          case PROP_N_CHANNELS:
+                  g_value_set_int (value, gdk_pixbuf_get_n_channels (pixbuf));
+                  break;
+          case PROP_HAS_ALPHA:
+                  g_value_set_boolean (value, gdk_pixbuf_get_has_alpha (pixbuf));
+                  break;
+          case PROP_BITS_PER_SAMPLE:
+                  g_value_set_int (value, gdk_pixbuf_get_bits_per_sample (pixbuf));
+                  break;
+          case PROP_WIDTH:
+                  g_value_set_int (value, gdk_pixbuf_get_width (pixbuf));
+                  break;
+          case PROP_HEIGHT:
+                  g_value_set_int (value, gdk_pixbuf_get_height (pixbuf));
+                  break;
+          case PROP_ROWSTRIDE:
+                  g_value_set_int (value, gdk_pixbuf_get_rowstride (pixbuf));
+                  break;
+          case PROP_PIXELS:
+                  g_value_set_pointer (value, gdk_pixbuf_get_pixels (pixbuf));
+                  break;
+          default:
+                  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                  break;
+          }
+}
diff --git a/gdk-pixbuf/gdk-pixbuf.h b/gdk-pixbuf/gdk-pixbuf.h
new file mode 100644 (file)
index 0000000..9a30131
--- /dev/null
@@ -0,0 +1,45 @@
+/* GdkPixbuf library - Main header file
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Authors: Mark Crichton <crichton@gimp.org>
+ *          Miguel de Icaza <miguel@gnu.org>
+ *          Federico Mena-Quintero <federico@gimp.org>
+ *          Havoc Pennington <hp@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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_H
+#define GDK_PIXBUF_H
+
+#define GDK_PIXBUF_H_INSIDE
+
+#include <glib.h>
+#include <gdk-pixbuf/gdk-pixbuf-features.h>
+#include <glib-object.h>
+
+#include <gdk-pixbuf/gdk-pixbuf-core.h>
+#include <gdk-pixbuf/gdk-pixbuf-transform.h>
+#include <gdk-pixbuf/gdk-pixbuf-animation.h>
+#include <gdk-pixbuf/gdk-pixbuf-simple-anim.h>
+#include <gdk-pixbuf/gdk-pixbuf-io.h>
+#include <gdk-pixbuf/gdk-pixbuf-loader.h>
+#include <gdk-pixbuf/gdk-pixbuf-enum-types.h>
+
+#undef GDK_PIXBUF_H_INSIDE
+
+#endif  /* GDK_PIXBUF_H */
diff --git a/gdk-pixbuf/gdk-pixbuf.symbols b/gdk-pixbuf/gdk-pixbuf.symbols
new file mode 100644 (file)
index 0000000..faddd47
--- /dev/null
@@ -0,0 +1,226 @@
+/* This file lists all exported symbols. It is used to generate
+ * the gdk_pixbuf.def file used to control exports on Windows
+ *
+ * Every symbol must be included in the right
+ * #ifdef IN_HEADER(sym) #endif and
+ * #ifdef IN_FILE(sym) #endif sections.
+ */
+#ifdef ALL_FILES
+#define IN_FILE(x) 1
+#define IN_HEADER(x) 1
+#endif
+#if IN_HEADER(GDK_PIXBUF_CORE_H)
+#if IN_FILE(__GDK_PIXBUF_C__)
+gdk_pixbuf_error_quark
+gdk_pixbuf_get_type G_GNUC_CONST
+#ifndef GDK_PIXBUF_DISABLE_DEPRECATED
+gdk_pixbuf_ref
+gdk_pixbuf_unref
+#endif
+gdk_pixbuf_new
+gdk_pixbuf_get_bits_per_sample
+gdk_pixbuf_get_colorspace
+gdk_pixbuf_get_has_alpha
+gdk_pixbuf_get_height
+gdk_pixbuf_get_n_channels
+gdk_pixbuf_get_pixels
+gdk_pixbuf_get_pixels_with_length
+gdk_pixbuf_get_byte_length
+gdk_pixbuf_get_rowstride
+gdk_pixbuf_get_width
+gdk_pixbuf_get_option
+gdk_pixbuf_copy
+gdk_pixbuf_new_subpixbuf
+gdk_pixbuf_fill
+#endif
+#endif
+
+#if IN_HEADER(GDK_PIXBUF_CORE_H)
+#if IN_FILE(__GDK_PIXBUF_DATA_C__)
+gdk_pixbuf_new_from_data
+#endif
+#endif
+
+#if IN_HEADER(GDK_PIXBUF_CORE_H)
+#if IN_FILE(__GDK_PIXBUF_IO_C__)
+gdk_pixbuf_new_from_file PRIVATE
+#ifdef G_OS_WIN32
+gdk_pixbuf_new_from_file_utf8
+#endif
+gdk_pixbuf_new_from_file_at_size PRIVATE
+#ifdef G_OS_WIN32
+gdk_pixbuf_new_from_file_at_size_utf8
+#endif
+gdk_pixbuf_new_from_file_at_scale PRIVATE
+#ifdef G_OS_WIN32
+gdk_pixbuf_new_from_file_at_scale_utf8
+#endif
+gdk_pixbuf_new_from_xpm_data
+gdk_pixbuf_new_from_resource
+gdk_pixbuf_new_from_resource_at_scale
+gdk_pixbuf_new_from_stream
+gdk_pixbuf_new_from_stream_async
+gdk_pixbuf_new_from_stream_finish
+gdk_pixbuf_new_from_stream_at_scale
+gdk_pixbuf_new_from_stream_at_scale_async
+gdk_pixbuf_save PRIVATE G_GNUC_NULL_TERMINATED
+#ifdef G_OS_WIN32
+gdk_pixbuf_save_utf8
+#endif
+gdk_pixbuf_save_to_buffer G_GNUC_NULL_TERMINATED
+gdk_pixbuf_save_to_bufferv
+gdk_pixbuf_save_to_callback G_GNUC_NULL_TERMINATED
+gdk_pixbuf_save_to_callbackv
+gdk_pixbuf_savev PRIVATE
+#ifdef G_OS_WIN32
+gdk_pixbuf_savev_utf8
+#endif
+gdk_pixbuf_save_to_stream
+gdk_pixbuf_save_to_stream_async
+gdk_pixbuf_save_to_stream_finish
+#endif
+#endif
+
+#if IN_HEADER(GDK_PIXBUF_CORE_H)
+#if IN_FILE(__GDK_PIXDATA_C__)
+gdk_pixbuf_new_from_inline
+#endif
+#endif
+
+#if IN_HEADER(GDK_PIXBUF_CORE_H)
+#if IN_FILE(__GDK_PIXBUF_UTIL_C__)
+gdk_pixbuf_add_alpha
+gdk_pixbuf_copy_area
+gdk_pixbuf_saturate_and_pixelate
+gdk_pixbuf_apply_embedded_orientation
+#endif
+#endif
+
+#if IN_HEADER(__GDKPIXBUFINTL_H__)
+#if IN_FILE(__GDK_PIXBUF_UTIL_C__)
+gdk_pixbuf_gettext
+#endif
+#endif
+
+#if IN_HEADER(GDK_PIXBUF_TRANSFORM_H)
+#if IN_FILE(__GDK_PIXBUF_SCALE_C__)
+gdk_pixbuf_rotate_simple
+gdk_pixbuf_scale
+gdk_pixbuf_scale_simple
+gdk_pixbuf_flip
+gdk_pixbuf_composite
+gdk_pixbuf_composite_color
+gdk_pixbuf_composite_color_simple
+#endif
+#endif
+
+#if IN_HEADER(GDK_PIXBUF_ANIMATION_H)
+#if IN_FILE(__GDK_PIXBUF_ANIMATION_C__)
+gdk_pixbuf_animation_get_height
+gdk_pixbuf_animation_get_iter
+gdk_pixbuf_animation_get_static_image
+gdk_pixbuf_animation_get_type G_GNUC_CONST
+gdk_pixbuf_animation_get_width
+gdk_pixbuf_animation_is_static_image
+gdk_pixbuf_animation_iter_advance
+gdk_pixbuf_animation_iter_get_delay_time
+gdk_pixbuf_animation_iter_get_pixbuf
+gdk_pixbuf_animation_iter_get_type G_GNUC_CONST
+gdk_pixbuf_animation_iter_on_currently_loading_frame
+gdk_pixbuf_animation_new_from_file PRIVATE
+#ifdef G_OS_WIN32
+gdk_pixbuf_animation_new_from_file_utf8
+#endif
+#ifndef GDK_PIXBUF_DISABLE_DEPRECATED
+gdk_pixbuf_animation_ref
+gdk_pixbuf_animation_unref
+#endif
+gdk_pixbuf_non_anim_new
+gdk_pixbuf_non_anim_get_type G_GNUC_CONST
+#endif
+#endif
+
+#if IN_HEADER(GDK_PIXBUF_SIMPLE_ANIM_H)
+#if IN_FILE(__GDK_PIXBUF_SIMPLE_ANIM_C__)
+gdk_pixbuf_simple_anim_get_type G_GNUC_CONST
+gdk_pixbuf_simple_anim_iter_get_type G_GNUC_CONST
+gdk_pixbuf_simple_anim_new
+gdk_pixbuf_simple_anim_add_frame
+gdk_pixbuf_simple_anim_set_loop
+gdk_pixbuf_simple_anim_get_loop
+#endif
+#endif
+
+#if IN_HEADER(GDK_PIXBUF_SCALED_ANIM_H)
+#if IN_FILE(__GDK_PIXBUF_SCALED_ANIM_C__)
+gdk_pixbuf_scaled_anim_get_type G_GNUC_CONST
+gdk_pixbuf_scaled_anim_iter_get_type G_GNUC_CONST
+#endif
+#endif
+
+#if IN_HEADER(GDK_PIXBUF_IO_H)
+#if IN_FILE(__GDK_PIXBUF_IO_C__)
+gdk_pixbuf_get_formats
+gdk_pixbuf_format_get_type G_GNUC_CONST;
+gdk_pixbuf_format_copy
+gdk_pixbuf_format_free
+gdk_pixbuf_format_get_description
+gdk_pixbuf_format_get_extensions
+gdk_pixbuf_format_get_license
+gdk_pixbuf_format_get_mime_types
+gdk_pixbuf_format_get_name
+gdk_pixbuf_format_is_disabled
+gdk_pixbuf_format_is_scalable
+gdk_pixbuf_format_is_writable
+gdk_pixbuf_format_set_disabled
+gdk_pixbuf_get_file_info
+#endif
+#endif
+
+#if IN_HEADER(GDK_PIXBUF_IO_H)
+#if IN_FILE(__GDK_PIXBUF_C__)
+gdk_pixbuf_set_option
+#endif
+#endif
+
+#if IN_HEADER(GDK_PIXBUF_LOADER_H)
+#if IN_FILE(__GDK_PIXBUF_LOADER_C__)
+gdk_pixbuf_loader_close
+gdk_pixbuf_loader_get_animation
+gdk_pixbuf_loader_get_format
+gdk_pixbuf_loader_get_pixbuf
+gdk_pixbuf_loader_get_type G_GNUC_CONST
+gdk_pixbuf_loader_new
+gdk_pixbuf_loader_new_with_mime_type
+gdk_pixbuf_loader_new_with_type
+gdk_pixbuf_loader_set_size
+gdk_pixbuf_loader_write
+#endif
+#endif
+
+#if IN_HEADER(__GDK_PIXBUF_ENUM_TYPES_H__)
+#if IN_FILE(__GDK_PIXBUF_ENUM_TYPES_C__)
+gdk_colorspace_get_type G_GNUC_CONST
+gdk_interp_type_get_type G_GNUC_CONST
+gdk_pixbuf_alpha_mode_get_type G_GNUC_CONST
+gdk_pixbuf_rotation_get_type G_GNUC_CONST
+gdk_pixbuf_error_get_type
+#endif
+#endif
+
+#if IN_HEADER(__GDK_PIXDATA_H__)
+#if IN_FILE(__GDK_PIXDATA_C__)
+gdk_pixbuf_from_pixdata
+gdk_pixdata_deserialize
+gdk_pixdata_from_pixbuf
+gdk_pixdata_serialize
+gdk_pixdata_to_csource
+#endif
+#endif
+
+#ifdef INCLUDE_VARIABLES
+gdk_pixbuf_major_version
+gdk_pixbuf_micro_version
+gdk_pixbuf_minor_version
+gdk_pixbuf_version
+#endif
diff --git a/gdk-pixbuf/gdk-pixdata.c b/gdk-pixbuf/gdk-pixdata.c
new file mode 100644 (file)
index 0000000..8680229
--- /dev/null
@@ -0,0 +1,915 @@
+/* GdkPixbuf library - GdkPixdata - functions for inlined pixbuf handling
+ * Copyright (C) 1999, 2001 Tim Janik
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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 "gdk-pixbuf-private.h"
+#include "gdk-pixdata.h"
+#include <string.h>
+
+/**
+ * SECTION:inline
+ * @Short_description: Functions for inlined pixbuf handling.
+ * @Title: Inline data
+ * 
+ * Using #GdkPixdata, images can be compiled into an application,
+ * making it unnecessary to refer to external image files at runtime.
+ * &gdk-pixbuf; includes a utility named gdk-pixbuf-csource, which 
+ * can be used to convert image files into #GdkPixdata structures suitable
+ * for inclusion in C sources. To convert the #GdkPixdata structures back 
+ * into #GdkPixbuf<!-- -->s, use gdk_pixbuf_from_pixdata.
+ */
+
+#define APPEND g_string_append_printf
+
+/* --- functions --- */
+static guint
+pixdata_get_length (const GdkPixdata *pixdata)
+{
+  guint bpp, length;
+
+  if ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB)
+    bpp = 3;
+  else if ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA)
+    bpp = 4;
+  else
+    return 0;  /* invalid format */
+  switch (pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK)
+    {
+      guint8 *rle_buffer;
+      guint max_length;
+    case GDK_PIXDATA_ENCODING_RAW:
+      length = pixdata->rowstride * pixdata->height;
+      break;
+    case GDK_PIXDATA_ENCODING_RLE:
+      /* need an RLE walk to determine size */
+      max_length = pixdata->rowstride * pixdata->height;
+      rle_buffer = pixdata->pixel_data;
+      length = 0;
+      while (length < max_length)
+       {
+         guint chunk_length = *(rle_buffer++);
+
+         if (chunk_length & 128)
+           {
+             chunk_length = chunk_length - 128;
+             if (!chunk_length)        /* RLE data corrupted */
+               return 0;
+             length += chunk_length * bpp;
+             rle_buffer += bpp;
+           }
+         else
+           {
+             if (!chunk_length)        /* RLE data corrupted */
+               return 0;
+             chunk_length *= bpp;
+             length += chunk_length;
+             rle_buffer += chunk_length;
+           }
+       }
+      length = rle_buffer - pixdata->pixel_data;
+      break;
+    default:
+      length = 0;
+      break;
+    }
+  return length;
+}
+
+/**
+ * gdk_pixdata_serialize:
+ * @pixdata: a valid #GdkPixdata structure to serialize.
+ * @stream_length_p: location to store the resulting stream length in.
+ *
+ * Serializes a #GdkPixdata structure into a byte stream.
+ * The byte stream consists of a straightforward writeout of the
+ * #GdkPixdata fields in network byte order, plus the @pixel_data
+ * bytes the structure points to.
+ *
+ * Return value: (array length=stream_length_p) (transfer full): A
+ * newly-allocated string containing the serialized #GdkPixdata
+ * structure.
+ **/
+guint8* /* free result */
+gdk_pixdata_serialize (const GdkPixdata *pixdata,
+                      guint            *stream_length_p)
+{
+  guint8 *stream, *s;
+  guint32 *istream;
+  guint length;
+
+  /* check args passing */
+  g_return_val_if_fail (pixdata != NULL, NULL);
+  g_return_val_if_fail (stream_length_p != NULL, NULL);
+  /* check pixdata contents */
+  g_return_val_if_fail (pixdata->magic == GDK_PIXBUF_MAGIC_NUMBER, NULL);
+  g_return_val_if_fail (pixdata->width > 0, NULL);
+  g_return_val_if_fail (pixdata->height > 0, NULL);
+  g_return_val_if_fail (pixdata->rowstride >= pixdata->width, NULL);
+  g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ||
+                       (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA, NULL);
+  g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_SAMPLE_WIDTH_MASK) == GDK_PIXDATA_SAMPLE_WIDTH_8, NULL);
+  g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RAW ||
+                       (pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RLE, NULL);
+  g_return_val_if_fail (pixdata->pixel_data != NULL, NULL);
+
+  length = pixdata_get_length (pixdata);
+
+  /* check length field */
+  g_return_val_if_fail (length != 0, NULL);
+  
+  stream = g_malloc (GDK_PIXDATA_HEADER_LENGTH + length);
+  istream = (guint32*) stream;
+
+  /* store header */
+  *istream++ = g_htonl (GDK_PIXBUF_MAGIC_NUMBER);
+  *istream++ = g_htonl (GDK_PIXDATA_HEADER_LENGTH + length);
+  *istream++ = g_htonl (pixdata->pixdata_type);
+  *istream++ = g_htonl (pixdata->rowstride);
+  *istream++ = g_htonl (pixdata->width);
+  *istream++ = g_htonl (pixdata->height);
+
+  /* copy pixel data */
+  s = (guint8*) istream;
+  memcpy (s, pixdata->pixel_data, length);
+  s += length;
+
+  *stream_length_p = GDK_PIXDATA_HEADER_LENGTH + length;
+  g_assert (s - stream == *stream_length_p);   /* paranoid */
+
+  return stream;
+}
+
+#define        return_header_corrupt(error)    { \
+  g_set_error_literal (error, GDK_PIXBUF_ERROR, \
+                       GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Image header corrupt")); \
+  return FALSE; \
+}
+#define        return_invalid_format(error)    { \
+  g_set_error_literal (error, GDK_PIXBUF_ERROR, \
+                       GDK_PIXBUF_ERROR_UNKNOWN_TYPE, _("Image format unknown")); \
+  return FALSE; \
+}
+#define        return_pixel_corrupt(error)     { \
+  g_set_error_literal (error, GDK_PIXBUF_ERROR, \
+                       GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Image pixel data corrupt")); \
+  return FALSE; \
+}
+
+static inline const guint8 *
+get_uint32 (const guint8 *stream, guint *result)
+{
+  *result = (stream[0] << 24) + (stream[1] << 16) + (stream[2] << 8) + stream[3];
+  return stream + 4;
+}
+
+/**
+ * gdk_pixdata_deserialize:
+ * @pixdata: a #GdkPixdata structure to be filled in.
+ * @stream_length: length of the stream used for deserialization.
+ * @stream: (array length=stream_length): stream of bytes containing a
+ *   serialized #GdkPixdata structure.
+ * @error: #GError location to indicate failures (maybe %NULL to ignore errors).
+ *
+ * Deserializes (reconstruct) a #GdkPixdata structure from a byte stream.
+ * The byte stream consists of a straightforward writeout of the
+ * #GdkPixdata fields in network byte order, plus the @pixel_data
+ * bytes the structure points to.
+ * The @pixdata contents are reconstructed byte by byte and are checked
+ * for validity. This function may fail with %GDK_PIXBUF_CORRUPT_IMAGE
+ * or %GDK_PIXBUF_ERROR_UNKNOWN_TYPE.
+ *
+ * Return value: Upon successful deserialization %TRUE is returned,
+ * %FALSE otherwise.
+ **/
+gboolean
+gdk_pixdata_deserialize (GdkPixdata   *pixdata,
+                        guint         stream_length,
+                        const guint8 *stream,
+                        GError      **error)
+{
+  guint color_type, sample_width, encoding;
+
+  g_return_val_if_fail (pixdata != NULL, FALSE);
+  if (stream_length < GDK_PIXDATA_HEADER_LENGTH)
+    return_header_corrupt (error);
+  g_return_val_if_fail (stream != NULL, FALSE);
+
+
+  /* deserialize header */
+  stream = get_uint32 (stream, &pixdata->magic);
+  stream = get_uint32 (stream, (guint32 *)&pixdata->length);
+  if (pixdata->magic != GDK_PIXBUF_MAGIC_NUMBER || pixdata->length < GDK_PIXDATA_HEADER_LENGTH)
+    return_header_corrupt (error);
+  stream = get_uint32 (stream, &pixdata->pixdata_type);
+  stream = get_uint32 (stream, &pixdata->rowstride);
+  stream = get_uint32 (stream, &pixdata->width);
+  stream = get_uint32 (stream, &pixdata->height);
+  if (pixdata->width < 1 || pixdata->height < 1 ||
+      pixdata->rowstride < pixdata->width)
+    return_header_corrupt (error);
+  color_type = pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK;
+  sample_width = pixdata->pixdata_type & GDK_PIXDATA_SAMPLE_WIDTH_MASK;
+  encoding = pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK;
+  if ((color_type != GDK_PIXDATA_COLOR_TYPE_RGB &&
+       color_type != GDK_PIXDATA_COLOR_TYPE_RGBA) ||
+      sample_width != GDK_PIXDATA_SAMPLE_WIDTH_8 ||
+      (encoding != GDK_PIXDATA_ENCODING_RAW &&
+       encoding != GDK_PIXDATA_ENCODING_RLE))
+    return_invalid_format (error);
+
+  /* deserialize pixel data */
+  if (stream_length < pixdata->length - GDK_PIXDATA_HEADER_LENGTH)
+    return_pixel_corrupt (error);
+  pixdata->pixel_data = (guint8 *)stream;
+
+  return TRUE;
+}
+
+static gboolean
+diff2_rgb (guint8 *ip)
+{
+  return ip[0] != ip[3] || ip[1] != ip[4] || ip[2] != ip[5];
+}
+
+static gboolean
+diff2_rgba (guint8 *ip)
+{
+  return ip[0] != ip[4] || ip[1] != ip[5] || ip[2] != ip[6] || ip[3] != ip[7];
+}
+
+static guint8*                 /* dest buffer bound */
+rl_encode_rgbx (guint8 *bp,    /* dest buffer */
+               guint8 *ip,     /* image pointer */
+               guint8 *limit,  /* image upper bound */
+               guint   n_ch)
+{
+  gboolean (*diff2_pix) (guint8 *) = n_ch > 3 ? diff2_rgba : diff2_rgb;
+  guint8 *ilimit = limit - n_ch;
+
+  while (ip < limit)
+    {
+      g_assert (ip < ilimit); /* paranoid */
+
+      if (diff2_pix (ip))
+       {
+         guint8 *s_ip = ip;
+         guint l = 1;
+
+         ip += n_ch;
+         while (l < 127 && ip < ilimit && diff2_pix (ip))
+           { ip += n_ch; l += 1; }
+         if (ip == ilimit && l < 127)
+           { ip += n_ch; l += 1; }
+         *(bp++) = l;
+         memcpy (bp, s_ip, l * n_ch);
+         bp += l * n_ch;
+       }
+      else
+       {
+         guint l = 2;
+
+         ip += n_ch;
+         while (l < 127 && ip < ilimit && !diff2_pix (ip))
+           { ip += n_ch; l += 1; }
+         *(bp++) = l | 128;
+         memcpy (bp, ip, n_ch);
+         ip += n_ch;
+         bp += n_ch;
+       }
+      if (ip == ilimit)
+       {
+         *(bp++) = 1;
+         memcpy (bp, ip, n_ch);
+         ip += n_ch;
+         bp += n_ch;
+       }
+    }
+
+  return bp;
+}
+
+/* Used as the destroy notification function for gdk_pixbuf_new() */
+static void
+free_buffer (guchar *pixels, gpointer data)
+{
+       g_free (pixels);
+}
+
+/**
+ * gdk_pixdata_from_pixbuf: (skip)
+ * @pixdata: a #GdkPixdata to fill.
+ * @pixbuf: the data to fill @pixdata with.
+ * @use_rle: whether to use run-length encoding for the pixel data.
+ *
+ * Converts a #GdkPixbuf to a #GdkPixdata. If @use_rle is %TRUE, the
+ * pixel data is run-length encoded into newly-allocated memory and a 
+ * pointer to that memory is returned. 
+ *
+ * Returns: If @ure_rle is %TRUE, a pointer to the newly-allocated memory 
+ *   for the run-length encoded pixel data, otherwise %NULL.
+ **/
+gpointer
+gdk_pixdata_from_pixbuf (GdkPixdata      *pixdata,
+                        const GdkPixbuf *pixbuf,
+                        gboolean         use_rle)
+{
+  gpointer free_me = NULL;
+  guint height, rowstride, encoding, bpp, length;
+  guint8 *img_buffer;
+
+  g_return_val_if_fail (pixdata != NULL, NULL);
+  g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
+  g_return_val_if_fail (pixbuf->bits_per_sample == 8, NULL);
+  g_return_val_if_fail ((pixbuf->n_channels == 3 && !pixbuf->has_alpha) ||
+                       (pixbuf->n_channels == 4 && pixbuf->has_alpha), NULL);
+  g_return_val_if_fail (pixbuf->rowstride >= pixbuf->width, NULL);
+
+  height = pixbuf->height;
+  rowstride = pixbuf->rowstride;
+  bpp = pixbuf->has_alpha ? 4 : 3;
+  encoding = use_rle && ((rowstride / bpp | height) > 1) ? GDK_PIXDATA_ENCODING_RLE : GDK_PIXDATA_ENCODING_RAW;
+
+  if (encoding == GDK_PIXDATA_ENCODING_RLE)
+    {
+      guint pad, n_bytes = rowstride * height;
+      guint8 *img_buffer_end, *data;
+      GdkPixbuf *buf = NULL;
+
+      if (n_bytes % bpp != 0) 
+       {
+         rowstride = pixbuf->width * bpp;
+         n_bytes = rowstride * height;
+         data = g_malloc (n_bytes);
+         buf = gdk_pixbuf_new_from_data (data,
+                                         GDK_COLORSPACE_RGB,
+                                         pixbuf->has_alpha, 8,
+                                         pixbuf->width,
+                                         pixbuf->height,
+                                         rowstride,
+                                         free_buffer, NULL);
+         gdk_pixbuf_copy_area (pixbuf, 0, 0, pixbuf->width, pixbuf->height,
+                               buf, 0, 0);
+       }
+      else
+       buf = (GdkPixbuf *)pixbuf;
+      pad = rowstride;
+      pad = MAX (pad, 130 + n_bytes / 127);
+      data = g_new (guint8, pad + n_bytes);
+      free_me = data;
+      img_buffer = data;
+      img_buffer_end = rl_encode_rgbx (img_buffer,
+                                      buf->pixels, buf->pixels + n_bytes,
+                                      bpp);
+      length = img_buffer_end - img_buffer;
+      if (buf != pixbuf)
+       g_object_unref (buf);
+    }
+  else
+    {
+      img_buffer = pixbuf->pixels;
+      length = rowstride * height;
+    }
+
+  pixdata->magic = GDK_PIXBUF_MAGIC_NUMBER;
+  pixdata->length = GDK_PIXDATA_HEADER_LENGTH + length;
+  pixdata->pixdata_type = pixbuf->has_alpha ? GDK_PIXDATA_COLOR_TYPE_RGBA : GDK_PIXDATA_COLOR_TYPE_RGB;
+  pixdata->pixdata_type |= GDK_PIXDATA_SAMPLE_WIDTH_8;
+  pixdata->pixdata_type |= encoding;
+  pixdata->rowstride = rowstride;
+  pixdata->width = pixbuf->width;
+  pixdata->height = height;
+  pixdata->pixel_data = img_buffer;
+
+  return free_me;
+}
+
+/**
+ * gdk_pixbuf_from_pixdata:
+ * @pixdata: a #GdkPixdata to convert into a #GdkPixbuf.
+ * @copy_pixels: whether to copy raw pixel data; run-length encoded
+ *     pixel data is always copied.
+ * @error: location to store possible errors.
+ * 
+ * Converts a #GdkPixdata to a #GdkPixbuf. If @copy_pixels is %TRUE or
+ * if the pixel data is run-length-encoded, the pixel data is copied into
+ * newly-allocated memory; otherwise it is reused.
+ *
+ * Returns: (transfer full): a new #GdkPixbuf.
+ **/
+GdkPixbuf*
+gdk_pixbuf_from_pixdata (const GdkPixdata *pixdata,
+                        gboolean          copy_pixels,
+                        GError          **error)
+{
+  guint encoding, bpp;
+  guint8 *data = NULL;
+
+  g_return_val_if_fail (pixdata != NULL, NULL);
+  g_return_val_if_fail (pixdata->width > 0, NULL);
+  g_return_val_if_fail (pixdata->height > 0, NULL);
+  g_return_val_if_fail (pixdata->rowstride >= pixdata->width, NULL);
+  g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ||
+                       (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA, NULL);
+  g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_SAMPLE_WIDTH_MASK) == GDK_PIXDATA_SAMPLE_WIDTH_8, NULL);
+  g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RAW ||
+                       (pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RLE, NULL);
+  g_return_val_if_fail (pixdata->pixel_data != NULL, NULL);
+
+  bpp = (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ? 3 : 4;
+  encoding = pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK;
+  if (encoding == GDK_PIXDATA_ENCODING_RLE)
+    copy_pixels = TRUE;
+  if (copy_pixels)
+    {
+      data = g_try_malloc (pixdata->rowstride * pixdata->height);
+      if (!data)
+       {
+         g_set_error (error, GDK_PIXBUF_ERROR,
+                      GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                      g_dngettext(GETTEXT_PACKAGE,
+                                  "failed to allocate image buffer of %u byte",
+                                  "failed to allocate image buffer of %u bytes",
+                                  pixdata->rowstride * pixdata->height),
+                      pixdata->rowstride * pixdata->height);
+         return NULL;
+       }
+    }
+  if (encoding == GDK_PIXDATA_ENCODING_RLE)
+    {
+      const guint8 *rle_buffer = pixdata->pixel_data;
+      guint8 *image_buffer = data;
+      guint8 *image_limit = data + pixdata->rowstride * pixdata->height;
+      gboolean check_overrun = FALSE;
+
+      while (image_buffer < image_limit)
+       {
+         guint length = *(rle_buffer++);
+
+         if (length & 128)
+           {
+             length = length - 128;
+             check_overrun = image_buffer + length * bpp > image_limit;
+             if (check_overrun)
+               length = (image_limit - image_buffer) / bpp;
+             if (bpp < 4)      /* RGB */
+               do
+                 {
+                   memcpy (image_buffer, rle_buffer, 3);
+                   image_buffer += 3;
+                 }
+               while (--length);
+             else              /* RGBA */
+               do
+                 {
+                   memcpy (image_buffer, rle_buffer, 4);
+                   image_buffer += 4;
+                 }
+               while (--length);
+             rle_buffer += bpp;
+           }
+         else
+           {
+             length *= bpp;
+             check_overrun = image_buffer + length > image_limit;
+             if (check_overrun)
+               length = image_limit - image_buffer;
+             memcpy (image_buffer, rle_buffer, length);
+             image_buffer += length;
+             rle_buffer += length;
+           }
+       }
+      if (check_overrun)
+       {
+         g_free (data);
+         g_set_error_literal (error, GDK_PIXBUF_ERROR,
+                               GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                               _("Image pixel data corrupt"));
+         return NULL;
+       }
+    }
+  else if (copy_pixels)
+    memcpy (data, pixdata->pixel_data, pixdata->rowstride * pixdata->height);
+  else
+    data = pixdata->pixel_data;
+
+  return gdk_pixbuf_new_from_data (data, GDK_COLORSPACE_RGB,
+                                  (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA,
+                                  8, pixdata->width, pixdata->height, pixdata->rowstride,
+                                  copy_pixels ? (GdkPixbufDestroyNotify) g_free : NULL, data);
+}
+
+typedef struct {
+  /* config */
+  gboolean     dump_stream;
+  gboolean     dump_struct;
+  gboolean     dump_macros;
+  gboolean     dump_gtypes;
+  gboolean     dump_rle_decoder;
+  const gchar *static_prefix;
+  const gchar *const_prefix;
+  /* runtime */
+  GString *gstring;
+  guint    pos;
+  gboolean pad;
+} CSourceData;
+
+static inline void
+save_uchar (CSourceData *cdata,
+           guint8       d)
+{
+  GString *gstring = cdata->gstring;
+
+  if (cdata->pos > 70)
+    {
+      if (cdata->dump_struct || cdata->dump_stream)
+       {
+         g_string_append (gstring, "\"\n  \"");
+         cdata->pos = 3;
+         cdata->pad = FALSE;
+       }
+      if (cdata->dump_macros)
+       {
+         g_string_append (gstring, "\" \\\n  \"");
+         cdata->pos = 3;
+         cdata->pad = FALSE;
+       }
+    }
+  if (d < 33 || d > 126 || d == '?')
+    {
+      APPEND (gstring, "\\%o", d);
+      cdata->pos += 1 + 1 + (d > 7) + (d > 63);
+      cdata->pad = d < 64;
+      return;
+    }
+  if (d == '\\')
+    {
+      g_string_append (gstring, "\\\\");
+      cdata->pos += 2;
+    }
+  else if (d == '"')
+    {
+      g_string_append (gstring, "\\\"");
+      cdata->pos += 2;
+    }
+  else if (cdata->pad && d >= '0' && d <= '9')
+    {
+      g_string_append (gstring, "\"\"");
+      g_string_append_c (gstring, d);
+      cdata->pos += 3;
+    }
+  else
+    {
+      g_string_append_c (gstring, d);
+      cdata->pos += 1;
+    }
+  cdata->pad = FALSE;
+  return;
+}
+
+static inline void
+save_rle_decoder (GString     *gstring,
+                 const gchar *macro_name,
+                 const gchar *s_uint,
+                 const gchar *s_uint_8,
+                 guint        n_ch)
+{
+  APPEND (gstring, "#define %s_RUN_LENGTH_DECODE(image_buf, rle_data, size, bpp) do \\\n",
+         macro_name);
+  APPEND (gstring, "{ %s __bpp; %s *__ip; const %s *__il, *__rd; \\\n", s_uint, s_uint_8, s_uint_8);
+  APPEND (gstring, "  __bpp = (bpp); __ip = (image_buf); __il = __ip + (size) * __bpp; \\\n");
+  
+  APPEND (gstring, "  __rd = (rle_data); if (__bpp > 3) { /* RGBA */ \\\n");
+  
+  APPEND (gstring, "    while (__ip < __il) { %s __l = *(__rd++); \\\n", s_uint);
+  APPEND (gstring, "      if (__l & 128) { __l = __l - 128; \\\n");
+  APPEND (gstring, "        do { memcpy (__ip, __rd, 4); __ip += 4; } while (--__l); __rd += 4; \\\n");
+  APPEND (gstring, "      } else { __l *= 4; memcpy (__ip, __rd, __l); \\\n");
+  APPEND (gstring, "               __ip += __l; __rd += __l; } } \\\n");
+  
+  APPEND (gstring, "  } else { /* RGB */ \\\n");
+  
+  APPEND (gstring, "    while (__ip < __il) { %s __l = *(__rd++); \\\n", s_uint);
+  APPEND (gstring, "      if (__l & 128) { __l = __l - 128; \\\n");
+  APPEND (gstring, "        do { memcpy (__ip, __rd, 3); __ip += 3; } while (--__l); __rd += 3; \\\n");
+  APPEND (gstring, "      } else { __l *= 3; memcpy (__ip, __rd, __l); \\\n");
+  APPEND (gstring, "               __ip += __l; __rd += __l; } } \\\n");
+  
+  APPEND (gstring, "  } } while (0)\n");
+}
+
+/**
+ * gdk_pixdata_to_csource:
+ * @pixdata: a #GdkPixdata to convert to C source.
+ * @name: used for naming generated data structures or macros.
+ * @dump_type: a #GdkPixdataDumpType determining the kind of C
+ *   source to be generated.
+ *
+ * Generates C source code suitable for compiling images directly 
+ * into programs. 
+ *
+ * gdk-pixbuf ships with a program called <command>gdk-pixbuf-csource</command> 
+ * which offers a command line interface to this function.
+ *
+ * Returns: a newly-allocated string containing the C source form
+ *   of @pixdata.
+ **/
+GString*
+gdk_pixdata_to_csource (GdkPixdata        *pixdata,
+                       const gchar       *name,
+                       GdkPixdataDumpType dump_type)
+{
+  CSourceData cdata = { 0, };
+  gchar *s_uint_8;
+  guint bpp, width, height, rowstride;
+  gboolean rle_encoded;
+  gchar *macro_name;
+  guint8 *img_buffer, *img_buffer_end, *stream = NULL;
+  guint stream_length;
+  GString *gstring;
+  
+  /* check args passing */
+  g_return_val_if_fail (pixdata != NULL, NULL);
+  g_return_val_if_fail (name != NULL, NULL);
+  /* check pixdata contents */
+  g_return_val_if_fail (pixdata->magic == GDK_PIXBUF_MAGIC_NUMBER, NULL);
+  g_return_val_if_fail (pixdata->width > 0, NULL);
+  g_return_val_if_fail (pixdata->height > 0, NULL);
+  g_return_val_if_fail (pixdata->rowstride >= pixdata->width, NULL);
+  g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ||
+                       (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA, NULL);
+  g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_SAMPLE_WIDTH_MASK) == GDK_PIXDATA_SAMPLE_WIDTH_8, NULL);
+  g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RAW ||
+                       (pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RLE, NULL);
+  g_return_val_if_fail (pixdata->pixel_data != NULL, NULL);
+
+  img_buffer = pixdata->pixel_data;
+  if (pixdata->length < 1)
+    img_buffer_end = img_buffer + pixdata_get_length (pixdata);
+  else
+    img_buffer_end = img_buffer + pixdata->length - GDK_PIXDATA_HEADER_LENGTH;
+  g_return_val_if_fail (img_buffer < img_buffer_end, NULL);
+
+  bpp = (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ? 3 : 4;
+  width = pixdata->width;
+  height = pixdata->height;
+  rowstride = pixdata->rowstride;
+  rle_encoded = (pixdata->pixdata_type & GDK_PIXDATA_ENCODING_RLE) > 0;
+  macro_name = g_ascii_strup (name, -1);
+
+  cdata.dump_macros = (dump_type & GDK_PIXDATA_DUMP_MACROS) > 0;
+  cdata.dump_struct = (dump_type & GDK_PIXDATA_DUMP_PIXDATA_STRUCT) > 0;
+  cdata.dump_stream = !cdata.dump_macros && !cdata.dump_struct;
+  g_return_val_if_fail (cdata.dump_macros + cdata.dump_struct + cdata.dump_stream == 1, NULL);
+
+  cdata.dump_gtypes = (dump_type & GDK_PIXDATA_DUMP_CTYPES) == 0;
+  cdata.dump_rle_decoder = (dump_type & GDK_PIXDATA_DUMP_RLE_DECODER) > 0;
+  cdata.static_prefix = (dump_type & GDK_PIXDATA_DUMP_STATIC) ? "static " : "";
+  cdata.const_prefix = (dump_type & GDK_PIXDATA_DUMP_CONST) ? "const " : "";
+  gstring = g_string_new (NULL);
+  cdata.gstring = gstring;
+
+  if (!cdata.dump_macros && cdata.dump_gtypes)
+    s_uint_8 =  "guint8 ";
+  else if (!cdata.dump_macros)
+    s_uint_8 =  "unsigned char";
+  else if (cdata.dump_macros && cdata.dump_gtypes)
+    s_uint_8 =  "guint8";
+  else /* cdata.dump_macros && !cdata.dump_gtypes */
+    s_uint_8 =  "unsigned char";
+
+  /* initial comment
+   */
+  APPEND (gstring,
+         "/* GdkPixbuf %s C-Source image dump %s*/\n\n",
+         bpp > 3 ? "RGBA" : "RGB",
+         rle_encoded ? "1-byte-run-length-encoded " : "");
+  
+  /* dump RLE decoder for structures
+   */
+  if (cdata.dump_rle_decoder && cdata.dump_struct)
+    save_rle_decoder (gstring,
+                     macro_name,
+                     cdata.dump_gtypes ? "guint" : "unsigned int",
+                     cdata.dump_gtypes ? "guint8" : "unsigned char",
+                     bpp);
+
+  /* format & size blurbs
+   */
+  if (cdata.dump_macros)
+    {
+      APPEND (gstring, "#define %s_ROWSTRIDE (%u)\n",
+             macro_name, rowstride);
+      APPEND (gstring, "#define %s_WIDTH (%u)\n",
+             macro_name, width);
+      APPEND (gstring, "#define %s_HEIGHT (%u)\n",
+             macro_name, height);
+      APPEND (gstring, "#define %s_BYTES_PER_PIXEL (%u) /* 3:RGB, 4:RGBA */\n",
+             macro_name, bpp);
+    }
+  if (cdata.dump_struct)
+    {
+      APPEND (gstring, "%s%sGdkPixdata %s = {\n",
+             cdata.static_prefix, cdata.const_prefix, name);
+      APPEND (gstring, "  0x%x, /* Pixbuf magic: 'GdkP' */\n",
+             GDK_PIXBUF_MAGIC_NUMBER);
+      APPEND (gstring, "  %d + %lu, /* header length + pixel_data length */\n",
+             GDK_PIXDATA_HEADER_LENGTH,
+             rle_encoded ? (glong)(img_buffer_end - img_buffer) : (glong)rowstride * height);
+      APPEND (gstring, "  0x%x, /* pixdata_type */\n",
+             pixdata->pixdata_type);
+      APPEND (gstring, "  %u, /* rowstride */\n",
+             rowstride);
+      APPEND (gstring, "  %u, /* width */\n",
+             width);
+      APPEND (gstring, "  %u, /* height */\n",
+             height);
+      APPEND (gstring, "  /* pixel_data: */\n");
+    }
+  if (cdata.dump_stream)
+    {
+      guint pix_length = img_buffer_end - img_buffer;
+      
+      stream = gdk_pixdata_serialize (pixdata, &stream_length);
+      img_buffer = stream;
+      img_buffer_end = stream + stream_length;
+
+      APPEND (gstring, "#ifdef __SUNPRO_C\n");
+      APPEND (gstring, "#pragma align 4 (%s)\n", name);   
+      APPEND (gstring, "#endif\n");
+
+      APPEND (gstring, "#ifdef __GNUC__\n");
+      APPEND (gstring, "%s%s%s %s[] __attribute__ ((__aligned__ (4))) = \n",
+             cdata.static_prefix, cdata.const_prefix,
+             cdata.dump_gtypes ? "guint8" : "unsigned char",
+             name);
+      APPEND (gstring, "#else\n");
+      APPEND (gstring, "%s%s%s %s[] = \n",
+             cdata.static_prefix, cdata.const_prefix,
+             cdata.dump_gtypes ? "guint8" : "unsigned char",
+             name);
+      APPEND (gstring, "#endif\n");
+
+      APPEND (gstring, "{ \"\"\n  /* Pixbuf magic (0x%x) */\n  \"",
+             GDK_PIXBUF_MAGIC_NUMBER);
+      cdata.pos = 3;
+      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
+      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
+      APPEND (gstring, "\"\n  /* length: header (%d) + pixel_data (%u) */\n  \"",
+             GDK_PIXDATA_HEADER_LENGTH,
+             rle_encoded ? pix_length : rowstride * height);
+      cdata.pos = 3;
+      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
+      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
+      APPEND (gstring, "\"\n  /* pixdata_type (0x%x) */\n  \"",
+             pixdata->pixdata_type);
+      cdata.pos = 3;
+      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
+      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
+      APPEND (gstring, "\"\n  /* rowstride (%u) */\n  \"",
+             rowstride);
+      cdata.pos = 3;
+      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
+      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
+      APPEND (gstring, "\"\n  /* width (%u) */\n  \"", width);
+      cdata.pos = 3;
+      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
+      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
+      APPEND (gstring, "\"\n  /* height (%u) */\n  \"", height);
+      cdata.pos = 3;
+      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
+      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
+      APPEND (gstring, "\"\n  /* pixel_data: */\n");
+    }
+
+  /* pixel_data intro
+   */
+  if (cdata.dump_macros)
+    {
+      APPEND (gstring, "#define %s_%sPIXEL_DATA ((%s*) \\\n",
+             macro_name,
+             rle_encoded ? "RLE_" : "",
+             s_uint_8);
+      APPEND (gstring, "  \"");
+      cdata.pos = 2;
+    }
+  if (cdata.dump_struct)
+    {
+      APPEND (gstring, "  \"");
+      cdata.pos = 3;
+    }
+  if (cdata.dump_stream)
+    {
+      APPEND (gstring, "  \"");
+      cdata.pos = 3;
+    }
+    
+  /* pixel_data
+   */
+  do
+    save_uchar (&cdata, *img_buffer++);
+  while (img_buffer < img_buffer_end);
+
+  /* pixel_data trailer
+   */
+  if (cdata.dump_macros)
+    APPEND (gstring, "\")\n\n");
+  if (cdata.dump_struct)
+    APPEND (gstring, "\",\n};\n\n");
+  if (cdata.dump_stream)
+    APPEND (gstring, "\"};\n\n");
+
+  /* dump RLE decoder for macros
+   */
+  if (cdata.dump_rle_decoder && cdata.dump_macros)
+    save_rle_decoder (gstring,
+                     macro_name,
+                     cdata.dump_gtypes ? "guint" : "unsigned int",
+                     cdata.dump_gtypes ? "guint8" : "unsigned char",
+                     bpp);
+
+  /* cleanup
+   */
+  g_free (stream);
+  g_free (macro_name);
+    
+  return gstring;
+}
+
+/**
+ * gdk_pixbuf_new_from_inline:
+ * @data_length: Length in bytes of the @data argument or -1 to 
+ *    disable length checks
+ * @data: (array length=data_length): Byte data containing a
+ *    serialized #GdkPixdata structure
+ * @copy_pixels: Whether to copy the pixel data, or use direct pointers
+ *               @data for the resulting pixbuf
+ * @error: #GError return location, may be %NULL to ignore errors
+ *
+ * Create a #GdkPixbuf from a flat representation that is suitable for
+ * storing as inline data in a program. This is useful if you want to
+ * ship a program with images, but don't want to depend on any
+ * external files.
+ *
+ * gdk-pixbuf ships with a program called <command>gdk-pixbuf-csource</command> 
+ * which allows for conversion of #GdkPixbufs into such a inline representation.
+ * In almost all cases, you should pass the <option>--raw</option> flag to
+ * <command>gdk-pixbuf-csource</command>. A sample invocation would be:
+ *
+ * <informalexample><programlisting>
+ *  gdk-pixbuf-csource --raw --name=myimage_inline myimage.png
+ * </programlisting></informalexample>
+ * 
+ * For the typical case where the inline pixbuf is read-only static data,
+ * you don't need to copy the pixel data unless you intend to write to
+ * it, so you can pass %FALSE for @copy_pixels.  (If you pass 
+ * <option>--rle</option> to <command>gdk-pixbuf-csource</command>, a copy 
+ * will be made even if @copy_pixels is %FALSE, so using this option is 
+ * generally a bad idea.)
+ *
+ * If you create a pixbuf from const inline data compiled into your
+ * program, it's probably safe to ignore errors and disable length checks, 
+ * since things will always succeed:
+ * <informalexample><programlisting>
+ * pixbuf = gdk_pixbuf_new_from_inline (-1, myimage_inline, FALSE, NULL);
+ * </programlisting></informalexample>
+ *
+ * For non-const inline data, you could get out of memory. For untrusted 
+ * inline data located at runtime, you could have corrupt inline data in 
+ * addition.
+ *
+ * Return value: A newly-created #GdkPixbuf structure with a reference,
+ *   count of 1, or %NULL if an error occurred.
+ **/
+GdkPixbuf*
+gdk_pixbuf_new_from_inline (gint          data_length,
+                           const guint8 *data,
+                           gboolean      copy_pixels,
+                           GError      **error)
+{
+  GdkPixdata pixdata;
+
+  if (data_length != -1)
+    g_return_val_if_fail (data_length > GDK_PIXDATA_HEADER_LENGTH, NULL);
+  g_return_val_if_fail (data != NULL, NULL);
+
+  if (!gdk_pixdata_deserialize (&pixdata, data_length, data, error))
+    return NULL;
+
+  return gdk_pixbuf_from_pixdata (&pixdata, copy_pixels, error);
+}
diff --git a/gdk-pixbuf/gdk-pixdata.h b/gdk-pixbuf/gdk-pixdata.h
new file mode 100644 (file)
index 0000000..c217781
--- /dev/null
@@ -0,0 +1,170 @@
+/* GdkPixbuf library - GdkPixdata - functions for inlined pixbuf handling
+ * Copyright (C) 1999, 2001 Tim Janik
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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_PIXDATA_H__
+#define __GDK_PIXDATA_H__
+
+#include        <gdk-pixbuf/gdk-pixbuf.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GDK_PIXBUF_MAGIC_NUMBER:
+ *
+ * Magic number for #GdkPixdata structures.
+ **/
+#define GDK_PIXBUF_MAGIC_NUMBER (0x47646b50)    /* 'GdkP' */
+
+/**
+ * GdkPixdataType:
+ * @GDK_PIXDATA_COLOR_TYPE_RGB:  each pixel has red, green and blue samples.
+ * @GDK_PIXDATA_COLOR_TYPE_RGBA: each pixel has red, green and blue samples 
+ *    and an alpha value.
+ * @GDK_PIXDATA_COLOR_TYPE_MASK: mask for the colortype flags of the enum.
+ * @GDK_PIXDATA_SAMPLE_WIDTH_8: each sample has 8 bits.
+ * @GDK_PIXDATA_SAMPLE_WIDTH_MASK: mask for the sample width flags of the enum.
+ * @GDK_PIXDATA_ENCODING_RAW: the pixel data is in raw form. 
+ * @GDK_PIXDATA_ENCODING_RLE: the pixel data is run-length encoded. Runs may 
+ *    be up to 127 bytes long; their length is stored in a single byte 
+ *    preceding the pixel data for the run. If a run is constant, its length
+ *    byte has the high bit set and the pixel data consists of a single pixel
+ *    which must be repeated. 
+ * @GDK_PIXDATA_ENCODING_MASK: mask for the encoding flags of the enum.
+ *
+ * An enumeration containing three sets of flags for a #GdkPixdata struct: 
+ * one for the used colorspace, one for the width of the samples and one 
+ * for the encoding of the pixel data.  
+ **/
+typedef enum
+{
+  /* colorspace + alpha */
+  GDK_PIXDATA_COLOR_TYPE_RGB    = 0x01,
+  GDK_PIXDATA_COLOR_TYPE_RGBA   = 0x02,
+  GDK_PIXDATA_COLOR_TYPE_MASK   = 0xff,
+  /* width, support 8bits only currently */
+  GDK_PIXDATA_SAMPLE_WIDTH_8    = 0x01 << 16,
+  GDK_PIXDATA_SAMPLE_WIDTH_MASK = 0x0f << 16,
+  /* encoding */
+  GDK_PIXDATA_ENCODING_RAW      = 0x01 << 24,
+  GDK_PIXDATA_ENCODING_RLE      = 0x02 << 24,
+  GDK_PIXDATA_ENCODING_MASK     = 0x0f << 24
+} GdkPixdataType;
+
+/**
+ * GdkPixdata:
+ * @magic: magic number. A valid #GdkPixdata structure must have 
+ *    #GDK_PIXBUF_MAGIC_NUMBER here.
+ * @length: less than 1 to disable length checks, otherwise 
+ *    #GDK_PIXDATA_HEADER_LENGTH + length of @pixel_data. 
+ * @pixdata_type: information about colorspace, sample width and 
+ *    encoding, in a #GdkPixdataType. 
+ * @rowstride: Distance in bytes between rows.
+ * @width: Width of the image in pixels.
+ * @height: Height of the image in pixels.
+ * @pixel_data: (array) (element-type guint8): @width x @height pixels, encoded according to @pixdata_type
+ *   and @rowstride.
+ *
+ * A #GdkPixdata contains pixbuf information in a form suitable for 
+ * serialization and streaming.
+ **/
+typedef struct _GdkPixdata GdkPixdata;
+struct _GdkPixdata
+{
+  guint32 magic;        /* GDK_PIXBUF_MAGIC_NUMBER */
+  gint32  length;       /* <1 to disable length checks, otherwise:
+                        * GDK_PIXDATA_HEADER_LENGTH + pixel_data length
+                        */
+  guint32 pixdata_type; /* GdkPixdataType */
+  guint32 rowstride;
+  guint32 width;
+  guint32 height;
+  guint8 *pixel_data;
+};
+
+/**
+ * GDK_PIXDATA_HEADER_LENGTH:
+ *
+ * The length of a #GdkPixdata structure without the @pixel_data pointer.
+ **/
+#define        GDK_PIXDATA_HEADER_LENGTH       (4 + 4 + 4 + 4 + 4 + 4)
+
+/* the returned stream is plain htonl of GdkPixdata members + pixel_data */
+guint8*                gdk_pixdata_serialize   (const GdkPixdata       *pixdata,
+                                        guint                  *stream_length_p);
+gboolean       gdk_pixdata_deserialize (GdkPixdata             *pixdata,
+                                        guint                   stream_length,
+                                        const guint8           *stream,
+                                        GError                **error);
+gpointer       gdk_pixdata_from_pixbuf (GdkPixdata             *pixdata,
+                                        const GdkPixbuf        *pixbuf,
+                                        gboolean                use_rle);
+GdkPixbuf*     gdk_pixbuf_from_pixdata (const GdkPixdata       *pixdata,
+                                        gboolean                copy_pixels,
+                                        GError                **error);
+/** 
+ * GdkPixdataDumpType:
+ * @GDK_PIXDATA_DUMP_PIXDATA_STREAM: Generate pixbuf data stream (a single 
+ *    string containing a serialized #GdkPixdata structure in network byte 
+ *    order).
+ * @GDK_PIXDATA_DUMP_PIXDATA_STRUCT: Generate #GdkPixdata structure (needs 
+ *    the #GdkPixdata structure definition from gdk-pixdata.h).
+ * @GDK_PIXDATA_DUMP_MACROS: Generate <function>*_ROWSTRIDE</function>,     
+ *    <function>*_WIDTH</function>, <function>*_HEIGHT</function>,
+ *    <function>*_BYTES_PER_PIXEL</function> and 
+ *    <function>*_RLE_PIXEL_DATA</function> or <function>*_PIXEL_DATA</function>
+ *    macro definitions for the image.
+ * @GDK_PIXDATA_DUMP_GTYPES: Generate GLib data types instead of 
+ *    standard C data types.
+ * @GDK_PIXDATA_DUMP_CTYPES: Generate standard C data types instead of 
+ *    GLib data types.
+ * @GDK_PIXDATA_DUMP_STATIC: Generate static symbols.
+ * @GDK_PIXDATA_DUMP_CONST: Generate const symbols.
+ * @GDK_PIXDATA_DUMP_RLE_DECODER: Provide a <function>*_RUN_LENGTH_DECODE(image_buf, rle_data, size, bpp)</function> 
+ *    macro definition  to  decode  run-length encoded image data.
+ *  
+ * An enumeration which is used by gdk_pixdata_to_csource() to
+ * determine the form of C source to be generated. The three values
+ * @GDK_PIXDATA_DUMP_PIXDATA_STREAM, @GDK_PIXDATA_DUMP_PIXDATA_STRUCT
+ * and @GDK_PIXDATA_DUMP_MACROS are mutually exclusive, as are
+ * @GDK_PIXBUF_DUMP_GTYPES and @GDK_PIXBUF_DUMP_CTYPES. The remaining
+ * elements are optional flags that can be freely added. 
+ **/
+typedef enum
+{
+  /* type of source to save */
+  GDK_PIXDATA_DUMP_PIXDATA_STREAM      = 0,
+  GDK_PIXDATA_DUMP_PIXDATA_STRUCT      = 1,
+  GDK_PIXDATA_DUMP_MACROS              = 2,
+  /* type of variables to use */
+  GDK_PIXDATA_DUMP_GTYPES              = 0,
+  GDK_PIXDATA_DUMP_CTYPES              = 1 << 8,
+  GDK_PIXDATA_DUMP_STATIC              = 1 << 9,
+  GDK_PIXDATA_DUMP_CONST               = 1 << 10,
+  /* save RLE decoder macro? */
+  GDK_PIXDATA_DUMP_RLE_DECODER         = 1 << 16
+} GdkPixdataDumpType;
+  
+
+GString*       gdk_pixdata_to_csource  (GdkPixdata             *pixdata,
+                                        const gchar            *name,
+                                        GdkPixdataDumpType      dump_type);
+
+
+G_END_DECLS
+
+#endif /* __GDK_PIXDATA_H__ */
diff --git a/gdk-pixbuf/gdk_pixbuf.def b/gdk-pixbuf/gdk_pixbuf.def
new file mode 100644 (file)
index 0000000..4fc8bdc
--- /dev/null
@@ -0,0 +1,123 @@
+EXPORTS
+       gdk_pixbuf_error_quark
+       gdk_pixbuf_get_type 
+       gdk_pixbuf_ref
+       gdk_pixbuf_unref
+       gdk_pixbuf_new
+       gdk_pixbuf_get_bits_per_sample
+       gdk_pixbuf_get_colorspace
+       gdk_pixbuf_get_has_alpha
+       gdk_pixbuf_get_height
+       gdk_pixbuf_get_n_channels
+       gdk_pixbuf_get_pixels
+       gdk_pixbuf_get_pixels_with_length
+       gdk_pixbuf_get_byte_length
+       gdk_pixbuf_get_rowstride
+       gdk_pixbuf_get_width
+       gdk_pixbuf_get_option
+       gdk_pixbuf_copy
+       gdk_pixbuf_new_subpixbuf
+       gdk_pixbuf_fill
+       gdk_pixbuf_new_from_data
+       gdk_pixbuf_new_from_file PRIVATE
+       gdk_pixbuf_new_from_file_utf8
+       gdk_pixbuf_new_from_file_at_size PRIVATE
+       gdk_pixbuf_new_from_file_at_size_utf8
+       gdk_pixbuf_new_from_file_at_scale PRIVATE
+       gdk_pixbuf_new_from_file_at_scale_utf8
+       gdk_pixbuf_new_from_xpm_data
+       gdk_pixbuf_new_from_resource
+       gdk_pixbuf_new_from_resource_at_scale
+       gdk_pixbuf_new_from_stream
+       gdk_pixbuf_new_from_stream_async
+       gdk_pixbuf_new_from_stream_finish
+       gdk_pixbuf_new_from_stream_at_scale
+       gdk_pixbuf_new_from_stream_at_scale_async
+       gdk_pixbuf_save PRIVATE 
+       gdk_pixbuf_save_utf8
+       gdk_pixbuf_save_to_buffer 
+       gdk_pixbuf_save_to_bufferv
+       gdk_pixbuf_save_to_callback 
+       gdk_pixbuf_save_to_callbackv
+       gdk_pixbuf_savev PRIVATE
+       gdk_pixbuf_savev_utf8
+       gdk_pixbuf_save_to_stream
+       gdk_pixbuf_save_to_stream_async
+       gdk_pixbuf_save_to_stream_finish
+       gdk_pixbuf_new_from_inline
+       gdk_pixbuf_add_alpha
+       gdk_pixbuf_copy_area
+       gdk_pixbuf_saturate_and_pixelate
+       gdk_pixbuf_apply_embedded_orientation
+       gdk_pixbuf_gettext
+       gdk_pixbuf_rotate_simple
+       gdk_pixbuf_scale
+       gdk_pixbuf_scale_simple
+       gdk_pixbuf_flip
+       gdk_pixbuf_composite
+       gdk_pixbuf_composite_color
+       gdk_pixbuf_composite_color_simple
+       gdk_pixbuf_animation_get_height
+       gdk_pixbuf_animation_get_iter
+       gdk_pixbuf_animation_get_static_image
+       gdk_pixbuf_animation_get_type 
+       gdk_pixbuf_animation_get_width
+       gdk_pixbuf_animation_is_static_image
+       gdk_pixbuf_animation_iter_advance
+       gdk_pixbuf_animation_iter_get_delay_time
+       gdk_pixbuf_animation_iter_get_pixbuf
+       gdk_pixbuf_animation_iter_get_type 
+       gdk_pixbuf_animation_iter_on_currently_loading_frame
+       gdk_pixbuf_animation_new_from_file PRIVATE
+       gdk_pixbuf_animation_new_from_file_utf8
+       gdk_pixbuf_animation_ref
+       gdk_pixbuf_animation_unref
+       gdk_pixbuf_non_anim_new
+       gdk_pixbuf_non_anim_get_type 
+       gdk_pixbuf_simple_anim_get_type 
+       gdk_pixbuf_simple_anim_iter_get_type 
+       gdk_pixbuf_simple_anim_new
+       gdk_pixbuf_simple_anim_add_frame
+       gdk_pixbuf_simple_anim_set_loop
+       gdk_pixbuf_simple_anim_get_loop
+       gdk_pixbuf_scaled_anim_get_type 
+       gdk_pixbuf_scaled_anim_iter_get_type 
+       gdk_pixbuf_get_formats
+       gdk_pixbuf_format_get_type 
+       gdk_pixbuf_format_copy
+       gdk_pixbuf_format_free
+       gdk_pixbuf_format_get_description
+       gdk_pixbuf_format_get_extensions
+       gdk_pixbuf_format_get_license
+       gdk_pixbuf_format_get_mime_types
+       gdk_pixbuf_format_get_name
+       gdk_pixbuf_format_is_disabled
+       gdk_pixbuf_format_is_scalable
+       gdk_pixbuf_format_is_writable
+       gdk_pixbuf_format_set_disabled
+       gdk_pixbuf_get_file_info
+       gdk_pixbuf_set_option
+       gdk_pixbuf_loader_close
+       gdk_pixbuf_loader_get_animation
+       gdk_pixbuf_loader_get_format
+       gdk_pixbuf_loader_get_pixbuf
+       gdk_pixbuf_loader_get_type 
+       gdk_pixbuf_loader_new
+       gdk_pixbuf_loader_new_with_mime_type
+       gdk_pixbuf_loader_new_with_type
+       gdk_pixbuf_loader_set_size
+       gdk_pixbuf_loader_write
+       gdk_colorspace_get_type 
+       gdk_interp_type_get_type 
+       gdk_pixbuf_alpha_mode_get_type 
+       gdk_pixbuf_rotation_get_type 
+       gdk_pixbuf_error_get_type
+       gdk_pixbuf_from_pixdata
+       gdk_pixdata_deserialize
+       gdk_pixdata_from_pixbuf
+       gdk_pixdata_serialize
+       gdk_pixdata_to_csource
+       gdk_pixbuf_major_version
+       gdk_pixbuf_micro_version
+       gdk_pixbuf_minor_version
+       gdk_pixbuf_version
diff --git a/gdk-pixbuf/gdk_pixbuf.rc b/gdk-pixbuf/gdk_pixbuf.rc
new file mode 100644 (file)
index 0000000..98a689f
--- /dev/null
@@ -0,0 +1,30 @@
+#include <winver.h>
+
+VS_VERSION_INFO VERSIONINFO
+  FILEVERSION 2,26,1,0
+  PRODUCTVERSION 2,26,1,0
+  FILEFLAGSMASK 0
+  FILEFLAGS 0
+  FILEOS VOS__WINDOWS32
+  FILETYPE VFT_DLL
+  FILESUBTYPE VFT2_UNKNOWN
+  BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+      BLOCK "040904B0"
+      BEGIN
+       VALUE "CompanyName", "The GTK developer community"
+       VALUE "FileDescription", "GIMP Toolkit"
+       VALUE "FileVersion", "2.26.1.0"
+       VALUE "InternalName", "libgdk_pixbuf-2.0-0"
+       VALUE "LegalCopyright", "Copyright (C) 1999 The Free Software Foundation. Modified by the GTK+ Team and others 1999-2011."
+       VALUE "OriginalFilename", "libgdk_pixbuf-2.0-0.dll"
+       VALUE "ProductName", "GTK+"
+       VALUE "ProductVersion", "2.26.1"
+      END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+      VALUE "Translation", 0x409, 1200
+    END
+  END
diff --git a/gdk-pixbuf/gdk_pixbuf.rc.in b/gdk-pixbuf/gdk_pixbuf.rc.in
new file mode 100644 (file)
index 0000000..9fcfd5e
--- /dev/null
@@ -0,0 +1,30 @@
+#include <winver.h>
+
+VS_VERSION_INFO VERSIONINFO
+  FILEVERSION @GDK_PIXBUF_MAJOR@,@GDK_PIXBUF_MINOR@,@GDK_PIXBUF_MICRO@,0
+  PRODUCTVERSION @GDK_PIXBUF_MAJOR@,@GDK_PIXBUF_MINOR@,@GDK_PIXBUF_MICRO@,0
+  FILEFLAGSMASK 0
+  FILEFLAGS 0
+  FILEOS VOS__WINDOWS32
+  FILETYPE VFT_DLL
+  FILESUBTYPE VFT2_UNKNOWN
+  BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+      BLOCK "040904B0"
+      BEGIN
+       VALUE "CompanyName", "The GTK developer community"
+       VALUE "FileDescription", "GIMP Toolkit"
+       VALUE "FileVersion", "@GDK_PIXBUF_VERSION@.0"
+       VALUE "InternalName", "libgdk_pixbuf-@GDK_PIXBUF_API_VERSION@-@LT_CURRENT_MINUS_AGE@"
+       VALUE "LegalCopyright", "Copyright (C) 1999 The Free Software Foundation. Modified by the GTK+ Team and others 1999-2011."
+       VALUE "OriginalFilename", "libgdk_pixbuf-@GDK_PIXBUF_API_VERSION@-@LT_CURRENT_MINUS_AGE@.dll"
+       VALUE "ProductName", "GTK+"
+       VALUE "ProductVersion", "@GDK_PIXBUF_VERSION@"
+      END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+      VALUE "Translation", 0x409, 1200
+    END
+  END
diff --git a/gdk-pixbuf/gen-color-table.pl b/gdk-pixbuf/gen-color-table.pl
new file mode 100755 (executable)
index 0000000..8b02fe5
--- /dev/null
@@ -0,0 +1,74 @@
+#!/usr/bin/perl -w
+
+if (@ARGV != 1) {
+    die "Usage: gen-color-table.pl rgb.txt > xpm-color-table.h\n";
+}
+
+open IN, $ARGV[0] || die "Cannot open $ARGV[0]: $!\n";
+
+@colors = ();
+while (defined($_ = <IN>)) {
+    next if /^!/;
+    if (!/^\s*([0-9]+)\s+([0-9]+)\s+([0-9]+)\s+(.*\S)\s+$/) {
+       die "Cannot parse line $_";
+    }
+
+    push @colors, [$1, $2, $3, $4];
+}
+
+@colors = sort { lc($a->[3]) cmp lc($b->[3]) } @colors;
+
+$offset = 0;
+
+$date = gmtime;
+
+print <<EOT;
+/* xpm-color-table.h: Generated by gen-color-table.pl from rgb.txt
+ *
+ *  Date: $date
+ *
+ * Do not edit.   
+ */
+static const char color_names[] =
+EOT
+
+for $color (@colors) {
+    $name = $color->[3];
+
+    if ($offset != 0) {
+       print qq(\n);
+    }
+    print qq(  "$name\\0");
+
+    $color->[4] = $offset;
+    $offset += length($name) + 1;
+}
+
+print ";\n\n";
+
+print <<EOT;
+typedef struct {
+    guint16 name_offset;
+    guchar red;
+    guchar green;
+    guchar blue;
+} XPMColorEntry;
+
+static const XPMColorEntry xColors[] = {
+EOT
+
+$i = 0;
+for $color (@colors) {
+    $red = $color->[0];
+    $green = $color->[1];
+    $blue = $color->[2];
+    $offset = $color->[4];
+
+    if ($i != 0) {
+       print ",\n";
+    }
+    print "  { $offset, $red, $green, $blue }";
+    $i++;
+}
+
+print "\n};\n";
diff --git a/gdk-pixbuf/io-ani-animation.c b/gdk-pixbuf/io-ani-animation.c
new file mode 100644 (file)
index 0000000..c6b28cc
--- /dev/null
@@ -0,0 +1,298 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* GdkPixbuf library - ani support
+ *
+ * Copyright (C) 2002 The Free Software Foundation
+ *
+ * Author: Matthias Clasen <maclas@gmx.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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 <errno.h>
+#include "gdk-pixbuf-private.h"
+#include "io-ani-animation.h"
+
+static void gdk_pixbuf_ani_anim_finalize   (GObject        *object);
+
+static gboolean                gdk_pixbuf_ani_anim_is_static_image  (GdkPixbufAnimation *animation);
+static GdkPixbuf*              gdk_pixbuf_ani_anim_get_static_image (GdkPixbufAnimation *animation);
+static void                    gdk_pixbuf_ani_anim_get_size (GdkPixbufAnimation *anim,
+                                                             int                *width,
+                                                             int                *height);
+static GdkPixbufAnimationIter* gdk_pixbuf_ani_anim_get_iter (GdkPixbufAnimation *anim,
+                                                             const GTimeVal     *start_time);
+
+
+\f
+
+G_DEFINE_TYPE  (GdkPixbufAniAnim, gdk_pixbuf_ani_anim, GDK_TYPE_PIXBUF_ANIMATION)
+
+static void
+gdk_pixbuf_ani_anim_init (GdkPixbufAniAnim *anim)
+{
+}
+
+static void
+gdk_pixbuf_ani_anim_class_init (GdkPixbufAniAnimClass *klass)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+        GdkPixbufAnimationClass *anim_class = GDK_PIXBUF_ANIMATION_CLASS (klass);
+
+        object_class->finalize = gdk_pixbuf_ani_anim_finalize;
+
+        anim_class->is_static_image = gdk_pixbuf_ani_anim_is_static_image;
+        anim_class->get_static_image = gdk_pixbuf_ani_anim_get_static_image;
+        anim_class->get_size = gdk_pixbuf_ani_anim_get_size;
+        anim_class->get_iter = gdk_pixbuf_ani_anim_get_iter;
+}
+
+static void
+gdk_pixbuf_ani_anim_finalize (GObject *object)
+{
+        GdkPixbufAniAnim *ani_anim = GDK_PIXBUF_ANI_ANIM (object);
+        gint i;
+
+        for (i = 0; i < ani_anim->n_pixbufs; i++) {
+                if (ani_anim->pixbufs[i])
+                        g_object_unref (ani_anim->pixbufs[i]);
+        }
+        g_free (ani_anim->pixbufs);
+        g_free (ani_anim->sequence);
+        g_free (ani_anim->delay);
+
+        G_OBJECT_CLASS (gdk_pixbuf_ani_anim_parent_class)->finalize (object);
+}
+
+static gboolean
+gdk_pixbuf_ani_anim_is_static_image (GdkPixbufAnimation *animation)
+{
+        GdkPixbufAniAnim *ani_anim;
+
+        ani_anim = GDK_PIXBUF_ANI_ANIM (animation);
+
+        return ani_anim->n_frames == 1;
+}
+
+static GdkPixbuf*
+gdk_pixbuf_ani_anim_get_static_image (GdkPixbufAnimation *animation)
+{
+        GdkPixbufAniAnim *ani_anim;
+
+        ani_anim = GDK_PIXBUF_ANI_ANIM (animation);
+
+        if (ani_anim->pixbufs == NULL)
+                return NULL;
+        else
+                return ani_anim->pixbufs[0];
+}
+
+static void
+gdk_pixbuf_ani_anim_get_size (GdkPixbufAnimation *anim,
+                              int                *width,
+                              int                *height)
+{
+        GdkPixbufAniAnim *ani_anim;
+
+        ani_anim = GDK_PIXBUF_ANI_ANIM (anim);
+
+        if (width)
+                *width = ani_anim->width;
+
+        if (height)
+                *height = ani_anim->height;
+}
+
+
+static void
+iter_restart (GdkPixbufAniAnimIter *iter)
+{
+        iter->current_frame = 0;
+        iter->position = 0;
+        iter->elapsed = 0;
+}
+
+static GdkPixbufAnimationIter*
+gdk_pixbuf_ani_anim_get_iter (GdkPixbufAnimation *anim,
+                              const GTimeVal     *start_time)
+{
+        GdkPixbufAniAnimIter *iter;
+
+        iter = g_object_new (GDK_TYPE_PIXBUF_ANI_ANIM_ITER, NULL);
+
+        iter->ani_anim = GDK_PIXBUF_ANI_ANIM (anim);
+
+        g_object_ref (iter->ani_anim);
+
+        iter_restart (iter);
+
+        iter->start_time = *start_time;
+        iter->current_time = *start_time;
+
+        return GDK_PIXBUF_ANIMATION_ITER (iter);
+}
+
+\f
+
+static void gdk_pixbuf_ani_anim_iter_finalize   (GObject                   *object);
+
+static int        gdk_pixbuf_ani_anim_iter_get_delay_time             (GdkPixbufAnimationIter *iter);
+static GdkPixbuf* gdk_pixbuf_ani_anim_iter_get_pixbuf                 (GdkPixbufAnimationIter *iter);
+static gboolean   gdk_pixbuf_ani_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter);
+static gboolean   gdk_pixbuf_ani_anim_iter_advance                    (GdkPixbufAnimationIter *iter,
+                                                                       const GTimeVal         *current_time);
+
+\f
+
+G_DEFINE_TYPE (GdkPixbufAniAnimIter, gdk_pixbuf_ani_anim_iter, GDK_TYPE_PIXBUF_ANIMATION_ITER);
+
+static void
+gdk_pixbuf_ani_anim_iter_init (GdkPixbufAniAnimIter *anim)
+{
+}
+
+static void
+gdk_pixbuf_ani_anim_iter_class_init (GdkPixbufAniAnimIterClass *klass)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+        GdkPixbufAnimationIterClass *anim_iter_class =
+                GDK_PIXBUF_ANIMATION_ITER_CLASS (klass);
+
+        object_class->finalize = gdk_pixbuf_ani_anim_iter_finalize;
+
+        anim_iter_class->get_delay_time = gdk_pixbuf_ani_anim_iter_get_delay_time;
+        anim_iter_class->get_pixbuf = gdk_pixbuf_ani_anim_iter_get_pixbuf;
+        anim_iter_class->on_currently_loading_frame = gdk_pixbuf_ani_anim_iter_on_currently_loading_frame;
+        anim_iter_class->advance = gdk_pixbuf_ani_anim_iter_advance;
+}
+
+static void
+gdk_pixbuf_ani_anim_iter_finalize (GObject *object)
+{
+        GdkPixbufAniAnimIter *iter = GDK_PIXBUF_ANI_ANIM_ITER (object);
+
+        g_object_unref (iter->ani_anim);
+
+        G_OBJECT_CLASS (gdk_pixbuf_ani_anim_iter_parent_class)->finalize (object);
+}
+
+static gboolean
+gdk_pixbuf_ani_anim_iter_advance (GdkPixbufAnimationIter *anim_iter,
+                                  const GTimeVal         *current_time)
+{
+        GdkPixbufAniAnimIter *iter;
+        gint elapsed;
+        gint tmp;
+        gint old;
+
+        iter = GDK_PIXBUF_ANI_ANIM_ITER (anim_iter);
+
+        iter->current_time = *current_time;
+
+        /* We use milliseconds for all times */
+        elapsed =
+          (((iter->current_time.tv_sec - iter->start_time.tv_sec) * G_USEC_PER_SEC +
+            iter->current_time.tv_usec - iter->start_time.tv_usec)) / 1000;
+
+        if (elapsed < 0) {
+                /* Try to compensate; probably the system clock
+                 * was set backwards
+                 */
+                iter->start_time = iter->current_time;
+                elapsed = 0;
+        }
+
+        g_assert (iter->ani_anim->total_time > 0);
+
+        /* See how many times we've already played the full animation,
+         * and subtract time for that.
+         */
+        elapsed = elapsed % iter->ani_anim->total_time;
+
+        iter->position = elapsed;
+
+        /* Now move to the proper frame */
+
+        iter->elapsed = 0;
+        for (tmp = 0; tmp < iter->ani_anim->n_frames; tmp++) {
+                if (iter->position >= iter->elapsed &&
+                    iter->position < (iter->elapsed + iter->ani_anim->delay[tmp]))
+                        break;
+                iter->elapsed += iter->ani_anim->delay[tmp];
+        }
+
+        old = iter->current_frame;
+
+        iter->current_frame = tmp;
+
+        return iter->current_frame != old;
+}
+
+int
+gdk_pixbuf_ani_anim_iter_get_delay_time (GdkPixbufAnimationIter *anim_iter)
+{
+        GdkPixbufAniAnimIter *iter;
+
+        iter = GDK_PIXBUF_ANI_ANIM_ITER (anim_iter);
+
+        return iter->ani_anim->delay[iter->current_frame] - (iter->position - iter->elapsed);
+}
+
+GdkPixbuf*
+gdk_pixbuf_ani_anim_iter_get_pixbuf (GdkPixbufAnimationIter *anim_iter)
+{
+        GdkPixbufAniAnimIter *iter;
+        gint frame;
+
+        iter = GDK_PIXBUF_ANI_ANIM_ITER (anim_iter);
+
+        frame = iter->ani_anim->sequence[iter->current_frame];
+
+        /* this is necessary if the animation is displayed while loading */
+        while (frame > 0 && !iter->ani_anim->pixbufs[frame])
+                frame--;
+
+        return iter->ani_anim->pixbufs[frame];
+}
+
+static gboolean
+gdk_pixbuf_ani_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *anim_iter)
+{
+        GdkPixbufAniAnimIter *iter;
+        gint frame;
+
+        iter = GDK_PIXBUF_ANI_ANIM_ITER (anim_iter);
+
+        if (iter->current_frame >= iter->ani_anim->n_frames - 1)
+                return TRUE;
+
+        frame = iter->ani_anim->sequence[iter->current_frame + 1];
+
+        if (!iter->ani_anim->pixbufs[frame])
+                return TRUE;
+
+        return FALSE;
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/gdk-pixbuf/io-ani-animation.h b/gdk-pixbuf/io-ani-animation.h
new file mode 100644 (file)
index 0000000..88629ab
--- /dev/null
@@ -0,0 +1,113 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* GdkPixbuf library - ANI loader declarations
+ *
+ * Copyright (C) 2002 The Free Software Foundation
+ *
+ * Author: Matthias Clasen <maclas@gmx.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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_ANI_ANIMATION_H
+#define GDK_PIXBUF_ANI_ANIMATION_H
+
+#include "gdk-pixbuf-private.h"
+#include "gdk-pixbuf-animation.h"
+
+typedef struct _GdkPixbufAniAnim GdkPixbufAniAnim;
+typedef struct _GdkPixbufAniAnimClass GdkPixbufAniAnimClass;
+
+#define GDK_TYPE_PIXBUF_ANI_ANIM              (gdk_pixbuf_ani_anim_get_type ())
+#define GDK_PIXBUF_ANI_ANIM(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_ANI_ANIM, GdkPixbufAniAnim))
+#define GDK_IS_PIXBUF_ANI_ANIM(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_ANI_ANIM))
+
+#define GDK_PIXBUF_ANI_ANIM_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_ANI_ANIM, GdkPixbufAniAnimClass))
+#define GDK_IS_PIXBUF_ANI_ANIM_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_ANI_ANIM))
+#define GDK_PIXBUF_ANI_ANIM_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_ANI_ANIM, GdkPixbufAniAnimClass))
+
+/* Private part of the GdkPixbufAniAnim structure */
+struct _GdkPixbufAniAnim {
+        GdkPixbufAnimation parent_instance;
+
+        /* Total length of animation */
+        int total_time;
+        
+        /* Number of frames */
+        int n_frames;
+        
+        /* Number of pixbufs */
+        int n_pixbufs;
+        
+        GdkPixbuf **pixbufs;
+        
+        /* Maps frame number to pixbuf */
+        int *sequence;
+        
+        /* The duration of each frame, in milliseconds */
+       int *delay;
+        
+        /* bounding box size */
+       int width, height;
+};
+
+struct _GdkPixbufAniAnimClass {
+        GdkPixbufAnimationClass parent_class;
+        
+};
+
+GType gdk_pixbuf_ani_anim_get_type (void) G_GNUC_CONST;
+
+\f
+
+typedef struct _GdkPixbufAniAnimIter GdkPixbufAniAnimIter;
+typedef struct _GdkPixbufAniAnimIterClass GdkPixbufAniAnimIterClass;
+
+
+#define GDK_TYPE_PIXBUF_ANI_ANIM_ITER              (gdk_pixbuf_ani_anim_iter_get_type ())
+#define GDK_PIXBUF_ANI_ANIM_ITER(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_ANI_ANIM_ITER, GdkPixbufAniAnimIter))
+#define GDK_IS_PIXBUF_ANI_ANIM_ITER(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_ANI_ANIM_ITER))
+
+#define GDK_PIXBUF_ANI_ANIM_ITER_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_ANI_ANIM_ITER, GdkPixbufAniAnimIterClass))
+#define GDK_IS_PIXBUF_ANI_ANIM_ITER_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_ANI_ANIM_ITER))
+#define GDK_PIXBUF_ANI_ANIM_ITER_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_ANI_ANIM_ITER, GdkPixbufAniAnimIterClass))
+
+struct _GdkPixbufAniAnimIter {
+        GdkPixbufAnimationIter parent_instance;
+        
+        GdkPixbufAniAnim   *ani_anim;
+
+        GTimeVal            start_time;
+        GTimeVal            current_time;
+
+        /* Time in milliseconds into this run of the animation */
+        gint                position;
+
+        /* Index of the current frame */
+        gint                current_frame;
+
+        /* Time in milliseconds from the start of the animation till the
+           begin of the current frame */
+        gint                elapsed;
+};
+
+struct _GdkPixbufAniAnimIterClass {
+        GdkPixbufAnimationIterClass parent_class;
+
+};
+
+GType gdk_pixbuf_ani_anim_iter_get_type (void) G_GNUC_CONST;
+
+#endif
diff --git a/gdk-pixbuf/io-ani.c b/gdk-pixbuf/io-ani.c
new file mode 100644 (file)
index 0000000..c8a3ee8
--- /dev/null
@@ -0,0 +1,714 @@
+/* -*- mode: C; c-file-style: "linux" -*- */
+/* GdkPixbuf library - ANI image loader
+ *
+ * Copyright (C) 2002 The Free Software Foundation
+ *
+ * Authors: Matthias Clasen <maclas@gmx.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#undef DEBUG_ANI
+
+#include "config.h"
+#include <stdlib.h>
+#include <string.h>
+#include "gdk-pixbuf-private.h"
+#include "gdk-pixbuf-loader.h"
+#include "io-ani-animation.h"
+
+static int
+lsb_32 (guchar *src)
+{
+       return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+}
+
+#define MAKE_TAG(a,b,c,d) ( (guint32)d << 24 | \
+                           (guint32)c << 16 | \
+                           (guint32)b <<  8 | \
+                           (guint32)a )
+
+#define TAG_RIFF MAKE_TAG('R','I','F','F')
+#define TAG_ACON MAKE_TAG('A','C','O','N')
+#define TAG_LIST MAKE_TAG('L','I','S','T')
+#define TAG_INAM MAKE_TAG('I','N','A','M')
+#define TAG_IART MAKE_TAG('I','A','R','T')
+#define TAG_anih MAKE_TAG('a','n','i','h')
+#define TAG_seq  MAKE_TAG('s','e','q',' ')
+#define TAG_rate MAKE_TAG('r','a','t','e')
+#define TAG_icon MAKE_TAG('i','c','o','n')
+
+typedef struct _AniLoaderContext 
+{
+        guint32 cp;
+        
+        guchar *buffer;
+        guchar *byte;
+        guint   n_bytes;
+        guint   buffer_size;
+        
+        GdkPixbufModulePreparedFunc prepared_func;
+        GdkPixbufModuleUpdatedFunc updated_func;
+        gpointer user_data;
+        
+        guint32 data_size;
+        
+        guint32 HeaderSize;
+        guint32 NumFrames; 
+        guint32 NumSteps; 
+        guint32 Width;   
+        guint32 Height; 
+        guint32 BitCount; 
+        guint32 NumPlanes; 
+        guint32 DisplayRate; 
+        guint32 Flags;
+        
+        guint32 chunk_id;
+        guint32 chunk_size;
+        
+        gchar  *title;
+        gchar  *author;
+
+        GdkPixbufAniAnim *animation;
+       GdkPixbufLoader *loader;
+
+        int     pos;
+} AniLoaderContext;
+
+
+#define BYTES_LEFT(context) \
+        ((context)->n_bytes - ((context)->byte - (context)->buffer))
+
+static void
+read_int8 (AniLoaderContext *context,
+           guchar     *data,
+           int        count)
+{
+        int total = MIN (count, BYTES_LEFT (context));
+        memcpy (data, context->byte, total);
+        context->byte += total;
+        context->cp += total;
+}
+
+
+static guint32
+read_int32 (AniLoaderContext *context)
+{
+        guint32 result;
+
+        read_int8 (context, (guchar*) &result, 4);
+        return lsb_32 ((guchar *) &result);
+}
+
+static void
+context_free (AniLoaderContext *context)
+{
+        if (!context)
+                return;
+
+       if (context->loader) 
+       {
+               gdk_pixbuf_loader_close (context->loader, NULL);
+               g_object_unref (context->loader);
+       }
+        if (context->animation) 
+               g_object_unref (context->animation);
+        g_free (context->buffer);
+        g_free (context->title);
+        g_free (context->author);
+        
+        g_free (context);
+}
+
+static void
+prepared_callback (GdkPixbufLoader *loader,
+                   gpointer data)
+{
+       AniLoaderContext *context = (AniLoaderContext*)data;
+
+#ifdef DEBUG_ANI
+       g_print ("%d pixbuf prepared\n", context->pos);
+#endif
+
+       GdkPixbuf *pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+        if (!pixbuf)
+               return;
+
+       if (gdk_pixbuf_get_width (pixbuf) > context->animation->width) 
+               context->animation->width = gdk_pixbuf_get_width (pixbuf);
+       
+       if (gdk_pixbuf_get_height (pixbuf) > context->animation->height) 
+               context->animation->height = gdk_pixbuf_get_height (pixbuf);
+       
+       if (context->title != NULL) 
+               gdk_pixbuf_set_option (pixbuf, "Title", context->title);
+       
+       if (context->author != NULL) 
+               gdk_pixbuf_set_option (pixbuf, "Author", context->author);
+
+       g_object_ref (pixbuf);
+       context->animation->pixbufs[context->pos] = pixbuf;
+
+       if (context->pos == 0) 
+       {
+               if (context->prepared_func)
+                       (* context->prepared_func) (pixbuf, 
+                                                   GDK_PIXBUF_ANIMATION (context->animation), 
+                                                   context->user_data);
+       }
+       else {
+               /* FIXME - this is necessary for nice display of loading 
+                  animations because GtkImage ignores 
+                  gdk_pixbuf_animation_iter_on_currently_loading_frame()
+                  and always exposes the full frame */
+               GdkPixbuf *last = context->animation->pixbufs[context->pos - 1];
+               gint width = MIN (gdk_pixbuf_get_width (last), gdk_pixbuf_get_width (pixbuf));
+               gint height = MIN (gdk_pixbuf_get_height (last), gdk_pixbuf_get_height (pixbuf));
+               gdk_pixbuf_copy_area (last, 0, 0, width, height, pixbuf, 0, 0);
+       }
+
+       context->pos++;
+}
+
+static void
+updated_callback (GdkPixbufLoader* loader,
+                 gint x, gint y, gint width, gint height,
+                 gpointer data)
+{
+       AniLoaderContext *context = (AniLoaderContext*)data;
+
+       GdkPixbuf *pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+       
+       if (context->updated_func)
+               (* context->updated_func) (pixbuf, 
+                                          x, y, width, height,
+                                          context->user_data);
+}
+
+static gboolean
+ani_load_chunk (AniLoaderContext *context, GError **error)
+{
+        int i;
+        
+        if (context->chunk_id == 0x0) {
+                if (BYTES_LEFT (context) < 8)
+                        return FALSE;
+                context->chunk_id = read_int32 (context);
+                context->chunk_size = read_int32 (context);
+               /* Pad it up to word length */
+               if (context->chunk_size % 2)
+                       context->chunk_size += (2 - (context->chunk_size % 2));
+        
+        }
+        
+        while (context->chunk_id == TAG_LIST)
+       {
+               if (BYTES_LEFT (context) < 12)
+                       return FALSE;
+                        
+               read_int32 (context);
+               context->chunk_id = read_int32 (context);
+               context->chunk_size = read_int32 (context);
+               /* Pad it up to word length */
+               if (context->chunk_size % 2)
+                       context->chunk_size += (2 - (context->chunk_size % 2));
+        
+       }
+        
+       if (context->chunk_id == TAG_icon) 
+       {
+               GError *loader_error = NULL;
+               guchar *data;
+               guint32 towrite;
+
+               if (context->loader == NULL) 
+               {
+                       if (context->pos >= context->NumFrames) 
+                       {
+                               g_set_error_literal (error,
+                                                     GDK_PIXBUF_ERROR,
+                                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                                     _("Unexpected icon chunk in animation"));
+                               return FALSE; 
+                       }
+
+#ifdef DEBUG_ANI
+                       g_print ("opening loader\n");
+#endif
+                       context->loader = gdk_pixbuf_loader_new_with_type ("ico", &loader_error);
+                       if (loader_error) 
+                       {
+                               g_propagate_error (error, loader_error);
+                               return FALSE;
+                       }
+                       g_signal_connect (context->loader, "area_prepared",
+                                         G_CALLBACK (prepared_callback), context);
+                       g_signal_connect (context->loader, "area_updated",
+                                         G_CALLBACK (updated_callback), context);
+               }
+
+               towrite = MIN (context->chunk_size, BYTES_LEFT (context));
+               data = context->byte;
+               context->byte += towrite;
+               context->cp += towrite;
+#ifdef DEBUG_ANI
+               g_print ("miss %d, get %d, leftover %d\n", context->chunk_size, towrite, BYTES_LEFT (context));
+#endif
+               context->chunk_size -= towrite;
+               if (!gdk_pixbuf_loader_write (context->loader, data, towrite, &loader_error)) 
+               {
+                       g_propagate_error (error, loader_error);
+                       gdk_pixbuf_loader_close (context->loader, NULL);
+                       g_object_unref (context->loader);
+                       context->loader = NULL;
+                       return FALSE; 
+               }
+               if (context->chunk_size == 0) 
+               {
+#ifdef DEBUG_ANI
+                       g_print ("closing loader\n");
+#endif
+                       if (!gdk_pixbuf_loader_close (context->loader, &loader_error)) 
+                       {
+                               g_propagate_error (error, loader_error);
+                               g_object_unref (context->loader);
+                               context->loader = NULL;
+                               return FALSE;
+                       }
+                       g_object_unref (context->loader);
+                       context->loader = NULL;
+                       context->chunk_id = 0x0;
+               }
+               return BYTES_LEFT (context) > 0;
+       }
+
+        if (BYTES_LEFT (context) < context->chunk_size)
+                return FALSE;
+        
+        if (context->chunk_id == TAG_anih) 
+       {
+               context->HeaderSize = read_int32 (context);
+               context->NumFrames = read_int32 (context);
+               context->NumSteps = read_int32 (context);
+               context->Width = read_int32 (context);
+               context->Height = read_int32 (context);
+               context->BitCount = read_int32 (context);
+               context->NumPlanes = read_int32 (context);
+               context->DisplayRate = read_int32 (context);
+               context->Flags = read_int32 (context);
+                        
+#ifdef DEBUG_ANI         
+               g_print ("HeaderSize \t%" G_GUINT32_FORMAT
+                        "\nNumFrames \t%" G_GUINT32_FORMAT
+                        "\nNumSteps \t%" G_GUINT32_FORMAT
+                        "\nWidth    \t%" G_GUINT32_FORMAT
+                        "\nHeight   \t%" G_GUINT32_FORMAT
+                        "\nBitCount \t%" G_GUINT32_FORMAT
+                        "\nNumPlanes \t%" G_GUINT32_FORMAT
+                        "\nDisplayRate \t%" G_GUINT32_FORMAT
+                        "\nSequenceFlag \t%d"
+                        "\nIconFlag \t%d"
+                        "\n",
+                        context->HeaderSize, context->NumFrames, 
+                        context->NumSteps, context->Width, 
+                        context->Height, context->BitCount, 
+                        context->NumPlanes, context->DisplayRate, 
+                        (context->Flags & 0x2) != 0, 
+                        (context->Flags & 0x1) != 0);
+#endif
+               if (!(context->Flags & 0x2))
+                       context->NumSteps = context->NumFrames;
+               if (context->NumFrames == 0 || 
+                   context->NumFrames >= 1024 || 
+                   context->NumSteps == 0 || 
+                   context->NumSteps >= 1024) 
+               {
+                       g_set_error_literal (error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                             _("Invalid header in animation"));
+                       return FALSE;
+               }
+      
+               context->animation = g_object_new (GDK_TYPE_PIXBUF_ANI_ANIM, NULL);        
+               if (!context->animation) 
+               {
+                       g_set_error_literal (error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                             _("Not enough memory to load animation"));
+                       return FALSE;
+               }
+
+               context->animation->n_pixbufs = context->NumFrames;
+               context->animation->n_frames = context->NumSteps;
+
+               context->animation->total_time = context->NumSteps * (context->DisplayRate * 1000 / 60);
+               context->animation->width = 0;
+               context->animation->height = 0;
+
+               context->animation->pixbufs = g_try_new0 (GdkPixbuf*, context->NumFrames);
+               context->animation->delay = g_try_new (gint, context->NumSteps);
+               context->animation->sequence = g_try_new (gint, context->NumSteps);
+
+               if (!context->animation->pixbufs || 
+                   !context->animation->delay || 
+                   !context->animation->sequence) 
+               {
+                       g_set_error_literal (error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                             _("Not enough memory to load animation"));
+                       return FALSE;
+               }
+
+               for (i = 0; i < context->NumSteps; i++) 
+               {
+                       /* default values if the corresponding chunks are absent */
+                       context->animation->delay[i] = context->DisplayRate * 1000 / 60;
+                       context->animation->sequence[i] = MIN (i, context->NumFrames  - 1);       
+               }
+       }
+        else if (context->chunk_id == TAG_rate) 
+       {
+               if (context->chunk_size != 4 * context->NumSteps) 
+               {
+                       g_set_error_literal (error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                             _("Malformed chunk in animation"));
+                       return FALSE; 
+               }
+               if (!context->animation) 
+               {
+                       g_set_error_literal (error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                             _("Invalid header in animation"));
+                       return FALSE;
+               }
+
+               context->animation->total_time = 0;
+               for (i = 0; i < context->NumSteps; i++) 
+               {
+                       context->animation->delay[i] = read_int32 (context) * 1000 / 60;
+                       context->animation->total_time += context->animation->delay[i];
+               }
+       }
+        else if (context->chunk_id == TAG_seq) 
+       {
+               if (context->chunk_size != 4 * context->NumSteps) 
+               {
+                       g_set_error_literal (error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                             _("Malformed chunk in animation"));
+                       return FALSE; 
+               }
+               if (!context->animation) 
+               {
+                       g_set_error_literal (error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                             _("Invalid header in animation"));
+                       return FALSE;
+               }
+               for (i = 0; i < context->NumSteps; i++) 
+               {
+                       context->animation->sequence[i] = read_int32 (context);
+                       if (context->animation->sequence[i] >= context->NumFrames) 
+                       {
+                               g_set_error_literal (error,
+                                                     GDK_PIXBUF_ERROR,
+                                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                                     _("Malformed chunk in animation"));
+                               return FALSE; 
+                       }
+               }
+       }
+        else if (context->chunk_id == TAG_INAM) 
+       {
+               if (!context->animation) 
+               {
+                       g_set_error_literal (error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                             _("Invalid header in animation"));
+                       return FALSE;
+               }
+               context->title = g_try_malloc (context->chunk_size + 1);
+               if (!context->title) 
+               {
+                       g_set_error_literal (error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                             _("Not enough memory to load animation"));
+                       return FALSE;
+               }
+               context->title[context->chunk_size] = 0;
+               read_int8 (context, (guchar *)context->title, context->chunk_size);
+#ifdef DEBUG_ANI
+               g_print ("INAM %s\n", context->title);
+#endif
+               for (i = 0; i < context->pos; i++)
+                       gdk_pixbuf_set_option (context->animation->pixbufs[i], "Title", context->title);                        
+       }
+        else if (context->chunk_id == TAG_IART) 
+       {
+               if (!context->animation) 
+               {
+                       g_set_error_literal (error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                             _("Invalid header in animation"));
+                       return FALSE;
+               }
+               context->author = g_try_malloc (context->chunk_size + 1);
+               if (!context->author) 
+               {
+                       g_set_error_literal (error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                             _("Not enough memory to load animation"));
+                       return FALSE;
+               }
+               context->author[context->chunk_size] = 0;
+               read_int8 (context, (guchar *)context->author, context->chunk_size);
+#ifdef DEBUG_ANI
+               g_print ("IART %s\n", context->author);
+#endif
+               for (i = 0; i < context->pos; i++)
+                       gdk_pixbuf_set_option (context->animation->pixbufs[i], "Author", context->author);                      
+       }
+
+#ifdef DEBUG_ANI
+       {
+               gint32 dummy = lsb_32 ((guchar *)&context->chunk_id);
+        
+               g_print ("Loaded chunk with ID '%c%c%c%c' and length %" G_GUINT32_FORMAT "\n",
+                        ((char*)&dummy)[0], ((char*)&dummy)[1],
+                        ((char*)&dummy)[2], ((char*)&dummy)[3], 
+                        context->chunk_size);
+       }
+#endif 
+               
+       context->chunk_id = 0x0;
+        return TRUE;
+}
+
+static gboolean
+gdk_pixbuf__ani_image_load_increment (gpointer data,
+                                     const guchar *buf, guint size,
+                                     GError **error)
+{
+        AniLoaderContext *context = (AniLoaderContext *)data;
+        
+        if (context->n_bytes + size >= context->buffer_size) {
+                int drop = context->byte - context->buffer;
+                memmove (context->buffer, context->byte, context->n_bytes - drop);
+                context->n_bytes -= drop;
+                context->byte = context->buffer;
+                if (context->n_bytes + size >= context->buffer_size) {
+                       guchar *tmp;
+                        context->buffer_size = MAX (context->n_bytes + size, context->buffer_size + 4096);
+#ifdef DEBUG_ANI
+                        g_print ("growing buffer to %" G_GUINT32_FORMAT "\n", context->buffer_size);
+#endif
+                        tmp = g_try_realloc (context->buffer, context->buffer_size);
+                        if (!tmp) 
+                       {
+                               g_set_error_literal (error,
+                                                     GDK_PIXBUF_ERROR,
+                                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                                     _("Not enough memory to load animation"));
+                               return FALSE;
+                       }
+                        context->byte = context->buffer = tmp;
+                }
+        }
+        memcpy (context->buffer + context->n_bytes, buf, size);
+        context->n_bytes += size;
+
+        if (context->data_size == 0) 
+       {
+               guint32 riff_id, chunk_id;
+                        
+               if (BYTES_LEFT (context) < 12)
+                       return TRUE;
+                        
+               riff_id = read_int32 (context);
+               context->data_size = read_int32 (context);
+               chunk_id = read_int32 (context);
+                        
+               if (riff_id != TAG_RIFF || 
+                   context->data_size == 0 || 
+                   chunk_id != TAG_ACON) 
+               {
+                       g_set_error_literal (error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                             _("Invalid header in animation"));
+                       return FALSE; 
+               }
+       }
+        
+        if (context->cp < context->data_size + 8) 
+       {
+               GError *chunk_error = NULL;
+
+               while (ani_load_chunk (context, &chunk_error)) ;
+               if (chunk_error) 
+               {
+                       g_propagate_error (error, chunk_error);
+                       return FALSE;
+               }
+       }
+
+        return TRUE;
+}
+
+static gpointer
+gdk_pixbuf__ani_image_begin_load (GdkPixbufModuleSizeFunc size_func, 
+                                  GdkPixbufModulePreparedFunc prepared_func, 
+                                 GdkPixbufModuleUpdatedFunc  updated_func,
+                                 gpointer user_data,
+                                 GError **error)
+{
+        AniLoaderContext *context;
+        
+        context = g_new0 (AniLoaderContext, 1);
+        
+        context->prepared_func = prepared_func;
+        context->updated_func = updated_func;
+        context->user_data = user_data;
+        
+        context->pos = 0;
+        
+        context->buffer_size = 4096;
+        context->buffer = g_try_malloc (context->buffer_size);
+        if (!context->buffer) 
+       {
+               context_free (context);
+               g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                     _("Not enough memory to load animation"));
+               return NULL;
+       }
+        
+        context->byte = context->buffer;
+        context->n_bytes = 0;
+        
+        return (gpointer) context;
+}
+
+static gboolean
+gdk_pixbuf__ani_image_stop_load (gpointer data,
+                                GError **error)
+{
+        AniLoaderContext *context = (AniLoaderContext *) data;
+        
+       g_return_val_if_fail (context != NULL, TRUE);
+        context_free (context);
+        
+        return TRUE;
+}
+
+static void
+prepared_notify (GdkPixbuf *pixbuf, 
+                GdkPixbufAnimation *anim, 
+                gpointer user_data)
+{
+       if (anim != NULL)
+               g_object_ref (anim);
+       *((GdkPixbufAnimation **)user_data) = anim;
+}
+
+static GdkPixbufAnimation *
+gdk_pixbuf__ani_image_load_animation (FILE *f, GError **error)
+{
+       guchar buffer[4096];
+       size_t length;
+       GdkPixbufAnimation *anim = NULL;
+       gpointer context;
+
+       context = gdk_pixbuf__ani_image_begin_load (NULL, prepared_notify, 
+                                                   NULL, &anim, error);
+       
+       if (!context)
+                return NULL;
+       
+       while (!feof (f) && !ferror (f)) {
+               length = fread (buffer, 1, sizeof (buffer), f);
+               if (length > 0)
+                       if (!gdk_pixbuf__ani_image_load_increment (context, buffer, length, error)) {
+                               gdk_pixbuf__ani_image_stop_load (context, NULL);
+                               if (anim != NULL)
+                                       g_object_unref (anim);
+                               return NULL;
+                       }
+       }
+
+       if (!gdk_pixbuf__ani_image_stop_load (context, error)) {
+               if (anim != NULL)
+                       g_object_unref (anim);
+               return NULL;
+       }
+       
+       return anim;
+}
+
+#ifndef INCLUDE_ani
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
+#else
+#define MODULE_ENTRY(function) void _gdk_pixbuf__ani_ ## function
+#endif
+
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
+{
+        module->load_animation = gdk_pixbuf__ani_image_load_animation;
+        module->begin_load = gdk_pixbuf__ani_image_begin_load;
+        module->stop_load = gdk_pixbuf__ani_image_stop_load;
+        module->load_increment = gdk_pixbuf__ani_image_load_increment;
+}
+
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
+{
+       static GdkPixbufModulePattern signature[] = {
+               { "RIFF    ACON", "    xxxx    ", 100 },
+               { NULL, NULL, 0 }
+       };
+       static gchar * mime_types[] = {
+               "application/x-navi-animation",
+               NULL
+       };
+       static gchar * extensions[] = {
+               "ani",
+               NULL
+       };
+       
+       info->name = "ani";
+       info->signature = signature;
+       info->description = N_("The ANI image format");
+       info->mime_types = mime_types;
+       info->extensions = extensions;
+       info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
+       info->license = "LGPL";
+}
+
+
+
+
diff --git a/gdk-pixbuf/io-bmp.c b/gdk-pixbuf/io-bmp.c
new file mode 100644 (file)
index 0000000..26ffb62
--- /dev/null
@@ -0,0 +1,1428 @@
+/* -*- mode: C; c-file-style: "linux" -*- */
+/* GdkPixbuf library - Windows Bitmap image loader
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Authors: Arjan van de Ven <arjan@fenrus.demon.nl>
+ *          Federico Mena-Quintero <federico@gimp.org>
+ *
+ * Based on io-ras.c
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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 <stdio.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include "gdk-pixbuf-private.h"
+
+#define DUMPBIH 0
+
+\f
+
+#if 0
+/* If these structures were unpacked, they would define the two headers of the
+ * BMP file.  After them comes the palette, and then the image data.
+ *
+ * We do not use these structures; we just keep them here for reference.
+ */
+struct BitmapFileHeader {
+       guint16 magic;
+       guint32 file_size;
+       guint32 reserved;
+       guint32 data_offset;
+};
+
+struct BitmapInfoHeader {
+       guint32 header_size;
+       guint32 width;
+       guint32 height;
+       guint16 planes;
+       guint16 bpp;
+       guint32 compression;
+       guint32 data_size;
+       guint32 x_ppm;
+       guint32 y_ppm;
+       guint32 n_colors;
+       guint32 n_important_colors;
+};
+#endif
+
+/* Compression values */
+
+#define BI_RGB 0
+#define BI_RLE8 1
+#define BI_RLE4 2
+#define BI_BITFIELDS 3
+
+/* State machine */
+typedef enum {
+       READ_STATE_HEADERS,     /* Reading the bitmap file header and bitmap info header */
+       READ_STATE_PALETTE,     /* Reading the palette */
+       READ_STATE_BITMASKS,    /* Reading the bitmasks for BI_BITFIELDS */
+       READ_STATE_DATA,        /* Reading the actual image data */
+       READ_STATE_ERROR,       /* An error occurred; further data will be ignored */
+       READ_STATE_DONE         /* Done reading the image; further data will be ignored */
+} ReadState;
+
+/*
+
+DumpBIH printf's the values in a BitmapInfoHeader to the screen, for
+debugging purposes.
+
+*/
+#if DUMPBIH
+static void DumpBIH(unsigned char *BIH)
+{
+       printf("biSize      = %i \n",
+              (int) (BIH[3] << 24) + (BIH[2] << 16) + (BIH[1] << 8) +
+              (BIH[0]));
+       printf("biWidth     = %i \n",
+              (int) (BIH[7] << 24) + (BIH[6] << 16) + (BIH[5] << 8) +
+              (BIH[4]));
+       printf("biHeight    = %i \n",
+              (int) (BIH[11] << 24) + (BIH[10] << 16) + (BIH[9] << 8) +
+              (BIH[8]));
+       printf("biPlanes    = %i \n", (int) (BIH[13] << 8) + (BIH[12]));
+       printf("biBitCount  = %i \n", (int) (BIH[15] << 8) + (BIH[14]));
+       printf("biCompress  = %i \n",
+              (int) (BIH[19] << 24) + (BIH[18] << 16) + (BIH[17] << 8) +
+              (BIH[16]));
+       printf("biSizeImage = %i \n",
+              (int) (BIH[23] << 24) + (BIH[22] << 16) + (BIH[21] << 8) +
+              (BIH[20]));
+       printf("biXPels     = %i \n",
+              (int) (BIH[27] << 24) + (BIH[26] << 16) + (BIH[25] << 8) +
+              (BIH[24]));
+       printf("biYPels     = %i \n",
+              (int) (BIH[31] << 24) + (BIH[30] << 16) + (BIH[29] << 8) +
+              (BIH[28]));
+       printf("biClrUsed   = %i \n",
+              (int) (BIH[35] << 24) + (BIH[34] << 16) + (BIH[33] << 8) +
+              (BIH[32]));
+       printf("biClrImprtnt= %i \n",
+              (int) (BIH[39] << 24) + (BIH[38] << 16) + (BIH[37] << 8) +
+              (BIH[36]));
+}
+#endif
+/* struct headerpair contains the decoded width/height/depth info for
+   the current bitmap */
+
+struct headerpair {
+       guint32 size;
+       gint32 width;
+       gint32 height;
+       guint depth;
+       guint Negative;         /* Negative = 1 -> top down BMP,
+                                  Negative = 0 -> bottom up BMP */
+       guint  n_colors;
+};
+
+/* Data needed for the "state" during decompression */
+struct bmp_compression_state {
+       gint phase;
+       gint run;
+       gint count;
+       gint x, y;
+       guchar *p;
+};
+
+/* Progressive loading */
+
+struct bmp_progressive_state {
+       GdkPixbufModuleSizeFunc size_func;
+       GdkPixbufModulePreparedFunc prepared_func;
+       GdkPixbufModuleUpdatedFunc updated_func;
+       gpointer user_data;
+
+       ReadState read_state;
+
+       guint LineWidth;
+       guint Lines;            /* # of finished lines */
+
+       guchar *buff;
+       guint BufferSize;
+       guint BufferPadding;
+       guint BufferDone;
+
+       guchar (*Colormap)[3];
+
+       gint Type;              /*
+                                  32 = RGB + alpha
+                                  24 = RGB
+                                  16 = RGB
+                                  4  = 4 bpp colormapped
+                                  8  = 8 bpp colormapped
+                                  1  = 1 bit bitonal
+                                */
+       guint Compressed;
+       struct bmp_compression_state compr;
+
+
+       struct headerpair Header;       /* Decoded (BE->CPU) header */
+
+       /* Bit masks, shift amounts, and significant bits for BI_BITFIELDS coding */
+       int r_mask, r_shift, r_bits;
+       int g_mask, g_shift, g_bits;
+       int b_mask, b_shift, b_bits;
+       int a_mask, a_shift, a_bits;
+
+       GdkPixbuf *pixbuf;      /* Our "target" */
+};
+
+static gpointer
+gdk_pixbuf__bmp_image_begin_load(GdkPixbufModuleSizeFunc size_func,
+                                 GdkPixbufModulePreparedFunc prepared_func,
+                                GdkPixbufModuleUpdatedFunc updated_func,
+                                 gpointer user_data,
+                                 GError **error);
+
+static gboolean gdk_pixbuf__bmp_image_stop_load(gpointer data, GError **error);
+static gboolean gdk_pixbuf__bmp_image_load_increment(gpointer data,
+                                                     const guchar * buf,
+                                                     guint size,
+                                                     GError **error);
+
+
+/* Picks up a 32-bit little-endian integer starting at the specified location.
+ * Does it by hand instead of dereferencing a simple (gint *) cast due to
+ * alignment constraints many platforms.
+ */
+static int
+lsb_32 (guchar *src)
+{
+       return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+}
+
+/* Same as above, but for 16-bit little-endian integers. */
+static short
+lsb_16 (guchar *src)
+{
+       return src[0] | (src[1] << 8);
+}
+
+static gboolean grow_buffer (struct bmp_progressive_state *State,
+                             GError **error)
+{
+  guchar *tmp;
+
+  if (State->BufferSize == 0) {
+    g_set_error_literal (error,
+                         GDK_PIXBUF_ERROR,
+                         GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                         _("BMP image has bogus header data"));
+    State->read_state = READ_STATE_ERROR;
+    return FALSE;
+  }
+
+  tmp = g_try_realloc (State->buff, State->BufferSize);
+
+  if (!tmp) {
+    g_set_error_literal (error,
+                         GDK_PIXBUF_ERROR,
+                         GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                         _("Not enough memory to load bitmap image"));
+    State->read_state = READ_STATE_ERROR;
+    return FALSE;
+  }
+
+  State->buff = tmp;
+  return TRUE;
+}
+
+static gboolean
+decode_bitmasks (guchar *buf,
+                struct bmp_progressive_state *State, 
+                GError **error);
+
+static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
+                             struct bmp_progressive_state *State,
+                             GError **error)
+{
+       gint clrUsed;
+
+       /* First check for the two first bytes content. A sane
+          BMP file must start with bytes 0x42 0x4D.  */
+       if (*BFH != 0x42 || *(BFH + 1) != 0x4D) {
+               g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("BMP image has bogus header data"));
+               State->read_state = READ_STATE_ERROR;
+               return FALSE;
+       }
+
+        /* FIXME this is totally unrobust against bogus image data. */
+       if (State->BufferSize < lsb_32 (&BIH[0]) + 14) {
+               State->BufferSize = lsb_32 (&BIH[0]) + 14;
+               if (!grow_buffer (State, error))
+                       return FALSE;
+               return TRUE;
+       }
+
+#if DUMPBIH
+       DumpBIH(BIH);
+#endif    
+
+       State->Header.size = lsb_32 (&BIH[0]);
+       if (State->Header.size == 124) {
+                /* BMP v5 */
+               State->Header.width = lsb_32 (&BIH[4]);
+               State->Header.height = lsb_32 (&BIH[8]);
+               State->Header.depth = lsb_16 (&BIH[14]);
+               State->Compressed = lsb_32 (&BIH[16]);
+       } else if (State->Header.size == 108) {
+                /* BMP v4 */
+               State->Header.width = lsb_32 (&BIH[4]);
+               State->Header.height = lsb_32 (&BIH[8]);
+               State->Header.depth = lsb_16 (&BIH[14]);
+               State->Compressed = lsb_32 (&BIH[16]);
+       } else if (State->Header.size == 64) {
+                /* BMP OS/2 v2 */
+               State->Header.width = lsb_32 (&BIH[4]);
+               State->Header.height = lsb_32 (&BIH[8]);
+               State->Header.depth = lsb_16 (&BIH[14]);
+               State->Compressed = lsb_32 (&BIH[16]);
+       } else if (State->Header.size == 40) {
+                /* BMP v3 */ 
+               State->Header.width = lsb_32 (&BIH[4]);
+               State->Header.height = lsb_32 (&BIH[8]);
+               State->Header.depth = lsb_16 (&BIH[14]);
+               State->Compressed = lsb_32 (&BIH[16]);
+       } else if (State->Header.size == 12) {
+                /* BMP OS/2 */
+               State->Header.width = lsb_16 (&BIH[4]);
+               State->Header.height = lsb_16 (&BIH[6]);
+               State->Header.depth = lsb_16 (&BIH[10]);
+               State->Compressed = BI_RGB;
+       } else {
+               g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("BMP image has unsupported header size"));
+               State->read_state = READ_STATE_ERROR;
+               return FALSE;
+       }
+
+       if (State->Header.size == 12)
+               clrUsed = 1 << State->Header.depth;
+       else
+               clrUsed = (int) (BIH[35] << 24) + (BIH[34] << 16) + (BIH[33] << 8) + (BIH[32]);
+
+       if (clrUsed != 0)
+               State->Header.n_colors = clrUsed;
+       else
+            State->Header.n_colors = (1 << State->Header.depth);
+       
+       if (State->Header.n_colors > (1 << State->Header.depth)) {
+               g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("BMP image has bogus header data"));
+               State->read_state = READ_STATE_ERROR;
+               return FALSE;
+       }
+
+       State->Type = State->Header.depth;      /* This may be less trivial someday */
+
+       /* Negative heights indicates bottom-down pixelorder */
+       if (State->Header.height < 0) {
+               State->Header.height = -State->Header.height;
+               State->Header.Negative = 1;
+       }
+
+       if (State->Header.Negative && 
+           (State->Compressed != BI_RGB && State->Compressed != BI_BITFIELDS))
+       {
+               g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("Topdown BMP images cannot be compressed"));
+               State->read_state = READ_STATE_ERROR;
+               return FALSE;
+       }
+
+       if (State->Header.width <= 0 || State->Header.height == 0 ||
+           (State->Compressed == BI_RLE4 && State->Type != 4)    ||
+           (State->Compressed == BI_RLE8 && State->Type != 8)    ||
+           (State->Compressed == BI_BITFIELDS && !(State->Type == 16 || State->Type == 32)) ||
+           (State->Compressed > BI_BITFIELDS)) {
+               g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("BMP image has bogus header data"));
+               State->read_state = READ_STATE_ERROR;
+               return FALSE;
+       }
+
+       if (State->Type == 32)
+               State->LineWidth = State->Header.width * 4;
+       else if (State->Type == 24)
+               State->LineWidth = State->Header.width * 3;
+       else if (State->Type == 16)
+               State->LineWidth = State->Header.width * 2;
+       else if (State->Type == 8)
+               State->LineWidth = State->Header.width * 1;
+       else if (State->Type == 4)
+               State->LineWidth = (State->Header.width + 1) / 2;
+       else if (State->Type == 1) {
+               State->LineWidth = State->Header.width / 8;
+               if ((State->Header.width & 7) != 0)
+                       State->LineWidth++;
+       } else {
+               g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("BMP image has bogus header data"));
+               State->read_state = READ_STATE_ERROR;
+               return FALSE;
+       }
+
+       /* Pad to a 32 bit boundary */
+       if (((State->LineWidth % 4) > 0)
+           && (State->Compressed == BI_RGB || State->Compressed == BI_BITFIELDS))
+               State->LineWidth = (State->LineWidth / 4) * 4 + 4;
+
+       if (State->pixbuf == NULL) {
+               if (State->size_func) {
+                       gint width = State->Header.width;
+                       gint height = State->Header.height;
+
+                       (*State->size_func) (&width, &height, State->user_data);
+                       if (width == 0 || height == 0) {
+                               State->read_state = READ_STATE_DONE;
+                               State->BufferSize = 0;
+                               return TRUE;
+                       }
+               }
+
+               if (State->Type == 32 || 
+                   State->Compressed == BI_RLE4 || 
+                   State->Compressed == BI_RLE8)
+                       State->pixbuf =
+                               gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
+                                              (gint) State->Header.width,
+                                              (gint) State->Header.height);
+               else
+                       State->pixbuf =
+                               gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
+                                              (gint) State->Header.width,
+                                              (gint) State->Header.height);
+               
+               if (State->pixbuf == NULL) {
+                       g_set_error_literal (error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                             _("Not enough memory to load bitmap image"));
+                       State->read_state = READ_STATE_ERROR;
+                       return FALSE;
+                       }
+               
+               if (State->prepared_func != NULL)
+                       /* Notify the client that we are ready to go */
+                       (*State->prepared_func) (State->pixbuf, NULL, State->user_data);
+               
+               /* make all pixels initially transparent */
+               if (State->Compressed == BI_RLE4 || State->Compressed == BI_RLE8) {
+                       memset (State->pixbuf->pixels, 0, State->pixbuf->rowstride * State->Header.height);
+                       State->compr.p = State->pixbuf->pixels 
+                               + State->pixbuf->rowstride * (State->Header.height- 1);
+               }
+       }
+       
+       State->BufferDone = 0;
+       if (State->Type <= 8) {
+                gint samples;
+
+               State->read_state = READ_STATE_PALETTE;
+
+               /* Allocate enough to hold the palette */
+               samples = (State->Header.size == 12 ? 3 : 4);
+               State->BufferSize = State->Header.n_colors * samples;
+
+               /* Skip over everything between the palette and the data.
+                  This protects us against a malicious BFH[10] value.
+                */
+               State->BufferPadding = (lsb_32 (&BFH[10]) - 14 - State->Header.size) - State->BufferSize;
+
+       } else if (State->Compressed == BI_RGB) {
+               if (State->BufferSize < lsb_32 (&BFH[10]))
+               {
+                       /* skip over padding between headers and image data */
+                       State->read_state = READ_STATE_HEADERS;
+                       State->BufferDone = State->BufferSize;
+                       State->BufferSize = lsb_32 (&BFH[10]);
+               }
+               else
+               {
+                       State->read_state = READ_STATE_DATA;
+                       State->BufferSize = State->LineWidth;
+               }
+       } else if (State->Compressed == BI_BITFIELDS) {
+               if (State->Header.size == 108 || State->Header.size == 124) 
+               {
+                       /* v4 and v5 have the bitmasks in the header */
+                       if (!decode_bitmasks (&BIH[40], State, error)) {
+                              State->read_state = READ_STATE_ERROR;
+                              return FALSE;
+                        }
+               }
+               else 
+               {
+                      State->read_state = READ_STATE_BITMASKS;
+                      State->BufferSize = 12;
+               }
+       } else {
+               g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("BMP image has bogus header data"));
+               State->read_state = READ_STATE_ERROR;
+               return FALSE;
+       }
+
+       if (!grow_buffer (State, error)) 
+               return FALSE;
+
+        return TRUE;
+}
+
+static gboolean DecodeColormap (guchar *buff,
+                               struct bmp_progressive_state *State,
+                               GError **error)
+{
+       gint i;
+       gint samples;
+
+       g_assert (State->read_state == READ_STATE_PALETTE);
+
+       samples = (State->Header.size == 12 ? 3 : 4);
+       if (State->BufferSize < State->Header.n_colors * samples) {
+               State->BufferSize = State->Header.n_colors * samples;
+               if (!grow_buffer (State, error))
+                       return FALSE;
+               return TRUE;
+       }
+
+       State->Colormap = g_malloc0 ((1 << State->Header.depth) * sizeof (*State->Colormap));
+       for (i = 0; i < State->Header.n_colors; i++)
+
+       {
+               State->Colormap[i][0] = buff[i * samples];
+               State->Colormap[i][1] = buff[i * samples + 1];
+               State->Colormap[i][2] = buff[i * samples + 2];
+#ifdef DUMPCMAP
+               g_print ("color %d %x %x %x\n", i,
+                        State->Colormap[i][0],
+                        State->Colormap[i][1],
+                        State->Colormap[i][2]);
+#endif
+       }
+
+       State->read_state = READ_STATE_DATA;
+
+       State->BufferDone = 0;
+       if (!(State->Compressed == BI_RGB || State->Compressed == BI_BITFIELDS))
+               State->BufferSize = 2;
+       else
+               State->BufferSize = State->LineWidth;
+       
+       if (!grow_buffer (State, error))
+               return FALSE;
+
+       return TRUE;
+}
+
+/* Finds the lowest set bit and the number of set bits */
+static void
+find_bits (int n, int *lowest, int *n_set)
+{
+       int i;
+
+       *n_set = 0;
+
+       for (i = 31; i >= 0; i--)
+               if (n & (1 << i)) {
+                       *lowest = i;
+                       (*n_set)++;
+               }
+}
+
+/* Decodes the bitmasks for BI_BITFIELDS coding */
+static gboolean
+decode_bitmasks (guchar *buf,
+                struct bmp_progressive_state *State, 
+                GError **error)
+{
+        State->a_mask = State->a_shift = State->a_bits = 0;
+       State->r_mask = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+       buf += 4;
+
+       State->g_mask = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+       buf += 4;
+
+       State->b_mask = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+
+       find_bits (State->r_mask, &State->r_shift, &State->r_bits);
+       find_bits (State->g_mask, &State->g_shift, &State->g_bits);
+       find_bits (State->b_mask, &State->b_shift, &State->b_bits);
+
+        /* v4 and v5 have an alpha mask */
+        if (State->Header.size == 108 || State->Header.size == 124) {
+             buf += 4;
+             State->a_mask = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+             find_bits (State->a_mask, &State->a_shift, &State->a_bits);
+        }
+
+       if (State->r_bits == 0 || State->g_bits == 0 || State->b_bits == 0) {
+                if (State->Type == 16) {
+                      State->r_mask = 0x7c00;
+                      State->r_shift = 10;
+                      State->g_mask = 0x03e0;
+                      State->g_shift = 5;
+                      State->b_mask = 0x001f;
+                      State->b_shift = 0;
+
+                      State->r_bits = State->g_bits = State->b_bits = 5;
+                }
+                else {
+                      State->r_mask = 0x00ff0000;
+                      State->r_shift = 16;
+                      State->g_mask = 0x0000ff00;
+                      State->g_shift = 8;
+                      State->b_mask = 0x000000ff;
+                      State->b_shift = 0;
+                      State->a_mask = 0xff000000;
+                      State->a_shift = 24;
+
+                      State->r_bits = State->g_bits = State->b_bits = State->a_bits = 8;
+                }
+       }
+
+        if (State->r_bits > 8) {
+          State->r_shift += State->r_bits - 8;
+          State->r_bits = 8;
+        }
+        if (State->g_bits > 8) {
+          State->g_shift += State->g_bits - 8;
+          State->g_bits = 8;
+        }
+        if (State->b_bits > 8) {
+          State->b_shift += State->b_bits - 8;
+          State->b_bits = 8;
+        }
+        if (State->a_bits > 8) {
+          State->a_shift += State->a_bits - 8;
+          State->a_bits = 8;
+        }
+
+       State->read_state = READ_STATE_DATA;
+       State->BufferDone = 0;
+       State->BufferSize = State->LineWidth;
+       if (!grow_buffer (State, error)) 
+               return FALSE;
+
+       return TRUE;
+}
+
+/*
+ * func - called when we have pixmap created (but no image data)
+ * user_data - passed as arg 1 to func
+ * return context (opaque to user)
+ */
+
+static gpointer
+gdk_pixbuf__bmp_image_begin_load(GdkPixbufModuleSizeFunc size_func,
+                                 GdkPixbufModulePreparedFunc prepared_func,
+                                GdkPixbufModuleUpdatedFunc updated_func,
+                                 gpointer user_data,
+                                 GError **error)
+{
+       struct bmp_progressive_state *context;
+       
+       context = g_new0(struct bmp_progressive_state, 1);
+       context->size_func = size_func;
+       context->prepared_func = prepared_func;
+       context->updated_func = updated_func;
+       context->user_data = user_data;
+
+       context->read_state = READ_STATE_HEADERS;
+
+       context->BufferSize = 26;
+       context->BufferPadding = 0;
+       context->buff = g_malloc(26);
+       context->BufferDone = 0;
+       /* 14 for the BitmapFileHeader, 12 for the BitmapImageHeader */
+
+       context->Colormap = NULL;
+
+       context->Lines = 0;
+
+       context->Type = 0;
+
+       memset(&context->Header, 0, sizeof(struct headerpair));
+       memset(&context->compr, 0, sizeof(struct bmp_compression_state));
+
+
+       context->pixbuf = NULL;
+       
+       return (gpointer) context;
+}
+
+/*
+ * context - returned from image_begin_load
+ *
+ * free context, unref gdk_pixbuf
+ */
+static gboolean gdk_pixbuf__bmp_image_stop_load(gpointer data, GError **error)
+{
+       gboolean retval = TRUE;
+       
+       struct bmp_progressive_state *context =
+           (struct bmp_progressive_state *) data;
+
+        /* FIXME this thing needs to report errors if
+         * we have unused image data
+         */
+       
+       g_return_val_if_fail(context != NULL, TRUE);
+
+       g_free(context->Colormap);
+
+       if (context->pixbuf)
+               g_object_unref(context->pixbuf);
+
+       if (context->read_state == READ_STATE_HEADERS) {
+                if (error && *error == NULL) {
+                        g_set_error_literal (error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                             _("Premature end-of-file encountered"));
+                }
+               retval = FALSE;
+       }
+       
+       g_free(context->buff);
+       g_free(context);
+
+        return retval;
+}
+
+
+/*
+The OneLineXX functions are called when 1 line worth of data is present.
+OneLine24 is the 24 bpp-version.
+*/
+static void OneLine32(struct bmp_progressive_state *context)
+{
+       int i;
+       guchar *pixels;
+       guchar *src;
+
+       if (!context->Header.Negative)
+               pixels = (context->pixbuf->pixels +
+                         context->pixbuf->rowstride * (context->Header.height - context->Lines - 1));
+       else
+               pixels = (context->pixbuf->pixels +
+                         context->pixbuf->rowstride * context->Lines);
+
+       src = context->buff;
+
+       if (context->Compressed == BI_BITFIELDS) {
+               int r_lshift, r_rshift;
+               int g_lshift, g_rshift;
+               int b_lshift, b_rshift;
+               int a_lshift, a_rshift;
+
+               r_lshift = 8 - context->r_bits;
+               g_lshift = 8 - context->g_bits;
+               b_lshift = 8 - context->b_bits;
+               a_lshift = 8 - context->a_bits;
+
+               r_rshift = context->r_bits - r_lshift;
+               g_rshift = context->g_bits - g_lshift;
+               b_rshift = context->b_bits - b_lshift;
+               a_rshift = context->a_bits - a_lshift;
+
+               for (i = 0; i < context->Header.width; i++) {
+                       unsigned int v, r, g, b, a;
+
+                       v = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+
+                       r = (v & context->r_mask) >> context->r_shift;
+                       g = (v & context->g_mask) >> context->g_shift;
+                       b = (v & context->b_mask) >> context->b_shift;
+                       a = (v & context->a_mask) >> context->a_shift;
+
+                       *pixels++ = (r << r_lshift) | (r >> r_rshift);
+                       *pixels++ = (g << g_lshift) | (g >> g_rshift);
+                       *pixels++ = (b << b_lshift) | (b >> b_rshift);
+                        if (context->a_bits)
+                         *pixels++ = (a << a_lshift) | (a >> a_rshift);
+                        else
+                          *pixels++ = 0xff;
+
+                       src += 4;
+               }
+       } else
+               for (i = 0; i < context->Header.width; i++) {
+                       *pixels++ = src[2];
+                       *pixels++ = src[1];
+                       *pixels++ = src[0];
+                       *pixels++ = 0xff;
+
+                       src += 4;
+               }
+}
+
+static void OneLine24(struct bmp_progressive_state *context)
+{
+       gint X;
+       guchar *Pixels;
+
+       X = 0;
+       if (context->Header.Negative == 0)
+               Pixels = (context->pixbuf->pixels +
+                         context->pixbuf->rowstride *
+                         (context->Header.height - context->Lines - 1));
+       else
+               Pixels = (context->pixbuf->pixels +
+                         context->pixbuf->rowstride *
+                         context->Lines);
+       while (X < context->Header.width) {
+               Pixels[X * 3 + 0] = context->buff[X * 3 + 2];
+               Pixels[X * 3 + 1] = context->buff[X * 3 + 1];
+               Pixels[X * 3 + 2] = context->buff[X * 3 + 0];
+               X++;
+       }
+
+}
+
+static void OneLine16(struct bmp_progressive_state *context)
+{
+       int i;
+       guchar *pixels;
+       guchar *src;
+
+       if (!context->Header.Negative)
+               pixels = (context->pixbuf->pixels +
+                         context->pixbuf->rowstride * (context->Header.height - context->Lines - 1));
+       else
+               pixels = (context->pixbuf->pixels +
+                         context->pixbuf->rowstride * context->Lines);
+
+       src = context->buff;
+
+       if (context->Compressed == BI_BITFIELDS) {
+               int r_lshift, r_rshift;
+               int g_lshift, g_rshift;
+               int b_lshift, b_rshift;
+
+               r_lshift = 8 - context->r_bits;
+               g_lshift = 8 - context->g_bits;
+               b_lshift = 8 - context->b_bits;
+
+               r_rshift = context->r_bits - r_lshift;
+               g_rshift = context->g_bits - g_lshift;
+               b_rshift = context->b_bits - b_lshift;
+
+               for (i = 0; i < context->Header.width; i++) {
+                       int v, r, g, b;
+
+                       v = (int) src[0] | ((int) src[1] << 8);
+
+                       r = (v & context->r_mask) >> context->r_shift;
+                       g = (v & context->g_mask) >> context->g_shift;
+                       b = (v & context->b_mask) >> context->b_shift;
+
+                       *pixels++ = (r << r_lshift) | (r >> r_rshift);
+                       *pixels++ = (g << g_lshift) | (g >> g_rshift);
+                       *pixels++ = (b << b_lshift) | (b >> b_rshift);
+
+                       src += 2;
+               }
+       } else
+               for (i = 0; i < context->Header.width; i++) {
+                       int v, r, g, b;
+
+                       v = src[0] | (src[1] << 8);
+
+                       r = (v >> 10) & 0x1f;
+                       g = (v >> 5) & 0x1f;
+                       b = v & 0x1f;
+
+                       *pixels++ = (r << 3) | (r >> 2);
+                       *pixels++ = (g << 3) | (g >> 2);
+                       *pixels++ = (b << 3) | (b >> 2);
+
+                       src += 2;
+               }
+}
+
+static void OneLine8(struct bmp_progressive_state *context)
+{
+       gint X;
+       guchar *Pixels;
+
+       X = 0;
+       if (context->Header.Negative == 0)
+               Pixels = (context->pixbuf->pixels +
+                         context->pixbuf->rowstride *
+                         (context->Header.height - context->Lines - 1));
+       else
+               Pixels = (context->pixbuf->pixels +
+                         context->pixbuf->rowstride *
+                         context->Lines);
+       while (X < context->Header.width) {
+               Pixels[X * 3 + 0] =
+                   context->Colormap[context->buff[X]][2];
+               Pixels[X * 3 + 1] =
+                   context->Colormap[context->buff[X]][1];
+               Pixels[X * 3 + 2] =
+                   context->Colormap[context->buff[X]][0];
+               X++;
+       }
+}
+
+static void OneLine4(struct bmp_progressive_state *context)
+{
+       gint X;
+       guchar *Pixels;
+
+       X = 0;
+       if (context->Header.Negative == 0)
+               Pixels = (context->pixbuf->pixels +
+                         context->pixbuf->rowstride *
+                         (context->Header.height - context->Lines - 1));
+       else
+               Pixels = (context->pixbuf->pixels +
+                         context->pixbuf->rowstride *
+                         context->Lines);
+
+       while (X < context->Header.width) {
+               guchar Pix;
+
+               Pix = context->buff[X / 2];
+
+               Pixels[X * 3 + 0] =
+                   context->Colormap[Pix >> 4][2];
+               Pixels[X * 3 + 1] =
+                   context->Colormap[Pix >> 4][1];
+               Pixels[X * 3 + 2] =
+                   context->Colormap[Pix >> 4][0];
+               X++;
+               if (X < context->Header.width) {
+                       /* Handle the other 4 bit pixel only when there is one */
+                       Pixels[X * 3 + 0] =
+                           context->Colormap[Pix & 15][2];
+                       Pixels[X * 3 + 1] =
+                           context->Colormap[Pix & 15][1];
+                       Pixels[X * 3 + 2] =
+                           context->Colormap[Pix & 15][0];
+                       X++;
+               }
+       }
+
+}
+
+static void OneLine1(struct bmp_progressive_state *context)
+{
+       gint X;
+       guchar *Pixels;
+
+       X = 0;
+       if (context->Header.Negative == 0)
+               Pixels = (context->pixbuf->pixels +
+                         context->pixbuf->rowstride *
+                         (context->Header.height - context->Lines - 1));
+       else
+               Pixels = (context->pixbuf->pixels +
+                         context->pixbuf->rowstride *
+                         context->Lines);
+       while (X < context->Header.width) {
+               gint Bit;
+
+               Bit = (context->buff[X / 8]) >> (7 - (X & 7));
+               Bit = Bit & 1;
+               Pixels[X * 3 + 0] = context->Colormap[Bit][2];
+               Pixels[X * 3 + 1] = context->Colormap[Bit][1];
+               Pixels[X * 3 + 2] = context->Colormap[Bit][0];
+               X++;
+       }
+}
+
+
+static void OneLine(struct bmp_progressive_state *context)
+{
+       context->BufferDone = 0;
+       if (context->Lines >= context->Header.height)
+               return;
+
+       if (context->Type == 32)
+               OneLine32(context);
+       else if (context->Type == 24)
+               OneLine24(context);
+       else if (context->Type == 16)
+               OneLine16(context);
+       else if (context->Type == 8)
+               OneLine8(context);
+       else if (context->Type == 4)
+               OneLine4(context);
+       else if (context->Type == 1)
+               OneLine1(context);
+       else
+               g_assert_not_reached ();
+
+       context->Lines++;
+
+       if (context->updated_func != NULL) {
+               (*context->updated_func) (context->pixbuf,
+                                         0,
+                                         (context->Header.Negative ?
+                                          (context->Lines - 1) :
+                                          (context->Header.height - context->Lines)),
+                                         context->Header.width,
+                                         1,
+                                         context->user_data);
+
+       }
+}
+
+#define NEUTRAL       0
+#define ENCODED       1
+#define ESCAPE        2   
+#define DELTA_X       3
+#define DELTA_Y       4
+#define ABSOLUTE      5
+#define SKIP          6
+
+#define END_OF_LINE   0
+#define END_OF_BITMAP 1
+#define DELTA         2
+
+static gboolean 
+DoCompressed(struct bmp_progressive_state *context, GError **error)
+{
+       gint i, j;
+       gint y;
+       guchar c;
+       gint idx;
+
+       /* context->compr.y might be past the last line because we are
+        * on padding past the end of a valid data, or we might have hit
+        * out-of-bounds data. Either way we just eat-and-ignore the
+        * rest of the file. Doing the check only here and not when
+        * we change y below is fine since BufferSize is always 2 here
+        * and the BMP file format always starts new data on 16-bit
+        * boundaries.
+        */
+       if (context->compr.y >= context->Header.height) {
+               context->BufferDone = 0;
+               return TRUE;
+       }
+
+       y = context->compr.y;
+
+       for (i = 0; i < context->BufferSize; i++) {
+               c = context->buff[i];
+               switch (context->compr.phase) {
+                   case NEUTRAL:
+                           if (c) {
+                                   context->compr.run = c;
+                                   context->compr.phase = ENCODED;
+                           }
+                           else
+                                   context->compr.phase = ESCAPE;
+                           break;
+                   case ENCODED:
+                           for (j = 0; j < context->compr.run; j++) {
+                                   if (context->Compressed == BI_RLE8)
+                                           idx = c;
+                                   else if (j & 1) 
+                                           idx = c & 0x0f;
+                                   else 
+                                           idx = (c >> 4) & 0x0f;
+                                   if (context->compr.x < context->Header.width) {
+                                           *context->compr.p++ = context->Colormap[idx][2];
+                                           *context->compr.p++ = context->Colormap[idx][1];
+                                           *context->compr.p++ = context->Colormap[idx][0];
+                                           *context->compr.p++ = 0xff;
+                                           context->compr.x++;    
+                                   }
+                           }
+                           context->compr.phase = NEUTRAL;
+                           break;
+                   case ESCAPE:
+                           switch (c) {
+                               case END_OF_LINE:
+                                       context->compr.x = 0;
+                                       context->compr.y++;
+                                       context->compr.p = context->pixbuf->pixels 
+                                               + (context->pixbuf->rowstride * (context->Header.height - context->compr.y - 1))
+                                               + (4 * context->compr.x);
+                                       context->compr.phase = NEUTRAL;
+                                       break;
+                               case END_OF_BITMAP:
+                                       context->compr.x = 0;
+                                       context->compr.y = context->Header.height;
+                                       context->compr.phase = NEUTRAL;
+                                       break;
+                               case DELTA:
+                                       context->compr.phase = DELTA_X;
+                                       break;
+                               default:
+                                       context->compr.run = c;
+                                       context->compr.count = 0;
+                                       context->compr.phase = ABSOLUTE;
+                                       break;
+                           }
+                           break;
+                   case DELTA_X:
+                           context->compr.x += c;
+                           context->compr.phase = DELTA_Y;
+                           break;
+                   case DELTA_Y:
+                           context->compr.y += c;
+                           context->compr.p = context->pixbuf->pixels 
+                                   + (context->pixbuf->rowstride * (context->Header.height - context->compr.y - 1))
+                                   + (4 * context->compr.x);
+                           context->compr.phase = NEUTRAL;
+                           break;
+                   case ABSOLUTE:
+                           if (context->Compressed == BI_RLE8) {
+                                   idx = c;
+                                   if (context->compr.x < context->Header.width) {
+                                           *context->compr.p++ = context->Colormap[idx][2];
+                                           *context->compr.p++ = context->Colormap[idx][1];
+                                           *context->compr.p++ = context->Colormap[idx][0];
+                                           *context->compr.p++ = 0xff;
+                                           context->compr.x++;    
+                                   }
+                                   context->compr.count++;
+
+                                   if (context->compr.count == context->compr.run) {
+                                           if (context->compr.run & 1)
+                                                   context->compr.phase = SKIP;
+                                           else
+                                                   context->compr.phase = NEUTRAL;
+                                   }
+                           }
+                           else {
+                                   for (j = 0; j < 2; j++) {
+                                           if (context->compr.count & 1)
+                                                   idx = c & 0x0f;
+                                           else 
+                                                   idx = (c >> 4) & 0x0f;
+                                           if (context->compr.x < context->Header.width) {
+                                                   *context->compr.p++ = context->Colormap[idx][2];
+                                                   *context->compr.p++ = context->Colormap[idx][1];
+                                                   *context->compr.p++ = context->Colormap[idx][0];
+                                                   *context->compr.p++ = 0xff;
+                                                   context->compr.x++;    
+                                           }
+                                           context->compr.count++;
+
+                                           if (context->compr.count == context->compr.run) {
+                                                   if ((context->compr.run & 3) == 1
+                                                       || (context->compr.run & 3) == 2) 
+                                                           context->compr.phase = SKIP;
+                                                   else
+                                                           context->compr.phase = NEUTRAL;
+                                                   break;
+                                           }
+                                   }
+                           }
+                           break;
+                   case SKIP:
+                           context->compr.phase = NEUTRAL;
+                           break;
+               }
+       }
+       if (context->updated_func != NULL) {
+               if (context->compr.y > y)
+               {
+                       gint new_y = MIN (context->compr.y, context->Header.height);
+                       (*context->updated_func) (context->pixbuf,
+                                                 0,
+                                                 context->Header.height - new_y,
+                                                 context->Header.width,
+                                                 new_y - y,
+                                                 context->user_data);
+               }
+
+       }
+
+       context->BufferDone = 0;
+       return TRUE;
+}
+
+/*
+ * context - from image_begin_load
+ * buf - new image data
+ * size - length of new image data
+ *
+ * append image data onto incrementally built output image
+ */
+static gboolean
+gdk_pixbuf__bmp_image_load_increment(gpointer data,
+                                     const guchar * buf,
+                                     guint size,
+                                     GError **error)
+{
+       struct bmp_progressive_state *context =
+           (struct bmp_progressive_state *) data;
+
+       gint BytesToCopy;
+       gint BytesToRemove;
+
+       if (context->read_state == READ_STATE_DONE)
+               return TRUE;
+       else if (context->read_state == READ_STATE_ERROR)
+               return FALSE;
+
+       while (size > 0) {
+               if (context->BufferDone < context->BufferSize) {        /* We still
+                                                                          have headerbytes to do */
+                       BytesToCopy =
+                           context->BufferSize - context->BufferDone;
+                       if (BytesToCopy > size)
+                               BytesToCopy = size;
+
+                       memmove(context->buff + context->BufferDone,
+                               buf, BytesToCopy);
+
+                       size -= BytesToCopy;
+                       buf += BytesToCopy;
+                       context->BufferDone += BytesToCopy;
+
+                       if (context->BufferDone != context->BufferSize)
+                               break;
+               }
+
+               /* context->buff is full.  Now we discard all "padding" */
+               if (context->BufferPadding != 0) {
+                       BytesToRemove = context->BufferPadding - size;
+                       if (BytesToRemove > size) {
+                               BytesToRemove = size;
+                       }
+                       size -= BytesToRemove;
+                       context->BufferPadding -= BytesToRemove;
+
+                       if (context->BufferPadding != 0)
+                               break;
+               }
+
+               switch (context->read_state) {
+               case READ_STATE_HEADERS:
+                       if (!DecodeHeader (context->buff,
+                                          context->buff + 14, context,
+                                          error))
+                               return FALSE;
+
+                       break;
+
+               case READ_STATE_PALETTE:
+                       if (!DecodeColormap (context->buff, context, error))
+                               return FALSE;
+                       break;
+
+               case READ_STATE_BITMASKS:
+                       if (!decode_bitmasks (context->buff, context, error))
+                               return FALSE;
+                       break;
+
+               case READ_STATE_DATA:
+                       if (context->Compressed == BI_RGB || context->Compressed == BI_BITFIELDS)
+                               OneLine (context);
+                       else if (!DoCompressed (context, error))
+                               return FALSE;
+
+                       break;
+               case READ_STATE_DONE:
+                       return TRUE;
+                       break;
+
+               default:
+                       g_assert_not_reached ();
+               }
+       }
+
+       return TRUE;
+}
+
+/* for our convenience when filling file header */
+#define put16(buf,data)        { guint16 x; \
+                         x = GUINT16_TO_LE (data); \
+                         memcpy(buf, &x, 2); \
+                         buf += 2; }
+#define put32(buf,data)        { guint32 x; \
+                         x = GUINT32_TO_LE (data); \
+                         memcpy(buf, &x, 4); \
+                         buf += 4; }
+
+static gboolean
+gdk_pixbuf__bmp_image_save_to_callback (GdkPixbufSaveFunc   save_func,
+                                       gpointer            user_data,
+                                       GdkPixbuf          *pixbuf, 
+                                       gchar             **keys,
+                                       gchar             **values,
+                                       GError            **error)
+{
+       guint width, height, channel, size, stride, src_stride, x, y;
+       guchar BFH_BIH[54], *pixels, *buf, *src, *dst, *dst_line;
+       gboolean ret;
+
+       width = gdk_pixbuf_get_width (pixbuf);
+       height = gdk_pixbuf_get_height (pixbuf);
+       channel = gdk_pixbuf_get_n_channels (pixbuf);
+       pixels = gdk_pixbuf_get_pixels (pixbuf);
+       src_stride = gdk_pixbuf_get_rowstride (pixbuf);
+       stride = (width * 3 + 3) & ~3;
+       size = stride * height;
+
+       /* filling BFH */
+       dst = BFH_BIH;
+       *dst++ = 'B';                   /* bfType */
+       *dst++ = 'M';
+       put32 (dst, size + 14 + 40);    /* bfSize */
+       put32 (dst, 0);                 /* bfReserved1 + bfReserved2 */
+       put32 (dst, 14 + 40);           /* bfOffBits */
+
+       /* filling BIH */
+       put32 (dst, 40);                /* biSize */
+       put32 (dst, width);             /* biWidth */
+       put32 (dst, height);            /* biHeight */
+       put16 (dst, 1);                 /* biPlanes */
+       put16 (dst, 24);                /* biBitCount */
+       put32 (dst, BI_RGB);            /* biCompression */
+       put32 (dst, size);              /* biSizeImage */
+       put32 (dst, 0);                 /* biXPelsPerMeter */
+       put32 (dst, 0);                 /* biYPelsPerMeter */
+       put32 (dst, 0);                 /* biClrUsed */
+       put32 (dst, 0);                 /* biClrImportant */
+
+       if (!save_func ((gchar *)BFH_BIH, 14 + 40, error, user_data))
+               return FALSE;
+
+       dst_line = buf = g_try_malloc (size);
+       if (!buf) {
+               g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                     _("Couldn't allocate memory for saving BMP file"));
+               return FALSE;
+       }
+
+       /* saving as a bottom-up bmp */
+       pixels += (height - 1) * src_stride;
+       for (y = 0; y < height; ++y, pixels -= src_stride, dst_line += stride) {
+               dst = dst_line;
+               src = pixels;
+               for (x = 0; x < width; ++x, dst += 3, src += channel) {
+                       dst[0] = src[2];
+                       dst[1] = src[1];
+                       dst[2] = src[0];
+               }
+       }
+       ret = save_func ((gchar *)buf, size, error, user_data);
+       g_free (buf);
+
+       return ret;
+}
+
+static gboolean
+save_to_file_cb (const gchar *buf,
+                gsize count,
+                GError **error,
+                gpointer data)
+{
+       gint bytes;
+       
+       while (count > 0) {
+               bytes = fwrite (buf, sizeof (gchar), count, (FILE *) data);
+               if (bytes <= 0)
+                       break;
+               count -= bytes;
+               buf += bytes;
+       }
+
+       if (count) {
+               g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_FAILED,
+                                     _("Couldn't write to BMP file"));
+               return FALSE;
+       }
+       
+       return TRUE;
+}
+
+static gboolean
+gdk_pixbuf__bmp_image_save (FILE          *f, 
+                            GdkPixbuf     *pixbuf, 
+                            gchar        **keys,
+                            gchar        **values,
+                            GError       **error)
+{
+       return gdk_pixbuf__bmp_image_save_to_callback (save_to_file_cb,
+                                                      f, pixbuf, keys,
+                                                      values, error);
+}
+
+#ifndef INCLUDE_bmp
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
+#else
+#define MODULE_ENTRY(function) void _gdk_pixbuf__bmp_ ## function
+#endif
+
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
+{
+       module->begin_load = gdk_pixbuf__bmp_image_begin_load;
+       module->stop_load = gdk_pixbuf__bmp_image_stop_load;
+       module->load_increment = gdk_pixbuf__bmp_image_load_increment;
+       module->save = gdk_pixbuf__bmp_image_save;
+       module->save_to_callback = gdk_pixbuf__bmp_image_save_to_callback;
+}
+
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
+{
+       static GdkPixbufModulePattern signature[] = {
+               { "BM", NULL, 100 },
+               { NULL, NULL, 0 }
+       };
+       static gchar * mime_types[] = {
+               "image/bmp",
+               "image/x-bmp",
+               "image/x-MS-bmp",
+               NULL
+       };
+       static gchar * extensions[] = {
+               "bmp",
+               NULL
+       };
+
+       info->name = "bmp";
+       info->signature = signature;
+       info->description = N_("The BMP image format");
+       info->mime_types = mime_types;
+       info->extensions = extensions;
+       info->flags = GDK_PIXBUF_FORMAT_WRITABLE | GDK_PIXBUF_FORMAT_THREADSAFE;
+       info->license = "LGPL";
+}
+
diff --git a/gdk-pixbuf/io-gdip-animation.c b/gdk-pixbuf/io-gdip-animation.c
new file mode 100644 (file)
index 0000000..ecd17bf
--- /dev/null
@@ -0,0 +1,330 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* GdkPixbuf library - animated gdip support
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Authors: Jonathan Blandford <jrb@redhat.com>
+ *          Havoc Pennington <hp@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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 <errno.h>
+#include "io-gdip-native.h"
+#include "io-gdip-animation.h"
+
+static void gdk_pixbuf_gdip_anim_finalize   (GObject        *object);
+
+static gboolean                gdk_pixbuf_gdip_anim_is_static_image  (GdkPixbufAnimation *animation);
+static GdkPixbuf*              gdk_pixbuf_gdip_anim_get_static_image (GdkPixbufAnimation *animation);
+
+static void                    gdk_pixbuf_gdip_anim_get_size (GdkPixbufAnimation *anim,
+                                                             int                *width,
+                                                             int                *height);
+static GdkPixbufAnimationIter* gdk_pixbuf_gdip_anim_get_iter (GdkPixbufAnimation *anim,
+                                                             const GTimeVal     *start_time);
+
+
+G_DEFINE_TYPE (GdkPixbufGdipAnim, gdk_pixbuf_gdip_anim, GDK_TYPE_PIXBUF_ANIMATION);
+
+static void
+gdk_pixbuf_gdip_anim_init (GdkPixbufGdipAnim *anim)
+{
+}
+
+static void
+gdk_pixbuf_gdip_anim_class_init (GdkPixbufGdipAnimClass *klass)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+        GdkPixbufAnimationClass *anim_class = GDK_PIXBUF_ANIMATION_CLASS (klass);
+
+        object_class->finalize = gdk_pixbuf_gdip_anim_finalize;
+
+        anim_class->is_static_image = gdk_pixbuf_gdip_anim_is_static_image;
+        anim_class->get_static_image = gdk_pixbuf_gdip_anim_get_static_image;
+        anim_class->get_size = gdk_pixbuf_gdip_anim_get_size;
+        anim_class->get_iter = gdk_pixbuf_gdip_anim_get_iter;
+}
+
+static void
+gdk_pixbuf_gdip_anim_finalize (GObject *object)
+{
+        GdkPixbufGdipAnim *gdip_anim = GDK_PIXBUF_GDIP_ANIM (object);
+
+        GList *l;
+        GdkPixbufFrame *frame;
+
+        for (l = gdip_anim->frames; l; l = l->next) {
+                frame = l->data;
+                g_object_unref (frame->pixbuf);
+                g_free (frame);
+        }
+
+        g_list_free (gdip_anim->frames);
+
+        G_OBJECT_CLASS (gdk_pixbuf_gdip_anim_parent_class)->finalize (object);
+}
+
+static gboolean
+gdk_pixbuf_gdip_anim_is_static_image  (GdkPixbufAnimation *animation)
+{
+        GdkPixbufGdipAnim *gdip_anim;
+
+        gdip_anim = GDK_PIXBUF_GDIP_ANIM (animation);
+
+        return (gdip_anim->frames != NULL &&
+                gdip_anim->frames->next == NULL);
+}
+
+static GdkPixbuf*
+gdk_pixbuf_gdip_anim_get_static_image (GdkPixbufAnimation *animation)
+{
+        GdkPixbufGdipAnim *gdip_anim;
+
+        gdip_anim = GDK_PIXBUF_GDIP_ANIM (animation);
+
+        if (gdip_anim->frames == NULL)
+                return NULL;
+        else
+                return GDK_PIXBUF (((GdkPixbufFrame*)gdip_anim->frames->data)->pixbuf);
+}
+
+static void
+gdk_pixbuf_gdip_anim_get_size (GdkPixbufAnimation *anim,
+                              int                *width,
+                              int                *height)
+{
+        GdkPixbufGdipAnim *gdip_anim;
+
+        gdip_anim = GDK_PIXBUF_GDIP_ANIM (anim);
+
+        if (width)
+                *width = gdip_anim->width;
+
+        if (height)
+                *height = gdip_anim->height;
+}
+
+
+static void
+iter_clear (GdkPixbufGdipAnimIter *iter)
+{
+        iter->current_frame = NULL;
+}
+
+static void
+iter_restart (GdkPixbufGdipAnimIter *iter)
+{
+        iter_clear (iter);
+
+        iter->current_frame = iter->gdip_anim->frames;
+}
+
+static GdkPixbufAnimationIter*
+gdk_pixbuf_gdip_anim_get_iter (GdkPixbufAnimation *anim,
+                              const GTimeVal     *start_time)
+{
+        GdkPixbufGdipAnimIter *iter;
+
+        iter = g_object_new (GDK_TYPE_PIXBUF_GDIP_ANIM_ITER, NULL);
+
+        iter->gdip_anim = GDK_PIXBUF_GDIP_ANIM (anim);
+
+        g_object_ref (iter->gdip_anim);
+
+        iter_restart (iter);
+
+        iter->start_time = *start_time;
+        iter->current_time = *start_time;
+        iter->first_loop_slowness = 0;
+
+        return GDK_PIXBUF_ANIMATION_ITER (iter);
+}
+
+static void gdk_pixbuf_gdip_anim_iter_finalize   (GObject                   *object);
+
+static int        gdk_pixbuf_gdip_anim_iter_get_delay_time             (GdkPixbufAnimationIter *iter);
+static GdkPixbuf* gdk_pixbuf_gdip_anim_iter_get_pixbuf                 (GdkPixbufAnimationIter *iter);
+static gboolean   gdk_pixbuf_gdip_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter);
+static gboolean   gdk_pixbuf_gdip_anim_iter_advance                    (GdkPixbufAnimationIter *iter,
+                                                                       const GTimeVal         *current_time);
+
+G_DEFINE_TYPE (GdkPixbufGdipAnimIter, gdk_pixbuf_gdip_anim_iter, GDK_TYPE_PIXBUF_ANIMATION_ITER);
+
+static void
+gdk_pixbuf_gdip_anim_iter_init (GdkPixbufGdipAnimIter *iter)
+{
+}
+
+static void
+gdk_pixbuf_gdip_anim_iter_class_init (GdkPixbufGdipAnimIterClass *klass)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+        GdkPixbufAnimationIterClass *anim_iter_class =
+                GDK_PIXBUF_ANIMATION_ITER_CLASS (klass);
+
+        object_class->finalize = gdk_pixbuf_gdip_anim_iter_finalize;
+
+        anim_iter_class->get_delay_time = gdk_pixbuf_gdip_anim_iter_get_delay_time;
+        anim_iter_class->get_pixbuf = gdk_pixbuf_gdip_anim_iter_get_pixbuf;
+        anim_iter_class->on_currently_loading_frame = gdk_pixbuf_gdip_anim_iter_on_currently_loading_frame;
+        anim_iter_class->advance = gdk_pixbuf_gdip_anim_iter_advance;
+}
+
+static void
+gdk_pixbuf_gdip_anim_iter_finalize (GObject *object)
+{
+        GdkPixbufGdipAnimIter *iter = GDK_PIXBUF_GDIP_ANIM_ITER (object);
+
+        iter_clear (iter);
+
+        g_object_unref (iter->gdip_anim);
+
+        G_OBJECT_CLASS (gdk_pixbuf_gdip_anim_iter_parent_class)->finalize (object);
+}
+
+static gboolean
+gdk_pixbuf_gdip_anim_iter_advance (GdkPixbufAnimationIter *anim_iter,
+                                  const GTimeVal         *current_time)
+{
+        GdkPixbufGdipAnimIter *iter;
+        gint elapsed;
+        gint loop;
+        GList *tmp;
+        GList *old;
+
+        iter = GDK_PIXBUF_GDIP_ANIM_ITER (anim_iter);
+
+        iter->current_time = *current_time;
+
+        /* We use milliseconds for all times */
+        elapsed =
+          (((iter->current_time.tv_sec - iter->start_time.tv_sec) * G_USEC_PER_SEC +
+            iter->current_time.tv_usec - iter->start_time.tv_usec)) / 1000;
+
+        if (elapsed < 0) {
+                /* Try to compensate; probably the system clock
+                 * was set backwards
+                 */
+                iter->start_time = iter->current_time;
+                elapsed = 0;
+        }
+
+        g_assert (iter->gdip_anim->total_time > 0);
+
+        /* See how many times we've already played the full animation,
+         * and subtract time for that.
+         */
+
+        if (iter->gdip_anim->loading)
+                loop = 0;
+        else {
+                /* If current_frame is NULL at this point, we have loaded the
+                 * animation from a source which fell behind the speed of the 
+                 * display. We remember how much slower the first loop was due
+                 * to this and correct the position calculation in order to not
+                 * jump in the middle of the second loop.
+                 */
+                if (iter->current_frame == NULL)
+                        iter->first_loop_slowness = MAX(0, elapsed - iter->gdip_anim->total_time);
+
+                loop = (elapsed - iter->first_loop_slowness) / iter->gdip_anim->total_time;
+                elapsed = (elapsed - iter->first_loop_slowness) % iter->gdip_anim->total_time;
+        }
+
+        iter->position = elapsed;
+
+        /* Now move to the proper frame */
+        if (iter->gdip_anim->loop == 0 || loop < iter->gdip_anim->loop)
+                tmp = iter->gdip_anim->frames;
+        else
+                tmp = NULL;
+        while (tmp != NULL) {
+                GdkPixbufFrame *frame = tmp->data;
+
+                if (iter->position >= frame->elapsed &&
+                    iter->position < (frame->elapsed + frame->delay_time))
+                        break;
+
+                tmp = tmp->next;
+        }
+
+        old = iter->current_frame;
+
+        iter->current_frame = tmp;
+
+        return iter->current_frame != old;
+}
+
+int
+gdk_pixbuf_gdip_anim_iter_get_delay_time (GdkPixbufAnimationIter *anim_iter)
+{
+        GdkPixbufFrame *frame;
+        GdkPixbufGdipAnimIter *iter;
+
+        iter = GDK_PIXBUF_GDIP_ANIM_ITER (anim_iter);
+
+        if (iter->current_frame) {
+                frame = iter->current_frame->data;
+
+#if 0
+                g_print ("frame start: %d pos: %d frame len: %d frame remaining: %d\n",
+                         frame->elapsed,
+                         iter->position,
+                         frame->delay_time,
+                         frame->delay_time - (iter->position - frame->elapsed));
+#endif
+
+                return frame->delay_time - (iter->position - frame->elapsed);
+        } else
+                return -1; /* show last frame forever */
+}
+
+GdkPixbuf*
+gdk_pixbuf_gdip_anim_iter_get_pixbuf (GdkPixbufAnimationIter *anim_iter)
+{
+        GdkPixbufGdipAnimIter *iter;
+        GdkPixbufFrame *frame;
+
+        iter = GDK_PIXBUF_GDIP_ANIM_ITER (anim_iter);
+
+        frame = iter->current_frame ? iter->current_frame->data : g_list_last (iter->gdip_anim->frames)->data;
+
+#if 0
+        if (FALSE && frame)
+          g_print ("current frame %d dispose mode %d  %d x %d\n",
+                   g_list_index (iter->gdip_anim->frames,
+                                 frame),
+                   frame->action,
+                   gdk_pixbuf_get_width (frame->pixbuf),
+                   gdk_pixbuf_get_height (frame->pixbuf));
+#endif
+
+        if (frame == NULL)
+                return NULL;
+
+        return frame->pixbuf;
+}
+
+static gboolean
+gdk_pixbuf_gdip_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *anim_iter)
+{
+        GdkPixbufGdipAnimIter *iter;
+
+        iter = GDK_PIXBUF_GDIP_ANIM_ITER (anim_iter);
+
+        return iter->current_frame == NULL || iter->current_frame->next == NULL;
+}
diff --git a/gdk-pixbuf/io-gdip-animation.h b/gdk-pixbuf/io-gdip-animation.h
new file mode 100644 (file)
index 0000000..01e8278
--- /dev/null
@@ -0,0 +1,117 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* GdkPixbuf library - GDIP loader declarations
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Authors: Mark Crichton <crichton@gimp.org>
+ *          Miguel de Icaza <miguel@gnu.org>
+ *          Federico Mena-Quintero <federico@gimp.org>
+ *          Havoc Pennington <hp@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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_GDIP_H
+#define GDK_PIXBUF_GDIP_H
+
+#include <gdk-pixbuf/gdk-pixbuf-animation.h>
+
+typedef struct _GdkPixbufGdipAnim GdkPixbufGdipAnim;
+typedef struct _GdkPixbufGdipAnimClass GdkPixbufGdipAnimClass;
+typedef struct _GdkPixbufFrame GdkPixbufFrame;
+
+#define GDK_TYPE_PIXBUF_GDIP_ANIM              (gdk_pixbuf_gdip_anim_get_type ())
+#define GDK_PIXBUF_GDIP_ANIM(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_GDIP_ANIM, GdkPixbufGdipAnim))
+#define GDK_IS_PIXBUF_GDIP_ANIM(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_GDIP_ANIM))
+
+#define GDK_PIXBUF_GDIP_ANIM_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_GDIP_ANIM, GdkPixbufGdipAnimClass))
+#define GDK_IS_PIXBUF_GDIP_ANIM_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_GDIP_ANIM))
+#define GDK_PIXBUF_GDIP_ANIM_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_GDIP_ANIM, GdkPixbufGdipAnimClass))
+
+/* Private part of the GdkPixbufGdipAnim structure */
+struct _GdkPixbufGdipAnim {
+        GdkPixbufAnimation parent_instance;
+
+        /* Number of frames */
+        int n_frames;
+
+        /* Total length of animation */
+        int total_time;
+        
+       /* List of GdkPixbufFrame structures */
+        GList *frames;
+
+       /* bounding box size */
+       int width, height;
+        
+        int loop;
+        gboolean loading;
+};
+
+struct _GdkPixbufGdipAnimClass {
+        GdkPixbufAnimationClass parent_class;
+        
+};
+
+GType gdk_pixbuf_gdip_anim_get_type (void) G_GNUC_CONST;
+
+typedef struct _GdkPixbufGdipAnimIter GdkPixbufGdipAnimIter;
+typedef struct _GdkPixbufGdipAnimIterClass GdkPixbufGdipAnimIterClass;
+
+
+#define GDK_TYPE_PIXBUF_GDIP_ANIM_ITER              (gdk_pixbuf_gdip_anim_iter_get_type ())
+#define GDK_PIXBUF_GDIP_ANIM_ITER(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_GDIP_ANIM_ITER, GdkPixbufGdipAnimIter))
+#define GDK_IS_PIXBUF_GDIP_ANIM_ITER(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_GDIP_ANIM_ITER))
+
+#define GDK_PIXBUF_GDIP_ANIM_ITER_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_GDIP_ANIM_ITER, GdkPixbufGdipAnimIterClass))
+#define GDK_IS_PIXBUF_GDIP_ANIM_ITER_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_GDIP_ANIM_ITER))
+#define GDK_PIXBUF_GDIP_ANIM_ITER_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_GDIP_ANIM_ITER, GdkPixbufGdipAnimIterClass))
+
+struct _GdkPixbufGdipAnimIter {
+        GdkPixbufAnimationIter parent_instance;
+        
+        GdkPixbufGdipAnim   *gdip_anim;
+
+        GTimeVal            start_time;
+        GTimeVal            current_time;
+
+        /* Time in milliseconds into this run of the animation */
+        gint                position;
+        
+        GList              *current_frame;
+        
+        gint                first_loop_slowness;
+};
+
+struct _GdkPixbufGdipAnimIterClass {
+        GdkPixbufAnimationIterClass parent_class;
+
+};
+
+GType gdk_pixbuf_gdip_anim_iter_get_type (void) G_GNUC_CONST;
+
+struct _GdkPixbufFrame {
+       /* The pixbuf with this frame's image data */
+       GdkPixbuf *pixbuf;
+
+       /* Frame duration in ms */
+       int delay_time;
+
+        /* Sum of preceding delay times */
+        int elapsed;        
+};
+
+#endif
diff --git a/gdk-pixbuf/io-gdip-bmp.c b/gdk-pixbuf/io-gdip-bmp.c
new file mode 100644 (file)
index 0000000..40f6a5f
--- /dev/null
@@ -0,0 +1,87 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\r
+/* GdkPixbuf library - Win32 GDI+ Pixbuf Loader\r
+ *\r
+ * Copyright (C) 2008 Dominic Lachowicz\r
+ * Copyright (C) 2008 Alberto Ruiz\r
+ *\r
+ * Authors: Dominic Lachowicz <domlachowicz@gmail.com>\r
+ *          Alberto Ruiz <aruiz@gnome.org>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2 of the License, or (at your option) any later version.\r
+ *\r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more  * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the\r
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,\r
+ * Boston, MA 02111-1307, USA.\r
+ */\r
+\r
+#include "io-gdip-utils.h"\r
+\r
+static gboolean\r
+gdk_pixbuf__gdip_image_save_BMP_to_callback (GdkPixbufSaveFunc   save_func,\r
+                                             gpointer            user_data,\r
+                                             GdkPixbuf          *pixbuf,\r
+                                             gchar             **keys,\r
+                                             gchar             **values,\r
+                                             GError            **error)\r
+{\r
+  return gdip_save_pixbuf (pixbuf, L"image/bmp", NULL, save_func, user_data, error);\r
+}\r
+\r
+static gboolean\r
+gdk_pixbuf__gdip_image_save_BMP (FILE          *f,\r
+                                 GdkPixbuf     *pixbuf,\r
+                                 gchar        **keys,\r
+                                 gchar        **values,\r
+                                 GError       **error)\r
+{\r
+  return gdk_pixbuf__gdip_image_save_BMP_to_callback (gdip_save_to_file_callback, f, pixbuf, keys, values, error);\r
+}\r
+\r
+#ifndef INCLUDE_gdiplus\r
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function\r
+#else\r
+#define MODULE_ENTRY(function) void _gdk_pixbuf__gdip_bmp_ ## function\r
+#endif\r
+\r
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)\r
+{\r
+  gdip_fill_vtable (module);\r
+\r
+  module->save_to_callback = gdk_pixbuf__gdip_image_save_BMP_to_callback;\r
+  module->save = gdk_pixbuf__gdip_image_save_BMP; /* for gtk < 2.14, you need to implement both. otherwise gdk-pixbuf-queryloaders fails */\r
+}\r
+\r
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)\r
+{\r
+  static GdkPixbufModulePattern signature[] = {\r
+    { "BM", NULL, 100 }, /* BMP */\r
+    { NULL, NULL, 0 }\r
+  };\r
+\r
+  static gchar *mime_types[] = {\r
+    "image/bmp",\r
+    "image/x-bmp",\r
+    "image/x-MS-bmp",\r
+    NULL\r
+  };\r
+\r
+  static gchar *extensions[] = {\r
+    "bmp",\r
+    NULL\r
+  };\r
+\r
+  info->name        = "bmp";\r
+  info->signature   = signature;\r
+  info->description = _("The BMP image format");\r
+  info->mime_types  = mime_types;\r
+  info->extensions  = extensions;\r
+  info->flags       = GDK_PIXBUF_FORMAT_WRITABLE | GDK_PIXBUF_FORMAT_THREADSAFE;\r
+  info->license     = "LGPL";\r
+}\r
diff --git a/gdk-pixbuf/io-gdip-emf.c b/gdk-pixbuf/io-gdip-emf.c
new file mode 100644 (file)
index 0000000..07ee0b0
--- /dev/null
@@ -0,0 +1,64 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* GdkPixbuf library - Win32 GDI+ Pixbuf Loader
+ *
+ * Copyright (C) 2008 Dominic Lachowicz
+ * Copyright (C) 2008 Alberto Ruiz
+ *
+ * Authors: Dominic Lachowicz <domlachowicz@gmail.com>
+ *          Alberto Ruiz <aruiz@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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  * You should have received a copy of the GNU Lesser 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 "io-gdip-utils.h"
+
+#ifndef INCLUDE_gdiplus
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
+#else
+#define MODULE_ENTRY(function) void _gdk_pixbuf__gdip_emf_ ## function
+#endif
+
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
+{
+  gdip_fill_vector_vtable (module);
+}
+
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
+{
+  static GdkPixbufModulePattern signature[] = {
+    { "\x01\x00\x00\x00", NULL, 100 }, /* EMF */
+    { NULL, NULL, 0 }
+  };
+
+  static gchar *mime_types[] = {
+    "application/emf",
+    "application/x-emf",
+    "image/x-emf",
+    "image/x-mgx-emf",
+    NULL
+  };
+
+  static gchar *extensions[] = {
+    "emf",
+    NULL
+  };
+
+  info->name        = "emf";
+  info->signature   = signature;
+  info->description = _("The EMF image format");
+  info->mime_types  = mime_types;
+  info->extensions  = extensions;
+  info->flags       = GDK_PIXBUF_FORMAT_THREADSAFE;
+  info->license     = "LGPL";
+}
diff --git a/gdk-pixbuf/io-gdip-gif.c b/gdk-pixbuf/io-gdip-gif.c
new file mode 100644 (file)
index 0000000..f991a9d
--- /dev/null
@@ -0,0 +1,85 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\r
+/* GdkPixbuf library - Win32 GDI+ Pixbuf Loader\r
+ *\r
+ * Copyright (C) 2008 Dominic Lachowicz\r
+ * Copyright (C) 2008 Alberto Ruiz\r
+ *\r
+ * Authors: Dominic Lachowicz <domlachowicz@gmail.com>\r
+ *          Alberto Ruiz <aruiz@gnome.org>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2 of the License, or (at your option) any later version.\r
+ *\r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more  * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the\r
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,\r
+ * Boston, MA 02111-1307, USA.\r
+ */\r
+\r
+#include "io-gdip-utils.h"\r
+\r
+static gboolean\r
+gdk_pixbuf__gdip_image_save_GIF_to_callback (GdkPixbufSaveFunc   save_func,\r
+                                             gpointer            user_data,\r
+                                             GdkPixbuf          *pixbuf,\r
+                                             gchar             **keys,\r
+                                             gchar             **values,\r
+                                             GError            **error)\r
+{\r
+  return gdip_save_pixbuf (pixbuf, L"image/gif", NULL, save_func, user_data, error);\r
+}\r
+\r
+static gboolean\r
+gdk_pixbuf__gdip_image_save_GIF (FILE          *f,\r
+                                 GdkPixbuf     *pixbuf,\r
+                                 gchar        **keys,\r
+                                 gchar        **values,\r
+                                 GError       **error)\r
+{\r
+  return gdk_pixbuf__gdip_image_save_GIF_to_callback (gdip_save_to_file_callback, f, pixbuf, keys, values, error);\r
+}\r
+\r
+#ifndef INCLUDE_gdiplus\r
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function\r
+#else\r
+#define MODULE_ENTRY(function) void _gdk_pixbuf__gdip_gif_ ## function\r
+#endif\r
+\r
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)\r
+{\r
+  gdip_fill_vtable (module);\r
+\r
+  module->save_to_callback = gdk_pixbuf__gdip_image_save_GIF_to_callback;\r
+  module->save = gdk_pixbuf__gdip_image_save_GIF; /* for gtk < 2.14, you need to implement both. otherwise gdk-pixbuf-queryloaders fails */\r
+}\r
+\r
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)\r
+{\r
+  static GdkPixbufModulePattern signature[] = {\r
+    { "GIF8", NULL, 100 }, /* GIF */\r
+    { NULL, NULL, 0 }\r
+  };\r
+\r
+  static gchar *mime_types[] = {\r
+    "image/gif",\r
+    NULL\r
+  };\r
+\r
+  static gchar *extensions[] = {\r
+    "gif",\r
+    NULL\r
+  };\r
+\r
+  info->name        = "gif";\r
+  info->signature   = signature;\r
+  info->description = _("The GIF image format");\r
+  info->mime_types  = mime_types;\r
+  info->extensions  = extensions;\r
+  info->flags       = GDK_PIXBUF_FORMAT_WRITABLE | GDK_PIXBUF_FORMAT_THREADSAFE;\r
+  info->license     = "LGPL";\r
+}\r
diff --git a/gdk-pixbuf/io-gdip-ico.c b/gdk-pixbuf/io-gdip-ico.c
new file mode 100644 (file)
index 0000000..8538b58
--- /dev/null
@@ -0,0 +1,64 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* GdkPixbuf library - Win32 GDI+ Pixbuf Loader
+ *
+ * Copyright (C) 2008 Dominic Lachowicz
+ * Copyright (C) 2008 Alberto Ruiz
+ *
+ * Authors: Dominic Lachowicz <domlachowicz@gmail.com>
+ *          Alberto Ruiz <aruiz@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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  * You should have received a copy of the GNU Lesser 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 "io-gdip-utils.h"
+
+#ifndef INCLUDE_gdiplus
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
+#else
+#define MODULE_ENTRY(function) void _gdk_pixbuf__gdip_ico_ ## function
+#endif
+
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
+{
+  gdip_fill_vtable (module);
+}
+
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
+{
+  static GdkPixbufModulePattern signature[] = {
+    { "  \x1   ", "zz znz", 100 }, /* ICO */
+    { "  \x2   ", "zz znz", 100 }, /* ICO */
+    { NULL, NULL, 0 }
+  };
+
+  static gchar *mime_types[] = {
+    "image/x-icon",
+    "image/x-ico",
+    NULL
+  };
+
+  static gchar *extensions[] = {
+    "ico",
+    "cur",
+    NULL
+  };
+
+  info->name        = "ico";
+  info->signature   = signature;
+  info->description = _("The ICO image format");
+  info->mime_types  = mime_types;
+  info->extensions  = extensions;
+  info->flags       = GDK_PIXBUF_FORMAT_THREADSAFE;
+  info->license     = "LGPL";
+}
diff --git a/gdk-pixbuf/io-gdip-jpeg.c b/gdk-pixbuf/io-gdip-jpeg.c
new file mode 100644 (file)
index 0000000..8bd3058
--- /dev/null
@@ -0,0 +1,141 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\r
+/* GdkPixbuf library - Win32 GDI+ Pixbuf Loader\r
+ *\r
+ * Copyright (C) 2008 Dominic Lachowicz\r
+ * Copyright (C) 2008 Alberto Ruiz\r
+ *\r
+ * Authors: Dominic Lachowicz <domlachowicz@gmail.com>\r
+ *          Alberto Ruiz <aruiz@gnome.org>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2 of the License, or (at your option) any later version.\r
+ *\r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more  * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the\r
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,\r
+ * Boston, MA 02111-1307, USA.\r
+ */\r
+\r
+#define INITGUID\r
+#include "io-gdip-utils.h"\r
+\r
+DEFINE_GUID(EncoderQuality, 0x1d5be4b5,0xfa4a,0x452d,0x9c,0xdd,0x5d,0xb3,0x51,0x05,0xe7,0xeb);\r
+\r
+static gboolean\r
+gdk_pixbuf__gdip_image_save_JPEG_to_callback (GdkPixbufSaveFunc   save_func,\r
+                                              gpointer            user_data,\r
+                                              GdkPixbuf          *pixbuf,\r
+                                              gchar             **keys,\r
+                                              gchar             **values,\r
+                                              GError            **error)\r
+{\r
+  EncoderParameters encoder_params;\r
+  LONG quality = 75; /* default; must be between 0 and 100 */\r
+\r
+  if (keys && *keys) {\r
+    gchar **kiter = keys;\r
+    gchar **viter = values;\r
+    \r
+    while (*kiter) {\r
+      if (strcmp (*kiter, "quality") == 0) {\r
+        char *endptr = NULL;\r
+        quality = strtol (*viter, &endptr, 10);\r
+        \r
+        if (endptr == *viter) {\r
+          g_set_error (error,\r
+                       GDK_PIXBUF_ERROR,\r
+                       GDK_PIXBUF_ERROR_BAD_OPTION,\r
+                       _("JPEG quality must be a value between 0 and 100; value '%s' could not be parsed."),\r
+                       *viter);\r
+          \r
+          return FALSE;\r
+        }\r
+        \r
+        if (quality < 0 ||\r
+            quality > 100) {\r
+          /* This is a user-visible error;\r
+           * lets people skip the range-checking\r
+           * in their app.\r
+           */\r
+          g_set_error (error,\r
+                       GDK_PIXBUF_ERROR,\r
+                       GDK_PIXBUF_ERROR_BAD_OPTION,\r
+                       _("JPEG quality must be a value between 0 and 100; value '%d' is not allowed."),\r
+                       (int)quality);\r
+          \r
+          return FALSE;\r
+        }\r
+      } else {\r
+        g_warning ("Unrecognized parameter (%s) passed to JPEG saver.", *kiter);\r
+      }\r
+      \r
+      ++kiter;\r
+      ++viter;\r
+    }\r
+  }\r
+\r
+  encoder_params.Count = 1;\r
+  encoder_params.Parameter[0].Guid = EncoderQuality;\r
+  encoder_params.Parameter[0].Type = EncoderParameterValueTypeLong;\r
+  encoder_params.Parameter[0].NumberOfValues = 1;\r
+  encoder_params.Parameter[0].Value = &quality;\r
+     \r
+  return gdip_save_pixbuf (pixbuf, L"image/jpeg", &encoder_params, save_func, user_data, error);\r
+}\r
+\r
+static gboolean\r
+gdk_pixbuf__gdip_image_save_JPEG (FILE         *f,\r
+                                 GdkPixbuf     *pixbuf,\r
+                                 gchar        **keys,\r
+                                 gchar        **values,\r
+                                 GError       **error)\r
+{\r
+  return gdk_pixbuf__gdip_image_save_JPEG_to_callback (gdip_save_to_file_callback, f, pixbuf, keys, values, error);\r
+}\r
+\r
+#ifndef INCLUDE_gdiplus\r
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function\r
+#else\r
+#define MODULE_ENTRY(function) void _gdk_pixbuf__gdip_jpeg_ ## function\r
+#endif\r
+\r
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)\r
+{\r
+  gdip_fill_vtable (module);\r
+\r
+  module->save_to_callback = gdk_pixbuf__gdip_image_save_JPEG_to_callback;\r
+  module->save = gdk_pixbuf__gdip_image_save_JPEG; /* for gtk < 2.14, you need to implement both. otherwise gdk-pixbuf-queryloaders fails */\r
+}\r
+\r
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)\r
+{\r
+  static GdkPixbufModulePattern signature[] = {\r
+    { "\xff\xd8", NULL, 100 }, /* JPEG */\r
+    { NULL, NULL, 0 }\r
+  };\r
+\r
+  static gchar *mime_types[] = {\r
+    "image/jpeg",\r
+    NULL\r
+  };\r
+\r
+  static gchar *extensions[] = {\r
+    "jpeg",\r
+    "jpe",\r
+    "jpg",\r
+    NULL\r
+  };\r
+\r
+  info->name        = "jpeg";\r
+  info->signature   = signature;\r
+  info->description = _("The JPEG image format");\r
+  info->mime_types  = mime_types;\r
+  info->extensions  = extensions;\r
+  info->flags       = GDK_PIXBUF_FORMAT_WRITABLE | GDK_PIXBUF_FORMAT_THREADSAFE;\r
+  info->license     = "LGPL";\r
+}\r
diff --git a/gdk-pixbuf/io-gdip-native.h b/gdk-pixbuf/io-gdip-native.h
new file mode 100644 (file)
index 0000000..417a747
--- /dev/null
@@ -0,0 +1,255 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* GdkPixbuf library - Win32 GDI+ Pixbuf Loader
+ *
+ * Copyright (C) 2007 Google (Evan Stade)
+ * Copyright (C) 2008 Alberto Ruiz <aruiz@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _HAVE_IO_GDIP_NATIVE_H
+#define _HAVE_IO_GDIP_NATIVE_H
+
+#include <windows.h>
+
+#include <glib.h>
+
+/* //////////// Native API ///////////// */
+
+#define WINGDIPAPI __stdcall
+
+typedef gulong ARGB;
+typedef gint PixelFormat;
+
+typedef enum {
+    EncoderParameterValueTypeByte = 1,
+    EncoderParameterValueTypeASCII = 2,
+    EncoderParameterValueTypeShort = 3,
+    EncoderParameterValueTypeLong = 4,
+    EncoderParameterValueTypeRational = 5,
+    EncoderParameterValueTypeLongRange = 6,
+    EncoderParameterValueTypeUndefined = 7,
+    EncoderParameterValueTypeRationalRange = 8,
+    EncoderParameterValueTypePointer = 9
+} EncoderParameterValueType;
+
+#define    PixelFormatIndexed   0x00010000
+#define    PixelFormatGDI       0x00020000
+#define    PixelFormatAlpha     0x00040000
+#define    PixelFormatPAlpha    0x00080000
+#define    PixelFormatExtended  0x00100000
+#define    PixelFormatCanonical 0x00200000
+
+#define    PixelFormatUndefined 0
+#define    PixelFormatDontCare  0
+
+#define    PixelFormat1bppIndexed       (1 | ( 1 << 8) | PixelFormatIndexed | PixelFormatGDI)
+#define    PixelFormat4bppIndexed       (2 | ( 4 << 8) | PixelFormatIndexed | PixelFormatGDI)
+#define    PixelFormat8bppIndexed       (3 | ( 8 << 8) | PixelFormatIndexed | PixelFormatGDI)
+#define    PixelFormat16bppGrayScale    (4 | (16 << 8) | PixelFormatExtended)
+#define    PixelFormat16bppRGB555       (5 | (16 << 8) | PixelFormatGDI)
+#define    PixelFormat16bppRGB565       (6 | (16 << 8) | PixelFormatGDI)
+#define    PixelFormat16bppARGB1555     (7 | (16 << 8) | PixelFormatAlpha | PixelFormatGDI)
+#define    PixelFormat24bppRGB          (8 | (24 << 8) | PixelFormatGDI)
+#define    PixelFormat32bppRGB          (9 | (32 << 8) | PixelFormatGDI)
+#define    PixelFormat32bppARGB         (10 | (32 << 8) | PixelFormatAlpha | PixelFormatGDI | PixelFormatCanonical)
+#define    PixelFormat32bppPARGB        (11 | (32 << 8) | PixelFormatAlpha | PixelFormatPAlpha | PixelFormatGDI)
+#define    PixelFormat48bppRGB          (12 | (48 << 8) | PixelFormatExtended)
+#define    PixelFormat64bppARGB         (13 | (64 << 8) | PixelFormatAlpha  | PixelFormatCanonical | PixelFormatExtended)
+#define    PixelFormat64bppPARGB        (14 | (64 << 8) | PixelFormatAlpha  | PixelFormatPAlpha | PixelFormatExtended)
+#define    PixelFormatMax               15
+
+enum _Status
+{
+    Ok                          = 0,
+    GenericError                = 1,
+    InvalidParameter            = 2,
+    OutOfMemory                 = 3,
+    ObjectBusy                  = 4,
+    InsufficientBuffer          = 5,
+    NotImplemented              = 6,
+    Win32Error                  = 7,
+    WrongState                  = 8,
+    Aborted                     = 9,
+    FileNotFound                = 10,
+    ValueOverflow               = 11,
+    AccessDenied                = 12,
+    UnknownImageFormat          = 13,
+    FontFamilyNotFound          = 14,
+    FontStyleNotFound           = 15,
+    NotTrueTypeFont             = 16,
+    UnsupportedGdiplusVersion   = 17,
+    GdiplusNotInitialized       = 18,
+    PropertyNotFound            = 19,
+    PropertyNotSupported        = 20,
+    ProfileNotFound             = 21
+};
+typedef enum _Status Status;
+typedef enum _Status GpStatus;
+
+typedef enum {
+    ImageFlagsNone = 0,
+    ImageFlagsScalable = 0x0001,
+    ImageFlagsHasAlpha = 0x0002,
+    ImageFlagsHasTranslucent = 0x0004,
+    ImageFlagsPartiallyScalable = 0x0008,
+    ImageFlagsColorSpaceRGB = 0x0010,
+    ImageFlagsColorSpaceCMYK = 0x0020,
+    ImageFlagsColorSpaceGRAY = 0x0040,
+    ImageFlagsColorSpaceYCBCR = 0x0080,
+    ImageFlagsColorSpaceYCCK = 0x0100,
+    ImageFlagsHasRealDPI = 0x1000,
+    ImageFlagsHasRealPixelSize = 0x2000,
+    ImageFlagsReadOnly = 0x00010000,
+    ImageFlagsCaching = 0x00020000
+} ImageFlags;
+
+enum _ImageLockMode
+{
+    ImageLockModeRead           = 1,
+    ImageLockModeWrite          = 2,
+    ImageLockModeUserInputBuf   = 4
+};
+typedef enum _ImageLockMode ImageLockMode;
+
+enum _ImageType
+{
+    ImageTypeUnknown,
+    ImageTypeBitmap,
+    ImageTypeMetafile
+};
+typedef enum _ImageType ImageType;
+
+typedef struct _GpImage GpImage;
+typedef struct _GpBitmap GpBitmap;
+typedef struct _GpGraphics GpGraphics;
+
+struct _GdiplusStartupInput
+{
+    UINT32 GdiplusVersion;
+    gpointer DebugEventCallback;
+    BOOL SuppressBackgroundThread;
+    BOOL SuppressExternalCodecs;
+};
+typedef struct _GdiplusStartupInput GdiplusStartupInput;
+
+struct _PropItem
+{
+  ULONG id;
+  ULONG length;
+  WORD type;
+  VOID *value;
+};
+typedef struct _PropItem PropertyItem;
+
+struct _EncoderParameter
+{
+    GUID    Guid;
+    ULONG   NumberOfValues;
+    ULONG   Type;
+    VOID*   Value;
+};
+typedef struct _EncoderParameter EncoderParameter;
+
+struct _EncoderParameters
+{
+    UINT Count;                      /* Number of parameters in this structure */
+    EncoderParameter Parameter[1];   /* Parameter values */
+};
+typedef struct _EncoderParameters EncoderParameters;
+
+struct _ImageCodecInfo
+{
+    CLSID Clsid;
+    GUID  FormatID;
+    const WCHAR* CodecName;
+    const WCHAR* DllName;
+    const WCHAR* FormatDescription;
+    const WCHAR* FilenameExtension;
+    const WCHAR* MimeType;
+    DWORD Flags;
+    DWORD Version;
+    DWORD SigCount;
+    DWORD SigSize;
+    const BYTE* SigPattern;
+    const BYTE* SigMask;
+};
+typedef struct _ImageCodecInfo ImageCodecInfo;
+
+struct _BitmapData
+{
+    UINT Width;
+    UINT Height;
+    INT Stride;
+    PixelFormat PixelFormat;
+    VOID* Scan0;
+    UINT_PTR Reserved;
+};
+typedef struct _BitmapData BitmapData;
+
+struct _GpRect
+{
+    INT X;
+    INT Y;
+    INT Width;
+    INT Height;
+};
+typedef struct _GpRect GpRect;
+
+#ifndef IStream_Release
+#define IStream_Release(This) (This)->lpVtbl->Release(This)
+#endif
+
+#ifndef IStream_Seek
+#define IStream_Seek(This,dlibMove,dwOrigin,plibNewPosition) (This)->lpVtbl->Seek(This,dlibMove,dwOrigin,plibNewPosition)
+#endif
+
+#ifndef IStream_Read
+#define IStream_Read(This,pv,cb,pcbRead) (This)->lpVtbl->Read(This,pv,cb,pcbRead)
+#endif
+
+#ifndef IStream_SetSize
+#define IStream_SetSize(This,size) (This)->lpVtbl->SetSize(This,size)
+#endif
+
+GpStatus WINGDIPAPI GdiplusStartup (gpointer, const gpointer, gpointer);
+GpStatus WINGDIPAPI GdipCreateBitmapFromStream (gpointer, GpBitmap**);
+GpStatus WINGDIPAPI GdipBitmapGetPixel (GpBitmap*, gint x, gint y, ARGB*);
+GpStatus WINGDIPAPI GdipGetImageWidth (GpImage*, guint*);
+GpStatus WINGDIPAPI GdipGetImageHeight (GpImage*, guint*);
+GpStatus WINGDIPAPI GdipDisposeImage (GpImage*);
+GpStatus WINGDIPAPI GdipGetImageFlags (GpImage *, guint*);
+GpStatus WINGDIPAPI GdipImageGetFrameCount (GpImage *image, const GUID* dimensionID, UINT* count);
+GpStatus WINGDIPAPI GdipImageSelectActiveFrame (GpImage *image, const GUID* dimensionID, UINT frameIndex);
+GpStatus WINGDIPAPI GdipGetPropertyItemSize (GpImage *image, int propId, guint* size);
+GpStatus WINGDIPAPI GdipGetPropertyItem (GpImage *image, int propId, guint propSize, PropertyItem* buffer);
+GpStatus WINGDIPAPI GdipCreateBitmapFromScan0 (INT width, INT height, INT stride, PixelFormat format, BYTE* scan0, 
+                                               GpBitmap** bitmap);
+GpStatus WINGDIPAPI GdipSaveImageToStream (GpImage *image, IStream* stream, const CLSID* clsidEncoder, 
+                                           const EncoderParameters* encoderParams);
+GpStatus WINGDIPAPI GdipGetImageEncoders (UINT numEncoders, UINT size, ImageCodecInfo *encoders);
+GpStatus WINGDIPAPI GdipGetImageEncodersSize (UINT *numEncoders, UINT *size);
+GpStatus WINGDIPAPI GdipBitmapSetPixel (GpBitmap* bitmap, INT x, INT y, ARGB color);
+GpStatus WINGDIPAPI GdipDrawImageI (GpGraphics *graphics, GpImage *image, INT x, INT y);
+GpStatus WINGDIPAPI GdipGetImageGraphicsContext (GpImage *image, GpGraphics **graphics);
+GpStatus WINGDIPAPI GdipFlush (GpGraphics *graphics, INT intention);
+GpStatus WINGDIPAPI GdipGraphicsClear (GpGraphics *graphics, ARGB color);
+GpStatus WINGDIPAPI GdipBitmapSetResolution (GpBitmap* bitmap, float xdpi, float ydpi);
+GpStatus WINGDIPAPI GdipGetImageHorizontalResolution (GpImage *image, float *resolution);
+GpStatus WINGDIPAPI GdipGetImageVerticalResolution (GpImage *image, float *resolution);
+GpStatus WINGDIPAPI GdipLoadImageFromStream (IStream* stream, GpImage **image);
+GpStatus WINGDIPAPI GdipDeleteGraphics (GpGraphics *graphics);
+
+#endif
diff --git a/gdk-pixbuf/io-gdip-propertytags.h b/gdk-pixbuf/io-gdip-propertytags.h
new file mode 100644 (file)
index 0000000..95243bf
--- /dev/null
@@ -0,0 +1,228 @@
+#ifndef HAVE_IO_GDIP_PROPERTIES_H
+#define HAVE_IO_GDIP_PROPERTIES_H
+
+#define PropertyTagTypeByte        1
+#define PropertyTagTypeASCII       2
+#define PropertyTagTypeShort       3
+#define PropertyTagTypeLong        4
+#define PropertyTagTypeRational    5
+#define PropertyTagTypeUndefined   7
+#define PropertyTagTypeSLONG       9
+#define PropertyTagTypeSRational  10
+
+#define PropertyTagExifIFD             0x8769
+#define PropertyTagGpsIFD              0x8825
+#define PropertyTagNewSubfileType      0x00FE
+#define PropertyTagSubfileType         0x00FF
+#define PropertyTagImageWidth          0x0100
+#define PropertyTagImageHeight         0x0101
+#define PropertyTagBitsPerSample       0x0102
+#define PropertyTagCompression         0x0103
+#define PropertyTagPhotometricInterp   0x0106
+#define PropertyTagThreshHolding       0x0107
+#define PropertyTagCellWidth           0x0108
+#define PropertyTagCellHeight          0x0109
+#define PropertyTagFillOrder           0x010A
+#define PropertyTagDocumentName        0x010D
+#define PropertyTagImageDescription    0x010E
+#define PropertyTagEquipMake           0x010F
+#define PropertyTagEquipModel          0x0110
+#define PropertyTagStripOffsets        0x0111
+#define PropertyTagOrientation         0x0112
+#define PropertyTagSamplesPerPixel     0x0115
+#define PropertyTagRowsPerStrip        0x0116
+#define PropertyTagStripBytesCount     0x0117
+#define PropertyTagMinSampleValue      0x0118
+#define PropertyTagMaxSampleValue      0x0119
+#define PropertyTagXResolution         0x011A   
+#define PropertyTagYResolution         0x011B   
+#define PropertyTagPlanarConfig        0x011C   
+#define PropertyTagPageName            0x011D
+#define PropertyTagXPosition           0x011E
+#define PropertyTagYPosition           0x011F
+#define PropertyTagFreeOffset          0x0120
+#define PropertyTagFreeByteCounts      0x0121
+#define PropertyTagGrayResponseUnit    0x0122
+#define PropertyTagGrayResponseCurve   0x0123
+#define PropertyTagT4Option            0x0124
+#define PropertyTagT6Option            0x0125
+#define PropertyTagResolutionUnit      0x0128   
+#define PropertyTagPageNumber          0x0129
+#define PropertyTagTransferFuncition   0x012D
+#define PropertyTagSoftwareUsed        0x0131
+#define PropertyTagDateTime            0x0132
+#define PropertyTagArtist              0x013B
+#define PropertyTagHostComputer        0x013C
+#define PropertyTagPredictor           0x013D
+#define PropertyTagWhitePoint          0x013E
+#define PropertyTagPrimaryChromaticities 0x013F
+#define PropertyTagColorMap            0x0140
+#define PropertyTagHalftoneHints       0x0141
+#define PropertyTagTileWidth           0x0142
+#define PropertyTagTileLength          0x0143
+#define PropertyTagTileOffset          0x0144
+#define PropertyTagTileByteCounts      0x0145
+#define PropertyTagInkSet              0x014C
+#define PropertyTagInkNames            0x014D
+#define PropertyTagNumberOfInks        0x014E
+#define PropertyTagDotRange            0x0150
+#define PropertyTagTargetPrinter       0x0151
+#define PropertyTagExtraSamples        0x0152
+#define PropertyTagSampleFormat        0x0153
+#define PropertyTagSMinSampleValue     0x0154
+#define PropertyTagSMaxSampleValue     0x0155
+#define PropertyTagTransferRange       0x0156
+#define PropertyTagJPEGProc            0x0200
+#define PropertyTagJPEGInterFormat     0x0201
+#define PropertyTagJPEGInterLength     0x0202
+#define PropertyTagJPEGRestartInterval 0x0203
+#define PropertyTagJPEGLosslessPredictors  0x0205
+#define PropertyTagJPEGPointTransforms     0x0206
+#define PropertyTagJPEGQTables         0x0207
+#define PropertyTagJPEGDCTables        0x0208
+#define PropertyTagJPEGACTables        0x0209
+#define PropertyTagYCbCrCoefficients   0x0211
+#define PropertyTagYCbCrSubsampling    0x0212
+#define PropertyTagYCbCrPositioning    0x0213
+#define PropertyTagREFBlackWhite       0x0214
+#define PropertyTagICCProfile          0x8773   
+#define PropertyTagGamma               0x0301
+#define PropertyTagICCProfileDescriptor 0x0302
+#define PropertyTagSRGBRenderingIntent 0x0303
+#define PropertyTagImageTitle          0x0320
+#define PropertyTagCopyright           0x8298
+#define PropertyTagResolutionXUnit           0x5001
+#define PropertyTagResolutionYUnit           0x5002
+#define PropertyTagResolutionXLengthUnit     0x5003
+#define PropertyTagResolutionYLengthUnit     0x5004
+#define PropertyTagPrintFlags                0x5005
+#define PropertyTagPrintFlagsVersion         0x5006
+#define PropertyTagPrintFlagsCrop            0x5007
+#define PropertyTagPrintFlagsBleedWidth      0x5008
+#define PropertyTagPrintFlagsBleedWidthScale 0x5009
+#define PropertyTagHalftoneLPI               0x500A
+#define PropertyTagHalftoneLPIUnit           0x500B
+#define PropertyTagHalftoneDegree            0x500C
+#define PropertyTagHalftoneShape             0x500D
+#define PropertyTagHalftoneMisc              0x500E
+#define PropertyTagHalftoneScreen            0x500F
+#define PropertyTagJPEGQuality               0x5010
+#define PropertyTagGridSize                  0x5011
+#define PropertyTagThumbnailFormat           0x5012  
+#define PropertyTagThumbnailWidth            0x5013
+#define PropertyTagThumbnailHeight           0x5014
+#define PropertyTagThumbnailColorDepth       0x5015
+#define PropertyTagThumbnailPlanes           0x5016
+#define PropertyTagThumbnailRawBytes         0x5017
+#define PropertyTagThumbnailSize             0x5018
+#define PropertyTagThumbnailCompressedSize   0x5019
+#define PropertyTagColorTransferFunction     0x501A
+#define PropertyTagThumbnailData             0x501B
+#define PropertyTagThumbnailImageWidth       0x5020  
+#define PropertyTagThumbnailImageHeight      0x5021  
+#define PropertyTagThumbnailBitsPerSample    0x5022  
+#define PropertyTagThumbnailCompression      0x5023  
+#define PropertyTagThumbnailPhotometricInterp 0x5024 
+#define PropertyTagThumbnailImageDescription 0x5025  
+#define PropertyTagThumbnailEquipMake        0x5026  
+#define PropertyTagThumbnailEquipModel       0x5027  
+#define PropertyTagThumbnailStripOffsets     0x5028  
+#define PropertyTagThumbnailOrientation      0x5029  
+#define PropertyTagThumbnailSamplesPerPixel  0x502A  
+#define PropertyTagThumbnailRowsPerStrip     0x502B  
+#define PropertyTagThumbnailStripBytesCount  0x502C  
+#define PropertyTagThumbnailResolutionX      0x502D  
+#define PropertyTagThumbnailResolutionY      0x502E  
+#define PropertyTagThumbnailPlanarConfig     0x502F  
+#define PropertyTagThumbnailResolutionUnit   0x5030  
+#define PropertyTagThumbnailTransferFunction 0x5031  
+#define PropertyTagThumbnailSoftwareUsed     0x5032  
+#define PropertyTagThumbnailDateTime         0x5033  
+#define PropertyTagThumbnailArtist           0x5034  
+#define PropertyTagThumbnailWhitePoint       0x5035  
+#define PropertyTagThumbnailPrimaryChromaticities 0x5036 
+#define PropertyTagThumbnailYCbCrCoefficients 0x5037 
+#define PropertyTagThumbnailYCbCrSubsampling 0x5038  
+#define PropertyTagThumbnailYCbCrPositioning 0x5039  
+#define PropertyTagThumbnailRefBlackWhite    0x503A  
+#define PropertyTagThumbnailCopyRight        0x503B  
+#define PropertyTagLuminanceTable            0x5090
+#define PropertyTagChrominanceTable          0x5091
+#define PropertyTagFrameDelay                0x5100
+#define PropertyTagLoopCount                 0x5101
+#define PropertyTagPixelUnit         0x5110  
+#define PropertyTagPixelPerUnitX     0x5111  
+#define PropertyTagPixelPerUnitY     0x5112  
+#define PropertyTagPaletteHistogram  0x5113  
+#define PropertyTagExifExposureTime  0x829A
+#define PropertyTagExifFNumber       0x829D
+#define PropertyTagExifExposureProg  0x8822
+#define PropertyTagExifSpectralSense 0x8824
+#define PropertyTagExifISOSpeed      0x8827
+#define PropertyTagExifOECF          0x8828
+#define PropertyTagExifVer            0x9000
+#define PropertyTagExifDTOrig         0x9003 
+#define PropertyTagExifDTDigitized    0x9004 
+#define PropertyTagExifCompConfig     0x9101
+#define PropertyTagExifCompBPP        0x9102
+#define PropertyTagExifShutterSpeed   0x9201
+#define PropertyTagExifAperture       0x9202
+#define PropertyTagExifBrightness     0x9203
+#define PropertyTagExifExposureBias   0x9204
+#define PropertyTagExifMaxAperture    0x9205
+#define PropertyTagExifSubjectDist    0x9206
+#define PropertyTagExifMeteringMode   0x9207
+#define PropertyTagExifLightSource    0x9208
+#define PropertyTagExifFlash          0x9209
+#define PropertyTagExifFocalLength    0x920A
+#define PropertyTagExifMakerNote      0x927C
+#define PropertyTagExifUserComment    0x9286
+#define PropertyTagExifDTSubsec       0x9290  
+#define PropertyTagExifDTOrigSS       0x9291  
+#define PropertyTagExifDTDigSS        0x9292  
+#define PropertyTagExifFPXVer         0xA000
+#define PropertyTagExifColorSpace     0xA001
+#define PropertyTagExifPixXDim        0xA002
+#define PropertyTagExifPixYDim        0xA003
+#define PropertyTagExifRelatedWav     0xA004  
+#define PropertyTagExifInterop        0xA005
+#define PropertyTagExifFlashEnergy    0xA20B
+#define PropertyTagExifSpatialFR      0xA20C  
+#define PropertyTagExifFocalXRes      0xA20E  
+#define PropertyTagExifFocalYRes      0xA20F  
+#define PropertyTagExifFocalResUnit   0xA210  
+#define PropertyTagExifSubjectLoc     0xA214
+#define PropertyTagExifExposureIndex  0xA215
+#define PropertyTagExifSensingMethod  0xA217
+#define PropertyTagExifFileSource     0xA300
+#define PropertyTagExifSceneType      0xA301
+#define PropertyTagExifCfaPattern     0xA302
+#define PropertyTagGpsVer             0x0000
+#define PropertyTagGpsLatitudeRef     0x0001
+#define PropertyTagGpsLatitude        0x0002
+#define PropertyTagGpsLongitudeRef    0x0003
+#define PropertyTagGpsLongitude       0x0004
+#define PropertyTagGpsAltitudeRef     0x0005
+#define PropertyTagGpsAltitude        0x0006
+#define PropertyTagGpsGpsTime         0x0007
+#define PropertyTagGpsGpsSatellites   0x0008
+#define PropertyTagGpsGpsStatus       0x0009
+#define PropertyTagGpsGpsMeasureMode  0x00A
+#define PropertyTagGpsGpsDop          0x000B  
+#define PropertyTagGpsSpeedRef        0x000C
+#define PropertyTagGpsSpeed           0x000D
+#define PropertyTagGpsTrackRef        0x000E
+#define PropertyTagGpsTrack           0x000F
+#define PropertyTagGpsImgDirRef       0x0010
+#define PropertyTagGpsImgDir          0x0011
+#define PropertyTagGpsMapDatum        0x0012
+#define PropertyTagGpsDestLatRef      0x0013
+#define PropertyTagGpsDestLat         0x0014
+#define PropertyTagGpsDestLongRef     0x0015
+#define PropertyTagGpsDestLong        0x0016
+#define PropertyTagGpsDestBearRef     0x0017
+#define PropertyTagGpsDestBear        0x0018
+#define PropertyTagGpsDestDistRef     0x0019
+#define PropertyTagGpsDestDist        0x001A
+
+#endif
diff --git a/gdk-pixbuf/io-gdip-tiff.c b/gdk-pixbuf/io-gdip-tiff.c
new file mode 100644 (file)
index 0000000..7e0a189
--- /dev/null
@@ -0,0 +1,87 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\r
+/* GdkPixbuf library - Win32 GDI+ Pixbuf Loader\r
+ *\r
+ * Copyright (C) 2008 Dominic Lachowicz\r
+ * Copyright (C) 2008 Alberto Ruiz\r
+ *\r
+ * Authors: Dominic Lachowicz <domlachowicz@gmail.com>\r
+ *          Alberto Ruiz <aruiz@gnome.org>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2 of the License, or (at your option) any later version.\r
+ *\r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more  * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the\r
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,\r
+ * Boston, MA 02111-1307, USA.\r
+ */\r
+\r
+#include "io-gdip-utils.h"\r
+\r
+static gboolean\r
+gdk_pixbuf__gdip_image_save_TIFF_to_callback (GdkPixbufSaveFunc   save_func,\r
+                                              gpointer            user_data,\r
+                                              GdkPixbuf          *pixbuf,\r
+                                              gchar             **keys,\r
+                                              gchar             **values,\r
+                                              GError            **error)\r
+{\r
+  return gdip_save_pixbuf (pixbuf, L"image/tiff", NULL, save_func, user_data, error);\r
+}\r
+\r
+static gboolean\r
+gdk_pixbuf__gdip_image_save_TIFF (FILE         *f,\r
+                                 GdkPixbuf     *pixbuf,\r
+                                 gchar        **keys,\r
+                                 gchar        **values,\r
+                                 GError       **error)\r
+{\r
+  return gdk_pixbuf__gdip_image_save_TIFF_to_callback (gdip_save_to_file_callback, f, pixbuf, keys, values, error);\r
+}\r
+\r
+#ifndef INCLUDE_gdiplus\r
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function\r
+#else\r
+#define MODULE_ENTRY(function) void _gdk_pixbuf__gdip_tiff_ ## function\r
+#endif\r
+\r
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)\r
+{\r
+  gdip_fill_vtable (module);\r
+\r
+  module->save_to_callback = gdk_pixbuf__gdip_image_save_TIFF_to_callback;\r
+  module->save = gdk_pixbuf__gdip_image_save_TIFF; /* for gtk < 2.14, you need to implement both. otherwise gdk-pixbuf-queryloaders fails */\r
+}\r
+\r
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)\r
+{\r
+  static GdkPixbufModulePattern signature[] = {\r
+    { "MM \x2a", "  z ", 100 }, /* TIFF */\r
+    { "II\x2a ", "   z", 100 }, /* TIFF */\r
+    { NULL, NULL, 0 }\r
+  };\r
+\r
+  static gchar *mime_types[] = {\r
+    "image/tiff",\r
+    NULL\r
+  };\r
+\r
+  static gchar *extensions[] = {\r
+    "tiff",\r
+    "tif",\r
+    NULL\r
+  };\r
+\r
+  info->name        = "tiff";\r
+  info->signature   = signature;\r
+  info->description = "The TIFF image format";\r
+  info->mime_types  = mime_types;\r
+  info->extensions  = extensions;\r
+  info->flags       = GDK_PIXBUF_FORMAT_WRITABLE | GDK_PIXBUF_FORMAT_THREADSAFE;\r
+  info->license     = "LGPL";\r
+}\r
diff --git a/gdk-pixbuf/io-gdip-utils.c b/gdk-pixbuf/io-gdip-utils.c
new file mode 100644 (file)
index 0000000..01befd8
--- /dev/null
@@ -0,0 +1,949 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* GdkPixbuf library - Win32 GDI+ Pixbuf Loader
+ *
+ * Copyright (C) 2008 Dominic Lachowicz
+ * Copyright (C) 2008 Alberto Ruiz
+ *
+ * Authors: Dominic Lachowicz <domlachowicz@gmail.com>
+ *          Alberto Ruiz <aruiz@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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  * You should have received a copy of the GNU Lesser 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.
+ */
+
+#define INITGUID
+#include <ole2.h>
+
+#include "io-gdip-utils.h"
+#include "io-gdip-native.h"
+#include "io-gdip-propertytags.h"
+#include "io-gdip-animation.h"
+
+#define LOAD_BUFFER_SIZE 65536
+
+struct _GdipContext {
+  GdkPixbufModuleUpdatedFunc  updated_func;
+  GdkPixbufModulePreparedFunc prepared_func;
+  GdkPixbufModuleSizeFunc     size_func;
+
+  gpointer                    user_data;
+  GByteArray                 *buffer;
+  IStream                    *stream;
+  HGLOBAL                     hg;
+};
+typedef struct _GdipContext GdipContext;
+
+DEFINE_GUID(FrameDimensionTime, 0x6aedbd6d,0x3fb5,0x418a,0x83,0xa6,0x7f,0x45,0x22,0x9d,0xc8,0x72);
+DEFINE_GUID(FrameDimensionPage, 0x7462dc86,0x6180,0x4c7e,0x8e,0x3f,0xee,0x73,0x33,0xa7,0xa4,0x83);
+
+static void
+gdip_set_error_from_hresult (GError **error, gint code, HRESULT hr, const char *format)
+{
+  gchar *msg;
+  
+  msg = g_win32_error_message (hr);
+  
+  if (msg) {
+    g_set_error (error, GDK_PIXBUF_ERROR, code, format, msg);
+    g_free (msg);
+  }
+}
+
+static void
+gdip_set_error_from_gpstatus (GError **error, gint code, GpStatus status)
+{
+  const char *msg;
+
+  switch (status)
+    {
+#define CASE(x) case x: msg = #x; break
+    CASE (GenericError);
+    CASE (InvalidParameter);
+    CASE (OutOfMemory);
+    CASE (ObjectBusy);
+    CASE (InsufficientBuffer);
+    CASE (NotImplemented);
+    CASE (Win32Error);
+    CASE (WrongState);
+    CASE (Aborted);
+    CASE (FileNotFound);
+    CASE (ValueOverflow);
+    CASE (AccessDenied);
+    CASE (UnknownImageFormat);
+    CASE (FontFamilyNotFound);
+    CASE (FontStyleNotFound);
+    CASE (NotTrueTypeFont);
+    CASE (UnsupportedGdiplusVersion);
+    CASE (GdiplusNotInitialized);
+    CASE (PropertyNotFound);
+    CASE (PropertyNotSupported);
+    CASE (ProfileNotFound);
+    default:
+      msg = "Unknown error";
+    }
+  g_set_error_literal (error, GDK_PIXBUF_ERROR, code, msg);
+}
+
+static gboolean
+gdip_init (void)
+{
+  GdiplusStartupInput input;
+  ULONG_PTR gdiplusToken = 0;
+  static gboolean beenhere = FALSE;
+
+  if (beenhere)
+    return TRUE; /* gdip_init() is idempotent */
+
+  beenhere = TRUE;
+
+  input.GdiplusVersion = 1;
+  input.DebugEventCallback = NULL;
+  input.SuppressBackgroundThread = input.SuppressExternalCodecs = FALSE;
+  
+  return (GdiplusStartup (&gdiplusToken, &input, NULL) == 0 ? TRUE : FALSE);
+}
+
+static gboolean
+GetEncoderClsid (const WCHAR *format, CLSID *pClsid)
+{
+  UINT num, size;
+  int j;
+  ImageCodecInfo *pImageCodecInfo;
+    
+  if (Ok != GdipGetImageEncodersSize (&num, &size))
+    return FALSE;
+    
+  pImageCodecInfo = (ImageCodecInfo *) g_malloc (size);
+    
+  if (Ok != GdipGetImageEncoders (num, size, pImageCodecInfo)) {
+    g_free (pImageCodecInfo);
+    return FALSE;
+  }
+
+  for (j = 0; j < num; j++) {
+    if (wcscmp (pImageCodecInfo[j].MimeType, format) == 0) {
+      *pClsid = pImageCodecInfo[j].Clsid;
+      g_free (pImageCodecInfo);
+      return TRUE;
+    }
+  }
+  g_free (pImageCodecInfo);
+
+  return FALSE;
+}
+
+static HGLOBAL
+gdip_buffer_to_hglobal (const gchar *buffer, size_t size, GError **error)
+{
+  HGLOBAL hg = NULL;
+
+  hg = GlobalAlloc (GPTR, size);
+
+  if (!hg) {
+    gdip_set_error_from_hresult (error, GDK_PIXBUF_ERROR_FAILED, GetLastError (), _("Could not allocate memory: %s"));
+    return NULL;
+  }
+
+  CopyMemory (hg, buffer, size);
+
+  return hg;
+}
+
+static gboolean
+gdip_save_bitmap_to_callback (GpBitmap *bitmap,
+                              const CLSID *format,
+                              const EncoderParameters *encoder_params,
+                              GdkPixbufSaveFunc save_func,
+                              gpointer user_data,
+                              GError **error)
+{
+  HRESULT hr;  
+  IStream *streamOut = NULL;
+  gboolean success = FALSE;
+  guint64 zero = 0;
+  GpStatus status;
+
+  hr = CreateStreamOnHGlobal (NULL, TRUE, &streamOut);
+  if (!SUCCEEDED (hr)) {
+    gdip_set_error_from_hresult (error, GDK_PIXBUF_ERROR_FAILED, hr, _("Could not create stream: %s"));
+    return FALSE;
+  }
+
+  status = GdipSaveImageToStream ((GpImage *)bitmap, streamOut, format, encoder_params);
+  if (Ok != status) {
+    gdip_set_error_from_gpstatus (error, GDK_PIXBUF_ERROR_FAILED, status);
+    IStream_Release (streamOut);
+    return FALSE;
+  }
+
+  /* seek back to the beginning of the stream */
+  hr = IStream_Seek (streamOut, *(LARGE_INTEGER *)&zero, STREAM_SEEK_SET, NULL);
+  if (!SUCCEEDED (hr)) {
+    gdip_set_error_from_hresult (error, GDK_PIXBUF_ERROR_FAILED, hr, _("Could not seek stream: %s"));
+    IStream_Release (streamOut);
+    return FALSE;
+  }
+  
+  for (;;) {
+    char buffer[LOAD_BUFFER_SIZE];
+    ULONG nread;
+    
+    hr = IStream_Read (streamOut, buffer, sizeof(buffer), &nread);
+    if (!SUCCEEDED (hr))
+      {
+        gdip_set_error_from_hresult (error, GDK_PIXBUF_ERROR_FAILED, hr, _("Could not read from stream: %s"));
+        break;
+      }
+    else if (0 == nread) {
+      success = TRUE; /* EOF */
+      break;
+    }
+    else if (!(*save_func) (buffer, nread, error, user_data))
+      break;
+  }
+  
+  IStream_Release (streamOut);
+  
+  return success;
+}                     
+
+static GpBitmap *
+gdip_pixbuf_to_bitmap (GdkPixbuf *pixbuf)
+{
+  GpBitmap *bitmap = NULL;
+
+  int width, height, stride, n_channels;
+  guint8 *pixels;
+
+  width = gdk_pixbuf_get_width (pixbuf);
+  height = gdk_pixbuf_get_height (pixbuf);
+  stride = gdk_pixbuf_get_rowstride (pixbuf);
+  n_channels = gdk_pixbuf_get_n_channels (pixbuf);
+  pixels = gdk_pixbuf_get_pixels (pixbuf);
+
+  if (n_channels == 3 || n_channels == 4) {
+    /* rgbX. need to convert to argb. pass a null data to get an empty bitmap */
+    GdipCreateBitmapFromScan0 (width, height, 0, PixelFormat32bppARGB, NULL, &bitmap);
+    
+    if (bitmap) {
+      int x, y;
+      
+      for (y = 0; y < height; y++) {
+        for (x = 0; x < width; x++) {
+          ARGB p;
+          guint8 alpha;
+          guchar *base = pixels + (y * stride + (x * n_channels));
+          
+          if (n_channels == 4)
+            alpha = base[3];
+          else
+            alpha = 0xff;
+                  
+          if (alpha == 0) 
+            p = 0;
+          else {
+            guint8 red = base[0];
+            guint8 green = base[1];
+            guint8 blue = base[2];
+            
+            p = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
+          }
+          
+          GdipBitmapSetPixel (bitmap, x, y, p);
+        }
+      }
+    }
+  }
+  else {
+    g_warning ("Unsupported number of channels: %d\n", n_channels);
+  }
+  
+  return bitmap;
+}
+
+static GpBitmap *
+gdip_buffer_to_bitmap (GdipContext *context, GError **error)
+{
+  HRESULT hr;
+  HGLOBAL hg = NULL;
+  GpBitmap *bitmap = NULL;
+  IStream *stream = NULL;
+  GpStatus status;
+  guint64 size64 = context->buffer->len;
+
+  hg = gdip_buffer_to_hglobal (context->buffer->data, context->buffer->len, error);
+
+  if (!hg)
+    return NULL;
+
+  hr = CreateStreamOnHGlobal (hg, FALSE, (LPSTREAM *)&stream);
+
+  if (!SUCCEEDED (hr)) {
+    gdip_set_error_from_hresult (error, GDK_PIXBUF_ERROR_FAILED, hr, _("Could not create stream: %s"));
+    GlobalFree (hg);
+    return NULL;
+  }
+
+  IStream_SetSize (stream, *(ULARGE_INTEGER *)&size64);
+
+  status = GdipCreateBitmapFromStream (stream, &bitmap);
+
+  if (Ok != status) {
+    gdip_set_error_from_gpstatus (error, GDK_PIXBUF_ERROR_FAILED, status);
+    IStream_Release (stream);
+    GlobalFree (hg);
+    return NULL;
+  }
+
+  context->stream = stream;
+  context->hg = hg;
+
+  return bitmap;
+}
+
+static GpImage *
+gdip_buffer_to_image (GdipContext *context, GError **error)
+{
+  HRESULT hr;
+  HGLOBAL hg = NULL;
+  GpImage *image = NULL;
+  IStream *stream = NULL;
+  GpStatus status;
+  guint64 size64 = context->buffer->len;
+
+  hg = gdip_buffer_to_hglobal (context->buffer->data, context->buffer->len, error);
+
+  if (!hg)
+    return NULL;
+
+  hr = CreateStreamOnHGlobal (hg, FALSE, (LPSTREAM *)&stream);
+
+  if (!SUCCEEDED (hr)) {
+    gdip_set_error_from_hresult (error, GDK_PIXBUF_ERROR_FAILED, hr, _("Could not create stream: %s"));
+    GlobalFree (hg);
+    return NULL;
+  }
+  
+  IStream_SetSize (stream, *(ULARGE_INTEGER *)&size64);
+  status = GdipLoadImageFromStream (stream, &image);
+
+  if (Ok != status) {
+    gdip_set_error_from_gpstatus (error, GDK_PIXBUF_ERROR_FAILED, status);
+    IStream_Release (stream);
+    GlobalFree (hg);
+    return NULL;
+  }
+
+  context->stream = stream;
+  context->hg = hg;
+
+  return image;
+}
+
+static void
+gdip_bitmap_get_size (GpBitmap *bitmap, guint *width, guint *height)
+{
+  if (bitmap == NULL || width == NULL || height == NULL)
+    return;
+
+  *width = *height = 0;
+
+  GdipGetImageWidth ((GpImage *) bitmap, width);
+  GdipGetImageHeight ((GpImage *) bitmap, height);
+}
+
+static void
+gdip_bitmap_get_has_alpha (GpBitmap *bitmap, gboolean *has_alpha)
+{
+  guint flags = 0;
+
+  if (bitmap == NULL || has_alpha == NULL)
+    return;
+
+  GdipGetImageFlags ((GpImage *) bitmap, &flags);
+  *has_alpha = (flags & ImageFlagsHasAlpha);
+}
+
+static gboolean
+gdip_bitmap_get_n_frames (GpBitmap *bitmap, guint *n_frames, gboolean timeDimension)
+{
+  if (bitmap == NULL || n_frames == NULL)
+    return FALSE;
+
+  *n_frames = 1;
+
+  return (Ok == GdipImageGetFrameCount ((GpImage *) bitmap, (timeDimension ? &FrameDimensionTime : &FrameDimensionPage), n_frames));
+}
+
+static gboolean
+gdip_bitmap_select_frame (GpBitmap *bitmap, guint frame, gboolean timeDimension)
+{
+  if (bitmap == NULL)
+    return FALSE;
+
+  return (Ok == GdipImageSelectActiveFrame ((GpImage *)bitmap, (timeDimension ? &FrameDimensionTime : &FrameDimensionPage), frame));
+}
+
+static gboolean
+gdip_bitmap_get_property_as_string (GpBitmap *bitmap, guint propertyId, gchar **str)
+{
+  guint item_size;
+  gboolean success = FALSE;
+
+  if (bitmap == NULL || str == NULL)
+    return FALSE;
+
+  *str = 0;
+
+  if (Ok == GdipGetPropertyItemSize ((GpImage *)bitmap, propertyId, &item_size)) {
+    PropertyItem *item;
+    
+    item = (PropertyItem *)g_try_malloc (item_size);
+    if (Ok == GdipGetPropertyItem ((GpImage *)bitmap, propertyId, item_size, item)) {
+      GString *gstr;
+      int i;
+      
+      gstr = g_string_new (NULL);
+      
+      success = TRUE;
+      switch (item->type) {
+      case PropertyTagTypeByte:
+        for (i = 0; i < item->length / sizeof(guint8); i++) {
+          guint8 *bytes = (guint8 *)item->value;
+          
+          if (gstr->len != 0)
+            g_string_append_c(gstr, ',');
+          g_string_append_printf (gstr, "%u", (guint32)bytes[i]);
+        }
+        break;
+        
+      case PropertyTagTypeASCII:
+        g_string_append_len (gstr, (const char *)item->value, item->length);
+        break;
+        
+      case PropertyTagTypeShort:
+        for (i = 0; i < item->length / sizeof(guint16); i++) {
+          guint16 *shorts = (guint16 *)item->value;
+          
+          if (gstr->len != 0)
+            g_string_append_c (gstr, ',');
+          g_string_append_printf (gstr, "%u", (guint32)shorts[i]);
+        }
+        break;
+        
+      case PropertyTagTypeLong:
+        for (i = 0; i < item->length / sizeof(guint32); i++) {
+          guint32 *longs = (guint32 *)item->value;
+          
+          if (gstr->len != 0)
+            g_string_append_c (gstr, ',');
+          g_string_append_printf (gstr, "%u", longs[i]);
+        }
+        break;
+
+      case PropertyTagTypeSLONG:
+        for (i = 0; i < item->length / sizeof(guint32); i++) {
+          gint32 *longs = (gint32 *)item->value;
+          
+          if (gstr->len != 0)
+            g_string_append_c (gstr, ',');
+          g_string_append_printf (gstr, "%d", longs[i]);
+        }
+        break;
+        
+      default:
+        success = FALSE;
+        break;
+      }
+      
+      if (gstr->len > 0)
+        *str = g_string_free (gstr, FALSE);
+      else
+        g_string_free (gstr, TRUE);
+    }
+    
+    g_free (item);
+  }
+  
+  return success;
+}
+
+static gboolean
+gdip_bitmap_get_frame_delay (GpBitmap *bitmap, guint frame, guint *delay)
+{
+  guint item_size, item_count;
+  gboolean success = FALSE;
+
+  if (bitmap == NULL || delay == NULL)
+    return FALSE;
+
+  *delay = 0;
+
+  if (Ok == GdipGetPropertyItemSize ((GpImage *)bitmap, PropertyTagFrameDelay, &item_size)) {
+    PropertyItem *item;
+    
+    item = (PropertyItem *)g_try_malloc (item_size);
+    if (Ok == GdipGetPropertyItem ((GpImage *)bitmap, PropertyTagFrameDelay, item_size, item)) {
+      item_count = item_size / sizeof(long);
+      /* PropertyTagFrameDelay. Time delay, in hundredths of a second, between two frames in an animated GIF image. */
+      *delay = ((long *)item->value)[(frame < item_count) ? frame : item_count - 1];
+      success = TRUE;
+    }
+    
+    g_free (item);
+  }
+  
+  return success;
+}
+
+static gboolean
+gdip_bitmap_get_n_loops (GpBitmap *bitmap, guint *loops)
+{
+  guint item_size;
+  gboolean success = FALSE;
+
+  if (bitmap == NULL || loops == NULL)
+    return FALSE;
+
+  *loops = 1;
+
+  /* PropertyTagLoopCount. 0 == infinitely */
+  if (Ok == GdipGetPropertyItemSize ((GpImage *)bitmap, PropertyTagLoopCount, &item_size)) {
+    PropertyItem *item;
+    
+    item = (PropertyItem *)g_try_malloc (item_size);
+    if (Ok == GdipGetPropertyItem ((GpImage *)bitmap, PropertyTagLoopCount, item_size, item)) {
+      *loops = *((short *)item->value);
+      success = TRUE;
+    }
+    
+    g_free (item);
+  }
+  
+  return success;
+}
+
+static void
+destroy_gdipcontext (GdipContext *context)
+{
+  if (context != NULL) {
+    if (context->stream != NULL) {
+      IStream_Release(context->stream);
+      GlobalFree (context->hg);
+    }
+    g_byte_array_free (context->buffer, TRUE);
+    g_free (context);
+  }
+}
+
+static void
+emit_updated (GdipContext *context, GdkPixbuf *pixbuf)
+{
+  if (context->updated_func)
+    (*context->updated_func) (pixbuf,
+                              0, 0,
+                              gdk_pixbuf_get_width (pixbuf),
+                              gdk_pixbuf_get_height (pixbuf),
+                              context->user_data);
+}
+
+static void
+emit_prepared (GdipContext *context, GdkPixbuf *pixbuf, GdkPixbufAnimation *anim)
+{
+  if (context->prepared_func)
+    (*context->prepared_func) (pixbuf, anim, context->user_data);
+}
+
+static gpointer
+gdk_pixbuf__gdip_image_begin_load (GdkPixbufModuleSizeFunc size_func,
+                                   GdkPixbufModulePreparedFunc prepared_func,
+                                   GdkPixbufModuleUpdatedFunc  updated_func,
+                                   gpointer user_data,
+                                   GError **error)
+{
+  GdipContext *context = g_new0 (GdipContext, 1);
+
+  context->size_func     = size_func;
+  context->prepared_func = prepared_func;
+  context->updated_func  = updated_func;
+  context->user_data     = user_data;
+  context->buffer        = g_byte_array_new ();
+
+  return context;
+}
+
+static gboolean
+gdk_pixbuf__gdip_image_load_increment (gpointer data,
+                                       const guchar *buf, guint size,
+                                       GError **error)
+{
+  GdipContext *context = (GdipContext *)data;
+  GByteArray *image_buffer = context->buffer;
+
+  g_byte_array_append (image_buffer, (guint8 *)buf, size);
+
+  return TRUE;
+}
+
+static GdkPixbuf *
+gdip_bitmap_to_pixbuf (GpBitmap *bitmap, GError **error)
+{
+  GdkPixbuf *pixbuf = NULL;
+  guchar *cursor = NULL;
+  gint rowstride;
+  gboolean has_alpha = FALSE;
+  gint n_channels = 0;
+  gchar *option;
+
+  guint width = 0, height = 0, x, y;
+
+  gdip_bitmap_get_size (bitmap, &width, &height);
+  gdip_bitmap_get_has_alpha (bitmap, &has_alpha);
+
+  pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, has_alpha, 8, width, height);
+
+  if (!pixbuf) {
+    g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't load bitmap"));
+    return NULL;
+  }
+
+  rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+  cursor = gdk_pixbuf_get_pixels (pixbuf);
+  n_channels = gdk_pixbuf_get_n_channels (pixbuf);
+
+  for (y = 0; y < height; y++) {
+    for (x = 0; x < width; x++) {
+      ARGB pixel;
+      GpStatus status;
+      guchar *b = cursor + (y * rowstride + (x * n_channels));
+      
+      if (Ok != (status = GdipBitmapGetPixel (bitmap, x, y, &pixel))) {
+        gdip_set_error_from_gpstatus (error, GDK_PIXBUF_ERROR_FAILED, status);
+        g_object_unref (pixbuf);
+        return NULL;
+      }
+      
+      b[0] = (pixel & 0xff0000) >> 16;
+      b[1] = (pixel & 0x00ff00) >> 8;
+      b[2] = (pixel & 0x0000ff) >> 0;
+      
+      if (has_alpha)      
+        b[3] = (pixel & 0xff000000) >> 24;
+    }
+  }
+
+  if (gdip_bitmap_get_property_as_string (bitmap, PropertyTagOrientation, &option)) {
+    gdk_pixbuf_set_option (pixbuf, "orientation", option);
+    g_free (option);
+  }
+
+  if (gdip_bitmap_get_property_as_string (bitmap, PropertyTagArtist, &option)) {
+    gdk_pixbuf_set_option (pixbuf, "Author", option);
+    g_free (option);
+  }
+
+  if (gdip_bitmap_get_property_as_string (bitmap, PropertyTagImageTitle, &option)) {
+    gdk_pixbuf_set_option (pixbuf, "Title", option);
+    g_free (option);
+  }
+
+  return pixbuf;
+}
+
+static gboolean
+stop_load (GpBitmap *bitmap, GdipContext *context, GError **error)
+{
+  guint       n_frames = 1, i;
+  GdkPixbufGdipAnim *animation = NULL;
+
+  gdip_bitmap_get_n_frames (bitmap, &n_frames, TRUE);
+
+  for (i = 0; i < n_frames; i++) {
+    GdkPixbuf *pixbuf = NULL;
+    GdkPixbufFrame *frame;
+    guint frame_delay = 0;
+
+    gdip_bitmap_select_frame (bitmap, i, TRUE);
+    
+    pixbuf = gdip_bitmap_to_pixbuf (bitmap, error);
+    
+    if (!pixbuf) {
+      if (animation != NULL)
+        g_object_unref (G_OBJECT (animation));
+
+      GdipDisposeImage ((GpImage *)bitmap);
+      destroy_gdipcontext (context);
+      return FALSE;
+    }
+    
+    if (animation == NULL) {
+      guint n_loops = 1;
+
+      animation = g_object_new (GDK_TYPE_PIXBUF_GDIP_ANIM, NULL);
+      gdip_bitmap_get_n_loops (bitmap, &n_loops);
+      animation->loop = n_loops;
+    }
+
+    frame = g_new (GdkPixbufFrame, 1);
+    frame->pixbuf = pixbuf;
+
+    gdip_bitmap_get_frame_delay (bitmap, i, &frame_delay);
+  
+    animation->n_frames++;
+    animation->frames = g_list_append (animation->frames, frame);
+
+    animation->width = gdk_pixbuf_get_width (pixbuf);
+    animation->height = gdk_pixbuf_get_height (pixbuf);
+
+    /* GIF delay is in hundredths, we want thousandths */
+    frame->delay_time = frame_delay * 10;
+
+    /* GIFs with delay time 0 are mostly broken, but they
+     * just want a default, "not that fast" delay.
+     */
+    if (frame->delay_time == 0)
+      frame->delay_time = 100;
+
+    /* No GIFs gets to play faster than 50 fps. They just
+     * lock up poor gtk.
+     */
+    else if (frame->delay_time < 20)
+      frame->delay_time = 20; /* 20 = "fast" */
+
+    frame->elapsed = animation->total_time;
+    animation->total_time += frame->delay_time;
+
+    if (i == 0)
+      emit_prepared (context, pixbuf, GDK_PIXBUF_ANIMATION (animation));
+
+    emit_updated (context, pixbuf);
+  }
+
+  if (animation != NULL)
+    g_object_unref (G_OBJECT (animation));
+
+  GdipDisposeImage ((GpImage *)bitmap);
+  destroy_gdipcontext (context);
+  
+  return TRUE;
+}
+
+static gboolean
+gdk_pixbuf__gdip_image_stop_load (gpointer data, GError **error)
+{
+  GdipContext *context = (GdipContext *)data;
+  GpBitmap    *bitmap = NULL;
+
+  bitmap = gdip_buffer_to_bitmap (context, error);
+
+  if (!bitmap) {
+    destroy_gdipcontext (context);
+    g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Couldn't load bitmap"));
+    return FALSE;
+  }
+
+  return stop_load (bitmap, context, error);
+}
+
+static gboolean
+gdk_pixbuf__gdip_image_stop_vector_load (gpointer data, GError **error)
+{
+  GdipContext *context = (GdipContext *)data;
+
+  GpImage *metafile;
+  GpGraphics *graphics;
+  GpBitmap *bitmap;
+  GpStatus status;
+  float metafile_xres, metafile_yres;
+  guint width, height;
+
+  metafile = gdip_buffer_to_image (context, error);
+  if (!metafile) {
+    destroy_gdipcontext (context);
+    g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Couldn't load metafile"));
+    return FALSE;
+  }
+
+  GdipGetImageWidth (metafile, &width);
+  GdipGetImageHeight (metafile, &height);
+
+  status = GdipCreateBitmapFromScan0 (width, height, 0, PixelFormat32bppARGB, NULL, &bitmap);
+  if (Ok != status) {
+    gdip_set_error_from_gpstatus (error, GDK_PIXBUF_ERROR_FAILED, status);
+    GdipDisposeImage (metafile);
+    
+    return FALSE;
+  }
+
+  GdipGetImageHorizontalResolution (metafile, &metafile_xres);
+  GdipGetImageVerticalResolution (metafile, &metafile_yres);
+  GdipBitmapSetResolution (bitmap, metafile_xres, metafile_yres);
+
+  status = GdipGetImageGraphicsContext ((GpImage *)bitmap, &graphics);
+  if (Ok != status) {
+    gdip_set_error_from_gpstatus (error, GDK_PIXBUF_ERROR_FAILED, status);
+    GdipDisposeImage ((GpImage *)bitmap);
+    GdipDisposeImage (metafile);
+    
+    return FALSE;
+  }
+  
+  /* gotta clear the bitmap */
+  GdipGraphicsClear (graphics, 0xffffffff);
+  
+  status = GdipDrawImageI (graphics, metafile, 0, 0);
+  if (Ok != status) {
+    gdip_set_error_from_gpstatus (error, GDK_PIXBUF_ERROR_FAILED, status);
+    GdipDeleteGraphics (graphics);
+    GdipDisposeImage ((GpImage *)bitmap);
+    GdipDisposeImage (metafile);
+    
+    return FALSE;
+  }
+  
+  GdipFlush (graphics, 1);
+  
+  GdipDeleteGraphics (graphics);
+  GdipDisposeImage (metafile);
+
+  return stop_load (bitmap, context, error);
+}
+
+static void 
+gdip_animation_prepare (GdkPixbuf *pixbuf,
+                        GdkPixbufAnimation *animation,
+                        gpointer user_data)
+{
+  GdkPixbufAnimation **anim;
+
+  anim = (GdkPixbufAnimation **)user_data;
+
+  /* save a reference to the animation */
+  g_object_ref (animation);
+  *anim = animation;
+}
+
+static GdkPixbufAnimation *
+gdk_pixbuf__gdip_image_load_animation (FILE *file,
+                                       GError **error)
+{
+  GdkPixbufAnimation *animation = NULL;
+
+  gpointer context;
+  char buffer[LOAD_BUFFER_SIZE];
+  size_t length;
+
+  context = gdk_pixbuf__gdip_image_begin_load (NULL, gdip_animation_prepare, NULL, &animation, error);
+
+  while (!feof (file) && !ferror (file)) {
+    length = fread (buffer, 1, sizeof (buffer), file);
+    if (length > 0) {
+      if (!gdk_pixbuf__gdip_image_load_increment (context, buffer, length, error)) {
+        gdk_pixbuf__gdip_image_stop_load (context, NULL);
+
+        if (animation)
+          g_object_unref (animation);
+
+        return NULL;
+      }
+    }
+  }
+
+  if (!gdk_pixbuf__gdip_image_stop_load(context, error)) {
+    if (animation)
+      g_object_unref (animation);
+    
+    return NULL;
+  }
+
+  return animation;
+}
+
+gboolean
+gdip_save_to_file_callback (const gchar *buf,
+                            gsize        count,
+                            GError     **error,
+                            gpointer     data)
+{
+  FILE *filehandle = data;
+  gsize n;
+  
+  n = fwrite (buf, 1, count, filehandle);
+  if (n != count) {
+    gint save_errno = errno;
+    g_set_error (error,
+                 G_FILE_ERROR,
+                 g_file_error_from_errno (save_errno),
+                 _("Error writing to image file: %s"),
+                 g_strerror (save_errno));
+    return FALSE;
+  }
+  
+  return TRUE;
+}
+
+void
+gdip_fill_vtable (GdkPixbufModule *module)
+{
+  if (gdip_init ()) {
+    module->begin_load     = gdk_pixbuf__gdip_image_begin_load;
+    module->stop_load      = gdk_pixbuf__gdip_image_stop_load;
+    module->load_increment = gdk_pixbuf__gdip_image_load_increment;
+    
+    /* this is the only way to get gtk_image_new_from_file() to load animations. it regrettably
+       does not use the GdkPixbufLoader interface. */
+    module->load_animation = gdk_pixbuf__gdip_image_load_animation;
+  }
+}
+
+void
+gdip_fill_vector_vtable (GdkPixbufModule *module)
+{
+  if (gdip_init ()) {
+    module->begin_load     = gdk_pixbuf__gdip_image_begin_load;
+    module->stop_load      = gdk_pixbuf__gdip_image_stop_vector_load;
+    module->load_increment = gdk_pixbuf__gdip_image_load_increment;
+  }
+}
+
+gboolean
+gdip_save_pixbuf (GdkPixbuf *pixbuf,
+                  const WCHAR *format,
+                  const EncoderParameters *encoder_params,
+                  GdkPixbufSaveFunc save_func,
+                  gpointer user_data,
+                  GError **error)
+{
+  GpBitmap *image;
+  CLSID clsid;
+  gboolean success;
+
+  if (!GetEncoderClsid (format, &clsid)) {
+    g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, _("Unsupported image format for GDI+"));
+    return FALSE;
+  }
+  
+  image = gdip_pixbuf_to_bitmap (pixbuf);
+
+  if (image == NULL) {
+    g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, _("Couldn't save"));
+    return FALSE;
+  }
+  
+  success = gdip_save_bitmap_to_callback (image, &clsid, encoder_params, save_func, user_data, error);
+
+  GdipDisposeImage ((GpImage *)image);
+
+  return success;
+}
diff --git a/gdk-pixbuf/io-gdip-utils.h b/gdk-pixbuf/io-gdip-utils.h
new file mode 100644 (file)
index 0000000..14681c1
--- /dev/null
@@ -0,0 +1,52 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* GdkPixbuf library - Win32 GDI+ Pixbuf Loader
+ *
+ * Copyright (C) 2008 Dominic Lachowicz
+ * Copyright (C) 2008 Alberto Ruiz
+ *
+ * Authors: Dominic Lachowicz <domlachowicz@gmail.com>
+ *          Alberto Ruiz <aruiz@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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  * You should have received a copy of the GNU Lesser 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 _HAVE_IO_GDIP_UTILS_H
+#define _HAVE_IO_GDIP_UTILS_H
+
+#include "gdk-pixbuf.h"
+#include "gdk-pixbuf-i18n.h"
+
+#include "io-gdip-native.h"
+
+gboolean
+gdip_save_to_file_callback (const gchar *buf,
+                            gsize        count,
+                            GError     **error,
+                            gpointer     data);
+
+void
+gdip_fill_vtable (GdkPixbufModule *module);
+
+void
+gdip_fill_vector_vtable (GdkPixbufModule *module);
+
+gboolean
+gdip_save_pixbuf (GdkPixbuf *pixbuf,
+                  const WCHAR *format,
+                  const EncoderParameters *encoder_params,
+                  GdkPixbufSaveFunc save_func,
+                  gpointer user_data,
+                  GError **error);
+
+#endif
diff --git a/gdk-pixbuf/io-gdip-wmf.c b/gdk-pixbuf/io-gdip-wmf.c
new file mode 100644 (file)
index 0000000..3c89d4a
--- /dev/null
@@ -0,0 +1,63 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* GdkPixbuf library - Win32 GDI+ Pixbuf Loader
+ *
+ * Copyright (C) 2008 Dominic Lachowicz
+ * Copyright (C) 2008 Alberto Ruiz
+ *
+ * Authors: Dominic Lachowicz <domlachowicz@gmail.com>
+ *          Alberto Ruiz <aruiz@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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  * You should have received a copy of the GNU Lesser 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 "io-gdip-utils.h"
+
+#ifndef INCLUDE_gdiplus
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
+#else
+#define MODULE_ENTRY(function) void _gdk_pixbuf__gdip_wmf_ ## function
+#endif
+
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
+{
+  gdip_fill_vector_vtable (module);
+}
+
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
+{
+  static GdkPixbufModulePattern signature[] = {
+    { "\xd7\xcd\xc6\x9a", NULL, 100 }, /* WMF */
+    { "\x01\x00\x09\x00", NULL, 100 }, /* WMF */
+    { NULL, NULL, 0 }
+  };
+
+  static gchar *mime_types[] = {
+    "image/x-wmf",
+    NULL
+  };
+
+  static gchar *extensions[] = {
+    "wmf",
+    "apm",
+    NULL
+  };
+
+  info->name        = "wmf";
+  info->signature   = signature;
+  info->description = _("The WMF image format");
+  info->mime_types  = mime_types;
+  info->extensions  = extensions;
+  info->flags       = GDK_PIXBUF_FORMAT_THREADSAFE;
+  info->license     = "LGPL";
+}
diff --git a/gdk-pixbuf/io-gif-animation.c b/gdk-pixbuf/io-gif-animation.c
new file mode 100644 (file)
index 0000000..17e0aa8
--- /dev/null
@@ -0,0 +1,555 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* GdkPixbuf library - animated gif support
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Authors: Jonathan Blandford <jrb@redhat.com>
+ *          Havoc Pennington <hp@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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 <errno.h>
+#include "gdk-pixbuf-transform.h"
+#include "gdk-pixbuf-private.h"
+#include "io-gif-animation.h"
+
+static void gdk_pixbuf_gif_anim_finalize   (GObject        *object);
+
+static gboolean                gdk_pixbuf_gif_anim_is_static_image  (GdkPixbufAnimation *animation);
+static GdkPixbuf*              gdk_pixbuf_gif_anim_get_static_image (GdkPixbufAnimation *animation);
+
+static void                    gdk_pixbuf_gif_anim_get_size (GdkPixbufAnimation *anim,
+                                                             int                *width,
+                                                             int                *height);
+static GdkPixbufAnimationIter* gdk_pixbuf_gif_anim_get_iter (GdkPixbufAnimation *anim,
+                                                             const GTimeVal     *start_time);
+
+
+\f
+
+G_DEFINE_TYPE (GdkPixbufGifAnim, gdk_pixbuf_gif_anim, GDK_TYPE_PIXBUF_ANIMATION);
+
+static void
+gdk_pixbuf_gif_anim_init (GdkPixbufGifAnim *anim)
+{
+}
+
+static void
+gdk_pixbuf_gif_anim_class_init (GdkPixbufGifAnimClass *klass)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+        GdkPixbufAnimationClass *anim_class = GDK_PIXBUF_ANIMATION_CLASS (klass);
+
+        object_class->finalize = gdk_pixbuf_gif_anim_finalize;
+
+        anim_class->is_static_image = gdk_pixbuf_gif_anim_is_static_image;
+        anim_class->get_static_image = gdk_pixbuf_gif_anim_get_static_image;
+        anim_class->get_size = gdk_pixbuf_gif_anim_get_size;
+        anim_class->get_iter = gdk_pixbuf_gif_anim_get_iter;
+}
+
+static void
+gdk_pixbuf_gif_anim_finalize (GObject *object)
+{
+        GdkPixbufGifAnim *gif_anim = GDK_PIXBUF_GIF_ANIM (object);
+
+        GList *l;
+        GdkPixbufFrame *frame;
+
+        for (l = gif_anim->frames; l; l = l->next) {
+                frame = l->data;
+                g_object_unref (frame->pixbuf);
+                if (frame->composited)
+                        g_object_unref (frame->composited);
+                if (frame->revert)
+                        g_object_unref (frame->revert);
+                g_free (frame);
+        }
+
+        g_list_free (gif_anim->frames);
+
+        G_OBJECT_CLASS (gdk_pixbuf_gif_anim_parent_class)->finalize (object);
+}
+
+static gboolean
+gdk_pixbuf_gif_anim_is_static_image  (GdkPixbufAnimation *animation)
+{
+        GdkPixbufGifAnim *gif_anim;
+
+        gif_anim = GDK_PIXBUF_GIF_ANIM (animation);
+
+        return (gif_anim->frames != NULL &&
+                gif_anim->frames->next == NULL);
+}
+
+static GdkPixbuf*
+gdk_pixbuf_gif_anim_get_static_image (GdkPixbufAnimation *animation)
+{
+        GdkPixbufGifAnim *gif_anim;
+
+        gif_anim = GDK_PIXBUF_GIF_ANIM (animation);
+
+        if (gif_anim->frames == NULL)
+                return NULL;
+        else
+                return GDK_PIXBUF (((GdkPixbufFrame*)gif_anim->frames->data)->pixbuf);
+}
+
+static void
+gdk_pixbuf_gif_anim_get_size (GdkPixbufAnimation *anim,
+                              int                *width,
+                              int                *height)
+{
+        GdkPixbufGifAnim *gif_anim;
+
+        gif_anim = GDK_PIXBUF_GIF_ANIM (anim);
+
+        if (width)
+                *width = gif_anim->width;
+
+        if (height)
+                *height = gif_anim->height;
+}
+
+
+static void
+iter_clear (GdkPixbufGifAnimIter *iter)
+{
+        iter->current_frame = NULL;
+}
+
+static void
+iter_restart (GdkPixbufGifAnimIter *iter)
+{
+        iter_clear (iter);
+
+        iter->current_frame = iter->gif_anim->frames;
+}
+
+static GdkPixbufAnimationIter*
+gdk_pixbuf_gif_anim_get_iter (GdkPixbufAnimation *anim,
+                              const GTimeVal     *start_time)
+{
+        GdkPixbufGifAnimIter *iter;
+
+        iter = g_object_new (GDK_TYPE_PIXBUF_GIF_ANIM_ITER, NULL);
+
+        iter->gif_anim = GDK_PIXBUF_GIF_ANIM (anim);
+
+        g_object_ref (iter->gif_anim);
+
+        iter_restart (iter);
+
+        iter->start_time = *start_time;
+        iter->current_time = *start_time;
+        iter->first_loop_slowness = 0;
+
+        return GDK_PIXBUF_ANIMATION_ITER (iter);
+}
+
+\f
+
+static void gdk_pixbuf_gif_anim_iter_finalize   (GObject                   *object);
+
+static int        gdk_pixbuf_gif_anim_iter_get_delay_time             (GdkPixbufAnimationIter *iter);
+static GdkPixbuf* gdk_pixbuf_gif_anim_iter_get_pixbuf                 (GdkPixbufAnimationIter *iter);
+static gboolean   gdk_pixbuf_gif_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter);
+static gboolean   gdk_pixbuf_gif_anim_iter_advance                    (GdkPixbufAnimationIter *iter,
+                                                                       const GTimeVal         *current_time);
+
+\f
+
+G_DEFINE_TYPE (GdkPixbufGifAnimIter, gdk_pixbuf_gif_anim_iter, GDK_TYPE_PIXBUF_ANIMATION_ITER);
+
+static void
+gdk_pixbuf_gif_anim_iter_init (GdkPixbufGifAnimIter *iter)
+{
+}
+
+static void
+gdk_pixbuf_gif_anim_iter_class_init (GdkPixbufGifAnimIterClass *klass)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+        GdkPixbufAnimationIterClass *anim_iter_class =
+                GDK_PIXBUF_ANIMATION_ITER_CLASS (klass);
+
+        object_class->finalize = gdk_pixbuf_gif_anim_iter_finalize;
+
+        anim_iter_class->get_delay_time = gdk_pixbuf_gif_anim_iter_get_delay_time;
+        anim_iter_class->get_pixbuf = gdk_pixbuf_gif_anim_iter_get_pixbuf;
+        anim_iter_class->on_currently_loading_frame = gdk_pixbuf_gif_anim_iter_on_currently_loading_frame;
+        anim_iter_class->advance = gdk_pixbuf_gif_anim_iter_advance;
+}
+
+static void
+gdk_pixbuf_gif_anim_iter_finalize (GObject *object)
+{
+        GdkPixbufGifAnimIter *iter = GDK_PIXBUF_GIF_ANIM_ITER (object);
+
+        iter_clear (iter);
+
+        g_object_unref (iter->gif_anim);
+
+        G_OBJECT_CLASS (gdk_pixbuf_gif_anim_iter_parent_class)->finalize (object);
+}
+
+static gboolean
+gdk_pixbuf_gif_anim_iter_advance (GdkPixbufAnimationIter *anim_iter,
+                                  const GTimeVal         *current_time)
+{
+        GdkPixbufGifAnimIter *iter;
+        gint elapsed;
+        gint loop;
+        GList *tmp;
+        GList *old;
+
+        iter = GDK_PIXBUF_GIF_ANIM_ITER (anim_iter);
+
+        iter->current_time = *current_time;
+
+        /* We use milliseconds for all times */
+        elapsed =
+          (((iter->current_time.tv_sec - iter->start_time.tv_sec) * G_USEC_PER_SEC +
+            iter->current_time.tv_usec - iter->start_time.tv_usec)) / 1000;
+
+        if (elapsed < 0) {
+                /* Try to compensate; probably the system clock
+                 * was set backwards
+                 */
+                iter->start_time = iter->current_time;
+                elapsed = 0;
+        }
+
+        g_assert (iter->gif_anim->total_time > 0);
+
+        /* See how many times we've already played the full animation,
+         * and subtract time for that.
+         */
+
+        if (iter->gif_anim->loading)
+                loop = 0;
+        else {
+                /* If current_frame is NULL at this point, we have loaded the
+                 * animation from a source which fell behind the speed of the 
+                 * display. We remember how much slower the first loop was due
+                 * to this and correct the position calculation in order to not
+                 * jump in the middle of the second loop.
+                 */
+                if (iter->current_frame == NULL)
+                        iter->first_loop_slowness = MAX(0, elapsed - iter->gif_anim->total_time);
+
+                loop = (elapsed - iter->first_loop_slowness) / iter->gif_anim->total_time;
+                elapsed = (elapsed - iter->first_loop_slowness) % iter->gif_anim->total_time;
+        }
+
+        iter->position = elapsed;
+
+        /* Now move to the proper frame */
+        if (iter->gif_anim->loop == 0 || loop < iter->gif_anim->loop)
+                tmp = iter->gif_anim->frames;
+        else
+                tmp = NULL;
+        while (tmp != NULL) {
+                GdkPixbufFrame *frame = tmp->data;
+
+                if (iter->position >= frame->elapsed &&
+                    iter->position < (frame->elapsed + frame->delay_time))
+                        break;
+
+                tmp = tmp->next;
+        }
+
+        old = iter->current_frame;
+
+        iter->current_frame = tmp;
+
+        return iter->current_frame != old;
+}
+
+int
+gdk_pixbuf_gif_anim_iter_get_delay_time (GdkPixbufAnimationIter *anim_iter)
+{
+        GdkPixbufFrame *frame;
+        GdkPixbufGifAnimIter *iter;
+
+        iter = GDK_PIXBUF_GIF_ANIM_ITER (anim_iter);
+
+        if (iter->current_frame) {
+                frame = iter->current_frame->data;
+
+#if 0
+                g_print ("frame start: %d pos: %d frame len: %d frame remaining: %d\n",
+                         frame->elapsed,
+                         iter->position,
+                         frame->delay_time,
+                         frame->delay_time - (iter->position - frame->elapsed));
+#endif
+
+                return frame->delay_time - (iter->position - frame->elapsed);
+        } else
+                return -1; /* show last frame forever */
+}
+
+void
+gdk_pixbuf_gif_anim_frame_composite (GdkPixbufGifAnim *gif_anim,
+                                     GdkPixbufFrame   *frame)
+{
+        GList *link;
+        GList *tmp;
+
+        link = g_list_find (gif_anim->frames, frame);
+
+        if (frame->need_recomposite || frame->composited == NULL) {
+                /* For now, to composite we start with the last
+                 * composited frame and composite everything up to
+                 * here.
+                 */
+
+                /* Rewind to last composited frame. */
+                tmp = link;
+                while (tmp != NULL) {
+                        GdkPixbufFrame *f = tmp->data;
+
+                        if (f->need_recomposite) {
+                                if (f->composited) {
+                                        g_object_unref (f->composited);
+                                        f->composited = NULL;
+                                }
+                        }
+
+                        if (f->composited != NULL)
+                                break;
+
+                        tmp = tmp->prev;
+                }
+
+                /* Go forward, compositing all frames up to the current frame */
+                if (tmp == NULL)
+                        tmp = gif_anim->frames;
+
+                while (tmp != NULL) {
+                        GdkPixbufFrame *f = tmp->data;
+                        gint clipped_width, clipped_height;
+
+                        if (f->pixbuf == NULL)
+                                return;
+
+                        clipped_width = MIN (gif_anim->width - f->x_offset, gdk_pixbuf_get_width (f->pixbuf));
+                        clipped_height = MIN (gif_anim->height - f->y_offset, gdk_pixbuf_get_height (f->pixbuf));
+
+                        if (f->need_recomposite) {
+                                if (f->composited) {
+                                        g_object_unref (f->composited);
+                                        f->composited = NULL;
+                                }
+                        }
+
+                        if (f->composited != NULL)
+                                goto next;
+
+                        if (tmp->prev == NULL) {
+                                /* First frame may be smaller than the whole image;
+                                 * if so, we make the area outside it full alpha if the
+                                 * image has alpha, and background color otherwise.
+                                 * GIF spec doesn't actually say what to do about this.
+                                 */
+                                f->composited = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+                                                                TRUE,
+                                                                8, gif_anim->width, gif_anim->height);
+
+                                if (f->composited == NULL)
+                                        return;
+
+                                /* alpha gets dumped if f->composited has no alpha */
+
+                                gdk_pixbuf_fill (f->composited,
+                                                 (gif_anim->bg_red << 24) |
+                                                 (gif_anim->bg_green << 16) |
+                                                 (gif_anim->bg_blue << 8));
+
+                                if (clipped_width > 0 && clipped_height > 0)
+                                        gdk_pixbuf_composite (f->pixbuf,
+                                                              f->composited,
+                                                              f->x_offset,
+                                                              f->y_offset,
+                                                              clipped_width,
+                                                              clipped_height,
+                                                              f->x_offset, f->y_offset,
+                                                              1.0, 1.0,
+                                                              GDK_INTERP_BILINEAR,
+                                                              255);
+
+                                if (f->action == GDK_PIXBUF_FRAME_REVERT)
+                                        g_warning ("First frame of GIF has bad dispose mode, GIF loader should not have loaded this image");
+
+                                f->need_recomposite = FALSE;
+                        } else {
+                                GdkPixbufFrame *prev_frame;
+                                gint prev_clipped_width;
+                                gint prev_clipped_height;
+
+                                prev_frame = tmp->prev->data;
+
+                                prev_clipped_width = MIN (gif_anim->width - prev_frame->x_offset, gdk_pixbuf_get_width (prev_frame->pixbuf));
+                                prev_clipped_height = MIN (gif_anim->height - prev_frame->y_offset, gdk_pixbuf_get_height (prev_frame->pixbuf));
+
+                                /* Init f->composited with what we should have after the previous
+                                 * frame
+                                 */
+
+                                if (prev_frame->action == GDK_PIXBUF_FRAME_RETAIN) {
+                                        f->composited = gdk_pixbuf_copy (prev_frame->composited);
+
+                                        if (f->composited == NULL)
+                                                return;
+
+                                } else if (prev_frame->action == GDK_PIXBUF_FRAME_DISPOSE) {
+                                        f->composited = gdk_pixbuf_copy (prev_frame->composited);
+
+                                        if (f->composited == NULL)
+                                                return;
+
+                                        if (prev_clipped_width > 0 && prev_clipped_height > 0) {
+                                                /* Clear area of previous frame to background */
+                                                GdkPixbuf *area;
+
+                                                area = gdk_pixbuf_new_subpixbuf (f->composited,
+                                                                                 prev_frame->x_offset,
+                                                                                 prev_frame->y_offset,
+                                                                                 prev_clipped_width,
+                                                                                 prev_clipped_height);
+
+                                                if (area == NULL)
+                                                        return;
+
+                                                gdk_pixbuf_fill (area,
+                                                                 (gif_anim->bg_red << 24) |
+                                                                 (gif_anim->bg_green << 16) |
+                                                                 (gif_anim->bg_blue << 8));
+
+                                                g_object_unref (area);
+                                        }
+                                } else if (prev_frame->action == GDK_PIXBUF_FRAME_REVERT) {
+                                        f->composited = gdk_pixbuf_copy (prev_frame->composited);
+
+                                        if (f->composited == NULL)
+                                                return;
+
+                                        if (prev_frame->revert != NULL &&
+                                            prev_clipped_width > 0 && prev_clipped_height > 0) {
+                                                /* Copy in the revert frame */
+                                                gdk_pixbuf_copy_area (prev_frame->revert,
+                                                                      0, 0,
+                                                                      gdk_pixbuf_get_width (prev_frame->revert),
+                                                                      gdk_pixbuf_get_height (prev_frame->revert),
+                                                                      f->composited,
+                                                                      prev_frame->x_offset,
+                                                                      prev_frame->y_offset);
+                                        }
+                                } else {
+                                        g_warning ("Unknown revert action for GIF frame");
+                                }
+
+                                if (f->revert == NULL &&
+                                    f->action == GDK_PIXBUF_FRAME_REVERT) {
+                                        if (clipped_width > 0 && clipped_height > 0) {
+                                                /* We need to save the contents before compositing */
+                                                GdkPixbuf *area;
+
+                                                area = gdk_pixbuf_new_subpixbuf (f->composited,
+                                                                                 f->x_offset,
+                                                                                 f->y_offset,
+                                                                                 clipped_width,
+                                                                                 clipped_height);
+
+                                                if (area == NULL)
+                                                        return;
+
+                                                f->revert = gdk_pixbuf_copy (area);
+
+                                                g_object_unref (area);
+
+                                                if (f->revert == NULL)
+                                                        return;
+                                        }
+                                }
+
+                                if (clipped_width > 0 && clipped_height > 0 &&
+                                    f->pixbuf != NULL && f->composited != NULL) {
+                                        /* Put current frame onto f->composited */
+                                        gdk_pixbuf_composite (f->pixbuf,
+                                                              f->composited,
+                                                              f->x_offset,
+                                                              f->y_offset,
+                                                              clipped_width,
+                                                              clipped_height,
+                                                              f->x_offset, f->y_offset,
+                                                              1.0, 1.0,
+                                                              GDK_INTERP_NEAREST,
+                                                              255);
+                                }
+
+                                f->need_recomposite = FALSE;
+                        }
+
+                next:
+                        if (tmp == link)
+                                break;
+
+                        tmp = tmp->next;
+                }
+        }
+}
+
+GdkPixbuf*
+gdk_pixbuf_gif_anim_iter_get_pixbuf (GdkPixbufAnimationIter *anim_iter)
+{
+        GdkPixbufGifAnimIter *iter;
+        GdkPixbufFrame *frame;
+
+        iter = GDK_PIXBUF_GIF_ANIM_ITER (anim_iter);
+
+        frame = iter->current_frame ? iter->current_frame->data : g_list_last (iter->gif_anim->frames)->data;
+
+#if 0
+        if (FALSE && frame)
+          g_print ("current frame %d dispose mode %d  %d x %d\n",
+                   g_list_index (iter->gif_anim->frames,
+                                 frame),
+                   frame->action,
+                   gdk_pixbuf_get_width (frame->pixbuf),
+                   gdk_pixbuf_get_height (frame->pixbuf));
+#endif
+
+        if (frame == NULL)
+                return NULL;
+
+        gdk_pixbuf_gif_anim_frame_composite (iter->gif_anim, frame);
+
+        return frame->composited;
+}
+
+static gboolean
+gdk_pixbuf_gif_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *anim_iter)
+{
+        GdkPixbufGifAnimIter *iter;
+
+        iter = GDK_PIXBUF_GIF_ANIM_ITER (anim_iter);
+
+        return iter->current_frame == NULL || iter->current_frame->next == NULL;
+}
diff --git a/gdk-pixbuf/io-gif-animation.h b/gdk-pixbuf/io-gif-animation.h
new file mode 100644 (file)
index 0000000..3e8e522
--- /dev/null
@@ -0,0 +1,175 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* GdkPixbuf library - GIF loader declarations
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Authors: Mark Crichton <crichton@gimp.org>
+ *          Miguel de Icaza <miguel@gnu.org>
+ *          Federico Mena-Quintero <federico@gimp.org>
+ *          Havoc Pennington <hp@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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_GIF_H
+#define GDK_PIXBUF_GIF_H
+
+#include "gdk-pixbuf-animation.h"
+
+typedef enum {
+        /* Keep this frame and composite next frame over it */
+        /* (GIF disposal method 1) */
+       GDK_PIXBUF_FRAME_RETAIN,
+        /* Revert to background color before compositing next frame */
+        /* (GIF disposal method 2) */
+       GDK_PIXBUF_FRAME_DISPOSE,
+        /* Revert to previously-displayed composite image after
+         * displaying this frame
+         */
+        /* (GIF disposal method 3) */
+       GDK_PIXBUF_FRAME_REVERT
+} GdkPixbufFrameAction;
+
+\f
+
+typedef struct _GdkPixbufGifAnim GdkPixbufGifAnim;
+typedef struct _GdkPixbufGifAnimClass GdkPixbufGifAnimClass;
+typedef struct _GdkPixbufFrame GdkPixbufFrame;
+
+#define GDK_TYPE_PIXBUF_GIF_ANIM              (gdk_pixbuf_gif_anim_get_type ())
+#define GDK_PIXBUF_GIF_ANIM(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_GIF_ANIM, GdkPixbufGifAnim))
+#define GDK_IS_PIXBUF_GIF_ANIM(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_GIF_ANIM))
+
+#define GDK_PIXBUF_GIF_ANIM_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_GIF_ANIM, GdkPixbufGifAnimClass))
+#define GDK_IS_PIXBUF_GIF_ANIM_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_GIF_ANIM))
+#define GDK_PIXBUF_GIF_ANIM_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_GIF_ANIM, GdkPixbufGifAnimClass))
+
+/* Private part of the GdkPixbufGifAnim structure */
+struct _GdkPixbufGifAnim {
+        GdkPixbufAnimation parent_instance;
+
+        /* Number of frames */
+        int n_frames;
+
+        /* Total length of animation */
+        int total_time;
+        
+       /* List of GdkPixbufFrame structures */
+        GList *frames;
+
+       /* bounding box size */
+       int width, height;
+
+        guchar bg_red;
+        guchar bg_green;
+        guchar bg_blue;
+        
+        int loop;
+        gboolean loading;
+};
+
+struct _GdkPixbufGifAnimClass {
+        GdkPixbufAnimationClass parent_class;
+        
+};
+
+GType gdk_pixbuf_gif_anim_get_type (void) G_GNUC_CONST;
+
+\f
+
+typedef struct _GdkPixbufGifAnimIter GdkPixbufGifAnimIter;
+typedef struct _GdkPixbufGifAnimIterClass GdkPixbufGifAnimIterClass;
+
+
+#define GDK_TYPE_PIXBUF_GIF_ANIM_ITER              (gdk_pixbuf_gif_anim_iter_get_type ())
+#define GDK_PIXBUF_GIF_ANIM_ITER(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_GIF_ANIM_ITER, GdkPixbufGifAnimIter))
+#define GDK_IS_PIXBUF_GIF_ANIM_ITER(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_GIF_ANIM_ITER))
+
+#define GDK_PIXBUF_GIF_ANIM_ITER_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_GIF_ANIM_ITER, GdkPixbufGifAnimIterClass))
+#define GDK_IS_PIXBUF_GIF_ANIM_ITER_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_GIF_ANIM_ITER))
+#define GDK_PIXBUF_GIF_ANIM_ITER_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_GIF_ANIM_ITER, GdkPixbufGifAnimIterClass))
+
+struct _GdkPixbufGifAnimIter {
+        GdkPixbufAnimationIter parent_instance;
+        
+        GdkPixbufGifAnim   *gif_anim;
+
+        GTimeVal            start_time;
+        GTimeVal            current_time;
+
+        /* Time in milliseconds into this run of the animation */
+        gint                position;
+        
+        GList              *current_frame;
+        
+        gint                first_loop_slowness;
+};
+
+struct _GdkPixbufGifAnimIterClass {
+        GdkPixbufAnimationIterClass parent_class;
+
+};
+
+GType gdk_pixbuf_gif_anim_iter_get_type (void) G_GNUC_CONST;
+
+\f
+
+struct _GdkPixbufFrame {
+       /* The pixbuf with this frame's image data */
+       GdkPixbuf *pixbuf;
+
+        /* Offsets for overlaying onto the GIF graphic area */
+        int x_offset;
+       int y_offset;
+
+       /* Frame duration in ms */
+       int delay_time;
+
+        /* Sum of preceding delay times */
+        int elapsed;
+        
+        /* Overlay mode */
+       GdkPixbufFrameAction action;
+
+        /* TRUE if the pixbuf has been modified since
+         * the last frame composite operation
+         */
+        gboolean need_recomposite;
+
+        /* TRUE if the background for this frame is transparent */
+        gboolean bg_transparent;
+        
+        /* The below reflects the "use hell of a lot of RAM"
+         * philosophy of coding
+         */
+        
+        /* Cached composite image (the image you actually display
+         * for this frame)
+         */
+        GdkPixbuf *composited;
+
+        /* Cached revert image (the contents of the area
+         * covered by the frame prior to compositing;
+         * same size as pixbuf, not as the composite image; only
+         * used for FRAME_REVERT frames)
+         */
+        GdkPixbuf *revert;
+};
+
+void gdk_pixbuf_gif_anim_frame_composite (GdkPixbufGifAnim *gif_anim,
+                                          GdkPixbufFrame   *frame);
+
+#endif
diff --git a/gdk-pixbuf/io-gif.c b/gdk-pixbuf/io-gif.c
new file mode 100644 (file)
index 0000000..8a1fa3e
--- /dev/null
@@ -0,0 +1,1704 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* GdkPixbuf library - GIF image loader
+ *
+ * Copyright (C) 1999 Mark Crichton
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Authors: Jonathan Blandford <jrb@redhat.com>
+ *          Adapted from the gimp gif filter written by Adam Moss <adam@gimp.org>
+ *          Gimp work based on earlier work.
+ *          Permission to relicense under the LGPL obtained.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+/* This loader is very hairy code.
+ *
+ * The main loop was not designed for incremental loading, so when it was hacked
+ * in it got a bit messy.  Basicly, every function is written to expect a failed
+ * read_gif, and lets you call it again assuming that the bytes are there.
+ *
+ * Return vals.
+ * Unless otherwise specified, these are the return vals for most functions:
+ *
+ *  0 -> success
+ * -1 -> more bytes needed.
+ * -2 -> failure; abort the load
+ * -3 -> control needs to be passed back to the main loop
+ *        \_ (most of the time returning 0 will get this, but not always)
+ *
+ * >1 -> for functions that get a guchar, the char will be returned.
+ *
+ * -jrb (11/03/1999)
+ */
+
+/*
+ * If you have any images that crash this code, please, please let me know and
+ * send them to me.
+ *                                            <jrb@redhat.com>
+ */
+
+\f
+
+#include "config.h"
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include "gdk-pixbuf-private.h"
+#include "io-gif-animation.h"
+
+\f
+
+#undef DUMP_IMAGE_DETAILS 
+#undef IO_GIFDEBUG
+
+#define MAXCOLORMAPSIZE  256
+#define MAX_LZW_BITS     12
+
+#define INTERLACE          0x40
+#define LOCALCOLORMAP      0x80
+#define BitSet(byte, bit)  (((byte) & (bit)) == (bit))
+#define LM_to_uint(a,b)         (((b)<<8)|(a))
+
+\f
+
+typedef unsigned char CMap[3][MAXCOLORMAPSIZE];
+
+/* Possible states we can be in. */
+enum {
+       GIF_START,
+       GIF_GET_COLORMAP,
+       GIF_GET_NEXT_STEP,
+       GIF_GET_FRAME_INFO,
+       GIF_GET_EXTENSION,
+       GIF_GET_COLORMAP2,
+       GIF_PREPARE_LZW,
+       GIF_LZW_FILL_BUFFER,
+       GIF_LZW_CLEAR_CODE,
+       GIF_GET_LZW,
+       GIF_DONE
+};
+
+
+typedef struct _Gif89 Gif89;
+struct _Gif89
+{
+       int transparent;
+       int delay_time;
+       int input_flag;
+       int disposal;
+};
+
+typedef struct _GifContext GifContext;
+struct _GifContext
+{
+       int state; /* really only relevant for progressive loading */
+       unsigned int width;
+       unsigned int height;
+
+        gboolean has_global_cmap;
+
+        CMap global_color_map;
+        gint global_colormap_size;
+        unsigned int global_bit_pixel;
+       unsigned int global_color_resolution;
+        unsigned int background_index;
+        gboolean stop_after_first_frame;
+
+        gboolean frame_cmap_active;
+        CMap frame_color_map;
+        gint frame_colormap_size;
+        unsigned int frame_bit_pixel;
+
+       unsigned int aspect_ratio;
+       GdkPixbufGifAnim *animation;
+       GdkPixbufFrame *frame;
+       Gif89 gif89;
+
+       /* stuff per frame. */
+       int frame_len;
+       int frame_height;
+       int frame_interlace;
+       int x_offset;
+       int y_offset;
+
+       /* Static read only */
+       FILE *file;
+
+       /* progressive read, only. */
+       GdkPixbufModulePreparedFunc prepare_func;
+       GdkPixbufModuleUpdatedFunc update_func;
+       gpointer user_data;
+        guchar *buf;
+       guint ptr;
+       guint size;
+       guint amount_needed;
+
+       /* extension context */
+       guchar extension_label;
+       guchar extension_flag;
+        gboolean in_loop_extension;
+
+       /* get block context */
+       guchar block_count;
+       guchar block_buf[280];
+       gint block_ptr;
+
+       int old_state; /* used by lzw_fill buffer */
+       /* get_code context */
+       int code_curbit;
+       int code_lastbit;
+       int code_done;
+       int code_last_byte;
+       int lzw_code_pending;
+
+       /* lzw context */
+       gint lzw_fresh;
+       gint lzw_code_size;
+       guchar lzw_set_code_size;
+       gint lzw_max_code;
+       gint lzw_max_code_size;
+       gint lzw_firstcode;
+       gint lzw_oldcode;
+       gint lzw_clear_code;
+       gint lzw_end_code;
+       gint *lzw_sp;
+
+       gint lzw_table[2][(1 << MAX_LZW_BITS)];
+       gint lzw_stack[(1 << (MAX_LZW_BITS)) * 2 + 1];
+
+       /* painting context */
+       gint draw_xpos;
+       gint draw_ypos;
+       gint draw_pass;
+
+        /* error pointer */
+        GError **error;
+};
+
+static int GetDataBlock (GifContext *, unsigned char *);
+
+\f
+
+#ifdef IO_GIFDEBUG
+static int count = 0;
+#endif
+
+/* Returns TRUE if read is OK,
+ * FALSE if more memory is needed. */
+static gboolean
+gif_read (GifContext *context, guchar *buffer, size_t len)
+{
+       gboolean retval;
+#ifdef IO_GIFDEBUG
+       gint i;
+#endif
+       if (context->file) {
+#ifdef IO_GIFDEBUG
+               count += len;
+               g_print ("Fsize :%d\tcount :%d\t", len, count);
+#endif
+               retval = (fread(buffer, len, 1, context->file) != 0);
+
+                if (!retval && ferror (context->file)) {
+                        gint save_errno = errno;
+                        g_set_error (context->error,
+                                     G_FILE_ERROR,
+                                     g_file_error_from_errno (save_errno),
+                                     _("Failure reading GIF: %s"), 
+                                     g_strerror (save_errno));
+                }
+                
+#ifdef IO_GIFDEBUG
+               if (len < 100) {
+                       for (i = 0; i < len; i++)
+                               g_print ("%d ", buffer[i]);
+               }
+               g_print ("\n");
+#endif
+                
+               return retval;
+       } else {
+#ifdef IO_GIFDEBUG
+/*             g_print ("\tlooking for %d bytes.  size == %d, ptr == %d\n", len, context->size, context->ptr); */
+#endif
+               if ((context->size - context->ptr) >= len) {
+#ifdef IO_GIFDEBUG
+                       count += len;
+#endif
+                       memcpy (buffer, context->buf + context->ptr, len);
+                       context->ptr += len;
+                       context->amount_needed = 0;
+#ifdef IO_GIFDEBUG
+                       g_print ("Psize :%d\tcount :%d\t", len, count);
+                       if (len < 100) {
+                               for (i = 0; i < len; i++)
+                                       g_print ("%d ", buffer[i]);
+                       }
+                       g_print ("\n");
+#endif
+                       return TRUE;
+               }
+               context->amount_needed = len - (context->size - context->ptr);
+       }
+       return FALSE;
+}
+
+/* Changes the stage to be GIF_GET_COLORMAP */
+static void
+gif_set_get_colormap (GifContext *context)
+{
+       context->global_colormap_size = 0;
+       context->state = GIF_GET_COLORMAP;
+}
+
+static void
+gif_set_get_colormap2 (GifContext *context)
+{
+       context->frame_colormap_size = 0;
+       context->state = GIF_GET_COLORMAP2;
+}
+
+static gint
+gif_get_colormap (GifContext *context)
+{
+       unsigned char rgb[3];
+
+       while (context->global_colormap_size < context->global_bit_pixel) {
+               if (!gif_read (context, rgb, sizeof (rgb))) {
+                       return -1;
+               }
+
+               context->global_color_map[0][context->global_colormap_size] = rgb[0];
+               context->global_color_map[1][context->global_colormap_size] = rgb[1];
+               context->global_color_map[2][context->global_colormap_size] = rgb[2];
+
+                if (context->global_colormap_size == context->background_index) {
+                        context->animation->bg_red = rgb[0];
+                        context->animation->bg_green = rgb[1];
+                        context->animation->bg_blue = rgb[2];
+                }
+
+               context->global_colormap_size ++;
+       }
+
+       return 0;
+}
+
+
+static gint
+gif_get_colormap2 (GifContext *context)
+{
+       unsigned char rgb[3];
+
+       while (context->frame_colormap_size < context->frame_bit_pixel) {
+               if (!gif_read (context, rgb, sizeof (rgb))) {
+                       return -1;
+               }
+
+               context->frame_color_map[0][context->frame_colormap_size] = rgb[0];
+               context->frame_color_map[1][context->frame_colormap_size] = rgb[1];
+               context->frame_color_map[2][context->frame_colormap_size] = rgb[2];
+
+               context->frame_colormap_size ++;
+       }
+
+       return 0;
+}
+
+/*
+ * in order for this function to work, we need to perform some black magic.
+ * We want to return -1 to let the calling function know, as before, that it needs
+ * more bytes.  If we return 0, we were able to successfully read all block->count bytes.
+ * Problem is, we don't want to reread block_count every time, so we check to see if
+ * context->block_count is 0 before we read in the function.
+ *
+ * As a result, context->block_count MUST be 0 the first time the get_data_block is called
+ * within a context, and cannot be 0 the second time it's called.
+ */
+
+static int
+get_data_block (GifContext *context,
+               unsigned char *buf,
+               gint *empty_block)
+{
+
+       if (context->block_count == 0) {
+               if (!gif_read (context, &context->block_count, 1)) {
+                       return -1;
+               }
+       }
+
+       if (context->block_count == 0)
+               if (empty_block) {
+                       *empty_block = TRUE;
+                       return 0;
+               }
+
+       if (!gif_read (context, buf, context->block_count)) {
+               return -1;
+       }
+
+       return 0;
+}
+
+static void
+gif_set_get_extension (GifContext *context)
+{
+       context->state = GIF_GET_EXTENSION;
+       context->extension_flag = TRUE;
+       context->extension_label = 0;
+       context->block_count = 0;
+       context->block_ptr = 0;
+}
+
+static int
+gif_get_extension (GifContext *context)
+{
+       gint retval;
+       gint empty_block = FALSE;
+
+       if (context->extension_flag) {
+               if (context->extension_label == 0) {
+                       /* I guess bad things can happen if we have an extension of 0 )-: */
+                       /* I should look into this sometime */
+                       if (!gif_read (context, & context->extension_label , 1)) {
+                               return -1;
+                       }
+               }
+
+               switch (context->extension_label) {
+                case 0xf9:                     /* Graphic Control Extension */
+                        retval = get_data_block (context, (unsigned char *) context->block_buf, NULL);
+                       if (retval != 0)
+                               return retval;
+
+                       if (context->frame == NULL) {
+                               /* I only want to set the transparency if I haven't
+                                * created the frame yet.
+                                 */
+                               context->gif89.disposal = (context->block_buf[0] >> 2) & 0x7;
+                               context->gif89.input_flag = (context->block_buf[0] >> 1) & 0x1;
+                               context->gif89.delay_time = LM_to_uint (context->block_buf[1], context->block_buf[2]);
+                               
+                               if ((context->block_buf[0] & 0x1) != 0) {
+                                       context->gif89.transparent = context->block_buf[3];
+                               } else {
+                                       context->gif89.transparent = -1;
+                               }
+                       }
+
+                       /* Now we've successfully loaded this one, we continue on our way */
+                       context->block_count = 0;
+                       context->extension_flag = FALSE;
+                       break;
+                case 0xff: /* application extension */
+                        if (!context->in_loop_extension) { 
+                                retval = get_data_block (context, (unsigned char *) context->block_buf, NULL);
+                                if (retval != 0)
+                                        return retval;
+                                if (!strncmp ((gchar *)context->block_buf, "NETSCAPE2.0", 11) ||
+                                    !strncmp ((gchar *)context->block_buf, "ANIMEXTS1.0", 11)) {
+                                        context->in_loop_extension = TRUE;
+                                }
+                                context->block_count = 0;
+                        }
+                        if (context->in_loop_extension) {
+                                do {
+                                        retval = get_data_block (context, (unsigned char *) context->block_buf, &empty_block);
+                                        if (retval != 0)
+                                                return retval;
+                                        if (context->block_buf[0] == 0x01) {
+                                                context->animation->loop = context->block_buf[1] + (context->block_buf[2] << 8);
+                                                if (context->animation->loop != 0) 
+                                                        context->animation->loop++;
+                                        }
+                                        context->block_count = 0;
+                                }
+                                while (!empty_block);
+                                context->in_loop_extension = FALSE;
+                                context->extension_flag = FALSE;
+                                return 0;
+                        }
+                       break;                          
+               default:
+                       /* Unhandled extension */
+                       break;
+               }
+       }
+       /* read all blocks, until I get an empty block, in case there was an extension I didn't know about. */
+       do {
+               retval = get_data_block (context, (unsigned char *) context->block_buf, &empty_block);
+               if (retval != 0)
+                       return retval;
+               context->block_count = 0;
+       } while (!empty_block);
+
+       return 0;
+}
+
+static int ZeroDataBlock = FALSE;
+
+static int
+GetDataBlock (GifContext *context,
+             unsigned char *buf)
+{
+/*     unsigned char count; */
+
+       if (!gif_read (context, &context->block_count, 1)) {
+               /*g_message (_("GIF: error in getting DataBlock size\n"));*/
+               return -1;
+       }
+
+       ZeroDataBlock = context->block_count == 0;
+
+       if ((context->block_count != 0) && (!gif_read (context, buf, context->block_count))) {
+               /*g_message (_("GIF: error in reading DataBlock\n"));*/
+               return -1;
+       }
+
+       return context->block_count;
+}
+
+
+static void
+gif_set_lzw_fill_buffer (GifContext *context)
+{
+       context->block_count = 0;
+       context->old_state = context->state;
+       context->state = GIF_LZW_FILL_BUFFER;
+}
+
+static int
+gif_lzw_fill_buffer (GifContext *context)
+{
+       gint retval;
+
+       if (context->code_done) {
+               if (context->code_curbit >= context->code_lastbit) {
+                        g_set_error_literal (context->error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                             _("GIF file was missing some data (perhaps it was truncated somehow?)"));
+
+                       return -2;
+               }
+                /* Is this supposed to be an error or what? */
+               /* g_message ("trying to read more data after we've done stuff\n"); */
+                g_set_error (context->error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_FAILED,
+                             _("Internal error in the GIF loader (%s)"),
+                             G_STRLOC);
+                
+               return -2;
+       }
+
+       context->block_buf[0] = context->block_buf[context->code_last_byte - 2];
+       context->block_buf[1] = context->block_buf[context->code_last_byte - 1];
+
+       retval = get_data_block (context, &context->block_buf[2], NULL);
+
+       if (retval == -1)
+               return -1;
+
+       if (context->block_count == 0)
+               context->code_done = TRUE;
+
+       context->code_last_byte = 2 + context->block_count;
+       context->code_curbit = (context->code_curbit - context->code_lastbit) + 16;
+       context->code_lastbit = (2 + context->block_count) * 8;
+
+       context->state = context->old_state;
+       return 0;
+}
+
+static int
+get_code (GifContext *context,
+         int   code_size)
+{
+       int i, j, ret;
+
+       if ((context->code_curbit + code_size) >= context->code_lastbit){
+               gif_set_lzw_fill_buffer (context);
+               return -3;
+       }
+
+       ret = 0;
+       for (i = context->code_curbit, j = 0; j < code_size; ++i, ++j)
+               ret |= ((context->block_buf[i / 8] & (1 << (i % 8))) != 0) << j;
+
+       context->code_curbit += code_size;
+
+       return ret;
+}
+
+
+static void
+set_gif_lzw_clear_code (GifContext *context)
+{
+       context->state = GIF_LZW_CLEAR_CODE;
+       context->lzw_code_pending = -1;
+}
+
+static int
+gif_lzw_clear_code (GifContext *context)
+{
+       gint code;
+
+       code = get_code (context, context->lzw_code_size);
+       if (code == -3)
+               return -0;
+
+       context->lzw_firstcode = context->lzw_oldcode = code;
+       context->lzw_code_pending = code;
+       context->state = GIF_GET_LZW;
+       return 0;
+}
+
+#define CHECK_LZW_SP() G_STMT_START {                                           \
+        if ((guchar *)context->lzw_sp >=                                        \
+            (guchar *)context->lzw_stack + sizeof (context->lzw_stack)) {       \
+                 g_set_error_literal (context->error,                           \
+                                      GDK_PIXBUF_ERROR,                         \
+                                      GDK_PIXBUF_ERROR_CORRUPT_IMAGE,           \
+                                      _("Stack overflow"));                     \
+                return -2;                                                      \
+        }                                                                       \
+} G_STMT_END
+
+static int
+lzw_read_byte (GifContext *context)
+{
+       int code, incode;
+       gint retval;
+       gint my_retval;
+       register int i;
+
+       if (context->lzw_code_pending != -1) {
+               retval = context->lzw_code_pending;
+               context->lzw_code_pending = -1;
+               return retval;
+       }
+
+       if (context->lzw_fresh) {
+               context->lzw_fresh = FALSE;
+               do {
+                       retval = get_code (context, context->lzw_code_size);
+                       if (retval < 0) {
+                               return retval;
+                       }
+
+                       context->lzw_firstcode = context->lzw_oldcode = retval;
+               } while (context->lzw_firstcode == context->lzw_clear_code);
+               return context->lzw_firstcode;
+       }
+
+       if (context->lzw_sp > context->lzw_stack) {
+               my_retval = *--(context->lzw_sp);
+               return my_retval;
+       }
+
+       while ((code = get_code (context, context->lzw_code_size)) >= 0) {
+               if (code == context->lzw_clear_code) {
+                       for (i = 0; i < context->lzw_clear_code; ++i) {
+                               context->lzw_table[0][i] = 0;
+                               context->lzw_table[1][i] = i;
+                       }
+                       for (; i < (1 << MAX_LZW_BITS); ++i)
+                               context->lzw_table[0][i] = context->lzw_table[1][i] = 0;
+                       context->lzw_code_size = context->lzw_set_code_size + 1;
+                       context->lzw_max_code_size = 2 * context->lzw_clear_code;
+                       context->lzw_max_code = context->lzw_clear_code + 2;
+                       context->lzw_sp = context->lzw_stack;
+
+                       set_gif_lzw_clear_code (context);
+                       return -3;
+               } else if (code == context->lzw_end_code) {
+                       int count;
+                       unsigned char buf[260];
+
+                        /*  FIXME - we should handle this case */
+                        g_set_error_literal (context->error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_FAILED,
+                                             _("GIF image loader cannot understand this image."));
+                        return -2;
+                        
+                       if (ZeroDataBlock) {
+                               return -2;
+                       }
+
+                       while ((count = GetDataBlock (context, buf)) > 0)
+                               ;
+
+                       if (count != 0) {
+                               /*g_print (_("GIF: missing EOD in data stream (common occurence)"));*/
+                               return -2;
+                       }
+               }
+
+               incode = code;
+
+               if (code >= context->lzw_max_code) {
+                        CHECK_LZW_SP ();
+                       *(context->lzw_sp)++ = context->lzw_firstcode;
+                       code = context->lzw_oldcode;
+               }
+
+               while (code >= context->lzw_clear_code) {
+                        if (code >= (1 << MAX_LZW_BITS)) {
+                                g_set_error_literal (context->error,
+                                                     GDK_PIXBUF_ERROR,
+                                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                                     _("Bad code encountered"));
+                               return -2;
+                        }
+                        CHECK_LZW_SP ();
+                       *(context->lzw_sp)++ = context->lzw_table[1][code];
+
+                       if (code == context->lzw_table[0][code]) {
+                                g_set_error_literal (context->error,
+                                                     GDK_PIXBUF_ERROR,
+                                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                                     _("Circular table entry in GIF file"));
+                               return -2;
+                       }
+                       code = context->lzw_table[0][code];
+               }
+
+                CHECK_LZW_SP ();
+               *(context->lzw_sp)++ = context->lzw_firstcode = context->lzw_table[1][code];
+
+               if ((code = context->lzw_max_code) < (1 << MAX_LZW_BITS)) {
+                       context->lzw_table[0][code] = context->lzw_oldcode;
+                       context->lzw_table[1][code] = context->lzw_firstcode;
+                       ++context->lzw_max_code;
+                       if ((context->lzw_max_code >= context->lzw_max_code_size) &&
+                           (context->lzw_max_code_size < (1 << MAX_LZW_BITS))) {
+                               context->lzw_max_code_size *= 2;
+                               ++context->lzw_code_size;
+                       }
+               }
+
+               context->lzw_oldcode = incode;
+
+               if (context->lzw_sp > context->lzw_stack) {
+                       my_retval = *--(context->lzw_sp);
+                       return my_retval;
+               }
+       }
+       return code;
+}
+
+static void
+gif_set_get_lzw (GifContext *context)
+{
+       context->state = GIF_GET_LZW;
+       context->draw_xpos = 0;
+       context->draw_ypos = 0;
+       context->draw_pass = 0;
+}
+
+static void
+gif_fill_in_pixels (GifContext *context, guchar *dest, gint offset, guchar v)
+{
+       guchar *pixel = NULL;
+        guchar (*cmap)[MAXCOLORMAPSIZE];
+
+        if (context->frame_cmap_active)
+                cmap = context->frame_color_map;
+        else
+                cmap = context->global_color_map;
+        
+       if (context->gif89.transparent != -1) {
+               pixel = dest + (context->draw_ypos + offset) * gdk_pixbuf_get_rowstride (context->frame->pixbuf) + context->draw_xpos * 4;
+               *pixel = cmap [0][(guchar) v];
+               *(pixel+1) = cmap [1][(guchar) v];
+               *(pixel+2) = cmap [2][(guchar) v];
+               *(pixel+3) = (guchar) ((v == context->gif89.transparent) ? 0 : 255);
+       } else {
+               pixel = dest + (context->draw_ypos + offset) * gdk_pixbuf_get_rowstride (context->frame->pixbuf) + context->draw_xpos * 3;
+               *pixel = cmap [0][(guchar) v];
+               *(pixel+1) = cmap [1][(guchar) v];
+               *(pixel+2) = cmap [2][(guchar) v];
+       }
+}
+
+
+/* only called if progressive and interlaced */
+static void
+gif_fill_in_lines (GifContext *context, guchar *dest, guchar v)
+{
+       switch (context->draw_pass) {
+       case 0:
+               if (context->draw_ypos > 4) {
+                       gif_fill_in_pixels (context, dest, -4, v);
+                       gif_fill_in_pixels (context, dest, -3, v);
+               }
+               if (context->draw_ypos < (context->frame_height - 4)) {
+                       gif_fill_in_pixels (context, dest, 3, v);
+                       gif_fill_in_pixels (context, dest, 4, v);
+               }
+               /* we don't need a break here.  We draw the outer pixels first, then the
+                * inner ones, then the innermost ones.  case 0 needs to draw all 3 bands.
+                * case 1, just the last two, and case 2 just draws the last one*/
+       case 1:
+               if (context->draw_ypos > 2)
+                       gif_fill_in_pixels (context, dest, -2, v);
+               if (context->draw_ypos < (context->frame_height - 2))
+                       gif_fill_in_pixels (context, dest, 2, v);
+               /* no break as above. */
+       case 2:
+               if (context->draw_ypos > 1)
+                       gif_fill_in_pixels (context, dest, -1, v);
+               if (context->draw_ypos < (context->frame_height - 1))
+                       gif_fill_in_pixels (context, dest, 1, v);
+       case 3:
+       default:
+               break;
+       }
+}
+
+/* Clips a rectancle to the base dimensions. Returns TRUE if the clipped rectangle is non-empty. */
+static gboolean
+clip_frame (GifContext *context, 
+            gint       *x, 
+            gint       *y, 
+            gint       *width, 
+            gint       *height)
+{
+        gint orig_x, orig_y;
+        
+        orig_x = *x;
+        orig_y = *y;
+       *x = MAX (0, *x);
+       *y = MAX (0, *y);
+       *width = MIN (context->width, orig_x + *width) - *x;
+       *height = MIN (context->height, orig_y + *height) - *y;
+
+       if (*width > 0 && *height > 0)
+               return TRUE;
+
+       /* The frame is completely off-bounds */
+
+       *x = 0;
+       *y = 0;
+       *width = 0;
+       *height = 0;
+
+        return FALSE;
+}
+
+/* Call update_func on the given rectangle, unless it is completely off-bounds */
+static void
+maybe_update (GifContext *context,
+              gint        x,
+              gint        y,
+              gint        width,
+              gint        height)
+{
+        if (clip_frame (context, &x, &y, &width, &height))
+                (*context->update_func) (context->frame->pixbuf, 
+                                         x, y, width, height,
+                                         context->user_data);
+}
+
+static int
+gif_get_lzw (GifContext *context)
+{
+       guchar *dest, *temp;
+       gint lower_bound, upper_bound; /* bounds for emitting the area_updated signal */
+       gboolean bound_flag;
+       gint first_pass; /* bounds for emitting the area_updated signal */
+       gint v;
+
+       if (context->frame == NULL) {
+                context->frame = g_new (GdkPixbufFrame, 1);
+
+                context->frame->composited = NULL;
+                context->frame->revert = NULL;
+                
+                if (context->frame_len == 0 || context->frame_height == 0) {
+                        /* An empty frame, we just output a single transparent
+                         * pixel at (0, 0).
+                         */
+                        context->x_offset = 0;
+                        context->y_offset = 0;
+                        context->frame_len = 1;
+                        context->frame_height = 1;
+                        context->frame->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 1, 1);
+                        if (context->frame->pixbuf) {
+                                guchar *pixels;
+
+                                pixels = gdk_pixbuf_get_pixels (context->frame->pixbuf);
+                                pixels[0] = 0;
+                                pixels[1] = 0;
+                                pixels[2] = 0;
+                                pixels[3] = 0;
+                        }
+                } else
+                        context->frame->pixbuf =
+                                gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+                                                TRUE,
+                                                8,
+                                                context->frame_len,
+                                                context->frame_height);
+                if (!context->frame->pixbuf) {
+                        g_free (context->frame);
+                        g_set_error_literal (context->error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                             _("Not enough memory to load GIF file"));
+                        return -2;
+                }
+
+                context->frame->x_offset = context->x_offset;
+                context->frame->y_offset = context->y_offset;
+                context->frame->need_recomposite = TRUE;
+                
+                /* GIF delay is in hundredths, we want thousandths */
+                context->frame->delay_time = context->gif89.delay_time * 10;
+
+                /* GIFs with delay time 0 are mostly broken, but they
+                 * just want a default, "not that fast" delay.
+                 */
+                if (context->frame->delay_time == 0)
+                        context->frame->delay_time = 100;
+
+                /* No GIFs gets to play faster than 50 fps. They just
+                 * lock up poor gtk.
+                 */
+                if (context->frame->delay_time < 20)
+                        context->frame->delay_time = 20; /* 20 = "fast" */
+                
+                context->frame->elapsed = context->animation->total_time;
+                context->animation->total_time += context->frame->delay_time;                
+                
+                switch (context->gif89.disposal) {
+                case 0:
+                case 1:
+                        context->frame->action = GDK_PIXBUF_FRAME_RETAIN;
+                        break;
+                case 2:
+                        context->frame->action = GDK_PIXBUF_FRAME_DISPOSE;
+                        break;
+                case 3:
+                        context->frame->action = GDK_PIXBUF_FRAME_REVERT;
+                        break;
+                default:
+                        context->frame->action = GDK_PIXBUF_FRAME_RETAIN;
+                        break;
+                }
+
+                context->frame->bg_transparent = (context->gif89.transparent == context->background_index);
+                
+                context->animation->n_frames ++;
+                context->animation->frames = g_list_append (context->animation->frames, context->frame);
+
+                /* Only call prepare_func for the first frame */
+               if (context->animation->frames->next == NULL) { 
+                        if (context->animation->width == 0 )
+                                context->animation->width = gdk_pixbuf_get_width(context->frame->pixbuf);
+                        if (context->animation->height == 0)
+                                context->animation->height = gdk_pixbuf_get_height (context->frame->pixbuf);
+
+                        if (context->prepare_func)
+                                (* context->prepare_func) (context->frame->pixbuf,
+                                                           GDK_PIXBUF_ANIMATION (context->animation),
+                                                           context->user_data);
+                } else {
+                        /* Otherwise init frame with last frame */
+                        GList *link;
+                        GdkPixbufFrame *prev_frame;
+                        gint x, y, w, h;
+                        
+                        link = g_list_find (context->animation->frames, context->frame);
+
+                        prev_frame = link->prev->data;
+
+                        gdk_pixbuf_gif_anim_frame_composite (context->animation, prev_frame);
+
+                        /* Composite failed */
+                        if (prev_frame->composited == NULL) {
+                                GdkPixbufFrame *frame = NULL;
+                                link = g_list_first (context->animation->frames);
+                                while (link != NULL) {
+                                        frame = (GdkPixbufFrame *)link->data;
+                                        if (frame != NULL) {
+                                                if (frame->pixbuf != NULL)
+                                                        g_object_unref (frame->pixbuf);
+                                                if (frame->composited != NULL)
+                                                        g_object_unref (frame->composited);
+                                                if (frame->revert != NULL)
+                                                        g_object_unref (frame->revert);
+                                                g_free (frame);
+                                        }
+                                        link = link->next;
+                                }
+                                
+                                g_list_free (context->animation->frames);
+                                context->animation->frames = NULL;
+                                
+                                g_set_error_literal (context->error,
+                                                     GDK_PIXBUF_ERROR,
+                                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                                     _("Not enough memory to composite a frame in GIF file"));
+                                return -2;
+                        }
+                    
+                        x = context->frame->x_offset;
+                        y = context->frame->y_offset;
+                        w = gdk_pixbuf_get_width (context->frame->pixbuf);
+                        h = gdk_pixbuf_get_height (context->frame->pixbuf);
+                        if (clip_frame (context, &x, &y, &w, &h))
+                                gdk_pixbuf_copy_area (prev_frame->composited,
+                                                      x, y, w, h,
+                                                      context->frame->pixbuf,
+                                                      0, 0);
+                }
+        }
+
+       dest = gdk_pixbuf_get_pixels (context->frame->pixbuf);
+
+       bound_flag = FALSE;
+       lower_bound = upper_bound = context->draw_ypos;
+       first_pass = context->draw_pass;
+
+       while (TRUE) {
+                guchar (*cmap)[MAXCOLORMAPSIZE];
+
+                if (context->frame_cmap_active)
+                        cmap = context->frame_color_map;
+                else
+                        cmap = context->global_color_map;
+                
+               v = lzw_read_byte (context);
+               if (v < 0) {
+                       goto finished_data;
+               }
+               bound_flag = TRUE;
+
+                g_assert (gdk_pixbuf_get_has_alpha (context->frame->pixbuf));
+                
+                temp = dest + context->draw_ypos * gdk_pixbuf_get_rowstride (context->frame->pixbuf) + context->draw_xpos * 4;
+                *temp = cmap [0][(guchar) v];
+                *(temp+1) = cmap [1][(guchar) v];
+                *(temp+2) = cmap [2][(guchar) v];
+                *(temp+3) = (guchar) ((v == context->gif89.transparent) ? 0 : 255);
+
+               if (context->prepare_func && context->frame_interlace)
+                       gif_fill_in_lines (context, dest, v);
+
+               context->draw_xpos++;
+                
+               if (context->draw_xpos == context->frame_len) {
+                       context->draw_xpos = 0;
+                       if (context->frame_interlace) {
+                               switch (context->draw_pass) {
+                               case 0:
+                               case 1:
+                                       context->draw_ypos += 8;
+                                       break;
+                               case 2:
+                                       context->draw_ypos += 4;
+                                       break;
+                               case 3:
+                                       context->draw_ypos += 2;
+                                       break;
+                               }
+
+                               if (context->draw_ypos >= context->frame_height) {
+                                       context->draw_pass++;
+                                       switch (context->draw_pass) {
+                                       case 1:
+                                               context->draw_ypos = 4;
+                                               break;
+                                       case 2:
+                                               context->draw_ypos = 2;
+                                               break;
+                                       case 3:
+                                               context->draw_ypos = 1;
+                                               break;
+                                       default:
+                                               goto done;
+                                       }
+                               }
+                       } else {
+                               context->draw_ypos++;
+                       }
+                       if (context->draw_pass != first_pass) {
+                               if (context->draw_ypos > lower_bound) {
+                                       lower_bound = 0;
+                                       upper_bound = context->frame_height;
+                               } else {
+                                        
+                               }
+                       } else
+                               upper_bound = context->draw_ypos;
+               }
+               if (context->draw_ypos >= context->frame_height)
+                       break;
+       }
+
+ done:
+
+        context->state = GIF_GET_NEXT_STEP;
+
+        v = 0;
+
+ finished_data:
+        
+        if (bound_flag)
+                context->frame->need_recomposite = TRUE;
+        
+       if (bound_flag && context->update_func) {
+               if (lower_bound <= upper_bound && first_pass == context->draw_pass) {
+                        maybe_update (context, 
+                                      context->frame->x_offset,
+                                      context->frame->y_offset + lower_bound,
+                                      gdk_pixbuf_get_width (context->frame->pixbuf),
+                                      upper_bound - lower_bound);
+               } else {
+                       if (lower_bound <= upper_bound) {
+                                maybe_update (context,
+                                              context->frame->x_offset,
+                                              context->frame->y_offset,
+                                              gdk_pixbuf_get_width (context->frame->pixbuf),
+                                              gdk_pixbuf_get_height (context->frame->pixbuf));
+                       } else {
+                                maybe_update (context,
+                                              context->frame->x_offset,
+                                              context->frame->y_offset,
+                                              gdk_pixbuf_get_width (context->frame->pixbuf),
+                                              upper_bound);
+                                maybe_update (context,
+                                              context->frame->x_offset,
+                                              context->frame->y_offset + lower_bound,
+                                              gdk_pixbuf_get_width (context->frame->pixbuf),
+                                              gdk_pixbuf_get_height (context->frame->pixbuf) - lower_bound);
+                       }
+               }
+       }
+
+       if (context->state == GIF_GET_NEXT_STEP) {
+                /* Will be freed with context->animation, we are just
+                 * marking that we're done with it (no current frame)
+                 */
+               context->frame = NULL;
+                context->frame_cmap_active = FALSE;
+
+                if (context->stop_after_first_frame)
+                        context->state =  GIF_DONE;
+       }
+       
+       return v;
+}
+
+static void
+gif_set_prepare_lzw (GifContext *context)
+{
+       context->state = GIF_PREPARE_LZW;
+       context->lzw_code_pending = -1;
+}
+static int
+gif_prepare_lzw (GifContext *context)
+{
+       gint i;
+
+       if (!gif_read (context, &(context->lzw_set_code_size), 1)) {
+               /*g_message (_("GIF: EOF / read error on image data\n"));*/
+               return -1;
+       }
+        
+        if (context->lzw_set_code_size > MAX_LZW_BITS) {
+                g_set_error_literal (context->error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("GIF image is corrupt (incorrect LZW compression)"));
+                return -2;
+        }
+
+       context->lzw_code_size = context->lzw_set_code_size + 1;
+       context->lzw_clear_code = 1 << context->lzw_set_code_size;
+       context->lzw_end_code = context->lzw_clear_code + 1;
+       context->lzw_max_code_size = 2 * context->lzw_clear_code;
+       context->lzw_max_code = context->lzw_clear_code + 2;
+       context->lzw_fresh = TRUE;
+       context->code_curbit = 0;
+       context->code_lastbit = 0;
+       context->code_last_byte = 0;
+       context->code_done = FALSE;
+
+        g_assert (context->lzw_clear_code <= 
+                  G_N_ELEMENTS (context->lzw_table[0]));
+
+       for (i = 0; i < context->lzw_clear_code; ++i) {
+               context->lzw_table[0][i] = 0;
+               context->lzw_table[1][i] = i;
+       }
+       for (; i < (1 << MAX_LZW_BITS); ++i)
+               context->lzw_table[0][i] = context->lzw_table[1][0] = 0;
+
+       context->lzw_sp = context->lzw_stack;
+       gif_set_get_lzw (context);
+
+       return 0;
+}
+
+/* needs 13 bytes to proceed. */
+static gint
+gif_init (GifContext *context)
+{
+       unsigned char buf[16];
+       char version[4];
+
+       if (!gif_read (context, buf, 6)) {
+               /* Unable to read magic number,
+                 * gif_read() should have set error
+                 */
+               return -1;
+       }
+
+       if (strncmp ((char *) buf, "GIF", 3) != 0) {
+               /* Not a GIF file */
+                g_set_error_literal (context->error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("File does not appear to be a GIF file"));
+               return -2;
+       }
+
+       strncpy (version, (char *) buf + 3, 3);
+       version[3] = '\0';
+
+       if ((strcmp (version, "87a") != 0) && (strcmp (version, "89a") != 0)) {
+               /* bad version number, not '87a' or '89a' */
+                g_set_error (context->error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                             _("Version %s of the GIF file format is not supported"),
+                             version);
+               return -2;
+       }
+
+       /* read the screen descriptor */
+       if (!gif_read (context, buf, 7)) {
+               /* Failed to read screen descriptor, error set */
+               return -1;
+       }
+
+       context->width = LM_to_uint (buf[0], buf[1]);
+       context->height = LM_to_uint (buf[2], buf[3]);
+        /* The 4th byte is
+         * high bit: whether to use the background index
+         * next 3:   color resolution
+         * next:     whether colormap is sorted by priority of allocation
+         * last 3:   size of colormap
+         */
+       context->global_bit_pixel = 2 << (buf[4] & 0x07);
+       context->global_color_resolution = (((buf[4] & 0x70) >> 3) + 1);
+        context->has_global_cmap = (buf[4] & 0x80) != 0;
+       context->background_index = buf[5];
+       context->aspect_ratio = buf[6];
+
+        /* Use background of transparent black as default, though if
+         * one isn't set explicitly no one should ever use it.
+         */
+        context->animation->bg_red = 0;
+        context->animation->bg_green = 0;
+        context->animation->bg_blue = 0;
+
+        context->animation->width = context->width;
+        context->animation->height = context->height;
+
+       if (context->has_global_cmap) {
+               gif_set_get_colormap (context);
+       } else {
+               context->state = GIF_GET_NEXT_STEP;
+       }
+
+#ifdef DUMP_IMAGE_DETAILS
+        g_print (">Image width: %d height: %d global_cmap: %d background: %d\n",
+                 context->width, context->height, context->has_global_cmap, context->background_index);
+#endif
+        
+       return 0;
+}
+
+static void
+gif_set_get_frame_info (GifContext *context)
+{
+       context->state = GIF_GET_FRAME_INFO;
+}
+
+static gint
+gif_get_frame_info (GifContext *context)
+{
+       unsigned char buf[9];
+        
+       if (!gif_read (context, buf, 9)) {
+               return -1;
+       }
+        
+       /* Okay, we got all the info we need.  Lets record it */
+       context->frame_len = LM_to_uint (buf[4], buf[5]);
+       context->frame_height = LM_to_uint (buf[6], buf[7]);
+       context->x_offset = LM_to_uint (buf[0], buf[1]);
+       context->y_offset = LM_to_uint (buf[2], buf[3]);
+
+       if (context->animation->frames == NULL &&
+            context->gif89.disposal == 3) {
+                /* First frame can't have "revert to previous" as its
+                 * dispose mode. Silently use "retain" instead.
+                 */
+                context->gif89.disposal = 0;
+       }
+
+       context->frame_interlace = BitSet (buf[8], INTERLACE);
+
+#ifdef DUMP_IMAGE_DETAILS
+        g_print (">width: %d height: %d xoffset: %d yoffset: %d disposal: %d delay: %d transparent: %d interlace: %d\n",
+                 context->frame_len, context->frame_height, context->x_offset, context->y_offset,
+                 context->gif89.disposal, context->gif89.delay_time, context->gif89.transparent, context->frame_interlace);
+#endif
+        
+       if (BitSet (buf[8], LOCALCOLORMAP)) {
+
+#ifdef DUMP_IMAGE_DETAILS
+                g_print (">has local colormap\n");
+#endif
+                
+               /* Does this frame have it's own colormap. */
+               /* really only relevant when looking at the first frame
+                * of an animated gif. */
+               /* if it does, we need to re-read in the colormap,
+                * the gray_scale, and the bit_pixel */
+                context->frame_cmap_active = TRUE;
+               context->frame_bit_pixel = 1 << ((buf[8] & 0x07) + 1);
+               gif_set_get_colormap2 (context);
+               return 0;
+       }
+
+        if (!context->has_global_cmap) {
+                context->state = GIF_DONE;
+                
+                g_set_error_literal (context->error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("GIF image has no global colormap, and a frame inside it has no local colormap."));
+                
+               return -2;
+        }
+
+       gif_set_prepare_lzw (context);
+       return 0;
+
+}
+
+static gint
+gif_get_next_step (GifContext *context)
+{
+       unsigned char c;
+       while (TRUE) {
+               if (!gif_read (context, &c, 1)) {
+                       return -1;
+               }
+               if (c == ';') {
+                       /* GIF terminator */
+                       /* hmm.  Not 100% sure what to do about this.  Should
+                        * i try to return a blank image instead? */
+                       context->state = GIF_DONE;
+                       return 0;
+               }
+
+               if (c == '!') {
+                       /* Check the extension */
+                       gif_set_get_extension (context);
+                       return 0;
+               }
+
+               /* look for frame */
+               if (c != ',') {
+                       /* Not a valid start character */
+                       continue;
+               }
+               /* load the frame */
+               gif_set_get_frame_info (context);
+               return 0;
+       }
+}
+
+
+#define LOG(x) /* g_print ("%s: %s\n", G_STRLOC, x); */
+
+static gint
+gif_main_loop (GifContext *context)
+{
+       gint retval = 0;
+
+       do {
+               switch (context->state) {
+               case GIF_START:
+                        LOG("start\n");
+                       retval = gif_init (context);
+                       break;
+
+               case GIF_GET_COLORMAP:
+                        LOG("get_colormap\n");
+                       retval = gif_get_colormap (context);
+                       if (retval == 0)
+                               context->state = GIF_GET_NEXT_STEP;
+                       break;
+
+               case GIF_GET_NEXT_STEP:
+                        LOG("next_step\n");
+                       retval = gif_get_next_step (context);
+                       break;
+
+               case GIF_GET_FRAME_INFO:
+                        LOG("frame_info\n");
+                       retval = gif_get_frame_info (context);
+                       break;
+
+               case GIF_GET_EXTENSION:
+                        LOG("get_extension\n");
+                       retval = gif_get_extension (context);
+                       if (retval == 0)
+                               context->state = GIF_GET_NEXT_STEP;
+                       break;
+
+               case GIF_GET_COLORMAP2:
+                        LOG("get_colormap2\n");
+                       retval = gif_get_colormap2 (context);
+                       if (retval == 0)
+                               gif_set_prepare_lzw (context);
+                       break;
+
+               case GIF_PREPARE_LZW:
+                        LOG("prepare_lzw\n");
+                       retval = gif_prepare_lzw (context);
+                       break;
+
+               case GIF_LZW_FILL_BUFFER:
+                        LOG("fill_buffer\n");
+                       retval = gif_lzw_fill_buffer (context);
+                       break;
+
+               case GIF_LZW_CLEAR_CODE:
+                        LOG("clear_code\n");
+                       retval = gif_lzw_clear_code (context);
+                       break;
+
+               case GIF_GET_LZW:
+                        LOG("get_lzw\n");
+                       retval = gif_get_lzw (context);
+                       break;
+
+               case GIF_DONE:
+                        LOG("done\n");
+               default:
+                       retval = 0;
+                       goto done;
+               };
+       } while ((retval == 0) || (retval == -3));
+ done:
+       return retval;
+}
+
+static GifContext *
+new_context (void)
+{
+       GifContext *context;
+
+       context = g_try_malloc (sizeof (GifContext));
+        if (context == NULL)
+                return NULL;
+
+        memset (context, 0, sizeof (GifContext));
+        
+        context->animation = g_object_new (GDK_TYPE_PIXBUF_GIF_ANIM, NULL);
+       context->frame = NULL;
+       context->file = NULL;
+       context->state = GIF_START;
+       context->prepare_func = NULL;
+       context->update_func = NULL;
+       context->user_data = NULL;
+       context->buf = NULL;
+       context->amount_needed = 0;
+       context->gif89.transparent = -1;
+       context->gif89.delay_time = -1;
+       context->gif89.input_flag = -1;
+       context->gif89.disposal = -1;
+        context->animation->loop = 1;
+        context->in_loop_extension = FALSE;
+        context->stop_after_first_frame = FALSE;
+
+       return context;
+}
+/* Shared library entry point */
+static GdkPixbuf *
+gdk_pixbuf__gif_image_load (FILE *file, GError **error)
+{
+       GifContext *context;
+       GdkPixbuf *pixbuf;
+        gint retval;
+
+       g_return_val_if_fail (file != NULL, NULL);
+
+       context = new_context ();
+
+        if (context == NULL) {
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                     _("Not enough memory to load GIF file"));
+                return NULL;
+        }
+        
+       context->file = file;
+        context->error = error;
+        context->stop_after_first_frame = TRUE;
+
+        retval = gif_main_loop (context);
+       if (retval == -1 || context->animation->frames == NULL) {
+                if (context->error && *(context->error) == NULL)
+                        g_set_error_literal (context->error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                             _("GIF file was missing some data (perhaps it was truncated somehow?)"));
+        }
+        else if (retval == -2) {
+                pixbuf = NULL;
+                goto out;
+        }
+        
+        pixbuf = gdk_pixbuf_animation_get_static_image (GDK_PIXBUF_ANIMATION (context->animation));
+
+        if (pixbuf)
+                g_object_ref (pixbuf);
+
+out:
+        g_object_unref (context->animation);
+        
+        g_free (context->buf);
+       g_free (context);
+       return pixbuf;
+}
+
+static gpointer
+gdk_pixbuf__gif_image_begin_load (GdkPixbufModuleSizeFunc size_func,
+                                  GdkPixbufModulePreparedFunc prepare_func,
+                                 GdkPixbufModuleUpdatedFunc update_func,
+                                 gpointer user_data,
+                                  GError **error)
+{
+       GifContext *context;
+
+#ifdef IO_GIFDEBUG
+       count = 0;
+#endif
+       context = new_context ();
+
+        if (context == NULL) {
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                     _("Not enough memory to load GIF file"));
+                return NULL;
+        }
+        
+        context->error = error;
+       context->prepare_func = prepare_func;
+       context->update_func = update_func;
+       context->user_data = user_data;
+
+       return (gpointer) context;
+}
+
+static gboolean
+gdk_pixbuf__gif_image_stop_load (gpointer data, GError **error)
+{
+       GifContext *context = (GifContext *) data;
+        gboolean retval = TRUE;
+        
+        if (context->state != GIF_DONE || context->animation->frames == NULL) {
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("GIF image was truncated or incomplete."));
+
+                retval = FALSE;
+        }
+        
+        g_object_unref (context->animation);
+
+       g_free (context->buf);
+       g_free (context);
+
+        return retval;
+}
+
+static gboolean
+gdk_pixbuf__gif_image_load_increment (gpointer data,
+                                      const guchar *buf, guint size,
+                                      GError **error)
+{
+       gint retval;
+       GifContext *context = (GifContext *) data;
+
+        context->error = error;
+        
+       if (context->amount_needed == 0) {
+               /* we aren't looking for some bytes. */
+               /* we can use buf now, but we don't want to keep it around at all.
+                * it will be gone by the end of the call. */
+               context->buf = (guchar*) buf; /* very dubious const cast */
+               context->ptr = 0;
+               context->size = size;
+       } else {
+               /* we need some bytes */
+               if (size < context->amount_needed) {
+                       context->amount_needed -= size;
+                       /* copy it over and return */
+                       memcpy (context->buf + context->size, buf, size);
+                       context->size += size;
+                       return TRUE;
+               } else if (size == context->amount_needed) {
+                       memcpy (context->buf + context->size, buf, size);
+                       context->size += size;
+               } else {
+                       context->buf = g_realloc (context->buf, context->size + size);
+                       memcpy (context->buf + context->size, buf, size);
+                       context->size += size;
+               }
+       }
+
+       retval = gif_main_loop (context);
+
+       if (retval == -2) {
+               if (context->buf == buf)
+                        context->buf = NULL;
+               return FALSE;
+        }
+       if (retval == -1) {
+               /* we didn't have enough memory */
+               /* prepare for the next image_load_increment */
+               if (context->buf == buf) {
+                       g_assert (context->size == size);
+                       context->buf = g_new (guchar, context->amount_needed + (context->size - context->ptr));
+                       memcpy (context->buf, buf + context->ptr, context->size - context->ptr);
+               } else {
+                       /* copy the left overs to the begining of the buffer */
+                       /* and realloc the memory */
+                       memmove (context->buf, context->buf + context->ptr, context->size - context->ptr);
+                       context->buf = g_realloc (context->buf, context->amount_needed + (context->size - context->ptr));
+               }
+               context->size = context->size - context->ptr;
+               context->ptr = 0;
+       } else {
+               /* we are prolly all done */
+               if (context->buf == buf)
+                       context->buf = NULL;
+       }
+       return TRUE;
+}
+
+static GdkPixbufAnimation *
+gdk_pixbuf__gif_image_load_animation (FILE *file,
+                                      GError **error)
+{
+       GifContext *context;
+       GdkPixbufAnimation *animation;
+
+       g_return_val_if_fail (file != NULL, NULL);
+
+       context = new_context ();
+
+        if (context == NULL) {
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                     _("Not enough memory to load GIF file"));
+                return NULL;
+        }
+        
+        context->error = error;
+       context->file = file;
+
+       if (gif_main_loop (context) == -1 || context->animation->frames == NULL) {
+                if (context->error && *(context->error) == NULL)
+                        g_set_error_literal (context->error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                             _("GIF file was missing some data (perhaps it was truncated somehow?)"));
+
+                g_object_unref (context->animation);
+                context->animation = NULL;
+        }
+
+        if (context->animation)
+                animation = GDK_PIXBUF_ANIMATION (context->animation);
+        else
+                animation = NULL;
+
+        if (context->error && *(context->error))
+                g_print ("%s\n", (*(context->error))->message);
+        
+        g_free (context->buf);
+       g_free (context);
+       return animation;
+}
+
+#ifndef INCLUDE_gif
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
+#else
+#define MODULE_ENTRY(function) void _gdk_pixbuf__gif_ ## function
+#endif
+
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
+{
+        module->load = gdk_pixbuf__gif_image_load;
+        module->begin_load = gdk_pixbuf__gif_image_begin_load;
+        module->stop_load = gdk_pixbuf__gif_image_stop_load;
+        module->load_increment = gdk_pixbuf__gif_image_load_increment;
+        module->load_animation = gdk_pixbuf__gif_image_load_animation;
+}
+
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
+{
+        static GdkPixbufModulePattern signature[] = {
+                { "GIF8", NULL, 100 },
+                { NULL, NULL, 0 }
+        };
+       static gchar * mime_types[] = {
+               "image/gif",
+               NULL
+       };
+       static gchar * extensions[] = {
+               "gif",
+               NULL
+       };
+
+       info->name = "gif";
+        info->signature = signature;
+       info->description = N_("The GIF image format");
+       info->mime_types = mime_types;
+       info->extensions = extensions;
+       info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
+       info->license = "LGPL";
+}
diff --git a/gdk-pixbuf/io-icns.c b/gdk-pixbuf/io-icns.c
new file mode 100644 (file)
index 0000000..00cdc50
--- /dev/null
@@ -0,0 +1,404 @@
+/* Mac OS X .icns icons loader
+ *
+ * Copyright (c) 2007 Lyonel Vincent <lyonel@ezix.org>
+ * Copyright (c) 2007 Bastien Nocera <hadess@hadess.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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 _WIN32
+#define _GNU_SOURCE
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "gdk-pixbuf-private.h"
+#include "gdk-pixbuf-loader.h"
+
+G_MODULE_EXPORT void fill_vtable (GdkPixbufModule * module);
+G_MODULE_EXPORT void fill_info (GdkPixbufFormat * info);
+
+#define IN /**/
+#define OUT /**/
+#define INOUT /**/
+
+struct IcnsBlockHeader
+{
+  char id[4];
+  guint32 size;                        /* caution: bigendian */
+};
+typedef struct IcnsBlockHeader IcnsBlockHeader;
+
+/*
+ * load raw icon data from 'icns' resource
+ *
+ * returns TRUE when successful
+ */
+static gboolean
+load_resources (unsigned size, IN gpointer data, gsize datalen,
+               OUT guchar ** picture, OUT gsize * plen,
+               OUT guchar ** mask, OUT gsize * mlen)
+{
+  IcnsBlockHeader *header = NULL;
+  const char *bytes = NULL;
+  const char *current = NULL;
+  guint32 blocklen = 0;
+  guint32 icnslen = 0;
+  gboolean needs_mask = TRUE;
+
+  if (datalen < 2 * sizeof (guint32))
+    return FALSE;
+  if (!data)
+    return FALSE;
+
+  *picture = *mask = NULL;
+  *plen = *mlen = 0;
+
+  bytes = data;
+  header = (IcnsBlockHeader *) data;
+  if (memcmp (header->id, "icns", 4) != 0)
+    return FALSE;
+
+  icnslen = GUINT32_FROM_BE (header->size);
+  if ((icnslen > datalen) || (icnslen < 2 * sizeof (guint32)))
+    return FALSE;
+
+  current = bytes + sizeof (IcnsBlockHeader);
+  while ((current - bytes < icnslen) && (icnslen - (current - bytes) >= sizeof (IcnsBlockHeader)))
+    {
+      header = (IcnsBlockHeader *) current;
+      blocklen = GUINT32_FROM_BE (header->size);
+
+      /* Check that blocklen isn't garbage */
+      if (blocklen > icnslen - (current - bytes))
+        return FALSE;
+
+      switch (size)
+       {
+       case 256:
+       case 512:
+          if (memcmp (header->id, "ic08", 4) == 0      /* 256x256 icon */
+              || memcmp (header->id, "ic09", 4) == 0)  /* 512x512 icon */
+            {
+             *picture = (gpointer) (current + sizeof (IcnsBlockHeader));
+             *plen = blocklen - sizeof (IcnsBlockHeader);
+           }
+           needs_mask = FALSE;
+         break;
+       case 128:
+         if (memcmp (header->id, "it32", 4) == 0)      /* 128x128 icon */
+           {
+             *picture = (gpointer) (current + sizeof (IcnsBlockHeader));
+             *plen = blocklen - sizeof (IcnsBlockHeader);
+             if (memcmp (*picture, "\0\0\0\0", 4) == 0)
+               {
+                 *picture += 4;
+                 *plen -= 4;
+               }
+           }
+         if (memcmp (header->id, "t8mk", 4) == 0)      /* 128x128 mask */
+           {
+             *mask = (gpointer) (current + sizeof (IcnsBlockHeader));
+             *mlen = blocklen - sizeof (IcnsBlockHeader);
+           }
+         break;
+       case 48:
+         if (memcmp (header->id, "ih32", 4) == 0)      /* 48x48 icon */
+           {
+             *picture = (gpointer) (current + sizeof (IcnsBlockHeader));
+             *plen = blocklen - sizeof (IcnsBlockHeader);
+           }
+         if (memcmp (header->id, "h8mk", 4) == 0)      /* 48x48 mask */
+           {
+             *mask = (gpointer) (current + sizeof (IcnsBlockHeader));
+             *mlen = blocklen - sizeof (IcnsBlockHeader);
+           }
+         break;
+       case 32:
+         if (memcmp (header->id, "il32", 4) == 0)      /* 32x32 icon */
+           {
+             *picture = (gpointer) (current + sizeof (IcnsBlockHeader));
+             *plen = blocklen - sizeof (IcnsBlockHeader);
+           }
+         if (memcmp (header->id, "l8mk", 4) == 0)      /* 32x32 mask */
+           {
+             *mask = (gpointer) (current + sizeof (IcnsBlockHeader));
+             *mlen = blocklen - sizeof (IcnsBlockHeader);
+           }
+         break;
+       case 16:
+         if (memcmp (header->id, "is32", 4) == 0)      /* 16x16 icon */
+           {
+             *picture = (gpointer) (current + sizeof (IcnsBlockHeader));
+             *plen = blocklen - sizeof (IcnsBlockHeader);
+           }
+         if (memcmp (header->id, "s8mk", 4) == 0)      /* 16x16 mask */
+           {
+             *mask = (gpointer) (current + sizeof (IcnsBlockHeader));
+             *mlen = blocklen - sizeof (IcnsBlockHeader);
+           }
+         break;
+       default:
+         return FALSE;
+       }
+
+      current += blocklen;
+    }
+
+  if (!*picture)
+    return FALSE;
+  if (needs_mask && !*mask)
+    return FALSE;
+  return TRUE;
+}
+
+/*
+ * uncompress RLE-encoded bytes into RGBA scratch zone:
+ * if firstbyte >= 0x80, it indicates the number of identical bytes + 125
+ *     (repeated value is stored next: 1 byte)
+ * otherwise, it indicates the number of non-repeating bytes - 1
+ *     (non-repeating values are stored next: n bytes)
+ */
+static gboolean
+uncompress (unsigned size, INOUT guchar ** source, OUT guchar * target, INOUT gsize * _remaining)
+{
+  guchar *data = *source;
+  gsize remaining;
+  gsize i = 0;
+
+  /* The first time we're called, set remaining */
+  if (*_remaining == 0) {
+    remaining = size * size;
+  } else {
+    remaining = *_remaining;
+  }
+
+  while (remaining > 0)
+    {
+      guint8 count = 0;
+
+      if (data[0] & 0x80)      /* repeating byte */
+       {
+         count = data[0] - 125;
+
+         if (count > remaining)
+           return FALSE;
+
+         for (i = 0; i < count; i++)
+           {
+             *target = data[1];
+             target += 4;
+           }
+
+         data += 2;
+       }
+      else                     /* non-repeating bytes */
+       {
+         count = data[0] + 1;
+
+         if (count > remaining)
+           return FALSE;
+
+         for (i = 0; i < count; i++)
+           {
+             *target = data[i + 1];
+             target += 4;
+           }
+         data += count + 1;
+       }
+
+      remaining -= count;
+    }
+
+  *source = data;
+  *_remaining = remaining;
+  return TRUE;
+}
+
+static GdkPixbuf *
+load_icon (unsigned size, IN gpointer data, gsize datalen)
+{
+  guchar *icon = NULL;
+  guchar *mask = NULL;
+  gsize isize = 0, msize = 0, i;
+  guchar *image = NULL;
+
+  if (!load_resources (size, data, datalen, &icon, &isize, &mask, &msize))
+    return NULL;
+
+  /* 256x256 icons don't use RLE or uncompressed data,
+   * They're usually JPEG 2000 images */
+  if (size == 256)
+    {
+      GdkPixbufLoader *loader;
+      GdkPixbuf *pixbuf;
+
+      loader = gdk_pixbuf_loader_new ();
+      if (!gdk_pixbuf_loader_write (loader, icon, isize, NULL)
+         || !gdk_pixbuf_loader_close (loader, NULL))
+        {
+          g_object_unref (loader);
+          return NULL;
+       }
+
+      pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+      g_object_ref (pixbuf);
+      g_object_unref (loader);
+
+      return pixbuf;
+    }
+
+  g_assert (mask);
+
+  if (msize != size * size)    /* wrong mask size */
+    return NULL;
+
+  image = (guchar *) g_try_malloc0 (size * size * 4);  /* 4 bytes/pixel = RGBA */
+
+  if (!image)
+    return NULL;
+
+  if (isize == size * size * 4)        /* icon data is uncompressed */
+    for (i = 0; i < size * size; i++)  /* 4 bytes/pixel = ARGB (A: ignored) */
+      {
+       image[i * 4] = icon[4 * i + 1]; /* R */
+       image[i * 4 + 1] = icon[4 * i + 2];     /* G */
+       image[i * 4 + 2] = icon[4 * i + 3];     /* B */
+      }
+  else
+    {
+      guchar *data = icon;
+      gsize remaining = 0;
+
+      /* R */
+      if (!uncompress (size, &data, image, &remaining))
+        goto bail;
+      /* G */
+      if (!uncompress (size, &data, image + 1, &remaining))
+        goto bail;
+      /* B */
+      if (!uncompress (size, &data, image + 2, &remaining))
+        goto bail;
+    }
+
+  for (i = 0; i < size * size; i++)    /* copy mask to alpha channel */
+    image[i * 4 + 3] = mask[i];
+
+  return gdk_pixbuf_new_from_data ((guchar *) image, GDK_COLORSPACE_RGB,       /* RGB image */
+                                  TRUE,        /* with alpha channel */
+                                  8,   /* 8 bits per sample */
+                                  size,        /* width */
+                                  size,        /* height */
+                                  size * 4,    /* no gap between rows */
+                                  (GdkPixbufDestroyNotify)g_free,      /* free() function */
+                                  NULL);       /* param to free() function */
+
+bail:
+  g_free (image);
+  return NULL;
+}
+
+static int sizes[] = {
+  256, /* late-Tiger icons */
+  128, /* Standard OS X */
+  48,  /* Not very common */
+  32,  /* Standard Mac OS Classic (8 & 9) */
+  24,  /* OS X toolbars */
+  16   /* used in Mac OS Classic and dialog boxes */
+};
+
+static GdkPixbuf *
+icns_image_load (FILE *f, GError ** error)
+{
+  GByteArray *data;
+  GdkPixbuf *pixbuf = NULL;
+  guint i;
+
+  data = g_byte_array_new ();
+  while (!feof (f))
+    {
+      gint save_errno;
+      guchar buf[4096];
+      gsize bytes;
+
+      bytes = fread (buf, 1, sizeof (buf), f);
+      save_errno = errno;
+      data = g_byte_array_append (data, buf, bytes);
+
+      if (ferror (f))
+        {
+         g_set_error (error,
+                      G_FILE_ERROR,
+                      g_file_error_from_errno (save_errno),
+                      _("Error reading ICNS image: %s"),
+                      g_strerror (save_errno));
+
+         g_byte_array_free (data, TRUE);
+
+         return NULL;
+       }
+    }
+
+  for (i = 0; i < G_N_ELEMENTS(sizes) && !pixbuf; i++)
+    pixbuf = load_icon (sizes[i], data->data, data->len);
+
+  g_byte_array_free (data, TRUE);
+
+  if (!pixbuf)
+    g_set_error_literal (error, GDK_PIXBUF_ERROR,
+                         GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                         _("Could not decode ICNS file"));
+
+  return pixbuf;
+}
+
+#ifndef INCLUDE_icns
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
+#else
+#define MODULE_ENTRY(function) void _gdk_pixbuf__icns_ ## function
+#endif
+
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule * module)
+{
+  module->load = icns_image_load;
+}
+
+MODULE_ENTRY (fill_info) (GdkPixbufFormat * info)
+{
+  static GdkPixbufModulePattern signature[] = {
+    {"icns", NULL, 100},       /* file begins with 'icns' */
+    {NULL, NULL, 0}
+  };
+  static gchar *mime_types[] = {
+    "image/x-icns",
+    NULL
+  };
+  static gchar *extensions[] = {
+    "icns",
+    NULL
+  };
+
+  info->name = "icns";
+  info->signature = signature;
+  info->description = N_("The ICNS image format");
+  info->mime_types = mime_types;
+  info->extensions = extensions;
+  info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
+  info->license = "GPL";
+  info->disabled = FALSE;
+}
+
diff --git a/gdk-pixbuf/io-ico.c b/gdk-pixbuf/io-ico.c
new file mode 100644 (file)
index 0000000..b73211c
--- /dev/null
@@ -0,0 +1,1280 @@
+/* -*- mode: C; c-file-style: "linux" -*- */
+/* GdkPixbuf library - Windows Icon/Cursor image loader
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Authors: Arjan van de Ven <arjan@fenrus.demon.nl>
+ *          Federico Mena-Quintero <federico@gimp.org>
+ *
+ * Based on io-bmp.c
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#undef DUMPBIH
+/*
+
+Icons are just like BMP's, except for the header.
+Known bugs:
+       * bi-tonal files aren't tested 
+
+*/
+
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <errno.h>
+#include "gdk-pixbuf-private.h"
+
+\f
+
+/* 
+
+These structures are actually dummies. These are according to
+the "Windows API reference guide volume II" as written by 
+Borland International, but GCC fiddles with the alignment of
+the internal members.
+
+*/
+
+struct BitmapFileHeader {
+       gushort bfType;
+       guint bfSize;
+       guint reserverd;
+       guint bfOffbits;
+};
+
+struct BitmapInfoHeader {
+       guint biSize;
+       guint biWidth;
+       guint biHeight;
+       gushort biPlanes;
+       gushort biBitCount;
+       guint biCompression;
+       guint biSizeImage;
+       guint biXPelsPerMeter;
+       guint biYPelsPerMeter;
+       guint biClrUsed;
+       guint biClrImportant;
+};
+
+#ifdef DUMPBIH
+/* 
+
+DumpBIH printf's the values in a BitmapInfoHeader to the screen, for 
+debugging purposes.
+
+*/
+static void DumpBIH(unsigned char *BIH)
+{                              
+       printf("biSize      = %i \n",
+              (int)(BIH[3] << 24) + (BIH[2] << 16) + (BIH[1] << 8) + (BIH[0]));
+       printf("biWidth     = %i \n",
+              (int)(BIH[7] << 24) + (BIH[6] << 16) + (BIH[5] << 8) + (BIH[4]));
+       printf("biHeight    = %i \n",
+              (int)(BIH[11] << 24) + (BIH[10] << 16) + (BIH[9] << 8) +
+              (BIH[8]));
+       printf("biPlanes    = %i \n", (int)(BIH[13] << 8) + (BIH[12]));
+       printf("biBitCount  = %i \n", (int)(BIH[15] << 8) + (BIH[14]));
+       printf("biCompress  = %i \n",
+              (int)(BIH[19] << 24) + (BIH[18] << 16) + (BIH[17] << 8) +
+              (BIH[16]));
+       printf("biSizeImage = %i \n",
+              (int)(BIH[23] << 24) + (BIH[22] << 16) + (BIH[21] << 8) +
+              (BIH[20]));
+       printf("biXPels     = %i \n",
+              (int)(BIH[27] << 24) + (BIH[26] << 16) + (BIH[25] << 8) +
+              (BIH[24]));
+       printf("biYPels     = %i \n",
+              (int)(BIH[31] << 24) + (BIH[30] << 16) + (BIH[29] << 8) +
+              (BIH[28]));
+       printf("biClrUsed   = %i \n",
+              (int)(BIH[35] << 24) + (BIH[34] << 16) + (BIH[33] << 8) +
+              (BIH[32]));
+       printf("biClrImprtnt= %i \n",
+              (int)(BIH[39] << 24) + (BIH[38] << 16) + (BIH[37] << 8) +
+              (BIH[36]));
+}
+#endif
+
+/* Progressive loading */
+struct headerpair {
+       gint width;
+       gint height;
+       guint depth;
+       guint Negative;         /* Negative = 1 -> top down BMP,  
+                                  Negative = 0 -> bottom up BMP */
+};
+
+/* Score the various parts of the icon */
+struct ico_direntry_data {
+       gint ImageScore;
+       gint DIBoffset;
+       gint x_hot;
+       gint y_hot;
+};
+
+struct ico_progressive_state {
+       GdkPixbufModuleSizeFunc size_func;
+       GdkPixbufModulePreparedFunc prepared_func;
+       GdkPixbufModuleUpdatedFunc updated_func;
+       gpointer user_data;
+
+       gint HeaderSize;        /* The size of the header-part (incl colormap) */
+       guchar *HeaderBuf;      /* The buffer for the header (incl colormap) */
+       gint BytesInHeaderBuf;  /* The size of the allocated HeaderBuf */
+       gint HeaderDone;        /* The nr of bytes actually in HeaderBuf */
+
+       gint LineWidth;         /* The width of a line in bytes */
+       guchar *LineBuf;        /* Buffer for 1 line */
+       gint LineDone;          /* # of bytes in LineBuf */
+       gint Lines;             /* # of finished lines */
+
+       gint Type;              /*  
+                                  32 = RGBA
+                                  24 = RGB
+                                  16 = 555 RGB
+                                  8 = 8 bit colormapped
+                                  4 = 4 bpp colormapped
+                                  1  = 1 bit bitonal 
+                                */
+        gboolean cursor;
+        gint x_hot;
+        gint y_hot;
+
+       struct headerpair Header;       /* Decoded (BE->CPU) header */
+       GList *entries;
+       gint                    DIBoffset;
+
+       GdkPixbuf *pixbuf;      /* Our "target" */
+};
+
+static gpointer
+gdk_pixbuf__ico_image_begin_load(GdkPixbufModuleSizeFunc size_func,
+                                 GdkPixbufModulePreparedFunc prepared_func,
+                                GdkPixbufModuleUpdatedFunc updated_func,
+                                gpointer user_data,
+                                 GError **error);
+static gboolean gdk_pixbuf__ico_image_stop_load(gpointer data, GError **error);
+static gboolean gdk_pixbuf__ico_image_load_increment(gpointer data,
+                                                     const guchar * buf, guint size,
+                                                     GError **error);
+
+static void 
+context_free (struct ico_progressive_state *context)
+{
+       g_free (context->LineBuf);
+       context->LineBuf = NULL;
+       g_free (context->HeaderBuf);
+       g_list_free_full (context->entries, g_free);
+       if (context->pixbuf)
+               g_object_unref (context->pixbuf);
+
+       g_free (context);
+}
+
+static gint
+compare_direntry_scores (gconstpointer a,
+                         gconstpointer b)
+{
+       const struct ico_direntry_data *ia = a;
+       const struct ico_direntry_data *ib = b;
+
+       /* Backwards, so largest first */
+       return ib->ImageScore - ia->ImageScore;
+}
+
+static void DecodeHeader(guchar *Data, gint Bytes,
+                        struct ico_progressive_state *State,
+                        GError **error)
+{
+/* For ICO's we have to be very clever. There are multiple images possible
+   in an .ICO. As a simple heuristic, we select the image which occupies the 
+   largest number of bytes.
+ */   
+       struct ico_direntry_data *entry;
+       gint IconCount = 0; /* The number of icon-versions in the file */
+       guchar *BIH; /* The DIB for the used icon */
+       guchar *Ptr;
+       gint I;
+       guint16 imgtype; /* 1 = icon, 2 = cursor */
+       GList *l;
+
+       /* Step 1: The ICO header */
+
+       /* First word should be 0 according to specs */
+       if (((Data[1] << 8) + Data[0]) != 0) {
+               g_set_error_literal (error,
+                                    GDK_PIXBUF_ERROR,
+                                    GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                    _("Invalid header in icon"));
+               return;
+
+       }
+
+       imgtype = (Data[3] << 8) + Data[2];
+
+       State->cursor = (imgtype == 2) ? TRUE : FALSE;
+
+       /* If it is not a cursor make sure it is actually an icon */
+       if (!State->cursor && imgtype != 1) {
+               g_set_error_literal (error,
+                                    GDK_PIXBUF_ERROR,
+                                    GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                    _("Invalid header in icon"));
+               return;
+       }
+
+
+       IconCount = (Data[5] << 8) + (Data[4]);
+       
+       State->HeaderSize = 6 + IconCount*16;
+
+       if (State->HeaderSize>State->BytesInHeaderBuf) {
+               guchar *tmp=g_try_realloc(State->HeaderBuf,State->HeaderSize);
+               if (!tmp) {
+                       g_set_error_literal (error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                             _("Not enough memory to load icon"));
+                       return;
+               }
+               State->HeaderBuf = tmp;
+               State->BytesInHeaderBuf = State->HeaderSize;
+       }
+       if (Bytes < State->HeaderSize)
+               return;
+
+       /* Now iterate through the ICONDIRENTRY structures, and sort them by
+        * which one we think is "best" (essentially the largest) */
+       g_list_free_full (State->entries, g_free);
+       State->entries = 0;
+       Ptr = Data + 6;
+       for (I=0;I<IconCount;I++) {
+               entry = g_new0 (struct ico_direntry_data, 1);
+               entry->ImageScore = (Ptr[11] << 24) + (Ptr[10] << 16) + (Ptr[9] << 8) + (Ptr[8]);
+               entry->x_hot = (Ptr[5] << 8) + Ptr[4];
+               entry->y_hot = (Ptr[7] << 8) + Ptr[6];
+               entry->DIBoffset = (Ptr[15]<<24)+(Ptr[14]<<16)+
+                                  (Ptr[13]<<8) + (Ptr[12]);
+               State->entries = g_list_insert_sorted (State->entries, entry, compare_direntry_scores);
+               Ptr += 16;
+       } 
+
+       /* Now go through and find one we can parse */
+       entry = NULL;
+       for (l = State->entries; l != NULL; l = g_list_next (l)) {
+               entry = l->data;
+
+               if (entry->DIBoffset < 0) {
+                       g_set_error_literal (error,
+                                            GDK_PIXBUF_ERROR,
+                                            GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                            _("Invalid header in icon"));
+                       return;
+               }
+
+               /* We know how many bytes are in the "header" part. */
+               State->HeaderSize = entry->DIBoffset + 40; /* 40 = sizeof(InfoHeader) */
+
+               if (State->HeaderSize < 0) {
+                       g_set_error_literal (error,
+                                            GDK_PIXBUF_ERROR,
+                                            GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                            _("Invalid header in icon"));
+                       return;
+               }
+
+               if (State->HeaderSize>State->BytesInHeaderBuf) {
+                       guchar *tmp=g_try_realloc(State->HeaderBuf,State->HeaderSize);
+                       if (!tmp) {
+                               g_set_error_literal (error,
+                                                    GDK_PIXBUF_ERROR,
+                                                    GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                                    _("Not enough memory to load icon"));
+                               return;
+                       }
+                       State->HeaderBuf = tmp;
+                       State->BytesInHeaderBuf = State->HeaderSize;
+               }
+               if (Bytes<State->HeaderSize)
+                       return;
+
+               BIH = Data+entry->DIBoffset;
+
+               /* A compressed icon, try the next one */
+               if ((BIH[16] != 0) || (BIH[17] != 0) || (BIH[18] != 0)
+                   || (BIH[19] != 0))
+                       continue;
+
+               /* If we made it to here then we have selected a BIH structure
+                * in a format that we can parse */
+               break;
+       }
+
+       /* No valid icon found, because all are compressed? */
+       if (l == NULL) {
+               g_set_error_literal (error,
+                                    GDK_PIXBUF_ERROR,
+                                    GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                    _("Compressed icons are not supported"));
+               return;
+       }
+
+       /* This is the one we're going with */
+       State->DIBoffset = entry->DIBoffset;
+       State->x_hot = entry->x_hot;
+       State->y_hot = entry->y_hot;
+
+#ifdef DUMPBIH
+       DumpBIH(BIH);
+#endif 
+       /* Add the palette to the headersize */
+               
+       State->Header.width =
+           (int)(BIH[7] << 24) + (BIH[6] << 16) + (BIH[5] << 8) + (BIH[4]);
+       if (State->Header.width == 0) {
+               g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("Icon has zero width"));
+               return;
+       }
+       State->Header.height =
+           (int)((BIH[11] << 24) + (BIH[10] << 16) + (BIH[9] << 8) + (BIH[8]))/2;
+           /* /2 because the BIH height includes the transparency mask */
+       if (State->Header.height == 0) {
+               g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("Icon has zero height"));
+               return;
+       }
+       State->Header.depth = (BIH[15] << 8) + (BIH[14]);
+
+       State->Type = State->Header.depth;      
+       if (State->Lines>=State->Header.height)
+               State->Type = 1; /* The transparency mask is 1 bpp */
+       
+       /* Determine the  palette size. If the header indicates 0, it
+          is actually the maximum for the bpp. You have to love the
+          guys who made the spec. */
+       I = (int)(BIH[35] << 24) + (BIH[34] << 16) + (BIH[33] << 8) + (BIH[32]);
+       I = I*4;
+       if ((I==0)&&(State->Type==1))
+               I = 2*4;
+       if ((I==0)&&(State->Type==4))
+               I = 16*4;
+       if ((I==0)&&(State->Type==8))
+               I = 256*4;
+       
+       State->HeaderSize+=I;
+       
+       if (State->HeaderSize < 0) {
+               g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("Invalid header in icon"));
+               return;
+       }
+
+       if (State->HeaderSize>State->BytesInHeaderBuf) {
+               guchar *tmp=g_try_realloc(State->HeaderBuf,State->HeaderSize);
+               if (!tmp) {
+                       g_set_error_literal (error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                             _("Not enough memory to load icon"));
+                       return;
+               }
+               State->HeaderBuf = tmp;
+               State->BytesInHeaderBuf = State->HeaderSize;
+       }
+       if (Bytes < State->HeaderSize)
+               return;
+
+       /* Negative heights mean top-down pixel-order */
+       if (State->Header.height < 0) {
+               State->Header.height = -State->Header.height;
+               State->Header.Negative = 1;
+       }
+       if (State->Header.width < 0) {
+               State->Header.width = -State->Header.width;
+       }
+       g_assert (State->Header.width > 0);
+       g_assert (State->Header.height > 0);
+
+        if (State->Type == 32)
+                State->LineWidth = State->Header.width * 4;
+        else if (State->Type == 24)
+               State->LineWidth = State->Header.width * 3;
+        else if (State->Type == 16)
+                State->LineWidth = State->Header.width * 2;
+        else if (State->Type == 8)
+               State->LineWidth = State->Header.width * 1;
+        else if (State->Type == 4)
+               State->LineWidth = (State->Header.width+1)/2;
+        else if (State->Type == 1) {
+               State->LineWidth = State->Header.width / 8;
+               if ((State->Header.width & 7) != 0)
+                       State->LineWidth++;
+        } else {
+          g_set_error_literal (error,
+                               GDK_PIXBUF_ERROR,
+                               GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                               _("Unsupported icon type"));
+          return;
+       }
+
+       /* Pad to a 32 bit boundary */
+       if (((State->LineWidth % 4) > 0))
+               State->LineWidth = (State->LineWidth / 4) * 4 + 4;
+
+
+       if (State->LineBuf == NULL) {
+               State->LineBuf = g_try_malloc(State->LineWidth);
+               if (!State->LineBuf) {
+                       g_set_error_literal (error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                             _("Not enough memory to load icon"));
+                       return;
+               }
+       }
+
+       g_assert(State->LineBuf != NULL);
+
+
+       if (State->pixbuf == NULL) {
+#if 1
+               if (State->size_func) {
+                       gint width = State->Header.width;
+                       gint height = State->Header.height;
+
+                       (*State->size_func) (&width, &height, State->user_data);
+                       if (width == 0 || height == 0) {
+                               State->LineWidth = 0;
+                               return;
+                       }
+               }
+#endif
+
+               State->pixbuf =
+                   gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
+                                  State->Header.width,
+                                  State->Header.height);
+               if (!State->pixbuf) {
+                       g_set_error_literal (error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                             _("Not enough memory to load icon"));
+                       return;
+               }
+               if (State->cursor) {
+                       gchar hot[10];
+                       g_snprintf (hot, 10, "%d", State->x_hot);
+                       gdk_pixbuf_set_option (State->pixbuf, "x_hot", hot);
+                       g_snprintf (hot, 10, "%d", State->y_hot);
+                       gdk_pixbuf_set_option (State->pixbuf, "y_hot", hot);
+               }
+
+               if (State->prepared_func != NULL)
+                       /* Notify the client that we are ready to go */
+                       (*State->prepared_func) (State->pixbuf,
+                                                 NULL,
+                                                State->user_data);
+
+       }
+
+}
+
+/* 
+ * func - called when we have pixmap created (but no image data)
+ * user_data - passed as arg 1 to func
+ * return context (opaque to user)
+ */
+
+static gpointer
+gdk_pixbuf__ico_image_begin_load(GdkPixbufModuleSizeFunc size_func,
+                                 GdkPixbufModulePreparedFunc prepared_func,
+                                GdkPixbufModuleUpdatedFunc updated_func,
+                                gpointer user_data,
+                                 GError **error)
+{
+       struct ico_progressive_state *context;
+
+       context = g_new0(struct ico_progressive_state, 1);
+       context->size_func = size_func;
+       context->prepared_func = prepared_func;
+       context->updated_func = updated_func;
+       context->user_data = user_data;
+
+       context->HeaderSize = 54;
+       context->HeaderBuf = g_try_malloc(14 + 40 + 4*256 + 512);
+       if (!context->HeaderBuf) {
+               g_free (context);
+               g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                     _("Not enough memory to load ICO file"));
+               return NULL;
+       }
+       /* 4*256 for the colormap */
+       context->BytesInHeaderBuf = 14 + 40 + 4*256 + 512 ;
+       context->HeaderDone = 0;
+
+       context->LineWidth = 0;
+       context->LineBuf = NULL;
+       context->LineDone = 0;
+       context->Lines = 0;
+
+       context->Type = 0;
+
+       memset(&context->Header, 0, sizeof(struct headerpair));
+
+
+       context->pixbuf = NULL;
+
+
+       return (gpointer) context;
+}
+
+/*
+ * context - returned from image_begin_load
+ *
+ * free context, unref gdk_pixbuf
+ */
+static gboolean 
+gdk_pixbuf__ico_image_stop_load(gpointer data,
+                               GError **error)
+{
+       struct ico_progressive_state *context =
+           (struct ico_progressive_state *) data;
+
+        /* FIXME this thing needs to report errors if
+         * we have unused image data
+         */
+
+       g_return_val_if_fail(context != NULL, TRUE);
+
+       context_free (context);
+        return TRUE;
+}
+
+static void
+OneLine32 (struct ico_progressive_state *context)
+{
+        gint X;
+        guchar *Pixels;
+
+        X = 0;
+        if (context->Header.Negative == 0)
+                Pixels = (context->pixbuf->pixels +
+                          context->pixbuf->rowstride *
+                          (context->Header.height - context->Lines - 1));
+        else
+                Pixels = (context->pixbuf->pixels +
+                          context->pixbuf->rowstride *
+                          context->Lines);
+        while (X < context->Header.width) {
+                Pixels[X * 4 + 0] = context->LineBuf[X * 4 + 2];
+                Pixels[X * 4 + 1] = context->LineBuf[X * 4 + 1];
+                Pixels[X * 4 + 2] = context->LineBuf[X * 4 + 0];
+                Pixels[X * 4 + 3] = context->LineBuf[X * 4 + 3];
+                X++;
+        }
+}
+
+static void OneLine24(struct ico_progressive_state *context)
+{
+       gint X;
+       guchar *Pixels;
+
+       X = 0;
+       if (context->Header.Negative == 0)
+               Pixels = (context->pixbuf->pixels +
+                         context->pixbuf->rowstride *
+                         (context->Header.height - context->Lines - 1));
+       else
+               Pixels = (context->pixbuf->pixels +
+                         context->pixbuf->rowstride *
+                         context->Lines);
+       while (X < context->Header.width) {
+               Pixels[X * 4 + 0] = context->LineBuf[X * 3 + 2];
+               Pixels[X * 4 + 1] = context->LineBuf[X * 3 + 1];
+               Pixels[X * 4 + 2] = context->LineBuf[X * 3 + 0];
+               X++;
+       }
+
+}
+
+static void
+OneLine16 (struct ico_progressive_state *context)
+{
+        int i;
+        guchar *pixels;
+        guchar *src;
+
+        if (context->Header.Negative == 0)
+                pixels = (context->pixbuf->pixels +
+                          context->pixbuf->rowstride * (context->Header.height - context->Lines - 1));
+        else
+                pixels = (context->pixbuf->pixels +
+                          context->pixbuf->rowstride * context->Lines);
+
+        src = context->LineBuf;
+
+        for (i = 0; i < context->Header.width; i++) {
+                int v, r, g, b;
+
+                v = (int) src[0] | ((int) src[1] << 8);
+                src += 2;
+
+                /* Extract 5-bit RGB values */
+
+                r = (v >> 10) & 0x1f;
+                g = (v >> 5) & 0x1f;
+                b = v & 0x1f;
+
+                /* Fill the rightmost bits to form 8-bit values */
+
+                *pixels++ = (r << 3) | (r >> 2);
+                *pixels++ = (g << 3) | (g >> 2);
+                *pixels++ = (b << 3) | (b >> 2);
+                pixels++; /* skip alpha channel */
+        }
+}
+
+
+static void OneLine8(struct ico_progressive_state *context)
+{
+       gint X;
+       guchar *Pixels;
+
+       X = 0;
+       if (context->Header.Negative == 0)
+               Pixels = (context->pixbuf->pixels +
+                         context->pixbuf->rowstride *
+                         (context->Header.height - context->Lines - 1));
+       else
+               Pixels = (context->pixbuf->pixels +
+                         context->pixbuf->rowstride *
+                         context->Lines);
+       while (X < context->Header.width) {
+               /* The joys of having a BGR byteorder */
+               Pixels[X * 4 + 0] =
+                   context->HeaderBuf[4 * context->LineBuf[X] + 42+context->DIBoffset];
+               Pixels[X * 4 + 1] =
+                   context->HeaderBuf[4 * context->LineBuf[X] + 41+context->DIBoffset];
+               Pixels[X * 4 + 2] =
+                   context->HeaderBuf[4 * context->LineBuf[X] + 40+context->DIBoffset];
+               X++;
+       }
+}
+static void OneLine4(struct ico_progressive_state *context)
+{
+       gint X;
+       guchar *Pixels;
+
+       X = 0;
+       if (context->Header.Negative == 0)
+               Pixels = (context->pixbuf->pixels +
+                         context->pixbuf->rowstride *
+                         (context->Header.height - context->Lines - 1));
+       else
+               Pixels = (context->pixbuf->pixels +
+                         context->pixbuf->rowstride *
+                         context->Lines);
+       
+       while (X < context->Header.width) {
+               guchar Pix;
+               
+               Pix = context->LineBuf[X/2];
+
+               Pixels[X * 4 + 0] =
+                   context->HeaderBuf[4 * (Pix>>4) + 42+context->DIBoffset];
+               Pixels[X * 4 + 1] =
+                   context->HeaderBuf[4 * (Pix>>4) + 41+context->DIBoffset];
+               Pixels[X * 4 + 2] =
+                   context->HeaderBuf[4 * (Pix>>4) + 40+context->DIBoffset];
+               X++;
+               if (X<context->Header.width) { 
+                       /* Handle the other 4 bit pixel only when there is one */
+                       Pixels[X * 4 + 0] =
+                           context->HeaderBuf[4 * (Pix&15) + 42+context->DIBoffset];
+                       Pixels[X * 4 + 1] =
+                           context->HeaderBuf[4 * (Pix&15) + 41+context->DIBoffset];
+                       Pixels[X * 4 + 2] =
+                           context->HeaderBuf[4 * (Pix&15) + 40+context->DIBoffset];
+                       X++;
+               }
+       }
+       
+}
+
+static void OneLine1(struct ico_progressive_state *context)
+{
+       gint X;
+       guchar *Pixels;
+
+       X = 0;
+       if (context->Header.Negative == 0)
+               Pixels = (context->pixbuf->pixels +
+                         context->pixbuf->rowstride *
+                         (context->Header.height - context->Lines - 1));
+       else
+               Pixels = (context->pixbuf->pixels +
+                         context->pixbuf->rowstride *
+                         context->Lines);
+       while (X < context->Header.width) {
+               int Bit;
+
+               Bit = (context->LineBuf[X / 8]) >> (7 - (X & 7));
+               Bit = Bit & 1;
+               /* The joys of having a BGR byteorder */
+               Pixels[X * 4 + 0] = Bit*255;
+               Pixels[X * 4 + 1] = Bit*255;
+               Pixels[X * 4 + 2] = Bit*255;
+               X++;
+       }
+}
+
+static void OneLineTransp(struct ico_progressive_state *context)
+{
+       gint X;
+       guchar *Pixels;
+
+       /* Ignore the XOR mask for XP style 32-bpp icons with alpha */ 
+       if (context->Header.depth == 32)
+               return;
+
+       X = 0;
+       if (context->Header.Negative == 0)
+               Pixels = (context->pixbuf->pixels +
+                         context->pixbuf->rowstride *
+                         (2*context->Header.height - context->Lines - 1));
+       else
+               Pixels = (context->pixbuf->pixels +
+                         context->pixbuf->rowstride *
+                         (context->Lines-context->Header.height));
+       while (X < context->Header.width) {
+               int Bit;
+
+               Bit = (context->LineBuf[X / 8]) >> (7 - (X & 7));
+               Bit = Bit & 1;
+               /* The joys of having a BGR byteorder */
+               Pixels[X * 4 + 3] = 255-Bit*255;
+#if 0
+               if (Bit){
+                 Pixels[X*4+0] = 255;
+                 Pixels[X*4+1] = 255;
+               } else {
+                 Pixels[X*4+0] = 0;
+                 Pixels[X*4+1] = 0;
+               }
+#endif         
+               X++;
+       }
+}
+
+
+static void OneLine(struct ico_progressive_state *context)
+{
+       context->LineDone = 0;
+       
+       if (context->Lines >= context->Header.height*2) {
+               return;
+       }
+               
+       if (context->Lines <context->Header.height) {           
+                if (context->Type == 32)
+                        OneLine32 (context);
+               else if (context->Type == 24)
+                       OneLine24(context);
+                else if (context->Type == 16)
+                        OneLine16 (context);
+               else if (context->Type == 8)
+                       OneLine8(context);
+               else if (context->Type == 4)
+                       OneLine4(context);
+               else if (context->Type == 1)
+                       OneLine1(context);
+               else 
+                       g_assert_not_reached ();
+       } else
+               OneLineTransp(context);
+       
+       context->Lines++;
+       if (context->Lines>=context->Header.height) {
+               context->Type = 1;
+               context->LineWidth = context->Header.width / 8;
+               if ((context->Header.width & 7) != 0)
+                       context->LineWidth++;
+               /* Pad to a 32 bit boundary */
+               if (((context->LineWidth % 4) > 0))
+                       context->LineWidth = (context->LineWidth / 4) * 4 + 4;
+                       
+       }
+         
+
+       if (context->updated_func != NULL) {
+               (*context->updated_func) (context->pixbuf,
+                                         0,
+                                         context->Lines % context->Header.height,
+                                         context->Header.width,
+                                         1,
+                                         context->user_data);
+
+       }
+}
+
+/*
+ * context - from image_begin_load
+ * buf - new image data
+ * size - length of new image data
+ *
+ * append image data onto inrecrementally built output image
+ */
+static gboolean
+gdk_pixbuf__ico_image_load_increment(gpointer data,
+                                     const guchar * buf,
+                                     guint size,
+                                     GError **error)
+{
+       struct ico_progressive_state *context =
+           (struct ico_progressive_state *) data;
+
+       gint BytesToCopy;
+
+       while (size > 0) {
+               g_assert(context->LineDone >= 0);
+               if (context->HeaderDone < context->HeaderSize) {        /* We still 
+                                                                          have headerbytes to do */
+                       BytesToCopy =
+                           context->HeaderSize - context->HeaderDone;
+                       if (BytesToCopy > size)
+                               BytesToCopy = size;
+
+                       memmove(context->HeaderBuf + context->HeaderDone,
+                              buf, BytesToCopy);
+
+                       size -= BytesToCopy;
+                       buf += BytesToCopy;
+                       context->HeaderDone += BytesToCopy;
+               } 
+               else {
+                       BytesToCopy =
+                           context->LineWidth - context->LineDone;
+                       if (BytesToCopy > size)
+                               BytesToCopy = size;
+
+                       if (BytesToCopy > 0) {
+                               memmove(context->LineBuf +
+                                      context->LineDone, buf,
+                                      BytesToCopy);
+
+                               size -= BytesToCopy;
+                               buf += BytesToCopy;
+                               context->LineDone += BytesToCopy;
+                       }
+                       if ((context->LineDone >= context->LineWidth) &&
+                           (context->LineWidth > 0))
+                               OneLine(context);
+
+
+               }
+
+               if (context->HeaderDone >= 6 && context->pixbuf == NULL) {
+                       GError *decode_err = NULL;
+                       DecodeHeader(context->HeaderBuf,
+                                    context->HeaderDone, context, &decode_err);
+                       if (context->LineBuf != NULL && context->LineWidth == 0)
+                               return TRUE;
+
+                       if (decode_err) {
+                               g_propagate_error (error, decode_err);
+                               return FALSE;
+                       }
+               }
+       }
+
+       return TRUE;
+}
+
+/* saving ICOs */ 
+
+static gint
+write8 (FILE     *f,
+       guint8   *data,
+       gint      count)
+{
+  gint bytes;
+  gint written;
+
+  written = 0;
+  while (count > 0)
+    {
+      bytes = fwrite ((char*) data, sizeof (char), count, f);
+      if (bytes <= 0)
+        break;
+      count -= bytes;
+      data += bytes;
+      written += bytes;
+    }
+
+  return written;
+}
+
+static gint
+write16 (FILE     *f,
+        guint16  *data,
+        gint      count)
+{
+  gint i;
+
+  for (i = 0; i < count; i++)
+         data[i] = GUINT16_TO_LE (data[i]);
+
+  return write8 (f, (guint8*) data, count * 2);
+}
+
+static gint
+write32 (FILE     *f,
+        guint32  *data,
+        gint      count)
+{
+  gint i;
+
+  for (i = 0; i < count; i++)
+         data[i] = GUINT32_TO_LE (data[i]);
+  
+  return write8 (f, (guint8*) data, count * 4);
+}
+
+typedef struct _IconEntry IconEntry;
+struct _IconEntry {
+       gint width;
+       gint height;
+       gint depth;
+       gint hot_x;
+       gint hot_y;
+
+       guint8 n_colors;
+       guint32 *colors;
+       guint xor_rowstride;
+       guint8 *xor;
+       guint and_rowstride;
+       guint8 *and;
+};
+
+static gboolean
+fill_entry (IconEntry *icon, 
+           GdkPixbuf *pixbuf, 
+           gint       hot_x, 
+           gint       hot_y, 
+           GError   **error) 
+ {
+       guchar *p, *pixels, *and, *xor;
+       gint n_channels, v, x, y;
+
+       if (icon->width > 255 || icon->height > 255) {
+               g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_BAD_OPTION,
+                                     _("Image too large to be saved as ICO"));
+               return FALSE;
+       } 
+       
+       if (hot_x > -1 && hot_y > -1) {
+               icon->hot_x = hot_x;
+               icon->hot_y = hot_y;
+               if (icon->hot_x >= icon->width || icon->hot_y >= icon->height) {
+                       g_set_error_literal (error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_BAD_OPTION,
+                                             _("Cursor hotspot outside image"));
+                       return FALSE;
+               }
+       }
+       else {
+               icon->hot_x = -1;
+               icon->hot_y = -1;
+       }
+       
+       switch (icon->depth) {
+       case 32:
+               icon->xor_rowstride = icon->width * 4;
+               break;
+       case 24:
+               icon->xor_rowstride = icon->width * 3;
+               break;
+       case 16:
+               icon->xor_rowstride = icon->width * 2;
+               break;
+       default:
+               g_set_error (error,
+                            GDK_PIXBUF_ERROR,
+                            GDK_PIXBUF_ERROR_BAD_OPTION,
+                            _("Unsupported depth for ICO file: %d"), icon->depth);
+               return FALSE;
+       }
+
+       if ((icon->xor_rowstride % 4) != 0)
+               icon->xor_rowstride = 4 * ((icon->xor_rowstride / 4) + 1);
+       icon->xor = g_new0 (guchar, icon->xor_rowstride * icon->height);
+
+       icon->and_rowstride = (icon->width + 7) / 8;
+       if ((icon->and_rowstride % 4) != 0)
+               icon->and_rowstride = 4 * ((icon->and_rowstride / 4) + 1);
+       icon->and = g_new0 (guchar, icon->and_rowstride * icon->height);
+
+       pixels = gdk_pixbuf_get_pixels (pixbuf);
+       n_channels = gdk_pixbuf_get_n_channels (pixbuf);
+       for (y = 0; y < icon->height; y++) {
+               p = pixels + gdk_pixbuf_get_rowstride (pixbuf) * (icon->height - 1 - y);
+               and = icon->and + icon->and_rowstride * y;
+               xor = icon->xor + icon->xor_rowstride * y;
+               for (x = 0; x < icon->width; x++) {
+                       switch (icon->depth) {
+                       case 32:
+                               xor[0] = p[2];
+                               xor[1] = p[1];
+                               xor[2] = p[0];
+                               xor[3] = 0xff;
+                               if (n_channels == 4) {
+                                       xor[3] = p[3];
+                                       if (p[3] < 0x80)
+                                               *and |= 1 << (7 - x % 8);
+                               }
+                               xor += 4;
+                               break;
+                       case 24:
+                               xor[0] = p[2];
+                               xor[1] = p[1];
+                               xor[2] = p[0];
+                               if (n_channels == 4 && p[3] < 0x80)
+                                       *and |= 1 << (7 - x % 8);
+                               xor += 3;
+                               break;
+                       case 16:
+                               v = ((p[0] >> 3) << 10) | ((p[1] >> 3) << 5) | (p[2] >> 3);
+                               xor[0] = v & 0xff;
+                               xor[1] = v >> 8;
+                               if (n_channels == 4 && p[3] < 0x80)
+                                       *and |= 1 << (7 - x % 8);
+                               xor += 2;
+                               break;
+                       }
+                       
+                       p += n_channels;
+                       if (x % 8 == 7) 
+                               and++;
+               }
+       }
+
+       return TRUE;
+}
+
+static void
+free_entry (IconEntry *icon)
+{
+       g_free (icon->colors);
+       g_free (icon->and);
+       g_free (icon->xor);
+       g_free (icon);
+}
+
+static void
+write_icon (FILE *f, GSList *entries)
+{
+       IconEntry *icon;
+       GSList *entry;
+       guint8 bytes[4];
+       guint16 words[4];
+       guint32 dwords[6];
+       gint type;
+       gint n_entries;
+       gint offset;
+       gint size;
+
+       if (((IconEntry *)entries->data)->hot_x > -1)
+               type = 2;
+       else 
+               type = 1;
+       n_entries = g_slist_length (entries);
+
+       /* header */
+       words[0] = 0;
+       words[1] = type;
+       words[2] = n_entries;
+       write16 (f, words, 3);
+       
+       offset = 6 + 16 * n_entries;
+
+       for (entry = entries; entry; entry = entry->next) {
+               icon = (IconEntry *)entry->data;
+               size = 40 + icon->height * (icon->and_rowstride + icon->xor_rowstride);
+               
+               /* directory entry */
+               bytes[0] = icon->width;
+               bytes[1] = icon->height;
+               bytes[2] = icon->n_colors;
+               bytes[3] = 0;
+               write8 (f, bytes, 4);
+               if (type == 1) {
+                       words[0] = 1;
+                       words[1] = icon->depth;
+               }
+               else {
+                       words[0] = icon->hot_x;
+                       words[1] = icon->hot_y;
+               }
+               write16 (f, words, 2);
+               dwords[0] = size;
+               dwords[1] = offset;
+               write32 (f, dwords, 2);
+
+               offset += size;
+       }
+
+       for (entry = entries; entry; entry = entry->next) {
+               icon = (IconEntry *)entry->data;
+
+               /* bitmap header */
+               dwords[0] = 40;
+               dwords[1] = icon->width;
+               dwords[2] = icon->height * 2;
+               write32 (f, dwords, 3);
+               words[0] = 1;
+               words[1] = icon->depth;
+               write16 (f, words, 2);
+               dwords[0] = 0;
+               dwords[1] = 0;
+               dwords[2] = 0;
+               dwords[3] = 0;
+               dwords[4] = 0;
+               dwords[5] = 0;
+               write32 (f, dwords, 6);
+
+               /* image data */
+               write8 (f, icon->xor, icon->xor_rowstride * icon->height);
+               write8 (f, icon->and, icon->and_rowstride * icon->height);
+       }
+}
+
+static gboolean
+gdk_pixbuf__ico_image_save (FILE          *f, 
+                            GdkPixbuf     *pixbuf, 
+                            gchar        **keys,
+                            gchar        **values,
+                            GError       **error)
+{
+       gint hot_x, hot_y;
+       IconEntry *icon;
+       GSList *entries = NULL;
+
+       /* support only single-image ICOs for now */
+       icon = g_new0 (IconEntry, 1);
+       icon->width = gdk_pixbuf_get_width (pixbuf);
+       icon->height = gdk_pixbuf_get_height (pixbuf);
+       icon->depth = gdk_pixbuf_get_has_alpha (pixbuf) ? 32 : 24;
+       hot_x = -1;
+       hot_y = -1;
+       
+       /* parse options */
+       if (keys && *keys) {
+               gchar **kiter;
+               gchar **viter;
+               
+               for (kiter = keys, viter = values; *kiter && *viter; kiter++, viter++) {
+                       char *endptr;
+                       if (strcmp (*kiter, "depth") == 0) {
+                               sscanf (*viter, "%d", &icon->depth);
+                       }
+                       else if (strcmp (*kiter, "x_hot") == 0) {
+                               hot_x = strtol (*viter, &endptr, 10);
+                       }
+                       else if (strcmp (*kiter, "y_hot") == 0) {
+                               hot_y = strtol (*viter, &endptr, 10);
+                       }
+
+               }
+       }
+
+       if (!fill_entry (icon, pixbuf, hot_x, hot_y, error)) {
+               free_entry (icon);
+               return FALSE;
+       }
+
+       entries = g_slist_append (entries, icon); 
+       write_icon (f, entries);
+
+       g_slist_foreach (entries, (GFunc)free_entry, NULL);
+       g_slist_free (entries);
+
+       return TRUE;
+}
+
+#ifndef INCLUDE_ico
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
+#else
+#define MODULE_ENTRY(function) void _gdk_pixbuf__ico_ ## function
+#endif
+
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
+{
+       module->begin_load = gdk_pixbuf__ico_image_begin_load;
+       module->stop_load = gdk_pixbuf__ico_image_stop_load;
+       module->load_increment = gdk_pixbuf__ico_image_load_increment;
+        module->save = gdk_pixbuf__ico_image_save;
+}
+
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
+{
+       static GdkPixbufModulePattern signature[] = {
+               { "  \x1   ", "zz znz", 100 }, 
+               { "  \x2   ", "zz znz", 100 },
+               { NULL, NULL, 0 }
+       };
+       static gchar * mime_types[] = {
+               "image/x-icon",
+               "image/x-ico",
+               "image/x-win-bitmap",
+               NULL
+       };
+       static gchar * extensions[] = {
+               "ico",
+               "cur",
+               NULL
+       };
+
+       info->name = "ico";
+       info->signature = signature;
+       info->description = N_("The ICO image format");
+       info->mime_types = mime_types;
+       info->extensions = extensions;
+       info->flags = GDK_PIXBUF_FORMAT_WRITABLE | GDK_PIXBUF_FORMAT_THREADSAFE;
+       info->license = "LGPL";
+}
+
+
+
+
diff --git a/gdk-pixbuf/io-jasper.c b/gdk-pixbuf/io-jasper.c
new file mode 100644 (file)
index 0000000..72046c6
--- /dev/null
@@ -0,0 +1,312 @@
+/* JPEG 2000 loader
+ *
+ * Copyright (c) 2007 Bastien Nocera <hadess@hadess.net>
+ * Inspired by work by Ben Karel <web+moz@eschew.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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 <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "gdk-pixbuf-private.h"
+
+#include <jasper/jasper.h>
+
+G_MODULE_EXPORT void fill_vtable (GdkPixbufModule * module);
+G_MODULE_EXPORT void fill_info (GdkPixbufFormat * info);
+
+struct jasper_context {
+       GdkPixbuf *pixbuf;
+
+       GdkPixbufModuleSizeFunc size_func;
+       GdkPixbufModuleUpdatedFunc updated_func;
+       GdkPixbufModulePreparedFunc prepared_func;
+       gpointer user_data;
+
+       jas_stream_t *stream;
+
+       int width, height;
+};
+
+static void
+free_jasper_context (struct jasper_context *context)
+{
+       if (!context)
+               return;
+
+       if (context->stream) {
+               jas_stream_close (context->stream);
+               context->stream = NULL;
+       }
+
+       g_free (context);
+}
+
+static gpointer
+jasper_image_begin_load (GdkPixbufModuleSizeFunc size_func,
+                        GdkPixbufModulePreparedFunc prepared_func,
+                        GdkPixbufModuleUpdatedFunc updated_func,
+                        gpointer user_data, GError **error)
+{
+       struct jasper_context *context;
+       jas_stream_t *stream;
+
+       jas_init ();
+
+       stream = jas_stream_memopen (NULL, -1);
+       if (!stream) {
+               g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                     _("Couldn't allocate memory for stream"));
+               return NULL;
+       }
+
+       context = g_new0 (struct jasper_context, 1);
+       if (!context)
+               return NULL;
+
+       context->size_func = size_func;
+       context->updated_func = updated_func;
+       context->prepared_func = prepared_func;
+       context->user_data = user_data;
+       context->width = context->height = -1;
+
+       context->stream = stream;
+
+       return context;
+}
+
+static gboolean
+jasper_image_try_load (struct jasper_context *context, GError **error)
+{
+       jas_image_t *raw_image, *image;
+       int num_components, colourspace_family;
+       int i, rowstride, shift;
+       guchar *pixels;
+
+       raw_image = jas_image_decode (context->stream, -1, 0);
+       if (!raw_image) {
+               g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("Couldn't decode image"));
+               return FALSE;
+       }
+
+       if (context->width == -1 && context->height == -1) {
+               int width, height;
+
+               context->width = width = jas_image_cmptwidth (raw_image, 0);
+               context->height = height = jas_image_cmptheight (raw_image, 0);
+
+               if (context->size_func) {
+                       (*context->size_func) (&width, &height, context->user_data);
+
+                       if (width == 0 || height == 0) {
+                               jas_image_destroy(raw_image);
+                               g_set_error_literal (error,
+                                                     GDK_PIXBUF_ERROR,
+                                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                                     _("Transformed JPEG2000 has zero width or height"));
+                               return FALSE;
+                       }
+               }
+       }
+
+       /* We only know how to handle grayscale and RGB images */
+       num_components = jas_image_numcmpts (raw_image);
+       colourspace_family = jas_clrspc_fam (jas_image_clrspc (raw_image));
+
+       if ((num_components != 3 && num_components != 4 && num_components != 1) ||
+           (colourspace_family != JAS_CLRSPC_FAM_RGB  && colourspace_family != JAS_CLRSPC_FAM_GRAY)) {
+               jas_image_destroy (raw_image);
+               g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+                                     _("Image type currently not supported"));
+               return FALSE;
+       }
+
+       /* Apply the colour profile to the image, creating a new one */
+       if (jas_image_clrspc (raw_image) != JAS_CLRSPC_SRGB) {
+               jas_cmprof_t *profile;
+
+               profile = jas_cmprof_createfromclrspc (JAS_CLRSPC_SRGB);
+               if (!profile) {
+                       jas_image_destroy (raw_image);
+                       g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                             _("Couldn't allocate memory for color profile"));
+                       return FALSE;
+               }
+
+               image = jas_image_chclrspc (raw_image, profile, JAS_CMXFORM_INTENT_PER);
+               if (!image) {
+                       jas_image_destroy (raw_image);
+                       g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                             _("Couldn't allocate memory for color profile"));
+                       return FALSE;
+               }
+       } else {
+               image = raw_image;
+       }
+
+       if (!context->pixbuf) {
+               int bits_per_sample;
+
+               /* Unfortunately, gdk-pixbuf doesn't support 16 bpp images
+                * bits_per_sample = jas_image_cmptprec (image, 0);
+               if (bits_per_sample < 8)
+                       bits_per_sample = 8;
+               else if (bits_per_sample > 8)
+                       bits_per_sample = 16;
+               */
+               bits_per_sample = 8;
+
+               context->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+                                                 FALSE, bits_per_sample,
+                                                 context->width, context->height);
+               if (context->pixbuf == NULL) {
+                       g_set_error_literal (error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                             _("Insufficient memory to open JPEG 2000 file"));
+                       return FALSE;
+               }
+               if (context->prepared_func)
+                       context->prepared_func (context->pixbuf, NULL, context->user_data);
+       }
+
+       /* We calculate how much we should shift the pixel
+        * data by to make it fit into our pixbuf */
+       shift = MAX (jas_image_cmptprec (image, 0) - gdk_pixbuf_get_bits_per_sample (context->pixbuf), 0);
+
+       /* Loop over the 3 colourspaces */
+       rowstride = gdk_pixbuf_get_rowstride (context->pixbuf);
+       pixels = gdk_pixbuf_get_pixels (context->pixbuf);
+
+       for (i = 0; i < num_components; i++) {
+               jas_matrix_t *matrix;
+               int j;
+
+               matrix = jas_matrix_create (context->height, context->width);
+
+               /* in libjasper, R is 0, G is 1, etc. we're lucky :)
+                * but we need to handle the "opacity" channel ourselves */
+               if (i != 4) {
+                       jas_image_readcmpt (image, i, 0, 0, context->width, context->height, matrix);
+               } else {
+                       jas_image_readcmpt (image, JAS_IMAGE_CT_OPACITY, 0, 0, context->width, context->height, matrix);
+               }
+
+               for (j = 0; j < context->height; j++) {
+                       int k;
+
+                       for (k = 0; k < context->width; k++) {
+                               if (num_components == 3 || num_components == 4) {
+                                       pixels[j * rowstride + k * 3 + i] = jas_matrix_get (matrix, j, k) >> shift;
+                               } else {
+                                       pixels[j * rowstride + k * 3] =
+                                               pixels[j * rowstride + k * 3 + 1] =
+                                               pixels[j * rowstride + k * 3 + 2] = jas_matrix_get (matrix, j, k) >> shift;
+                               }
+                       }
+                       /* Update once per line for the last component, otherwise
+                        * we might contain garbage */
+                       if (context->updated_func && (i == num_components - 1) && k != 0) {
+                               context->updated_func (context->pixbuf, 0, j, k, 1, context->user_data);
+                       }
+               }
+
+               jas_matrix_destroy (matrix);
+       }
+
+       if (image != raw_image)
+               jas_image_destroy (image);
+       jas_image_destroy (raw_image);
+
+       return TRUE;
+}
+
+static gboolean
+jasper_image_stop_load (gpointer data, GError **error)
+{
+       struct jasper_context *context = (struct jasper_context *) data;
+       gboolean ret;
+
+       jas_stream_rewind (context->stream);
+       ret = jasper_image_try_load (context, error);
+
+       free_jasper_context (context);
+
+       return ret;
+}
+
+static gboolean
+jasper_image_load_increment (gpointer data, const guchar *buf, guint size, GError **error)
+{
+       struct jasper_context *context = (struct jasper_context *) data;
+
+       if (jas_stream_write (context->stream, buf, size) < 0) {
+               g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                     _("Couldn't allocate memory to buffer image data"));
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+#ifndef INCLUDE_jasper
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
+#else
+#define MODULE_ENTRY(function) void _gdk_pixbuf__jasper_ ## function
+#endif
+
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule * module)
+{
+       module->begin_load = jasper_image_begin_load;
+       module->stop_load = jasper_image_stop_load;
+       module->load_increment = jasper_image_load_increment;
+}
+
+MODULE_ENTRY (fill_info) (GdkPixbufFormat * info)
+{
+       static GdkPixbufModulePattern signature[] = {
+               { "    jP", "!!!!  ", 100 },            /* file begins with 'jP' at offset 4 */
+               { "\xff\x4f\xff\x51\x00", NULL, 100 },  /* file starts with FF 4F FF 51 00 */
+               { NULL, NULL, 0 }
+       };
+       static gchar *mime_types[] = {
+               "image/jp2",
+               "image/jpeg2000",
+               "image/jpx",
+               NULL
+       };
+       static gchar *extensions[] = {
+               "jp2",
+               "jpc",
+               "jpx",
+               "j2k",
+               "jpf",
+               NULL
+       };
+
+       info->name = "jpeg2000";
+       info->signature = signature;
+       info->description = N_("The JPEG 2000 image format");
+       info->mime_types = mime_types;
+       info->extensions = extensions;
+       info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
+       info->license = "LGPL";
+       info->disabled = FALSE;
+}
+
diff --git a/gdk-pixbuf/io-jpeg.c b/gdk-pixbuf/io-jpeg.c
new file mode 100644 (file)
index 0000000..8560c94
--- /dev/null
@@ -0,0 +1,1321 @@
+/* -*- mode: C; c-file-style: "linux" -*- */
+/* GdkPixbuf library - JPEG image loader
+ *
+ * Copyright (C) 1999 Michael Zucchi
+ * Copyright (C) 1999 The Free Software Foundation
+ * 
+ * Progressive loading code Copyright (C) 1999 Red Hat, Inc.
+ *
+ * Authors: Michael Zucchi <zucchi@zedzone.mmc.com.au>
+ *          Federico Mena-Quintero <federico@gimp.org>
+ *          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
+ * 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.
+ *
+ * You should have received a copy of the GNU Lesser 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <setjmp.h>
+#include <jpeglib.h>
+#include <jerror.h>
+#include "gdk-pixbuf-private.h"
+
+#ifndef HAVE_SIGSETJMP
+#define sigjmp_buf jmp_buf
+#define sigsetjmp(jb, x) setjmp(jb)
+#define siglongjmp longjmp
+#endif
+\f
+
+/* we are a "source manager" as far as libjpeg is concerned */
+#define JPEG_PROG_BUF_SIZE 65536
+
+typedef struct {
+       struct jpeg_source_mgr pub;   /* public fields */
+
+       JOCTET buffer[JPEG_PROG_BUF_SIZE];              /* start of buffer */
+       long  skip_next;              /* number of bytes to skip next read */
+       
+} my_source_mgr;
+
+typedef my_source_mgr * my_src_ptr;
+
+/* error handler data */
+struct error_handler_data {
+       struct jpeg_error_mgr pub;
+       sigjmp_buf setjmp_buffer;
+        GError **error;
+};
+
+/* progressive loader context */
+typedef struct {
+        GdkPixbufModuleSizeFunc     size_func;
+       GdkPixbufModuleUpdatedFunc  updated_func;
+       GdkPixbufModulePreparedFunc prepared_func;
+       gpointer                    user_data;
+       
+       GdkPixbuf                *pixbuf;
+       guchar                   *dptr;   /* current position in pixbuf */
+
+       gboolean                 did_prescan;  /* are we in image data yet? */
+       gboolean                 got_header;  /* have we loaded jpeg header? */
+       gboolean                 src_initialized;/* TRUE when jpeg lib initialized */
+       gboolean                 in_output;   /* did we get suspended in an output pass? */
+       struct jpeg_decompress_struct cinfo;
+       struct error_handler_data     jerr;
+} JpegProgContext;
+
+static GdkPixbuf *gdk_pixbuf__jpeg_image_load (FILE *f, GError **error);
+static gpointer gdk_pixbuf__jpeg_image_begin_load (GdkPixbufModuleSizeFunc           func0,
+                                                   GdkPixbufModulePreparedFunc func1, 
+                                                   GdkPixbufModuleUpdatedFunc func2,
+                                                   gpointer user_data,
+                                                   GError **error);
+static gboolean gdk_pixbuf__jpeg_image_stop_load (gpointer context, GError **error);
+static gboolean gdk_pixbuf__jpeg_image_load_increment(gpointer context,
+                                                      const guchar *buf, guint size,
+                                                      GError **error);
+
+
+static void
+fatal_error_handler (j_common_ptr cinfo)
+{
+       struct error_handler_data *errmgr;
+        char buffer[JMSG_LENGTH_MAX];
+        
+       errmgr = (struct error_handler_data *) cinfo->err;
+        
+        /* Create the message */
+        (* cinfo->err->format_message) (cinfo, buffer);
+
+        /* broken check for *error == NULL for robustness against
+         * crappy JPEG library
+         */
+        if (errmgr->error && *errmgr->error == NULL) {
+                g_set_error (errmgr->error,
+                             GDK_PIXBUF_ERROR,
+                             cinfo->err->msg_code == JERR_OUT_OF_MEMORY 
+                            ? GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY 
+                            : GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                             _("Error interpreting JPEG image file (%s)"),
+                             buffer);
+        }
+        
+       siglongjmp (errmgr->setjmp_buffer, 1);
+
+        g_assert_not_reached ();
+}
+
+static void
+output_message_handler (j_common_ptr cinfo)
+{
+  /* This method keeps libjpeg from dumping crap to stderr */
+
+  /* do nothing */
+}
+
+/* explode gray image data from jpeg library into rgb components in pixbuf */
+static void
+explode_gray_into_buf (struct jpeg_decompress_struct *cinfo,
+                      guchar **lines) 
+{
+       gint i, j;
+       guint w;
+
+       g_return_if_fail (cinfo != NULL);
+       g_return_if_fail (cinfo->output_components == 1);
+       g_return_if_fail (cinfo->out_color_space == JCS_GRAYSCALE);
+
+       /* Expand grey->colour.  Expand from the end of the
+        * memory down, so we can use the same buffer.
+        */
+       w = cinfo->output_width;
+       for (i = cinfo->rec_outbuf_height - 1; i >= 0; i--) {
+               guchar *from, *to;
+               
+               from = lines[i] + w - 1;
+               to = lines[i] + (w - 1) * 3;
+               for (j = w - 1; j >= 0; j--) {
+                       to[0] = from[0];
+                       to[1] = from[0];
+                       to[2] = from[0];
+                       to -= 3;
+                       from--;
+               }
+       }
+}
+
+
+static void
+convert_cmyk_to_rgb (struct jpeg_decompress_struct *cinfo,
+                    guchar **lines) 
+{
+       gint i, j;
+
+       g_return_if_fail (cinfo != NULL);
+       g_return_if_fail (cinfo->output_components == 4);
+       g_return_if_fail (cinfo->out_color_space == JCS_CMYK);
+
+       for (i = cinfo->rec_outbuf_height - 1; i >= 0; i--) {
+               guchar *p;
+               
+               p = lines[i];
+               for (j = 0; j < cinfo->output_width; j++) {
+                       int c, m, y, k;
+                       c = p[0];
+                       m = p[1];
+                       y = p[2];
+                       k = p[3];
+                       if (cinfo->saw_Adobe_marker) {
+                               p[0] = k*c / 255;
+                               p[1] = k*m / 255;
+                               p[2] = k*y / 255;
+                       }
+                       else {
+                               p[0] = (255 - k)*(255 - c) / 255;
+                               p[1] = (255 - k)*(255 - m) / 255;
+                               p[2] = (255 - k)*(255 - y) / 255;
+                       }
+                       p[3] = 255;
+                       p += 4;
+               }
+       }
+}
+
+typedef struct {
+  struct jpeg_source_mgr pub;  /* public fields */
+
+  FILE * infile;               /* source stream */
+  JOCTET * buffer;             /* start of buffer */
+  boolean start_of_file;       /* have we gotten any data yet? */
+} stdio_source_mgr;
+
+typedef stdio_source_mgr * stdio_src_ptr;
+
+static void
+stdio_init_source (j_decompress_ptr cinfo)
+{
+  stdio_src_ptr src = (stdio_src_ptr)cinfo->src;
+  src->start_of_file = FALSE;
+}
+
+static boolean
+stdio_fill_input_buffer (j_decompress_ptr cinfo)
+{
+  stdio_src_ptr src = (stdio_src_ptr) cinfo->src;
+  size_t nbytes;
+
+  nbytes = fread (src->buffer, 1, JPEG_PROG_BUF_SIZE, src->infile);
+
+  if (nbytes <= 0) {
+#if 0
+    if (src->start_of_file)    /* Treat empty input file as fatal error */
+      ERREXIT(cinfo, JERR_INPUT_EMPTY);
+    WARNMS(cinfo, JWRN_JPEG_EOF);
+#endif
+    /* Insert a fake EOI marker */
+    src->buffer[0] = (JOCTET) 0xFF;
+    src->buffer[1] = (JOCTET) JPEG_EOI;
+    nbytes = 2;
+  }
+
+  src->pub.next_input_byte = src->buffer;
+  src->pub.bytes_in_buffer = nbytes;
+  src->start_of_file = FALSE;
+
+  return TRUE;
+}
+
+static void
+stdio_skip_input_data (j_decompress_ptr cinfo, long num_bytes)
+{
+  stdio_src_ptr src = (stdio_src_ptr) cinfo->src;
+
+  if (num_bytes > 0) {
+    while (num_bytes > (long) src->pub.bytes_in_buffer) {
+      num_bytes -= (long) src->pub.bytes_in_buffer;
+      (void)stdio_fill_input_buffer(cinfo);
+    }
+    src->pub.next_input_byte += (size_t) num_bytes;
+    src->pub.bytes_in_buffer -= (size_t) num_bytes;
+  }
+}
+
+static void
+stdio_term_source (j_decompress_ptr cinfo)
+{
+}
+
+static gchar *
+colorspace_name (const J_COLOR_SPACE jpeg_color_space) 
+{
+       switch (jpeg_color_space) {
+           case JCS_UNKNOWN: return "UNKNOWN"; 
+           case JCS_GRAYSCALE: return "GRAYSCALE"; 
+           case JCS_RGB: return "RGB"; 
+           case JCS_YCbCr: return "YCbCr"; 
+           case JCS_CMYK: return "CMYK"; 
+           case JCS_YCCK: return "YCCK";
+           default: return "invalid";
+       }
+}
+
+
+const char leth[]  = {0x49, 0x49, 0x2a, 0x00}; // Little endian TIFF header
+const char beth[]  = {0x4d, 0x4d, 0x00, 0x2a}; // Big endian TIFF header
+const char types[] = {0x00, 0x01, 0x01, 0x02, 0x04, 0x08, 0x00, 
+                     0x08, 0x00, 0x04, 0x08};  // size in bytes for EXIF types
+#define DE_ENDIAN16(val) endian == G_BIG_ENDIAN ? GUINT16_FROM_BE(val) : GUINT16_FROM_LE(val)
+#define DE_ENDIAN32(val) endian == G_BIG_ENDIAN ? GUINT32_FROM_BE(val) : GUINT32_FROM_LE(val)
+#define ENDIAN16_IT(val) endian == G_BIG_ENDIAN ? GUINT16_TO_BE(val) : GUINT16_TO_LE(val)
+#define ENDIAN32_IT(val) endian == G_BIG_ENDIAN ? GUINT32_TO_BE(val) : GUINT32_TO_LE(val)
+#define EXIF_JPEG_MARKER   JPEG_APP0+1
+#define EXIF_IDENT_STRING  "Exif\000\000"
+
+static unsigned short de_get16(void *ptr, guint endian)
+{
+       unsigned short val;
+
+       memcpy(&val, ptr, sizeof(val));
+       val = DE_ENDIAN16(val);
+
+       return val;
+}
+
+static unsigned int de_get32(void *ptr, guint endian)
+{
+       unsigned int val;
+
+       memcpy(&val, ptr, sizeof(val));
+       val = DE_ENDIAN32(val);
+
+       return val;
+}
+
+static gint 
+get_orientation (j_decompress_ptr cinfo)
+{
+       /* This function looks through the meta data in the libjpeg decompress structure to
+          determine if an EXIF Orientation tag is present and if so return its value (1-8). 
+          If no EXIF Orientation tag is found 0 (zero) is returned. */
+
+       guint   i;              /* index into working buffer */
+       guint   orient_tag_id;  /* endianed version of orientation tag ID */
+       guint   ret;            /* Return value */
+       guint   offset;         /* de-endianed offset in various situations */
+       guint   tags;           /* number of tags in current ifd */
+       guint   type;           /* de-endianed type of tag used as index into types[] */
+       guint   count;          /* de-endianed count of elements in a tag */
+        guint   tiff = 0;      /* offset to active tiff header */
+        guint   endian = 0;    /* detected endian of data */
+
+       jpeg_saved_marker_ptr exif_marker;  /* Location of the Exif APP1 marker */
+       jpeg_saved_marker_ptr cmarker;      /* Location to check for Exif APP1 marker */
+
+       /* check for Exif marker (also called the APP1 marker) */
+       exif_marker = NULL;
+       cmarker = cinfo->marker_list;
+       while (cmarker) {
+               if (cmarker->marker == EXIF_JPEG_MARKER) {
+                       /* The Exif APP1 marker should contain a unique
+                          identification string ("Exif\0\0"). Check for it. */
+                       if (!memcmp (cmarker->data, EXIF_IDENT_STRING, 6)) {
+                               exif_marker = cmarker;
+                               }
+                       }
+               cmarker = cmarker->next;
+       }
+         
+       /* Did we find the Exif APP1 marker? */
+       if (exif_marker == NULL)
+               return 0;
+
+       /* Do we have enough data? */
+       if (exif_marker->data_length < 32)
+               return 0;
+
+        /* Check for TIFF header and catch endianess */
+       i = 0;
+
+       /* Just skip data until TIFF header - it should be within 16 bytes from marker start.
+          Normal structure relative to APP1 marker -
+               0x0000: APP1 marker entry = 2 bytes
+               0x0002: APP1 length entry = 2 bytes
+               0x0004: Exif Identifier entry = 6 bytes
+               0x000A: Start of TIFF header (Byte order entry) - 4 bytes  
+                       - This is what we look for, to determine endianess.
+               0x000E: 0th IFD offset pointer - 4 bytes
+
+               exif_marker->data points to the first data after the APP1 marker
+               and length entries, which is the exif identification string.
+               The TIFF header should thus normally be found at i=6, below,
+               and the pointer to IFD0 will be at 6+4 = 10.
+       */
+                   
+       while (i < 16) {
+               /* Little endian TIFF header */
+               if (memcmp (&exif_marker->data[i], leth, 4) == 0){ 
+                       endian = G_LITTLE_ENDIAN;
+                }
+               /* Big endian TIFF header */
+               else if (memcmp (&exif_marker->data[i], beth, 4) == 0){ 
+                       endian = G_BIG_ENDIAN;
+                }
+               /* Keep looking through buffer */
+               else {
+                       i++;
+                       continue;
+               }
+               /* We have found either big or little endian TIFF header */
+               tiff = i;
+               break;
+        }
+
+       /* So did we find a TIFF header or did we just hit end of buffer? */
+       if (tiff == 0) 
+               return 0;
+        /* Endian the orientation tag ID, to locate it more easily */
+        orient_tag_id = ENDIAN16_IT(0x112);
+        /* Read out the offset pointer to IFD0 */
+        offset  = de_get32(&exif_marker->data[i] + 4, endian);
+       i       = i + offset;
+
+       /* Check that we still are within the buffer and can read the tag count */
+       if ((i + 2) > exif_marker->data_length)
+               return 0;
+
+       /* Find out how many tags we have in IFD0. As per the TIFF spec, the first
+          two bytes of the IFD contain a count of the number of tags. */
+       tags    = de_get16(&exif_marker->data[i], endian);
+       i       = i + 2;
+
+       /* Check that we still have enough data for all tags to check. The tags
+          are listed in consecutive 12-byte blocks. The tag ID, type, size, and
+          a pointer to the actual value, are packed into these 12 byte entries. */
+       if ((i + tags * 12) > exif_marker->data_length)
+               return 0;
+
+       /* Check through IFD0 for tags of interest */
+       while (tags--){
+               type   = de_get16(&exif_marker->data[i + 2], endian);
+               count  = de_get32(&exif_marker->data[i + 4], endian);
+
+               /* Is this the orientation tag? */
+               if (memcmp (&exif_marker->data[i], (char *) &orient_tag_id, 2) == 0){ 
+                       /* Check that type and count fields are OK. The orientation field 
+                          will consist of a single (count=1) 2-byte integer (type=3). */
+                       if (type != 3 || count != 1) return 0;
+
+                       /* Return the orientation value. Within the 12-byte block, the
+                          pointer to the actual data is at offset 8. */
+                       ret =  de_get16(&exif_marker->data[i + 8], endian);
+                       return ret <= 8 ? ret : 0;
+               }
+               /* move the pointer to the next 12-byte tag field. */
+               i = i + 12;
+       }
+
+       return 0; /* No EXIF Orientation tag found */
+}
+
+
+/* Shared library entry point */
+static GdkPixbuf *
+gdk_pixbuf__jpeg_image_load (FILE *f, GError **error)
+{
+       gint   i;
+       int     is_otag;
+       char   otag_str[5];
+       GdkPixbuf * volatile pixbuf = NULL;
+       guchar *dptr;
+       guchar *lines[4]; /* Used to expand rows, via rec_outbuf_height, 
+                           * from the header file: 
+                           * " Usually rec_outbuf_height will be 1 or 2, 
+                           * at most 4."
+                          */
+       guchar **lptr;
+       struct jpeg_decompress_struct cinfo;
+       struct error_handler_data jerr;
+       stdio_src_ptr src;
+
+       /* setup error handler */
+       cinfo.err = jpeg_std_error (&jerr.pub);
+       jerr.pub.error_exit = fatal_error_handler;
+        jerr.pub.output_message = output_message_handler;
+        jerr.error = error;
+        
+       if (sigsetjmp (jerr.setjmp_buffer, 1)) {
+               /* Whoops there was a jpeg error */
+               if (pixbuf)
+                       g_object_unref (pixbuf);
+
+               jpeg_destroy_decompress (&cinfo);
+
+               /* error should have been set by fatal_error_handler () */
+               return NULL;
+       }
+
+       /* load header, setup */
+       jpeg_create_decompress (&cinfo);
+
+       cinfo.src = (struct jpeg_source_mgr *)
+         (*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT,
+                                 sizeof (stdio_source_mgr));
+       src = (stdio_src_ptr) cinfo.src;
+       src->buffer = (JOCTET *)
+         (*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT,
+                                     JPEG_PROG_BUF_SIZE * sizeof (JOCTET));
+
+       src->pub.init_source = stdio_init_source;
+       src->pub.fill_input_buffer = stdio_fill_input_buffer;
+       src->pub.skip_input_data = stdio_skip_input_data;
+       src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
+       src->pub.term_source = stdio_term_source;
+       src->infile = f;
+       src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
+       src->pub.next_input_byte = NULL; /* until buffer loaded */
+
+       jpeg_save_markers (&cinfo, EXIF_JPEG_MARKER, 0xffff);
+       jpeg_read_header (&cinfo, TRUE);
+
+       /* check for orientation tag */
+       is_otag = get_orientation (&cinfo);
+       
+       jpeg_start_decompress (&cinfo);
+       cinfo.do_fancy_upsampling = FALSE;
+       cinfo.do_block_smoothing = FALSE;
+
+       pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 
+                                cinfo.out_color_components == 4 ? TRUE : FALSE, 
+                                8, cinfo.output_width, cinfo.output_height);
+             
+       if (!pixbuf) {
+               jpeg_destroy_decompress (&cinfo);
+
+                /* broken check for *error == NULL for robustness against
+                 * crappy JPEG library
+                 */
+                if (error && *error == NULL) {
+                        g_set_error_literal (error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                             _("Insufficient memory to load image, try exiting some applications to free memory"));
+                }
+                
+               return NULL;
+       }
+
+       /* if orientation tag was found set an option to remember its value */
+       if (is_otag) {
+               g_snprintf (otag_str, sizeof (otag_str), "%d", is_otag);
+               gdk_pixbuf_set_option (pixbuf, "orientation", otag_str);
+       }
+
+
+       dptr = pixbuf->pixels;
+
+       /* decompress all the lines, a few at a time */
+       while (cinfo.output_scanline < cinfo.output_height) {
+               lptr = lines;
+               for (i = 0; i < cinfo.rec_outbuf_height; i++) {
+                       *lptr++ = dptr;
+                       dptr += pixbuf->rowstride;
+               }
+
+               jpeg_read_scanlines (&cinfo, lines, cinfo.rec_outbuf_height);
+
+               switch (cinfo.out_color_space) {
+                   case JCS_GRAYSCALE:
+                     explode_gray_into_buf (&cinfo, lines);
+                     break;
+                   case JCS_RGB:
+                     /* do nothing */
+                     break;
+                   case JCS_CMYK:
+                     convert_cmyk_to_rgb (&cinfo, lines);
+                     break;
+                   default:
+                     g_object_unref (pixbuf);
+                     if (error && *error == NULL) {
+                        g_set_error (error,
+                                     GDK_PIXBUF_ERROR,
+                                    GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+                                    _("Unsupported JPEG color space (%s)"),
+                                    colorspace_name (cinfo.out_color_space)); 
+                     }
+                
+                     jpeg_destroy_decompress (&cinfo);
+                     return NULL;
+               }
+       }
+
+       jpeg_finish_decompress (&cinfo);
+       jpeg_destroy_decompress (&cinfo);
+
+       return pixbuf;
+}
+
+
+/**** Progressive image loading handling *****/
+
+/* these routines required because we are acting as a source manager for */
+/* libjpeg. */
+static void
+init_source (j_decompress_ptr cinfo)
+{
+       my_src_ptr src = (my_src_ptr) cinfo->src;
+
+       src->skip_next = 0;
+}
+
+
+static void
+term_source (j_decompress_ptr cinfo)
+{
+       /* XXXX - probably should scream something has happened */
+}
+
+
+/* for progressive loading (called "I/O Suspension" by libjpeg docs) */
+/* we do nothing except return "FALSE"                               */
+static boolean
+fill_input_buffer (j_decompress_ptr cinfo)
+{
+       return FALSE;
+}
+
+
+static void
+skip_input_data (j_decompress_ptr cinfo, long num_bytes)
+{
+       my_src_ptr src = (my_src_ptr) cinfo->src;
+       long   num_can_do;
+
+       /* move as far as we can into current buffer */
+       /* then set skip_next to catch the rest      */
+       if (num_bytes > 0) {
+               num_can_do = MIN (src->pub.bytes_in_buffer, num_bytes);
+               src->pub.next_input_byte += (size_t) num_can_do;
+               src->pub.bytes_in_buffer -= (size_t) num_can_do;
+
+               src->skip_next = num_bytes - num_can_do;
+       }
+}
+
+/* 
+ * func - called when we have pixmap created (but no image data)
+ * user_data - passed as arg 1 to func
+ * return context (opaque to user)
+ */
+
+static gpointer
+gdk_pixbuf__jpeg_image_begin_load (GdkPixbufModuleSizeFunc size_func,
+                                  GdkPixbufModulePreparedFunc prepared_func, 
+                                  GdkPixbufModuleUpdatedFunc updated_func,
+                                  gpointer user_data,
+                                   GError **error)
+{
+       JpegProgContext *context;
+       my_source_mgr   *src;
+
+       context = g_new0 (JpegProgContext, 1);
+       context->size_func = size_func;
+       context->prepared_func = prepared_func;
+       context->updated_func  = updated_func;
+       context->user_data = user_data;
+       context->pixbuf = NULL;
+       context->got_header = FALSE;
+       context->did_prescan = FALSE;
+       context->src_initialized = FALSE;
+       context->in_output = FALSE;
+
+        /* From jpeglib.h: "NB: you must set up the error-manager
+         * BEFORE calling jpeg_create_xxx". */
+       context->cinfo.err = jpeg_std_error (&context->jerr.pub);
+       context->jerr.pub.error_exit = fatal_error_handler;
+        context->jerr.pub.output_message = output_message_handler;
+        context->jerr.error = error;
+
+        if (sigsetjmp (context->jerr.setjmp_buffer, 1)) {
+                jpeg_destroy_decompress (&context->cinfo);
+                g_free(context);
+                /* error should have been set by fatal_error_handler () */
+                return NULL;
+        }
+
+       /* create libjpeg structures */
+       jpeg_create_decompress (&context->cinfo);
+
+       context->cinfo.src = (struct jpeg_source_mgr *) g_try_malloc (sizeof (my_source_mgr));
+       if (!context->cinfo.src) {
+               g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                     _("Couldn't allocate memory for loading JPEG file"));
+               return NULL;
+       }
+       memset (context->cinfo.src, 0, sizeof (my_source_mgr));
+
+       src = (my_src_ptr) context->cinfo.src;
+       src->pub.init_source = init_source;
+       src->pub.fill_input_buffer = fill_input_buffer;
+       src->pub.skip_input_data = skip_input_data;
+       src->pub.resync_to_restart = jpeg_resync_to_restart;
+       src->pub.term_source = term_source;
+       src->pub.bytes_in_buffer = 0;
+       src->pub.next_input_byte = NULL;
+
+        context->jerr.error = NULL;
+        
+       return (gpointer) context;
+}
+
+/*
+ * context - returned from image_begin_load
+ *
+ * free context, unref gdk_pixbuf
+ */
+static gboolean
+gdk_pixbuf__jpeg_image_stop_load (gpointer data, GError **error)
+{
+       JpegProgContext *context = (JpegProgContext *) data;
+        gboolean retval;
+
+       g_return_val_if_fail (context != NULL, TRUE);
+       
+        /* FIXME this thing needs to report errors if
+         * we have unused image data
+         */
+        
+       if (context->pixbuf)
+               g_object_unref (context->pixbuf);
+       
+       /* if we have an error? */
+       context->jerr.error = error;
+       if (sigsetjmp (context->jerr.setjmp_buffer, 1)) {
+                retval = FALSE;
+       } else {
+               jpeg_finish_decompress (&context->cinfo);
+                retval = TRUE;
+       }
+
+        jpeg_destroy_decompress (&context->cinfo);
+
+       if (context->cinfo.src) {
+               my_src_ptr src = (my_src_ptr) context->cinfo.src;
+               
+               g_free (src);
+       }
+
+       g_free (context);
+
+        return retval;
+}
+
+
+static gboolean
+gdk_pixbuf__jpeg_image_load_lines (JpegProgContext  *context,
+                                   GError          **error)
+{
+        struct jpeg_decompress_struct *cinfo = &context->cinfo;
+        guchar *lines[4];
+        guchar **lptr;
+        guchar *rowptr;
+        gint   nlines, i;
+
+        /* keep going until we've done all scanlines */
+        while (cinfo->output_scanline < cinfo->output_height) {
+                lptr = lines;
+                rowptr = context->dptr;
+                for (i=0; i < cinfo->rec_outbuf_height; i++) {
+                        *lptr++ = rowptr;
+                        rowptr += context->pixbuf->rowstride;
+                }
+
+                nlines = jpeg_read_scanlines (cinfo, lines,
+                                              cinfo->rec_outbuf_height);
+                if (nlines == 0)
+                        break;
+
+                switch (cinfo->out_color_space) {
+                case JCS_GRAYSCALE:
+                        explode_gray_into_buf (cinfo, lines);
+                        break;
+                case JCS_RGB:
+                        /* do nothing */
+                        break;
+                case JCS_CMYK:
+                        convert_cmyk_to_rgb (cinfo, lines);
+                        break;
+                default:
+                        if (error && *error == NULL) {
+                                g_set_error (error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+                                             _("Unsupported JPEG color space (%s)"),
+                                             colorspace_name (cinfo->out_color_space));
+                        }
+
+                        return FALSE;
+                }
+
+                context->dptr += nlines * context->pixbuf->rowstride;
+
+                /* send updated signal */
+               if (context->updated_func)
+                       (* context->updated_func) (context->pixbuf,
+                                                  0,
+                                                  cinfo->output_scanline - 1,
+                                                  cinfo->image_width,
+                                                  nlines,
+                                                  context->user_data);
+        }
+
+        return TRUE;
+}
+
+
+/*
+ * context - from image_begin_load
+ * buf - new image data
+ * size - length of new image data
+ *
+ * append image data onto inrecrementally built output image
+ */
+static gboolean
+gdk_pixbuf__jpeg_image_load_increment (gpointer data,
+                                       const guchar *buf, guint size,
+                                       GError **error)
+{
+       JpegProgContext *context = (JpegProgContext *)data;
+       struct           jpeg_decompress_struct *cinfo;
+       my_src_ptr       src;
+       guint            num_left, num_copy;
+       guint            last_num_left, last_bytes_left;
+       guint            spinguard;
+       gboolean         first;
+       const guchar    *bufhd;
+       gint             width, height;
+        int              is_otag;
+       char             otag_str[5];
+
+       g_return_val_if_fail (context != NULL, FALSE);
+       g_return_val_if_fail (buf != NULL, FALSE);
+
+       src = (my_src_ptr) context->cinfo.src;
+
+       cinfo = &context->cinfo;
+
+        context->jerr.error = error;
+        
+       /* check for fatal error */
+       if (sigsetjmp (context->jerr.setjmp_buffer, 1)) {
+               return FALSE;
+       }
+
+       /* skip over data if requested, handle unsigned int sizes cleanly */
+       /* only can happen if we've already called jpeg_get_header once   */
+       if (context->src_initialized && src->skip_next) {
+               if (src->skip_next > size) {
+                       src->skip_next -= size;
+                       return TRUE;
+               } else {
+                       num_left = size - src->skip_next;
+                       bufhd = buf + src->skip_next;
+                       src->skip_next = 0;
+               }
+       } else {
+               num_left = size;
+               bufhd = buf;
+       }
+
+       if (num_left == 0)
+               return TRUE;
+
+       last_num_left = num_left;
+       last_bytes_left = 0;
+       spinguard = 0;
+       first = TRUE;
+       while (TRUE) {
+
+               /* handle any data from caller we haven't processed yet */
+               if (num_left > 0) {
+                       if(src->pub.bytes_in_buffer && 
+                          src->pub.next_input_byte != src->buffer)
+                               memmove(src->buffer, src->pub.next_input_byte,
+                                       src->pub.bytes_in_buffer);
+
+
+                       num_copy = MIN (JPEG_PROG_BUF_SIZE - src->pub.bytes_in_buffer,
+                                       num_left);
+
+                       memcpy(src->buffer + src->pub.bytes_in_buffer, bufhd,num_copy);
+                       src->pub.next_input_byte = src->buffer;
+                       src->pub.bytes_in_buffer += num_copy;
+                       bufhd += num_copy;
+                       num_left -= num_copy;
+               }
+
+                /* did anything change from last pass, if not return */
+                if (first) {
+                        last_bytes_left = src->pub.bytes_in_buffer;
+                        first = FALSE;
+                } else if (src->pub.bytes_in_buffer == last_bytes_left
+                          && num_left == last_num_left) {
+                        spinguard++;
+               } else {
+                        last_bytes_left = src->pub.bytes_in_buffer;
+                       last_num_left = num_left;
+               }
+
+               /* should not go through twice and not pull bytes out of buf */
+               if (spinguard > 2)
+                       return TRUE;
+
+               /* try to load jpeg header */
+               if (!context->got_header) {
+                       int rc;
+               
+                       jpeg_save_markers (cinfo, EXIF_JPEG_MARKER, 0xffff);
+                       rc = jpeg_read_header (cinfo, TRUE);
+                       context->src_initialized = TRUE;
+                       
+                       if (rc == JPEG_SUSPENDED)
+                               continue;
+                       
+                       context->got_header = TRUE;
+
+                       /* check for orientation tag */
+                       is_otag = get_orientation (cinfo);
+               
+                       width = cinfo->image_width;
+                       height = cinfo->image_height;
+                       if (context->size_func) {
+                               (* context->size_func) (&width, &height, context->user_data);
+                               if (width == 0 || height == 0) {
+                                       g_set_error_literal (error,
+                                                             GDK_PIXBUF_ERROR,
+                                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                                             _("Transformed JPEG has zero width or height."));
+                                       return FALSE;
+                               }
+                       }
+                       
+                       cinfo->scale_num = 1;
+                       for (cinfo->scale_denom = 2; cinfo->scale_denom <= 8; cinfo->scale_denom *= 2) {
+                               jpeg_calc_output_dimensions (cinfo);
+                               if (cinfo->output_width < width || cinfo->output_height < height) {
+                                       cinfo->scale_denom /= 2;
+                                       break;
+                               }
+                       }
+                       jpeg_calc_output_dimensions (cinfo);
+                       
+                       context->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 
+                                                         cinfo->output_components == 4 ? TRUE : FALSE,
+                                                         8, 
+                                                         cinfo->output_width,
+                                                         cinfo->output_height);
+
+                       if (context->pixbuf == NULL) {
+                                g_set_error_literal (error,
+                                                     GDK_PIXBUF_ERROR,
+                                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                                     _("Couldn't allocate memory for loading JPEG file"));
+                                return FALSE;
+                       }
+               
+                       /* if orientation tag was found set an option to remember its value */
+                       if (is_otag) {
+                               g_snprintf (otag_str, sizeof (otag_str), "%d", is_otag);
+                               gdk_pixbuf_set_option (context->pixbuf, "orientation", otag_str);
+                       }
+
+                       /* Use pixbuf buffer to store decompressed data */
+                       context->dptr = context->pixbuf->pixels;
+                       
+                       /* Notify the client that we are ready to go */
+                       if (context->prepared_func)
+                               (* context->prepared_func) (context->pixbuf,
+                                                           NULL,
+                                                           context->user_data);
+                       
+               } else if (!context->did_prescan) {
+                       int rc;                 
+                       
+                       /* start decompression */
+                       cinfo->buffered_image = cinfo->progressive_mode;
+                       rc = jpeg_start_decompress (cinfo);
+                       cinfo->do_fancy_upsampling = FALSE;
+                       cinfo->do_block_smoothing = FALSE;
+
+                       if (rc == JPEG_SUSPENDED)
+                               continue;
+
+                       context->did_prescan = TRUE;
+               } else if (!cinfo->buffered_image) {
+                        /* we're decompressing unbuffered so
+                         * simply get scanline by scanline from jpeg lib
+                         */
+                        if (! gdk_pixbuf__jpeg_image_load_lines (context,
+                                                                 error))
+                                return FALSE;
+
+                       if (cinfo->output_scanline >= cinfo->output_height)
+                               return TRUE;
+               } else {
+                        /* we're decompressing buffered (progressive)
+                         * so feed jpeg lib scanlines
+                         */
+
+                       /* keep going until we've done all passes */
+                       while (!jpeg_input_complete (cinfo)) {
+                               if (!context->in_output) {
+                                       if (jpeg_start_output (cinfo, cinfo->input_scan_number)) {
+                                               context->in_output = TRUE;
+                                               context->dptr = context->pixbuf->pixels;
+                                       }
+                                       else
+                                               break;
+                               }
+
+                                /* get scanlines from jpeg lib */
+                                if (! gdk_pixbuf__jpeg_image_load_lines (context,
+                                                                         error))
+                                        return FALSE;
+
+                               if (cinfo->output_scanline >= cinfo->output_height &&
+                                   jpeg_finish_output (cinfo))
+                                       context->in_output = FALSE;
+                               else
+                                       break;
+                       }
+                       if (jpeg_input_complete (cinfo))
+                               /* did entire image */
+                               return TRUE;
+                       else
+                               continue;
+               }
+       }
+}
+
+/* Save */
+
+#define TO_FUNCTION_BUF_SIZE 4096
+
+typedef struct {
+       struct jpeg_destination_mgr pub;
+       JOCTET             *buffer;
+       GdkPixbufSaveFunc   save_func;
+       gpointer            user_data;
+       GError            **error;
+} ToFunctionDestinationManager;
+
+void
+to_callback_init (j_compress_ptr cinfo)
+{
+       ToFunctionDestinationManager *destmgr;
+
+       destmgr = (ToFunctionDestinationManager*) cinfo->dest;
+       destmgr->pub.next_output_byte = destmgr->buffer;
+       destmgr->pub.free_in_buffer = TO_FUNCTION_BUF_SIZE;
+}
+
+static void
+to_callback_do_write (j_compress_ptr cinfo, gsize length)
+{
+       ToFunctionDestinationManager *destmgr;
+
+       destmgr = (ToFunctionDestinationManager*) cinfo->dest;
+        if (!destmgr->save_func ((gchar *)destmgr->buffer,
+                                length,
+                                destmgr->error,
+                                destmgr->user_data)) {
+               struct error_handler_data *errmgr;
+        
+               errmgr = (struct error_handler_data *) cinfo->err;
+               /* Use a default error message if the callback didn't set one,
+                * which it should have.
+                */
+               if (errmgr->error && *errmgr->error == NULL) {
+                       g_set_error_literal (errmgr->error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                             "write function failed");
+               }
+               siglongjmp (errmgr->setjmp_buffer, 1);
+               g_assert_not_reached ();
+        }
+}
+
+static boolean
+to_callback_empty_output_buffer (j_compress_ptr cinfo)
+{
+       ToFunctionDestinationManager *destmgr;
+
+       destmgr = (ToFunctionDestinationManager*) cinfo->dest;
+       to_callback_do_write (cinfo, TO_FUNCTION_BUF_SIZE);
+       destmgr->pub.next_output_byte = destmgr->buffer;
+       destmgr->pub.free_in_buffer = TO_FUNCTION_BUF_SIZE;
+       return TRUE;
+}
+
+void
+to_callback_terminate (j_compress_ptr cinfo)
+{
+       ToFunctionDestinationManager *destmgr;
+
+       destmgr = (ToFunctionDestinationManager*) cinfo->dest;
+       to_callback_do_write (cinfo, TO_FUNCTION_BUF_SIZE - destmgr->pub.free_in_buffer);
+}
+
+static gboolean
+real_save_jpeg (GdkPixbuf          *pixbuf,
+               gchar             **keys,
+               gchar             **values,
+               GError            **error,
+               gboolean            to_callback,
+               FILE               *f,
+               GdkPixbufSaveFunc   save_func,
+               gpointer            user_data)
+{
+        /* FIXME error handling is broken */
+        
+       struct jpeg_compress_struct cinfo;
+       guchar *buf = NULL;
+       guchar *ptr;
+       guchar *pixels = NULL;
+       JSAMPROW *jbuf;
+       int y = 0;
+       volatile int quality = 75; /* default; must be between 0 and 100 */
+       int i, j;
+       int w, h = 0;
+       int rowstride = 0;
+       int n_channels;
+       struct error_handler_data jerr;
+       ToFunctionDestinationManager to_callback_destmgr;
+
+       to_callback_destmgr.buffer = NULL;
+
+       if (keys && *keys) {
+               gchar **kiter = keys;
+               gchar **viter = values;
+
+               while (*kiter) {
+                       if (strcmp (*kiter, "quality") == 0) {
+                               char *endptr = NULL;
+                               quality = strtol (*viter, &endptr, 10);
+
+                               if (endptr == *viter) {
+                                       g_set_error (error,
+                                                    GDK_PIXBUF_ERROR,
+                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
+                                                    _("JPEG quality must be a value between 0 and 100; value '%s' could not be parsed."),
+                                                    *viter);
+
+                                       return FALSE;
+                               }
+                               
+                               if (quality < 0 ||
+                                   quality > 100) {
+                                       /* This is a user-visible error;
+                                        * lets people skip the range-checking
+                                        * in their app.
+                                        */
+                                       g_set_error (error,
+                                                    GDK_PIXBUF_ERROR,
+                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
+                                                    _("JPEG quality must be a value between 0 and 100; value '%d' is not allowed."),
+                                                    quality);
+
+                                       return FALSE;
+                               }
+                       } else {
+                               g_warning ("Unrecognized parameter (%s) passed to JPEG saver.", *kiter);
+                       }
+               
+                       ++kiter;
+                       ++viter;
+               }
+       }
+       
+       rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+       n_channels = gdk_pixbuf_get_n_channels (pixbuf);
+
+       w = gdk_pixbuf_get_width (pixbuf);
+       h = gdk_pixbuf_get_height (pixbuf);
+       pixels = gdk_pixbuf_get_pixels (pixbuf);
+
+       /* Allocate a small buffer to convert image data,
+       * and a larger buffer if doing to_callback save.
+       */
+       buf = g_try_malloc (w * 3 * sizeof (guchar));
+       if (!buf) {
+              g_set_error_literal (error,
+                                    GDK_PIXBUF_ERROR,
+                                    GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                    _("Couldn't allocate memory for loading JPEG file"));
+              return FALSE;
+       }
+       if (to_callback) {
+              to_callback_destmgr.buffer = g_try_malloc (TO_FUNCTION_BUF_SIZE);
+              if (!to_callback_destmgr.buffer) {
+                      g_set_error_literal (error,
+                                            GDK_PIXBUF_ERROR,
+                                            GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                            _("Couldn't allocate memory for loading JPEG file"));
+                       g_free (buf);
+                      return FALSE;
+              }
+       }
+
+       /* set up error handling */
+       cinfo.err = jpeg_std_error (&(jerr.pub));
+       jerr.pub.error_exit = fatal_error_handler;
+       jerr.pub.output_message = output_message_handler;
+       jerr.error = error;
+       
+       if (sigsetjmp (jerr.setjmp_buffer, 1)) {
+               jpeg_destroy_compress (&cinfo);
+               g_free (buf);
+              g_free (to_callback_destmgr.buffer);
+               return FALSE;
+       }
+
+       /* setup compress params */
+       jpeg_create_compress (&cinfo);
+       if (to_callback) {
+              to_callback_destmgr.pub.init_destination    = to_callback_init;
+              to_callback_destmgr.pub.empty_output_buffer = to_callback_empty_output_buffer;
+              to_callback_destmgr.pub.term_destination    = to_callback_terminate;
+              to_callback_destmgr.error = error;
+              to_callback_destmgr.save_func = save_func;
+              to_callback_destmgr.user_data = user_data;
+              cinfo.dest = (struct jpeg_destination_mgr*) &to_callback_destmgr;
+       } else {
+              jpeg_stdio_dest (&cinfo, f);
+       }
+       cinfo.image_width      = w;
+       cinfo.image_height     = h;
+       cinfo.input_components = 3; 
+       cinfo.in_color_space   = JCS_RGB;
+
+       /* set up jepg compression parameters */
+       jpeg_set_defaults (&cinfo);
+       jpeg_set_quality (&cinfo, quality, TRUE);
+       jpeg_start_compress (&cinfo, TRUE);
+       /* get the start pointer */
+       ptr = pixels;
+       /* go one scanline at a time... and save */
+       i = 0;
+       while (cinfo.next_scanline < cinfo.image_height) {
+               /* convert scanline from ARGB to RGB packed */
+               for (j = 0; j < w; j++)
+                       memcpy (&(buf[j*3]), &(ptr[i*rowstride + j*n_channels]), 3);
+
+               /* write scanline */
+               jbuf = (JSAMPROW *)(&buf);
+               jpeg_write_scanlines (&cinfo, jbuf, 1);
+               i++;
+               y++;
+
+       }
+       
+       /* finish off */
+       jpeg_finish_compress (&cinfo);
+       jpeg_destroy_compress(&cinfo);
+       g_free (buf);
+       g_free (to_callback_destmgr.buffer);
+       return TRUE;
+}
+
+static gboolean
+gdk_pixbuf__jpeg_image_save (FILE          *f, 
+                             GdkPixbuf     *pixbuf, 
+                             gchar        **keys,
+                             gchar        **values,
+                             GError       **error)
+{
+       return real_save_jpeg (pixbuf, keys, values, error,
+                              FALSE, f, NULL, NULL);
+}
+
+static gboolean
+gdk_pixbuf__jpeg_image_save_to_callback (GdkPixbufSaveFunc   save_func,
+                                        gpointer            user_data,
+                                        GdkPixbuf          *pixbuf, 
+                                        gchar             **keys,
+                                        gchar             **values,
+                                        GError            **error)
+{
+       return real_save_jpeg (pixbuf, keys, values, error,
+                              TRUE, NULL, save_func, user_data);
+}
+
+#ifndef INCLUDE_jpeg
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
+#else
+#define MODULE_ENTRY(function) void _gdk_pixbuf__jpeg_ ## function
+#endif
+
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
+{
+       module->load = gdk_pixbuf__jpeg_image_load;
+       module->begin_load = gdk_pixbuf__jpeg_image_begin_load;
+       module->stop_load = gdk_pixbuf__jpeg_image_stop_load;
+       module->load_increment = gdk_pixbuf__jpeg_image_load_increment;
+       module->save = gdk_pixbuf__jpeg_image_save;
+       module->save_to_callback = gdk_pixbuf__jpeg_image_save_to_callback;
+}
+
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
+{
+       static GdkPixbufModulePattern signature[] = {
+               { "\xff\xd8", NULL, 100 },
+               { NULL, NULL, 0 }
+       };
+       static gchar * mime_types[] = {
+               "image/jpeg",
+               NULL
+       };
+       static gchar * extensions[] = {
+               "jpeg",
+               "jpe",
+               "jpg",
+               NULL
+       };
+
+       info->name = "jpeg";
+       info->signature = signature;
+       info->description = N_("The JPEG image format");
+       info->mime_types = mime_types;
+       info->extensions = extensions;
+       info->flags = GDK_PIXBUF_FORMAT_WRITABLE | GDK_PIXBUF_FORMAT_THREADSAFE;
+       info->license = "LGPL";
+}
diff --git a/gdk-pixbuf/io-pcx.c b/gdk-pixbuf/io-pcx.c
new file mode 100644 (file)
index 0000000..b658f58
--- /dev/null
@@ -0,0 +1,760 @@
+/*
+ * GdkPixbuf library - PCX image loader
+ *
+ * Copyright (C) 2003 Josh A. Beam
+ *
+ * Authors: Josh A. Beam <josh@joshbeam.com>
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include "gdk-pixbuf-private.h"
+
+#undef PCX_DEBUG
+
+#define PCX_TASK_DONE 0
+#define PCX_TASK_LOAD_HEADER 1
+#define PCX_TASK_LOAD_DATA 2
+#define PCX_TASK_LOAD_PALETTE 3
+
+struct pcx_header {
+       guint8 manufacturer;
+       guint8 version;
+       guint8 encoding;
+       guint8 bitsperpixel;
+       gint16 xmin;
+       gint16 ymin;
+       gint16 xmax;
+       gint16 ymax;
+       guint16 horizdpi;
+       guint16 vertdpi;
+       guint8 palette[48];
+       guint8 reserved;
+       guint8 colorplanes;
+       guint16 bytesperline;
+       guint16 palettetype;
+       guint16 hscrsize;
+       guint16 vscrsize;
+       guint8 filler[54];
+};
+
+struct pcx_context {
+       GdkPixbuf *pixbuf;
+       gint rowstride;
+
+       GdkPixbufModuleSizeFunc size_func;
+       GdkPixbufModuleUpdatedFunc updated_func;
+       GdkPixbufModulePreparedFunc prepared_func;
+       gpointer user_data;
+
+       guchar current_task;
+
+       gboolean header_loaded;
+       struct pcx_header *header;
+       guint bpp;
+       gint width, height;
+       guint num_planes;
+       guint bytesperline;
+
+       guchar *buf;
+       guint buf_size;
+       guint buf_pos;
+       guchar *data;
+       guchar *line;
+       guint current_line;
+       guchar *p_data;
+};
+
+/*
+ * set context's image information based on the header
+ */
+static void
+fill_pcx_context(struct pcx_context *context)
+{
+       struct pcx_header *header = context->header;
+
+       context->bpp = header->bitsperpixel;
+       context->width = header->xmax - header->xmin + 1;
+       context->height = header->ymax - header->ymin + 1;
+       context->num_planes = header->colorplanes;
+       context->bytesperline = header->bytesperline;
+
+       if(header->version == 5 && context->bpp == 8 && context->num_planes == 3)
+               context->bpp = 24;
+}
+
+static void
+free_pcx_context(struct pcx_context *context, gboolean unref_pixbuf)
+{
+       g_free(context->header);
+       g_free(context->buf);
+       if(unref_pixbuf && context->pixbuf)
+               g_object_unref(context->pixbuf);
+       g_free(context->line);
+       g_free(context->p_data);
+
+       g_free(context);
+}
+
+/*
+ * read each plane of a single scanline. store_planes is
+ * the number of planes that can be stored in the planes array.
+ * data is the pointer to the block of memory to read
+ * from, size is the length of that data, and line_bytes
+ * is where the number of bytes read will be stored.
+ */
+static gboolean
+read_scanline_data(guchar *data, guint size, guchar *planes[],
+                   guint store_planes, guint num_planes, guint bytesperline,
+                   guint *line_bytes)
+{
+       guint i, j;
+       guint p, count;
+       guint d = 0;
+       guint8 byte;
+
+       for(p = 0; p < num_planes; p++) {
+               for(i = 0; i < bytesperline;) { /* i incremented when line byte set */
+                       if(d >= size)
+                               return FALSE;
+                       byte = data[d++];
+
+                       if(byte >> 6 == 0x3) {
+                               count = byte & ~(0x3 << 6);
+                               if(count == 0)
+                                       return FALSE;
+                               if(d >= size)
+                                       return FALSE;
+                               byte = data[d++];
+                       } else {
+                               count = 1;
+                       }
+
+                       for(j = 0; j < count; j++) {
+                               if(p < store_planes)
+                                       planes[p][i++] = byte;
+                               else
+                                       i++;
+
+                               if(i >= bytesperline) {
+                                       p++;
+                                       if(p >= num_planes) {
+                                               *line_bytes = d;
+                                               return TRUE;
+                                       }
+                                       i = 0;
+                               }
+                       }
+               }
+       }
+
+       *line_bytes = d; /* number of bytes read for scanline */
+       return TRUE;
+}
+
+static gpointer
+gdk_pixbuf__pcx_begin_load(GdkPixbufModuleSizeFunc size_func,
+                           GdkPixbufModulePreparedFunc prepared_func,
+                           GdkPixbufModuleUpdatedFunc updated_func,
+                           gpointer user_data, GError **error)
+{
+       struct pcx_context *context;
+
+       context = g_new0(struct pcx_context, 1);
+       if(!context)
+               return NULL;
+
+       context->header = g_try_malloc(sizeof(struct pcx_header));
+       if(!context->header) {
+               g_free(context);
+               g_set_error_literal(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't allocate memory for header"));
+               return NULL;
+       }
+
+       context->size_func = size_func;
+       context->updated_func = updated_func;
+       context->prepared_func = prepared_func;
+       context->user_data = user_data;
+
+       context->current_task = PCX_TASK_LOAD_HEADER;
+
+       context->buf = g_try_malloc(sizeof(guchar) * 512);
+       if(!context->buf) {
+               g_free(context->header);
+               g_free(context);
+               g_set_error_literal(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't allocate memory for context buffer"));
+               return NULL;
+       }
+       context->buf_size = 512;
+
+       context->header_loaded = FALSE;
+
+       return context;
+}
+
+static gboolean
+pcx_resize_context_buf(struct pcx_context *context, guint size)
+{
+       guchar *new_buf;
+
+       new_buf = g_try_realloc(context->buf, size);
+       if(!new_buf)
+               return FALSE;
+
+       context->buf = new_buf;
+       context->buf_size = size;
+       return TRUE;
+}
+
+/*
+ * remove a number of bytes (specified by size) from the
+ * beginning of a context's buf
+ */
+static gboolean
+pcx_chop_context_buf(struct pcx_context *context, guint size)
+{
+       guint i, j;
+
+       if (size > context->buf_pos)
+               return FALSE;
+       else if (size == 0)
+               return TRUE;
+
+       for (i = 0, j = size; j < context->buf_pos; i++, j++)
+               context->buf[i] = context->buf[j];
+
+       context->buf_pos -= size;
+
+       return TRUE;
+}
+
+static guchar
+read_pixel_1(guchar *data, guint offset)
+{
+       guchar retval;
+       guint bit_offset;
+
+       if(!(offset % 8)) {
+               offset /= 8;
+               retval = data[offset] >> 7;
+       } else {
+               bit_offset = offset % 8;
+               offset -= bit_offset;
+               offset /= 8;
+               retval = (data[offset] >> (7 - bit_offset)) & 0x1;
+       }
+
+       return retval;
+}
+
+static guchar
+read_pixel_4(guchar *data, guint offset)
+{
+       guchar retval;
+
+       if(!(offset % 2)) {
+               offset /= 2;
+               retval = data[offset] >> 4;
+       } else {
+               offset--;
+               offset /= 2;
+               retval = data[offset] & 0xf;
+       }
+
+       return retval;
+}
+
+static gboolean
+pcx_increment_load_data_1(struct pcx_context *context)
+{
+       guint i;
+       guchar *planes[4];
+       guint line_bytes;
+       guint store_planes;
+
+       if(context->num_planes == 4) {
+               planes[0] = context->line;
+               planes[1] = planes[0] + context->bytesperline;
+               planes[2] = planes[1] + context->bytesperline;
+               planes[3] = planes[2] + context->bytesperline;
+               store_planes = 4;
+       } else if(context->num_planes == 3) {
+               planes[0] = context->line;
+               planes[1] = planes[0] + context->bytesperline;
+               planes[2] = planes[1] + context->bytesperline;
+               store_planes = 3;
+       } else if(context->num_planes == 2) {
+               planes[0] = context->line;
+               planes[1] = planes[0] + context->bytesperline;
+               store_planes = 2;
+       } else if(context->num_planes == 1) {
+               planes[0] = context->line;
+               store_planes = 1;
+       } else {
+               return FALSE;
+       }
+
+       while(read_scanline_data(context->buf, context->buf_pos, planes, store_planes, context->num_planes, context->bytesperline, &line_bytes)) {
+               pcx_chop_context_buf(context, line_bytes);
+
+               for(i = 0; i < context->width; i++) {
+                       guchar p;
+
+                       if(context->num_planes == 4) {
+                               p = read_pixel_1(planes[3], i);
+                               p <<= 1;
+                               p |= read_pixel_1(planes[2], i);
+                               p <<= 1;
+                               p |= read_pixel_1(planes[1], i);
+                               p <<= 1;
+                               p |= read_pixel_1(planes[0], i);
+                       } else if(context->num_planes == 3) {
+                               p = read_pixel_1(planes[2], i);
+                               p <<= 1;
+                               p |= read_pixel_1(planes[1], i);
+                               p <<= 1;
+                               p |= read_pixel_1(planes[0], i);
+                       } else if(context->num_planes == 2) {
+                               p = read_pixel_1(planes[1], i);
+                               p <<= 1;
+                               p |= read_pixel_1(planes[0], i);
+                       } else if(context->num_planes == 1) {
+                               p = read_pixel_1(planes[0], i);
+                       } else {
+                               return FALSE;
+                       }
+                       p &= 0xf;
+                       context->data[context->current_line * context->rowstride + i * 3 + 0] = context->header->palette[p * 3 + 0];
+                       context->data[context->current_line * context->rowstride + i * 3 + 1] = context->header->palette[p * 3 + 1];
+                       context->data[context->current_line * context->rowstride + i * 3 + 2] = context->header->palette[p * 3 + 2];
+               }
+
+               if(context->updated_func)
+                       context->updated_func(context->pixbuf, 0, context->current_line, context->width, 1, context->user_data);
+
+               context->current_line++;
+
+               if(context->current_line == context->height) {
+                       context->current_task = PCX_TASK_DONE;
+                       return TRUE;
+               }
+       }
+
+       return TRUE;
+}
+
+static gboolean
+pcx_increment_load_data_2(struct pcx_context *context)
+{
+       guint i;
+       guchar *planes[1];
+       guint line_bytes;
+       guint shift, h;
+
+       planes[0] = context->line;
+
+       while(read_scanline_data(context->buf, context->buf_pos, planes, 1, context->num_planes, context->bytesperline, &line_bytes)) {
+               pcx_chop_context_buf(context, line_bytes);
+
+               for(i = 0; i < context->width; i++) {
+                       shift = 6 - 2 * (i % 4);
+                       h = (planes[0][i / 4] >> shift) & 0x3;
+                       context->data[context->current_line * context->rowstride + i * 3 + 0] = context->header->palette[h * 3 + 0];
+                       context->data[context->current_line * context->rowstride + i * 3 + 1] = context->header->palette[h * 3 + 1];
+                       context->data[context->current_line * context->rowstride + i * 3 + 2] = context->header->palette[h * 3 + 2];
+               }
+
+               if(context->updated_func)
+                       context->updated_func(context->pixbuf, 0, context->current_line, context->width, 1, context->user_data);
+
+               context->current_line++;
+
+               if(context->current_line == context->height) {
+                       context->current_task = PCX_TASK_DONE;
+                       return TRUE;
+               }
+       }
+
+       return TRUE;
+}
+
+static gboolean
+pcx_increment_load_data_4(struct pcx_context *context)
+{
+       guint i;
+       guchar *planes[1];
+       guint line_bytes;
+
+       planes[0] = context->line;
+
+       while(read_scanline_data(context->buf, context->buf_pos, planes, 1, context->num_planes, context->bytesperline, &line_bytes)) {
+               pcx_chop_context_buf(context, line_bytes);
+
+               for(i = 0; i < context->width; i++) {
+                       guchar p;
+
+                       p = read_pixel_4(planes[0], i) & 0xf;
+                       context->data[context->current_line * context->rowstride + i * 3 + 0] = context->header->palette[p * 3 + 0];
+                       context->data[context->current_line * context->rowstride + i * 3 + 1] = context->header->palette[p * 3 + 1];
+                       context->data[context->current_line * context->rowstride + i * 3 + 2] = context->header->palette[p * 3 + 2];
+               }
+
+               if(context->updated_func)
+                       context->updated_func(context->pixbuf, 0, context->current_line, context->width, 1, context->user_data);
+
+               context->current_line++;
+
+               if(context->current_line == context->height) {
+                       context->current_task = PCX_TASK_DONE;
+                       return TRUE;
+               }
+       }
+
+       return TRUE;
+}
+
+/*
+ * for loading 8-bit pcx images, we keep a buffer containing
+ * each pixel's palette number; once we've loaded each scanline,
+ * we wait for loading to stop and call pcx_load_palette_8,
+ * which finds the palette at the end of the pcx data and sets the
+ * RGB data.
+ */
+static gboolean
+pcx_increment_load_data_8(struct pcx_context *context)
+{
+       guint i;
+       guchar *planes[1];
+       guint line_bytes;
+
+       planes[0] = context->line;
+
+       while(read_scanline_data(context->buf, context->buf_pos, planes, 1, context->num_planes, context->bytesperline, &line_bytes)) {
+               pcx_chop_context_buf(context, line_bytes);
+
+               for(i = 0; i < context->width; i++)
+                       context->p_data[context->current_line * context->width + i + 0] = planes[0][i];
+
+               context->current_line++;
+
+               if(context->current_line == context->height) {
+                       context->current_task = PCX_TASK_LOAD_PALETTE;
+                       return TRUE;
+               }
+       }
+
+       return TRUE;
+}
+
+/*
+ * read the palette and set the RGB data
+ */
+static gboolean
+pcx_load_palette_8(struct pcx_context *context)
+{
+       guint i, j;
+
+       if(context->current_line < context->height)
+               return FALSE;
+
+       if(context->buf_pos >= 769) {
+               guchar *palette = context->buf + (context->buf_pos - 769);
+
+               if(palette[0] == 12) {
+                       palette++;
+                       for(i = 0; i < context->height; i++) {
+                               for(j = 0; j < context->width; j++) {
+                                       context->data[i * context->rowstride + j * 3 + 0] = palette[(context->p_data[i * context->width + j]) * 3 + 0];
+                                       context->data[i * context->rowstride + j * 3 + 1] = palette[(context->p_data[i * context->width + j]) * 3 + 1];
+                                       context->data[i * context->rowstride + j * 3 + 2] = palette[(context->p_data[i * context->width + j]) * 3 + 2];
+                               }
+
+                               if(context->updated_func)
+                                       context->updated_func(context->pixbuf, 0, i, context->width, 1, context->user_data);
+                       }
+
+#ifdef PCX_DEBUG
+                       g_print("read palette\n");
+#endif
+
+                       context->current_task = PCX_TASK_DONE;
+                       return TRUE;
+               } else {
+#ifdef PCX_DEBUG
+                       g_print("this ain't a palette\n");
+#endif
+                       return FALSE;
+               }
+       }
+
+       return FALSE;
+}
+
+/*
+ * in 24-bit images, each scanline has three color planes
+ * for red, green, and blue, respectively.
+ */
+static gboolean
+pcx_increment_load_data_24(struct pcx_context *context)
+{
+       guint i;
+       guchar *planes[3];
+       guint line_bytes;
+
+       planes[0] = context->line;
+       planes[1] = planes[0] + context->bytesperline;
+       planes[2] = planes[1] + context->bytesperline;
+
+       while(read_scanline_data(context->buf, context->buf_pos, planes, 3, context->num_planes, context->bytesperline, &line_bytes)) {
+               pcx_chop_context_buf(context, line_bytes);
+
+               for(i = 0; i < context->width; i++) {
+                       context->data[context->current_line * context->rowstride + i * 3 + 0] = planes[0][i];
+                       context->data[context->current_line * context->rowstride + i * 3 + 1] = planes[1][i];
+                       context->data[context->current_line * context->rowstride + i * 3 + 2] = planes[2][i];
+               }
+
+               if(context->updated_func)
+                       context->updated_func(context->pixbuf, 0, context->current_line, context->width, 1, context->user_data);
+
+               context->current_line++;
+
+               if(context->current_line == context->height) {
+                       context->current_task = PCX_TASK_DONE;
+                       return TRUE;
+               }
+       }
+
+       return TRUE;
+}
+
+static gboolean
+gdk_pixbuf__pcx_load_increment(gpointer data, const guchar *buf, guint size,
+                               GError **error)
+{
+       struct pcx_context *context = (struct pcx_context *)data;
+       struct pcx_header *header;
+       guint i;
+       gboolean retval = TRUE;
+
+       /* if context's buf isn't large enough to hold its current data plus the passed buf, increase its size */
+       if(context->buf_pos + size > context->buf_size) {
+               if(!pcx_resize_context_buf(context, sizeof(guchar) * (context->buf_pos + size))) {
+                       g_set_error_literal(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't allocate memory for context buffer"));
+                       return FALSE;
+               }
+       }
+
+       for(i = 0; i < size; i++)
+               context->buf[context->buf_pos++] = buf[i];
+
+       if(context->current_task == PCX_TASK_LOAD_HEADER) {
+               if(!context->header_loaded && context->buf_pos > sizeof(struct pcx_header)) { /* set header */
+                       gint width, height;
+
+                       memcpy(context->header, context->buf, sizeof(struct pcx_header));
+                       pcx_chop_context_buf(context, sizeof(struct pcx_header));
+                       header = context->header;
+
+                       /* convert the multi-byte header variables that will be used */
+                       header->xmin = GINT16_FROM_LE(header->xmin);
+                       header->ymin = GINT16_FROM_LE(header->ymin);
+                       header->xmax = GINT16_FROM_LE(header->xmax);
+                       header->ymax = GINT16_FROM_LE(header->ymax);
+                       header->bytesperline = GUINT16_FROM_LE(header->bytesperline);
+
+#ifdef PCX_DEBUG
+                       g_print ("Manufacturer %d\n"
+                                "Version %d\n"
+                                "Encoding %d\n"
+                                "Bits/Pixel %d\n"
+                                "Planes %d\n"
+                                "Palette %d\n", 
+                                header->manufacturer, header->version, 
+                                header->encoding, header->bitsperpixel,
+                                header->colorplanes, header->palettetype);
+#endif
+
+                       context->header_loaded = TRUE;
+                       fill_pcx_context(context);
+
+                       width = context->width;
+                       height = context->height;
+                       if(width <= 0 || height <= 0) {
+                               g_set_error_literal(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Image has invalid width and/or height"));
+                               return FALSE;
+                       }
+                       if (context->size_func)
+                         {
+                           (*context->size_func) (&width, &height, context->user_data);
+                           if (width == 0 || height == 0)
+                             return TRUE;
+                         }
+
+                       switch(context->bpp) {
+                               default:
+                                       g_set_error_literal(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_UNKNOWN_TYPE, _("Image has unsupported bpp"));
+                                       return FALSE;
+                                       break;
+                               case 1:
+                                       if(context->num_planes < 1 || context->num_planes > 4) {
+                                               g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_UNKNOWN_TYPE, _("Image has unsupported number of %d-bit planes"), 1);
+                                               return FALSE;
+                                       }
+                                       break;
+                               case 2:
+                               case 4:
+                               case 8:
+                                       if(context->num_planes != 1) {
+                                         g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_UNKNOWN_TYPE, _("Image has unsupported number of %d-bit planes"), (gint)context->bpp);
+                                               return FALSE;
+                                       }
+                                       break;
+                               case 24:
+                                       break; /* context's bpp is set to 24 if there are three 8-bit planes */
+                       }
+
+#ifdef PCX_DEBUG
+                       g_print("io-pcx: header loaded\n");
+                       g_print("bpp: %u\n", context->bpp);
+                       g_print("dimensions: %ux%u\n", context->width, context->height);
+#endif
+
+                       context->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, context->width, context->height);
+                       if(!context->pixbuf) {
+                               g_set_error_literal(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't create new pixbuf"));
+                               return FALSE;
+                       }
+                       context->data = gdk_pixbuf_get_pixels(context->pixbuf);
+                       context->rowstride = gdk_pixbuf_get_rowstride(context->pixbuf);
+
+                       context->line = g_try_malloc(sizeof(guchar) * context->bytesperline * context->num_planes);
+                       if(!context->line) {
+                               g_set_error_literal(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't allocate memory for line data"));
+                               return FALSE;
+                       }
+
+                       if(context->bpp == 8) {
+                               context->p_data = g_try_malloc(sizeof(guchar) * context->width * context->height);
+                               if(!context->p_data) {
+                                       g_set_error_literal(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't allocate memory for PCX image"));
+                                       return FALSE;
+                               }
+                       }
+
+                       if(context->prepared_func)
+                               context->prepared_func(context->pixbuf, NULL, context->user_data);
+
+                       context->current_task = PCX_TASK_LOAD_DATA;
+               }
+
+               retval = TRUE;
+       }
+
+       if(context->current_task == PCX_TASK_LOAD_DATA) {
+               switch(context->bpp) {
+                       default:
+                               g_set_error_literal(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_UNKNOWN_TYPE, _("Image has unsupported bpp"));
+                               retval = FALSE;
+                               break;
+                       case 1:
+                               retval = pcx_increment_load_data_1(context);
+                               break;
+                       case 2:
+                               retval = pcx_increment_load_data_2(context);
+                               break;
+                       case 4:
+                               retval = pcx_increment_load_data_4(context);
+                               break;
+                       case 8:
+                               retval = pcx_increment_load_data_8(context);
+                               break;
+                       case 24:
+                               retval = pcx_increment_load_data_24(context);
+                               break;
+               }
+       }
+
+       return retval;
+}
+
+static gboolean
+gdk_pixbuf__pcx_stop_load(gpointer data, GError **error)
+{
+       struct pcx_context *context = (struct pcx_context *)data;
+
+       if(context->current_line != context->height) {
+               g_set_error_literal(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, _("Didn't get all lines of PCX image"));
+               free_pcx_context(context, FALSE);
+               return FALSE;
+       }
+
+       if(context->current_task == PCX_TASK_LOAD_PALETTE) {
+               if(!pcx_load_palette_8(context)) {
+                       g_set_error_literal(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, _("No palette found at end of PCX data"));
+                       free_pcx_context(context, FALSE);
+                       return FALSE;
+               }
+       }
+
+       free_pcx_context(context, FALSE);
+
+       return TRUE;
+}
+
+#ifndef INCLUDE_pcx
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
+#else
+#define MODULE_ENTRY(function) void _gdk_pixbuf__pcx_ ## function
+#endif
+
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
+{
+       module->begin_load = gdk_pixbuf__pcx_begin_load;
+       module->stop_load = gdk_pixbuf__pcx_stop_load;
+       module->load_increment = gdk_pixbuf__pcx_load_increment;
+}
+
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
+{
+       static GdkPixbufModulePattern signature[] = {
+               { "\x0a \x01", NULL, 100 },
+               { "\x0a\x02\x01", NULL, 100 },
+               { "\x0a\x03\x01", NULL, 100 },
+               { "\x0a\x04\x01", NULL, 100 },
+               { "\x0a\x05\x01", NULL, 100 },
+               { NULL, NULL, 0 }
+       };
+       static gchar *mime_types[] = {
+               "image/x-pcx",
+               NULL,
+       };
+       static gchar *extensions[] = {
+               "pcx",
+               NULL,
+       };
+
+       info->name = "pcx";
+       info->signature = signature;
+       info->description = N_("The PCX image format");
+       info->mime_types = mime_types;
+       info->extensions = extensions;
+       info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
+       info->license = "LGPL";
+}
diff --git a/gdk-pixbuf/io-pixdata.c b/gdk-pixbuf/io-pixdata.c
new file mode 100644 (file)
index 0000000..08ae20b
--- /dev/null
@@ -0,0 +1,192 @@
+/* GdkPixdata loader
+ *
+ * Copyright (c) 2012 Alexander Larsson <alexl@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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 "gdk-pixbuf-private.h"
+#include "gdk-pixdata.h"
+
+G_MODULE_EXPORT void fill_vtable (GdkPixbufModule * module);
+G_MODULE_EXPORT void fill_info (GdkPixbufFormat * info);
+
+struct pixdata_context {
+  GdkPixbufModuleSizeFunc size_func;
+  GdkPixbufModuleUpdatedFunc updated_func;
+  GdkPixbufModulePreparedFunc prepared_func;
+  gpointer user_data;
+
+  GString *data;
+
+  GdkPixdata pixdata;
+  gboolean got_header;
+  gboolean got_pixbuf;
+};
+
+static void
+free_pixdata_context (struct pixdata_context *context)
+{
+  if (!context)
+    return;
+
+  g_free (context);
+}
+
+static gpointer
+pixdata_image_begin_load (GdkPixbufModuleSizeFunc size_func,
+                         GdkPixbufModulePreparedFunc prepared_func,
+                         GdkPixbufModuleUpdatedFunc updated_func,
+                         gpointer user_data, GError **error)
+{
+  struct pixdata_context *context;
+
+  context = g_new0 (struct pixdata_context, 1);
+  if (!context)
+    return NULL;
+
+  context->size_func = size_func;
+  context->updated_func = updated_func;
+  context->prepared_func = prepared_func;
+  context->user_data = user_data;
+
+  context->data = g_string_new ("");
+
+  return context;
+}
+
+static gboolean try_load (struct pixdata_context *context, GError **error)
+{
+  GdkPixbuf *pixbuf;
+
+  if (context->got_pixbuf)
+    return TRUE;
+
+  if (!gdk_pixdata_deserialize (&context->pixdata,
+                               context->data->len,
+                               (guchar *)context->data->str,
+                               error))
+    return FALSE;
+
+  pixbuf = gdk_pixbuf_from_pixdata (&context->pixdata,
+                                   TRUE, error);
+  if (pixbuf == NULL)
+    return FALSE;
+
+  context->got_pixbuf = TRUE;
+
+  if (context->prepared_func)
+    (* context->prepared_func) (pixbuf,
+                               NULL,
+                               context->user_data);
+  if (context->updated_func)
+    (* context->updated_func) (pixbuf, 0, 0, pixbuf->width, pixbuf->height, context->user_data);
+
+  return TRUE;
+}
+
+static gboolean
+pixdata_image_stop_load (gpointer data, GError **error)
+{
+  struct pixdata_context *context = (struct pixdata_context *) data;
+  gboolean res;
+
+  res = try_load (context, error);
+
+  g_string_free (context->data, TRUE);
+
+  free_pixdata_context (context);
+
+  return res;
+}
+
+static gboolean
+pixdata_image_load_increment (gpointer data, const guchar *buf, guint size, GError **error)
+{
+  struct pixdata_context *context = (struct pixdata_context *) data;
+
+  g_string_append_len (context->data, (char *)buf, size);
+
+  if (!context->got_header && context->data->len >= GDK_PIXDATA_HEADER_LENGTH)
+    {
+      /* This never reads past the header anyway, and we know we have at least
+        the header size, so we pass it a really large size to avoid any error reporting
+        due to missing data */
+      if (!gdk_pixdata_deserialize (&context->pixdata,
+                                   G_MAXUINT,
+                                   (guchar *)context->data->str,
+                                   error))
+       return FALSE;
+
+      context->got_header = TRUE;
+
+      if (context->size_func)
+       {
+         gint w = context->pixdata.width;
+         gint h = context->pixdata.height;
+         (* context->size_func) (&w, &h, context->user_data);
+
+         if (w == 0 || h == 0)
+           {
+             g_set_error_literal (error,
+                                  GDK_PIXBUF_ERROR,
+                                  GDK_PIXBUF_ERROR_FAILED,
+                                  _("Transformed pixbuf has zero width or height."));
+             return FALSE;
+           }
+       }
+    }
+
+  try_load (context, NULL);
+
+  return TRUE;
+}
+
+/* Always included */
+#define MODULE_ENTRY(function) void _gdk_pixbuf__pixdata_ ## function
+
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule * module)
+{
+       module->begin_load = pixdata_image_begin_load;
+       module->stop_load = pixdata_image_stop_load;
+       module->load_increment = pixdata_image_load_increment;
+}
+
+MODULE_ENTRY (fill_info) (GdkPixbufFormat * info)
+{
+       static GdkPixbufModulePattern signature[] = {
+               { "GdkP", NULL, 100 },          /* file begins with 'GdkP' at offset 0 */
+               { NULL, NULL, 0 }
+       };
+       static gchar *mime_types[] = {
+               "image/x-gdkpixdata",
+               NULL
+       };
+       static gchar *extensions[] = {
+               "gdkp",
+               NULL
+       };
+
+       info->name = "GdkPixdata";
+       info->signature = signature;
+       info->description = N_("The GdkPixdata format");
+       info->mime_types = mime_types;
+       info->extensions = extensions;
+       info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
+       info->license = "LGPL";
+       info->disabled = FALSE;
+}
diff --git a/gdk-pixbuf/io-png.c b/gdk-pixbuf/io-png.c
new file mode 100644 (file)
index 0000000..b2032c4
--- /dev/null
@@ -0,0 +1,1127 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* GdkPixbuf library - PNG image loader
+ *
+ * Copyright (C) 1999 Mark Crichton
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Authors: Mark Crichton <crichton@gimp.org>
+ *          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 Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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 <stdio.h>
+#include <stdlib.h>
+#include <png.h>
+#include "gdk-pixbuf-private.h"
+
+\f
+
+static gboolean
+setup_png_transformations(png_structp png_read_ptr, png_infop png_info_ptr,
+                          GError **error,
+                          png_uint_32* width_p, png_uint_32* height_p,
+                          int* color_type_p)
+{
+        png_uint_32 width, height;
+        int bit_depth, color_type, interlace_type, compression_type, filter_type;
+        int channels;
+        
+        /* Get the image info */
+
+        /* Must check bit depth, since png_get_IHDR generates an 
+           FPE on bit_depth 0.
+        */
+        bit_depth = png_get_bit_depth (png_read_ptr, png_info_ptr);
+        if (bit_depth < 1 || bit_depth > 16) {
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("Bits per channel of PNG image is invalid."));
+                return FALSE;
+        }
+        png_get_IHDR (png_read_ptr, png_info_ptr,
+                      &width, &height,
+                      &bit_depth,
+                      &color_type,
+                      &interlace_type,
+                      &compression_type,
+                      &filter_type);
+
+        /* set_expand() basically needs to be called unless
+           we are already in RGB/RGBA mode
+        */
+        if (color_type == PNG_COLOR_TYPE_PALETTE &&
+            bit_depth <= 8) {
+
+                /* Convert indexed images to RGB */
+                png_set_expand (png_read_ptr);
+
+        } else if (color_type == PNG_COLOR_TYPE_GRAY &&
+                   bit_depth < 8) {
+
+                /* Convert grayscale to RGB */
+                png_set_expand (png_read_ptr);
+
+        } else if (png_get_valid (png_read_ptr, 
+                                  png_info_ptr, PNG_INFO_tRNS)) {
+
+                /* If we have transparency header, convert it to alpha
+                   channel */
+                png_set_expand(png_read_ptr);
+                
+        } else if (bit_depth < 8) {
+
+                /* If we have < 8 scale it up to 8 */
+                png_set_expand(png_read_ptr);
+
+
+                /* Conceivably, png_set_packing() is a better idea;
+                 * God only knows how libpng works
+                 */
+        }
+
+        /* If we are 16-bit, convert to 8-bit */
+        if (bit_depth == 16) {
+                png_set_strip_16(png_read_ptr);
+        }
+
+        /* If gray scale, convert to RGB */
+        if (color_type == PNG_COLOR_TYPE_GRAY ||
+            color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
+                png_set_gray_to_rgb(png_read_ptr);
+        }
+        
+        /* If interlaced, handle that */
+        if (interlace_type != PNG_INTERLACE_NONE) {
+                png_set_interlace_handling(png_read_ptr);
+        }
+        
+        /* Update the info the reflect our transformations */
+        png_read_update_info(png_read_ptr, png_info_ptr);
+        
+        png_get_IHDR (png_read_ptr, png_info_ptr,
+                      &width, &height,
+                      &bit_depth,
+                      &color_type,
+                      &interlace_type,
+                      &compression_type,
+                      &filter_type);
+
+        *width_p = width;
+        *height_p = height;
+        *color_type_p = color_type;
+        
+        /* Check that the new info is what we want */
+        
+        if (width == 0 || height == 0) {
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("Transformed PNG has zero width or height."));
+                return FALSE;
+        }
+
+        if (bit_depth != 8) {
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("Bits per channel of transformed PNG is not 8."));
+                return FALSE;
+        }
+
+        if ( ! (color_type == PNG_COLOR_TYPE_RGB ||
+                color_type == PNG_COLOR_TYPE_RGB_ALPHA) ) {
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("Transformed PNG not RGB or RGBA."));
+                return FALSE;
+        }
+
+        channels = png_get_channels(png_read_ptr, png_info_ptr);
+        if ( ! (channels == 3 || channels == 4) ) {
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("Transformed PNG has unsupported number of channels, must be 3 or 4."));
+                return FALSE;
+        }
+        return TRUE;
+}
+
+static void
+png_simple_error_callback(png_structp png_save_ptr,
+                          png_const_charp error_msg)
+{
+        GError **error;
+        
+        error = png_get_error_ptr(png_save_ptr);
+
+        /* I don't trust libpng to call the error callback only once,
+         * so check for already-set error
+         */
+        if (error && *error == NULL) {
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_FAILED,
+                             _("Fatal error in PNG image file: %s"),
+                             error_msg);
+        }
+
+        longjmp (png_jmpbuf(png_save_ptr), 1);
+}
+
+static void
+png_simple_warning_callback(png_structp png_save_ptr,
+                            png_const_charp warning_msg)
+{
+        /* Don't print anything; we should not be dumping junk to
+         * stderr, since that may be bad for some apps. If it's
+         * important enough to display, we need to add a GError
+         * **warning return location wherever we have an error return
+         * location.
+         */
+}
+
+static gboolean
+png_text_to_pixbuf_option (png_text   text_ptr,
+                           gchar    **key,
+                           gchar    **value)
+{
+        gboolean is_ascii = TRUE;
+        int i;
+
+        /* Avoid loading iconv if the text is plain ASCII */
+        for (i = 0; i < text_ptr.text_length; i++)
+                if (text_ptr.text[i] & 0x80) {
+                        is_ascii = FALSE;
+                        break;
+                }
+
+        if (is_ascii) {
+                *value = g_strdup (text_ptr.text);
+        } else {
+                *value = g_convert (text_ptr.text, -1,
+                                     "UTF-8", "ISO-8859-1",
+                                     NULL, NULL, NULL);
+        }
+
+        if (*value) {
+                *key = g_strconcat ("tEXt::", text_ptr.key, NULL);
+                return TRUE;
+        } else {
+                g_warning ("Couldn't convert text chunk value to UTF-8.");
+                *key = NULL;
+                return FALSE;
+        }
+}
+
+static png_voidp
+png_malloc_callback (png_structp o, png_size_t size)
+{
+        return g_try_malloc (size);
+}
+
+static void
+png_free_callback (png_structp o, png_voidp x)
+{
+        g_free (x);
+}
+
+/* Shared library entry point */
+static GdkPixbuf *
+gdk_pixbuf__png_image_load (FILE *f, GError **error)
+{
+        GdkPixbuf * volatile pixbuf = NULL;
+       png_structp png_ptr;
+       png_infop info_ptr;
+        png_textp text_ptr;
+       gint i, ctype;
+       png_uint_32 w, h;
+       png_bytepp volatile rows = NULL;
+        gint    num_texts;
+        gchar *key;
+        gchar *value;
+        gchar *icc_profile_base64;
+        const gchar *icc_profile_title;
+        const gchar *icc_profile;
+        png_uint_32 icc_profile_size;
+        guint32 retval;
+        gint compression_type;
+
+#ifdef PNG_USER_MEM_SUPPORTED
+       png_ptr = png_create_read_struct_2 (PNG_LIBPNG_VER_STRING,
+                                            error,
+                                            png_simple_error_callback,
+                                            png_simple_warning_callback,
+                                            NULL, 
+                                            png_malloc_callback, 
+                                            png_free_callback);
+#else
+       png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,
+                                          error,
+                                          png_simple_error_callback,
+                                          png_simple_warning_callback);
+#endif
+       if (!png_ptr)
+               return NULL;
+
+       info_ptr = png_create_info_struct (png_ptr);
+       if (!info_ptr) {
+               png_destroy_read_struct (&png_ptr, NULL, NULL);
+               return NULL;
+       }
+
+       if (setjmp (png_jmpbuf(png_ptr))) {
+               g_free (rows);
+
+               if (pixbuf)
+                       g_object_unref (pixbuf);
+
+               png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
+               return NULL;
+       }
+
+       png_init_io (png_ptr, f);
+       png_read_info (png_ptr, info_ptr);
+
+        if (!setup_png_transformations(png_ptr, info_ptr, error, &w, &h, &ctype)) {
+                png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
+                return NULL;
+        }
+        
+        pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, ctype & PNG_COLOR_MASK_ALPHA, 8, w, h);
+
+       if (!pixbuf) {
+                if (error && *error == NULL) {
+                        g_set_error_literal (error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                             _("Insufficient memory to load PNG file"));
+                }
+                
+
+               png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
+               return NULL;
+       }
+
+       rows = g_new (png_bytep, h);
+
+       for (i = 0; i < h; i++)
+               rows[i] = pixbuf->pixels + i * pixbuf->rowstride;
+
+       png_read_image (png_ptr, rows);
+        png_read_end (png_ptr, info_ptr);
+
+        if (png_get_text (png_ptr, info_ptr, &text_ptr, &num_texts)) {
+                for (i = 0; i < num_texts; i++) {
+                        png_text_to_pixbuf_option (text_ptr[i], &key, &value);
+                        gdk_pixbuf_set_option (pixbuf, key, value);
+                        g_free (key);
+                        g_free (value);
+                }
+        }
+
+#if defined(PNG_cHRM_SUPPORTED)
+        /* Extract embedded ICC profile */
+        retval = png_get_iCCP (png_ptr, info_ptr,
+                               (png_charpp) &icc_profile_title, &compression_type,
+                               (png_charpp) &icc_profile, (png_uint_32*) &icc_profile_size);
+        if (retval != 0) {
+                icc_profile_base64 = g_base64_encode ((const guchar *) icc_profile, (gsize)icc_profile_size);
+                gdk_pixbuf_set_option (pixbuf, "icc-profile", icc_profile_base64);
+                g_free (icc_profile_base64);
+        }
+#endif
+
+       g_free (rows);
+       png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
+
+        return pixbuf;
+}
+
+/* I wish these avoided the setjmp()/longjmp() crap in libpng instead
+   just allow you to change the error reporting. */
+static void png_error_callback  (png_structp png_read_ptr,
+                                 png_const_charp error_msg);
+
+static void png_warning_callback (png_structp png_read_ptr,
+                                  png_const_charp warning_msg);
+
+/* Called at the start of the progressive load */
+static void png_info_callback   (png_structp png_read_ptr,
+                                 png_infop   png_info_ptr);
+
+/* Called for each row; note that you will get duplicate row numbers
+   for interlaced PNGs */
+static void png_row_callback   (png_structp png_read_ptr,
+                                png_bytep   new_row,
+                                png_uint_32 row_num,
+                                int pass_num);
+
+/* Called after reading the entire image */
+static void png_end_callback   (png_structp png_read_ptr,
+                                png_infop   png_info_ptr);
+
+typedef struct _LoadContext LoadContext;
+
+struct _LoadContext {
+        png_structp png_read_ptr;
+        png_infop   png_info_ptr;
+
+        GdkPixbufModuleSizeFunc size_func;
+        GdkPixbufModulePreparedFunc prepare_func;
+        GdkPixbufModuleUpdatedFunc update_func;
+        gpointer notify_user_data;
+
+        GdkPixbuf* pixbuf;
+
+        /* row number of first row seen, or -1 if none yet seen */
+
+        gint first_row_seen_in_chunk;
+
+        /* pass number for the first row seen */
+
+        gint first_pass_seen_in_chunk;
+        
+        /* row number of last row seen */
+        gint last_row_seen_in_chunk;
+
+        gint last_pass_seen_in_chunk;
+
+        /* highest row number seen */
+        gint max_row_seen_in_chunk;
+        
+        guint fatal_error_occurred : 1;
+
+        GError **error;
+};
+
+static gpointer
+gdk_pixbuf__png_image_begin_load (GdkPixbufModuleSizeFunc size_func,
+                                  GdkPixbufModulePreparedFunc prepare_func,
+                                 GdkPixbufModuleUpdatedFunc update_func,
+                                 gpointer user_data,
+                                  GError **error)
+{
+        LoadContext* lc;
+        
+        lc = g_new0(LoadContext, 1);
+        
+        lc->fatal_error_occurred = FALSE;
+
+        lc->size_func = size_func;
+        lc->prepare_func = prepare_func;
+        lc->update_func = update_func;
+        lc->notify_user_data = user_data;
+
+        lc->first_row_seen_in_chunk = -1;
+        lc->last_row_seen_in_chunk = -1;
+        lc->first_pass_seen_in_chunk = -1;
+        lc->last_pass_seen_in_chunk = -1;
+        lc->max_row_seen_in_chunk = -1;
+        lc->error = error;
+        
+        /* Create the main PNG context struct */
+
+#ifdef PNG_USER_MEM_SUPPORTED
+        lc->png_read_ptr = png_create_read_struct_2 (PNG_LIBPNG_VER_STRING,
+                                                     lc, /* error/warning callback data */
+                                                     png_error_callback,
+                                                     png_warning_callback,
+                                                     NULL,
+                                                     png_malloc_callback,
+                                                     png_free_callback);
+#else
+        lc->png_read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
+                                                  lc, /* error/warning callback data */
+                                                  png_error_callback,
+                                                  png_warning_callback);
+#endif
+        if (lc->png_read_ptr == NULL) {
+                g_free(lc);
+                /* error callback should have set the error */
+                return NULL;
+        }
+        
+       if (setjmp (png_jmpbuf(lc->png_read_ptr))) {
+               if (lc->png_info_ptr)
+                       png_destroy_read_struct(&lc->png_read_ptr, NULL, NULL);
+                g_free(lc);
+                /* error callback should have set the error */
+                return NULL;
+       }
+
+        /* Create the auxiliary context struct */
+
+        lc->png_info_ptr = png_create_info_struct(lc->png_read_ptr);
+
+        if (lc->png_info_ptr == NULL) {
+                png_destroy_read_struct(&lc->png_read_ptr, NULL, NULL);
+                g_free(lc);
+                /* error callback should have set the error */
+                return NULL;
+        }
+
+        png_set_progressive_read_fn(lc->png_read_ptr,
+                                    lc, /* callback data */
+                                    png_info_callback,
+                                    png_row_callback,
+                                    png_end_callback);
+        
+
+        /* We don't want to keep modifying error after returning here,
+         * it may no longer be valid.
+         */
+        lc->error = NULL;
+        
+        return lc;
+}
+
+static gboolean
+gdk_pixbuf__png_image_stop_load (gpointer context, GError **error)
+{
+        LoadContext* lc = context;
+
+        g_return_val_if_fail(lc != NULL, TRUE);
+
+        /* FIXME this thing needs to report errors if
+         * we have unused image data
+         */
+        
+        if (lc->pixbuf)
+                g_object_unref (lc->pixbuf);
+        
+        png_destroy_read_struct(&lc->png_read_ptr, &lc->png_info_ptr, NULL);
+        g_free(lc);
+
+        return TRUE;
+}
+
+static gboolean
+gdk_pixbuf__png_image_load_increment(gpointer context,
+                                     const guchar *buf, guint size,
+                                     GError **error)
+{
+        LoadContext* lc = context;
+
+        g_return_val_if_fail(lc != NULL, FALSE);
+
+        /* reset */
+        lc->first_row_seen_in_chunk = -1;
+        lc->last_row_seen_in_chunk = -1;
+        lc->first_pass_seen_in_chunk = -1;
+        lc->last_pass_seen_in_chunk = -1;
+        lc->max_row_seen_in_chunk = -1;
+        lc->error = error;
+        
+        /* Invokes our callbacks as needed */
+       if (setjmp (png_jmpbuf(lc->png_read_ptr))) {
+                lc->error = NULL;
+               return FALSE;
+       } else {
+               png_process_data(lc->png_read_ptr, lc->png_info_ptr,
+                                 (guchar*) buf, size);
+       }
+
+        if (lc->fatal_error_occurred) {
+                lc->error = NULL;
+                return FALSE;
+        } else {
+                if (lc->first_row_seen_in_chunk >= 0 && lc->update_func) {
+                        /* We saw at least one row */
+                        gint pass_diff = lc->last_pass_seen_in_chunk - lc->first_pass_seen_in_chunk;
+                        
+                        g_assert(pass_diff >= 0);
+                        
+                        if (pass_diff == 0) {
+                                /* start and end row were in the same pass */
+                                (lc->update_func)(lc->pixbuf, 0,
+                                                  lc->first_row_seen_in_chunk,
+                                                  lc->pixbuf->width,
+                                                  (lc->last_row_seen_in_chunk -
+                                                   lc->first_row_seen_in_chunk) + 1,
+                                                 lc->notify_user_data);
+                        } else if (pass_diff == 1) {
+                                /* We have from the first row seen to
+                                   the end of the image (max row
+                                   seen), then from the top of the
+                                   image to the last row seen */
+                                /* first row to end */
+                                (lc->update_func)(lc->pixbuf, 0,
+                                                  lc->first_row_seen_in_chunk,
+                                                  lc->pixbuf->width,
+                                                  (lc->max_row_seen_in_chunk -
+                                                   lc->first_row_seen_in_chunk) + 1,
+                                                 lc->notify_user_data);
+                                /* top to last row */
+                                (lc->update_func)(lc->pixbuf,
+                                                  0, 0, 
+                                                  lc->pixbuf->width,
+                                                  lc->last_row_seen_in_chunk + 1,
+                                                 lc->notify_user_data);
+                        } else {
+                                /* We made at least one entire pass, so update the
+                                   whole image */
+                                (lc->update_func)(lc->pixbuf,
+                                                  0, 0, 
+                                                  lc->pixbuf->width,
+                                                  lc->max_row_seen_in_chunk + 1,
+                                                 lc->notify_user_data);
+                        }
+                }
+
+                lc->error = NULL;
+                
+                return TRUE;
+        }
+}
+
+/* Called at the start of the progressive load, once we have image info */
+static void
+png_info_callback   (png_structp png_read_ptr,
+                     png_infop   png_info_ptr)
+{
+        LoadContext* lc;
+        png_uint_32 width, height;
+        png_textp png_text_ptr;
+        int i, num_texts;
+        int color_type;
+        gboolean have_alpha = FALSE;
+        gchar *icc_profile_base64;
+        const gchar *icc_profile_title;
+        const gchar *icc_profile;
+        png_uint_32 icc_profile_size;
+        guint32 retval;
+        gint compression_type;
+
+        lc = png_get_progressive_ptr(png_read_ptr);
+
+        if (lc->fatal_error_occurred)
+                return;
+
+        if (!setup_png_transformations(lc->png_read_ptr,
+                                       lc->png_info_ptr,
+                                       lc->error,
+                                       &width, &height, &color_type)) {
+                lc->fatal_error_occurred = TRUE;
+                return;
+        }
+
+        /* If we have alpha, set a flag */
+        if (color_type & PNG_COLOR_MASK_ALPHA)
+                have_alpha = TRUE;
+        
+        if (lc->size_func) {
+                gint w = width;
+                gint h = height;
+                (* lc->size_func) (&w, &h, lc->notify_user_data);
+                
+                if (w == 0 || h == 0) {
+                        lc->fatal_error_occurred = TRUE;
+                        if (lc->error && *lc->error == NULL) {
+                                g_set_error_literal (lc->error,
+                                                     GDK_PIXBUF_ERROR,
+                                                     GDK_PIXBUF_ERROR_FAILED,
+                                                     _("Transformed PNG has zero width or height."));
+                        }
+                        return;
+                }
+        }
+
+        lc->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, have_alpha, 8, width, height);
+
+        if (lc->pixbuf == NULL) {
+                /* Failed to allocate memory */
+                lc->fatal_error_occurred = TRUE;
+                if (lc->error && *lc->error == NULL) {
+                        g_set_error (lc->error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                     _("Insufficient memory to store a %ld by %ld image; try exiting some applications to reduce memory usage"),
+                                     width, height);
+                }
+                return;
+        }
+
+        /* Extract text chunks and attach them as pixbuf options */
+        
+        if (png_get_text (png_read_ptr, png_info_ptr, &png_text_ptr, &num_texts)) {
+                for (i = 0; i < num_texts; i++) {
+                        gchar *key, *value;
+
+                        if (png_text_to_pixbuf_option (png_text_ptr[i],
+                                                       &key, &value)) {
+                                gdk_pixbuf_set_option (lc->pixbuf, key, value);
+                                g_free (key);
+                                g_free (value);
+                        }
+                }
+        }
+
+#if defined(PNG_cHRM_SUPPORTED)
+        /* Extract embedded ICC profile */
+        retval = png_get_iCCP (png_read_ptr, png_info_ptr,
+                               (png_charpp) &icc_profile_title, &compression_type,
+                               (png_charpp) &icc_profile, &icc_profile_size);
+        if (retval != 0) {
+                icc_profile_base64 = g_base64_encode ((const guchar *) icc_profile, (gsize)icc_profile_size);
+                gdk_pixbuf_set_option (lc->pixbuf, "icc-profile", icc_profile_base64);
+                g_free (icc_profile_base64);
+        }
+#endif
+
+        /* Notify the client that we are ready to go */
+
+        if (lc->prepare_func)
+                (* lc->prepare_func) (lc->pixbuf, NULL, lc->notify_user_data);
+
+        return;
+}
+
+/* Called for each row; note that you will get duplicate row numbers
+   for interlaced PNGs */
+static void
+png_row_callback   (png_structp png_read_ptr,
+                    png_bytep   new_row,
+                    png_uint_32 row_num,
+                    int pass_num)
+{
+        LoadContext* lc;
+        guchar* old_row = NULL;
+
+        lc = png_get_progressive_ptr(png_read_ptr);
+
+        if (lc->fatal_error_occurred)
+                return;
+
+        if (row_num >= lc->pixbuf->height) {
+                lc->fatal_error_occurred = TRUE;
+                if (lc->error && *lc->error == NULL) {
+                        g_set_error_literal (lc->error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                             _("Fatal error reading PNG image file"));
+                }
+                return;
+        }
+
+        if (lc->first_row_seen_in_chunk < 0) {
+                lc->first_row_seen_in_chunk = row_num;
+                lc->first_pass_seen_in_chunk = pass_num;
+        }
+
+        lc->max_row_seen_in_chunk = MAX(lc->max_row_seen_in_chunk, ((gint)row_num));
+        lc->last_row_seen_in_chunk = row_num;
+        lc->last_pass_seen_in_chunk = pass_num;
+        
+        old_row = lc->pixbuf->pixels + (row_num * lc->pixbuf->rowstride);
+
+        png_progressive_combine_row(lc->png_read_ptr, old_row, new_row);
+}
+
+/* Called after reading the entire image */
+static void
+png_end_callback   (png_structp png_read_ptr,
+                    png_infop   png_info_ptr)
+{
+        LoadContext* lc;
+
+        lc = png_get_progressive_ptr(png_read_ptr);
+
+        if (lc->fatal_error_occurred)
+                return;
+}
+
+static void
+png_error_callback(png_structp png_read_ptr,
+                   png_const_charp error_msg)
+{
+        LoadContext* lc;
+        
+        lc = png_get_error_ptr(png_read_ptr);
+        
+        lc->fatal_error_occurred = TRUE;
+
+        /* I don't trust libpng to call the error callback only once,
+         * so check for already-set error
+         */
+        if (lc->error && *lc->error == NULL) {
+                g_set_error (lc->error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                             _("Fatal error reading PNG image file: %s"),
+                             error_msg);
+        }
+
+        longjmp (png_jmpbuf(png_read_ptr), 1);
+}
+
+static void
+png_warning_callback (png_structp png_read_ptr,
+                      png_const_charp warning_msg)
+{
+        LoadContext* lc;
+        
+        lc = png_get_error_ptr(png_read_ptr);
+
+        /* Don't print anything; we should not be dumping junk to
+         * stderr, since that may be bad for some apps. If it's
+         * important enough to display, we need to add a GError
+         * **warning return location wherever we have an error return
+         * location.
+         */
+}
+
+
+/* Save */
+
+typedef struct {
+        GdkPixbufSaveFunc save_func;
+        gpointer user_data;
+        GError **error;
+} SaveToFunctionIoPtr;
+
+static void
+png_save_to_callback_write_func (png_structp png_ptr,
+                                 png_bytep   data,
+                                 png_size_t  length)
+{
+        SaveToFunctionIoPtr *ioptr = png_get_io_ptr (png_ptr);
+
+        if (!ioptr->save_func ((gchar *)data, length, ioptr->error, ioptr->user_data)) {
+                /* If save_func has already set an error, which it
+                   should have done, this won't overwrite it. */
+                png_error (png_ptr, "write function failed");
+        }
+}
+
+static void
+png_save_to_callback_flush_func (png_structp png_ptr)
+{
+        ;
+}
+
+static gboolean real_save_png (GdkPixbuf        *pixbuf, 
+                               gchar           **keys,
+                               gchar           **values,
+                               GError          **error,
+                               gboolean          to_callback,
+                               FILE             *f,
+                               GdkPixbufSaveFunc save_func,
+                               gpointer          user_data)
+{
+       png_structp png_ptr = NULL;
+       png_infop info_ptr;
+       png_textp text_ptr = NULL;
+       guchar *ptr;
+       guchar *pixels;
+       int y;
+       int i;
+       png_bytep row_ptr;
+       png_color_8 sig_bit;
+       int w, h, rowstride;
+       int has_alpha;
+       int bpc;
+       int num_keys;
+       int compression = -1;
+       gboolean success = TRUE;
+       guchar *icc_profile = NULL;
+       gsize icc_profile_size = 0;
+       SaveToFunctionIoPtr to_callback_ioptr;
+
+       num_keys = 0;
+
+       if (keys && *keys) {
+               gchar **kiter = keys;
+               gchar **viter = values;
+
+               while (*kiter) {
+                       if (strncmp (*kiter, "tEXt::", 6) == 0) {
+                               gchar  *key = *kiter + 6;
+                               int     len = strlen (key);
+                               if (len <= 1 || len > 79) {
+                                       g_set_error_literal (error,
+                                                            GDK_PIXBUF_ERROR,
+                                                            GDK_PIXBUF_ERROR_BAD_OPTION,
+                                                            _("Keys for PNG text chunks must have at least 1 and at most 79 characters."));
+                                       success = FALSE;
+                                       goto cleanup;
+                               }
+                               for (i = 0; i < len; i++) {
+                                       if ((guchar) key[i] > 127) {
+                                               g_set_error_literal (error,
+                                                                    GDK_PIXBUF_ERROR,
+                                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
+                                                                    _("Keys for PNG text chunks must be ASCII characters."));
+                                               success = FALSE;
+                                               goto cleanup;
+                                       }
+                               }
+                               num_keys++;
+                       } else if (strcmp (*kiter, "icc-profile") == 0) {
+                               /* decode from base64 */
+                               icc_profile = g_base64_decode (*viter, &icc_profile_size);
+                               if (icc_profile_size < 127) {
+                                       /* This is a user-visible error */
+                                       g_set_error (error,
+                                                    GDK_PIXBUF_ERROR,
+                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
+                                                    _("Color profile has invalid length %d."),
+                                                    (gint)icc_profile_size);
+                                       success = FALSE;
+                                       goto cleanup;
+                               }
+                       } else if (strcmp (*kiter, "compression") == 0) {
+                               char *endptr = NULL;
+                               compression = strtol (*viter, &endptr, 10);
+
+                               if (endptr == *viter) {
+                                       g_set_error (error,
+                                                    GDK_PIXBUF_ERROR,
+                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
+                                                    _("PNG compression level must be a value between 0 and 9; value '%s' could not be parsed."),
+                                                    *viter);
+                                       success = FALSE;
+                                       goto cleanup;
+                               }
+                               if (compression < 0 || compression > 9) {
+                                       /* This is a user-visible error;
+                                        * lets people skip the range-checking
+                                        * in their app.
+                                        */
+                                       g_set_error (error,
+                                                    GDK_PIXBUF_ERROR,
+                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
+                                                    _("PNG compression level must be a value between 0 and 9; value '%d' is not allowed."),
+                                                    compression);
+                                       success = FALSE;
+                                       goto cleanup;
+                               }
+                       } else {
+                               g_warning ("Unrecognized parameter (%s) passed to PNG saver.", *kiter);
+                       }
+
+                       ++kiter;
+                       ++viter;
+               }
+       }
+
+       if (num_keys > 0) {
+               gchar **kiter = keys;
+               gchar **viter = values;
+
+               text_ptr = g_new0 (png_text, num_keys);
+               for (i = 0; i < num_keys; i++) {
+                       if (strncmp (*kiter, "tEXt::", 6) != 0) {
+                                kiter++;
+                                viter++;
+                       }
+
+                       text_ptr[i].compression = PNG_TEXT_COMPRESSION_NONE;
+                       text_ptr[i].key  = *kiter + 6;
+                       text_ptr[i].text = g_convert (*viter, -1, 
+                                                     "ISO-8859-1", "UTF-8", 
+                                                     NULL, &text_ptr[i].text_length, 
+                                                     NULL);
+
+#ifdef PNG_iTXt_SUPPORTED 
+                       if (!text_ptr[i].text) {
+                               text_ptr[i].compression = PNG_ITXT_COMPRESSION_NONE;
+                               text_ptr[i].text = g_strdup (*viter);
+                               text_ptr[i].text_length = 0;
+                               text_ptr[i].itxt_length = strlen (text_ptr[i].text);
+                               text_ptr[i].lang = NULL;
+                               text_ptr[i].lang_key = NULL;
+                       }
+#endif
+
+                       if (!text_ptr[i].text) {
+                               gint j;
+                               g_set_error (error,
+                                            GDK_PIXBUF_ERROR,
+                                            GDK_PIXBUF_ERROR_BAD_OPTION,
+                                            _("Value for PNG text chunk %s cannot be converted to ISO-8859-1 encoding."), *kiter + 6);
+                               for (j = 0; j < i; j++)
+                                       g_free (text_ptr[j].text);
+                               g_free (text_ptr);
+                               return FALSE;
+                       }
+
+                        kiter++;
+                        viter++;
+               }
+       }
+
+       bpc = gdk_pixbuf_get_bits_per_sample (pixbuf);
+       w = gdk_pixbuf_get_width (pixbuf);
+       h = gdk_pixbuf_get_height (pixbuf);
+       rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+       has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
+       pixels = gdk_pixbuf_get_pixels (pixbuf);
+
+       png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
+                                          error,
+                                          png_simple_error_callback,
+                                          png_simple_warning_callback);
+       if (png_ptr == NULL) {
+              success = FALSE;
+              goto cleanup;
+       }
+
+       info_ptr = png_create_info_struct (png_ptr);
+       if (info_ptr == NULL) {
+              success = FALSE;
+              goto cleanup;
+       }
+       if (setjmp (png_jmpbuf(png_ptr))) {
+              success = FALSE;
+              goto cleanup;
+       }
+
+       if (num_keys > 0) {
+               png_set_text (png_ptr, info_ptr, text_ptr, num_keys);
+       }
+
+       if (to_callback) {
+               to_callback_ioptr.save_func = save_func;
+               to_callback_ioptr.user_data = user_data;
+               to_callback_ioptr.error = error;
+               png_set_write_fn (png_ptr, &to_callback_ioptr,
+                                 png_save_to_callback_write_func,
+                                 png_save_to_callback_flush_func);
+       } else {
+               png_init_io (png_ptr, f);
+       }
+
+       if (compression >= 0)
+               png_set_compression_level (png_ptr, compression);
+
+#if defined(PNG_iCCP_SUPPORTED)
+        /* the proper ICC profile title is encoded in the profile */
+        if (icc_profile != NULL) {
+                png_set_iCCP (png_ptr, info_ptr,
+                              "ICC profile", PNG_COMPRESSION_TYPE_BASE,
+                              (gchar*) icc_profile, icc_profile_size);
+        }
+#endif
+
+       if (has_alpha) {
+               png_set_IHDR (png_ptr, info_ptr, w, h, bpc,
+                             PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
+                             PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+       } else {
+               png_set_IHDR (png_ptr, info_ptr, w, h, bpc,
+                             PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
+                             PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+       }
+       sig_bit.red = bpc;
+       sig_bit.green = bpc;
+       sig_bit.blue = bpc;
+       sig_bit.alpha = bpc;
+       png_set_sBIT (png_ptr, info_ptr, &sig_bit);
+       png_write_info (png_ptr, info_ptr);
+       png_set_shift (png_ptr, &sig_bit);
+       png_set_packing (png_ptr);
+
+       ptr = pixels;
+       for (y = 0; y < h; y++) {
+               row_ptr = (png_bytep)ptr;
+               png_write_rows (png_ptr, &row_ptr, 1);
+               ptr += rowstride;
+       }
+
+       png_write_end (png_ptr, info_ptr);
+
+cleanup:
+        if (png_ptr != NULL)
+                png_destroy_write_struct (&png_ptr, &info_ptr);
+
+        g_free (icc_profile);
+
+        if (text_ptr != NULL) {
+                for (i = 0; i < num_keys; i++)
+                        g_free (text_ptr[i].text);
+                g_free (text_ptr);
+        }
+
+       return success;
+}
+
+static gboolean
+gdk_pixbuf__png_image_save (FILE          *f, 
+                            GdkPixbuf     *pixbuf, 
+                            gchar        **keys,
+                            gchar        **values,
+                            GError       **error)
+{
+        return real_save_png (pixbuf, keys, values, error,
+                              FALSE, f, NULL, NULL);
+}
+
+static gboolean
+gdk_pixbuf__png_image_save_to_callback (GdkPixbufSaveFunc   save_func,
+                                        gpointer            user_data,
+                                        GdkPixbuf          *pixbuf, 
+                                        gchar             **keys,
+                                        gchar             **values,
+                                        GError            **error)
+{
+        return real_save_png (pixbuf, keys, values, error,
+                              TRUE, NULL, save_func, user_data);
+}
+
+#ifndef INCLUDE_png
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
+#else
+#define MODULE_ENTRY(function) void _gdk_pixbuf__png_ ## function
+#endif
+
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
+{
+        module->load = gdk_pixbuf__png_image_load;
+        module->begin_load = gdk_pixbuf__png_image_begin_load;
+        module->stop_load = gdk_pixbuf__png_image_stop_load;
+        module->load_increment = gdk_pixbuf__png_image_load_increment;
+        module->save = gdk_pixbuf__png_image_save;
+        module->save_to_callback = gdk_pixbuf__png_image_save_to_callback;
+}
+
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
+{
+        static GdkPixbufModulePattern signature[] = {
+                { "\x89PNG\r\n\x1a\x0a", NULL, 100 },
+                { NULL, NULL, 0 }
+        };
+       static gchar * mime_types[] = {
+               "image/png",
+               NULL
+       };
+       static gchar * extensions[] = {
+               "png",
+               NULL
+       };
+
+       info->name = "png";
+        info->signature = signature;
+       info->description = N_("The PNG image format");
+       info->mime_types = mime_types;
+       info->extensions = extensions;
+       info->flags = GDK_PIXBUF_FORMAT_WRITABLE | GDK_PIXBUF_FORMAT_THREADSAFE;
+       info->license = "LGPL";
+}
diff --git a/gdk-pixbuf/io-pnm.c b/gdk-pixbuf/io-pnm.c
new file mode 100644 (file)
index 0000000..b15aa91
--- /dev/null
@@ -0,0 +1,1084 @@
+/* -*- 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: 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 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <setjmp.h>
+#include "gdk-pixbuf-private.h"
+
+#define PNM_BUF_SIZE 4096
+
+#define PNM_FATAL_ERR  -1
+#define PNM_SUSPEND     0
+#define PNM_OK          1
+
+typedef enum {
+       PNM_FORMAT_PGM = 1,
+       PNM_FORMAT_PGM_RAW,
+       PNM_FORMAT_PPM,
+       PNM_FORMAT_PPM_RAW,
+       PNM_FORMAT_PBM,
+       PNM_FORMAT_PBM_RAW
+} PnmFormat;
+
+typedef struct {
+       guchar buffer[PNM_BUF_SIZE];
+       guchar *byte;
+       guint nbytes;
+} PnmIOBuffer;
+
+typedef struct {
+       GdkPixbufModuleUpdatedFunc updated_func;
+       GdkPixbufModulePreparedFunc prepared_func;
+       GdkPixbufModuleSizeFunc size_func;
+       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;
+
+       GError **error;
+       
+} PnmLoaderContext;
+
+static GdkPixbuf   *gdk_pixbuf__pnm_image_load          (FILE *f, GError **error);
+static gpointer    gdk_pixbuf__pnm_image_begin_load     (GdkPixbufModuleSizeFunc size_func, 
+                                                         GdkPixbufModulePreparedFunc func, 
+                                                        GdkPixbufModuleUpdatedFunc func2,
+                                                        gpointer user_data,
+                                                        GError **error);
+static gboolean    gdk_pixbuf__pnm_image_stop_load      (gpointer context, GError **error);
+static gboolean    gdk_pixbuf__pnm_image_load_increment (gpointer context,
+                                                        const guchar *buf, guint size,
+                                                        GError **error);
+
+static void explode_bitmap_into_buf              (PnmLoaderContext *context);
+static void explode_gray_into_buf                (PnmLoaderContext *context);
+
+
+/* explode bitmap data into rgb components         */
+/* we need to know what the row so we can          */
+/* do sub-byte expansion (since 1 byte = 8 pixels) */
+/* context->dptr MUST point at first byte in incoming data  */
+/* which corresponds to first pixel of row y       */
+static void
+explode_bitmap_into_buf (PnmLoaderContext *context)
+{
+       gint j;
+       guchar *from, *to, data;
+       gint bit;
+       guchar *dptr;
+       gint wid, x;
+       
+       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;
+       wid  = context->width;
+       
+       from = dptr + ((wid - 1) / 8);
+       to   = dptr + (wid - 1) * 3;
+       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 & 0x01) ? 0x00 : 0xff;
+               
+               to -= 3;
+               bit++;
+               
+               if (bit > 7 && x > 0) {
+                       from--;
+                       data = from[0];
+                       bit = 0;
+               } else {
+                       data >>= 1;
+               }
+       }
+       
+/*     g_print ("\n"); */
+}
+
+/* explode gray image row into rgb components in pixbuf */
+static void
+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.
+        */
+       w = context->width;
+       from = context->dptr + w - 1;
+       to = context->dptr + (w - 1) * 3;
+       for (j = w - 1; j >= 0; j--) {
+               to[0] = from[0];
+               to[1] = from[0];
+               to[2] = from[0];
+               to -= 3;
+               from--;
+       }
+}
+
+/* skip over whitespace and comments in input buffer */
+static gint
+pnm_skip_whitespace (PnmIOBuffer *inbuf, GError **error)
+{
+       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++)
+                               ;
+                       
+                       if ( inptr == inend || *inptr != '\n' ) {
+                               /* couldn't read whole comment */
+                               return PNM_SUSPEND;
+                       }
+                       
+               } else if (!g_ascii_isspace (*inptr)) {
+                       inbuf->byte = inptr;
+                       inbuf->nbytes = (guint) (inend - inptr);
+                       return PNM_OK;
+               }
+       }
+       
+       inbuf->byte = inptr;
+       inbuf->nbytes = (guint) (inend - inptr);
+       
+       return PNM_SUSPEND;
+}
+
+/* read next number from buffer */
+static gint
+pnm_read_next_value (PnmIOBuffer *inbuf, gint max_length, guint *value, GError **error)
+{
+       register guchar *inptr, *word, *p;
+       guchar *inend, buf[129];
+       gchar *endptr;
+       gint retval;
+       glong result;
+       
+       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);
+       
+       if (max_length < 0)
+               max_length = 128;
+
+       /* skip white space */
+       if ((retval = pnm_skip_whitespace (inbuf, error)) != 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) && !g_ascii_isspace (*p) && (*p != '#') && (p - inptr < max_length); p++, word++)
+               *word = *p;
+       *word = '\0';
+       
+       /* hmmm, there must be more data to this 'word' */
+       if (p == inend || (!g_ascii_isspace (*p) && (*p != '#')  && (p - inptr < max_length)))
+           return PNM_SUSPEND;
+       
+       /* get the value */
+       result = strtol ((gchar *)buf, &endptr, 10);
+       if (*endptr != '\0' || result < 0 || result > G_MAXUINT) {
+               g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("PNM loader expected to find an integer, but didn't"));
+               return PNM_FATAL_ERR;
+       }
+       *value = result;
+
+       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)
+{
+       PnmIOBuffer *inbuf;
+       gint retval;
+       
+       g_return_val_if_fail (context != NULL, PNM_FATAL_ERR);
+       
+       inbuf = &context->inbuf;
+       
+       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') {
+                       g_set_error_literal (context->error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                             _("PNM file has an incorrect initial byte"));
+                       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:
+                       g_set_error_literal (context->error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                             _("PNM file is not in a recognized PNM subformat"));
+                       return PNM_FATAL_ERR;
+               }
+               
+               if (!inbuf->nbytes)
+                       return PNM_SUSPEND;
+               
+               inbuf->byte++;
+               inbuf->nbytes--;
+       }
+       
+       if (!context->width) {
+               /* read the pixmap width */
+               guint width = 0;
+               
+               retval = pnm_read_next_value (inbuf, -1, &width,
+                                             context->error);
+               
+               if (retval != PNM_OK) 
+                       return retval;
+               
+               if (!width) {
+                       g_set_error_literal (context->error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                             _("PNM file has an image width of 0"));
+                       return PNM_FATAL_ERR;
+               }
+               
+               context->width = width;
+       }
+       
+       if (!context->height) {
+               /* read the pixmap height */
+               guint height = 0;
+               
+               retval = pnm_read_next_value (inbuf, -1, &height,
+                                             context->error);
+               
+               if (retval != PNM_OK)
+                       return retval;
+               
+               if (!height) {
+                       g_set_error_literal (context->error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                             _("PNM file has an image height of 0"));
+                       return PNM_FATAL_ERR;
+               }
+               
+               context->height = height;
+       }
+       
+       switch (context->type) {
+       case PNM_FORMAT_PPM:
+       case PNM_FORMAT_PPM_RAW:
+       case PNM_FORMAT_PGM:
+       case PNM_FORMAT_PGM_RAW:
+               if (!context->maxval) {
+                       retval = pnm_read_next_value (inbuf, -1, &context->maxval,
+                                                     context->error);
+                       
+                       if (retval != PNM_OK)
+                               return retval;
+                       
+                       if (context->maxval == 0) {
+                               g_set_error_literal (context->error,
+                                                     GDK_PIXBUF_ERROR,
+                                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                                     _("Maximum color value in PNM file is 0"));
+                               return PNM_FATAL_ERR;
+                       }
+
+                       if (context->maxval > 65535) {
+                               g_set_error_literal (context->error,
+                                                     GDK_PIXBUF_ERROR,
+                                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                                     _("Maximum color value in PNM file is too large"));
+                               return PNM_FATAL_ERR;
+                       }
+
+               }
+               break;
+       default:
+               break;
+       }
+       
+       return PNM_OK;
+}
+
+static gint
+pnm_read_raw_scanline (PnmLoaderContext *context)
+{
+       PnmIOBuffer *inbuf;
+       guint numbytes, offset;
+       guint numpix = 0;
+       guchar *dest;
+       guint i;
+       
+       g_return_val_if_fail (context != NULL, PNM_FATAL_ERR);
+       
+       inbuf = &context->inbuf;
+       
+       switch (context->type) {
+       case PNM_FORMAT_PBM_RAW:
+               numpix = inbuf->nbytes * 8;
+               break;
+       case PNM_FORMAT_PGM_RAW:
+               numpix = inbuf->nbytes;
+               break;
+       case PNM_FORMAT_PPM_RAW:
+               numpix = inbuf->nbytes / 3;
+               break;
+       default:
+               g_set_error_literal (context->error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("Raw PNM image type is invalid"));
+               return PNM_FATAL_ERR;
+       }
+       if(context->maxval>255) 
+               numpix/=2;
+       
+       numpix = MIN (numpix, context->width - context->output_col);
+       
+       if (!numpix)
+               return PNM_SUSPEND;
+       
+       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;
+               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;
+               break;
+       default:
+               g_set_error_literal (context->error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("Raw PNM image type is invalid"));
+               return PNM_FATAL_ERR;
+       }
+       if(context->maxval>255) 
+               numbytes*=2;                            
+       
+       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 if(context->maxval == 65535) {
+                       /* optimized version of the next case */
+                       for(i=0; i < numbytes ; i+=2) {
+                               *dest++=inbuf->byte[i];
+                       }
+               } else if(context->maxval > 255) {
+                       /* scale down to 256 colors */
+                       for(i=0; i < numbytes ; i+=2) {
+                               guint v=inbuf->byte[i]*256+inbuf->byte[i+1];
+                               *dest++=v*255/context->maxval;
+                       }
+               } 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_set_error_literal (context->error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("Raw PNM image type is invalid"));
+               return PNM_FATAL_ERR;
+       }
+       
+       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)
+                       explode_gray_into_buf (context);
+               
+               context->output_col = 0;
+               context->output_row++;
+       } else {
+               return PNM_SUSPEND;
+       }
+       
+       return PNM_OK;
+}
+
+static gint
+pnm_read_ascii_mono_scanline (PnmLoaderContext *context)
+{
+       PnmIOBuffer *inbuf;
+       guint value;
+       gint retval;
+       guchar *dptr;
+       gint max_length;
+
+       if (context->type == PNM_FORMAT_PBM)
+               max_length = 1;
+       else
+               max_length = -1;
+
+       inbuf = &context->inbuf;
+
+       context->dptr = context->pixels + context->output_row * context->rowstride;
+
+       dptr = context->dptr + context->output_col * 3;
+
+       while (TRUE) {
+               retval = pnm_read_next_value (inbuf, max_length, &value, context->error);
+               if (retval != PNM_OK)
+                       return retval;
+
+               if (context->type == PNM_FORMAT_PBM) {
+                       value = value ? 0 : 0xff;
+               }
+               else {
+                       /* scale the color up or down to an 8-bit color depth */
+                       if (value > context->maxval)
+                               value = 255;
+                       else
+                               value = (guchar)(255 * value / context->maxval);
+               }
+                       
+               *dptr++ = value;
+               *dptr++ = value;
+               *dptr++ = value;
+
+               context->output_col++;
+
+               if (context->output_col == context->width) {
+                       context->output_col = 0;
+                       context->output_row++;
+                       break;
+               }
+       }
+
+       return PNM_OK;
+}
+
+static gint
+pnm_read_ascii_color_scanline (PnmLoaderContext *context)
+{
+       PnmIOBuffer *inbuf;
+       guint value, i;
+       guchar *dptr;
+       gint retval;
+       
+       inbuf = &context->inbuf;
+       
+       context->dptr = context->pixels + context->output_row * context->rowstride;
+       
+       dptr = context->dptr + context->output_col * 3 + context->scan_state;
+       
+       while (TRUE) {
+               for (i = context->scan_state; i < 3; i++) {
+                       retval = pnm_read_next_value (inbuf, -1, &value, context->error);
+                       if (retval != PNM_OK) {
+                               /* save state and return */
+                               context->scan_state = i;
+                               return retval;
+                       }
+                       
+                       if (value > context->maxval)
+                               *dptr++ = 255;
+                       else
+                               *dptr++ = (guchar)(255 * value / context->maxval);
+               }
+               
+               context->scan_state = 0;
+               context->output_col++;
+               
+               if (context->output_col == context->width) {
+                       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 */
+static gint
+pnm_read_scanline (PnmLoaderContext *context)
+{
+       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:
+               retval = pnm_read_raw_scanline (context);
+               if (retval != PNM_OK)
+                       return retval;
+               break;
+       case PNM_FORMAT_PBM:
+       case PNM_FORMAT_PGM:
+               retval = pnm_read_ascii_mono_scanline (context);
+               if (retval != PNM_OK)
+                       return retval;
+               break;          
+       case PNM_FORMAT_PPM:
+               retval = pnm_read_ascii_color_scanline (context);
+               if (retval != PNM_OK)
+                       return retval;
+               break;
+       default:
+               g_set_error_literal (context->error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+                                     _("PNM image loader does not support this PNM subformat"));
+
+               return PNM_FATAL_ERR;
+       }
+       
+       return PNM_OK;
+}
+
+/* Shared library entry point */
+static GdkPixbuf *
+gdk_pixbuf__pnm_image_load (FILE *f, GError **error)
+{
+       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.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 = FALSE;
+       context.did_prescan = FALSE;
+       context.scan_state = 0;
+       context.error = error;
+       
+       inbuf = &context.inbuf;
+       
+       while (TRUE) {
+               guint num_to_read;
+               
+               /* keep buffer as full as possible */
+               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) {
+                       /* we ran out of data? */
+                       if (context.pixbuf)
+                               g_object_unref (context.pixbuf);
+                       g_set_error_literal (error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                             _("Premature end-of-file encountered"));
+                       return NULL;
+               }
+               
+               inbuf->nbytes += nbytes;
+               inbuf->byte = inbuf->buffer;
+               
+               /* get header if needed */
+               if (!context.got_header) {
+                       retval = pnm_read_header (&context);
+                       if (retval == PNM_FATAL_ERR)
+                               return NULL;
+                       else if (retval == PNM_SUSPEND)
+                               continue;
+                       
+                       context.got_header = TRUE;
+               }
+               
+               /* scan until we hit image data */
+               if (!context.did_prescan) {
+                       switch (context.type) {
+                       case PNM_FORMAT_PBM_RAW:
+                       case PNM_FORMAT_PGM_RAW:
+                       case PNM_FORMAT_PPM_RAW:
+                               if (inbuf->nbytes <= 0)
+                                       continue;
+                               /* raw formats require exactly one whitespace */
+                               if (!g_ascii_isspace(*(inbuf->byte))) 
+                                       {
+                                               g_set_error_literal (error,
+                                                                     GDK_PIXBUF_ERROR,
+                                                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                                                     _("Raw PNM formats require exactly one whitespace before sample data"));
+                                               return NULL;
+                                       }
+                               inbuf->nbytes--;
+                               inbuf->byte++;
+                               break;
+                       default:
+                               retval = pnm_skip_whitespace (inbuf,
+                                                             context.error);
+                               if (retval == PNM_FATAL_ERR)
+                                       return NULL;
+                               else if (retval == PNM_SUSPEND)
+                                       continue;
+                               break;
+                       }
+                       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);
+                       
+                       if (!context.pixbuf) {
+                               /* Failed to allocate memory */
+                               g_set_error_literal (error,
+                                                     GDK_PIXBUF_ERROR,
+                                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                                     _("Cannot allocate memory for loading PNM image"));
+                               return NULL;
+                       }
+
+                       context.rowstride = context.pixbuf->rowstride;
+                       context.pixels = context.pixbuf->pixels;
+               }
+               
+               /* if we got here we're reading image data */
+               while (context.output_row < context.height) {
+                       retval = pnm_read_scanline (&context);
+                       
+                       if (retval == PNM_SUSPEND) {
+                               break;
+                       } else if (retval == PNM_FATAL_ERR) {
+                               if (context.pixbuf)
+                                       g_object_unref (context.pixbuf);
+
+                               return NULL;
+                       }
+               }
+               
+               if (context.output_row < context.height)
+                       continue;
+               else
+                       break;
+       }
+       
+       return context.pixbuf;
+}
+
+/* 
+ * func - called when we have pixmap created (but no image data)
+ * user_data - passed as arg 1 to func
+ * return context (opaque to user)
+ */
+
+static gpointer
+gdk_pixbuf__pnm_image_begin_load (GdkPixbufModuleSizeFunc size_func, 
+                                  GdkPixbufModulePreparedFunc prepared_func, 
+                                 GdkPixbufModuleUpdatedFunc  updated_func,
+                                 gpointer user_data,
+                                 GError **error)
+{
+       PnmLoaderContext *context;
+       
+       context = g_try_malloc (sizeof (PnmLoaderContext));
+       if (!context) {
+               g_set_error_literal (error, GDK_PIXBUF_ERROR, 
+                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                     _("Insufficient memory to load PNM context struct"));
+               return NULL;
+       }
+       memset (context, 0, sizeof (PnmLoaderContext));
+       context->size_func = size_func;
+       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->scan_state = 0;
+       
+       context->inbuf.nbytes = 0;
+       context->inbuf.byte  = NULL;
+
+       context->error = error;
+       
+       return (gpointer) context;
+}
+
+/*
+ * context - returned from image_begin_load
+ *
+ * free context, unref gdk_pixbuf
+ */
+static gboolean
+gdk_pixbuf__pnm_image_stop_load (gpointer data,
+                                GError **error)
+{
+       PnmLoaderContext *context = (PnmLoaderContext *) data;
+       gboolean retval = TRUE;
+       
+       g_return_val_if_fail (context != NULL, TRUE);
+       
+       if (context->pixbuf)
+               g_object_unref (context->pixbuf);
+
+#if 0
+       /* We should ignore trailing newlines and we can't
+          generally complain about trailing stuff at all, since 
+          pnm allows to put multiple images in a file
+       */
+       if (context->inbuf.nbytes > 0) {
+               g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("Unexpected end of PNM image data"));
+               retval = FALSE;
+       }
+#endif
+       
+       g_free (context);
+
+       return retval;
+}
+
+/*
+ * context - from image_begin_load
+ * buf - new image data
+ * size - length of new image data
+ *
+ * append image data onto inrecrementally built output image
+ */
+static gboolean
+gdk_pixbuf__pnm_image_load_increment (gpointer data,
+                                     const guchar *buf, guint size,
+                                     GError **error)
+{
+       PnmLoaderContext *context = (PnmLoaderContext *)data;
+       PnmIOBuffer *inbuf;
+       const guchar *bufhd;
+       guint num_left, spinguard;
+       gint retval;
+       
+       g_return_val_if_fail (context != NULL, FALSE);
+       g_return_val_if_fail (buf != NULL, FALSE);
+
+       context->error = error;
+       
+       bufhd = buf;
+       inbuf = &context->inbuf;
+       
+       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->nbytes, num_left);
+               
+               if (num_to_copy == 0)
+                       spinguard++;
+               
+               if (spinguard > 1)
+                       return TRUE;
+               
+               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->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->nbytes == 0)
+                       return TRUE;
+               
+               /* get header if needed */
+               if (!context->got_header) {
+                       retval = pnm_read_header (context);
+                       
+                       if (retval == PNM_FATAL_ERR)
+                               return FALSE;
+                       else if (retval == PNM_SUSPEND)
+                               continue;
+                       
+                       context->got_header = TRUE;
+               }
+
+               if (context->size_func) {
+                       gint w = context->width;
+                       gint h = context->height;
+                       (*context->size_func) (&w, &h, context->user_data);
+                       
+                       if (w == 0 || h == 0) 
+                               return FALSE;
+               }
+               
+               
+               /* scan until we hit image data */
+               if (!context->did_prescan) {
+                       switch (context->type) {
+                       case PNM_FORMAT_PBM_RAW:
+                       case PNM_FORMAT_PGM_RAW:
+                       case PNM_FORMAT_PPM_RAW:
+                               if (inbuf->nbytes <= 0)
+                                       continue;
+                               /* raw formats require exactly one whitespace */
+                               if (!g_ascii_isspace(*(inbuf->byte)))
+                                       {
+                                               g_set_error_literal (error,
+                                                                     GDK_PIXBUF_ERROR,
+                                                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                                                     _("Raw PNM formats require exactly one whitespace before sample data"));
+                                               return FALSE;
+                                       }
+                               inbuf->nbytes--;
+                               inbuf->byte++;
+                               break;
+                       default:
+                               retval = pnm_skip_whitespace (inbuf,
+                                                             context->error);
+                               if (retval == PNM_FATAL_ERR)
+                                       return FALSE;
+                               else if (retval == PNM_SUSPEND)
+                                       continue;
+                               break;
+                       }
+                       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);
+                       
+                       if (context->pixbuf == NULL) {
+                               g_set_error_literal (error,
+                                                     GDK_PIXBUF_ERROR,
+                                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                                     _("Insufficient memory to load PNM file"));
+                               return FALSE;
+                       }
+                       
+                       context->pixels = context->pixbuf->pixels;
+                       context->rowstride = context->pixbuf->rowstride;
+                       
+                       /* Notify the client that we are ready to go */
+                       if (context->prepared_func)
+                               (* context->prepared_func) (context->pixbuf,
+                                                           NULL,
+                                                           context->user_data);
+               }
+               
+               /* if we got here we're reading image data */
+               while (context->output_row < context->height) {
+                       retval = pnm_read_scanline (context);
+                       
+                       if (retval == PNM_SUSPEND) {
+                               break;
+                       } else if (retval == PNM_FATAL_ERR) {
+                               return FALSE;
+                       } else if (retval == PNM_OK && context->updated_func) { 
+                               /* send updated signal */
+                               (* context->updated_func) (context->pixbuf,
+                                                          0, 
+                                                          context->output_row-1,
+                                                          context->width, 
+                                                          1,
+                                                          context->user_data);
+                       }
+               }
+               
+               if (context->output_row < context->height)
+                       continue;
+               else
+                       break;
+       }
+       
+       return TRUE;
+}
+
+#ifndef INCLUDE_pnm
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
+#else
+#define MODULE_ENTRY(function) void _gdk_pixbuf__pnm_ ## function
+#endif
+
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
+{
+       module->load = gdk_pixbuf__pnm_image_load;
+       module->begin_load = gdk_pixbuf__pnm_image_begin_load;
+       module->stop_load = gdk_pixbuf__pnm_image_stop_load;
+       module->load_increment = gdk_pixbuf__pnm_image_load_increment;
+}
+
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
+{
+       static GdkPixbufModulePattern signature[] = {
+               { "P1", NULL, 100 },
+               { "P2", NULL, 100 },
+               { "P3", NULL, 100 },
+               { "P4", NULL, 100 },
+               { "P5", NULL, 100 },
+               { "P6", NULL, 100 },
+               { NULL, NULL, 0 }
+       };
+       static gchar * mime_types[] = {
+               "image/x-portable-anymap",
+               "image/x-portable-bitmap",
+               "image/x-portable-graymap",
+               "image/x-portable-pixmap",
+               NULL
+       };
+       static gchar * extensions[] = {
+               "pnm",
+               "pbm",
+               "pgm",
+               "ppm",
+               NULL
+       };
+
+       info->name = "pnm";
+       info->signature = signature;
+       info->description = N_("The PNM/PBM/PGM/PPM image format family");
+       info->mime_types = mime_types;
+       info->extensions = extensions;
+       info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
+       info->license = "LGPL";
+}
diff --git a/gdk-pixbuf/io-qtif.c b/gdk-pixbuf/io-qtif.c
new file mode 100644 (file)
index 0000000..ee4ffd0
--- /dev/null
@@ -0,0 +1,624 @@
+/* -*- mode: C; c-file-style: "linux" -*- */
+/* GdkPixbuf library - QTIF image loader
+ *
+ * This module extracts image data from QTIF format and uses
+ * other GDK pixbuf modules to decode the image data.
+ *
+ * Copyright (C) 2008 Kevin Peng
+ *
+ * Authors: Kevin Peng <kevin@zycomtech.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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 <errno.h>
+#include <libintl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <setjmp.h>
+#include "gdk-pixbuf.h"
+#include "gdk-pixbuf-private.h"
+
+/***
+ * Definitions
+ */
+/* Read buffer size */
+#define READ_BUFFER_SIZE    8192
+
+/* Only allow atom of size up to 10MB. */
+#define ATOM_SIZE_MAX       100000000
+
+/* Aborts after going to through this many atoms. */
+#define QTIF_ATOM_COUNT_MAX 10u
+
+/* QTIF static image data tag "idat". */
+#define QTIF_TAG_IDATA      0x69646174u
+
+
+/***
+ * Types
+ */
+/* QTIF State */
+typedef enum {
+    STATE_READY,
+    STATE_DATA,
+    STATE_OTHER
+} QTIFState;
+
+/* QTIF Atom Header */
+typedef struct {
+    guint32 length;
+    guint32 tag;
+} QtHeader;
+
+/* QTIF loader context */
+typedef struct {
+    GdkPixbufLoader *loader;
+    gpointer        user_data;
+    QTIFState       state;
+    guint32         run_length;
+    gint            atom_count;
+
+    guchar          header_buffer[sizeof(QtHeader)];
+
+    GdkPixbufModuleSizeFunc     size_func;
+    GdkPixbufModulePreparedFunc prepare_func;
+    GdkPixbufModuleUpdatedFunc  update_func;
+    gint            cb_prepare_count;
+    gint            cb_update_count;
+} QTIFContext;
+
+/***
+ * Local function prototypes
+ */
+static GdkPixbuf *gdk_pixbuf__qtif_image_load (FILE *f, GError **error);
+static gpointer gdk_pixbuf__qtif_image_begin_load (GdkPixbufModuleSizeFunc size_func,
+                                                   GdkPixbufModulePreparedFunc prepare_func,
+                                                   GdkPixbufModuleUpdatedFunc update_func,
+                                                   gpointer user_data,
+                                                   GError **error);
+static gboolean gdk_pixbuf__qtif_image_stop_load (gpointer context, GError **error);
+static gboolean gdk_pixbuf__qtif_image_load_increment(gpointer context,
+                                                      const guchar *buf, guint size,
+                                                      GError **error);
+static gboolean gdk_pixbuf__qtif_image_create_loader (QTIFContext *context, GError **error);
+static gboolean gdk_pixbuf__qtif_image_free_loader (QTIFContext *context, GError **error);
+
+static void gdk_pixbuf__qtif_cb_size_prepared(GdkPixbufLoader *loader,
+                                              gint width,
+                                              gint height,
+                                              gpointer user_data);
+static void gdk_pixbuf__qtif_cb_area_prepared(GdkPixbufLoader *loader, gpointer user_data);
+static void gdk_pixbuf__qtif_cb_area_updated(GdkPixbufLoader *loader,
+                                             gint x,
+                                             gint y,
+                                             gint width,
+                                             gint height,
+                                             gpointer user_data);
+
+/***
+ * Function definitions.
+ */
+
+/* Load QTIF from a file handler. */
+static GdkPixbuf *gdk_pixbuf__qtif_image_load (FILE *f, GError **error)
+{
+    guint count;
+
+    if(f == NULL)
+    {
+        g_set_error_literal (error, GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_BAD_OPTION,
+                             _("Input file descriptor is NULL."));
+        return NULL;
+    }
+
+    for(count = QTIF_ATOM_COUNT_MAX; count != 0u; count--)
+    {
+        QtHeader hdr;
+        size_t rd;
+
+        /* Read QtHeader. */
+        rd = fread(&hdr, 1, sizeof(QtHeader), f);
+        if(rd != sizeof(QtHeader))
+        {
+            g_set_error_literal(error, GDK_PIXBUF_ERROR,
+                                GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                _("Failed to read QTIF header"));
+            return NULL;
+        }
+
+        hdr.length = GUINT32_FROM_BE(hdr.length) - sizeof(QtHeader);
+        if(hdr.length > ATOM_SIZE_MAX)
+        {
+            g_set_error(error, GDK_PIXBUF_ERROR,
+                        GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                        ngettext (  "QTIF atom size too large (%d byte)",
+                                    "QTIF atom size too large (%d bytes)",
+                                    hdr.length),
+                        hdr.length);
+            return NULL;
+        }
+
+        switch(GUINT32_FROM_BE(hdr.tag))
+        {
+        case QTIF_TAG_IDATA: /* "idat" data atom. */
+            {
+                /* Load image using GdkPixbufLoader. */
+                guchar *buf;
+                GdkPixbufLoader *loader;
+                GdkPixbuf *pixbuf = NULL;
+                GError *tmp = NULL;
+
+                /* Allocate read buffer. */
+                buf = g_try_malloc(READ_BUFFER_SIZE);
+                if(buf == NULL)
+                {
+                    g_set_error(error, GDK_PIXBUF_ERROR,
+                                GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                ngettext ( "Failed to allocate %d byte for file read buffer",
+                                           "Failed to allocate %d bytes for file read buffer",
+                                           READ_BUFFER_SIZE
+                                ),
+                                READ_BUFFER_SIZE);
+                    return NULL;
+                }
+
+                /* Create GdkPixbufLoader. */
+                loader = gdk_pixbuf_loader_new();
+                if(loader == NULL)
+                {
+                    g_set_error(error, GDK_PIXBUF_ERROR,
+                                GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                ngettext (  "QTIF atom size too large (%d byte)",
+                                            "QTIF atom size too large (%d bytes)",
+                                            hdr.length),
+                                hdr.length);
+                    goto clean_up;
+                }
+
+                /* Read atom data. */
+                while(hdr.length != 0u)
+                {
+                    rd = (hdr.length > READ_BUFFER_SIZE) ? READ_BUFFER_SIZE : hdr.length;
+
+                    rd = fread(buf, 1, rd, f);
+                    if(rd < 0)
+                    {
+                        g_set_error(error, GDK_PIXBUF_ERROR,
+                                    GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                    _("File error when reading QTIF atom: %s"), g_strerror(errno));
+                        break;
+                    }
+
+                    if(!gdk_pixbuf_loader_write(loader, buf, rd, &tmp))
+                    {
+                        g_propagate_error (error, tmp);
+                        break;
+                    }
+                    hdr.length -= rd;
+                }
+
+clean_up:
+                /* Release loader */
+                if(loader != NULL)
+                {
+                    gdk_pixbuf_loader_close(loader, NULL);
+                    pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
+                    if(pixbuf != NULL)
+                    {
+                        g_object_ref(pixbuf);
+                    }
+                    g_object_unref(loader);
+                }
+                if(buf != NULL)
+                {
+                    g_free(buf);
+                }
+                return pixbuf;
+            }
+
+        default:
+            /* Skip any other types of atom. */
+            if(!fseek(f, hdr.length, SEEK_CUR))
+            {
+                g_set_error(error, GDK_PIXBUF_ERROR,
+                            GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                            ngettext (  "Failed to skip the next %d byte with seek().",
+                                        "Failed to skip the next %d bytes with seek().",
+                                        hdr.length),
+                            hdr.length);
+                return NULL;
+            }
+            break;
+        }
+    }
+    return NULL;
+}
+
+/* Incremental load begin. */
+static gpointer gdk_pixbuf__qtif_image_begin_load (GdkPixbufModuleSizeFunc size_func,
+                                                   GdkPixbufModulePreparedFunc prepare_func,
+                                                   GdkPixbufModuleUpdatedFunc update_func,
+                                                   gpointer user_data,
+                                                   GError **error)
+{
+    QTIFContext *context;
+
+    /* Create context struct. */
+    context = g_new0(QTIFContext, 1);
+    if(context == NULL)
+    {
+        g_set_error_literal (error, GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                             _("Failed to allocate QTIF context structure."));
+        return NULL;
+    }
+
+    /* Fill context parameters. */
+    context->loader = NULL;
+    context->user_data = user_data;
+    context->state = STATE_READY;
+    context->run_length = 0u;
+    context->atom_count = QTIF_ATOM_COUNT_MAX;
+    context->size_func = size_func;
+    context->prepare_func = prepare_func;
+    context->update_func = update_func;
+
+    return context;
+}
+
+/* Incremental load clean up. */
+static gboolean gdk_pixbuf__qtif_image_stop_load (gpointer data, GError **error)
+{
+    QTIFContext *context = (QTIFContext *)data;
+    gboolean ret = TRUE;
+
+    if(context->loader != NULL)
+    {
+        GError *tmp = NULL;
+
+        ret = gdk_pixbuf__qtif_image_free_loader(context, &tmp);
+        if(!ret)
+        {
+            g_propagate_error (error, tmp);
+        }
+    }
+    g_free(context);
+
+    return ret;
+}
+
+/* Create a new GdkPixbufLoader and connect to its signals. */
+static gboolean gdk_pixbuf__qtif_image_create_loader (QTIFContext *context, GError **error)
+{
+    GError *tmp = NULL;
+
+    if(context == NULL)
+    {
+        return FALSE;
+    }
+
+    /* Free existing loader. */
+    if(context->loader != NULL)
+    {
+        gdk_pixbuf__qtif_image_free_loader(context, &tmp);
+    }
+
+    /* Create GdkPixbufLoader object. */
+    context->loader = gdk_pixbuf_loader_new();
+    if(context->loader == NULL)
+    {
+        g_set_error_literal (error, GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_FAILED,
+                             _("Failed to create GdkPixbufLoader object."));
+        return FALSE;
+    }
+
+    /* Connect signals. */
+    context->cb_prepare_count = 0;
+    context->cb_update_count = 0;
+    if(context->size_func != NULL)
+    {
+        g_signal_connect(context->loader, "size-prepared",
+                         G_CALLBACK(gdk_pixbuf__qtif_cb_size_prepared),
+                         context);
+    }
+    if(context->prepare_func != NULL)
+    {
+        g_signal_connect(context->loader, "area-prepared",
+                         G_CALLBACK(gdk_pixbuf__qtif_cb_area_prepared),
+                         context);
+    }
+    if(context->update_func != NULL)
+    {
+        g_signal_connect(context->loader, "area-updated",
+                         G_CALLBACK(gdk_pixbuf__qtif_cb_area_updated),
+                         context);
+    }
+    return TRUE;
+}
+
+/* Free the GdkPixbufLoader and perform callback if haven't done so. */
+static gboolean gdk_pixbuf__qtif_image_free_loader (QTIFContext *context, GError **error)
+{
+    GdkPixbuf *pixbuf;
+    GError *tmp = NULL;
+    gboolean ret;
+
+    if((context == NULL) || (context->loader == NULL))
+    {
+        return FALSE;
+    }
+
+    /* Close GdkPixbufLoader. */
+    ret = gdk_pixbuf_loader_close(context->loader, &tmp);
+    if(!ret)
+    {
+        g_propagate_error (error, tmp);
+    }
+
+
+    /* Get GdkPixbuf from GdkPixbufLoader. */
+    pixbuf = gdk_pixbuf_loader_get_pixbuf(context->loader);
+    if(pixbuf != NULL)
+    {
+        g_object_ref(pixbuf);
+    }
+
+    /* Free GdkPixbufLoader. */
+    g_object_ref(context->loader);
+    context->loader = NULL;
+
+    if(pixbuf != NULL)
+    {
+        /* Callback functions should be called for at least once. */
+        if((context->prepare_func != NULL) && (context->cb_prepare_count == 0))
+        {
+            (context->prepare_func)(pixbuf, NULL, context->user_data);
+        }
+
+        if((context->update_func != NULL) && (context->cb_update_count == 0))
+        {
+            gint width;
+            gint height;
+
+            width = gdk_pixbuf_get_width(pixbuf);
+            height = gdk_pixbuf_get_height(pixbuf);
+            (context->update_func)(pixbuf, 0, 0, width, height, context->user_data);
+        }
+
+        /* Free GdkPixbuf (callback function should ref it). */
+        g_object_ref(pixbuf);
+    }
+
+    return ret;
+}
+
+
+/* Incrementally load the next chunk of data. */
+static gboolean gdk_pixbuf__qtif_image_load_increment (gpointer data,
+                                                       const guchar *buf, guint size,
+                                                       GError **error)
+{
+    QTIFContext *context = (QTIFContext *)data;
+    GError *tmp = NULL;
+    gboolean ret = TRUE; /* Return TRUE for insufficient data. */
+
+    while(ret && (size != 0u))
+    {
+        switch(context->state)
+        {
+        case STATE_READY:
+            /* Abort if we have seen too mant atoms. */
+            if(context->atom_count == 0u)
+            {
+                g_set_error_literal (error, GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("Failed to find an image data atom."));
+                return FALSE;
+            }
+            context->atom_count--;
+
+            /* Copy to header buffer in context, in case supplied data is not enough. */
+            while(context->run_length < sizeof(QtHeader))
+            {
+                context->header_buffer[context->run_length] = *buf;
+                context->run_length++;
+                buf++;
+                size--;
+            }
+
+            /* Parse buffer as QT header. */
+            if(context->run_length == sizeof(QtHeader))
+            {
+                QtHeader *hdr = (QtHeader *)context->header_buffer;
+                context->run_length = GUINT32_FROM_BE(hdr->length) - sizeof(QtHeader);
+
+                /* Atom max size check. */
+                if(context->run_length > ATOM_SIZE_MAX)
+                {
+                    g_set_error(error, GDK_PIXBUF_ERROR,
+                                       GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                       ngettext (  "QTIF atom size too large (%d byte)",
+                                                   "QTIF atom size too large (%d bytes)",
+                                                    hdr->length),
+                                       hdr->length);
+                    return FALSE;
+                }
+
+                /* Set state according to atom type. */
+                if(GUINT32_FROM_BE(hdr->tag) == QTIF_TAG_IDATA)
+                {
+                    GError *tmp = NULL;
+
+                    context->state = STATE_DATA;
+
+                    /* Create GdkPixbufLoader for this image data. */
+                    ret = gdk_pixbuf__qtif_image_create_loader(context, &tmp);
+                    if(!ret)
+                    {
+                        g_propagate_error (error, tmp);
+                    }
+                }
+                else
+                {
+                    context->state = STATE_OTHER;
+                }
+            }
+            break;
+
+        default: /* Both STATE_DATA and STATE_OTHER will come here. */
+            /* Check for atom boundary. */
+            if(context->run_length > size)
+            {
+                /* Supply image data to GdkPixbufLoader if in STATE_DATA. */
+                if(context->state == STATE_DATA)
+                {
+                    tmp = NULL;
+                    ret = gdk_pixbuf_loader_write(context->loader, buf, size, &tmp);
+                    if(!ret && (error != NULL) && (*error == NULL))
+                    {
+                        g_propagate_error (error, tmp);
+                    }
+                }
+                context->run_length -= size;
+                size = 0u;
+            }
+            else
+            {
+                /* Supply image data to GdkPixbufLoader if in STATE_DATA. */
+                if(context->state == STATE_DATA)
+                {
+                    gboolean r;
+
+                    /* Here we should have concluded a complete image atom. */
+                    tmp = NULL;
+                    ret = gdk_pixbuf_loader_write(context->loader, buf, context->run_length, &tmp);
+                    if(!ret && (error != NULL) && (*error == NULL))
+                    {
+                        g_propagate_error (error, tmp);
+                    }
+
+                    /* Free GdkPixbufLoader and handle callback. */
+                    tmp = NULL;
+                    r = gdk_pixbuf__qtif_image_free_loader(context, &tmp);
+                    if(!r)
+                    {
+                        if((error != NULL) && (*error == NULL))
+                        {
+                            g_propagate_error (error, tmp);
+                        }
+                        ret = FALSE;
+                    }
+                }
+                buf = &buf[context->run_length];
+                size -= context->run_length;
+                context->run_length = 0u;
+                context->state = STATE_READY;
+            }
+            break;
+        }
+    }
+
+    return ret;
+}
+
+/* Event handlers */
+static void gdk_pixbuf__qtif_cb_size_prepared(GdkPixbufLoader *loader,
+                                              gint width,
+                                              gint height,
+                                              gpointer user_data)
+{
+    QTIFContext *context = (QTIFContext *)user_data;
+    if((context != NULL) && (context->size_func != NULL))
+    {
+        (context->size_func)(&width, &height, context->user_data);
+        context->cb_prepare_count++;
+    }
+}
+
+static void gdk_pixbuf__qtif_cb_area_prepared(GdkPixbufLoader *loader, gpointer user_data)
+{
+    QTIFContext *context = (QTIFContext *)user_data;
+    if((loader != NULL) && (context != NULL) && (context->prepare_func != NULL))
+    {
+        GdkPixbuf *pixbuf = gdk_pixbuf_loader_get_pixbuf(context->loader);
+        (context->prepare_func)(pixbuf, NULL, context->user_data);
+        context->cb_update_count++;
+    }
+}
+
+static void gdk_pixbuf__qtif_cb_area_updated(GdkPixbufLoader *loader,
+                                             gint x,
+                                             gint y,
+                                             gint width,
+                                             gint height,
+                                             gpointer user_data)
+{
+    QTIFContext *context = (QTIFContext *)user_data;
+    if((loader != NULL) && (context != NULL) && (context->update_func != NULL))
+    {
+        GdkPixbuf *pixbuf = gdk_pixbuf_loader_get_pixbuf(context->loader);
+        (context->update_func)(pixbuf, x, y, width, height, context->user_data);
+    }
+}
+
+
+#ifndef INCLUDE_qtif
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
+#else
+#define MODULE_ENTRY(function) void _gdk_pixbuf__qtif_ ## function
+#endif
+
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
+{
+    module->load = gdk_pixbuf__qtif_image_load;
+    module->begin_load = gdk_pixbuf__qtif_image_begin_load;
+    module->stop_load = gdk_pixbuf__qtif_image_stop_load;
+    module->load_increment = gdk_pixbuf__qtif_image_load_increment;
+}
+
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
+{
+    static GdkPixbufModulePattern signature[] = {
+        { "abcdidsc", "xxxx    ", 100 },
+        { "abcdidat", "xxxx    ", 100 },
+        { NULL, NULL, 0 }
+    };
+    static gchar * mime_types[] = {
+        "image/x-quicktime",
+        "image/qtif",
+        NULL
+    };
+    static gchar * extensions[] = {
+        "qtif",
+        "qif",
+        NULL
+    };
+
+    info->name = "qtif";
+    info->signature = signature;
+    info->description = N_("The QTIF image format");
+    info->mime_types = mime_types;
+    info->extensions = extensions;
+    info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
+    info->license = "LGPL";
+}
+
diff --git a/gdk-pixbuf/io-ras.c b/gdk-pixbuf/io-ras.c
new file mode 100644 (file)
index 0000000..ee79f1a
--- /dev/null
@@ -0,0 +1,550 @@
+/* -*- mode: C; c-file-style: "linux" -*- */
+/* GdkPixbuf library - SUNRAS image loader
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Authors: Arjan van de Ven <arjan@fenrus.demon.nl>
+ *          Federico Mena-Quintero <federico@gimp.org>
+ *
+ * Based on io-gif.c, io-tiff.c and io-png.c
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+/*
+
+Known bugs:
+       * Compressed rasterfiles don't work yet
+
+*/
+
+#include "config.h"
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include "gdk-pixbuf-private.h"
+
+\f
+
+/* 
+   Header structure for sunras files.
+   All values are in big-endian order on disk
+   
+   Note: Every scanline is padded to be a multiple of 16 bits
+ */
+
+struct rasterfile {
+       guint magic;
+       guint width;
+       guint height;
+       guint depth;
+       guint length;
+       guint type;
+       guint maptype;
+       guint maplength;
+};
+
+/* 
+       This does a byte-order swap. Does glib have something like
+       be32_to_cpu() ??
+*/
+
+/* Progressive loading */
+
+struct ras_progressive_state {
+       GdkPixbufModuleSizeFunc size_func;
+       GdkPixbufModulePreparedFunc prepared_func;
+       GdkPixbufModuleUpdatedFunc updated_func;
+       gpointer user_data;
+
+       gint HeaderSize;        /* The size of the header-part (incl colormap) */
+       guchar *HeaderBuf;      /* The buffer for the header (incl colormap) */
+       gint HeaderDone;        /* The nr of bytes actually in HeaderBuf */
+
+       gint LineWidth;         /* The width of a line in bytes */
+       guchar *LineBuf;        /* Buffer for 1 line */
+       gint LineDone;          /* # of bytes in LineBuf */
+       gint Lines;             /* # of finished lines */
+
+       gint RasType;           /*  32 = BGRA
+                                  24 = BGR
+                                  8 = 8 bit colormapped
+                                  1  = 1 bit bitonal 
+                                */
+       gint DecoderState;        
+
+       struct rasterfile Header;       /* Decoded (BE->CPU) header */
+
+
+       GdkPixbuf *pixbuf;      /* Our "target" */
+};
+
+static gpointer
+gdk_pixbuf__ras_image_begin_load(GdkPixbufModuleSizeFunc size_func,
+                                 GdkPixbufModulePreparedFunc prepared_func,
+                                GdkPixbufModuleUpdatedFunc updated_func,
+                                gpointer user_data,
+                                 GError **error);
+static gboolean gdk_pixbuf__ras_image_stop_load(gpointer data, GError **error);
+static gboolean gdk_pixbuf__ras_image_load_increment(gpointer data,
+                                                     const guchar * buf, guint size,
+                                                     GError **error);
+
+static gboolean RAS2State(struct rasterfile *RAS,
+                         struct ras_progressive_state *State,
+                         GError **error)
+{
+       State->Header.width = GUINT32_FROM_BE(RAS->width);
+       State->Header.height = GUINT32_FROM_BE(RAS->height);
+       State->Header.depth = GUINT32_FROM_BE(RAS->depth);
+       State->Header.type = GUINT32_FROM_BE(RAS->type);
+       State->Header.maptype = GUINT32_FROM_BE(RAS->maptype);
+       State->Header.maplength = GUINT32_FROM_BE(RAS->maplength);
+
+       if ((gint)State->Header.width <= 0 ||
+           (gint)State->Header.height <= 0 || 
+           State->Header.maplength > 768) {
+               g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("RAS image has bogus header data"));
+               return FALSE;
+       }
+
+       State->RasType = State->Header.depth;   /* This may be less trivial someday */
+       State->HeaderSize = 32 + State->Header.maplength;
+
+       if (State->RasType == 32)
+               State->LineWidth = State->Header.width * 4;
+       else if (State->RasType == 24)
+               State->LineWidth = State->Header.width * 3;
+       else if (State->RasType == 8)
+               State->LineWidth = State->Header.width * 1;
+       else if (State->RasType == 1) {
+               State->LineWidth = State->Header.width / 8;
+               if ((State->Header.width & 7) != 0)
+                       State->LineWidth++;
+       }
+       else {
+               g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("RAS image has unknown type"));
+               return FALSE;
+       }
+
+       if (State->Header.type > 2 || State->Header.maptype > 1) {
+               g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("unsupported RAS image variation"));
+               return FALSE;
+       }
+
+       /* Now pad the line to be a multiple of 16 bits */
+       if ((State->LineWidth & 1) != 0)
+               State->LineWidth++;
+
+       if (!State->LineBuf) {
+               State->LineBuf = g_try_malloc (State->LineWidth);
+
+               if (!State->LineBuf) {
+                       g_set_error_literal (error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                             _("Not enough memory to load RAS image"));
+                       return FALSE;
+               }
+       }
+
+
+       if (!State->pixbuf) {
+               if (State->size_func) {
+                       gint width = State->Header.width;
+                       gint height = State->Header.height;
+                       
+                       (*State->size_func) (&width, &height, State->user_data);
+                       if (width == 0 || height == 0)
+                               return FALSE;
+               }
+
+               if (State->RasType == 32)
+                       State->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
+                                                       (gint) State->Header.width,
+                                                       (gint) State->Header.height);
+               else
+                       State->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
+                                                       (gint) State->Header.width,
+                                                       (gint) State->Header.height);
+               
+                if (!State->pixbuf) {
+                        g_set_error_literal (error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                             _("Not enough memory to load RAS image"));
+                        return FALSE;
+                }
+
+               if (State->prepared_func != NULL)
+                       /* Notify the client that we are ready to go */
+                       (*State->prepared_func) (State->pixbuf,
+                                                 NULL,
+                                                State->user_data);
+
+       }
+       
+       if ((State->Header.maplength == 0) && (State->RasType == 1)) {
+               State->HeaderBuf[32] = 255;
+               State->HeaderBuf[33] = 0;
+               State->HeaderBuf[34] = 255;
+               State->HeaderBuf[35] = 0;
+               State->HeaderBuf[36] = 255;
+               State->HeaderBuf[37] = 0;
+       }
+
+       return TRUE;
+}
+
+/* 
+ * func - called when we have pixmap created (but no image data)
+ * user_data - passed as arg 1 to func
+ * return context (opaque to user)
+ */
+
+static gpointer
+gdk_pixbuf__ras_image_begin_load(GdkPixbufModuleSizeFunc size_func, 
+                                 GdkPixbufModulePreparedFunc prepared_func,
+                                GdkPixbufModuleUpdatedFunc updated_func,
+                                gpointer user_data,
+                                 GError **error)
+{
+       struct ras_progressive_state *context;
+
+       context = g_new0(struct ras_progressive_state, 1);
+       context->size_func = size_func;
+       context->prepared_func = prepared_func;
+       context->updated_func = updated_func;
+       context->user_data = user_data;
+
+       context->HeaderSize = 32;
+       context->HeaderBuf = g_malloc(32 + 768);        /* 32 for rasheader,
+                                                          768 for the colormap */
+       context->HeaderDone = 0;
+
+       context->LineWidth = 0;
+       context->LineBuf = NULL;
+       context->LineDone = 0;
+       context->Lines = 0;
+
+       context->RasType = 0;
+       context->DecoderState = 0;
+       
+       memset(&context->Header, 0, sizeof(struct rasterfile));
+
+
+       context->pixbuf = NULL;
+
+
+       return (gpointer) context;
+}
+
+/*
+ * context - returned from image_begin_load
+ *
+ * free context, unref gdk_pixbuf
+ */
+static gboolean
+gdk_pixbuf__ras_image_stop_load(gpointer data, GError **error)
+{
+       struct ras_progressive_state *context =
+           (struct ras_progressive_state *) data;
+
+        /* FIXME this thing needs to report errors if
+         * we have unused image data
+         */
+
+       g_return_val_if_fail(context != NULL, TRUE);
+
+       g_free(context->LineBuf);
+       g_free(context->HeaderBuf);
+
+       if (context->pixbuf)
+               g_object_unref(context->pixbuf);
+
+       g_free(context);
+
+        return TRUE;
+}
+
+/* 
+ OneLine is called when enough data is received to process 1 line 
+ of pixels 
+ */
+
+static void OneLine32(struct ras_progressive_state *context)
+{
+       gint X;
+       guchar *Pixels;
+
+       X = 0;
+       Pixels = context->pixbuf->pixels + context->pixbuf->rowstride * context->Lines;
+       while (X < context->Header.width) {
+               /* The joys of having a BGR byteorder */
+               Pixels[X * 4 + 0] = context->LineBuf[X * 4 + 2];
+               Pixels[X * 4 + 1] = context->LineBuf[X * 4 + 1];
+               Pixels[X * 4 + 2] = context->LineBuf[X * 4 + 0];
+               Pixels[X * 4 + 3] = context->LineBuf[X * 4 + 3];
+               X++;
+       }
+}
+
+static void OneLine24(struct ras_progressive_state *context)
+{
+       gint X;
+       guchar *Pixels;
+
+       X = 0;
+       Pixels = context->pixbuf->pixels + context->pixbuf->rowstride * context->Lines;
+       while (X < context->Header.width) {
+               /* The joys of having a BGR byteorder */
+               Pixels[X * 3 + 0] = context->LineBuf[X * 3 + 2];
+               Pixels[X * 3 + 1] = context->LineBuf[X * 3 + 1];
+               Pixels[X * 3 + 2] = context->LineBuf[X * 3 + 0];
+               X++;
+       }
+
+}
+
+static void OneLine8(struct ras_progressive_state *context)
+{
+       gint X;
+       guchar *Pixels;
+       int offset = context->Header.maplength / 3;
+
+       X = 0;
+       Pixels = context->pixbuf->pixels + context->pixbuf->rowstride * context->Lines;
+       while (X < context->Header.width) {
+               /* The joys of having a BGR byteorder */
+               Pixels[X * 3 + 0] =
+                   context->HeaderBuf[context->LineBuf[X] + 32];
+               Pixels[X * 3 + 1] =
+                   context->HeaderBuf[context->LineBuf[X] + offset + 32];
+               Pixels[X * 3 + 2] =
+                   context->HeaderBuf[context->LineBuf[X] + 2*offset + 32];
+               X++;
+       }
+}
+
+static void OneLine1(struct ras_progressive_state *context)
+{
+       gint X;
+       guchar *Pixels;
+
+       X = 0;
+       Pixels = context->pixbuf->pixels + context->pixbuf->rowstride * context->Lines;
+       while (X < context->Header.width) {
+               int Bit;
+               
+               Bit = (context->LineBuf[X/8])>>(7-(X&7));
+               Bit = Bit & 1;
+               /* The joys of having a BGR byteorder */
+               Pixels[X * 3 + 0] =
+                   context->HeaderBuf[Bit + 32];
+               Pixels[X * 3 + 1] =
+                   context->HeaderBuf[Bit + 2 + 32];
+               Pixels[X * 3 + 2] =
+                   context->HeaderBuf[Bit + 4 + 32];
+               X++;
+       }
+}
+
+
+static void OneLine(struct ras_progressive_state *context)
+{
+       context->LineDone = 0;
+       if (context->Lines >= context->Header.height)
+               return;
+       if (context->RasType == 32)
+               OneLine32(context);
+       if (context->RasType == 24)
+               OneLine24(context);
+       if (context->RasType == 8)
+               OneLine8(context);
+       if (context->RasType == 1)
+               OneLine1(context);
+
+       context->LineDone = 0;
+       context->Lines++;
+
+       if (context->updated_func != NULL) {
+               (*context->updated_func) (context->pixbuf,
+                                         0,
+                                         context->Lines,
+                                         context->Header.width,
+                                         1,
+                                         context->user_data);
+
+       }
+}
+
+static gboolean
+DoCompressed (struct ras_progressive_state *context,
+             const guchar * buf, guint size,
+             GError **error)
+{
+       int i;
+
+       for (i = 0; i < size; i++) {
+               switch (context->DecoderState) {
+                   case 0:
+                           if (buf[i] == 0x80)
+                                   context->DecoderState = 1;
+                           else
+                                   context->LineBuf[context->LineDone++] = buf[i];
+                           break;
+                   case 1:
+                           if (buf[i] == 0) {
+                                   context->LineBuf[context->LineDone++] = 0x80;
+                                   context->DecoderState = 0;
+                           }
+                           else
+                                   context->DecoderState = buf[i] + 1;
+                           break;
+                   default:
+                           for (; context->DecoderState; context->DecoderState--) {
+                                   context->LineBuf[context->LineDone++] = buf[i];
+                                   if ((context->LineDone >= context->LineWidth) && (context->LineWidth > 0))
+                                           OneLine(context);
+                           }
+               }
+               if ((context->LineDone >= context->LineWidth) && (context->LineWidth > 0))
+                       OneLine(context);
+       }
+       return TRUE;
+}
+
+/*
+ * context - from image_begin_load
+ * buf - new image data
+ * size - length of new image data
+ *
+ * append image data onto incrementally built output image
+ */
+static gboolean
+gdk_pixbuf__ras_image_load_increment(gpointer data,
+                                     const guchar * buf, guint size,
+                                     GError **error)
+{
+       struct ras_progressive_state *context =
+           (struct ras_progressive_state *) data;
+
+       gint BytesToCopy;
+
+       while (size > 0) {
+               if (context->HeaderDone < context->HeaderSize) {        /* We still 
+                                                                          have headerbytes to do */
+                       BytesToCopy =
+                           context->HeaderSize - context->HeaderDone;
+                       if (BytesToCopy > size)
+                               BytesToCopy = size;
+
+                       memmove(context->HeaderBuf + context->HeaderDone,
+                              buf, BytesToCopy);
+
+                       size -= BytesToCopy;
+                       buf += BytesToCopy;
+                       context->HeaderDone += BytesToCopy;
+
+               } else if (context->Header.type == 2) {
+                       if (!DoCompressed (context, buf, size, error)) {
+                               return FALSE;
+                       }
+                       size = 0;
+               }
+               else {
+                       BytesToCopy =
+                           context->LineWidth - context->LineDone;
+                       if (BytesToCopy > size)
+                               BytesToCopy = size;
+
+                       if (BytesToCopy > 0) {
+                               memmove(context->LineBuf +
+                                      context->LineDone, buf,
+                                      BytesToCopy);
+
+                               size -= BytesToCopy;
+                               buf += BytesToCopy;
+                               context->LineDone += BytesToCopy;
+                       }
+                       if ((context->LineDone >= context->LineWidth) &&
+                           (context->LineWidth > 0))
+                               OneLine(context);
+
+
+               }
+
+               if (context->HeaderDone >= 32)
+                       if (!RAS2State((struct rasterfile *) context->HeaderBuf,
+                                      context, error)) {
+                               return FALSE;
+                       }
+
+
+       }
+
+       return TRUE;
+}
+
+#ifndef INCLUDE_ras
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
+#else
+#define MODULE_ENTRY(function) void _gdk_pixbuf__ras_ ## function
+#endif
+
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
+{
+       module->begin_load = gdk_pixbuf__ras_image_begin_load;
+       module->stop_load = gdk_pixbuf__ras_image_stop_load;
+       module->load_increment = gdk_pixbuf__ras_image_load_increment;
+}
+
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
+{
+       static GdkPixbufModulePattern signature[] = {
+               { "\x59\xa6\x6a\x95", NULL, 100 },
+               { NULL, NULL, 0 }
+       };
+       static gchar * mime_types[] = {
+               "image/x-cmu-raster",
+               "image/x-sun-raster",
+               NULL
+       };
+       static gchar * extensions[] = {
+               "ras",
+               NULL
+       };
+
+       info->name = "ras";
+       info->signature = signature;
+       info->description = N_("The Sun raster image format");
+       info->mime_types = mime_types;
+       info->extensions = extensions;
+       info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
+       info->license = "LGPL";
+}
+
diff --git a/gdk-pixbuf/io-tga.c b/gdk-pixbuf/io-tga.c
new file mode 100644 (file)
index 0000000..5ef14fa
--- /dev/null
@@ -0,0 +1,1012 @@
+/* -*- mode: C; c-file-style: "linux" -*- */
+/* 
+ * GdkPixbuf library - TGA image loader
+ * Copyright (C) 1999 Nicola Girardi <nikke@swlibero.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.
+ *
+ */
+
+/*
+ * Some NOTES about the TGA loader (2001/06/07, nikke@swlibero.org)
+ *
+ * - The TGAFooter isn't present in all TGA files.  In fact, there's an older
+ *   format specification, still in use, which doesn't cover the TGAFooter.
+ *   Actually, most TGA files I have are of the older type.  Anyway I put the 
+ *   struct declaration here for completeness.
+ *
+ * - Error handling was designed to be very paranoid.
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <string.h>
+
+#include "gdk-pixbuf-private.h"
+
+#undef DEBUG_TGA
+
+#define TGA_INTERLEAVE_MASK     0xc0
+#define TGA_INTERLEAVE_NONE     0x00
+#define TGA_INTERLEAVE_2WAY     0x40
+#define TGA_INTERLEAVE_4WAY     0x80
+
+#define TGA_ORIGIN_MASK         0x30
+#define TGA_ORIGIN_RIGHT        0x10
+#define TGA_ORIGIN_UPPER        0x20
+
+enum {
+       TGA_TYPE_NODATA = 0,
+       TGA_TYPE_PSEUDOCOLOR = 1,
+       TGA_TYPE_TRUECOLOR = 2,
+       TGA_TYPE_GRAYSCALE = 3,
+       TGA_TYPE_RLE_PSEUDOCOLOR = 9,
+       TGA_TYPE_RLE_TRUECOLOR = 10,
+       TGA_TYPE_RLE_GRAYSCALE = 11
+};
+
+#define LE16(p) ((p)[0] + ((p)[1] << 8))
+
+typedef struct _IOBuffer IOBuffer;
+
+typedef struct _TGAHeader TGAHeader;
+typedef struct _TGAFooter TGAFooter;
+
+typedef struct _TGAColormap TGAColormap;
+typedef struct _TGAColor TGAColor;
+
+typedef struct _TGAContext TGAContext;
+
+struct _TGAHeader {
+       guint8 infolen;
+       guint8 has_cmap;
+       guint8 type;
+       
+       guint8 cmap_start[2];
+       guint8 cmap_n_colors[2];
+       guint8 cmap_bpp;
+       
+       guint8 x_origin[2];
+       guint8 y_origin[2];
+       
+       guint8 width[2];
+       guint8 height[2];
+       guint8 bpp;
+       
+       guint8 flags;
+};
+
+struct _TGAFooter {
+       guint32 extension_area_offset;
+       guint32 developer_directory_offset;
+
+       /* Standard TGA signature, "TRUEVISION-XFILE.\0". */
+       union {
+               gchar sig_full[18];
+               struct {
+                       gchar sig_chunk[16];
+                       gchar dot, null;
+               } sig_struct;
+       } sig;
+};
+
+struct _TGAColormap {
+       gint size;
+       TGAColor *cols;
+};
+
+struct _TGAColor {
+       guchar r, g, b, a;
+};
+
+struct _TGAContext {
+       TGAHeader *hdr;
+       guint rowstride;
+       guint completed_lines;
+       gboolean run_length_encoded;
+
+       TGAColormap *cmap;
+       guint cmap_size;
+
+       GdkPixbuf *pbuf;
+       guint pbuf_bytes;
+       guint pbuf_bytes_done;
+       guchar *pptr;
+
+       IOBuffer *in;
+
+       gboolean skipped_info;
+       gboolean prepared;
+       gboolean done;
+
+       GdkPixbufModuleSizeFunc sfunc;
+       GdkPixbufModulePreparedFunc pfunc;
+       GdkPixbufModuleUpdatedFunc ufunc;
+       gpointer udata;
+};
+
+struct _IOBuffer {
+       guchar *data;
+       guint size;
+};
+
+static IOBuffer *io_buffer_new(GError **err)
+{
+       IOBuffer *buffer;
+       buffer = g_try_malloc(sizeof(IOBuffer));
+       if (!buffer) {
+               g_set_error_literal(err, GDK_PIXBUF_ERROR,
+                                    GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                    _("Cannot allocate memory for IOBuffer struct"));
+               return NULL;
+       }
+       buffer->data = NULL;
+       buffer->size = 0;
+       return buffer;
+}
+
+static IOBuffer *io_buffer_append(IOBuffer *buffer, 
+                                 const guchar *data, guint len, 
+                                 GError **err)
+{
+       if (!buffer)
+               return NULL;
+       if (!buffer->data) {
+               buffer->data = g_try_malloc(len);
+               if (!buffer->data) {
+                       g_set_error_literal(err, GDK_PIXBUF_ERROR,
+                                            GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                            _("Cannot allocate memory for IOBuffer data"));
+                       g_free(buffer);
+                       return NULL;
+               }
+               g_memmove(buffer->data, data, len);
+               buffer->size = len;
+       } else {
+               guchar *tmp = g_try_realloc (buffer->data, buffer->size + len);
+               if (!tmp) {
+                       g_set_error_literal(err, GDK_PIXBUF_ERROR,
+                                            GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                            _("Cannot realloc IOBuffer data"));
+                       g_free(buffer);
+                       return NULL;
+               }
+               buffer->data = tmp;
+               g_memmove(&buffer->data[buffer->size], data, len);
+               buffer->size += len;
+       }
+       return buffer;
+}
+
+static IOBuffer *io_buffer_free_segment(IOBuffer *buffer, 
+                                       guint count,
+                                        GError **err)
+{
+       g_return_val_if_fail(buffer != NULL, NULL);
+       g_return_val_if_fail(buffer->data != NULL, NULL);
+       if (count == buffer->size) {
+               g_free(buffer->data);
+               buffer->data = NULL;
+               buffer->size = 0;
+       } else {
+               guchar *new_buf;
+               guint new_size;
+
+               new_size = buffer->size - count;
+               new_buf = g_try_malloc(new_size);
+               if (!new_buf) {
+                       g_set_error_literal(err, GDK_PIXBUF_ERROR,
+                                            GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                            _("Cannot allocate temporary IOBuffer data"));
+                       g_free(buffer->data);
+                       g_free(buffer);
+                       return NULL;
+               }
+
+               g_memmove(new_buf, &buffer->data[count], new_size);
+               g_free(buffer->data);
+               buffer->data = new_buf;
+               buffer->size = new_size;
+       }
+       return buffer;
+}
+
+static void io_buffer_free(IOBuffer *buffer)
+{
+       g_return_if_fail(buffer != NULL);
+       g_free(buffer->data);
+       g_free(buffer);
+}
+
+static void free_buffer(guchar *pixels, gpointer data)
+{
+       g_free(pixels);
+}
+
+static GdkPixbuf *get_contiguous_pixbuf (guint width, 
+                                        guint height, 
+                                        gboolean has_alpha)
+{
+       guchar *pixels;
+       guint channels, rowstride, bytes;
+       
+       if (has_alpha) 
+               channels = 4;
+       else 
+               channels = 3;
+       
+       rowstride = width * channels;
+       
+       if (rowstride / channels != width)
+                return NULL;                
+
+       bytes = height * rowstride;
+
+        if (bytes / rowstride != height)
+                return NULL;                
+
+        pixels = g_try_malloc (bytes);
+
+       if (!pixels)
+               return NULL;
+       
+       return gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, has_alpha, 8,
+                                        width, height, rowstride, free_buffer, NULL);
+}
+
+static void pixbuf_flip_row (GdkPixbuf *pixbuf, guchar *ph)
+{
+       guchar *p, *s;
+       guchar tmp;
+       gint count;
+
+       p = ph;
+       s = p + pixbuf->n_channels * (pixbuf->width - 1);
+       while (p < s) {
+               for (count = pixbuf->n_channels; count > 0; count--, p++, s++) {
+                       tmp = *p;
+                       *p = *s;
+                       *s = tmp;
+               }
+               s -= 2 * pixbuf->n_channels;
+       }               
+}
+
+static void pixbuf_flip_vertically (GdkPixbuf *pixbuf)
+{
+       guchar *ph, *sh, *p, *s;
+       guchar tmp;
+       gint count;
+
+       ph = pixbuf->pixels;
+       sh = pixbuf->pixels + pixbuf->height*pixbuf->rowstride;
+       while (ph < sh - pixbuf->rowstride) {
+               p = ph;
+               s = sh - pixbuf->rowstride;
+               for (count = pixbuf->n_channels * pixbuf->width; count > 0; count--, p++, s++) {
+                       tmp = *p;
+                       *p = *s;
+                       *s = tmp;
+               }
+               sh -= pixbuf->rowstride;
+               ph += pixbuf->rowstride;
+       }
+}
+
+static gboolean fill_in_context(TGAContext *ctx, GError **err)
+{
+       gboolean alpha;
+       guint w, h;
+
+       g_return_val_if_fail(ctx != NULL, FALSE);
+
+       ctx->run_length_encoded =
+               ((ctx->hdr->type == TGA_TYPE_RLE_PSEUDOCOLOR)
+                || (ctx->hdr->type == TGA_TYPE_RLE_TRUECOLOR)
+                || (ctx->hdr->type == TGA_TYPE_RLE_GRAYSCALE));
+
+       if (ctx->hdr->has_cmap)
+               ctx->cmap_size = ((ctx->hdr->cmap_bpp + 7) >> 3) *
+                       LE16(ctx->hdr->cmap_n_colors);
+
+       alpha = ((ctx->hdr->bpp == 16) || 
+                (ctx->hdr->bpp == 32) ||
+                (ctx->hdr->has_cmap && (ctx->hdr->cmap_bpp == 32)));
+
+       w = LE16(ctx->hdr->width);
+       h = LE16(ctx->hdr->height);
+
+       if (ctx->sfunc) {
+               gint wi = w;
+               gint hi = h;
+               
+               (*ctx->sfunc) (&wi, &hi, ctx->udata);
+               
+               if (wi == 0 || hi == 0) 
+                       return FALSE;
+       }
+
+       ctx->pbuf = get_contiguous_pixbuf (w, h, alpha);
+
+       if (!ctx->pbuf) {
+               g_set_error_literal(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                    _("Cannot allocate new pixbuf"));
+               return FALSE;
+       }
+
+       ctx->pbuf_bytes = ctx->pbuf->rowstride * ctx->pbuf->height;
+       if ((ctx->hdr->flags & TGA_ORIGIN_UPPER) || ctx->run_length_encoded)
+               ctx->pptr = ctx->pbuf->pixels;
+       else
+               ctx->pptr = ctx->pbuf->pixels + (ctx->pbuf->height - 1)*ctx->pbuf->rowstride;
+
+       if (ctx->hdr->type == TGA_TYPE_PSEUDOCOLOR)
+         ctx->rowstride = ctx->pbuf->width;
+       else if (ctx->hdr->type == TGA_TYPE_GRAYSCALE)
+         ctx->rowstride = (alpha ? ctx->pbuf->width * 2 : ctx->pbuf->width);
+       else if (ctx->hdr->type == TGA_TYPE_TRUECOLOR)
+               ctx->rowstride = ctx->pbuf->rowstride;
+
+       ctx->completed_lines = 0;
+       return TRUE;
+}
+
+static void parse_data_for_row_pseudocolor(TGAContext *ctx)
+{
+       guchar *s = ctx->in->data;
+       guint upper_bound = ctx->pbuf->width;
+       guchar *p = ctx->pptr;
+
+       for (; upper_bound; upper_bound--, s++) {
+               *p++ = ctx->cmap->cols[*s].r;
+               *p++ = ctx->cmap->cols[*s].g;
+               *p++ = ctx->cmap->cols[*s].b;
+               if (ctx->hdr->cmap_bpp == 32)
+                       *p++ = ctx->cmap->cols[*s].a;
+       }
+}
+
+static void swap_channels(TGAContext *ctx)
+{
+       guchar swap;
+       guint count;
+       guchar *p = ctx->pptr;
+       for (count = ctx->pbuf->width; count; count--) {
+         swap = p[0];
+         p[0] = p[2];
+         p[2] = swap;
+         p += ctx->pbuf->n_channels;
+       }
+}
+
+static void parse_data_for_row_truecolor(TGAContext *ctx)
+{
+       g_memmove(ctx->pptr, ctx->in->data, ctx->pbuf->rowstride);
+       swap_channels(ctx);
+}
+
+static void parse_data_for_row_grayscale(TGAContext *ctx)
+{
+       guchar *s = ctx->in->data;
+       guint upper_bound = ctx->pbuf->width;
+
+       guchar *p = ctx->pptr;
+       for (; upper_bound; upper_bound--) {
+               p[0] = p[1] = p[2] = *s++;
+               if (ctx->pbuf->n_channels == 4)
+                 p[3] = *s++;
+               p += ctx->pbuf->n_channels;
+       }
+}
+
+static gboolean parse_data_for_row(TGAContext *ctx, GError **err)
+{
+       guint row;
+
+       if (ctx->hdr->type == TGA_TYPE_PSEUDOCOLOR)
+               parse_data_for_row_pseudocolor(ctx);
+       else if (ctx->hdr->type == TGA_TYPE_TRUECOLOR)
+               parse_data_for_row_truecolor(ctx);
+       else if (ctx->hdr->type == TGA_TYPE_GRAYSCALE)
+               parse_data_for_row_grayscale(ctx);
+
+       if (ctx->hdr->flags & TGA_ORIGIN_RIGHT)
+               pixbuf_flip_row (ctx->pbuf, ctx->pptr);
+       if (ctx->hdr->flags & TGA_ORIGIN_UPPER)
+               ctx->pptr += ctx->pbuf->rowstride;
+       else
+               ctx->pptr -= ctx->pbuf->rowstride;
+       ctx->pbuf_bytes_done += ctx->pbuf->rowstride;
+       if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
+               ctx->done = TRUE;
+       
+       ctx->in = io_buffer_free_segment(ctx->in, ctx->rowstride, err);
+       if (!ctx->in)
+               return FALSE;
+       row = (ctx->pptr - ctx->pbuf->pixels) / ctx->pbuf->rowstride - 1;
+       if (ctx->ufunc)
+               (*ctx->ufunc) (ctx->pbuf, 0, row, ctx->pbuf->width, 1, ctx->udata);
+       return TRUE;
+}
+
+static void write_rle_data(TGAContext *ctx, TGAColor *color, guint *rle_count)
+{
+       for (; *rle_count; (*rle_count)--) {
+               g_memmove(ctx->pptr, (guchar *) color, ctx->pbuf->n_channels);
+               ctx->pptr += ctx->pbuf->n_channels;
+               ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
+               if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
+                       return;
+       }
+}
+
+static guint parse_rle_data_pseudocolor(TGAContext *ctx)
+{
+       guint rle_num, raw_num;
+       guchar *s, tag;
+       guint n;
+
+       g_return_val_if_fail(ctx->in->size > 0, 0);
+       s = ctx->in->data;
+
+       for (n = 0; n < ctx->in->size; ) {
+               tag = *s;
+               s++, n++;
+               if (tag & 0x80) {
+                       if (n == ctx->in->size) {
+                               return --n;
+                       } else {
+                               rle_num = (tag & 0x7f) + 1;
+                               write_rle_data(ctx, &ctx->cmap->cols[*s], &rle_num);
+                               s++, n++;
+                               if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
+                                       ctx->done = TRUE;
+                                       return n;
+                               }
+                       }
+               } else {
+                       raw_num = tag + 1;
+                       if (n + raw_num >= ctx->in->size) {
+                               return --n;
+                       } else {
+                               for (; raw_num; raw_num--) {
+                                       *ctx->pptr++ =
+                                               ctx->cmap->cols[*s].r;
+                                       *ctx->pptr++ =
+                                               ctx->cmap->cols[*s].g;
+                                       *ctx->pptr++ =
+                                               ctx->cmap->cols[*s].b;
+                                       if (ctx->pbuf->n_channels == 4)
+                                               *ctx->pptr++ = ctx->cmap->cols[*s].a;
+                                       s++, n++;
+                                       ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
+                                       if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
+                                               ctx->done = TRUE;
+                                               return n;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) 
+               ctx->done = TRUE;
+       
+       return n;
+}
+
+static guint parse_rle_data_truecolor(TGAContext *ctx)
+{
+       TGAColor col;
+       guint rle_num, raw_num;
+       guchar *s, tag;
+       guint n = 0;
+
+       g_return_val_if_fail(ctx->in->size > 0, 0);
+       s = ctx->in->data;
+
+       for (n = 0; n < ctx->in->size; ) {
+               tag = *s;
+               s++, n++;
+               if (tag & 0x80) {
+                       if (n + ctx->pbuf->n_channels >= ctx->in->size) {
+                               return --n;
+                       } else {
+                               rle_num = (tag & 0x7f) + 1;
+                               col.b = *s++;
+                               col.g = *s++;
+                               col.r = *s++;
+                               if (ctx->hdr->bpp == 32)
+                                       col.a = *s++;
+                               n += ctx->pbuf->n_channels;
+                               write_rle_data(ctx, &col, &rle_num);
+                               if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
+                                       ctx->done = TRUE;
+                                       return n;
+                               }
+                       }
+               } else {
+                       raw_num = tag + 1;
+                       if (n + (raw_num * ctx->pbuf->n_channels) >= ctx->in->size) {
+                               return --n;
+                       } else {
+                               for (; raw_num; raw_num--) {
+                                       ctx->pptr[2] = *s++;
+                                       ctx->pptr[1] = *s++;
+                                       ctx->pptr[0] = *s++;
+                                       if (ctx->hdr->bpp == 32)
+                                               ctx->pptr[3] = *s++;
+                                       n += ctx->pbuf->n_channels;
+                                       ctx->pptr += ctx->pbuf->n_channels;
+                                       ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
+                                       if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
+                                               ctx->done = TRUE;
+                                               return n;
+                                       }
+                               }
+                               
+                               if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
+                                       ctx->done = TRUE;
+                                       return n;
+                               }
+                       }
+               }
+       }
+       if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
+               ctx->done = TRUE;
+       return n;
+}
+
+static guint parse_rle_data_grayscale(TGAContext *ctx)
+{
+       TGAColor tone;
+       guint rle_num, raw_num;
+       guchar *s, tag;
+       guint n;
+
+       g_return_val_if_fail(ctx->in->size > 0, 0);
+       s = ctx->in->data;
+
+       for (n = 0; n < ctx->in->size; ) {
+               tag = *s;
+               s++, n++;
+               if (tag & 0x80) {
+                       if (n + (ctx->pbuf->n_channels == 4 ? 2 : 1) >= ctx->in->size) {
+                               return --n;
+                       } else {
+                               rle_num = (tag & 0x7f) + 1;
+                               tone.r = tone.g = tone.b = *s;
+                               s++, n++;
+                               if (ctx->pbuf->n_channels == 4) {
+                                       tone.a = *s++;
+                                       n++;
+                               }
+                               write_rle_data(ctx, &tone, &rle_num);
+                               if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
+                                       ctx->done = TRUE;
+                                       return n;
+                               }
+                       }
+               } else {
+                       raw_num = tag + 1;
+                       if (n + raw_num * (ctx->pbuf->n_channels == 4 ? 2 : 1) >= ctx->in->size) {
+                               return --n;
+                       } else {
+                               for (; raw_num; raw_num--) {
+                                       ctx->pptr[0] = ctx->pptr[1] = ctx->pptr[2] = *s;
+                                       s++, n++;
+                                       if (ctx->pbuf->n_channels == 4) {
+                                               ctx->pptr[3] = *s++;
+                                               n++;
+                                       }
+                                       ctx->pptr += ctx->pbuf->n_channels;
+                                       ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
+                                       if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
+                                               ctx->done = TRUE;
+                                               return n;
+                                       }
+                               }
+                       }
+               }
+       }
+       if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
+               ctx->done = TRUE;
+       return n;
+}
+
+static gboolean parse_rle_data(TGAContext *ctx, GError **err)
+{
+       guint rows = 0;
+       guint count = 0;
+       guint bytes_done_before = ctx->pbuf_bytes_done;
+
+       if (ctx->hdr->type == TGA_TYPE_RLE_PSEUDOCOLOR)
+               count = parse_rle_data_pseudocolor(ctx);
+       else if (ctx->hdr->type == TGA_TYPE_RLE_TRUECOLOR)
+               count = parse_rle_data_truecolor(ctx);
+       else if (ctx->hdr->type == TGA_TYPE_RLE_GRAYSCALE)
+               count = parse_rle_data_grayscale(ctx);
+
+       if (ctx->hdr->flags & TGA_ORIGIN_RIGHT) {
+               guchar *row = ctx->pbuf->pixels + (bytes_done_before / ctx->pbuf->rowstride) * ctx->pbuf->rowstride;
+               guchar *row_after = ctx->pbuf->pixels + (ctx->pbuf_bytes_done / ctx->pbuf->rowstride) * ctx->pbuf->rowstride;
+               for (; row < row_after; row += ctx->pbuf->rowstride)
+                       pixbuf_flip_row (ctx->pbuf, row);
+       }
+
+       ctx->in = io_buffer_free_segment(ctx->in, count, err);
+       if (!ctx->in)
+               return FALSE;
+
+       if (ctx->done) {
+               /* FIXME doing the vertical flipping afterwards is not
+                * perfect, but doing it during the rle decoding in place
+                * is considerably more work. 
+                */
+               if (!(ctx->hdr->flags & TGA_ORIGIN_UPPER)) {
+                       pixbuf_flip_vertically (ctx->pbuf);
+                       ctx->hdr->flags |= TGA_ORIGIN_UPPER;
+               }
+
+       }
+               
+       rows = ctx->pbuf_bytes_done / ctx->pbuf->rowstride - bytes_done_before / ctx->pbuf->rowstride;
+       if (ctx->ufunc)
+               (*ctx->ufunc) (ctx->pbuf, 0, bytes_done_before / ctx->pbuf->rowstride,
+                              ctx->pbuf->width, rows,
+                              ctx->udata);
+
+       return TRUE;
+}
+
+static gboolean try_colormap(TGAContext *ctx, GError **err)
+{
+       static guchar *p;
+       static guint n;
+
+       g_return_val_if_fail(ctx != NULL, FALSE);
+
+        if (ctx->cmap_size == 0) {
+               g_set_error_literal(err, GDK_PIXBUF_ERROR,
+                                    GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                    _("Image is corrupted or truncated"));
+                       return FALSE;
+        }
+
+       ctx->cmap = g_try_malloc(sizeof(TGAColormap));
+       if (!ctx->cmap) {
+               g_set_error_literal(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                    _("Cannot allocate colormap structure"));
+               return FALSE;
+       }
+       ctx->cmap->size = LE16(ctx->hdr->cmap_n_colors);
+       ctx->cmap->cols = g_try_malloc(sizeof(TGAColor) * ctx->cmap->size);
+       if (!ctx->cmap->cols) {
+               g_set_error_literal(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                    _("Cannot allocate colormap entries"));
+               return FALSE;
+       }
+
+       p = ctx->in->data;
+       for (n = 0; n < ctx->cmap->size; n++) {
+               if ((ctx->hdr->cmap_bpp == 15) || (ctx->hdr->cmap_bpp == 16)) {
+                       guint16 col = p[0] + (p[1] << 8);
+                       ctx->cmap->cols[n].b = (col >> 7) & 0xf8;
+                       ctx->cmap->cols[n].g = (col >> 2) & 0xf8;
+                       ctx->cmap->cols[n].r = col << 3;
+                       p += 2;
+               }
+               else if ((ctx->hdr->cmap_bpp == 24) || (ctx->hdr->cmap_bpp == 32)) {
+                       ctx->cmap->cols[n].b = *p++;
+                       ctx->cmap->cols[n].g = *p++;
+                       ctx->cmap->cols[n].r = *p++;
+                       if (ctx->hdr->cmap_bpp == 32)
+                               ctx->cmap->cols[n].a = *p++;
+               } else {
+                       g_set_error_literal(err, GDK_PIXBUF_ERROR, 
+                                            GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                            _("Unexpected bitdepth for colormap entries"));
+                       return FALSE;
+               }
+       }
+       ctx->in = io_buffer_free_segment(ctx->in, ctx->cmap_size, err);
+       if (!ctx->in)
+               return FALSE;
+       return TRUE;
+}
+
+static gboolean try_preload(TGAContext *ctx, GError **err)
+{
+       if (!ctx->hdr) {
+               if (ctx->in->size >= sizeof(TGAHeader)) {
+                       ctx->hdr = g_try_malloc(sizeof(TGAHeader));
+                       if (!ctx->hdr) {
+                               g_set_error_literal(err, GDK_PIXBUF_ERROR,
+                                                    GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                                    _("Cannot allocate TGA header memory"));
+                               return FALSE;
+                       }
+                       g_memmove(ctx->hdr, ctx->in->data, sizeof(TGAHeader));
+                       ctx->in = io_buffer_free_segment(ctx->in, sizeof(TGAHeader), err);
+#ifdef DEBUG_TGA
+                       g_print ("infolen %d "
+                                "has_cmap %d "
+                                "type %d "
+                                "cmap_start %d "
+                                "cmap_n_colors %d "
+                                "cmap_bpp %d "
+                                "x %d y %d width %d height %d bpp %d "
+                                "flags %#x",
+                                ctx->hdr->infolen,
+                                ctx->hdr->has_cmap,
+                                ctx->hdr->type,
+                                LE16(ctx->hdr->cmap_start),
+                                LE16(ctx->hdr->cmap_n_colors),
+                                ctx->hdr->cmap_bpp,
+                                LE16(ctx->hdr->x_origin),
+                                LE16(ctx->hdr->y_origin),
+                                LE16(ctx->hdr->width),
+                                LE16(ctx->hdr->height),
+                                ctx->hdr->bpp,
+                                ctx->hdr->flags);
+#endif
+                       if (!ctx->in)
+                               return FALSE;
+                       if (LE16(ctx->hdr->width) == 0 || 
+                           LE16(ctx->hdr->height) == 0) {
+                               g_set_error_literal(err, GDK_PIXBUF_ERROR,
+                                                    GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                                    _("TGA image has invalid dimensions"));
+                               return FALSE;
+                       }
+                       if ((ctx->hdr->flags & TGA_INTERLEAVE_MASK) != TGA_INTERLEAVE_NONE) {
+                               g_set_error_literal(err, GDK_PIXBUF_ERROR, 
+                                                    GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+                                                    _("TGA image type not supported"));
+                               return FALSE;
+                       }
+                       switch (ctx->hdr->type) {
+                           case TGA_TYPE_PSEUDOCOLOR:
+                           case TGA_TYPE_RLE_PSEUDOCOLOR:
+                                   if (ctx->hdr->bpp != 8) {
+                                           g_set_error_literal(err, GDK_PIXBUF_ERROR, 
+                                                                GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+                                                                _("TGA image type not supported"));
+                                           return FALSE;
+                                   }
+                                   break;
+                           case TGA_TYPE_TRUECOLOR:
+                           case TGA_TYPE_RLE_TRUECOLOR:
+                                   if (ctx->hdr->bpp != 24 &&
+                                       ctx->hdr->bpp != 32) {
+                                           g_set_error_literal(err, GDK_PIXBUF_ERROR, 
+                                                                GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+                                                                _("TGA image type not supported"));
+                                           return FALSE;
+                                   }                         
+                                   break;
+                           case TGA_TYPE_GRAYSCALE:
+                           case TGA_TYPE_RLE_GRAYSCALE:
+                                   if (ctx->hdr->bpp != 8 &&
+                                       ctx->hdr->bpp != 16) {
+                                           g_set_error_literal(err, GDK_PIXBUF_ERROR, 
+                                                                GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+                                                                _("TGA image type not supported"));
+                                           return FALSE;
+                                   }
+                                   break;
+                           default:
+                                   g_set_error_literal(err, GDK_PIXBUF_ERROR, 
+                                                        GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+                                                        _("TGA image type not supported"));
+                                   return FALSE;    
+                       }
+                       if (!fill_in_context(ctx, err))
+                               return FALSE;
+               } else {
+                       return TRUE;
+               }
+       }
+       if (!ctx->skipped_info) {
+               if (ctx->in->size >= ctx->hdr->infolen) {
+                       ctx->in = io_buffer_free_segment(ctx->in, ctx->hdr->infolen, err);
+                       if (!ctx->in)
+                               return FALSE;
+                       ctx->skipped_info = TRUE;
+               } else {
+                       return TRUE;
+               }
+       }
+       if (ctx->hdr->has_cmap && !ctx->cmap) {
+               if (ctx->in->size >= ctx->cmap_size) {
+                       if (!try_colormap(ctx, err))
+                               return FALSE;
+               } else {
+                       return TRUE;
+               }
+       }
+       if (!ctx->prepared) {
+               if (ctx->pfunc)
+                       (*ctx->pfunc) (ctx->pbuf, NULL, ctx->udata);
+               ctx->prepared = TRUE;
+       }
+       /* We shouldn't get here anyway. */
+       return TRUE;
+}
+
+static gpointer gdk_pixbuf__tga_begin_load(GdkPixbufModuleSizeFunc f0,
+                                           GdkPixbufModulePreparedFunc f1,
+                                          GdkPixbufModuleUpdatedFunc f2,
+                                          gpointer udata, GError **err)
+{
+       TGAContext *ctx;
+
+       ctx = g_try_malloc(sizeof(TGAContext));
+       if (!ctx) {
+               g_set_error_literal(err, GDK_PIXBUF_ERROR, 
+                                    GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                    _("Cannot allocate memory for TGA context struct"));
+               return NULL;
+       }
+
+       ctx->hdr = NULL;
+       ctx->rowstride = 0;
+       ctx->run_length_encoded = FALSE;
+
+       ctx->cmap = NULL;
+       ctx->cmap_size = 0;
+
+       ctx->pbuf = NULL;
+       ctx->pbuf_bytes = 0;
+       ctx->pbuf_bytes_done = 0;
+       ctx->pptr = NULL;
+
+       ctx->in = io_buffer_new(err);
+       if (!ctx->in) {
+               g_free(ctx);
+               return NULL;
+       }
+
+       ctx->skipped_info = FALSE;
+       ctx->prepared = FALSE;
+       ctx->done = FALSE;
+
+       ctx->sfunc = f0;
+       ctx->pfunc = f1;
+       ctx->ufunc = f2;
+       ctx->udata = udata;
+
+       return ctx;
+}
+
+static gboolean gdk_pixbuf__tga_load_increment(gpointer data,
+                                              const guchar *buffer,
+                                              guint size,
+                                              GError **err)
+{
+       TGAContext *ctx = (TGAContext*) data;
+       g_return_val_if_fail(ctx != NULL, FALSE);
+
+       if (ctx->done)
+               return TRUE;
+
+       g_return_val_if_fail(buffer != NULL, TRUE);
+       ctx->in = io_buffer_append(ctx->in, buffer, size, err);
+       if (!ctx->in)
+               return FALSE;
+       if (!ctx->prepared) {
+               if (!try_preload(ctx, err))
+                       return FALSE;
+               if (!ctx->prepared)
+                       return TRUE;
+               if (ctx->in->size == 0)
+                       return TRUE;
+       }
+
+       if (ctx->run_length_encoded) {
+               if (!parse_rle_data(ctx, err))
+                       return FALSE;
+       } else {
+               while (ctx->in->size >= ctx->rowstride) {
+                       if (ctx->completed_lines >= ctx->pbuf->height) {
+                               g_set_error_literal(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED,
+                                                    _("Excess data in file"));
+                               return FALSE;
+                       }
+                       if (!parse_data_for_row(ctx, err))
+                               return FALSE;
+                       ctx->completed_lines++;
+               }
+       }
+
+       return TRUE;
+}
+
+static gboolean gdk_pixbuf__tga_stop_load(gpointer data, GError **err)
+{
+       TGAContext *ctx = (TGAContext *) data;
+       g_return_val_if_fail(ctx != NULL, FALSE);
+
+       if (ctx->hdr &&
+            (ctx->hdr->flags & TGA_ORIGIN_UPPER) == 0 && 
+            ctx->run_length_encoded && 
+            ctx->pbuf) {
+               pixbuf_flip_vertically (ctx->pbuf);
+               if (ctx->ufunc)
+                       (*ctx->ufunc) (ctx->pbuf, 0, 0,
+                                      ctx->pbuf->width, ctx->pbuf->height,
+                                      ctx->udata);
+       }
+       g_free (ctx->hdr);
+       if (ctx->cmap) {
+         g_free (ctx->cmap->cols);
+         g_free (ctx->cmap);
+       }
+       if (ctx->pbuf)
+               g_object_unref (ctx->pbuf);
+       if (ctx->in && ctx->in->size)
+               ctx->in = io_buffer_free_segment (ctx->in, ctx->in->size, err);
+       if (!ctx->in) {
+               g_free (ctx);
+               return FALSE;
+       }
+       io_buffer_free (ctx->in);
+       g_free (ctx);
+       return TRUE;
+}
+
+#ifndef INCLUDE_tga
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
+#else
+#define MODULE_ENTRY(function) void _gdk_pixbuf__tga_ ## function
+#endif
+
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
+{
+       module->begin_load = gdk_pixbuf__tga_begin_load;
+       module->stop_load = gdk_pixbuf__tga_stop_load;
+       module->load_increment = gdk_pixbuf__tga_load_increment;
+}
+
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
+{
+       static GdkPixbufModulePattern signature[] = {
+               { " \x1\x1", "x  ", 100 },
+               { " \x1\x9", "x  ", 100 },
+               { "  \x2", "xz ",  99 }, /* only 99 since .CUR also matches this */
+               { "  \x3", "xz ", 100 },
+               { "  \xa", "xz ", 100 },
+               { "  \xb", "xz ", 100 },
+               { NULL, NULL, 0 }
+       };
+       static gchar * mime_types[] = {
+               "image/x-tga",
+               NULL
+       };
+       static gchar * extensions[] = {
+               "tga",
+               "targa",
+               NULL
+       };
+
+       info->name = "tga";
+       info->signature = signature;
+       info->description = N_("The Targa image format");
+       info->mime_types = mime_types;
+       info->extensions = extensions;
+       info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
+       info->license = "LGPL";
+}
diff --git a/gdk-pixbuf/io-tiff.c b/gdk-pixbuf/io-tiff.c
new file mode 100644 (file)
index 0000000..49eea89
--- /dev/null
@@ -0,0 +1,874 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* GdkPixbuf library - TIFF image loader
+ *
+ * Copyright (C) 1999 Mark Crichton
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Authors: Mark Crichton <crichton@gimp.org>
+ *          Federico Mena-Quintero <federico@gimp.org>
+ *          Jonathan Blandford <jrb@redhat.com>
+ *          S�ren Sandmann <sandmann@daimi.au.dk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+/* Following code (almost) blatantly ripped from Imlib */
+
+#include "config.h"
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <tiffio.h>
+#include <errno.h>
+#include "gdk-pixbuf-private.h"
+
+#ifdef G_OS_WIN32
+#include <fcntl.h>
+#include <io.h>
+#define lseek(a,b,c) _lseek(a,b,c)
+#define O_RDWR _O_RDWR
+#endif
+\f
+
+typedef struct _TiffContext TiffContext;
+struct _TiffContext
+{
+       GdkPixbufModuleSizeFunc size_func;
+       GdkPixbufModulePreparedFunc prepare_func;
+       GdkPixbufModuleUpdatedFunc update_func;
+       gpointer user_data;
+        
+        guchar *buffer;
+        guint allocated;
+        guint used;
+        guint pos;
+};
+
+\f
+
+static char *global_error = NULL;
+static TIFFErrorHandler orig_error_handler = NULL;
+static TIFFErrorHandler orig_warning_handler = NULL;
+
+static void
+tiff_warning_handler (const char *mod, const char *fmt, va_list ap)
+{
+        /* Don't print anything; we should not be dumping junk to
+         * stderr, since that may be bad for some apps.
+         */
+
+        /* libTIFF seems to occasionally warn about things that
+         * are really errors, so maybe we should just call tiff_error_handler
+         * here.
+         */
+}
+
+static void
+tiff_error_handler (const char *mod, const char *fmt, va_list ap)
+{
+        if (global_error) {                
+                /* Blah, loader called us twice */
+                return;
+        }
+
+        global_error = g_strdup_vprintf (fmt, ap);
+}
+
+static void
+tiff_push_handlers (void)
+{
+        if (global_error)
+                g_warning ("TIFF loader left crufty global_error around, FIXME");
+        
+        orig_error_handler = TIFFSetErrorHandler (tiff_error_handler);
+        orig_warning_handler = TIFFSetWarningHandler (tiff_warning_handler);
+}
+
+static void
+tiff_pop_handlers (void)
+{
+        if (global_error)
+                g_warning ("TIFF loader left crufty global_error around, FIXME");
+        
+        TIFFSetErrorHandler (orig_error_handler);
+        TIFFSetWarningHandler (orig_warning_handler);
+}
+
+static void
+tiff_set_error (GError    **error,
+                int         error_code,
+                const char *msg)
+{
+        /* Take the error message from libtiff and merge it with
+         * some context we provide.
+         */
+        if (global_error) {
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             error_code,
+                             "%s%s%s", msg, ": ", global_error);
+
+                g_free (global_error);
+                global_error = NULL;
+        }
+        else {
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     error_code, msg);
+        }
+}
+
+\f
+
+static void free_buffer (guchar *pixels, gpointer data)
+{
+       g_free (pixels);
+}
+
+static GdkPixbuf *
+tiff_image_parse (TIFF *tiff, TiffContext *context, GError **error)
+{
+       guchar *pixels = NULL;
+       gint width, height, rowstride, bytes;
+       GdkPixbuf *pixbuf;
+       uint16 orientation = 0;
+       uint16 transform = 0;
+        uint16 codec;
+        gchar *icc_profile_base64;
+        const gchar *icc_profile;
+        guint icc_profile_size;
+        gint retval;
+
+        /* We're called with the lock held. */
+        
+        g_return_val_if_fail (global_error == NULL, NULL);
+
+       if (!TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width) || global_error) {
+                tiff_set_error (error,
+                                GDK_PIXBUF_ERROR_FAILED,
+                                _("Could not get image width (bad TIFF file)"));
+                return NULL;
+        }
+        
+        if (!TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height) || global_error) {
+                tiff_set_error (error,
+                                GDK_PIXBUF_ERROR_FAILED,
+                                _("Could not get image height (bad TIFF file)"));
+                return NULL;
+        }
+
+        if (width <= 0 || height <= 0) {
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("Width or height of TIFF image is zero"));
+                return NULL;                
+        }
+        
+        rowstride = width * 4;
+        if (rowstride / 4 != width) { /* overflow */
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("Dimensions of TIFF image too large"));
+                return NULL;                
+        }
+        
+        bytes = height * rowstride;
+        if (bytes / rowstride != height) { /* overflow */
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("Dimensions of TIFF image too large"));
+                return NULL;                
+        }
+
+       if (context && context->size_func) {
+                gint w = width;
+                gint h = height;
+               (* context->size_func) (&w, &h, context->user_data);
+                
+               /* This is a signal that this function is being called
+                  to support gdk_pixbuf_get_file_info, so we can stop
+                  parsing the tiff file at this point. It is not an
+                  error condition. */
+
+                if (w == 0 || h == 0)
+                    return NULL;
+        }
+
+        pixels = g_try_malloc (bytes);
+
+        if (!pixels) {
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                     _("Insufficient memory to open TIFF file"));
+                return NULL;
+        }
+
+       pixbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, TRUE, 8, 
+                                           width, height, rowstride,
+                                           free_buffer, NULL);
+        if (!pixbuf) {
+                g_free (pixels);
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                     _("Insufficient memory to open TIFF file"));
+                return NULL;
+        }
+
+       /* Set the "orientation" key associated with this image. libtiff 
+          orientation handling is odd, so further processing is required
+          by higher-level functions based on this tag. If the embedded
+          orientation tag is 1-4, libtiff flips/mirrors the image as
+          required, and no client processing is required - so we report 
+          no orientation. Orientations 5-8 require rotations which would 
+          swap the width and height of the image. libtiff does not do this. 
+          Instead it interprets orientations 5-8 the same as 1-4. 
+          See http://bugzilla.remotesensing.org/show_bug.cgi?id=1548.
+          To correct for this, the client must apply the transform normally
+          used for orientation 5 to both orientations 5 and 7, and apply
+          the transform normally used for orientation 7 for both
+          orientations 6 and 8. Then everythings works out OK! */
+       
+       TIFFGetField (tiff, TIFFTAG_ORIENTATION, &orientation);
+
+       switch (orientation) {
+               case 5:
+               case 7:
+                       transform = 5;
+                       break;
+               case 6:
+               case 8:
+                       transform = 7;
+                       break;
+               default:
+                       transform = 0;
+                       break;
+       }
+
+       if (transform > 0 ) {
+               gchar str[5];
+               g_snprintf (str, sizeof (str), "%d", transform);
+               gdk_pixbuf_set_option (pixbuf, "orientation", str);
+       }
+
+        TIFFGetField (tiff, TIFFTAG_COMPRESSION, &codec);
+        if (codec > 0) {
+          gchar str[5];
+          g_snprintf (str, sizeof (str), "%d", codec);
+          gdk_pixbuf_set_option (pixbuf, "compression", str);
+        }
+
+        /* Extract embedded ICC profile */
+        retval = TIFFGetField (tiff, TIFFTAG_ICCPROFILE, &icc_profile_size, &icc_profile);
+        if (retval == 1) {
+                icc_profile_base64 = g_base64_encode ((const guchar *) icc_profile, icc_profile_size);
+                gdk_pixbuf_set_option (pixbuf, "icc-profile", icc_profile_base64);
+                g_free (icc_profile_base64);
+        }
+
+       if (context && context->prepare_func)
+               (* context->prepare_func) (pixbuf, NULL, context->user_data);
+
+       if (!TIFFReadRGBAImageOriented (tiff, width, height, (uint32 *)pixels, ORIENTATION_TOPLEFT, 1) || global_error) {
+               tiff_set_error (error,
+                                GDK_PIXBUF_ERROR_FAILED,
+                                _("Failed to load RGB data from TIFF file"));
+               g_object_unref (pixbuf);
+               return NULL;
+       }
+
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+       /* Turns out that the packing used by TIFFRGBAImage depends on 
+         * the host byte order... 
+         */ 
+       while (pixels < pixbuf->pixels + bytes) {
+               uint32 pixel = *(uint32 *)pixels;
+               int r = TIFFGetR(pixel);
+               int g = TIFFGetG(pixel);
+               int b = TIFFGetB(pixel);
+               int a = TIFFGetA(pixel);
+               *pixels++ = r;
+               *pixels++ = g;
+               *pixels++ = b;
+               *pixels++ = a;
+       }
+#endif
+
+       if (context && context->update_func)
+               (* context->update_func) (pixbuf, 0, 0, width, height, context->user_data);
+
+        return pixbuf;
+}
+
+\f
+
+/* Static loader */
+
+static GdkPixbuf *
+gdk_pixbuf__tiff_image_load (FILE *f, GError **error)
+{
+        TIFF *tiff;
+        int fd;
+        GdkPixbuf *pixbuf;
+        
+        g_return_val_if_fail (f != NULL, NULL);
+
+        tiff_push_handlers ();
+        
+        fd = fileno (f);
+
+        /* On OSF, apparently fseek() works in some on-demand way, so
+         * the fseek gdk_pixbuf_new_from_file() doesn't work here
+         * since we are using the raw file descriptor. So, we call lseek() on the fd
+         * before using it. (#60840)
+         */
+        lseek (fd, 0, SEEK_SET);
+        tiff = TIFFFdOpen (fd, "libpixbuf-tiff", "r");
+        
+        if (!tiff || global_error) {
+                tiff_set_error (error,
+                                GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                _("Failed to open TIFF image"));
+                tiff_pop_handlers ();
+
+                return NULL;
+        }
+
+        pixbuf = tiff_image_parse (tiff, NULL, error);
+        
+        TIFFClose (tiff);
+        if (global_error) {
+                tiff_set_error (error,
+                                GDK_PIXBUF_ERROR_FAILED,
+                                _("TIFFClose operation failed"));
+        }
+        
+        tiff_pop_handlers ();
+
+        return pixbuf;
+}
+
+\f
+
+/* Progressive loader */
+
+static gpointer
+gdk_pixbuf__tiff_image_begin_load (GdkPixbufModuleSizeFunc size_func,
+                                   GdkPixbufModulePreparedFunc prepare_func,
+                                  GdkPixbufModuleUpdatedFunc update_func,
+                                  gpointer user_data,
+                                   GError **error)
+{
+       TiffContext *context;
+        
+       context = g_new0 (TiffContext, 1);
+       context->size_func = size_func;
+       context->prepare_func = prepare_func;
+       context->update_func = update_func;
+       context->user_data = user_data;
+        context->buffer = NULL;
+        context->allocated = 0;
+        context->used = 0;
+        context->pos = 0;
+        
+       return context;
+}
+
+static tsize_t
+tiff_load_read (thandle_t handle, tdata_t buf, tsize_t size)
+{
+        TiffContext *context = (TiffContext *)handle;
+        
+        if (context->pos + size > context->used)
+                return 0;
+        
+        memcpy (buf, context->buffer + context->pos, size);
+        context->pos += size;
+        return size;
+}
+
+static tsize_t
+tiff_load_write (thandle_t handle, tdata_t buf, tsize_t size)
+{
+        return -1;
+}
+
+static toff_t
+tiff_load_seek (thandle_t handle, toff_t offset, int whence)
+{
+        TiffContext *context = (TiffContext *)handle;
+        
+        switch (whence) {
+        case SEEK_SET:
+                if (offset > context->used)
+                        return -1;
+                context->pos = offset;
+                break;
+        case SEEK_CUR:
+                if (offset + context->pos >= context->used)
+                        return -1;
+                context->pos += offset;
+                break;
+        case SEEK_END:
+                if (offset + context->used > context->used)
+                        return -1;
+                context->pos = context->used + offset;
+                break;
+        default:
+                return -1;
+        }
+        return context->pos;
+}
+
+static int
+tiff_load_close (thandle_t context)
+{
+        return 0;
+}
+
+static toff_t
+tiff_load_size (thandle_t handle)
+{
+        TiffContext *context = (TiffContext *)handle;
+        
+        return context->used;
+}
+
+static int
+tiff_load_map_file (thandle_t handle, tdata_t *buf, toff_t *size)
+{
+        TiffContext *context = (TiffContext *)handle;
+        
+        *buf = context->buffer;
+        *size = context->used;
+        
+        return 0;
+}
+
+static void
+tiff_load_unmap_file (thandle_t handle, tdata_t data, toff_t offset)
+{
+}
+
+static gboolean
+gdk_pixbuf__tiff_image_stop_load (gpointer data,
+                                  GError **error)
+{
+        TiffContext *context = data;
+        TIFF *tiff;
+        gboolean retval;
+        
+        g_return_val_if_fail (data != NULL, FALSE);
+
+        tiff_push_handlers ();
+        
+        tiff = TIFFClientOpen ("libtiff-pixbuf", "r", data, 
+                               tiff_load_read, tiff_load_write, 
+                               tiff_load_seek, tiff_load_close, 
+                               tiff_load_size, 
+                               tiff_load_map_file, tiff_load_unmap_file);
+        if (!tiff || global_error) {
+                tiff_set_error (error,
+                                GDK_PIXBUF_ERROR_FAILED,
+                                _("Failed to load TIFF image"));
+                retval = FALSE;
+        } else {
+                GdkPixbuf *pixbuf;
+                
+                pixbuf = tiff_image_parse (tiff, context, error);
+                if (pixbuf)
+                        g_object_unref (pixbuf);
+                retval = pixbuf != NULL;
+                if (global_error)
+                        {
+                                tiff_set_error (error,
+                                                GDK_PIXBUF_ERROR_FAILED,
+                                                _("Failed to load TIFF image"));
+                                tiff_pop_handlers ();
+
+                                retval = FALSE;
+                        }
+        }
+
+        if (tiff)
+                TIFFClose (tiff);
+
+        g_assert (!global_error);
+        
+        g_free (context->buffer);
+        g_free (context);
+
+        tiff_pop_handlers ();
+
+        return retval;
+}
+
+static gboolean
+make_available_at_least (TiffContext *context, guint needed)
+{
+        guchar *new_buffer = NULL;
+        guint need_alloc;
+        
+        need_alloc = context->used + needed;
+        if (need_alloc > context->allocated) {
+                guint new_size = 1;
+                while (new_size < need_alloc)
+                        new_size *= 2;
+                
+                new_buffer = g_try_realloc (context->buffer, new_size);
+                if (new_buffer) {
+                        context->buffer = new_buffer;
+                        context->allocated = new_size;
+                        return TRUE;
+                }
+                return FALSE;
+        }
+        return TRUE;
+}
+
+static gboolean
+gdk_pixbuf__tiff_image_load_increment (gpointer data, const guchar *buf,
+                                       guint size, GError **error)
+{
+       TiffContext *context = (TiffContext *) data;
+        
+       g_return_val_if_fail (data != NULL, FALSE);
+        
+        if (!make_available_at_least (context, size)) {
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                     _("Insufficient memory to open TIFF file"));
+                return FALSE;
+        }
+        
+        memcpy (context->buffer + context->used, buf, size);
+        context->used += size;
+       return TRUE;
+}
+
+typedef struct {
+        gchar *buffer;
+        guint allocated;
+        guint used;
+        guint pos;
+} TiffSaveContext;
+
+static tsize_t
+tiff_save_read (thandle_t handle, tdata_t buf, tsize_t size)
+{
+        return -1;
+}
+
+static tsize_t
+tiff_save_write (thandle_t handle, tdata_t buf, tsize_t size)
+{
+        TiffSaveContext *context = (TiffSaveContext *)handle;
+
+        /* Modify buffer length */
+        if (context->pos + size > context->used)
+                context->used = context->pos + size;
+
+        /* Realloc */
+        if (context->used > context->allocated) {
+                context->buffer = g_realloc (context->buffer, context->pos + size);
+                context->allocated = context->used;
+        }
+
+        /* Now copy the data */
+        memcpy (context->buffer + context->pos, buf, size);
+
+        /* Update pos */
+        context->pos += size;
+
+        return size;
+}
+
+static toff_t
+tiff_save_seek (thandle_t handle, toff_t offset, int whence)
+{
+        TiffSaveContext *context = (TiffSaveContext *)handle;
+
+        switch (whence) {
+        case SEEK_SET:
+                context->pos = offset;
+                break;
+        case SEEK_CUR:
+                context->pos += offset;
+                break;
+        case SEEK_END:
+                context->pos = context->used + offset;
+                break;
+        default:
+                return -1;
+        }
+        return context->pos;
+}
+
+static int
+tiff_save_close (thandle_t context)
+{
+        return 0;
+}
+
+static toff_t
+tiff_save_size (thandle_t handle)
+{
+        return -1;
+}
+
+static TiffSaveContext *
+create_save_context (void)
+{
+        TiffSaveContext *context;
+
+        context = g_new (TiffSaveContext, 1);
+        context->buffer = NULL;
+        context->allocated = 0;
+        context->used = 0;
+        context->pos = 0;
+
+        return context;
+}
+
+static void
+free_save_context (TiffSaveContext *context)
+{
+        g_free (context->buffer);
+        g_free (context);
+}
+
+static gboolean
+gdk_pixbuf__tiff_image_save_to_callback (GdkPixbufSaveFunc   save_func,
+                                         gpointer            user_data,
+                                         GdkPixbuf          *pixbuf, 
+                                         gchar             **keys,
+                                         gchar             **values,
+                                         GError            **error)
+{
+        TIFF *tiff;
+        gint width, height, rowstride;
+        guchar *pixels;
+        gboolean has_alpha;
+        gushort alpha_samples[1] = { EXTRASAMPLE_UNASSALPHA };
+        int y;
+        TiffSaveContext *context;
+        gboolean retval;
+        guchar *icc_profile = NULL;
+        gsize icc_profile_size = 0;
+
+        tiff_push_handlers ();
+
+        context = create_save_context ();
+        tiff = TIFFClientOpen ("libtiff-pixbuf", "w", context,  
+                               tiff_save_read, tiff_save_write, 
+                               tiff_save_seek, tiff_save_close, 
+                               tiff_save_size, 
+                               NULL, NULL);
+
+        if (!tiff || global_error) {
+                tiff_set_error (error,
+                                GDK_PIXBUF_ERROR_FAILED,
+                                _("Failed to save TIFF image"));
+
+                tiff_pop_handlers ();
+
+                free_save_context (context);
+                return FALSE;
+        }
+
+        rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+        pixels = gdk_pixbuf_get_pixels (pixbuf);
+
+        has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
+
+        height = gdk_pixbuf_get_height (pixbuf);
+        width = gdk_pixbuf_get_width (pixbuf);
+
+        TIFFSetField (tiff, TIFFTAG_IMAGEWIDTH, width);
+        TIFFSetField (tiff, TIFFTAG_IMAGELENGTH, height);
+        TIFFSetField (tiff, TIFFTAG_BITSPERSAMPLE, 8);
+        TIFFSetField (tiff, TIFFTAG_SAMPLESPERPIXEL, has_alpha ? 4 : 3);
+        TIFFSetField (tiff, TIFFTAG_ROWSPERSTRIP, height);
+
+        /* libtiff supports a number of 'codecs' such as:
+           1 None, 2 Huffman, 5 LZW, 7 JPEG, 8 Deflate, see tiff.h */
+        if (keys && *keys && values && *values) {
+            guint i = 0;
+
+            while (keys[i]) {
+                if (g_str_equal (keys[i], "compression")) {
+                    guint16 codec = strtol (values[i], NULL, 0);
+                    if (TIFFIsCODECConfigured (codec))
+                        TIFFSetField (tiff, TIFFTAG_COMPRESSION, codec);
+                    else {
+                        tiff_set_error (error,
+                                        GDK_PIXBUF_ERROR_FAILED,
+                                        _("TIFF compression doesn't refer to a valid codec."));
+                        retval = FALSE;
+                        goto cleanup;
+                    }
+                } else if (g_str_equal (keys[i], "icc-profile")) {
+                        /* decode from base64 */
+                        icc_profile = g_base64_decode (values[i], &icc_profile_size);
+                        if (icc_profile_size < 127) {
+                            g_set_error (error,
+                                         GDK_PIXBUF_ERROR,
+                                         GDK_PIXBUF_ERROR_BAD_OPTION,
+                                         _("Color profile has invalid length %d."),
+                                         (gint)icc_profile_size);
+                            retval = FALSE;
+                            goto cleanup;
+                        }
+                }
+                i++;
+            }
+        }
+
+        if (has_alpha)
+                TIFFSetField (tiff, TIFFTAG_EXTRASAMPLES, 1, alpha_samples);
+
+        TIFFSetField (tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
+        TIFFSetField (tiff, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);        
+        TIFFSetField (tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+
+        if (icc_profile != NULL)
+                TIFFSetField (tiff, TIFFTAG_ICCPROFILE, icc_profile_size, icc_profile);
+
+        for (y = 0; y < height; y++) {
+                if (TIFFWriteScanline (tiff, pixels + y * rowstride, y, 0) == -1 ||
+                    global_error)
+                        break;
+        }
+
+        if (global_error) {
+                tiff_set_error (error,
+                                GDK_PIXBUF_ERROR_FAILED,
+                                _("Failed to write TIFF data"));
+
+                TIFFClose (tiff);
+                retval = FALSE;
+                goto cleanup;
+        }
+
+        TIFFClose (tiff);
+        if (global_error) {
+                tiff_set_error (error,
+                                GDK_PIXBUF_ERROR_FAILED,
+                                _("TIFFClose operation failed"));
+                retval = FALSE;
+                goto cleanup;
+        }
+
+
+        /* Now call the callback */
+        retval = save_func (context->buffer, context->used, error, user_data);
+
+cleanup:
+        g_free (icc_profile);
+        tiff_pop_handlers ();
+        free_save_context (context);
+        return retval;
+}
+
+static gboolean
+save_to_file_cb (const gchar *buf,
+                gsize count,
+                GError **error,
+                gpointer data)
+{
+       gint bytes;
+       
+       while (count > 0) {
+               bytes = fwrite (buf, sizeof (gchar), count, (FILE *) data);
+               if (bytes <= 0)
+                       break;
+               count -= bytes;
+               buf += bytes;
+       }
+
+       if (count) {
+               g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_FAILED,
+                                     _("Couldn't write to TIFF file"));
+               return FALSE;
+       }
+       
+       return TRUE;
+}
+
+static gboolean
+gdk_pixbuf__tiff_image_save (FILE          *f, 
+                             GdkPixbuf     *pixbuf, 
+                             gchar        **keys,
+                             gchar        **values,
+                             GError       **error)
+{
+       return gdk_pixbuf__tiff_image_save_to_callback (save_to_file_cb,
+                                                        f, pixbuf, keys,
+                                                        values, error);
+}
+
+#ifndef INCLUDE_tiff
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
+#else
+#define MODULE_ENTRY(function) void _gdk_pixbuf__tiff_ ## function
+#endif
+
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
+{
+        module->load = gdk_pixbuf__tiff_image_load;
+        module->begin_load = gdk_pixbuf__tiff_image_begin_load;
+        module->stop_load = gdk_pixbuf__tiff_image_stop_load;
+        module->load_increment = gdk_pixbuf__tiff_image_load_increment;
+        module->save = gdk_pixbuf__tiff_image_save;
+        module->save_to_callback = gdk_pixbuf__tiff_image_save_to_callback;
+}
+
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
+{
+        static GdkPixbufModulePattern signature[] = {
+                { "MM \x2a", "  z ", 100 },
+                { "II\x2a ", "   z", 100 },
+                { "II* \020   CR\002 ", "   z zzz   z", 0 },
+                { NULL, NULL, 0 }
+        };
+       static gchar * mime_types[] = {
+               "image/tiff",
+               NULL
+       };
+       static gchar * extensions[] = {
+               "tiff",
+               "tif",
+               NULL
+       };
+
+       info->name = "tiff";
+        info->signature = signature;
+       info->description = N_("The TIFF image format");
+       info->mime_types = mime_types;
+       info->extensions = extensions;
+        /* not threadsafe, due to the error handler handling */
+       info->flags = GDK_PIXBUF_FORMAT_WRITABLE;
+       info->license = "LGPL";
+}
diff --git a/gdk-pixbuf/io-wbmp.c b/gdk-pixbuf/io-wbmp.c
new file mode 100644 (file)
index 0000000..e961322
--- /dev/null
@@ -0,0 +1,379 @@
+/* -*- mode: C; c-file-style: "linux" -*- */
+/* GdkPixbuf library - Wireless Bitmap image loader
+ *
+ * Copyright (C) 2000 Red Hat, Inc.
+ *
+ * Authors: Elliot Lee <sopwith@redhat.com
+ *
+ * Based on io-bmp.c
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+/*
+
+Known bugs:
+        * Since this is based off the libgd implementation, no extended headers implemented (not required for a WAP client)
+*/
+
+#include "config.h"
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include "gdk-pixbuf-private.h"
+
+\f
+
+/* Progressive loading */
+
+struct wbmp_progressive_state {
+  GdkPixbufModulePreparedFunc prepared_func;
+  GdkPixbufModuleUpdatedFunc updated_func;
+  gpointer user_data;
+
+  guint need_type : 1;
+  guint need_header : 1;
+  guint need_width : 1;
+  guint need_height : 1;
+  guint needmore : 1;
+  guint call_progressive_updates : 1;
+
+  guchar last_buf[16]; /* Just needs to be big enough to hold the largest datum requestable via 'getin' */
+  guint last_len;
+
+  int type;
+  int width, height, curx, cury;
+
+  GdkPixbuf *pixbuf;   /* Our "target" */
+};
+
+static gpointer
+gdk_pixbuf__wbmp_image_begin_load(GdkPixbufModuleSizeFunc size_func, 
+                                  GdkPixbufModulePreparedFunc prepared_func,
+                                 GdkPixbufModuleUpdatedFunc updated_func,
+                                  gpointer user_data,
+                                  GError **error);
+
+static gboolean gdk_pixbuf__wbmp_image_stop_load(gpointer data, GError **error);
+static gboolean gdk_pixbuf__wbmp_image_load_increment(gpointer data,
+                                                      const guchar * buf,
+                                                      guint size,
+                                                      GError **error);
+
+/* 
+ * func - called when we have pixmap created (but no image data)
+ * user_data - passed as arg 1 to func
+ * return context (opaque to user)
+ */
+
+static gpointer
+gdk_pixbuf__wbmp_image_begin_load(GdkPixbufModuleSizeFunc size_func, 
+                                  GdkPixbufModulePreparedFunc prepared_func,
+                                  GdkPixbufModuleUpdatedFunc updated_func,
+                                  gpointer user_data,
+                                  GError **error)
+{
+       struct wbmp_progressive_state *context;
+
+       context = g_new0(struct wbmp_progressive_state, 1);
+       context->prepared_func = prepared_func;
+       context->updated_func = updated_func;
+       context->user_data = user_data;
+
+       context->needmore = context->need_type = context->need_header = context->need_width = context->need_height = TRUE;
+       context->call_progressive_updates = TRUE;
+       context->pixbuf = NULL;
+
+       return (gpointer) context;
+}
+
+/*
+ * context - returned from image_begin_load
+ *
+ * free context, unref gdk_pixbuf
+ */
+static gboolean gdk_pixbuf__wbmp_image_stop_load(gpointer data,
+                                                 GError **error)
+{
+       struct wbmp_progressive_state *context =
+           (struct wbmp_progressive_state *) data;
+
+        /* FIXME this thing needs to report errors if
+         * we have unused image data
+         */
+        
+       g_return_val_if_fail(context != NULL, TRUE);
+       if (context->pixbuf)
+         g_object_unref(context->pixbuf);
+
+       g_free(context);
+
+        return TRUE;
+}
+
+static gboolean
+getin(struct wbmp_progressive_state *context, const guchar **buf, guint *buf_size, guchar *ptr, int datum_size)
+{
+  int last_num, buf_num;
+
+  if((context->last_len + *buf_size) < datum_size)
+    return FALSE;
+
+  /* We know we can pull it out of there */
+  last_num = MIN(datum_size, context->last_len);
+  buf_num = MIN(datum_size-last_num, *buf_size);
+  memcpy(ptr, context->last_buf, last_num);
+  memcpy(ptr+last_num, *buf, buf_num);
+        
+  context->last_len -= last_num;
+  if(context->last_len)
+    memmove(context->last_buf, context->last_buf+last_num, context->last_len);
+  *buf_size -= buf_num;
+  *buf += buf_num;
+
+  return TRUE;
+}
+
+static gboolean
+save_rest(struct wbmp_progressive_state *context, const guchar *buf, guint buf_size)
+{
+  if(buf_size > (sizeof(context->last_buf) - context->last_len))
+    return FALSE;
+
+  memcpy(context->last_buf+context->last_len, buf, buf_size);
+  context->last_len += buf_size;
+
+  return TRUE;
+}
+
+static gboolean
+get_mbi(struct wbmp_progressive_state *context, const guchar **buf, guint *buf_size, int *val)
+{
+  guchar intbuf[16];
+  int n;
+  gboolean rv;
+
+  *val = 0;
+  n = 0;
+  do {
+    rv = getin(context, buf, buf_size, intbuf+n, 1);
+    if(!rv)
+      goto out;
+    *val <<= 7;
+    *val |= intbuf[n] & 0x7F;
+    n++;
+  } while(n < sizeof(intbuf) && (intbuf[n-1] & 0x80));
+
+ out:
+  if(!rv || (intbuf[n-1] & 0x80))
+    {
+      rv = save_rest(context, intbuf, n);
+
+      if(!rv)
+       g_error("Couldn't save_rest of intbuf");
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+/*
+ * context - from image_begin_load
+ * buf - new image data
+ * size - length of new image data
+ *
+ * append image data onto inrecrementally built output image
+ */
+static gboolean gdk_pixbuf__wbmp_image_load_increment(gpointer data,
+                                                      const guchar * buf,
+                                                      guint size, GError **error)
+{
+       struct wbmp_progressive_state *context =
+           (struct wbmp_progressive_state *) data;
+       gboolean bv = FALSE;
+
+       do
+         {
+           if(context->need_type)
+             {
+               guchar val;
+
+               bv = getin(context, &buf, &size, &val, 1);
+               if(bv)
+                 {
+                   context->type = val;
+                   context->need_type = FALSE;
+                 }
+             }
+           else if(context->need_header)
+             {
+               guchar val;
+
+               bv = getin(context, &buf, &size, &val, 1);
+               if(bv)
+                 {
+                   /* We skip over the extended header - val is unused */
+                   if(!(val & 0x80))
+                     context->need_header = FALSE;
+                 }
+             }
+           else if(context->need_width)
+             {
+               bv = get_mbi(context, &buf, &size, &context->width);
+               if(bv) {
+                 context->need_width = FALSE;
+
+                  if (context->width <= 0) {
+                   g_set_error_literal (error,
+                                         GDK_PIXBUF_ERROR,
+                                         GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                         _("Image has zero width"));
+
+                   return FALSE;
+                 }
+                }
+               
+             }
+           else if(context->need_height)
+             {
+               bv = get_mbi(context, &buf, &size, &context->height);
+               if(bv)
+                 {
+                   context->need_height = FALSE;
+
+                   if (context->height <= 0) {
+                     g_set_error_literal (error,
+                                           GDK_PIXBUF_ERROR,
+                                           GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                           _("Image has zero height"));
+                     
+                     return FALSE;
+                   }
+
+                   context->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, context->width, context->height);
+                   
+                   if (!context->pixbuf) {
+                     g_set_error_literal (error,
+                                           GDK_PIXBUF_ERROR,
+                                           GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                           _("Not enough memory to load image"));
+                     return FALSE;
+                   }
+
+
+                   if(context->prepared_func)
+                     context->prepared_func(context->pixbuf, NULL, context->user_data);
+                 }
+             }
+           else if(context->needmore)
+             {
+               int first_row;
+               first_row = context->cury;
+               for( ; context->cury < context->height; context->cury++, context->curx = 0)
+                 {
+                   for( ; context->curx < context->width; context->curx += 8)
+                     {
+                       guchar byte;
+                       guchar *ptr;
+                       int xoff;
+                       bv = getin(context, &buf, &size, &byte, 1);
+                       if(!bv)
+                         goto out;
+
+                       ptr = context->pixbuf->pixels + context->pixbuf->rowstride * context->cury + context->curx * 3;
+                       for(xoff = 7; xoff >= 0; xoff--, ptr += 3)
+                         {
+                           guchar pixval;
+
+                           if (context->curx + (7 - xoff) == context->width)
+                             break;
+
+                           if(byte & (1<<xoff))
+                             pixval = 0xFF;
+                           else
+                             pixval = 0x0;
+
+                           ptr[0] = ptr[1] = ptr[2] = pixval;
+                         }
+                     }
+                 }
+               context->needmore = FALSE;
+
+             out:
+               if(context->updated_func)
+                 context->updated_func(context->pixbuf, 0, first_row, context->width, context->cury - first_row + 1,
+                                       context->user_data);
+             }
+           else
+             bv = FALSE; /* Nothing left to do, stop feeding me data! */
+
+         } while(bv);
+
+       if(size) {
+         bv = save_rest(context, buf, size);
+         if (!bv) {
+             g_set_error_literal (error,
+                                   GDK_PIXBUF_ERROR,
+                                   GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                   _("Couldn't save the rest"));
+
+             return FALSE;
+         }
+       }
+       return TRUE;
+}
+
+#ifndef INCLUDE_wbmp
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
+#else
+#define MODULE_ENTRY(function) void _gdk_pixbuf__wbmp_ ## function
+#endif
+
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
+{
+       module->begin_load = gdk_pixbuf__wbmp_image_begin_load;
+       module->stop_load = gdk_pixbuf__wbmp_image_stop_load;
+       module->load_increment = gdk_pixbuf__wbmp_image_load_increment;
+}
+
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
+{
+       static GdkPixbufModulePattern signature[] = {
+               { "  ",    "zz", 1 }, 
+               { " \140", "z ", 1 },
+               { " \100", "z ", 1 },
+               { " \040", "z ", 1 },
+               { NULL, NULL, 0 }
+       };
+       static gchar * mime_types[] = {
+               "image/vnd.wap.wbmp",
+               NULL
+       };
+       static gchar * extensions[] = {
+               "wbmp",
+               NULL
+       };
+
+       info->name = "wbmp";
+       info->signature = signature;
+       info->description = N_("The WBMP image format");
+       info->mime_types = mime_types;
+       info->extensions = extensions;
+       info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
+       info->license = "LGPL";
+}
diff --git a/gdk-pixbuf/io-xbm.c b/gdk-pixbuf/io-xbm.c
new file mode 100644 (file)
index 0000000..4f3e1e8
--- /dev/null
@@ -0,0 +1,506 @@
+/* -*- mode: C; c-file-style: "linux" -*- */
+/* GdkPixbuf library - XBM image loader
+ *
+ * Copyright (C) 1999 Mark Crichton
+ * Copyright (C) 1999 The Free Software Foundation
+ * Copyright (C) 2001 Eazel, Inc.
+ *
+ * Authors: Mark Crichton <crichton@gimp.org>
+ *          Federico Mena-Quintero <federico@gimp.org>
+ *          Jonathan Blandford <jrb@redhat.com>
+ *         John Harper <jsh@eazel.com>
+ *
+ * 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.
+ */
+
+/* Following code adapted from io-tiff.c, which was ``(almost) blatantly
+   ripped from Imlib'' */
+
+#include "config.h"
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <errno.h>
+#include "gdk-pixbuf-private.h"
+#include <glib/gstdio.h>
+
+
+\f
+
+typedef struct _XBMData XBMData;
+struct _XBMData
+{
+       GdkPixbufModulePreparedFunc prepare_func;
+       GdkPixbufModuleUpdatedFunc update_func;
+       gpointer user_data;
+
+       gchar *tempname;
+       FILE *file;
+       gboolean all_okay;
+};
+
+\f
+/* xbm parser borrowed from xc/lib/X11/RdBitF.c */
+
+#define MAX_SIZE 255
+
+/* shared data for the image read/parse logic */
+static short hex_table[256];           /* conversion value */
+static gboolean initialized = FALSE;   /* easier to fill in at run time */
+
+
+/* Table index for the hex values. Initialized once, first time.
+ * Used for translation value or delimiter significance lookup.
+ */
+static void
+init_hex_table (void)
+{
+       /*
+        * We build the table at run time for several reasons:
+        *
+        * 1. portable to non-ASCII machines.
+        * 2. still reentrant since we set the init flag after setting table.
+        * 3. easier to extend.
+        * 4. less prone to bugs.
+        */
+       hex_table['0'] = 0;
+       hex_table['1'] = 1;
+       hex_table['2'] = 2;
+       hex_table['3'] = 3;
+       hex_table['4'] = 4;
+       hex_table['5'] = 5;
+       hex_table['6'] = 6;
+       hex_table['7'] = 7;
+       hex_table['8'] = 8;
+       hex_table['9'] = 9;
+       hex_table['A'] = 10;
+       hex_table['B'] = 11;
+       hex_table['C'] = 12;
+       hex_table['D'] = 13;
+       hex_table['E'] = 14;
+       hex_table['F'] = 15;
+       hex_table['a'] = 10;
+       hex_table['b'] = 11;
+       hex_table['c'] = 12;
+       hex_table['d'] = 13;
+       hex_table['e'] = 14;
+       hex_table['f'] = 15;
+
+       /* delimiters of significance are flagged w/ negative value */
+       hex_table[' '] = -1;
+       hex_table[','] = -1;
+       hex_table['}'] = -1;
+       hex_table['\n'] = -1;
+       hex_table['\t'] = -1;
+
+       initialized = TRUE;
+}
+
+/* Read next hex value in the input stream, return -1 if EOF */
+static int
+next_int (FILE *fstream)
+{
+       int ch;
+       int value = 0;
+       int gotone = 0;
+       int done = 0;
+    
+       /* loop, accumulate hex value until find delimiter 
+          skip any initial delimiters found in read stream */
+
+       while (!done) {
+               ch = getc (fstream);
+               if (ch == EOF) {
+                       value = -1;
+                       done++;
+               } else {
+                       /* trim high bits, check type and accumulate */
+                       ch &= 0xff;
+                       if (g_ascii_isxdigit (ch)) {
+                               value = (value << 4) + g_ascii_xdigit_value (ch);
+                               gotone++;
+                       } else if ((hex_table[ch]) < 0 && gotone) {
+                               done++;
+                       }
+               }
+       }
+       return value;
+}
+
+static gboolean
+read_bitmap_file_data (FILE    *fstream,
+                      guint   *width, 
+                      guint   *height,
+                      guchar **data,
+                      int     *x_hot, 
+                      int     *y_hot)
+{
+       guchar *bits = NULL;            /* working variable */
+       char line[MAX_SIZE];            /* input line from file */
+       int size;                       /* number of bytes of data */
+       char name_and_type[MAX_SIZE];   /* an input line */
+       char *type;                     /* for parsing */
+       int value;                      /* from an input line */
+       int version10p;                 /* boolean, old format */
+       int padding;                    /* to handle alignment */
+       int bytes_per_line;             /* per scanline of data */
+       guint ww = 0;                   /* width */
+       guint hh = 0;                   /* height */
+       int hx = -1;                    /* x hotspot */
+       int hy = -1;                    /* y hotspot */
+
+       /* first time initialization */
+       if (!initialized) {
+               init_hex_table ();
+       }
+
+       /* error cleanup and return macro */
+#define        RETURN(code) { g_free (bits); return code; }
+
+       while (fgets (line, MAX_SIZE, fstream)) {
+               if (strlen (line) == MAX_SIZE-1)
+                       RETURN (FALSE);
+               if (sscanf (line,"#define %s %d",name_and_type,&value) == 2) {
+                       if (!(type = strrchr (name_and_type, '_')))
+                               type = name_and_type;
+                       else {
+                               type++;
+                       }
+
+                       if (!strcmp ("width", type)) {
+                                if (value <= 0)
+                                        RETURN (FALSE);
+                               ww = (unsigned int) value;
+                        }
+                       if (!strcmp ("height", type)) {
+                                if (value <= 0)
+                                        RETURN (FALSE);
+                               hh = (unsigned int) value;
+                        }
+                       if (!strcmp ("hot", type)) {
+                               if (type-- == name_and_type
+                                   || type-- == name_and_type)
+                                       continue;
+                               if (!strcmp ("x_hot", type))
+                                       hx = value;
+                               if (!strcmp ("y_hot", type))
+                                       hy = value;
+                       }
+                       continue;
+               }
+    
+               if (sscanf (line, "static short %s = {", name_and_type) == 1)
+                       version10p = 1;
+               else if (sscanf (line,"static const unsigned char %s = {",name_and_type) == 1)
+                       version10p = 0;
+               else if (sscanf (line,"static unsigned char %s = {",name_and_type) == 1)
+                       version10p = 0;
+               else if (sscanf (line, "static const char %s = {", name_and_type) == 1)
+                       version10p = 0;
+               else if (sscanf (line, "static char %s = {", name_and_type) == 1)
+                       version10p = 0;
+               else
+                       continue;
+
+               if (!(type = strrchr (name_and_type, '_')))
+                       type = name_and_type;
+               else
+                       type++;
+
+               if (strcmp ("bits[]", type))
+                       continue;
+    
+               if (!ww || !hh)
+                       RETURN (FALSE);
+
+               if ((ww % 16) && ((ww % 16) < 9) && version10p)
+                       padding = 1;
+               else
+                       padding = 0;
+
+               bytes_per_line = (ww+7)/8 + padding;
+
+               size = bytes_per_line * hh;
+                if (size / bytes_per_line != hh) /* overflow */
+                        RETURN (FALSE);
+               bits = g_malloc (size);
+
+               if (version10p) {
+                       unsigned char *ptr;
+                       int bytes;
+
+                       for (bytes = 0, ptr = bits; bytes < size; (bytes += 2)) {
+                               if ((value = next_int (fstream)) < 0)
+                                       RETURN (FALSE);
+                               *(ptr++) = value;
+                               if (!padding || ((bytes+2) % bytes_per_line))
+                                       *(ptr++) = value >> 8;
+                       }
+               } else {
+                       unsigned char *ptr;
+                       int bytes;
+
+                       for (bytes = 0, ptr = bits; bytes < size; bytes++, ptr++) {
+                               if ((value = next_int (fstream)) < 0) 
+                                       RETURN (FALSE);
+                               *ptr=value;
+                       }
+               }
+               break;
+       }
+
+       if (!bits)
+               RETURN (FALSE);
+
+       *data = bits;
+       *width = ww;
+       *height = hh;
+       if (x_hot)
+               *x_hot = hx;
+       if (y_hot)
+               *y_hot = hy;
+
+       return TRUE;
+}
+
+\f
+
+static GdkPixbuf *
+gdk_pixbuf__xbm_image_load_real (FILE     *f, 
+                                XBMData  *context, 
+                                GError  **error)
+{
+       guint w, h;
+       int x_hot, y_hot;
+       guchar *data, *ptr;
+       guchar *pixels;
+       guint row_stride;
+       int x, y;
+       int reg = 0; /* Quiet compiler */
+       int bits;
+
+       GdkPixbuf *pixbuf;
+
+       if (!read_bitmap_file_data (f, &w, &h, &data, &x_hot, &y_hot)) {
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("Invalid XBM file"));
+               return NULL;
+       }
+
+       pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, w, h);
+
+        if (pixbuf == NULL) {
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                     _("Insufficient memory to load XBM image file"));
+                return NULL;
+        }
+        
+       if (x_hot != -1 && y_hot != -1) {
+               gchar hot[10];
+               g_snprintf (hot, 10, "%d", x_hot);
+               gdk_pixbuf_set_option (pixbuf, "x_hot", hot);
+               g_snprintf (hot, 10, "%d", y_hot);
+               gdk_pixbuf_set_option (pixbuf, "y_hot", hot);
+       }
+
+       pixels = gdk_pixbuf_get_pixels (pixbuf);
+       row_stride = gdk_pixbuf_get_rowstride (pixbuf);
+
+       if (context && context->prepare_func)
+               (* context->prepare_func) (pixbuf, NULL, context->user_data);
+
+
+       /* Initialize PIXBUF */
+
+       ptr = data;
+       for (y = 0; y < h; y++) {
+               bits = 0;
+               for (x = 0; x < w; x++) {
+                       guchar channel;
+                       if (bits == 0) {
+                               reg = *ptr++;
+                               bits = 8;
+                       }
+
+                       channel = (reg & 1) ? 0 : 255;
+                       reg >>= 1;
+                       bits--;
+
+                       pixels[x*3+0] = channel;
+                       pixels[x*3+1] = channel;
+                       pixels[x*3+2] = channel;
+               }
+               pixels += row_stride;
+       }
+       g_free (data);
+
+       if (context) {
+               if (context->update_func)
+                       (* context->update_func) (pixbuf, 0, 0, w, h, context->user_data);
+       }
+
+       return pixbuf;
+}
+
+\f
+/* Static loader */
+
+static GdkPixbuf *
+gdk_pixbuf__xbm_image_load (FILE    *f, 
+                           GError **error)
+{
+       return gdk_pixbuf__xbm_image_load_real (f, NULL, error);
+}
+
+\f
+/* Progressive loader */
+
+/*
+ * Proper XBM progressive loading isn't implemented.  Instead we write
+ * it to a file, then load the file when it's done.  It's not pretty.
+ */
+
+static gpointer
+gdk_pixbuf__xbm_image_begin_load (GdkPixbufModuleSizeFunc       size_func,
+                                  GdkPixbufModulePreparedFunc   prepare_func,
+                                 GdkPixbufModuleUpdatedFunc    update_func,
+                                 gpointer                      user_data,
+                                 GError                      **error)
+{
+       XBMData *context;
+       gint fd;
+
+       context = g_new (XBMData, 1);
+       context->prepare_func = prepare_func;
+       context->update_func = update_func;
+       context->user_data = user_data;
+       context->all_okay = TRUE;
+       fd = g_file_open_tmp ("gdkpixbuf-xbm-tmp.XXXXXX",
+                             &context->tempname,
+                             NULL);
+       if (fd < 0) {
+               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;
+}
+
+static gboolean
+gdk_pixbuf__xbm_image_stop_load (gpointer   data,
+                                 GError   **error)
+{
+       XBMData *context = (XBMData*) data;
+        gboolean retval = TRUE;
+
+       g_return_val_if_fail (data != NULL, TRUE);
+
+       fflush (context->file);
+       rewind (context->file);
+       if (context->all_okay) {
+                GdkPixbuf *pixbuf;
+                pixbuf = gdk_pixbuf__xbm_image_load_real (context->file, 
+                                                         context,
+                                                          error);
+                if (pixbuf == NULL)
+                        retval = FALSE;
+               else
+                       g_object_unref (pixbuf);
+        }
+
+       fclose (context->file);
+       g_unlink (context->tempname);
+       g_free (context->tempname);
+       g_free ((XBMData *) context);
+
+        return retval;
+}
+
+static gboolean
+gdk_pixbuf__xbm_image_load_increment (gpointer       data,
+                                      const guchar  *buf,
+                                      guint          size,
+                                      GError       **error)
+{
+       XBMData *context = (XBMData *) data;
+
+       g_return_val_if_fail (data != NULL, FALSE);
+
+       if (fwrite (buf, sizeof (guchar), size, context->file) != size) {
+               gint save_errno = errno;
+               context->all_okay = FALSE;
+                g_set_error_literal (error,
+                                     G_FILE_ERROR,
+                                     g_file_error_from_errno (save_errno),
+                                     _("Failed to write to temporary file when loading XBM image"));
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+#ifndef INCLUDE_xbm
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
+#else
+#define MODULE_ENTRY(function) void _gdk_pixbuf__xbm_ ## function
+#endif
+
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
+{
+       module->load = gdk_pixbuf__xbm_image_load;
+       module->begin_load = gdk_pixbuf__xbm_image_begin_load;
+       module->stop_load = gdk_pixbuf__xbm_image_stop_load;
+       module->load_increment = gdk_pixbuf__xbm_image_load_increment;
+}
+
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
+{
+       static GdkPixbufModulePattern signature[] = {
+               { "#define ", NULL, 100 },
+               { "/*", NULL, 50 },
+               { NULL, NULL, 0 }
+       };
+       static gchar * mime_types[] = {
+               "image/x-xbitmap",
+               NULL
+       };
+       static gchar * extensions[] = {
+               "xbm",
+               NULL
+       };
+
+       info->name = "xbm";
+       info->signature = signature;
+       info->description = N_("The XBM image format");
+       info->mime_types = mime_types;
+       info->extensions = extensions;
+       info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
+       info->license = "LGPL";
+}
diff --git a/gdk-pixbuf/io-xpm.c b/gdk-pixbuf/io-xpm.c
new file mode 100644 (file)
index 0000000..d65d942
--- /dev/null
@@ -0,0 +1,822 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* GdkPixbuf library - XPM image loader
+ *
+ * Copyright (C) 1999 Mark Crichton
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Authors: Mark Crichton <crichton@gimp.org>
+ *          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 Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h> /* for unlink */
+#endif
+#include <errno.h>
+#include "gdk-pixbuf-private.h"
+#include <glib/gstdio.h>
+
+
+\f
+
+/* I have must have done something to deserve this.
+ * XPM is such a crappy format to handle.
+ * This code is an ugly hybred from gdkpixmap.c
+ * modified to respect transparent colors.
+ * It's still a mess, though.
+ */
+
+enum buf_op {
+       op_header,
+       op_cmap,
+       op_body
+};
+
+typedef struct {
+       gchar *color_string;
+       guint16 red;
+       guint16 green;
+       guint16 blue;
+       gint transparent;
+} XPMColor;
+
+struct file_handle {
+       FILE *infile;
+       gchar *buffer;
+       guint buffer_size;
+};
+
+struct mem_handle {
+       const gchar **data;
+       int offset;
+};
+
+/* The following 2 routines (parse_color, find_color) come from Tk, via the Win32
+ * port of GDK. The licensing terms on these (longer than the functions) is:
+ *
+ * This software is copyrighted by the Regents of the University of
+ * California, Sun Microsystems, Inc., and other parties.  The following
+ * terms apply to all files associated with the software unless explicitly
+ * disclaimed in individual files.
+ * 
+ * The authors hereby grant permission to use, copy, modify, distribute,
+ * and license this software and its documentation for any purpose, provided
+ * that existing copyright notices are retained in all copies and that this
+ * notice is included verbatim in any distributions. No written agreement,
+ * license, or royalty fee is required for any of the authorized uses.
+ * Modifications to this software may be copyrighted by their authors
+ * and need not follow the licensing terms described here, provided that
+ * the new terms are clearly indicated on the first page of each file where
+ * they apply.
+ * 
+ * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
+ * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
+ * DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
+ * IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
+ * NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+ * MODIFICATIONS.
+ * 
+ * GOVERNMENT USE: If you are acquiring this software on behalf of the
+ * U.S. government, the Government shall have only "Restricted Rights"
+ * in the software and related documentation as defined in the Federal 
+ * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you
+ * are acquiring the software on behalf of the Department of Defense, the
+ * software shall be classified as "Commercial Computer Software" and the
+ * Government shall have only "Restricted Rights" as defined in Clause
+ * 252.227-7013 (c) (1) of DFARs.  Notwithstanding the foregoing, the
+ * authors grant the U.S. Government and others acting in its behalf
+ * permission to use and distribute the software in accordance with the
+ * terms specified in this license.
+ */
+
+#include "xpm-color-table.h"
+/*
+ *----------------------------------------------------------------------
+ *
+ * find_color --
+ *
+ *     This routine finds the color entry that corresponds to the
+ *     specified color.
+ *
+ * Results:
+ *     Returns non-zero on success.  The RGB values of the XColor
+ *     will be initialized to the proper values on success.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+compare_xcolor_entries (const void *a, const void *b)
+{
+  return g_ascii_strcasecmp ((const char *) a, 
+                            color_names + ((const XPMColorEntry *)b)->name_offset);
+}
+
+static gboolean
+find_color(const char *name,
+          XPMColor   *colorPtr)
+{
+       XPMColorEntry *found;
+
+       found = bsearch (name, xColors, G_N_ELEMENTS (xColors), sizeof (XPMColorEntry),
+                        compare_xcolor_entries);
+       if (found == NULL)
+         return FALSE;
+       
+       colorPtr->red = (found->red * 65535) / 255;
+       colorPtr->green = (found->green * 65535) / 255;
+       colorPtr->blue = (found->blue * 65535) / 255;
+       
+       return TRUE;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * parse_color --
+ *
+ *     Partial implementation of X color name parsing interface.
+ *
+ * Results:
+ *     Returns TRUE on success.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static gboolean
+parse_color (const char *spec,
+            XPMColor   *colorPtr)
+{
+       if (spec[0] == '#') {
+               char fmt[16];
+               int i, red, green, blue;
+
+               if ((i = strlen (spec + 1)) % 3) {
+                       return FALSE;
+               }
+               i /= 3;
+
+               g_snprintf (fmt, 16, "%%%dx%%%dx%%%dx", i, i, i);
+
+               if (sscanf (spec + 1, fmt, &red, &green, &blue) != 3) {
+                       return FALSE;
+               }
+               if (i == 4) {
+                       colorPtr->red = red;
+                       colorPtr->green = green;
+                       colorPtr->blue = blue;
+               } else if (i == 1) {
+                       colorPtr->red = (red * 65535) / 15;
+                       colorPtr->green = (green * 65535) / 15;
+                       colorPtr->blue = (blue * 65535) / 15;
+               } else if (i == 2)
+               {
+                       colorPtr->red = (red * 65535) / 255;
+                       colorPtr->green = (green * 65535) / 255;
+                       colorPtr->blue = (blue * 65535) / 255;
+               } else /* if (i == 3) */ {
+                       colorPtr->red = (red * 65535) / 4095;
+                       colorPtr->green = (green * 65535) / 4095;
+                       colorPtr->blue = (blue * 65535) / 4095;
+               }
+       } else {
+               if (!find_color(spec, colorPtr))
+                       return FALSE;
+       }
+       return TRUE;
+}
+
+static gint
+xpm_seek_string (FILE *infile, const gchar *str)
+{
+       char instr[1024];
+
+       while (!feof (infile)) {
+               if (fscanf (infile, "%1023s", instr) < 0)
+                        return FALSE;
+               if (strcmp (instr, str) == 0)
+                       return TRUE;
+       }
+
+       return FALSE;
+}
+
+static gint
+xpm_seek_char (FILE *infile, gchar c)
+{
+       gint b, oldb;
+
+       while ((b = getc (infile)) != EOF) {
+               if (c != b && b == '/') {
+                       b = getc (infile);
+                       if (b == EOF)
+                               return FALSE;
+
+                       else if (b == '*') {    /* we have a comment */
+                               b = -1;
+                               do {
+                                       oldb = b;
+                                       b = getc (infile);
+                                       if (b == EOF)
+                                               return FALSE;
+                               } while (!(oldb == '*' && b == '/'));
+                       }
+               } else if (c == b)
+                       return TRUE;
+       }
+
+       return FALSE;
+}
+
+static gint
+xpm_read_string (FILE *infile, gchar **buffer, guint *buffer_size)
+{
+       gint c;
+       guint cnt = 0, bufsiz, ret = FALSE;
+       gchar *buf;
+
+       buf = *buffer;
+       bufsiz = *buffer_size;
+       if (buf == NULL) {
+               bufsiz = 10 * sizeof (gchar);
+               buf = g_new (gchar, bufsiz);
+       }
+
+       do {
+               c = getc (infile);
+       } while (c != EOF && c != '"');
+
+       if (c != '"')
+               goto out;
+
+       while ((c = getc (infile)) != EOF) {
+               if (cnt == bufsiz) {
+                       guint new_size = bufsiz * 2;
+
+                       if (new_size > bufsiz)
+                               bufsiz = new_size;
+                       else
+                               goto out;
+
+                       buf = g_realloc (buf, bufsiz);
+                       buf[bufsiz - 1] = '\0';
+               }
+
+               if (c != '"')
+                       buf[cnt++] = c;
+               else {
+                       buf[cnt] = 0;
+                       ret = TRUE;
+                       break;
+               }
+       }
+
+ out:
+       buf[bufsiz - 1] = '\0'; /* ensure null termination for errors */
+       *buffer = buf;
+       *buffer_size = bufsiz;
+       return ret;
+}
+
+static gchar *
+xpm_extract_color (const gchar *buffer)
+{
+       const gchar *p = &buffer[0];
+       gint new_key = 0;
+       gint key = 0;
+       gint current_key = 1;
+       gint space = 128;
+       gchar word[129], color[129], current_color[129];
+       gchar *r; 
+       
+       word[0] = '\0';
+       color[0] = '\0';
+       current_color[0] = '\0';
+        while (1) {
+               /* skip whitespace */
+               for (; *p != '\0' && g_ascii_isspace (*p); p++) {
+               } 
+               /* copy word */
+               for (r = word; *p != '\0' && !g_ascii_isspace (*p) && r - word < sizeof (word) - 1; p++, r++) {
+                       *r = *p;
+               }
+               *r = '\0';
+               if (*word == '\0') {
+                       if (color[0] == '\0')  /* incomplete colormap entry */
+                               return NULL;                            
+                       else  /* end of entry, still store the last color */
+                               new_key = 1;
+               } 
+               else if (key > 0 && color[0] == '\0')  /* next word must be a color name part */
+                       new_key = 0;
+               else {
+                       if (strcmp (word, "c") == 0)
+                               new_key = 5;
+                       else if (strcmp (word, "g") == 0)
+                               new_key = 4;
+                       else if (strcmp (word, "g4") == 0)
+                               new_key = 3;
+                       else if (strcmp (word, "m") == 0)
+                               new_key = 2;
+                       else if (strcmp (word, "s") == 0)
+                               new_key = 1;
+                       else 
+                               new_key = 0;
+               }
+               if (new_key == 0) {  /* word is a color name part */
+                       if (key == 0)  /* key expected */
+                               return NULL;
+                       /* accumulate color name */
+                       if (color[0] != '\0') {
+                               strncat (color, " ", space);
+                               space -= MIN (space, 1);
+                       }
+                       strncat (color, word, space);
+                       space -= MIN (space, strlen (word));
+               }
+               else {  /* word is a key */
+                       if (key > current_key) {
+                               current_key = key;
+                               strcpy (current_color, color);
+                       }
+                       space = 128;
+                       color[0] = '\0';
+                       key = new_key;
+                       if (*p == '\0') break;
+               }
+               
+       }
+       if (current_key > 1)
+               return g_strdup (current_color);
+       else
+               return NULL; 
+}
+
+/* (almost) direct copy from gdkpixmap.c... loads an XPM from a file */
+
+static const gchar *
+file_buffer (enum buf_op op, gpointer handle)
+{
+       struct file_handle *h = handle;
+
+       switch (op) {
+       case op_header:
+               if (xpm_seek_string (h->infile, "XPM") != TRUE)
+                       break;
+
+               if (xpm_seek_char (h->infile, '{') != TRUE)
+                       break;
+               /* Fall through to the next xpm_seek_char. */
+
+       case op_cmap:
+               xpm_seek_char (h->infile, '"');
+               fseek (h->infile, -1, SEEK_CUR);
+               /* Fall through to the xpm_read_string. */
+
+       case op_body:
+               if(!xpm_read_string (h->infile, &h->buffer, &h->buffer_size))
+                       return NULL;
+               return h->buffer;
+
+       default:
+               g_assert_not_reached ();
+       }
+
+       return NULL;
+}
+
+/* This reads from memory */
+static const gchar *
+mem_buffer (enum buf_op op, gpointer handle)
+{
+       struct mem_handle *h = handle;
+       switch (op) {
+       case op_header:
+       case op_cmap:
+       case op_body:
+                if (h->data[h->offset]) {
+                        const gchar* retval;
+
+                        retval = h->data[h->offset];
+                        h->offset += 1;
+                        return retval;
+                }
+                break;
+
+       default:
+               g_assert_not_reached ();
+                break;
+       }
+
+       return NULL;
+}
+
+/* This function does all the work. */
+static GdkPixbuf *
+pixbuf_create_from_xpm (const gchar * (*get_buf) (enum buf_op op, gpointer handle), gpointer handle,
+                        GError **error)
+{
+       gint w, h, n_col, cpp, x_hot, y_hot, items;
+       gint cnt, xcnt, ycnt, wbytes, n;
+       gint is_trans = FALSE;
+       const gchar *buffer;
+        gchar *name_buf;
+       gchar pixel_str[32];
+       GHashTable *color_hash;
+       XPMColor *colors, *color, *fallbackcolor;
+       guchar *pixtmp;
+       GdkPixbuf *pixbuf;
+
+       fallbackcolor = NULL;
+
+       buffer = (*get_buf) (op_header, handle);
+       if (!buffer) {
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("No XPM header found"));
+               return NULL;
+       }
+       items = sscanf (buffer, "%d %d %d %d %d %d", &w, &h, &n_col, &cpp, &x_hot, &y_hot);
+
+       if (items != 4 && items != 6) {
+               g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("Invalid XPM header"));
+               return NULL;
+       }
+
+       if (w <= 0) {
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("XPM file has image width <= 0"));
+               return NULL;
+
+       }
+       if (h <= 0) {
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("XPM file has image height <= 0"));
+               return NULL;
+
+       }
+       if (cpp <= 0 || cpp >= 32) {
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("XPM has invalid number of chars per pixel"));
+               return NULL;
+       }
+       if (n_col <= 0 || 
+           n_col >= G_MAXINT / (cpp + 1) || 
+           n_col >= G_MAXINT / sizeof (XPMColor)) {
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("XPM file has invalid number of colors"));
+               return NULL;
+       }
+
+       /* The hash is used for fast lookups of color from chars */
+       color_hash = g_hash_table_new (g_str_hash, g_str_equal);
+
+       name_buf = g_try_malloc (n_col * (cpp + 1));
+       if (!name_buf) {
+               g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                     _("Cannot allocate memory for loading XPM image"));
+               g_hash_table_destroy (color_hash);
+               return NULL;
+       }
+       colors = (XPMColor *) g_try_malloc (sizeof (XPMColor) * n_col);
+       if (!colors) {
+               g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                     _("Cannot allocate memory for loading XPM image"));
+               g_hash_table_destroy (color_hash);
+               g_free (name_buf);
+               return NULL;
+       }
+
+       for (cnt = 0; cnt < n_col; cnt++) {
+               gchar *color_name;
+
+               buffer = (*get_buf) (op_cmap, handle);
+               if (!buffer) {
+                        g_set_error_literal (error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                             _("Cannot read XPM colormap"));
+                       g_hash_table_destroy (color_hash);
+                       g_free (name_buf);
+                       g_free (colors);
+                       return NULL;
+               }
+
+               color = &colors[cnt];
+               color->color_string = &name_buf[cnt * (cpp + 1)];
+               strncpy (color->color_string, buffer, cpp);
+               color->color_string[cpp] = 0;
+               buffer += strlen (color->color_string);
+               color->transparent = FALSE;
+
+               color_name = xpm_extract_color (buffer);
+
+               if ((color_name == NULL) || (g_ascii_strcasecmp (color_name, "None") == 0)
+                   || (parse_color (color_name, color) == FALSE)) {
+                       color->transparent = TRUE;
+                       color->red = 0;
+                       color->green = 0;
+                       color->blue = 0;
+                       is_trans = TRUE;
+               }
+
+               g_free (color_name);
+               g_hash_table_insert (color_hash, color->color_string, color);
+
+               if (cnt == 0)
+                       fallbackcolor = color;
+       }
+
+       pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, is_trans, 8, w, h);
+
+       if (!pixbuf) {
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                     _("Cannot allocate memory for loading XPM image"));
+               g_hash_table_destroy (color_hash);
+               g_free (colors);
+               g_free (name_buf);
+               return NULL;
+       }
+
+       wbytes = w * cpp;
+
+       for (ycnt = 0; ycnt < h; ycnt++) {
+               pixtmp = pixbuf->pixels + ycnt * pixbuf->rowstride;
+
+               buffer = (*get_buf) (op_body, handle);
+               if ((!buffer) || (strlen (buffer) < wbytes))
+                       continue;
+
+               for (n = 0, xcnt = 0; n < wbytes; n += cpp, xcnt++) {
+                       strncpy (pixel_str, &buffer[n], cpp);
+                       pixel_str[cpp] = 0;
+
+                       color = g_hash_table_lookup (color_hash, pixel_str);
+
+                       /* Bad XPM...punt */
+                       if (!color)
+                               color = fallbackcolor;
+
+                       *pixtmp++ = color->red >> 8;
+                       *pixtmp++ = color->green >> 8;
+                       *pixtmp++ = color->blue >> 8;
+
+                       if (is_trans && color->transparent)
+                               *pixtmp++ = 0;
+                       else if (is_trans)
+                               *pixtmp++ = 0xFF;
+               }
+       }
+
+       g_hash_table_destroy (color_hash);
+       g_free (colors);
+       g_free (name_buf);
+
+       if (items == 6) {
+               gchar hot[10];
+               g_snprintf (hot, 10, "%d", x_hot);
+               gdk_pixbuf_set_option (pixbuf, "x_hot", hot);
+               g_snprintf (hot, 10, "%d", y_hot);
+               gdk_pixbuf_set_option (pixbuf, "y_hot", hot);
+
+       }
+
+       return pixbuf;
+}
+
+/* Shared library entry point for file loading */
+static GdkPixbuf *
+gdk_pixbuf__xpm_image_load (FILE *f,
+                            GError **error)
+{
+       GdkPixbuf *pixbuf;
+       struct file_handle h;
+
+       memset (&h, 0, sizeof (h));
+       h.infile = f;
+       pixbuf = pixbuf_create_from_xpm (file_buffer, &h, error);
+       g_free (h.buffer);
+
+       return pixbuf;
+}
+
+/* Shared library entry point for memory loading */
+static GdkPixbuf *
+gdk_pixbuf__xpm_image_load_xpm_data (const gchar **data)
+{
+        GdkPixbuf *pixbuf;
+        struct mem_handle h;
+        GError *error = NULL;
+        
+        h.data = data;
+        h.offset = 0;
+        
+       pixbuf = pixbuf_create_from_xpm (mem_buffer, &h, &error);
+
+        if (error) {
+                g_warning ("Inline XPM data is broken: %s", error->message);
+                g_error_free (error);
+                error = NULL;
+        }
+        
+       return pixbuf;
+}
+
+/* Progressive loader */
+typedef struct _XPMContext XPMContext;
+struct _XPMContext
+{
+       GdkPixbufModulePreparedFunc prepare_func;
+       GdkPixbufModuleUpdatedFunc 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.
+ */
+static gpointer
+gdk_pixbuf__xpm_image_begin_load (GdkPixbufModuleSizeFunc size_func,
+                                  GdkPixbufModulePreparedFunc prepare_func,
+                                  GdkPixbufModuleUpdatedFunc update_func,
+                                  gpointer user_data,
+                                  GError **error)
+{
+       XPMContext *context;
+       gint fd;
+
+       context = g_new (XPMContext, 1);
+       context->prepare_func = prepare_func;
+       context->update_func = update_func;
+       context->user_data = user_data;
+       context->all_okay = TRUE;
+       fd = g_file_open_tmp ("gdkpixbuf-xpm-tmp.XXXXXX", &context->tempname,
+                            NULL);
+       if (fd < 0) {
+               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;
+}
+
+static gboolean
+gdk_pixbuf__xpm_image_stop_load (gpointer data,
+                                 GError **error)
+{
+       XPMContext *context = (XPMContext*) data;
+       GdkPixbuf *pixbuf;
+       gboolean retval = FALSE;
+       
+       g_return_val_if_fail (data != NULL, FALSE);
+
+       fflush (context->file);
+       rewind (context->file);
+       if (context->all_okay) {
+               pixbuf = gdk_pixbuf__xpm_image_load (context->file, error);
+
+               if (pixbuf != NULL) {
+                      if (context->prepare_func)
+                              (* context->prepare_func) (pixbuf,
+                                                         NULL,
+                                                         context->user_data);
+                      if (context->update_func)
+                              (* context->update_func) (pixbuf, 0, 0, pixbuf->width, pixbuf->height, context->user_data);
+                       g_object_unref (pixbuf);
+
+                       retval = TRUE;
+               }
+       }
+
+       fclose (context->file);
+       g_unlink (context->tempname);
+       g_free (context->tempname);
+       g_free ((XPMContext *) context);
+
+       return retval;
+}
+
+static gboolean
+gdk_pixbuf__xpm_image_load_increment (gpointer data,
+                                      const guchar *buf,
+                                      guint    size,
+                                      GError **error)
+{
+       XPMContext *context = (XPMContext *) data;
+
+       g_return_val_if_fail (data != NULL, FALSE);
+
+       if (fwrite (buf, sizeof (guchar), size, context->file) != size) {
+              gint save_errno = errno;
+               context->all_okay = FALSE;
+               g_set_error_literal (error,
+                                    G_FILE_ERROR,
+                                    g_file_error_from_errno (save_errno),
+                                    _("Failed to write to temporary file when loading XPM image"));
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+#ifndef INCLUDE_xpm
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
+#else
+#define MODULE_ENTRY(function) void _gdk_pixbuf__xpm_ ## function
+#endif
+
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
+{
+       module->load = gdk_pixbuf__xpm_image_load;
+       module->load_xpm_data = gdk_pixbuf__xpm_image_load_xpm_data;
+       module->begin_load = gdk_pixbuf__xpm_image_begin_load;
+       module->stop_load = gdk_pixbuf__xpm_image_stop_load;
+       module->load_increment = gdk_pixbuf__xpm_image_load_increment;
+}
+
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
+{
+       static GdkPixbufModulePattern signature[] = {
+               { "/* XPM */", NULL, 100 },
+               { NULL, NULL, 0 }
+       };
+       static gchar * mime_types[] = {
+               "image/x-xpixmap",
+               NULL
+       };
+       static gchar * extensions[] = {
+               "xpm",
+               NULL
+       };
+
+       info->name = "xpm";
+       info->signature = signature;
+       info->description = N_("The XPM image format");
+       info->mime_types = mime_types;
+       info->extensions = extensions;
+       info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
+       info->license = "LGPL";
+}
diff --git a/gdk-pixbuf/makefile.msc b/gdk-pixbuf/makefile.msc
new file mode 100644 (file)
index 0000000..7f6486a
--- /dev/null
@@ -0,0 +1,197 @@
+TOP = ..\..
+PRJ_TOP = ..
+PACKAGE = gdk_pixbuf
+PKG_VER = $(GDK_PIXBUF_VER)
+
+!INCLUDE $(TOP)/glib/build/win32/make.msc
+
+!IFNDEF PERL
+PERL = perl
+!ENDIF
+
+GDK_PIXBUF_VER = 2.0
+
+# -DINCLUDE_gdiplus _replaces_ -DINCLUDE_bmp -DINCLUDE_gif -DINCLUDE_ico -DINCLUDE_jpeg  -DINCLUDE_tiff
+# but not yet -DINCLUDE_png 
+##USEGDIP=1
+# to get _working_ include modules we need respective defines ...
+#   
+BUILT_IN_FORMATS = \
+!IFDEF USEGDIP
+       -DINCLUDE_gdiplus \
+!ELSE
+       -DINCLUDE_bmp -DINCLUDE_gif -DINCLUDE_ico -DINCLUDE_jpeg -DINCLUDE_tiff \
+!ENDIF
+       -DINCLUDE_png \
+       -DINCLUDE_xpm -DINCLUDE_wbmp \
+       -DINCLUDE_pnm -DINCLUDE_ras
+
+PKG_CFLAGS = -FImsvc_recommended_pragmas.h \
+!IFNDEF USEGDIP
+       $(JPEG_CFLAGS) $(TIFF_CFLAGS) \
+!ENDIF
+       -I. -I.. $(GLIB_CFLAGS) \
+       $(BUILT_IN_FORMATS) \
+       $(PNG_CFLAGS) $(INTL_CFLAGS) \
+       $(G_DEBUGGING) \
+       -DGDK_PIXBUF_ENABLE_BACKEND \
+       -DGTK_PREFIX=\"/just/some/non/existing/path/\" \
+       -UUSE_GMODULE # use built-in
+#      -DUSE_GMODULE -DPIXBUF_LIBDIR=\".\"
+
+PKG_LINK = $(GLIB_LIBS) \
+!IFNDEF USEGDIP
+       $(TIFF_LIBS) $(JPEG_LIBS) \
+!ENDIF
+       $(PNG_LIBS) $(INTL_LIBS) \
+       pixops\pixops.lib \
+OBJECTS_NON_NATIVE = \
+       io-bmp.obj \
+       io-gif.obj \
+       io-ico.obj \
+       io-tiff.obj \
+       io-jpeg.obj \
+
+OBJECTS_NATIVE = \
+       io-gdip-animation.obj \
+       io-gdip-bmp.obj \
+       io-gdip-emf.obj \
+       io-gdip-gif.obj \
+       io-gdip-ico.obj \
+       io-gdip-jpeg.obj \
+       io-gdip-tiff.obj \
+       io-gdip-utils.obj \
+       io-gdip-wmf.obj
+
+OBJECTS = \
+       gdk-pixbuf-enum-types.obj \
+       gdk-pixbuf-animation.obj \
+       gdk-pixbuf-data.obj \
+       gdk-pixbuf-io.obj \
+       gdk-pixbuf-loader.obj \
+       gdk-pixbuf-scale.obj \
+       gdk-pixbuf-scaled-anim.obj \
+       gdk-pixbuf-util.obj \
+       gdk-pixbuf.obj \
+       gdk-pixbuf-simple-anim.obj \
+       gdk-pixdata.obj \
+       io-wbmp.obj \
+       io-gif-animation.obj \
+       io-png.obj \
+       io-pnm.obj \
+       io-ras.obj \
+       io-xpm.obj \
+!IFDEF USEGDIP
+       $(OBJECTS_NATIVE)
+!ELSE
+       $(OBJECTS_NON_NATIVE)
+!ENDIF
+
+gdk_pixbuf_headers =   \
+       gdk-pixbuf.h    \
+       gdk-pixbuf-core.h       \
+       gdk-pixbuf-loader.h     \
+       gdk-pixbuf-transform.h
+
+gdk-pixbuf-marshal.h: gdk-pixbuf-marshal.list
+       ..\..\glib\gobject\glib-genmarshal --prefix=_gdk_pixbuf_marshal gdk-pixbuf-marshal.list --header >gdk-pixbuf-marshal.h
+
+gdk-pixbuf-marshal.c: gdk-pixbuf-marshal.h gdk-pixbuf-marshal.list
+       ..\..\glib\gobject\glib-genmarshal --prefix=_gdk_pixbuf_marshal gdk-pixbuf-marshal.list --body >gdk-pixbuf-marshal.c
+
+gdk-pixbuf-alias.h: gdk-pixbuf.symbols
+       perl makegdkpixbufalias.pl < gdk-pixbuf.symbols > gdk-pixbuf-alias.h
+
+gdk_pixbuf.def: gdk-pixbuf.symbols makefile.msc
+       echo EXPORTS > gdk_pixbuf.def
+       cl /EP -DINCLUDE_VARIABLES -DG_OS_WIN32 -DALL_FILES \
+       -DG_GNUC_MALLOC= -DG_GNUC_CONST= -DG_GNUC_NULL_TERMINATED= -DG_GNUC_NORETURN= -DG_GNUC_PRINTF=;G_GNUC_PRINTF \
+       gdk-pixbuf.symbols >> gdk_pixbuf.def
+
+gdk-pixbuf-aliasdef.c: gdk-pixbuf.symbols
+        perl makegdkpixbufalias.pl -def < gdk-pixbuf.symbols > gdk-pixbuf-aliasdef.c
+
+## common stuff
+
+INSTALL = copy
+
+CFLAGS = -I. -DHAVE_CONFIG_H
+
+sub-pixops :
+       cd pixops
+       nmake -f makefile.msc
+       cd ..
+
+## targets
+all : \
+       $(PRJ_TOP)\config.h \
+       gdk-pixbuf-alias.h \
+       gdk-pixbuf-aliasdef.c \
+       gdk-pixbuf-marshal.h \
+       gdk-pixbuf-marshal.c \
+       sub-pixops \
+       lib$(PACKAGE)-$(PKG_VER)-0.dll \
+       $(PACKAGE)-$(PKG_VER)s.lib \
+#      make-inline-pixbuf.exe \
+       gdk-pixbuf-csource.exe \
+       test-gdk-pixbuf.exe
+
+$(PACKAGE).res : $(PACKAGE).rc
+       rc -DBUILDNUMBER=0 -r -fo $(PACKAGE).res $(PACKAGE).rc
+
+$(PACKAGE)-$(PKG_VER)s.lib : $(OBJECTS)
+       lib /out:$(PACKAGE)-$(PKG_VER)s.lib $(OBJECTS) pixops\pixops.lib
+
+lib$(PACKAGE)-$(PKG_VER)-0.dll : $(OBJECTS) $(PACKAGE).def $(PACKAGE).res
+       $(CC) $(CFLAGS) -LD -Fe$@ $(OBJECTS) $(PKG_LINK) user32.lib advapi32.lib ole32.lib wsock32.lib $(PACKAGE).res \
+       $(LDFLAGS) /implib:$(PACKAGE)-$(PKG_VER).lib /def:$(PACKAGE).def
+
+make-inline-pixbuf.exe : make-inline-pixbuf.c
+       $(CC) $(PKG_CFLAGS) -Femake-inline-pixbuf.exe make-inline-pixbuf.c $(PKG_LINK) $(PACKAGE)-$(PKG_VER).lib
+
+gdk-pixbuf-csource.exe : gdk-pixbuf-csource.c
+       $(CC) $(PKG_CFLAGS) -Fegdk-pixbuf-csource.exe gdk-pixbuf-csource.c $(PKG_LINK) $(PACKAGE)-$(PKG_VER).lib
+
+test-gdk-pixbuf.exe : test-gdk-pixbuf.c
+       $(CC) $(PKG_CFLAGS) -Fetest-gdk-pixbuf.exe test-gdk-pixbuf.c $(PKG_LINK) $(PACKAGE)-$(PKG_VER).lib
+
+#
+# gdk-pixbuf-enum-types.h
+#
+gdk-pixbuf-enum-types.h : $(gdk_pixbuf_headers) makefile.msc
+       $(PERL) $(GLIB)\gobject\glib-mkenums \
+               --fhead "#ifndef __GDK_PIXBUF__ENUM_TYPES_H__\n#define __GDK_PIXBUF_ENUM_TYPES_H__\n" \
+               --fprod "/* enumerations from \"@filename@\" */\n" \
+               --vhead "GType @enum_name@_get_type (void);\n#define GDK_TYPE_@ENUMSHORT@ (@enum_name@_get_type())\n"         \
+               --ftail "#endif /* __GDK_PIXBUF_ENUM_TYPES_H__ */" \
+               $(gdk_pixbuf_headers) ) > gdk-pixbuf-enum-types.h
+
+#
+# gdk-pixbuf-enum-types.c
+#
+gdk-pixbuf-enum-types.c: $(gdk_pixbuf_headers) makefile.msc
+       $(PERL) $(GLIB)\gobject\glib-mkenums \
+               --fhead "#include <gdk-pixbuf/gdk-pixbuf.h>" \
+               --fprod "\n/* enumerations from \"@filename@\" */" \
+               --vhead "GType\n@enum_name@_get_type (void)\n{\n  static GType etype = 0;\n  if (etype == 0) {\n    static const G@Type@Value values[] = {"       \
+               --vprod "      { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \
+               --vtail "      { 0, NULL, NULL }\n    };\n    etype = g_@type@_register_static (\"@EnumName@\", values);\n  }\n  return etype;\n}\n" \
+                 $(gdk_pixbuf_headers) > gdk-pixbuf-enum-types.c
+
+gdk-pixbuf-enum-types.obj : gdk-pixbuf-enum-types.c gdk-pixbuf-enum-types.h
+
+$(PRJ_TOP)\config.h: $(PRJ_TOP)\config.h.win32
+       copy $(PRJ_TOP)\config.h.win32 $(PRJ_TOP)\config.h
+
+.c.obj :
+       $(CC) $(CFLAGS) -GD -c $(PKG_CFLAGS) $<
+
+clean::
+       del config.h
+       del gdk-pixbuf-marshal.h
+       del gdk-pixbuf-marshal.c
+       del gdk-pixbuf-alaias.h
+
+
+
diff --git a/gdk-pixbuf/pixops/DETAILS b/gdk-pixbuf/pixops/DETAILS
new file mode 100644 (file)
index 0000000..acf16f5
--- /dev/null
@@ -0,0 +1,355 @@
+General ideas of Pixops
+=======================
+
+ - Gain speed by special-casing the common case, and using
+   generic code to handle the uncommon case.
+
+ - Most of the time in scaling an image is in the center;
+   however code that can handle edges properly is slow
+   because it needs to deal with the possibility of running
+   off the edge. So make the fast case code only handle
+   the centers, and use generic, slow, code for the edges,
+
+Structure of Pixops
+===================
+
+The code of pixops can roughly be grouped into four parts:
+
+ - Filter computation functions
+
+ - Functions for scaling or compositing lines and pixels
+   using precomputed filters
+
+ - pixops process, the central driver that iterates through
+   the image calling pixel or line functions as necessary
+   
+ - Wrapper functions (pixops_scale/composite/composite_color)
+   that compute the filter, chooses the line and pixel functions
+   and then call pixops_processs with the filter, line,
+   and pixel functions.
+
+
+pixops process is a pretty scary looking function:
+
+static void
+pixops_process (guchar         *dest_buf,
+               int             render_x0,
+               int             render_y0,
+               int             render_x1,
+               int             render_y1,
+               int             dest_rowstride,
+               int             dest_channels,
+               gboolean        dest_has_alpha,
+               const guchar   *src_buf,
+               int             src_width,
+               int             src_height,
+               int             src_rowstride,
+               int             src_channels,
+               gboolean        src_has_alpha,
+               double          scale_x,
+               double          scale_y,
+               int             check_x,
+               int             check_y,
+               int             check_size,
+               guint32         color1,
+               guint32         color2,
+               PixopsFilter   *filter,
+               PixopsLineFunc  line_func,
+               PixopsPixelFunc pixel_func)
+
+(Some of the arguments should be moved into structures. It's basically
+"all the arguments to pixops_composite_color plus three more") The
+arguments can be divided up into:
+
+
+Information about the destination buffer
+
+   guchar *dest_buf, int dest_rowstride, int dest_channels, gboolean dest_has_alpha,
+
+Information about the source buffer
+
+   guchar *src_buf,  int src_rowstride,  int src_channels,  gboolean src_has_alpha,
+   int src_width, int src_height,
+
+Information on how to scale the source buf and the region of the scaled source
+to render onto the destination buffer
+
+   int render_x0, int render_y0, int render_x1, int render_y1
+   double scale_x, double scale_y
+
+Information about a constant color or check pattern onto which to to composite
+
+   int check_x,        int check_y, int check_size, guint32 color1, guint32 color2
+
+Information precomputed to use during the scale operation
+
+   PixopsFilter *filter, PixopsLineFunc line_func, OixopsPixelFunc pixel_func
+
+
+Filter computation
+==================
+
+The PixopsFilter structure looks like:
+
+struct _PixopsFilter
+{
+  int *weights;
+  int n_x;
+  int n_y;
+  double x_offset;
+  double y_offset;
+}; 
+
+
+'weights' is an array of size:
+
+ weights[SUBSAMPLE][SUBSAMPLE][n_x][n_y]
+
+SUBSAMPLE is a constant - currently 16 in pixops.c.
+
+
+In order to compute a scaled destination pixel we convolve
+an array of n_x by n_y source pixels with one of
+the SUBSAMPLE * SUBSAMPLE filter matrices stored
+in weights. The choice of filter matrix is determined
+by the fractional part of the source location.
+
+To compute dest[i,j] we do the following:
+
+ x = i * scale_x + x_offset;
+ y = i * scale_x + y_offset;
+ x_int = floor(x)
+ y_int = floor(y)
+
+ C = weights[SUBSAMPLE*(x - x_int)][SUBSAMPLE*(y - y_int)]
+ total  = sum[l=0..n_x-1, j=0..n_y-1] (C[l,m] * src[x_int + l, x_int + m])
+
+The filter weights are integers scaled so that the total of the
+weights in the weights array is equal to 65536.
+
+When the source does not have alpha, we simply compute each channel
+as above, so total is in the range [0,255*65536]
+
+ dest = src / 65536
+
+When the source does have alpha, then we need to compute using
+"pre-multiplied alpha":
+
+ a_total = sum (C[l,m] * src_a[x_int + l, x_int + m])
+ c_total = sum (C[l,m] * src_a[x_int + l, x_int + m] * src_c[x_int + l, x_int + m])
+This gives us a result for c_total in the range of [0,255*a_total]
+ c_dest = c_total / a_total
+
+Mathematical aside:
+
+The process of producing a destination filter consists
+of:
+
+ - Producing a continuous approximation to the source
+   image via interpolation. 
+
+ - Sampling that continuous approximation with filter.
+
+This is representable as:
+
+ S(x,y) = sum[i=-inf,inf; j=-inf,inf] A(frac(x),frac(y))[i,j] * S[floor(x)+i,floor(y)+j]
+
+ D[i,j] = Integral(s=-inf,inf; t=-inf,inf) B(i+x,j+y) S((i+x)/scale_x,(i+y)/scale_y)
+By reordering the sums and integrals, you get something of the form:
+
+ D[i,j] = sum[l=-inf,inf; m=-inf;inf] C[l,m] S[i+l,j+l]
+
+The arrays in weights are the C[l,m] above, and are thus
+determined by the interpolating algorithm in use and the
+sampling filter:
+
+                                       INTERPOLATE       SAMPLE
+ ART_FILTER_NEAREST                nearest neighbour     point
+ ART_FILTER_TILES                  nearest neighbour      box
+ ART_FILTER_BILINEAR (scale < 1)   nearest neighbour      box   (scale < 1)
+ ART_FILTER_BILINEAR (scale > 1)       bilinear           point  (scale > 1)
+ ART_FILTER_HYPER                      bilinear           box
+
+Pixel Functions
+===============
+
+typedef void (*PixopsPixelFunc) (guchar *dest, int dest_x, int dest_channels, int dest_has_alpha,
+                                int src_has_alpha, 
+                                 int check_size, guint32 color1, guint32 color2,
+                                int r, int g, int b, int a);
+
+The arguments here are:
+
+ dest: location to store the output pixel
+ dest_x: x coordinate of destination (for handling checks)
+ dest_has_alpha, dest_channels: Information about the destination pixbuf
+ src_has_alpha: Information about the source pixbuf
+
+ check_size, color1, color2: Information for color background for composite_color variant
+ r,g,b,a - scaled red, green, blue and alpha
+
+r,g,b are premultiplied alpha.
+
+ a is in [0,65536*255]
+ r is in [0,255*a]
+ g is in [0,255*a]
+ b is in [0,255*a]
+
+If src_has_alpha is false, then a will be 65536*255, allowing optimization.
+
+
+Line functions
+==============
+
+typedef guchar *(*PixopsLineFunc) (int *weights, int n_x, int n_y,
+                                  guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
+                                  guchar **src, int src_channels, gboolean src_has_alpha,
+                                  int x_init, int x_step, int src_width,
+                                  int check_size, guint32 color1, guint32 color2);
+
+The argumets are:
+
+ weights, n_x, n_y
+
+   Filter weights for this row - dimensions weights[SUBSAMPLE][n_x][n_y]
+
+ dest, dest_x, dest_end, dest_channels, dest_has_alpha
+
+   The destination buffer, function will start writing into *dest and
+   increment by dest_channels, until dest == dest_end. Reading from
+   src for these pixels is guaranteed not to go outside of the 
+   bufer bounds
+
+ src, src_channels, src_has_alpha
+   src[n_y] - an array of pointers to the start of the source rows
+   for each filter coordinate.
+
+ x_init, x_step
+
+   Information about x positions in source image.
+
+ src_width - unused
+
+ check_size, color1, color2: Information for color background for composite_color variant
+
+ The total for the destination pixel at dest + i is given by
+
+   SUM (l=0..n_x - 1, m=0..n_y - 1) 
+     src[m][(x_init + i * x_step)>> SCALE_SHIFT + l] * weights[m][l]
+
+
+Algorithms for compositing
+==========================
+
+Compositing alpha on non alpha:
+
+ R = As * Rs + (1 - As) * Rd
+ G = As * Gs + (1 - As) * Gd
+ B = As * Bs + (1 - As) * Bd
+
+This can be regrouped as:
+
+ Cd + Cs * (Cs - Rd)
+
+Compositing alpha on alpha:
+
+ A = As + (1 - As) * Ad
+ R = (As * Rs + (1 - As) * Rd * Ad)  / A
+ G = (As * Gs + (1 - As) * Gd * Ad)  / A
+ B = (As * Bs + (1 - As) * Bd * Ad)  / A
+
+The way to think of this is in terms of the "area":
+
+The final pixel is composed of area As of the source pixel
+and (1 - As) * Ad of the target pixel. So the final pixel
+is a weighted average with those weights.
+
+Note that the weights do not add up to one - hence the
+non-constant division.
+
+
+Integer tricks for compositing
+==============================
+
+
+
+MMX Code
+========
+
+Line functions are provided in MMX functionsfor a few special 
+cases:
+
+ n_x = n_y = 2
+
+   src_channels = 3 dest_channels = 3    op = scale
+   src_channels = 4 with alpha dest_channels = 4 no alpha  op = composite
+   src_channels = 4 with alpha dest_channels = 4 no alpha  op = composite_color
+
+For the case n_x = n_y = 2 - primarily hit when scaling up with bilinear
+scaling, we can take advantage of the fact that multiple destination
+pixels will be composed from the same source pixels.
+
+That is a destination pixel is a linear combination of the source
+pixels around it:
+
+
+  S0                     S1
+
+
+
+
+
+       D  D' D'' ...
+
+
+
+
+  S2                     S3
+
+Each mmx register is 64 bits wide, so we can unpack a source pixel
+into the low 8 bits of 4 16 bit words, and store it into a mmx 
+register.
+
+For each destination pixel, we first make sure that we have pixels S0
+... S3 loaded into registers mm0 ...mm3. (This will often involve not
+doing anything or moving mm1 and mm3 into mm0 and mm1 then reloading
+mm1 and mm3 with new values).
+
+Then we load up the appropriate weights for the 4 corner pixels
+based on the offsets of the destination pixel within the source
+pixels.
+
+We have preexpanded the weights to 64 bits wide and truncated the
+range to 8 bits, so an original filter value of 
+
+ 0x5321 would be expanded to
+
+ 0x0053005300530053
+
+For source buffers without alpha, we simply do a multiply-add
+of the weights, giving us a 16 bit quantity for the result
+that we shift left by 8 and store in the destination buffer.
+
+When the source buffer has alpha, then things become more
+complicated - when we load up mm0 and mm3, we premultiply
+the alpha, so they contain:
+
+ (a*ff >> 8) (r*a >> 8) (g*a >> 8) (b*a >> a)
+
+Then when we multiply by the weights, and add we end up
+with premultiplied r,g,b,a in the range of 0 .. 0xff * 0ff,
+call them A,R,G,B
+
+We then need to composite with the dest pixels - which 
+we do by:
+
+ r_dest = (R + ((0xff * 0xff - A) >> 8) * r_dest) >> 8
+
+(0xff * 0xff) 
diff --git a/gdk-pixbuf/pixops/Makefile.am b/gdk-pixbuf/pixops/Makefile.am
new file mode 100644 (file)
index 0000000..fe7775a
--- /dev/null
@@ -0,0 +1,34 @@
+include $(top_srcdir)/Makefile.decl
+
+noinst_LTLIBRARIES = libpixops.la
+
+INCLUDES = \
+       -I$(top_srcdir) -I$(top_builddir)       \
+       $(GTK_DEBUG_FLAGS)                      \
+       $(GDK_PIXBUF_DEP_CFLAGS)
+
+noinst_PROGRAMS = timescale
+
+timescale_SOURCES = timescale.c
+timescale_LDADD = libpixops.la $(GLIB_LIBS) $(GDK_PIXBUF_DEP_LIBS)
+
+if USE_MMX
+mmx_sources =                          \
+       have_mmx.S                      \
+       scale_line_22_33_mmx.S          \
+       composite_line_22_4a4_mmx.S     \
+       composite_line_color_22_4a4_mmx.S
+endif
+
+libpixops_la_SOURCES =                 \
+       pixops.c                        \
+       pixops.h                        \
+       pixops-internal.h               \
+       $(mmx_sources)
+
+EXTRA_DIST +=                          \
+       DETAILS                         \
+       pixbuf-transform-math.ltx       \
+       makefile.msc
+
+-include $(top_srcdir)/git.mk
diff --git a/gdk-pixbuf/pixops/Makefile.in b/gdk-pixbuf/pixops/Makefile.in
new file mode 100644 (file)
index 0000000..c677f0b
--- /dev/null
@@ -0,0 +1,749 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# GTK+ - The GIMP Toolkit
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+       $(top_srcdir)/Makefile.decl
+noinst_PROGRAMS = timescale$(EXEEXT)
+subdir = gdk-pixbuf/pixops
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \
+       $(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \
+       $(top_srcdir)/m4/intlmacosx.m4 \
+       $(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
+       $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+       $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+       $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+       $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+       $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+       $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libpixops_la_LIBADD =
+am__libpixops_la_SOURCES_DIST = pixops.c pixops.h pixops-internal.h \
+       have_mmx.S scale_line_22_33_mmx.S composite_line_22_4a4_mmx.S \
+       composite_line_color_22_4a4_mmx.S
+@USE_MMX_TRUE@am__objects_1 = have_mmx.lo scale_line_22_33_mmx.lo \
+@USE_MMX_TRUE@ composite_line_22_4a4_mmx.lo \
+@USE_MMX_TRUE@ composite_line_color_22_4a4_mmx.lo
+am_libpixops_la_OBJECTS = pixops.lo $(am__objects_1)
+libpixops_la_OBJECTS = $(am_libpixops_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+PROGRAMS = $(noinst_PROGRAMS)
+am_timescale_OBJECTS = timescale.$(OBJEXT)
+timescale_OBJECTS = $(am_timescale_OBJECTS)
+am__DEPENDENCIES_1 =
+timescale_DEPENDENCIES = libpixops.la $(am__DEPENDENCIES_1) \
+       $(am__DEPENDENCIES_1)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CPPASCOMPILE = $(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+       $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CCASFLAGS) $(CCASFLAGS)
+LTCPPASCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=compile $(CCAS) $(DEFS) \
+       $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+       $(AM_CCASFLAGS) $(CCASFLAGS)
+AM_V_CPPAS = $(am__v_CPPAS_@AM_V@)
+am__v_CPPAS_ = $(am__v_CPPAS_@AM_DEFAULT_V@)
+am__v_CPPAS_0 = @echo "  CPPAS " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+       $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+       $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC    " $@;
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+       $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD  " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN   " $@;
+SOURCES = $(libpixops_la_SOURCES) $(timescale_SOURCES)
+DIST_SOURCES = $(am__libpixops_la_SOURCES_DIST) $(timescale_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BASE_DEPENDENCIES_CFLAGS = @BASE_DEPENDENCIES_CFLAGS@
+BASE_DEPENDENCIES_LIBS = @BASE_DEPENDENCIES_LIBS@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DB2HTML = @DB2HTML@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXE_MANIFEST_ARCHITECTURE = @EXE_MANIFEST_ARCHITECTURE@
+FGREP = @FGREP@
+GDK_PIXBUF_API_VERSION = @GDK_PIXBUF_API_VERSION@
+GDK_PIXBUF_BINARY_VERSION = @GDK_PIXBUF_BINARY_VERSION@
+GDK_PIXBUF_CSOURCE = @GDK_PIXBUF_CSOURCE@
+GDK_PIXBUF_DEP_CFLAGS = @GDK_PIXBUF_DEP_CFLAGS@
+GDK_PIXBUF_DEP_LIBS = @GDK_PIXBUF_DEP_LIBS@
+GDK_PIXBUF_EXTRA_CFLAGS = @GDK_PIXBUF_EXTRA_CFLAGS@
+GDK_PIXBUF_EXTRA_LIBS = @GDK_PIXBUF_EXTRA_LIBS@
+GDK_PIXBUF_LINK_FLAGS = @GDK_PIXBUF_LINK_FLAGS@
+GDK_PIXBUF_MAJOR = @GDK_PIXBUF_MAJOR@
+GDK_PIXBUF_MICRO = @GDK_PIXBUF_MICRO@
+GDK_PIXBUF_MINOR = @GDK_PIXBUF_MINOR@
+GDK_PIXBUF_PACKAGES = @GDK_PIXBUF_PACKAGES@
+GDK_PIXBUF_VERSION = @GDK_PIXBUF_VERSION@
+GDK_PIXBUF_XLIB_DEP_CFLAGS = @GDK_PIXBUF_XLIB_DEP_CFLAGS@
+GDK_PIXBUF_XLIB_DEP_LIBS = @GDK_PIXBUF_XLIB_DEP_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_COMPILE_RESOURCES = @GLIB_COMPILE_RESOURCES@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GREP = @GREP@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+GTK_UPDATE_ICON_CACHE = @GTK_UPDATE_ICON_CACHE@
+HTML_DIR = @HTML_DIR@
+INCLUDED_LOADER_DEFINE = @INCLUDED_LOADER_DEFINE@
+INCLUDED_LOADER_OBJ = @INCLUDED_LOADER_OBJ@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
+INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
+INTROSPECTION_GENERATE = @INTROSPECTION_GENERATE@
+INTROSPECTION_GIRDIR = @INTROSPECTION_GIRDIR@
+INTROSPECTION_LIBS = @INTROSPECTION_LIBS@
+INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@
+INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@
+INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBJASPER = @LIBJASPER@
+LIBJPEG = @LIBJPEG@
+LIBOBJS = @LIBOBJS@
+LIBPNG = @LIBPNG@
+LIBS = @LIBS@
+LIBTIFF = @LIBTIFF@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_EXPORT_OPTIONS = @LIBTOOL_EXPORT_OPTIONS@
+LIB_EXE_MACHINE_FLAG = @LIB_EXE_MACHINE_FLAG@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+LT_CURRENT_MINUS_AGE = @LT_CURRENT_MINUS_AGE@
+LT_VERSION_INFO = @LT_VERSION_INFO@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MATH_LIB = @MATH_LIB@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PNG_DEP_CFLAGS_PACKAGES = @PNG_DEP_CFLAGS_PACKAGES@
+POSUB = @POSUB@
+RANLIB = @RANLIB@
+REBUILD = @REBUILD@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+WINDRES = @WINDRES@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+XSLTPROC = @XSLTPROC@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+ms_librarian = @ms_librarian@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+GTESTER = gtester              # in $PATH for non-GLIB packages
+GTESTER_REPORT = gtester-report                # in $PATH for non-GLIB packages
+
+# initialize variables for unconditional += appending
+EXTRA_DIST = DETAILS pixbuf-transform-math.ltx makefile.msc
+TEST_PROGS = 
+
+### testing rules
+
+# Xvfb based test rules
+XVFB = Xvfb -ac -noreset -screen 0 800x600x16
+XIDS = 101 102 103 104 105 106 107 197 199 211 223 227 293 307 308 309 310 311 \
+   491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 \
+   991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 \
+  1008 1009 4703 4721 4723 4729 4733 4751 9973 9974 9975 9976 9977 9978 9979 \
+  9980 9981 9982 9983 9984 9985 9986 9987 9988 9989 9990 9991 9992 9993 9994 \
+  9995 9996 9997 9998 9999
+
+SKIP_GDKTARGET = \
+       test "$(gdktarget)" != "x11" \
+       && echo "Gtk+Tests:INFO: Skipping GUI tests for non-X11 target."
+
+XVFB_START = \
+       ${XVFB} -help 2>/dev/null 1>&2 \
+       && XID=`for id in $(XIDS) ; do test -e /tmp/.X$$id-lock || { echo $$id; exit 0; }; done; exit 1` \
+       && { ${XVFB} :$$XID -screen 0 800x600x16 -nolisten tcp -auth /dev/null >/dev/null 2>&1 & \
+              trap "kill -15 $$! " 0 HUP INT QUIT TRAP USR1 PIPE TERM ; } \
+       || { echo "Gtk+Tests:ERROR: Failed to start Xvfb environment for X11 target tests."; exit 1; } \
+       && DISPLAY=:$$XID && export DISPLAY
+
+noinst_LTLIBRARIES = libpixops.la
+INCLUDES = \
+       -I$(top_srcdir) -I$(top_builddir)       \
+       $(GTK_DEBUG_FLAGS)                      \
+       $(GDK_PIXBUF_DEP_CFLAGS)
+
+timescale_SOURCES = timescale.c
+timescale_LDADD = libpixops.la $(GLIB_LIBS) $(GDK_PIXBUF_DEP_LIBS)
+@USE_MMX_TRUE@mmx_sources = \
+@USE_MMX_TRUE@ have_mmx.S                      \
+@USE_MMX_TRUE@ scale_line_22_33_mmx.S          \
+@USE_MMX_TRUE@ composite_line_22_4a4_mmx.S     \
+@USE_MMX_TRUE@ composite_line_color_22_4a4_mmx.S
+
+libpixops_la_SOURCES = \
+       pixops.c                        \
+       pixops.h                        \
+       pixops-internal.h               \
+       $(mmx_sources)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .S .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/Makefile.decl $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+               && { if test -f $@; then exit 0; else break; fi; }; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign gdk-pixbuf/pixops/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --foreign gdk-pixbuf/pixops/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+$(top_srcdir)/Makefile.decl:
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+       -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+       @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+         dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+         test "$$dir" != "$$p" || dir=.; \
+         echo "rm -f \"$${dir}/so_locations\""; \
+         rm -f "$${dir}/so_locations"; \
+       done
+libpixops.la: $(libpixops_la_OBJECTS) $(libpixops_la_DEPENDENCIES) $(EXTRA_libpixops_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK)  $(libpixops_la_OBJECTS) $(libpixops_la_LIBADD) $(LIBS)
+
+clean-noinstPROGRAMS:
+       @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+       echo " rm -f" $$list; \
+       rm -f $$list || exit $$?; \
+       test -n "$(EXEEXT)" || exit 0; \
+       list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+       echo " rm -f" $$list; \
+       rm -f $$list
+timescale$(EXEEXT): $(timescale_OBJECTS) $(timescale_DEPENDENCIES) $(EXTRA_timescale_DEPENDENCIES) 
+       @rm -f timescale$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(timescale_OBJECTS) $(timescale_LDADD) $(LIBS)
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT)
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/composite_line_22_4a4_mmx.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/composite_line_color_22_4a4_mmx.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/have_mmx.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pixops.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scale_line_22_33_mmx.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timescale.Po@am__quote@
+
+.S.o:
+@am__fastdepCCAS_TRUE@ $(AM_V_CPPAS)$(CPPASCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCCAS_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCCAS_FALSE@    $(AM_V_CPPAS)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCCAS_FALSE@    DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCCAS_FALSE@        $(AM_V_CPPAS@am__nodep@)$(CPPASCOMPILE) -c -o $@ $<
+
+.S.obj:
+@am__fastdepCCAS_TRUE@ $(AM_V_CPPAS)$(CPPASCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCCAS_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCCAS_FALSE@    $(AM_V_CPPAS)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCCAS_FALSE@    DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCCAS_FALSE@        $(AM_V_CPPAS@am__nodep@)$(CPPASCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.S.lo:
+@am__fastdepCCAS_TRUE@ $(AM_V_CPPAS)$(LTCPPASCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCCAS_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCCAS_FALSE@    $(AM_V_CPPAS)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCCAS_FALSE@    DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCCAS_FALSE@        $(AM_V_CPPAS@am__nodep@)$(LTCPPASCOMPILE) -c -o $@ $<
+
+.c.o:
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+       list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       set x; \
+       here=`pwd`; \
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       shift; \
+       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+         test -n "$$unique" || unique=$$empty_fix; \
+         if test $$# -gt 0; then \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             "$$@" $$unique; \
+         else \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             $$unique; \
+         fi; \
+       fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       test -z "$(CTAGS_ARGS)$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+            $$unique
+
+GTAGS:
+       here=`$(am__cd) $(top_builddir) && pwd` \
+         && $(am__cd) $(top_srcdir) \
+         && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d "$(distdir)/$$file"; then \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+         else \
+           test -f "$(distdir)/$$file" \
+           || cp -p $$d/$$file "$(distdir)/$$file" \
+           || exit 1; \
+         fi; \
+       done
+check-am: all-am
+       $(MAKE) $(AM_MAKEFLAGS) check-local
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+       if test -z '$(STRIP)'; then \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+             install; \
+       else \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+       fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+       clean-noinstPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+       distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+       mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am check-local clean \
+       clean-generic clean-libtool clean-noinstLTLIBRARIES \
+       clean-noinstPROGRAMS ctags distclean distclean-compile \
+       distclean-generic distclean-libtool distclean-tags distdir dvi \
+       dvi-am html html-am info info-am install install-am \
+       install-data install-data-am install-dvi install-dvi-am \
+       install-exec install-exec-am install-html install-html-am \
+       install-info install-info-am install-man install-pdf \
+       install-pdf-am install-ps install-ps-am install-strip \
+       installcheck installcheck-am installdirs maintainer-clean \
+       maintainer-clean-generic mostlyclean mostlyclean-compile \
+       mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+       tags uninstall uninstall-am
+
+# call as: $(XVFB_START) && someprogram
+
+# test: run all tests in cwd and subdirs
+test:  ${TEST_PROGS}
+       @$(SKIP_GDKTARGET) || test -z "${TEST_PROGS}" || { \
+         $(XVFB_START) && { set -e; ${GTESTER} --verbose ${TEST_PROGS}; }; \
+       }
+       @ for subdir in $(SUBDIRS) ; do \
+           test "$$subdir" = "." -o "$$subdir" = "po" -o "$$subdir" = "po-properties" || \
+           ( cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $@ ) || exit $? ; \
+         done
+# test-report: run tests in subdirs and generate report
+# perf-report: run tests in subdirs with -m perf and generate report
+# full-report: like test-report: with -m perf and -m slow
+test-report perf-report full-report:   ${TEST_PROGS}
+       @ ignore_logdir=true ; \
+         if test -z "$$GTESTER_LOGDIR" ; then \
+           GTESTER_LOGDIR=`mktemp -d "\`pwd\`/.testlogs-XXXXXX"`; export GTESTER_LOGDIR ; \
+           ignore_logdir=false ; \
+         fi ; \
+         for subdir in $(SUBDIRS) ; do \
+           test "$$subdir" = "." -o "$$subdir" = "po" -o "$$subdir" = "po-properties" || \
+           ( cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $@ ) || exit $? ; \
+         done ; \
+         $(SKIP_GDKTARGET) || test -z "${TEST_PROGS}" || { \
+           case $@ in \
+           test-report) test_options="-k";; \
+           perf-report) test_options="-k -m=perf";; \
+           full-report) test_options="-k -m=perf -m=slow";; \
+           esac ; \
+           $(XVFB_START) && { \
+             set -e; \
+             if test -z "$$GTESTER_LOGDIR" ; then \
+               ${GTESTER} --verbose $$test_options -o test-report.xml ${TEST_PROGS} ; \
+             elif test -n "${TEST_PROGS}" ; then \
+               ${GTESTER} --verbose $$test_options -o `mktemp "$$GTESTER_LOGDIR/log-XXXXXX"` ${TEST_PROGS} ; \
+             fi ; \
+           }; \
+         }; \
+         $$ignore_logdir || { \
+           echo '<?xml version="1.0"?>' > $@.xml ; \
+           echo '<report-collection>'  >> $@.xml ; \
+           for lf in `ls -L "$$GTESTER_LOGDIR"/.` ; do \
+             sed '1,1s/^<?xml\b[^>?]*?>//' <"$$GTESTER_LOGDIR"/"$$lf" >> $@.xml ; \
+           done ; \
+           echo >> $@.xml ; \
+           echo '</report-collection>' >> $@.xml ; \
+           rm -rf "$$GTESTER_LOGDIR"/ ; \
+           ${GTESTER_REPORT} --version 2>/dev/null 1>&2 ; test "$$?" != 0 || ${GTESTER_REPORT} $@.xml >$@.html ; \
+         }
+.PHONY: test test-report perf-report full-report
+# run make test as part of make check
+check-local: test
+
+-include $(top_srcdir)/git.mk
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/gdk-pixbuf/pixops/README b/gdk-pixbuf/pixops/README
new file mode 100644 (file)
index 0000000..354c3a1
--- /dev/null
@@ -0,0 +1,163 @@
+The code in this directory implements optimized, filtered scaling
+for pixmap data. 
+
+This code is copyright Red Hat, Inc, 2000 and licensed under the terms
+of the GNU Lesser General Public License (LGPL).
+
+(If you want to use it in a project where that license is not
+appropriate, please contact me, and most likely something can be
+worked out.)
+
+Owen Taylor <otaylor@redhat.com>
+
+PRINCIPLES
+==========
+
+The general principle of this code is that it first computes a filter
+matrix for the given filtering mode, and then calls a general driver
+routine, passing in functions to composite pixels and lines.
+
+(The pixel functions are used for handling edge cases, and the line
+functions are simply used for the middle parts of the image.)
+
+The system is designed so that the line functions can be simple, 
+don't have to worry about special cases, can be selected to
+be specific to the particular formats involved. This allows them
+to be hyper-optimized. Since most of the compution time is 
+spent in these functions, this results in an overall fast design.
+
+MMX assembly code for Intel (and compatible) processors is included
+for a number of the most common special cases:
+
+ scaling from RGB to RGB
+ compositing from RGBA to RGBx
+ compositing against a color from RGBA and storing in a RGBx buffer
+
+Alpha compositing 8 bit RGBAa onto RGB is defined in terms of
+rounding the exact result (real values in [0,1]):
+
+ cc = ca * aa + (1 - aa) * Cb
+
+ Cc = ROUND [255. * (Ca/255. * Aa/255. + (1 - Aa/255.) * Cb/255.)]
+
+ROUND(i / 255.) can be computed exactly for i in [0,255*255] as:
+
+ t = i + 0x80; result = (t + (t >> 8)) >> 8;  [ call this as To8(i) ]
+
+So, 
+  
+ t = Ca * Aa + (255 - Aa) * Cb + 0x80;
+ Cc = (t + (t >> 8)) >> 8;
+
+Alpha compositing 8 bit RaGaBaAa onto RbGbBbAa is a little harder, for
+non-premultiplied alpha. The premultiplied result is simple:
+
+ ac = aa + (1 - aa) * ab
+ cc = ca + (1 - aa) * cb
+
+Which can be computed in integers terms as:
+
+ Cc = Ca + To8 ((255 - Aa) * Cb)
+ Ac = Aa + To8 ((255 - Aa) * Ab)
+
+For non-premultiplied alpha, we need divide the color components by 
+the alpha:
+
+       +- (ca * aa + (1 - aa) * ab * cb)) / ac; aa != 0
+  cc = |
+       +- cb; aa == 0
+
+To calculate this as in integer, we note the alternate form:
+
+ cc = cb + aa * (ca - cb) / ac
+
+[ 'cc = ca + (ac - aa) * (cb - ca) / ac' can also be useful numerically,
+  but isn't important here ]
+
+We can express this as integers as:
+
+ Ac_tmp = Aa * 255 + (255 - Aa) * Ab;
+      +- Cb + (255 * Aa * (Ca - Cb) + Ac_tmp / 2) / Ac_tmp ; Ca > Cb
+ Cc = | 
+      +- Cb - (255 * Aa * (Cb - Ca) + Ac_tmp / 2) / Ac_tmp ; ca <= Cb
+
+Or, playing bit tricks to avoid the conditional
+
+ Cc = Cb + (255 * Aa * (Ca - Cb) + (((Ca - Cb) >> 8) ^ (Ac_tmp / 2)) ) / Ac_tmp
+
+TODO
+====
+
+* ART_FILTER_HYPER is not correctly implemented. It is currently
+  implemented as a filter that is derived by doing linear interpolation
+  on the source image and then averaging that with a box filter.
+
+  It should be defined as followed (see art_filterlevel.h)
+
+   "HYPER is the highest quality reconstruction function. It is derived
+    from the hyperbolic filters in Wolberg's "Digital Image Warping,"
+    and is formally defined as the hyperbolic-filter sampling the ideal
+    hyperbolic-filter interpolated image (the filter is designed to be
+    idempotent for 1:1 pixel mapping). It is the slowest and highest
+    quality."
+
+  The current HYPER is probably as slow, but lower quality. Also, there
+  are some subtle errors in the calculation current HYPER that show up as dark
+  stripes if you scale a constant-color image.
+
+* There are some roundoff errors in the compositing routines. 
+  the _nearest() variants do it right, most of the other code 
+  is wrong to some degree or another.
+
+  For instance, in composite_line_22_4a4(), we have:
+
+    dest[0] = ((0xff0000 - a) * dest[0] + r) >> 24;
+
+   if a is 0 (implies r == 0), then we have:
+
+    (0xff0000 * dest[0]) >> 24
+
+   which gives results which are 1 to low:
+
+       255 => 254,   1 => 0.
+
+   So, this should be something like:
+
+     ((0xff0000 - a) * dest[0] + r + 0xffffff) >> 24;
+
+   (Not checked, caveat emptor)
+
+   An alternatve formulation of this as:
+
+     dest[0] + (r - a * dest[0] + 0xffffff) >> 24
+
+   may be better numerically, but would need consideration for overflow.
+
+* The generic functions could be sped up considerably by
+  switching around conditionals and inner loops in various
+  places.
+
+* Right now, in several of the most common cases, there are
+  optimized mmx routines, but no optimized C routines.
+
+  For instance, there is a 
+
+    pixops_composite_line_22_4a4_mmx()
+
+  But no 
+  
+    pixops_composite_line_22_4a4()
+
+  Also, it may be desirable to include a few more special cases - in particular:
+
+    pixops_composite_line_22_4a3()
+
+  May be desirable.
+
+* Scaling down images by large scale factors is _slow_ since huge filter
+  matrixes are computed. (e.g., to scale down by a factor of 100, we compute
+  101x101 filter matrixes. At some point, it would be more efficent to
+  switch over to subsampling when scaling down - one should never need a filter
+  matrix bigger than 16x16. 
+
diff --git a/gdk-pixbuf/pixops/composite_line_22_4a4_mmx.S b/gdk-pixbuf/pixops/composite_line_22_4a4_mmx.S
new file mode 100644 (file)
index 0000000..dac0022
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2000 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+       .file   "composite_line_22_4a4_mmx.S"
+       .version        "01.01"
+gcc2_compiled.:
+.text
+       .align 16
+
+#if !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(__INTERIX)       
+       
+/* Magic indicating no need for an executable stack */
+#if !defined __powerpc64__ && !defined __ia64__
+.section .note.GNU-stack;  .previous
+#endif
+       
+.globl _pixops_composite_line_22_4a4_mmx
+       .type    _pixops_composite_line_22_4a4_mmx,@function
+_pixops_composite_line_22_4a4_mmx:
+       
+#else
+       
+.globl __pixops_composite_line_22_4a4_mmx
+__pixops_composite_line_22_4a4_mmx:
+       
+#endif
+/*
+ * Arguments
+ *             
+ * weights:     8(%ebp)
+ * p:          12(%ebp)        %esi
+ * q1:         16(%ebp)        
+ * q2:         20(%ebp)        
+ * xstep:       24(%ebp)       
+ * p_end:       28(%ebp)
+ * xinit:       32(%ebp)
+ *     
+*/
+/*
+ * Function call entry
+ */
+       pushl %ebp
+       movl %esp,%ebp
+       subl $28,%esp
+       pushl %edi
+       pushl %esi
+       pushl %ebx
+/* Locals:     
+ * int x                      %ebx
+ * int x_scaled             -24(%ebp)
+ */
+
+/*
+ * Setup
+ */
+/* Initialize variables */     
+       movl 32(%ebp),%ebx
+       movl 32(%ebp),%edx
+       sarl $16,%edx
+       movl 12(%ebp),%esi
+
+       movl %edx,-24(%ebp)
+
+       cmpl 28(%ebp),%esi
+       jnb  .out
+
+/* Load initial values into %mm1, %mm3 */
+       shll $2, %edx
+
+       pxor %mm4, %mm4
+       
+       movl 16(%ebp),%edi
+       movl (%edi, %edx), %eax
+       movd (%edi, %edx), %mm5
+       punpcklbw %mm4, %mm5
+       shrl $24, %eax
+       movl $0x010101, %ecx
+       mull %ecx
+       orl  $0xff000000, %eax
+       movd %eax, %mm1
+       punpcklbw %mm4, %mm1
+       pmullw %mm5,%mm1
+
+       movl -24(%ebp),%edx
+       shll $2, %edx
+               
+       movl 20(%ebp),%edi
+       movl (%edi, %edx), %eax
+       movd (%edi, %edx), %mm5
+       punpcklbw %mm4, %mm5
+       shrl $24, %eax
+       movl $0x010101, %ecx
+       mull %ecx
+       orl  $0xff000000, %eax
+       movd %eax, %mm3
+       punpcklbw %mm4, %mm3
+       pmullw %mm5,%mm3
+
+       psrlw $8,%mm1
+       psrlw $8,%mm3
+
+       addl $65536,%ebx
+       movl %ebx,%edx
+       sarl $16,%edx
+
+       jmp .newx
+       .p2align 4,,7
+.loop:
+/* int x_index = (x & 0xf000) >> 12 */
+       movl %ebx,%eax
+       andl $0xf000,%eax
+       shrl $7,%eax
+
+       movq (%edi,%eax),%mm4
+       pmullw %mm0,%mm4
+       movq 8(%edi,%eax),%mm5
+       pmullw %mm1,%mm5
+       movq 16(%edi,%eax),%mm6
+       movq 24(%edi,%eax),%mm7
+       pmullw %mm2,%mm6
+       pmullw %mm3,%mm7
+       paddw %mm4, %mm5
+       paddw %mm6, %mm7
+       paddw %mm5, %mm7
+
+       movl $0xffff,%ecx
+       movd %ecx,%mm4
+       psllq $48,%mm4
+       movq %mm4,%mm6
+       psubw %mm7,%mm4
+       pand %mm6,%mm4
+       
+       movq %mm4,%mm5
+       psrlq $16,%mm4
+       por %mm4,%mm5
+       psrlq $32,%mm5
+       por %mm4,%mm5
+       
+       psrlw $8,%mm5
+
+       movd (%esi),%mm7
+       pxor %mm4,%mm4
+       punpcklbw %mm4, %mm7
+               
+       pmullw %mm7,%mm5
+
+/* x += x_step; */
+       addl 24(%ebp),%ebx
+/* x_scale = x >> 16; */
+       movl %ebx,%edx
+       sarl $16,%edx
+
+       paddw %mm5,%mm6
+
+       psrlw $8,%mm6
+       packuswb %mm6, %mm6 
+       movd %mm6,(%esi)
+
+       addl $4, %esi
+               
+       cmpl %esi,28(%ebp)
+       je   .out
+
+       cmpl %edx,-24(%ebp)
+       je   .loop
+
+.newx:
+       movl %edx,-24(%ebp)
+/*
+ * Load the two new values into %mm1, %mm3, move old values into %mm0, %mm2
+ */
+       movq %mm1, %mm0
+       movq %mm3, %mm2
+
+       shll $2, %edx
+
+/* #   %mm4 will always be already clear here   */
+/* #   pxor %mm4, %mm4 */
+
+       movl 16(%ebp),%edi
+       movl (%edi, %edx), %eax
+       movd (%edi, %edx), %mm5
+       punpcklbw %mm4, %mm5
+       shrl $24, %eax
+       movl $0x010101, %ecx
+       mull %ecx
+/* 
+ *     mull destroyed %edx, need to reconstitute 
+ */
+       movl -24(%ebp),%edx
+       shll $2, %edx
+
+       orl  $0xff000000, %eax
+       movd %eax, %mm1
+       punpcklbw %mm4, %mm1
+       pmullw %mm5,%mm1
+               
+       movl 20(%ebp),%edi
+       movl (%edi, %edx), %eax
+       movd (%edi, %edx), %mm5
+       punpcklbw %mm4, %mm5
+       shrl $24, %eax
+       movl $0x010101, %ecx
+       mull %ecx
+       orl  $0xff000000, %eax
+       movd %eax, %mm3
+       punpcklbw %mm4, %mm3
+       pmullw %mm5,%mm3
+       
+       psrlw $8,%mm1
+       psrlw $8,%mm3
+
+       movl 8(%ebp),%edi
+       
+       jmp .loop
+
+.out:
+       movl %esi,%eax
+       emms
+       leal -40(%ebp),%esp
+       popl %ebx
+       popl %esi
+       popl %edi
+       movl %ebp,%esp
+       popl %ebp
+       ret
diff --git a/gdk-pixbuf/pixops/composite_line_color_22_4a4_mmx.S b/gdk-pixbuf/pixops/composite_line_color_22_4a4_mmx.S
new file mode 100644 (file)
index 0000000..ab7c872
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2000 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+       .file   "composite_line_color_22_4a4_mmx.S"
+       .version        "01.01"
+gcc2_compiled.:
+.text
+       .align 16
+
+#if !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(__INTERIX)       
+
+/* Magic indicating no need for an executable stack */
+#if !defined __powerpc64__ && !defined __ia64__
+.section .note.GNU-stack;  .previous
+#endif
+       
+.globl _pixops_composite_line_color_22_4a4_mmx
+       .type    _pixops_composite_line_color_22_4a4_mmx,@function
+_pixops_composite_line_color_22_4a4_mmx:
+
+#else
+
+.globl __pixops_composite_line_color_22_4a4_mmx
+__pixops_composite_line_color_22_4a4_mmx:
+       
+#endif
+/*
+ * Arguments
+ *             
+ * weights:     8(%ebp)
+ * p:          12(%ebp)        %esi
+ * q1:         16(%ebp)        
+ * q2:         20(%ebp)        
+ * xstep:       24(%ebp)       
+ * p_end:       28(%ebp)
+ * xinit:       32(%ebp)
+ * dest_x:     36(%ebp)
+ * check_shift:        40(%ebp)
+ * colors:     44(%ebp)
+ *     
+*/
+
+/*
+ * Function call entry
+ */
+       pushl %ebp
+       movl %esp,%ebp
+       subl $28,%esp
+       pushl %edi
+       pushl %esi
+       pushl %ebx
+/* Locals:     
+ * int x                      %ebx
+ * int x_scaled             -24(%ebp)
+ */
+
+/*
+ * Setup
+ */
+/* Initialize variables */     
+       movl 32(%ebp),%ebx
+       movl 32(%ebp),%edx
+       sarl $16,%edx
+       movl 12(%ebp),%esi
+
+       movl %edx,-24(%ebp)
+
+       cmpl 28(%ebp),%esi
+       jnb  .out
+
+/* Load initial values into %mm1, %mm3 */
+       shll $2, %edx
+
+       pxor %mm4, %mm4
+
+       movl 16(%ebp),%edi
+       movl (%edi, %edx), %eax
+       movd (%edi, %edx), %mm5
+       punpcklbw %mm4, %mm5
+       shrl $24, %eax
+       movl $0x010101, %ecx
+       mull %ecx
+       orl  $0xff000000, %eax
+       movd %eax, %mm1
+       punpcklbw %mm4, %mm1
+       pmullw %mm5,%mm1
+
+/* 
+ *     mull destroyed %edx, need to reconstitute 
+ */
+       movl -24(%ebp),%edx
+       shll $2, %edx
+               
+       movl 20(%ebp),%edi
+       movl (%edi, %edx), %eax
+       movd (%edi, %edx), %mm5
+       punpcklbw %mm4, %mm5
+       shrl $24, %eax
+       movl $0x010101, %ecx
+       mull %ecx
+       orl  $0xff000000, %eax
+       movd %eax, %mm3
+       punpcklbw %mm4, %mm3
+       pmullw %mm5,%mm3
+
+       psrlw $8,%mm1
+       psrlw $8,%mm3
+
+       addl $65536,%ebx
+       movl %ebx,%edx
+       sarl $16,%edx
+
+       jmp .newx
+       .p2align 4,,7
+.loop:
+/* int x_index = (x & 0xf000) >> 12 */
+       movl %ebx,%eax
+       andl $0xf000,%eax
+       shrl $7,%eax
+
+       movq (%edi,%eax),%mm4
+       pmullw %mm0,%mm4
+       movq 8(%edi,%eax),%mm5
+       pmullw %mm1,%mm5
+       movq 16(%edi,%eax),%mm6
+       movq 24(%edi,%eax),%mm7
+       pmullw %mm2,%mm6
+       pmullw %mm3,%mm7
+       paddw %mm4, %mm5
+       paddw %mm6, %mm7
+       paddw %mm5, %mm7
+
+       movl $0xffff,%ecx
+       movd %ecx,%mm4
+       psllq $48,%mm4
+       movq %mm4,%mm6
+       psubw %mm7,%mm4
+       pand %mm6,%mm4
+       
+       movq %mm4,%mm5
+       psrlq $16,%mm4
+       por %mm4,%mm5
+       psrlq $32,%mm5
+       por %mm4,%mm5
+       
+       psrlw $8,%mm5
+
+       movl 36(%ebp),%eax
+       incl 36(%ebp)
+
+       movl 40(%ebp),%ecx
+       shrl %cl,%eax
+       andl $1,%eax
+
+       movl 44(%ebp),%ecx
+       movq (%ecx,%eax,8),%mm6
+
+       pmullw %mm6,%mm5
+
+/* x += x_step; */
+       addl 24(%ebp),%ebx
+/* x_scale = x >> 16; */
+       movl %ebx,%edx
+       sarl $16,%edx
+
+       paddw %mm5,%mm7
+
+       psrlw $8,%mm7
+       packuswb %mm7, %mm7 
+       movd %mm7,(%esi)
+
+       addl $4, %esi
+               
+       cmpl %esi,28(%ebp)
+       je   .out
+
+       cmpl %edx,-24(%ebp)
+       je   .loop
+
+.newx:
+       movl %edx,-24(%ebp)
+/*
+ * Load the two new values into %mm1, %mm3, move old values into %mm0, %mm2
+ */
+       movq %mm1, %mm0
+       movq %mm3, %mm2
+
+       shll $2, %edx
+
+       pxor %mm4, %mm4
+
+       movl 16(%ebp),%edi
+       movl (%edi, %edx), %eax
+       movd (%edi, %edx), %mm5
+       punpcklbw %mm4, %mm5
+       shrl $24, %eax
+       movl $0x010101, %ecx
+       mull %ecx
+/* 
+ *     mull destroyed %edx, need to reconstitute 
+ */
+       movl -24(%ebp),%edx
+       shll $2, %edx
+
+       orl  $0xff000000, %eax
+       movd %eax, %mm1
+       punpcklbw %mm4, %mm1
+       pmullw %mm5,%mm1
+               
+       movl 20(%ebp),%edi
+       movl (%edi, %edx), %eax
+       movd (%edi, %edx), %mm5
+       punpcklbw %mm4, %mm5
+       shrl $24, %eax
+       movl $0x010101, %ecx
+       mull %ecx
+       orl  $0xff000000, %eax
+       movd %eax, %mm3
+       punpcklbw %mm4, %mm3
+       pmullw %mm5,%mm3
+       
+       psrlw $8,%mm1
+       psrlw $8,%mm3
+
+       movl 8(%ebp),%edi
+       
+       jmp .loop
+
+.out:
+       movl %esi,%eax
+       emms
+       leal -40(%ebp),%esp
+       popl %ebx
+       popl %esi
+       popl %edi
+       movl %ebp,%esp
+       popl %ebp
+       ret
diff --git a/gdk-pixbuf/pixops/have_mmx.S b/gdk-pixbuf/pixops/have_mmx.S
new file mode 100644 (file)
index 0000000..e455539
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2000 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+       .file   "have_mmx.S"
+       .version        "01.01"
+gcc2_compiled.:
+.text
+       .align 16
+
+#if !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(__INTERIX)
+
+/* Magic indicating no need for an executable stack */
+#if !defined __powerpc64__ && !defined __ia64__
+.section .note.GNU-stack;  .previous
+#endif
+       
+.globl _pixops_have_mmx
+       .type    _pixops_have_mmx,@function
+_pixops_have_mmx:
+
+#else
+
+.globl __pixops_have_mmx
+__pixops_have_mmx:
+
+#endif
+       
+       push    %ebx
+
+/* # Check if bit 21 in flags word is writeable */
+
+       pushfl  
+       popl    %eax
+       movl    %eax,%ebx
+       xorl    $0x00200000, %eax
+       pushl   %eax
+       popfl
+       pushfl
+       popl    %eax
+
+       cmpl    %eax, %ebx
+
+       je .notfound
+
+/* # OK, we have CPUID */
+
+       movl    $1, %eax
+       cpuid
+       
+       test    $0x00800000, %edx
+       jz      .notfound
+
+       movl    $1, %eax
+       jmp     .out
+
+.notfound:
+       movl    $0, %eax
+.out:  
+       popl    %ebx
+       ret
+
diff --git a/gdk-pixbuf/pixops/makefile.msc b/gdk-pixbuf/pixops/makefile.msc
new file mode 100644 (file)
index 0000000..f7132f8
--- /dev/null
@@ -0,0 +1,65 @@
+TOP = ../../..
+PACKAGE = pixops
+PRJ_TOP = ..\..
+
+!INCLUDE $(TOP)/glib/build/win32/make.msc
+
+PKG_CFLAGS = -I.. $(GLIB_CFLAGS)
+
+OBJECTS = \
+       pixops.obj \
+
+#?     timescale.obj
+
+## common stuff
+## compiler and linker switches
+!IFNDEF DEBUG
+# Full optimization:
+OPTIMIZE = -Ox -MD
+LINKDEBUG =
+!ELSE
+# Debugging:
+OPTIMIZE = -Zi -MDd
+LINKDEBUG = /debug
+!ENDIF
+
+# cl -? describes the options
+CC = cl -G5 -GF $(OPTIMIZE) -W3 -nologo
+
+# No general LDFLAGS needed
+LDFLAGS = /link $(LINKDEBUG)
+INSTALL = copy
+
+CFLAGS = -I. -I$(PRJ_TOP) -DHAVE_CONFIG_H
+
+## targets
+all : \
+       $(PRJ_TOP)\config.h \
+       $(PACKAGE).lib
+
+$(PACKAGE).lib : $(OBJECTS)
+       lib /out:$(PACKAGE).lib $(OBJECTS)
+
+$(PACKAGE).dll : $(OBJECTS) $(PACKAGE).def
+       $(CC) $(CFLAGS) -LD -Fe$(PACKAGE).dll $(OBJECTS) $(PKG_LINK) user32.lib advapi32.lib wsock32.lib $(LDFLAGS) /def:$(PACKAGE).def
+
+$(PRJ_TOP)\config.h: $(PRJ_TOP)\config.h.win32
+       copy $(PRJ_TOP)\config.h.win32 $(PRJ_TOP)\config.h
+
+.c.obj :
+       $(CC) $(CFLAGS) -GD -c $(PKG_CFLAGS) $<
+
+clean::
+       del config.h
+       del *.exe
+       del *.obj
+       del *.dll
+       del *.lib
+       del *.err
+       del *.map
+       del *.sym
+       del *.exp
+       del *.lk1
+       del *.mk1
+       del *.pdb
+       del *.ilk
diff --git a/gdk-pixbuf/pixops/pixbuf-transform-math.ltx b/gdk-pixbuf/pixops/pixbuf-transform-math.ltx
new file mode 100644 (file)
index 0000000..19e2313
--- /dev/null
@@ -0,0 +1,112 @@
+\documentclass{article}
+
+\begin{document}
+
+\title{Some image transform math}
+\author{Owen Taylor}
+\date{18 February 2003}
+\maketitle
+
+\section{Basics}
+
+The transform process is composed of three steps;
+first we reconstruct a continuous image from the 
+source data \(A_{i,j}\):
+\[a(u,v) = \sum_{i = -\infty}^{\infty} \sum_{j = -\infty}^{\infty} A_{i,j}F\left( {u - i \atop v - j} \right) \]
+Then we transform from destination coordinates to source coordinates:
+\[b(x,y) = a\left(u(x,y) \atop v(x,y)\right)
+         = a\left(t_{00}x + t_{01}y + t_{02} \atop t_{10}x + t_{11}y + t_{12} \right)\]
+Finally, we resample using a sampling function \(G\):
+\[B_{x_0,y_0} = \int_{-\infty}^{\infty}\int_{-\infty}^{\infty} b(x,y)G\left( {x - x_0 \atop y - y_0} \right) dxdy\]
+Putting all of these together:
+\[B_{x_0,y_0} = 
+\int_{-\infty}^{\infty}\int_{-\infty}^{\infty}
+\sum_{i = -\infty}^{\infty} \sum_{j = -\infty}^{\infty} A_{i,j}
+F\left( {u(x,y) - i \atop v(x,y) - j} \right)
+G\left( {x - x_0 \atop y - y_0} \right) dxdy\]
+We can reverse the order of the integrals and the sums:
+\[B_{x_0,y_0} = 
+\sum_{i = -\infty}^{\infty} \sum_{j = -\infty}^{\infty} A_{i,j}
+\int_{-\infty}^{\infty}\int_{-\infty}^{\infty}
+F\left( {u(x,y) - i \atop v(x,y) - j} \right)
+G\left( {x - x_0 \atop y - y_0} \right) dxdy\]
+Which shows that the destination pixel values are a linear combination of the 
+source pixel values. But the coefficents depend on \(x_0\) and \(y_0\). 
+To simplify this a bit, define:
+\[i_0 = \lfloor u(x_0,y_0) \rfloor = \lfloor {t_{00}x_0 + t_{01}y_0 + t_{02}} \rfloor \]
+\[j_0 = \lfloor v(x_0,y_0) \rfloor = \lfloor {t_{10}x_0 + t_{11}y_0 + t_{12}} \rfloor \]
+\[\Delta_u = u(x_0,y_0) - i_0 = t_{00}x_0 + t_{01}y_0 + t_{02} - \lfloor {t_{00}x_0 + t_{01}y_0 + t_{02}} \rfloor \]
+\[\Delta_v = v(x_0,y_0) - j_0 = t_{10}x_0 + t_{11}y_0 + t_{12} - \lfloor {t_{10}x_0 + t_{11}y_0 + t_{12}} \rfloor \]
+Then making the transforms \(x' = x - x_0\), \(y' = y - x_0\), \(i' = i - i_0\), \(j' = j - x_0\)
+\begin{eqnarray*}
+F(u,v) & = & F\left( {t_{00}x + t_{01}y + t_{02} - i \atop t_{10}x + t_{11}y + t_{12} - j} \right)\\
+       & = & F\left( {t_{00}(x'+x_0) + t_{01}(y'+y_0) + t_{02} - (i'+i_0) \atop 
+                      t_{10}(x'+x_0) + t_{11}(y'+y_0) + t_{12} - (j'+j_0)} \right) \\
+       & = & F\left( {\Delta_u + t_{00}x' + t_{01}y' - i' \atop 
+                      \Delta_v + t_{10}x' + t_{11}y' - j'} \right)
+\end{eqnarray*}
+Using that, we can then reparameterize the sums and integrals and
+define coefficients that depend only on \((\Delta_u,\Delta_v)\),
+which we'll call the \emph{phase} at the point \((x_0,y_0)\):
+\[
+B_{x_0,y_0} = 
+\sum_{i = -\infty}^{\infty} \sum_{j = -\infty}^{\infty} A_{i_0+i,j_0+j} C_{i,j}(\Delta_u,\Delta_v)
+\]
+\[
+C_{i,j}(\Delta_u,\Delta_v) =
+\int_{-\infty}^{\infty}\int_{-\infty}^{\infty}
+F\left( {\Delta_u + t_{00}x + t_{01}y - i \atop 
+         \Delta_v + t_{10}x + t_{11}y - j} \right)
+G\left( {x \atop y} \right) dxdy
+\]
+\section{Separability}
+A frequent special case is when the reconstruction and sampling functions
+are of the form:
+\[F(u,v) = f(u)f(v)\]
+\[G(x,y) = g(x)g(y)\]
+If we also have a transform that is purely a scale and translation;
+(\(t_{10} = 0\), \(t_{01} = 0\)), then we can separate 
+\(C_{i,j}(\Delta_u,\Delta_v)\) into the product of a \(x\) portion
+and a \(y\) portion:
+\[C_{i,j}(\Delta_u,\Delta_v) = c_{i}(\Delta_u) c_{j}(\Delta_v)\]
+\[c_{i}(\Delta_u) = \int_{-\infty}^{\infty} f(\Delta_u + t_{00}x - i)g(x)dx\]
+\[c_{j}(\Delta_v) = \int_{-\infty}^{\infty} f(\Delta_v + t_{11}y - j)g(y)dy\]
+
+\section{Some filters}
+gdk-pixbuf provides 4 standard filters for scaling, under the names ``NEAREST'',
+``TILES'', ``BILINEAR'', and ``HYPER''. All of turn out to be separable
+as discussed in the previous section. 
+For ``NEAREST'' filter, the reconstruction function is simple replication
+and the sampling function is a delta function\footnote{A delta function is an infinitely narrow spike, such that:
+\[\int_{-\infty}^{\infty}\delta(x)f(x) = f(0)\]}:
+\[f(t) = \cases{1, & if \(0 \le t \le 1\); \cr 
+                0, & otherwise}\]
+\[g(t) = \delta(t - 0.5)\]
+For ``TILES'', the reconstruction function is again replication, but we
+replace the delta-function for sampling with a box filter:
+\[f(t) = \cases{1, & if \(0 \le t \le 1\); \cr 
+                0, & otherwise}\]
+\[g(t) = \cases{1, & if \(0 \le t \le 1\); \cr 
+                0, & otherwise}\]
+The ``HYPER'' filter (in practice, it was originally intended to be 
+something else) uses bilinear interpolation for reconstruction and
+a box filter for sampling:
+\[f(t) = \cases{1 - |t - 0.5|, & if \(-0.5 \le t \le 1.5\); \cr 
+                0, & otherwise}\]
+\[g(t) = \cases{1, & if \(0 \le t \le 1\); \cr 
+                0, & otherwise}\]
+The ``BILINEAR'' filter is defined in a somewhat more complicated way;
+the definition depends on the scale factor in the transform (\(t_{00}\)
+or \(t_{01}]\). In the \(x\) direction, for \(t_{00} < 1\), it is
+the same as for ``TILES'':
+\[f_u(t) = \cases{1, & if \(0 \le t \le 1\); \cr 
+                  0, & otherwise}\]
+\[g_u(t) = \cases{1, & if \(0 \le t \le 1\); \cr 
+                  0, & otherwise}\]
+but for \(t_{10} > 1\), we use bilinear reconstruction and delta-function
+sampling:
+\[f_u(t) = \cases{1 - |t - 0.5|, & if \(-0.5 \le t \le 1.5\); \cr 
+                  0, & otherwise}\]
+\[g_u(t) = \delta(t - 0.5)\]
+The behavior in the \(y\) direction depends in the same way on \(t_{11}\).
+\end{document}
\ No newline at end of file
diff --git a/gdk-pixbuf/pixops/pixops-internal.h b/gdk-pixbuf/pixops/pixops-internal.h
new file mode 100644 (file)
index 0000000..a048b69
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2000 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+#ifdef USE_MMX
+guchar *_pixops_scale_line_22_33_mmx (guint32 weights[16][8], guchar *p, guchar *q1, guchar *q2, int x_step, guchar *p_stop, int x_init);
+guchar *_pixops_composite_line_22_4a4_mmx (guint32 weights[16][8], guchar *p, guchar *q1, guchar *q2, int x_step, guchar *p_stop, int x_init);
+guchar *_pixops_composite_line_color_22_4a4_mmx (guint32 weights[16][8], guchar *p, guchar *q1, guchar *q2, int x_step, guchar *p_stop, int x_init, int dest_x, int check_shift, int *colors);
+int _pixops_have_mmx (void);
+#endif
+
diff --git a/gdk-pixbuf/pixops/pixops.c b/gdk-pixbuf/pixops/pixops.c
new file mode 100644 (file)
index 0000000..5db165c
--- /dev/null
@@ -0,0 +1,2560 @@
+/*
+ * Copyright (C) 2000 Red Hat, Inc
+ * mediaLib integration Copyright (c) 2001-2007 Sun Microsystems, Inc.
+ * All rights reserved.  (Brian Cameron, Dmitriy Demin, James Cheng,
+ * Padraig O'Briain)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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 <math.h>
+#include <glib.h>
+
+#include "pixops.h"
+#include "pixops-internal.h"
+
+#define SUBSAMPLE_BITS 4
+#define SUBSAMPLE (1 << SUBSAMPLE_BITS)
+#define SUBSAMPLE_MASK ((1 << SUBSAMPLE_BITS)-1)
+#define SCALE_SHIFT 16
+
+static void
+_pixops_scale_real (guchar        *dest_buf,
+                    int            render_x0,
+                    int            render_y0,
+                    int            render_x1,
+                    int            render_y1,
+                    int            dest_rowstride,
+                    int            dest_channels,
+                    gboolean       dest_has_alpha,
+                    const guchar  *src_buf,
+                    int            src_width,
+                    int            src_height,
+                    int            src_rowstride,
+                    int            src_channels,
+                    gboolean       src_has_alpha,
+                    double         scale_x,
+                    double         scale_y,
+                    PixopsInterpType  interp_type);
+
+typedef struct _PixopsFilter PixopsFilter;
+typedef struct _PixopsFilterDimension PixopsFilterDimension;
+
+struct _PixopsFilterDimension
+{
+  int n;
+  double offset;
+  double *weights;
+};
+
+struct _PixopsFilter
+{
+  PixopsFilterDimension x;
+  PixopsFilterDimension y;
+  double overall_alpha;
+}; 
+
+typedef guchar *(*PixopsLineFunc) (int *weights, int n_x, int n_y,
+                                  guchar *dest, int dest_x, guchar *dest_end,
+                                  int dest_channels, int dest_has_alpha,
+                                  guchar **src, int src_channels,
+                                  gboolean src_has_alpha, int x_init,
+                                  int x_step, int src_width, int check_size,
+                                  guint32 color1, guint32 color2);
+typedef void (*PixopsPixelFunc)   (guchar *dest, int dest_x, int dest_channels,
+                                  int dest_has_alpha, int src_has_alpha,
+                                  int check_size, guint32 color1,
+                                  guint32 color2,
+                                  guint r, guint g, guint b, guint a);
+
+#ifdef USE_MEDIALIB
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <mlib_image.h>
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#if defined(HAVE_SYS_SYSTEMINFO_H)
+#include <sys/systeminfo.h>
+#elif defined(HAVE_SYS_SYSINFO_H)
+#include <sys/sysinfo.h>
+#endif
+
+static void pixops_medialib_composite    (guchar          *dest_buf,
+                                          int              dest_width,
+                                          int              dest_height,
+                                          int              dest_rowstride,
+                                          int              dest_channels,
+                                          int              dest_has_alpha,
+                                          const guchar    *src_buf,
+                                          int              src_width,
+                                          int              src_height,
+                                          int              src_rowstride,
+                                          int              src_channels,
+                                          int              src_has_alpha,
+                                          int              dest_x,
+                                          int              dest_y,
+                                          int              dest_region_width,
+                                          int              dest_region_height,
+                                          double           offset_x,
+                                          double           offset_y,
+                                          double           scale_x,
+                                          double           scale_y,
+                                          PixopsInterpType interp_type,
+                                          int              overall_alpha);
+
+static void pixops_medialib_scale        (guchar          *dest_buf,
+                                          int              dest_width,
+                                          int              dest_height,
+                                          int              dest_rowstride,
+                                          int              dest_channels,
+                                          int              dest_has_alpha,
+                                          const guchar    *src_buf,
+                                          int              src_width,
+                                          int              src_height,
+                                          int              src_rowstride,
+                                          int              src_channels,
+                                          int              src_has_alpha,
+                                          int              dest_x,
+                                          int              dest_y,
+                                          int              dest_region_width,
+                                          int              dest_region_height,
+                                          double           offset_x,
+                                          double           offset_y,
+                                          double           scale_x,
+                                          double           scale_y,
+                                          PixopsInterpType interp_type);
+
+typedef struct _mlInterp mlInterp;
+
+struct _mlInterp
+{
+  double       tx;
+  double       ty;
+  PixopsFilter po_filter;
+  void         *interp_table;
+};
+
+static gboolean medialib_initialized = FALSE;
+static gboolean use_medialib         = TRUE;
+
+/*
+ * Sun mediaLib(tm) support.
+ *
+ *   http://www.sun.com/processors/vis/mlib.html
+ *
+ */
+static void
+_pixops_use_medialib ()
+{
+  char *mlib_version_string;
+  char  sys_info[257];
+  long  count;
+
+  medialib_initialized = TRUE; 
+
+  if (getenv ("GDK_DISABLE_MEDIALIB"))
+    {
+      use_medialib = FALSE;
+      return;
+    }
+
+  /*
+   * The imaging functions we want to use were added in mediaLib version 2.
+   * So turn off mediaLib support if the user has an older version.
+   * mlib_version returns a string in this format:
+   *
+   * mediaLib:0210:20011101:v8plusa
+   * ^^^^^^^^ ^^^^ ^^^^^^^^ ^^^^^^^
+   * libname  vers  build   ISALIST identifier
+   *                date    (in this case sparcv8plus+vis)
+   * 
+   * The first 2 digits of the version are the major version.  The 3rd digit
+   * is the minor version, and the 4th digit is the micro version.  So the
+   * above string corresponds to version 2.1.0.  In the following test we only
+   * care about the major version.
+   */
+  mlib_version_string = mlib_version ();
+
+  count = sysinfo (SI_ARCHITECTURE, &sys_info[0], 257);
+
+  if (count != -1)
+    {
+      if (strcmp (sys_info, "i386") == 0)
+        {
+          char *mlib_target_isa = &mlib_version_string[23];
+
+          /*
+           * For x86 processors mediaLib generic C implementation
+           * does not give any performance advantage so disable it
+           */
+          if (strncmp (mlib_target_isa, "sse", 3) != 0)
+            {
+              use_medialib = FALSE;
+              return;
+            }
+
+          /*
+           * For x86 processors use of libumem conflicts with
+           * mediaLib, so avoid using it.
+           */
+          if (dlsym (RTLD_PROBE,   "umem_alloc") != NULL)
+            {
+              use_medialib = FALSE;
+              return;
+            }
+        }
+    }
+  else
+    {
+      /* Failed to get system architecture, disable mediaLib anyway */
+      use_medialib = FALSE;
+      return;
+    }
+}
+#endif
+
+static int
+get_check_shift (int check_size)
+{
+  int check_shift = 0;
+  g_return_val_if_fail (check_size >= 0, 4);
+
+  while (!(check_size & 1))
+    {
+      check_shift++;
+      check_size >>= 1;
+    }
+
+  return check_shift;
+}
+
+static void
+pixops_scale_nearest (guchar        *dest_buf,
+                     int            render_x0,
+                     int            render_y0,
+                     int            render_x1,
+                     int            render_y1,
+                     int            dest_rowstride,
+                     int            dest_channels,
+                     gboolean       dest_has_alpha,
+                     const guchar  *src_buf,
+                     int            src_width,
+                     int            src_height,
+                     int            src_rowstride,
+                     int            src_channels,
+                     gboolean       src_has_alpha,
+                     double         scale_x,
+                     double         scale_y)
+{
+  int i;
+  int x;
+  int x_step = (1 << SCALE_SHIFT) / scale_x;
+  int y_step = (1 << SCALE_SHIFT) / scale_y;
+  int xmax, xstart, xstop, x_pos, y_pos;
+  const guchar *p;
+
+#define INNER_LOOP(SRC_CHANNELS,DEST_CHANNELS,ASSIGN_PIXEL)     \
+      xmax = x + (render_x1 - render_x0) * x_step;              \
+      xstart = MIN (0, xmax);                                   \
+      xstop = MIN (src_width << SCALE_SHIFT, xmax);             \
+      p = src + (CLAMP (x, xstart, xstop) >> SCALE_SHIFT) * SRC_CHANNELS; \
+      while (x < xstart)                                        \
+        {                                                       \
+          ASSIGN_PIXEL;                                         \
+          dest += DEST_CHANNELS;                                \
+          x += x_step;                                          \
+        }                                                       \
+      while (x < xstop)                                         \
+        {                                                       \
+          p = src + (x >> SCALE_SHIFT) * SRC_CHANNELS;          \
+          ASSIGN_PIXEL;                                         \
+          dest += DEST_CHANNELS;                                \
+          x += x_step;                                          \
+        }                                                       \
+      x_pos = x >> SCALE_SHIFT;                                 \
+      p = src + CLAMP (x_pos, 0, src_width - 1) * SRC_CHANNELS; \
+      while (x < xmax)                                          \
+        {                                                       \
+          ASSIGN_PIXEL;                                         \
+          dest += DEST_CHANNELS;                                \
+          x += x_step;                                          \
+        }
+
+  for (i = 0; i < (render_y1 - render_y0); i++)
+    {
+      const guchar *src;
+      guchar       *dest;
+      y_pos = ((i + render_y0) * y_step + y_step / 2) >> SCALE_SHIFT;
+      y_pos = CLAMP (y_pos, 0, src_height - 1);
+      src  = src_buf + y_pos * src_rowstride;
+      dest = dest_buf + i * dest_rowstride;
+
+      x = render_x0 * x_step + x_step / 2;
+
+      if (src_channels == 3)
+       {
+         if (dest_channels == 3)
+           {
+             INNER_LOOP (3, 3, dest[0]=p[0];dest[1]=p[1];dest[2]=p[2]);
+           }
+         else
+           {
+             INNER_LOOP (3, 4, dest[0]=p[0];dest[1]=p[1];dest[2]=p[2];dest[3]=0xff);
+           }
+       }
+      else if (src_channels == 4)
+       {
+         if (dest_channels == 3)
+           {
+             INNER_LOOP (4, 3, dest[0]=p[0];dest[1]=p[1];dest[2]=p[2]);
+           }
+         else
+           {
+             guint32 *p32;
+             INNER_LOOP(4, 4, p32=(guint32*)dest;*p32=*((guint32*)p));
+           }
+       }
+    }
+}
+
+static void
+pixops_composite_nearest (guchar        *dest_buf,
+                         int            render_x0,
+                         int            render_y0,
+                         int            render_x1,
+                         int            render_y1,
+                         int            dest_rowstride,
+                         int            dest_channels,
+                         gboolean       dest_has_alpha,
+                         const guchar  *src_buf,
+                         int            src_width,
+                         int            src_height,
+                         int            src_rowstride,
+                         int            src_channels,
+                         gboolean       src_has_alpha,
+                         double         scale_x,
+                         double         scale_y,
+                         int            overall_alpha)
+{
+  int i;
+  int x;
+  int x_step = (1 << SCALE_SHIFT) / scale_x;
+  int y_step = (1 << SCALE_SHIFT) / scale_y;
+  int xmax, xstart, xstop, x_pos, y_pos;
+  const guchar *p;
+  unsigned int  a0;
+
+  for (i = 0; i < (render_y1 - render_y0); i++)
+    {
+      const guchar *src;
+      guchar       *dest;
+      y_pos = ((i + render_y0) * y_step + y_step / 2) >> SCALE_SHIFT;
+      y_pos = CLAMP (y_pos, 0, src_height - 1);
+      src  = src_buf + y_pos * src_rowstride;
+      dest = dest_buf + i * dest_rowstride;
+
+      x = render_x0 * x_step + x_step / 2;
+      
+      INNER_LOOP(src_channels, dest_channels,
+         if (src_has_alpha)
+           a0 = (p[3] * overall_alpha) / 0xff;
+         else
+           a0 = overall_alpha;
+
+          switch (a0)
+            {
+            case 0:
+              break;
+            case 255:
+              dest[0] = p[0];
+              dest[1] = p[1];
+              dest[2] = p[2];
+              if (dest_has_alpha)
+                dest[3] = 0xff;
+              break;
+            default:
+              if (dest_has_alpha)
+                {
+                  unsigned int w0 = 0xff * a0;
+                  unsigned int w1 = (0xff - a0) * dest[3];
+                  unsigned int w = w0 + w1;
+
+                 dest[0] = (w0 * p[0] + w1 * dest[0]) / w;
+                 dest[1] = (w0 * p[1] + w1 * dest[1]) / w;
+                 dest[2] = (w0 * p[2] + w1 * dest[2]) / w;
+                 dest[3] = w / 0xff;
+                }
+              else
+                {
+                  unsigned int a1 = 0xff - a0;
+                 unsigned int tmp;
+
+                 tmp = a0 * p[0] + a1 * dest[0] + 0x80;
+                  dest[0] = (tmp + (tmp >> 8)) >> 8;
+                 tmp = a0 * p[1] + a1 * dest[1] + 0x80;
+                  dest[1] = (tmp + (tmp >> 8)) >> 8;
+                 tmp = a0 * p[2] + a1 * dest[2] + 0x80;
+                  dest[2] = (tmp + (tmp >> 8)) >> 8;
+                }
+              break;
+            }
+       );
+    }
+}
+
+static void
+pixops_composite_color_nearest (guchar        *dest_buf,
+                               int            render_x0,
+                               int            render_y0,
+                               int            render_x1,
+                               int            render_y1,
+                               int            dest_rowstride,
+                               int            dest_channels,
+                               gboolean       dest_has_alpha,
+                               const guchar  *src_buf,
+                               int            src_width,
+                               int            src_height,
+                               int            src_rowstride,
+                               int            src_channels,
+                               gboolean       src_has_alpha,
+                               double         scale_x,
+                               double         scale_y,
+                               int            overall_alpha,
+                               int            check_x,
+                               int            check_y,
+                               int            check_size,
+                               guint32        color1,
+                               guint32        color2)
+{
+  int i, j;
+  int x;
+  int x_step = (1 << SCALE_SHIFT) / scale_x;
+  int y_step = (1 << SCALE_SHIFT) / scale_y;
+  int r1, g1, b1, r2, g2, b2;
+  int check_shift = get_check_shift (check_size);
+  int xmax, xstart, xstop, x_pos, y_pos;
+  const guchar *p;
+  unsigned int  a0;
+
+  for (i = 0; i < (render_y1 - render_y0); i++)
+    {
+      const guchar *src;
+      guchar       *dest;
+      y_pos = ((i + render_y0) * y_step + y_step / 2) >> SCALE_SHIFT;
+      y_pos = CLAMP (y_pos, 0, src_height - 1);
+      src  = src_buf + y_pos * src_rowstride;
+      dest = dest_buf + i * dest_rowstride;
+
+      x = render_x0 * x_step + x_step / 2;
+      
+      
+      if (((i + check_y) >> check_shift) & 1)
+       {
+         r1 = (color2 & 0xff0000) >> 16;
+         g1 = (color2 & 0xff00) >> 8;
+         b1 = color2 & 0xff;
+
+         r2 = (color1 & 0xff0000) >> 16;
+         g2 = (color1 & 0xff00) >> 8;
+         b2 = color1 & 0xff;
+       }
+      else
+       {
+         r1 = (color1 & 0xff0000) >> 16;
+         g1 = (color1 & 0xff00) >> 8;
+         b1 = color1 & 0xff;
+
+         r2 = (color2 & 0xff0000) >> 16;
+         g2 = (color2 & 0xff00) >> 8;
+         b2 = color2 & 0xff;
+       }
+
+      j = 0;
+      INNER_LOOP(src_channels, dest_channels,
+         if (src_has_alpha)
+           a0 = (p[3] * overall_alpha + 0xff) >> 8;
+         else
+           a0 = overall_alpha;
+
+          switch (a0)
+            {
+            case 0:
+              if (((j + check_x) >> check_shift) & 1)
+                {
+                  dest[0] = r2; 
+                  dest[1] = g2; 
+                  dest[2] = b2;
+                }
+              else
+                {
+                  dest[0] = r1; 
+                  dest[1] = g1; 
+                  dest[2] = b1;
+                }
+            break;
+            case 255:
+             dest[0] = p[0];
+             dest[1] = p[1];
+             dest[2] = p[2];
+              break;
+            default:
+                    {
+                      unsigned int tmp;
+              if (((j + check_x) >> check_shift) & 1)
+                {
+                  tmp = ((int) p[0] - r2) * a0;
+                  dest[0] = r2 + ((tmp + (tmp >> 8) + 0x80) >> 8);
+                  tmp = ((int) p[1] - g2) * a0;
+                  dest[1] = g2 + ((tmp + (tmp >> 8) + 0x80) >> 8);
+                  tmp = ((int) p[2] - b2) * a0;
+                  dest[2] = b2 + ((tmp + (tmp >> 8) + 0x80) >> 8);
+                }
+              else
+                {
+                  tmp = ((int) p[0] - r1) * a0;
+                  dest[0] = r1 + ((tmp + (tmp >> 8) + 0x80) >> 8);
+                  tmp = ((int) p[1] - g1) * a0;
+                  dest[1] = g1 + ((tmp + (tmp >> 8) + 0x80) >> 8);
+                  tmp = ((int) p[2] - b1) * a0;
+                  dest[2] = b1 + ((tmp + (tmp >> 8) + 0x80) >> 8);
+                }
+                    }
+              break;
+            }
+         
+         if (dest_channels == 4)
+           dest[3] = 0xff;
+
+                j++;
+       );
+    }
+}
+#undef INNER_LOOP
+
+static void
+composite_pixel (guchar *dest, int dest_x, int dest_channels, int dest_has_alpha,
+                int src_has_alpha, int check_size, guint32 color1, guint32 color2,
+                guint r, guint g, guint b, guint a)
+{
+  if (dest_has_alpha)
+    {
+      unsigned int w0 = a - (a >> 8);
+      unsigned int w1 = ((0xff0000 - a) >> 8) * dest[3];
+      unsigned int w = w0 + w1;
+      
+      if (w != 0)
+       {
+         dest[0] = (r - (r >> 8) + w1 * dest[0]) / w;
+         dest[1] = (g - (g >> 8) + w1 * dest[1]) / w;
+         dest[2] = (b - (b >> 8) + w1 * dest[2]) / w;
+         dest[3] = w / 0xff00;
+       }
+      else
+       {
+         dest[0] = 0;
+         dest[1] = 0;
+         dest[2] = 0;
+         dest[3] = 0;
+       }
+    }
+  else
+    {
+      dest[0] = (r + (0xff0000 - a) * dest[0]) / 0xff0000;
+      dest[1] = (g + (0xff0000 - a) * dest[1]) / 0xff0000;
+      dest[2] = (b + (0xff0000 - a) * dest[2]) / 0xff0000;
+    }
+}
+
+static guchar *
+composite_line (int *weights, int n_x, int n_y,
+               guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
+               guchar **src, int src_channels, gboolean src_has_alpha,
+               int x_init, int x_step, int src_width,
+               int check_size, guint32 color1, guint32 color2)
+{
+  int x = x_init;
+  int i, j;
+
+  while (dest < dest_end)
+    {
+      int x_scaled = x >> SCALE_SHIFT;
+      unsigned int r = 0, g = 0, b = 0, a = 0;
+      int *pixel_weights;
+      
+      pixel_weights = weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * n_x * n_y;
+      
+      for (i=0; i<n_y; i++)
+       {
+         guchar *q = src[i] + x_scaled * src_channels;
+         int *line_weights = pixel_weights + n_x * i;
+         
+         for (j=0; j<n_x; j++)
+           {
+             unsigned int ta;
+
+             if (src_has_alpha)
+               ta = q[3] * line_weights[j];
+             else
+               ta = 0xff * line_weights[j];
+             
+             r += ta * q[0];
+             g += ta * q[1];
+             b += ta * q[2];
+             a += ta;
+
+             q += src_channels;
+           }
+       }
+
+      if (dest_has_alpha)
+       {
+         unsigned int w0 = a - (a >> 8);
+         unsigned int w1 = ((0xff0000 - a) >> 8) * dest[3];
+         unsigned int w = w0 + w1;
+
+         if (w != 0)
+           {
+             dest[0] = (r - (r >> 8) + w1 * dest[0]) / w;
+             dest[1] = (g - (g >> 8) + w1 * dest[1]) / w;
+             dest[2] = (b - (b >> 8) + w1 * dest[2]) / w;
+             dest[3] = w / 0xff00;
+           }
+         else
+           {
+             dest[0] = 0;
+             dest[1] = 0;
+             dest[2] = 0;
+             dest[3] = 0;
+           }
+       }
+      else
+       {
+         dest[0] = (r + (0xff0000 - a) * dest[0]) / 0xff0000;
+         dest[1] = (g + (0xff0000 - a) * dest[1]) / 0xff0000;
+         dest[2] = (b + (0xff0000 - a) * dest[2]) / 0xff0000;
+       }
+      
+      dest += dest_channels;
+      x += x_step;
+    }
+
+  return dest;
+}
+
+static guchar *
+composite_line_22_4a4 (int *weights, int n_x, int n_y,
+                      guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
+                      guchar **src, int src_channels, gboolean src_has_alpha,
+                      int x_init, int x_step, int src_width,
+                      int check_size, guint32 color1, guint32 color2)
+{
+  int x = x_init;
+  guchar *src0 = src[0];
+  guchar *src1 = src[1];
+
+  g_return_val_if_fail (src_channels != 3, dest);
+  g_return_val_if_fail (src_has_alpha, dest);
+  
+  while (dest < dest_end)
+    {
+      int x_scaled = x >> SCALE_SHIFT;
+      unsigned int r, g, b, a, ta;
+      int *pixel_weights;
+      guchar *q0, *q1;
+      int w1, w2, w3, w4;
+      
+      q0 = src0 + x_scaled * 4;
+      q1 = src1 + x_scaled * 4;
+      
+      pixel_weights = (int *)((char *)weights +
+       ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS - 4)) & (SUBSAMPLE_MASK << 4)));
+      
+      w1 = pixel_weights[0];
+      w2 = pixel_weights[1];
+      w3 = pixel_weights[2];
+      w4 = pixel_weights[3];
+
+      a = w1 * q0[3];
+      r = a * q0[0];
+      g = a * q0[1];
+      b = a * q0[2];
+
+      ta = w2 * q0[7];
+      r += ta * q0[4];
+      g += ta * q0[5];
+      b += ta * q0[6];
+      a += ta;
+
+      ta = w3 * q1[3];
+      r += ta * q1[0];
+      g += ta * q1[1];
+      b += ta * q1[2];
+      a += ta;
+
+      ta = w4 * q1[7];
+      r += ta * q1[4];
+      g += ta * q1[5];
+      b += ta * q1[6];
+      a += ta;
+
+      dest[0] = ((0xff0000 - a) * dest[0] + r) >> 24;
+      dest[1] = ((0xff0000 - a) * dest[1] + g) >> 24;
+      dest[2] = ((0xff0000 - a) * dest[2] + b) >> 24;
+      dest[3] = a >> 16;
+      
+      dest += 4;
+      x += x_step;
+    }
+
+  return dest;
+}
+
+#ifdef USE_MMX
+static guchar *
+composite_line_22_4a4_mmx_stub (int *weights, int n_x, int n_y, guchar *dest,
+                               int dest_x, guchar *dest_end,
+                               int dest_channels, int dest_has_alpha,
+                               guchar **src, int src_channels,
+                               gboolean src_has_alpha, int x_init,
+                               int x_step, int src_width, int check_size,
+                               guint32 color1, guint32 color2)
+{
+  guint32 mmx_weights[16][8];
+  int j;
+
+  for (j=0; j<16; j++)
+    {
+      mmx_weights[j][0] = 0x00010001 * (weights[4*j] >> 8);
+      mmx_weights[j][1] = 0x00010001 * (weights[4*j] >> 8);
+      mmx_weights[j][2] = 0x00010001 * (weights[4*j + 1] >> 8);
+      mmx_weights[j][3] = 0x00010001 * (weights[4*j + 1] >> 8);
+      mmx_weights[j][4] = 0x00010001 * (weights[4*j + 2] >> 8);
+      mmx_weights[j][5] = 0x00010001 * (weights[4*j + 2] >> 8);
+      mmx_weights[j][6] = 0x00010001 * (weights[4*j + 3] >> 8);
+      mmx_weights[j][7] = 0x00010001 * (weights[4*j + 3] >> 8);
+    }
+
+  return _pixops_composite_line_22_4a4_mmx (mmx_weights, dest, src[0], src[1],
+                                           x_step, dest_end, x_init);
+}
+#endif /* USE_MMX */
+
+static void
+composite_pixel_color (guchar *dest, int dest_x, int dest_channels,
+                      int dest_has_alpha, int src_has_alpha, int check_size,
+                      guint32 color1, guint32 color2, guint r, guint g,
+                      guint b, guint a)
+{
+  int dest_r, dest_g, dest_b;
+  int check_shift = get_check_shift (check_size);
+
+  if ((dest_x >> check_shift) & 1)
+    {
+      dest_r = (color2 & 0xff0000) >> 16;
+      dest_g = (color2 & 0xff00) >> 8;
+      dest_b = color2 & 0xff;
+    }
+  else
+    {
+      dest_r = (color1 & 0xff0000) >> 16;
+      dest_g = (color1 & 0xff00) >> 8;
+      dest_b = color1 & 0xff;
+    }
+
+  dest[0] = ((0xff0000 - a) * dest_r + r) >> 24;
+  dest[1] = ((0xff0000 - a) * dest_g + g) >> 24;
+  dest[2] = ((0xff0000 - a) * dest_b + b) >> 24;
+
+  if (dest_has_alpha)
+    dest[3] = 0xff;
+  else if (dest_channels == 4)
+    dest[3] = a >> 16;
+}
+
+static guchar *
+composite_line_color (int *weights, int n_x, int n_y, guchar *dest,
+                     int dest_x, guchar *dest_end, int dest_channels,
+                     int dest_has_alpha, guchar **src, int src_channels,
+                     gboolean src_has_alpha, int x_init, int x_step,
+                     int src_width, int check_size, guint32 color1,
+                     guint32 color2)
+{
+  int x = x_init;
+  int i, j;
+  int check_shift = get_check_shift (check_size);
+  int dest_r1, dest_g1, dest_b1;
+  int dest_r2, dest_g2, dest_b2;
+
+  g_return_val_if_fail (check_size != 0, dest);
+
+  dest_r1 = (color1 & 0xff0000) >> 16;
+  dest_g1 = (color1 & 0xff00) >> 8;
+  dest_b1 = color1 & 0xff;
+
+  dest_r2 = (color2 & 0xff0000) >> 16;
+  dest_g2 = (color2 & 0xff00) >> 8;
+  dest_b2 = color2 & 0xff;
+
+  while (dest < dest_end)
+    {
+      int x_scaled = x >> SCALE_SHIFT;
+      unsigned int r = 0, g = 0, b = 0, a = 0;
+      int *pixel_weights;
+      
+      pixel_weights = weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * n_x * n_y;
+
+      for (i=0; i<n_y; i++)
+       {
+         guchar *q = src[i] + x_scaled * src_channels;
+         int *line_weights = pixel_weights + n_x * i;
+         
+         for (j=0; j<n_x; j++)
+           {
+             unsigned int ta;
+             
+             if (src_has_alpha)
+               ta = q[3] * line_weights[j];
+             else
+               ta = 0xff * line_weights[j];
+                 
+             r += ta * q[0];
+             g += ta * q[1];
+             b += ta * q[2];
+             a += ta;
+
+             q += src_channels;
+           }
+       }
+
+      if ((dest_x >> check_shift) & 1)
+       {
+         dest[0] = ((0xff0000 - a) * dest_r2 + r) >> 24;
+         dest[1] = ((0xff0000 - a) * dest_g2 + g) >> 24;
+         dest[2] = ((0xff0000 - a) * dest_b2 + b) >> 24;
+       }
+      else
+       {
+         dest[0] = ((0xff0000 - a) * dest_r1 + r) >> 24;
+         dest[1] = ((0xff0000 - a) * dest_g1 + g) >> 24;
+         dest[2] = ((0xff0000 - a) * dest_b1 + b) >> 24;
+       }
+
+      if (dest_has_alpha)
+       dest[3] = 0xff;
+      else if (dest_channels == 4)
+       dest[3] = a >> 16;
+       
+      dest += dest_channels;
+      x += x_step;
+      dest_x++;
+    }
+
+  return dest;
+}
+
+#ifdef USE_MMX
+static guchar *
+composite_line_color_22_4a4_mmx_stub (int *weights, int n_x, int n_y,
+                                     guchar *dest, int dest_x,
+                                     guchar *dest_end, int dest_channels,
+                                     int dest_has_alpha, guchar **src,
+                                     int src_channels, gboolean src_has_alpha,
+                                     int x_init, int x_step, int src_width,
+                                     int check_size, guint32 color1,
+                                     guint32 color2)
+{
+  guint32 mmx_weights[16][8];
+  int check_shift = get_check_shift (check_size);
+  int colors[4];
+  int j;
+
+  for (j=0; j<16; j++)
+    {
+      mmx_weights[j][0] = 0x00010001 * (weights[4*j] >> 8);
+      mmx_weights[j][1] = 0x00010001 * (weights[4*j] >> 8);
+      mmx_weights[j][2] = 0x00010001 * (weights[4*j + 1] >> 8);
+      mmx_weights[j][3] = 0x00010001 * (weights[4*j + 1] >> 8);
+      mmx_weights[j][4] = 0x00010001 * (weights[4*j + 2] >> 8);
+      mmx_weights[j][5] = 0x00010001 * (weights[4*j + 2] >> 8);
+      mmx_weights[j][6] = 0x00010001 * (weights[4*j + 3] >> 8);
+      mmx_weights[j][7] = 0x00010001 * (weights[4*j + 3] >> 8);
+    }
+
+  colors[0] = (color1 & 0xff00) << 8 | (color1 & 0xff);
+  colors[1] = (color1 & 0xff0000) >> 16;
+  colors[2] = (color2 & 0xff00) << 8 | (color2 & 0xff);
+  colors[3] = (color2 & 0xff0000) >> 16;
+
+  return _pixops_composite_line_color_22_4a4_mmx (mmx_weights, dest, src[0],
+    src[1], x_step, dest_end, x_init, dest_x, check_shift, colors);
+}
+#endif /* USE_MMX */
+
+static void
+scale_pixel (guchar *dest, int dest_x, int dest_channels, int dest_has_alpha,
+            int src_has_alpha, int check_size, guint32 color1, guint32 color2,
+            guint r, guint g, guint b, guint a)
+{
+  if (src_has_alpha)
+    {
+      if (a)
+       {
+         dest[0] = r / a;
+         dest[1] = g / a;
+         dest[2] = b / a;
+         dest[3] = a >> 16;
+       }
+      else
+       {
+         dest[0] = 0;
+         dest[1] = 0;
+         dest[2] = 0;
+         dest[3] = 0;
+       }
+    }
+  else
+    {
+      dest[0] = (r + 0xffffff) >> 24;
+      dest[1] = (g + 0xffffff) >> 24;
+      dest[2] = (b + 0xffffff) >> 24;
+      
+      if (dest_has_alpha)
+       dest[3] = 0xff;
+    }
+}
+
+static guchar *
+scale_line (int *weights, int n_x, int n_y, guchar *dest, int dest_x,
+           guchar *dest_end, int dest_channels, int dest_has_alpha,
+           guchar **src, int src_channels, gboolean src_has_alpha, int x_init,
+           int x_step, int src_width, int check_size, guint32 color1,
+           guint32 color2)
+{
+  int x = x_init;
+  int i, j;
+
+  while (dest < dest_end)
+    {
+      int x_scaled = x >> SCALE_SHIFT;
+      int *pixel_weights;
+
+      pixel_weights = weights +
+        ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * n_x * n_y;
+
+      if (src_has_alpha)
+       {
+         unsigned int r = 0, g = 0, b = 0, a = 0;
+         for (i=0; i<n_y; i++)
+           {
+             guchar *q = src[i] + x_scaled * src_channels;
+             int *line_weights  = pixel_weights + n_x * i;
+             
+             for (j=0; j<n_x; j++)
+               {
+                 unsigned int ta;
+                 
+                 ta = q[3] * line_weights[j];
+                 r += ta * q[0];
+                 g += ta * q[1];
+                 b += ta * q[2];
+                 a += ta;
+                 
+                 q += src_channels;
+               }
+           }
+
+         if (a)
+           {
+             dest[0] = r / a;
+             dest[1] = g / a;
+             dest[2] = b / a;
+             dest[3] = a >> 16;
+           }
+         else
+           {
+             dest[0] = 0;
+             dest[1] = 0;
+             dest[2] = 0;
+             dest[3] = 0;
+           }
+       }
+      else
+       {
+         unsigned int r = 0, g = 0, b = 0;
+         for (i=0; i<n_y; i++)
+           {
+             guchar *q = src[i] + x_scaled * src_channels;
+             int *line_weights  = pixel_weights + n_x * i;
+             
+             for (j=0; j<n_x; j++)
+               {
+                 unsigned int ta = line_weights[j];
+                 
+                 r += ta * q[0];
+                 g += ta * q[1];
+                 b += ta * q[2];
+
+                 q += src_channels;
+               }
+           }
+
+         dest[0] = (r + 0xffff) >> 16;
+         dest[1] = (g + 0xffff) >> 16;
+         dest[2] = (b + 0xffff) >> 16;
+         
+         if (dest_has_alpha)
+           dest[3] = 0xff;
+       }
+
+      dest += dest_channels;
+      
+      x += x_step;
+    }
+
+  return dest;
+}
+
+#ifdef USE_MMX 
+static guchar *
+scale_line_22_33_mmx_stub (int *weights, int n_x, int n_y, guchar *dest,
+                          int dest_x, guchar *dest_end, int dest_channels,
+                          int dest_has_alpha, guchar **src, int src_channels,
+                          gboolean src_has_alpha, int x_init, int x_step,
+                          int src_width, int check_size, guint32 color1,
+                          guint32 color2)
+{
+  guint32 mmx_weights[16][8];
+  int j;
+
+  for (j=0; j<16; j++)
+    {
+      mmx_weights[j][0] = 0x00010001 * (weights[4*j] >> 8);
+      mmx_weights[j][1] = 0x00010001 * (weights[4*j] >> 8);
+      mmx_weights[j][2] = 0x00010001 * (weights[4*j + 1] >> 8);
+      mmx_weights[j][3] = 0x00010001 * (weights[4*j + 1] >> 8);
+      mmx_weights[j][4] = 0x00010001 * (weights[4*j + 2] >> 8);
+      mmx_weights[j][5] = 0x00010001 * (weights[4*j + 2] >> 8);
+      mmx_weights[j][6] = 0x00010001 * (weights[4*j + 3] >> 8);
+      mmx_weights[j][7] = 0x00010001 * (weights[4*j + 3] >> 8);
+    }
+
+  return _pixops_scale_line_22_33_mmx (mmx_weights, dest, src[0], src[1],
+                                      x_step, dest_end, x_init);
+}
+#endif /* USE_MMX */
+
+static guchar *
+scale_line_22_33 (int *weights, int n_x, int n_y, guchar *dest, int dest_x,
+                 guchar *dest_end, int dest_channels, int dest_has_alpha,
+                 guchar **src, int src_channels, gboolean src_has_alpha,
+                 int x_init, int x_step, int src_width,
+                 int check_size, guint32 color1, guint32 color2)
+{
+  int x = x_init;
+  guchar *src0 = src[0];
+  guchar *src1 = src[1];
+  
+  while (dest < dest_end)
+    {
+      unsigned int r, g, b;
+      int x_scaled = x >> SCALE_SHIFT;
+      int *pixel_weights;
+      guchar *q0, *q1;
+      int w1, w2, w3, w4;
+
+      q0 = src0 + x_scaled * 3;
+      q1 = src1 + x_scaled * 3;
+      
+      pixel_weights = weights +
+        ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * 4;
+
+      w1 = pixel_weights[0];
+      w2 = pixel_weights[1];
+      w3 = pixel_weights[2];
+      w4 = pixel_weights[3];
+
+      r = w1 * q0[0];
+      g = w1 * q0[1];
+      b = w1 * q0[2];
+
+      r += w2 * q0[3];
+      g += w2 * q0[4];
+      b += w2 * q0[5];
+
+      r += w3 * q1[0];
+      g += w3 * q1[1];
+      b += w3 * q1[2];
+
+      r += w4 * q1[3];
+      g += w4 * q1[4];
+      b += w4 * q1[5];
+
+      dest[0] = (r + 0x8000) >> 16;
+      dest[1] = (g + 0x8000) >> 16;
+      dest[2] = (b + 0x8000) >> 16;
+      
+      dest += 3;
+      x += x_step;
+    }
+  
+  return dest;
+}
+
+static void
+process_pixel (int *weights, int n_x, int n_y, guchar *dest, int dest_x,
+              int dest_channels, int dest_has_alpha, guchar **src,
+              int src_channels, gboolean src_has_alpha, int x_start,
+              int src_width, int check_size, guint32 color1, guint32 color2,
+              PixopsPixelFunc pixel_func)
+{
+  unsigned int r = 0, g = 0, b = 0, a = 0;
+  int i, j;
+  
+  for (i=0; i<n_y; i++)
+    {
+      int *line_weights  = weights + n_x * i;
+
+      for (j=0; j<n_x; j++)
+       {
+         unsigned int ta;
+         guchar *q;
+
+         if (x_start + j < 0)
+           q = src[i];
+         else if (x_start + j < src_width)
+           q = src[i] + (x_start + j) * src_channels;
+         else
+           q = src[i] + (src_width - 1) * src_channels;
+
+         if (src_has_alpha)
+           ta = q[3] * line_weights[j];
+         else
+           ta = 0xff * line_weights[j];
+
+         r += ta * q[0];
+         g += ta * q[1];
+         b += ta * q[2];
+         a += ta;
+       }
+    }
+
+  (*pixel_func) (dest, dest_x, dest_channels, dest_has_alpha, src_has_alpha,
+    check_size, color1, color2, r, g, b, a);
+}
+
+static void 
+correct_total (int    *weights, 
+               int    n_x, 
+               int    n_y,
+               int    total, 
+               double overall_alpha)
+{
+  int correction = (int)(0.5 + 65536 * overall_alpha) - total;
+  int remaining, c, d, i;
+  
+  if (correction != 0)
+    {
+      remaining = correction;
+      for (d = 1, c = correction; c != 0 && remaining != 0; d++, c = correction / d) 
+       for (i = n_x * n_y - 1; i >= 0 && c != 0 && remaining != 0; i--) 
+         if (*(weights + i) + c >= 0) 
+           {
+             *(weights + i) += c;
+             remaining -= c;
+             if ((0 < remaining && remaining < c) ||
+                 (0 > remaining && remaining > c))
+               c = remaining;
+           }
+    }
+}
+
+static int *
+make_filter_table (PixopsFilter *filter)
+{
+  int i_offset, j_offset;
+  int n_x = filter->x.n;
+  int n_y = filter->y.n;
+  int *weights = g_new (int, SUBSAMPLE * SUBSAMPLE * n_x * n_y);
+
+  for (i_offset=0; i_offset < SUBSAMPLE; i_offset++)
+    for (j_offset=0; j_offset < SUBSAMPLE; j_offset++)
+      {
+        double weight;
+        int *pixel_weights = weights + ((i_offset*SUBSAMPLE) + j_offset) * n_x * n_y;
+        int total = 0;
+        int i, j;
+
+        for (i=0; i < n_y; i++)
+          for (j=0; j < n_x; j++)
+            {
+              weight = filter->x.weights[(j_offset * n_x) + j] *
+                       filter->y.weights[(i_offset * n_y) + i] *
+                       filter->overall_alpha * 65536 + 0.5;
+
+              total += (int)weight;
+
+              *(pixel_weights + n_x * i + j) = weight;
+            }
+
+        correct_total (pixel_weights, n_x, n_y, total, filter->overall_alpha);
+      }
+
+  return weights;
+}
+
+static void
+pixops_process (guchar         *dest_buf,
+               int             render_x0,
+               int             render_y0,
+               int             render_x1,
+               int             render_y1,
+               int             dest_rowstride,
+               int             dest_channels,
+               gboolean        dest_has_alpha,
+               const guchar   *src_buf,
+               int             src_width,
+               int             src_height,
+               int             src_rowstride,
+               int             src_channels,
+               gboolean        src_has_alpha,
+               double          scale_x,
+               double          scale_y,
+               int             check_x,
+               int             check_y,
+               int             check_size,
+               guint32         color1,
+               guint32         color2,
+               PixopsFilter   *filter,
+               PixopsLineFunc  line_func,
+               PixopsPixelFunc pixel_func)
+{
+  int i, j;
+  int x, y;                    /* X and Y position in source (fixed_point) */
+
+  guchar **line_bufs;
+  int *filter_weights;
+
+  int x_step;
+  int y_step;
+
+  int check_shift;
+  int scaled_x_offset;
+
+  int run_end_x;
+  int run_end_index;
+
+  x_step = (1 << SCALE_SHIFT) / scale_x; /* X step in source (fixed point) */
+  y_step = (1 << SCALE_SHIFT) / scale_y; /* Y step in source (fixed point) */
+
+  if (x_step == 0 || y_step == 0)
+    return; /* overflow, bail out */
+
+  line_bufs = g_new (guchar *, filter->y.n);
+  filter_weights = make_filter_table (filter);
+
+  check_shift = check_size ? get_check_shift (check_size) : 0;
+
+  scaled_x_offset = floor (filter->x.offset * (1 << SCALE_SHIFT));
+
+  /* Compute the index where we run off the end of the source buffer. The
+   * furthest source pixel we access at index i is:
+   *
+   *  ((render_x0 + i) * x_step + scaled_x_offset) >> SCALE_SHIFT + filter->x.n - 1
+   *
+   * So, run_end_index is the smallest i for which this pixel is src_width,
+   * i.e, for which:
+   *
+   *  (i + render_x0) * x_step >= ((src_width - filter->x.n + 1) << SCALE_SHIFT) - scaled_x_offset
+   *
+   */
+#define MYDIV(a,b) ((a) > 0 ? (a) / (b) : ((a) - (b) + 1) / (b))    /* Division so that -1/5 = -1 */
+
+  run_end_x = (((src_width - filter->x.n + 1) << SCALE_SHIFT) - scaled_x_offset);
+  run_end_index = MYDIV (run_end_x + x_step - 1, x_step) - render_x0;
+  run_end_index = MIN (run_end_index, render_x1 - render_x0);
+
+  y = render_y0 * y_step + floor (filter->y.offset * (1 << SCALE_SHIFT));
+  for (i = 0; i < (render_y1 - render_y0); i++)
+    {
+      int dest_x;
+      int y_start = y >> SCALE_SHIFT;
+      int x_start;
+      int *run_weights = filter_weights +
+                         ((y >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) *
+                         filter->x.n * filter->y.n * SUBSAMPLE;
+      guchar *new_outbuf;
+      guint32 tcolor1, tcolor2;
+
+      guchar *outbuf = dest_buf + dest_rowstride * i;
+      guchar *outbuf_end = outbuf + dest_channels * (render_x1 - render_x0);
+
+      if (((i + check_y) >> check_shift) & 1)
+       {
+         tcolor1 = color2;
+         tcolor2 = color1;
+       }
+      else
+       {
+         tcolor1 = color1;
+         tcolor2 = color2;
+       }
+
+      for (j=0; j<filter->y.n; j++)
+       {
+         if (y_start <  0)
+           line_bufs[j] = (guchar *)src_buf;
+         else if (y_start < src_height)
+           line_bufs[j] = (guchar *)src_buf + src_rowstride * y_start;
+         else
+           line_bufs[j] = (guchar *)src_buf + src_rowstride * (src_height - 1);
+
+         y_start++;
+       }
+
+      dest_x = check_x;
+      x = render_x0 * x_step + scaled_x_offset;
+      x_start = x >> SCALE_SHIFT;
+
+      while (x_start < 0 && outbuf < outbuf_end)
+       {
+         process_pixel (run_weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * (filter->x.n * filter->y.n), filter->x.n, filter->y.n,
+                        outbuf, dest_x, dest_channels, dest_has_alpha,
+                        line_bufs, src_channels, src_has_alpha,
+                        x >> SCALE_SHIFT, src_width,
+                        check_size, tcolor1, tcolor2, pixel_func);
+
+         x += x_step;
+         x_start = x >> SCALE_SHIFT;
+         dest_x++;
+         outbuf += dest_channels;
+       }
+
+      new_outbuf = (*line_func) (run_weights, filter->x.n, filter->y.n,
+                                outbuf, dest_x, dest_buf + dest_rowstride *
+                                i + run_end_index * dest_channels,
+                                dest_channels, dest_has_alpha,
+                                line_bufs, src_channels, src_has_alpha,
+                                x, x_step, src_width, check_size, tcolor1,
+                                tcolor2);
+
+      dest_x += (new_outbuf - outbuf) / dest_channels;
+
+      x = (dest_x - check_x + render_x0) * x_step + scaled_x_offset;
+      outbuf = new_outbuf;
+
+      while (outbuf < outbuf_end)
+       {
+         process_pixel (run_weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * (filter->x.n * filter->y.n), filter->x.n, filter->y.n,
+                        outbuf, dest_x, dest_channels, dest_has_alpha,
+                        line_bufs, src_channels, src_has_alpha,
+                        x >> SCALE_SHIFT, src_width,
+                        check_size, tcolor1, tcolor2, pixel_func);
+
+         x += x_step;
+         dest_x++;
+         outbuf += dest_channels;
+       }
+
+      y += y_step;
+    }
+
+  g_free (line_bufs);
+  g_free (filter_weights);
+}
+
+/* Compute weights for reconstruction by replication followed by
+ * sampling with a box filter
+ */
+static void
+tile_make_weights (PixopsFilterDimension *dim,
+                  double                 scale)
+{
+  int n = ceil (1 / scale + 1);
+  double *pixel_weights = g_new (double, SUBSAMPLE * n);
+  int offset;
+  int i;
+
+  dim->n = n;
+  dim->offset = 0;
+  dim->weights = pixel_weights;
+
+  for (offset = 0; offset < SUBSAMPLE; offset++)
+    {
+      double x = (double)offset / SUBSAMPLE;
+      double a = x + 1 / scale;
+
+      for (i = 0; i < n; i++)
+        {
+          if (i < x)
+            {
+              if (i + 1 > x)
+                *(pixel_weights++)  = (MIN (i + 1, a) - x) * scale;
+              else
+                *(pixel_weights++) = 0;
+            }
+          else
+            {
+              if (a > i)
+                *(pixel_weights++)  = (MIN (i + 1, a) - i) * scale;
+              else
+                *(pixel_weights++) = 0;
+            }
+       }
+    }
+}
+
+/* Compute weights for a filter that, for minification
+ * is the same as 'tiles', and for magnification, is bilinear
+ * reconstruction followed by a sampling with a delta function.
+ */
+static void
+bilinear_magnify_make_weights (PixopsFilterDimension *dim,
+                              double                 scale)
+{
+  double *pixel_weights;
+  int n;
+  int offset;
+  int i;
+
+  if (scale > 1.0)            /* Linear */
+    {
+      n = 2;
+      dim->offset = 0.5 * (1 / scale - 1);
+    }
+  else                          /* Tile */
+    {
+      n = ceil (1.0 + 1.0 / scale);
+      dim->offset = 0.0;
+    }
+
+  dim->n = n;
+  dim->weights = g_new (double, SUBSAMPLE * n);
+
+  pixel_weights = dim->weights;
+
+  for (offset=0; offset < SUBSAMPLE; offset++)
+    {
+      double x = (double)offset / SUBSAMPLE;
+
+      if (scale > 1.0)      /* Linear */
+        {
+          for (i = 0; i < n; i++)
+            *(pixel_weights++) = (((i == 0) ? (1 - x) : x) / scale) * scale;
+        }
+      else                  /* Tile */
+        {
+          double a = x + 1 / scale;
+
+          /*           x
+           * ---------|--.-|----|--.-|-------  SRC
+           * ------------|---------|---------  DEST
+           */
+          for (i = 0; i < n; i++)
+            {
+              if (i < x)
+                {
+                  if (i + 1 > x)
+                    *(pixel_weights++) = (MIN (i + 1, a) - x) * scale;
+                  else
+                    *(pixel_weights++) = 0;
+                }
+              else
+                {
+                  if (a > i)
+                    *(pixel_weights++) = (MIN (i + 1, a) - i) * scale;
+                  else
+                    *(pixel_weights++) = 0;
+                }
+            }
+        }
+    }
+}
+
+/* Computes the integral from b0 to b1 of
+ *
+ * f(x) = x; 0 <= x < 1
+ * f(x) = 0; otherwise
+ *
+ * We combine two of these to compute the convolution of
+ * a box filter with a triangular spike.
+ */
+static double
+linear_box_half (double b0, double b1)
+{
+  double a0, a1;
+  double x0, x1;
+
+  a0 = 0.;
+  a1 = 1.;
+
+  if (a0 < b0)
+    {
+      if (a1 > b0)
+        {
+          x0 = b0;
+          x1 = MIN (a1, b1);
+        }
+      else
+        return 0;
+    }
+  else
+    {
+      if (b1 > a0)
+        {
+          x0 = a0;
+          x1 = MIN (a1, b1);
+        }
+      else
+        return 0;
+    }
+
+  return 0.5 * (x1*x1 - x0*x0);
+}
+
+/* Compute weights for reconstructing with bilinear
+ * interpolation, then sampling with a box filter
+ */
+static void
+bilinear_box_make_weights (PixopsFilterDimension *dim,
+                          double                 scale)
+{
+  int n = ceil (1/scale + 3.0);
+  double *pixel_weights = g_new (double, SUBSAMPLE * n);
+  double w;
+  int offset, i;
+
+  dim->offset = -1.0;
+  dim->n = n;
+  dim->weights = pixel_weights;
+
+  for (offset = 0; offset < SUBSAMPLE; offset++)
+    {
+      double x = (double)offset / SUBSAMPLE;
+      double a = x + 1 / scale;
+
+      for (i = 0; i < n; i++)
+        {
+          w  = linear_box_half (0.5 + i - a, 0.5 + i - x);
+          w += linear_box_half (1.5 + x - i, 1.5 + a - i);
+      
+          *(pixel_weights++) = w * scale;
+        }
+    }
+}
+
+static void
+make_weights (PixopsFilter     *filter,
+             PixopsInterpType  interp_type,          
+             double            scale_x,
+             double            scale_y)
+{
+  switch (interp_type)
+    {
+    case PIXOPS_INTERP_NEAREST:
+      g_assert_not_reached ();
+      break;
+
+    case PIXOPS_INTERP_TILES:
+      tile_make_weights (&filter->x, scale_x);
+      tile_make_weights (&filter->y, scale_y);
+      break;
+      
+    case PIXOPS_INTERP_BILINEAR:
+      bilinear_magnify_make_weights (&filter->x, scale_x);
+      bilinear_magnify_make_weights (&filter->y, scale_y);
+      break;
+      
+    case PIXOPS_INTERP_HYPER:
+      bilinear_box_make_weights (&filter->x, scale_x);
+      bilinear_box_make_weights (&filter->y, scale_y);
+      break;
+    }
+}
+
+static void
+_pixops_composite_color_real (guchar          *dest_buf,
+                             int              render_x0,
+                             int              render_y0,
+                             int              render_x1,
+                             int              render_y1,
+                             int              dest_rowstride,
+                             int              dest_channels,
+                             gboolean         dest_has_alpha,
+                             const guchar    *src_buf,
+                             int              src_width,
+                             int              src_height,
+                             int              src_rowstride,
+                             int              src_channels,
+                             gboolean         src_has_alpha,
+                             double           scale_x,
+                             double           scale_y,
+                             PixopsInterpType interp_type,
+                             int              overall_alpha,
+                             int              check_x,
+                             int              check_y,
+                             int              check_size,
+                             guint32          color1,
+                             guint32          color2)
+{
+  PixopsFilter filter;
+  PixopsLineFunc line_func;
+  
+#ifdef USE_MMX
+  gboolean found_mmx = _pixops_have_mmx ();
+#endif
+
+  g_return_if_fail (!(dest_channels == 3 && dest_has_alpha));
+  g_return_if_fail (!(src_channels == 3 && src_has_alpha));
+
+  if (scale_x == 0 || scale_y == 0)
+    return;
+
+  if (interp_type == PIXOPS_INTERP_NEAREST)
+    {
+      pixops_composite_color_nearest (dest_buf, render_x0, render_y0,
+                                     render_x1, render_y1, dest_rowstride,
+                                     dest_channels, dest_has_alpha, src_buf,
+                                     src_width, src_height, src_rowstride,
+                                     src_channels, src_has_alpha, scale_x,
+                                     scale_y, overall_alpha, check_x, check_y,
+                                     check_size, color1, color2);
+      return;
+    }
+  
+  filter.overall_alpha = overall_alpha / 255.;
+  make_weights (&filter, interp_type, scale_x, scale_y);
+
+#ifdef USE_MMX
+  if (filter.x.n == 2 && filter.y.n == 2 &&
+      dest_channels == 4 && src_channels == 4 &&
+      src_has_alpha && !dest_has_alpha && found_mmx)
+    line_func = composite_line_color_22_4a4_mmx_stub;
+  else
+#endif
+    line_func = composite_line_color;
+  
+  pixops_process (dest_buf, render_x0, render_y0, render_x1, render_y1,
+                 dest_rowstride, dest_channels, dest_has_alpha,
+                 src_buf, src_width, src_height, src_rowstride, src_channels,
+                 src_has_alpha, scale_x, scale_y, check_x, check_y, check_size, color1, color2,
+                 &filter, line_func, composite_pixel_color);
+
+  g_free (filter.x.weights);
+  g_free (filter.y.weights);
+}
+
+void
+_pixops_composite_color (guchar          *dest_buf,
+                        int              dest_width,
+                        int              dest_height,
+                        int              dest_rowstride,
+                        int              dest_channels,
+                        gboolean         dest_has_alpha,
+                        const guchar    *src_buf,
+                        int              src_width,
+                        int              src_height,
+                        int              src_rowstride,
+                        int              src_channels,
+                        gboolean         src_has_alpha,
+                        int              dest_x,
+                        int              dest_y,
+                        int              dest_region_width,
+                        int              dest_region_height,
+                        double           offset_x,
+                        double           offset_y,
+                        double           scale_x,
+                        double           scale_y,
+                        PixopsInterpType interp_type,
+                        int              overall_alpha,
+                        int              check_x,
+                        int              check_y,
+                        int              check_size,
+                        guint32          color1,
+                        guint32          color2)
+{
+  guchar *new_dest_buf;
+  int render_x0;
+  int render_y0;
+  int render_x1;
+  int render_y1;
+
+  if (!src_has_alpha && overall_alpha == 255)
+    {
+      _pixops_scale (dest_buf, dest_width, dest_height, dest_rowstride,
+                    dest_channels, dest_has_alpha, src_buf, src_width,
+                    src_height, src_rowstride, src_channels, src_has_alpha,
+                    dest_x, dest_y, dest_region_width, dest_region_height,
+                    offset_x, offset_y, scale_x, scale_y, interp_type);
+      return;
+    }
+
+  new_dest_buf = dest_buf + dest_y * dest_rowstride + dest_x *
+                 dest_channels;
+  render_x0 = dest_x - offset_x;
+  render_y0 = dest_y - offset_y;
+  render_x1 = dest_x + dest_region_width  - offset_x;
+  render_y1 = dest_y + dest_region_height - offset_y;
+
+  _pixops_composite_color_real (new_dest_buf, render_x0, render_y0, render_x1,
+                               render_y1, dest_rowstride, dest_channels,
+                               dest_has_alpha, src_buf, src_width,
+                               src_height, src_rowstride, src_channels,
+                               src_has_alpha, scale_x, scale_y,
+                               (PixopsInterpType)interp_type, overall_alpha,
+                               check_x, check_y, check_size, color1, color2);
+}
+
+/**
+ * _pixops_composite_real:
+ * @dest_buf: pointer to location to store result
+ * @render_x0: x0 of region of scaled source to store into @dest_buf
+ * @render_y0: y0 of region of scaled source to store into @dest_buf
+ * @render_x1: x1 of region of scaled source to store into @dest_buf
+ * @render_y1: y1 of region of scaled source to store into @dest_buf
+ * @dest_rowstride: rowstride of @dest_buf
+ * @dest_channels: number of channels in @dest_buf
+ * @dest_has_alpha: whether @dest_buf has alpha
+ * @src_buf: pointer to source pixels
+ * @src_width: width of source (used for clipping)
+ * @src_height: height of source (used for clipping)
+ * @src_rowstride: rowstride of source
+ * @src_channels: number of channels in @src_buf
+ * @src_has_alpha: whether @src_buf has alpha
+ * @scale_x: amount to scale source by in X direction
+ * @scale_y: amount to scale source by in Y direction
+ * @interp_type: type of enumeration
+ * @overall_alpha: overall alpha factor to multiply source by
+ * 
+ * Scale source buffer by scale_x / scale_y, then composite a given rectangle
+ * of the result into the destination buffer.
+ **/
+static void
+_pixops_composite_real (guchar          *dest_buf,
+                       int              render_x0,
+                       int              render_y0,
+                       int              render_x1,
+                       int              render_y1,
+                       int              dest_rowstride,
+                       int              dest_channels,
+                       gboolean         dest_has_alpha,
+                       const guchar    *src_buf,
+                       int              src_width,
+                       int              src_height,
+                       int              src_rowstride,
+                       int              src_channels,
+                       gboolean         src_has_alpha,
+                       double           scale_x,
+                       double           scale_y,
+                       PixopsInterpType interp_type,
+                       int              overall_alpha)
+{
+  PixopsFilter filter;
+  PixopsLineFunc line_func;
+  
+#ifdef USE_MMX
+  gboolean found_mmx = _pixops_have_mmx ();
+#endif
+
+  g_return_if_fail (!(dest_channels == 3 && dest_has_alpha));
+  g_return_if_fail (!(src_channels == 3 && src_has_alpha));
+
+  if (scale_x == 0 || scale_y == 0)
+    return;
+
+  if (interp_type == PIXOPS_INTERP_NEAREST)
+    {
+      pixops_composite_nearest (dest_buf, render_x0, render_y0, render_x1,
+                               render_y1, dest_rowstride, dest_channels,
+                               dest_has_alpha, src_buf, src_width, src_height,
+                               src_rowstride, src_channels, src_has_alpha,
+                               scale_x, scale_y, overall_alpha);
+      return;
+    }
+  
+  filter.overall_alpha = overall_alpha / 255.;
+  make_weights (&filter, interp_type, scale_x, scale_y);
+
+  if (filter.x.n == 2 && filter.y.n == 2 && dest_channels == 4 &&
+      src_channels == 4 && src_has_alpha && !dest_has_alpha)
+    {
+#ifdef USE_MMX
+      if (found_mmx)
+       line_func = composite_line_22_4a4_mmx_stub;
+      else
+#endif 
+       line_func = composite_line_22_4a4;
+    }
+  else
+    line_func = composite_line;
+  
+  pixops_process (dest_buf, render_x0, render_y0, render_x1, render_y1,
+                 dest_rowstride, dest_channels, dest_has_alpha,
+                 src_buf, src_width, src_height, src_rowstride, src_channels,
+                 src_has_alpha, scale_x, scale_y, 0, 0, 0, 0, 0, 
+                 &filter, line_func, composite_pixel);
+
+  g_free (filter.x.weights);
+  g_free (filter.y.weights);
+}
+
+void
+_pixops_composite (guchar          *dest_buf,
+                   int              dest_width,
+                   int              dest_height,
+                   int              dest_rowstride,
+                   int              dest_channels,
+                   int              dest_has_alpha,
+                   const guchar    *src_buf,
+                   int              src_width,
+                   int              src_height,
+                   int              src_rowstride,
+                   int              src_channels,
+                   int              src_has_alpha,
+                   int              dest_x,
+                   int              dest_y,
+                   int              dest_region_width,
+                   int              dest_region_height,
+                   double           offset_x,
+                   double           offset_y,
+                   double           scale_x,
+                   double           scale_y,
+                   PixopsInterpType interp_type,
+                   int              overall_alpha)
+{
+  guchar *new_dest_buf;
+  int render_x0;
+  int render_y0;
+  int render_x1;
+  int render_y1;
+
+  if (!src_has_alpha && overall_alpha == 255)
+    {
+      _pixops_scale (dest_buf, dest_width, dest_height, dest_rowstride,
+                    dest_channels, dest_has_alpha, src_buf, src_width,
+                    src_height, src_rowstride, src_channels, src_has_alpha,
+                    dest_x, dest_y, dest_region_width, dest_region_height,
+                    offset_x, offset_y, scale_x, scale_y, interp_type);
+      return;
+    }
+
+#ifdef USE_MEDIALIB
+  pixops_medialib_composite (dest_buf, dest_width, dest_height, dest_rowstride,
+                             dest_channels, dest_has_alpha, src_buf,
+                             src_width, src_height, src_rowstride,
+                             src_channels, src_has_alpha, dest_x, dest_y,
+                             dest_region_width, dest_region_height, offset_x,
+                            offset_y, scale_x, scale_y,
+                             (PixopsInterpType)interp_type, overall_alpha);
+  return;
+#endif
+
+  new_dest_buf = dest_buf + dest_y * dest_rowstride + dest_x * dest_channels;
+  render_x0 = dest_x - offset_x;
+  render_y0 = dest_y - offset_y;
+  render_x1 = dest_x + dest_region_width  - offset_x;
+  render_y1 = dest_y + dest_region_height - offset_y;
+
+  _pixops_composite_real (new_dest_buf, render_x0, render_y0, render_x1,
+                         render_y1, dest_rowstride, dest_channels,
+                         dest_has_alpha, src_buf, src_width, src_height,
+                         src_rowstride, src_channels, src_has_alpha, scale_x,
+                         scale_y, (PixopsInterpType)interp_type,
+                         overall_alpha);
+}
+
+#ifdef USE_MEDIALIB
+static void
+medialib_get_interpolation (mlInterp * ml_interp,
+                            PixopsInterpType interp_type,
+                            double scale_x,
+                            double scale_y,
+                            double overall_alpha)
+{
+  mlib_s32 leftPadding, topPadding;
+  ml_interp->interp_table = NULL;
+
+ /*
+  * medialib 2.1 and later supports scaling with user-defined interpolation
+  * tables, so this logic is used.  
+  *
+  * bilinear_magnify_make_weights builds an interpolation table of size 2x2 if
+  * the scale factor >= 1.0 and "ceil (1.0 + 1.0/scale)" otherwise.  These map
+  * most closely to MLIB_BILINEAR, which uses an interpolation table of size
+  * 2x2.
+  *
+  * tile_make_weights builds an interpolation table of size 2x2 if the scale
+  * factor >= 1.0 and "ceil (1.0 + 1.0/scale)" otherwise.  These map most
+  * closely to MLIB_BILINEAR, which uses an interpolation table of size 2x2.
+  *
+  * bilinear_box_make_weights builds an interpolation table of size 4x4 if the
+  * scale factor >= 1.0 and "ceil (1.0 + 1.0/scale)" otherwise.  These map most
+  * closely to MLIB_BICUBIC, which uses an interpolation table of size 4x4.
+  *
+  * PIXOPS_INTERP_NEAREST calls pixops_scale_nearest which does not use an
+  * interpolation table.  This maps to MLIB_NEAREST.
+  */
+  switch (interp_type)
+    {
+    case PIXOPS_INTERP_BILINEAR:
+      bilinear_magnify_make_weights (&(ml_interp->po_filter.x), scale_x);
+      bilinear_magnify_make_weights (&(ml_interp->po_filter.y), scale_y);
+      leftPadding = 0;
+      topPadding  = 0;
+
+      if (scale_x <= 1.0)
+          ml_interp->tx = 0.5 * (1 - scale_x);
+      else
+          ml_interp->tx = 0.0;
+
+      if (scale_y <= 1.0)
+          ml_interp->ty = 0.5 * (1 - scale_y);
+      else
+          ml_interp->ty = 0.0;
+
+      break;
+
+    case PIXOPS_INTERP_TILES:
+      tile_make_weights (&(ml_interp->po_filter.x), scale_x);
+      tile_make_weights (&(ml_interp->po_filter.y), scale_y);
+      leftPadding   = 0;
+      topPadding    = 0;
+      ml_interp->tx = 0.5 * (1 - scale_x);
+      ml_interp->ty = 0.5 * (1 - scale_y);
+      break;
+
+    case PIXOPS_INTERP_HYPER:
+      bilinear_box_make_weights (&(ml_interp->po_filter.x), scale_x);
+      bilinear_box_make_weights (&(ml_interp->po_filter.y), scale_y);
+      leftPadding   = 1;
+      topPadding    = 1;
+      ml_interp->tx = 0.5 * (1 - scale_x);
+      ml_interp->ty = 0.5 * (1 - scale_y);
+      break;
+
+    case PIXOPS_INTERP_NEAREST:
+    default:
+      /*
+       * Note that this function should not be called in the
+       * PIXOPS_INTERP_NEAREST case since it does not use an interpolation
+       * table.
+       */
+      g_assert_not_reached ();
+      break;
+    }
+
+ /* 
+  * If overall_alpha is not 1.0, then multiply the vectors built by the
+  * sqrt (overall_alpha).  This will cause overall_alpha to get evenly
+  * blended across both axis.
+  *
+  * Note there is no need to multiply the vectors built by the various
+  * make-weight functions by sqrt (overall_alpha) since the make-weight
+  * functions are called with overall_alpha hardcoded to 1.0.
+  */
+  if (overall_alpha != 1.0)
+    {
+      double sqrt_alpha = sqrt (overall_alpha);
+      int i;
+
+      for (i=0; i < SUBSAMPLE * ml_interp->po_filter.x.n; i++)
+         ml_interp->po_filter.x.weights[i] *= sqrt_alpha;
+      for (i=0; i < SUBSAMPLE * ml_interp->po_filter.y.n; i++)
+         ml_interp->po_filter.y.weights[i] *= sqrt_alpha;
+    }
+    
+  ml_interp->interp_table = (void *) mlib_ImageInterpTableCreate (MLIB_DOUBLE,
+    ml_interp->po_filter.x.n, ml_interp->po_filter.y.n, leftPadding,
+    topPadding, SUBSAMPLE_BITS, SUBSAMPLE_BITS, 8,
+    ml_interp->po_filter.x.weights, ml_interp->po_filter.y.weights);
+
+  g_free (ml_interp->po_filter.x.weights);
+  g_free (ml_interp->po_filter.y.weights);  
+}
+
+static void
+pixops_medialib_composite (guchar          *dest_buf,
+                           int              dest_width,
+                           int              dest_height,
+                           int              dest_rowstride,
+                           int              dest_channels,
+                           int              dest_has_alpha,
+                           const guchar    *src_buf,
+                           int              src_width,
+                           int              src_height,
+                           int              src_rowstride,
+                           int              src_channels,
+                           int              src_has_alpha,
+                           int              dest_x,
+                           int              dest_y,
+                           int              dest_region_width,
+                           int              dest_region_height,
+                           double           offset_x,
+                           double           offset_y,
+                           double           scale_x,
+                           double           scale_y,
+                           PixopsInterpType interp_type,
+                           int              overall_alpha)
+{
+  mlib_blend blend;
+  g_return_if_fail (!(dest_channels == 3 && dest_has_alpha));
+  g_return_if_fail (!(src_channels == 3 && src_has_alpha));
+
+  if (scale_x == 0 || scale_y == 0)
+    return;
+
+  if (!medialib_initialized)
+    _pixops_use_medialib ();
+
+  if (!use_medialib)
+    {
+      /* Use non-mediaLib version */
+      _pixops_composite_real (dest_buf + dest_y * dest_rowstride + dest_x *
+                             dest_channels, dest_x - offset_x, dest_y -
+                             offset_y, dest_x + dest_region_width - offset_x,
+                             dest_y + dest_region_height - offset_y,
+                             dest_rowstride, dest_channels, dest_has_alpha,
+                             src_buf, src_width, src_height, src_rowstride,
+                             src_channels, src_has_alpha, scale_x, scale_y,
+                             interp_type, overall_alpha);
+    }
+  else
+    {
+      mlInterp ml_interp;
+      mlib_image img_src, img_dest;
+      double ml_offset_x, ml_offset_y;
+
+      if (!src_has_alpha && overall_alpha == 255 &&
+         dest_channels <= src_channels) 
+        {
+          pixops_medialib_scale (dest_buf, dest_region_width,
+                                dest_region_height, dest_rowstride,
+                                dest_channels, dest_has_alpha, src_buf,
+                                src_width, src_height, src_rowstride,
+                                src_channels, src_has_alpha, dest_x, dest_y,
+                                dest_region_width, dest_region_height,
+                                offset_x, offset_y, scale_x, scale_y,
+                                interp_type);
+          return;
+        }
+
+      mlib_ImageSetStruct (&img_src, MLIB_BYTE, src_channels,
+                          src_width, src_height, src_rowstride, src_buf);
+
+      if (dest_x == 0 && dest_y == 0 &&
+          dest_width  == dest_region_width &&
+          dest_height == dest_region_height)
+        {
+          mlib_ImageSetStruct (&img_dest, MLIB_BYTE, dest_channels,
+                              dest_width, dest_height, dest_rowstride,
+                              dest_buf);
+        }
+      else
+        {
+         mlib_u8 *data = dest_buf + (dest_y * dest_rowstride) + 
+                                    (dest_x * dest_channels);
+
+          mlib_ImageSetStruct (&img_dest, MLIB_BYTE, dest_channels,
+                              dest_region_width, dest_region_height,
+                              dest_rowstride, data);
+        }
+
+      ml_offset_x = floor (offset_x) - dest_x;
+      ml_offset_y = floor (offset_y) - dest_y;
+
+      if (interp_type == PIXOPS_INTERP_NEAREST)
+        {
+          blend = src_has_alpha ? MLIB_BLEND_GTK_SRC_OVER2 : MLIB_BLEND_GTK_SRC;
+
+          mlib_ImageZoomTranslateBlend (&img_dest,
+                                        &img_src,
+                                        scale_x,
+                                        scale_y,
+                                        ml_offset_x,
+                                        ml_offset_y,
+                                        MLIB_NEAREST,
+                                        MLIB_EDGE_SRC_EXTEND_INDEF,
+                                        blend,
+                                        overall_alpha,
+                                        1);
+        }
+      else
+        {
+          blend = src_has_alpha ? MLIB_BLEND_GTK_SRC_OVER : MLIB_BLEND_GTK_SRC;
+
+          if (interp_type == PIXOPS_INTERP_BILINEAR &&
+             scale_x > 1.0 && scale_y > 1.0)
+            {
+              mlib_ImageZoomTranslateBlend (&img_dest,
+                                            &img_src,
+                                            scale_x,
+                                            scale_y,
+                                            ml_offset_x,
+                                            ml_offset_y,
+                                            MLIB_BILINEAR,
+                                            MLIB_EDGE_SRC_EXTEND_INDEF,
+                                            blend,
+                                            overall_alpha,
+                                            1);
+            }
+          else
+            {
+              medialib_get_interpolation (&ml_interp, interp_type, scale_x,
+                                         scale_y, overall_alpha/255.0);
+
+              if (ml_interp.interp_table != NULL)
+                {
+                  mlib_ImageZoomTranslateTableBlend (&img_dest,
+                                                     &img_src,
+                                                     scale_x,
+                                                     scale_y,
+                                                     ml_offset_x + ml_interp.tx,
+                                                     ml_offset_y + ml_interp.ty,
+                                                     ml_interp.interp_table,
+                                                     MLIB_EDGE_SRC_EXTEND_INDEF,
+                                                     blend,
+                                                     1);
+                  mlib_ImageInterpTableDelete (ml_interp.interp_table);
+                }
+              else
+                {
+                  /* Should not happen - Use non-mediaLib version */
+                  _pixops_composite_real (dest_buf + dest_y * dest_rowstride +
+                                          dest_x * dest_channels,
+                                          dest_x - offset_x, dest_y - offset_y,
+                                          dest_x + dest_region_width - offset_x,
+                                          dest_y + dest_region_height - offset_y,
+                                          dest_rowstride, dest_channels,
+                                          dest_has_alpha, src_buf, src_width,
+                                          src_height, src_rowstride,
+                                          src_channels, src_has_alpha, scale_x,
+                                          scale_y, interp_type, overall_alpha);
+                }
+            }
+        }
+    }
+}
+#endif
+
+static void
+_pixops_scale_real (guchar        *dest_buf,
+                   int            render_x0,
+                   int            render_y0,
+                   int            render_x1,
+                   int            render_y1,
+                   int            dest_rowstride,
+                   int            dest_channels,
+                   gboolean       dest_has_alpha,
+                   const guchar  *src_buf,
+                   int            src_width,
+                   int            src_height,
+                   int            src_rowstride,
+                   int            src_channels,
+                   gboolean       src_has_alpha,
+                   double         scale_x,
+                   double         scale_y,
+                   PixopsInterpType  interp_type)
+{
+  PixopsFilter filter;
+  PixopsLineFunc line_func;
+
+#ifdef USE_MMX
+  gboolean found_mmx = _pixops_have_mmx ();
+#endif
+
+  g_return_if_fail (!(dest_channels == 3 && dest_has_alpha));
+  g_return_if_fail (!(src_channels == 3 && src_has_alpha));
+  g_return_if_fail (!(src_has_alpha && !dest_has_alpha));
+
+  if (scale_x == 0 || scale_y == 0)
+    return;
+
+  if (interp_type == PIXOPS_INTERP_NEAREST)
+    {
+      pixops_scale_nearest (dest_buf, render_x0, render_y0, render_x1,
+                           render_y1, dest_rowstride, dest_channels,
+                           dest_has_alpha, src_buf, src_width, src_height,
+                           src_rowstride, src_channels, src_has_alpha,
+                           scale_x, scale_y);
+      return;
+    }
+  
+  filter.overall_alpha = 1.0;
+  make_weights (&filter, interp_type, scale_x, scale_y);
+
+  if (filter.x.n == 2 && filter.y.n == 2 && dest_channels == 3 && src_channels == 3)
+    {
+#ifdef USE_MMX
+      if (found_mmx)
+       line_func = scale_line_22_33_mmx_stub;
+      else
+#endif
+       line_func = scale_line_22_33;
+    }
+  else
+    line_func = scale_line;
+  
+  pixops_process (dest_buf, render_x0, render_y0, render_x1, render_y1,
+                 dest_rowstride, dest_channels, dest_has_alpha,
+                 src_buf, src_width, src_height, src_rowstride, src_channels,
+                 src_has_alpha, scale_x, scale_y, 0, 0, 0, 0, 0,
+                 &filter, line_func, scale_pixel);
+
+  g_free (filter.x.weights);
+  g_free (filter.y.weights);
+}
+
+void
+_pixops_scale (guchar          *dest_buf,
+               int              dest_width,
+               int              dest_height,
+               int              dest_rowstride,
+               int              dest_channels,
+               int              dest_has_alpha,
+               const guchar    *src_buf,
+               int              src_width,
+               int              src_height,
+               int              src_rowstride,
+               int              src_channels,
+               int              src_has_alpha,
+               int              dest_x,
+               int              dest_y,
+               int              dest_region_width,
+               int              dest_region_height,
+               double           offset_x,
+               double           offset_y,
+               double           scale_x,
+               double           scale_y,
+               PixopsInterpType interp_type)
+{
+  guchar *new_dest_buf;
+  int render_x0;
+  int render_y0;
+  int render_x1;
+  int render_y1;
+
+#ifdef USE_MEDIALIB
+  pixops_medialib_scale (dest_buf, dest_width, dest_height, dest_rowstride,
+                         dest_channels, dest_has_alpha, src_buf, src_width,
+                         src_height, src_rowstride, src_channels,
+                         src_has_alpha, dest_x, dest_y, dest_region_width,
+                        dest_region_height, offset_x, offset_y, scale_x,
+                        scale_y, (PixopsInterpType)interp_type);
+  return;
+#endif
+
+  new_dest_buf = dest_buf + dest_y * dest_rowstride + dest_x * dest_channels;
+  render_x0    = dest_x - offset_x;
+  render_y0    = dest_y - offset_y;
+  render_x1    = dest_x + dest_region_width  - offset_x;
+  render_y1    = dest_y + dest_region_height - offset_y;
+
+  _pixops_scale_real (new_dest_buf, render_x0, render_y0, render_x1,
+                      render_y1, dest_rowstride, dest_channels,
+                      dest_has_alpha, src_buf, src_width, src_height,
+                      src_rowstride, src_channels, src_has_alpha,
+                      scale_x, scale_y, (PixopsInterpType)interp_type);
+}
+
+#ifdef USE_MEDIALIB
+static void
+pixops_medialib_scale     (guchar          *dest_buf,
+                           int              dest_width,
+                           int              dest_height,
+                           int              dest_rowstride,
+                           int              dest_channels,
+                           int              dest_has_alpha,
+                           const guchar    *src_buf,
+                           int              src_width,
+                           int              src_height,
+                           int              src_rowstride,
+                           int              src_channels,
+                           int              src_has_alpha,
+                           int              dest_x,
+                           int              dest_y,
+                           int              dest_region_width,
+                           int              dest_region_height,
+                           double           offset_x,
+                           double           offset_y,
+                           double           scale_x,
+                           double           scale_y,
+                           PixopsInterpType interp_type)
+{
+  if (scale_x == 0 || scale_y == 0)
+    return;
+
+  if (!medialib_initialized)
+    _pixops_use_medialib ();
+  /*
+   * We no longer support mediaLib 2.1 because it has a core dumping problem
+   * in the mlib_ImageZoomTranslateTable function that has been corrected in
+   * 2.2.  Although the mediaLib_zoom function could be used, it does not
+   * work properly if the source and destination images have different 
+   * values for "has_alpha" or "num_channels".  The complicated if-logic
+   * required to support both versions is not worth supporting
+   * mediaLib 2.1 moving forward.
+   */
+  if (!use_medialib)
+    {
+      _pixops_scale_real (dest_buf + dest_y * dest_rowstride + dest_x *
+                         dest_channels, dest_x - offset_x, dest_y - offset_y, 
+                         dest_x + dest_region_width - offset_x,
+                         dest_y + dest_region_height - offset_y,
+                         dest_rowstride, dest_channels, dest_has_alpha,
+                         src_buf, src_width, src_height, src_rowstride,
+                         src_channels, src_has_alpha, scale_x, scale_y,
+                         interp_type);
+    }
+  else 
+    {
+      mlInterp ml_interp;
+      mlib_image img_orig_src, img_src, img_dest;
+      double ml_offset_x, ml_offset_y;
+      guchar *tmp_buf = NULL;
+
+      mlib_ImageSetStruct (&img_orig_src, MLIB_BYTE, src_channels, src_width, 
+                          src_height, src_rowstride, src_buf);
+
+      if (dest_x == 0 && dest_y == 0 &&
+          dest_width == dest_region_width &&
+          dest_height == dest_region_height)
+        {
+          mlib_ImageSetStruct (&img_dest, MLIB_BYTE, dest_channels,
+                              dest_width, dest_height, dest_rowstride,
+                              dest_buf);
+        }
+      else
+        {
+         mlib_u8 *data = dest_buf + (dest_y * dest_rowstride) + 
+                                    (dest_x * dest_channels);
+
+          mlib_ImageSetStruct (&img_dest, MLIB_BYTE, dest_channels,
+                              dest_region_width, dest_region_height,
+                              dest_rowstride, data);
+        }
+
+      ml_offset_x = floor (offset_x) - dest_x;
+      ml_offset_y = floor (offset_y) - dest_y;
+
+     /*
+      * Note that zoomTranslate and zoomTranslateTable are faster
+      * than zoomTranslateBlend and zoomTranslateTableBlend.  However
+      * the faster functions only work in the following case:
+      *
+      *   if (src_channels == dest_channels &&
+      *       (!src_alpha && interp_table != PIXOPS_INTERP_NEAREST))
+      *
+      * We use the faster versions if we can.
+      *
+      * Note when the interp_type is BILINEAR and the interpolation
+      * table will be size 2x2 (when both x/y scale factors > 1.0),
+      * then we do not bother building the interpolation table.   In
+      * this case we can just use MLIB_BILINEAR, which is faster than
+      * using a specified interpolation table.
+      */
+      img_src = img_orig_src;
+
+      if (!src_has_alpha)
+        {
+          if (src_channels > dest_channels)
+            {
+              int channels  = 3;
+              int rowstride = (channels * src_width + 3) & ~3;
+        
+              tmp_buf = g_malloc (src_rowstride * src_height);
+
+              if (src_buf != NULL)
+                {
+                  src_channels  = channels;
+                  src_rowstride = rowstride;
+          
+                  mlib_ImageSetStruct (&img_src, MLIB_BYTE, src_channels,
+                                      src_width, src_height, src_rowstride,
+                                      tmp_buf);
+                  mlib_ImageChannelExtract (&img_src, &img_orig_src, 0xE);  
+                }
+            }
+        }
+    
+      if (interp_type == PIXOPS_INTERP_NEAREST)
+        {
+          if (src_channels == dest_channels)
+            {
+              mlib_ImageZoomTranslate (&img_dest,
+                                       &img_src,
+                                       scale_x,
+                                       scale_y,
+                                       ml_offset_x,
+                                       ml_offset_y,
+                                       MLIB_NEAREST,
+                                       MLIB_EDGE_SRC_EXTEND_INDEF);
+            }
+          else
+            {
+              mlib_ImageZoomTranslateBlend (&img_dest,
+                                            &img_src,
+                                            scale_x,
+                                            scale_y,
+                                            ml_offset_x,
+                                            ml_offset_y,
+                                            MLIB_NEAREST,
+                                            MLIB_EDGE_SRC_EXTEND_INDEF,
+                                            MLIB_BLEND_GTK_SRC,
+                                            1.0,
+                                            1);
+            }
+        }
+      else if (src_channels == dest_channels && !src_has_alpha)
+        {
+          if (interp_type == PIXOPS_INTERP_BILINEAR &&
+              scale_x > 1.0 && scale_y > 1.0)
+            {
+               mlib_ImageZoomTranslate (&img_dest,
+                                        &img_src,
+                                        scale_x,
+                                        scale_y,
+                                        ml_offset_x,
+                                        ml_offset_y,
+                                        MLIB_BILINEAR,
+                                        MLIB_EDGE_SRC_EXTEND_INDEF);
+            }
+          else
+            {
+              medialib_get_interpolation (&ml_interp, interp_type,
+                                          scale_x, scale_y, 1.0);
+
+              if (ml_interp.interp_table != NULL)
+                {
+                  mlib_ImageZoomTranslateTable (&img_dest, 
+                                                &img_src,
+                                                scale_x,
+                                                scale_y,
+                                                ml_offset_x + ml_interp.tx,
+                                                ml_offset_y + ml_interp.ty,
+                                                ml_interp.interp_table,
+                                                MLIB_EDGE_SRC_EXTEND_INDEF);
+
+                 mlib_ImageInterpTableDelete (ml_interp.interp_table);
+                }
+              else
+                {
+                  /* Should not happen. */
+                  mlib_filter  ml_filter;
+
+                  switch (interp_type)
+                    {
+                    case PIXOPS_INTERP_BILINEAR:
+                      ml_filter = MLIB_BILINEAR;
+                      break;
+
+                    case PIXOPS_INTERP_TILES:
+                      ml_filter = MLIB_BILINEAR;
+                      break;
+
+                    case PIXOPS_INTERP_HYPER:
+                      ml_filter = MLIB_BICUBIC;
+                      break;
+                    }
+
+                  mlib_ImageZoomTranslate (&img_dest,
+                                           &img_src,
+                                           scale_x,
+                                           scale_y,
+                                           ml_offset_x,
+                                           ml_offset_y,
+                                           ml_filter,
+                                           MLIB_EDGE_SRC_EXTEND_INDEF);
+                }
+            }
+        }
+
+      /* Deal with case where src_channels != dest_channels || src_has_alpha */
+      else if (interp_type == PIXOPS_INTERP_BILINEAR &&
+               scale_x > 1.0 && scale_y > 1.0)
+        {
+          mlib_ImageZoomTranslateBlend (&img_dest,
+                                        &img_src,
+                                        scale_x,
+                                        scale_y,
+                                        ml_offset_x,
+                                        ml_offset_y,
+                                        MLIB_BILINEAR,
+                                        MLIB_EDGE_SRC_EXTEND_INDEF,
+                                        MLIB_BLEND_GTK_SRC,
+                                        1.0,
+                                        1);
+        }
+      else
+        {
+          medialib_get_interpolation (&ml_interp, interp_type,
+                                      scale_x, scale_y, 1.0);
+
+          if (ml_interp.interp_table != NULL)
+            {
+              mlib_ImageZoomTranslateTableBlend (&img_dest,
+                                                 &img_src,
+                                                 scale_x,
+                                                 scale_y,
+                                                 ml_offset_x + ml_interp.tx,
+                                                 ml_offset_y + ml_interp.ty,
+                                                 ml_interp.interp_table,
+                                                 MLIB_EDGE_SRC_EXTEND_INDEF,
+                                                 MLIB_BLEND_GTK_SRC,
+                                                 1);
+              mlib_ImageInterpTableDelete (ml_interp.interp_table);
+            }
+          else
+            {
+              mlib_filter  ml_filter;
+
+              switch (interp_type)
+                {
+                case PIXOPS_INTERP_BILINEAR:
+                  ml_filter = MLIB_BILINEAR;
+                  break;
+            
+                case PIXOPS_INTERP_TILES:
+                  ml_filter = MLIB_BILINEAR;
+                  break;
+
+                case PIXOPS_INTERP_HYPER:
+                  ml_filter = MLIB_BICUBIC;
+                  break;
+                }
+
+              mlib_ImageZoomTranslate (&img_dest,
+                                       &img_src,
+                                       scale_x,
+                                       scale_y,
+                                       ml_offset_x,
+                                       ml_offset_y,
+                                       ml_filter,
+                                       MLIB_EDGE_SRC_EXTEND_INDEF);
+            }
+        }
+
+      if (tmp_buf != NULL)
+        g_free (tmp_buf);
+    }
+}
+#endif
diff --git a/gdk-pixbuf/pixops/pixops.h b/gdk-pixbuf/pixops/pixops.h
new file mode 100644 (file)
index 0000000..56d3ff0
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2000 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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 PIXOPS_H
+#define PIXOPS_H
+
+#include <glib.h>
+
+/* Interpolation modes; must match GdkInterpType */ 
+typedef enum {
+       PIXOPS_INTERP_NEAREST,
+       PIXOPS_INTERP_TILES,
+       PIXOPS_INTERP_BILINEAR,
+       PIXOPS_INTERP_HYPER
+} PixopsInterpType;
+
+/* Scale src_buf from src_width / src_height by factors scale_x, scale_y
+ * and composite the portion corresponding to
+ * render_x, render_y, render_width, render_height in the new
+ * coordinate system into dest_buf starting at 0, 0
+ */
+void _pixops_composite (guchar          *dest_buf,
+                        int              dest_width,
+                        int              dest_height,
+                        int              dest_rowstride,
+                        int              dest_channels,
+                        int              dest_has_alpha,
+                        const guchar    *src_buf,
+                        int              src_width,
+                        int              src_height,
+                        int              src_rowstride,
+                        int              src_channels,
+                        int              src_has_alpha,
+                        int              dest_x,
+                        int              dest_y,
+                        int              dest_region_width,
+                        int              dest_region_height,
+                        double           offset_x,
+                        double           offset_y,
+                        double           scale_x,
+                        double           scale_y,
+                        PixopsInterpType interp_type,
+                        int              overall_alpha);
+
+/* Scale src_buf from src_width / src_height by factors scale_x, scale_y
+ * and composite the portion corresponding to
+ * render_x, render_y, render_width, render_height in the new
+ * coordinate system against a checkboard with checks of size check_size
+ * of the colors color1 and color2 into dest_buf starting at 0, 0
+ */
+void _pixops_composite_color (guchar          *dest_buf,
+                              int              dest_width,
+                              int              dest_height,
+                              int              dest_rowstride,
+                              int              dest_channels,
+                              int              dest_has_alpha,
+                              const guchar    *src_buf,
+                              int              src_width,
+                              int              src_height,
+                              int              src_rowstride,
+                              int              src_channels,
+                              int              src_has_alpha,
+                              int              dest_x,
+                              int              dest_y,
+                              int              dest_region_width,
+                              int              dest_region_height,
+                              double           offset_x,
+                              double           offset_y,
+                              double           scale_x,
+                              double           scale_y,
+                              PixopsInterpType interp_type,
+                              int              overall_alpha,
+                              int              check_x,
+                              int              check_y,
+                              int              check_size,
+                              guint32          color1,
+                              guint32          color2);
+
+/* Scale src_buf from src_width / src_height by factors scale_x, scale_y
+ * and composite the portion corresponding to
+ * render_x, render_y, render_width, render_height in the new
+ * coordinate system into dest_buf starting at 0, 0
+ */
+void _pixops_scale    (guchar          *dest_buf,
+                       int              dest_width,
+                       int              dest_height,
+                       int              dest_rowstride,
+                       int              dest_channels,
+                       int              dest_has_alpha,
+                       const guchar    *src_buf,
+                       int              src_width,
+                       int              src_height,
+                       int              src_rowstride,
+                       int              src_channels,
+                       int              src_has_alpha,
+                       int              dest_x,
+                       int              dest_y,
+                       int              dest_region_width,
+                       int              dest_region_height,
+                       double           offset_x,
+                       double           offset_y,
+                       double           scale_x,
+                       double           scale_y,
+                       PixopsInterpType interp_type);
+#endif
diff --git a/gdk-pixbuf/pixops/scale_line_22_33_mmx.S b/gdk-pixbuf/pixops/scale_line_22_33_mmx.S
new file mode 100644 (file)
index 0000000..53144ae
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2000 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+       .file   "scale_line_22_33_mmx.S"
+       .version        "01.01"
+gcc2_compiled.:
+.text
+       .align 16
+
+#if !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(__INTERIX)
+       
+/* Magic indicating no need for an executable stack */
+#if !defined __powerpc64__ && !defined __ia64__
+.section .note.GNU-stack;  .previous
+#endif
+       
+.globl _pixops_scale_line_22_33_mmx
+       .type    _pixops_scale_line_22_33_mmx,@function
+_pixops_scale_line_22_33_mmx:
+       
+#else
+       
+.globl __pixops_scale_line_22_33_mmx
+__pixops_scale_line_22_33_mmx:
+       
+#endif
+/*
+ * Arguments
+ *             
+ * weights:     8(%ebp)
+ * p:          12(%ebp)        %esi
+ * q1:         16(%ebp)        
+ * q2:         20(%ebp)        
+ * xstep:       24(%ebp)       
+ * p_end:       28(%ebp)
+ * xinit:       32(%ebp)
+ *     
+*/
+
+/*
+ * Function call entry
+ */
+       pushl %ebp
+       movl %esp,%ebp
+       subl $28,%esp
+       pushl %edi
+       pushl %esi
+       pushl %ebx
+/* Locals:     
+ * int x                      %ebx
+ * int x_scaled             -24(%ebp)
+ */
+
+/*
+ * Setup
+ */
+/* Initialize variables */     
+       movl 32(%ebp),%ebx
+       movl 32(%ebp),%edx
+       sarl $16,%edx
+       movl 12(%ebp),%esi
+
+       cmpl 28(%ebp),%esi
+       jnb  .out
+
+/* For the body of this loop, %mm01, %mm1, %mm2, %mm3 hold the 4 adjoining
+ * points we are interpolating between, as:
+ *
+ *  000000BB00GG00RR
+ */    
+       
+/* Load initial values into %mm1, %mm3 */
+       leal (%edx,%edx,2),%edx  # Multiply by 3
+
+       movl 16(%ebp),%edi
+       pxor %mm4, %mm4
+       movzbl 2(%edi,%edx),%ecx
+       shll $16,%ecx
+       movzwl (%edi,%edx),%eax
+       orl %eax,%ecx
+       movd %ecx, %mm1
+       punpcklbw %mm4, %mm1
+
+       movl 20(%ebp),%edi
+       movzbl 2(%edi,%edx),%ecx
+       shll $16,%ecx
+       movzwl (%edi,%edx),%eax
+       orl %eax,%ecx
+       movd %ecx, %mm3
+       punpcklbw %mm4, %mm3
+
+       addl $65536,%ebx
+       movl %ebx,%edx
+       sarl $16,%edx
+
+       jmp .newx
+       .p2align 4,,7
+.loop:
+/* short *pixel_weights = weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * n_x * n_y
+ *                                             16             4                  0xf            2     2
+ */
+       movl %ebx,%eax
+       andl $0xf000,%eax
+       shrl $7,%eax
+
+/* At this point, %edi holds weights. Load the 4 weights into %mm4,%mm5,%mm6,%mm7, multiply and
+ * accumulate.
+ */
+       movq (%edi,%eax),%mm4
+       pmullw %mm0,%mm4
+       movq 8(%edi,%eax),%mm5
+       pmullw %mm1,%mm5
+       movq 16(%edi,%eax),%mm6
+       movq 24(%edi,%eax),%mm7
+       pmullw %mm2,%mm6
+       pmullw %mm3,%mm7
+       paddw %mm4, %mm5
+       paddw %mm6, %mm7
+       paddw %mm5, %mm7
+
+/* %mm7        holds the accumulated sum. Compute (C + 0x80) / 256
+ */
+       pxor %mm4, %mm4
+       movl $8421504, %eax  # 0x00808080
+       movd %eax, %mm6  
+       punpcklbw %mm4, %mm6
+       paddw %mm6, %mm7
+       psrlw $8, %mm7
+
+/* Pack into %eax and store result
+ */    
+       packuswb %mm7, %mm7
+       movd %mm7, %eax
+       
+       movb %al, (%esi)
+       shrl $8, %eax
+       movw %ax, 1(%esi)
+       addl $3, %esi
+               
+       cmpl %esi,28(%ebp)
+       je   .out
+
+/* x += x_step; */
+       addl 24(%ebp),%ebx
+/* x_scaled = x >> 16; */
+       movl %ebx,%edx
+       sarl $16,%edx
+
+       cmpl %edx,-24(%ebp)
+       je   .loop
+
+.newx:
+       movl %edx,-24(%ebp)
+/*
+ * Load the two new values into %mm1, %mm3, move old values into %mm0, %mm2
+ */
+       movq %mm1, %mm0
+       movq %mm3, %mm2
+       
+       leal (%edx,%edx,2),%edx  # Multiply by 3
+
+       movl 16(%ebp),%edi
+       movzbl 2(%edi,%edx),%ecx
+       shll $16,%ecx
+       movzwl (%edi,%edx),%eax
+       orl %eax,%ecx
+       movd %ecx, %mm1
+       punpcklbw %mm4, %mm1
+
+       movl 20(%ebp),%edi
+       movzbl 2(%edi,%edx),%ecx
+       shll $16,%ecx
+       movzwl (%edi,%edx),%eax
+       orl %eax,%ecx
+       movd %ecx, %mm3
+       punpcklbw %mm4, %mm3
+       
+       movl 8(%ebp),%edi
+       
+       jmp .loop
+
+.out:
+       movl %esi,%eax
+       emms
+       leal -40(%ebp),%esp
+       popl %ebx
+       popl %esi
+       popl %edi
+       movl %ebp,%esp
+       popl %ebp
+       ret
diff --git a/gdk-pixbuf/pixops/timescale.c b/gdk-pixbuf/pixops/timescale.c
new file mode 100644 (file)
index 0000000..cac11d9
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2000 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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.
+ *
+ * You should have received a copy of the GNU Lesser 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 <glib.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "pixops.h"
+
+static GTimeVal start_time;
+
+static void 
+start_timing (void)
+{
+  g_get_current_time (&start_time);
+}
+
+static double
+stop_timing (const char *test, int iterations, int bytes)
+{
+  GTimeVal stop_time;
+  double msecs;
+  
+  g_get_current_time (&stop_time);
+  if (stop_time.tv_usec < start_time.tv_usec)
+    {
+      stop_time.tv_usec += 1000000;
+      stop_time.tv_sec -= 1;
+    }
+
+  msecs = (stop_time.tv_sec - start_time.tv_sec) * 1000. +
+          (stop_time.tv_usec - start_time.tv_usec) / 1000.;
+
+  printf("%s%d\t%.1f\t\t%.2f\t\t%.2f\n",
+        test, iterations, msecs, msecs / iterations, ((double)bytes * iterations) / (1000*msecs));
+
+  return ((double)bytes * iterations) / (1000*msecs);
+}
+
+static void
+init_array (double times[3][3][4])
+{
+  int i, j, k;
+  
+  for (i=0; i<3; i++)
+    for (j=0; j<3; j++)
+      for (k=0; k<4; k++)
+       times[i][j][k] = -1;
+}
+
+static void
+dump_array (double times[3][3][4])
+{
+  int i, j;
+  
+  printf("        3\t4\t4a\n");
+  for (i=0; i<3; i++)
+    {
+      for (j=0; j<4; j++)
+       {
+         if (j == 0)
+           switch (i)
+             {
+             case 0:
+               printf("3  ");
+               break;
+             case 1:
+               printf("4  ");
+               break;
+             case 2:
+               printf("4a ");
+               break;
+             }
+         else
+           printf("   ");
+
+         printf("%6.2f  %6.2f   %6.2f",
+                times[i][0][j], times[i][1][j], times[i][2][j]);
+
+         switch (j)
+           {
+           case PIXOPS_INTERP_NEAREST:
+             printf ("  NEAREST\n");
+             break;
+           case PIXOPS_INTERP_TILES:
+             printf ("  TILES\n");
+             break;
+           case PIXOPS_INTERP_BILINEAR:
+             printf ("  BILINEAR\n");
+             break;
+           case PIXOPS_INTERP_HYPER:
+             printf ("  HYPER\n");
+             break;
+           }
+       }
+    }
+  printf("\n");
+}
+
+#define ITERS 10
+
+int main (int argc, char **argv)
+{
+  int src_width, src_height, dest_width, dest_height;
+  unsigned char *src_buf, *dest_buf;
+  int src_index, dest_index;
+  int i;
+  double scale_times[3][3][4];
+  double composite_times[3][3][4];
+  double composite_color_times[3][3][4];
+
+  if (argc == 5)
+    {
+      src_width = atoi(argv[1]);
+      src_height = atoi(argv[2]);
+      dest_width = atoi(argv[3]);
+      dest_height = atoi(argv[4]);
+    }
+  else if (argc == 1)
+    {
+      src_width = 343;
+      src_height = 343;
+      dest_width = 711;
+      dest_height = 711;
+    }
+  else
+    {
+      fprintf (stderr, "Usage: scale [src_width src_height dest_width dest_height]\n");
+      exit(1);
+    }
+
+
+  printf ("Scaling from (%d, %d) to (%d, %d)\n\n", src_width, src_height, dest_width, dest_height);
+
+  init_array (scale_times);
+  init_array (composite_times);
+  init_array (composite_color_times);
+
+  for (src_index = 0; src_index < 3; src_index++)
+    for (dest_index = 0; dest_index < 3; dest_index++)
+      {
+       int src_channels = (src_index == 0) ? 3 : 4;
+       int src_has_alpha = (src_index == 2);
+       int dest_channels = (dest_index == 0) ? 3 : 4;
+       int dest_has_alpha = (dest_index == 2);
+       
+       int src_rowstride = (src_channels*src_width + 3) & ~3;
+       int dest_rowstride = (dest_channels *dest_width + 3) & ~3;
+
+       int filter_level;
+
+       src_buf = g_malloc(src_rowstride * src_height);
+       memset (src_buf, 0x80, src_rowstride * src_height);
+       
+       dest_buf = g_malloc(dest_rowstride * dest_height);
+       memset (dest_buf, 0x80, dest_rowstride * dest_height);
+
+       for (filter_level = PIXOPS_INTERP_NEAREST ; filter_level <= PIXOPS_INTERP_HYPER; filter_level++)
+         {
+           printf ("src_channels = %d (%s); dest_channels = %d (%s); filter_level=",
+                   src_channels, src_has_alpha ? "alpha" : "no alpha",
+                   dest_channels, dest_has_alpha ? "alpha" : "no alpha");
+           switch (filter_level)
+             {
+             case PIXOPS_INTERP_NEAREST:
+               printf ("PIXOPS_INTERP_NEAREST\n");
+               break;
+             case PIXOPS_INTERP_TILES:
+               printf ("PIXOPS_INTERP_TILES\n");
+               break;
+             case PIXOPS_INTERP_BILINEAR:
+               printf ("PIXOPS_INTERP_BILINEAR\n");
+               break;
+             case PIXOPS_INTERP_HYPER:
+               printf ("PIXOPS_INTERP_HYPER\n");
+               break;
+             }
+
+           printf("\t\t\titers\ttotal\t\tmsecs/iter\tMpixels/sec\t\n");
+
+
+           if (!(src_has_alpha && !dest_has_alpha))
+             {
+               start_timing ();
+               for (i = 0; i < ITERS; i++)
+                 {
+                   _pixops_scale (dest_buf, dest_width, dest_height,
+                                  dest_rowstride, dest_channels,
+                                  dest_has_alpha, src_buf, src_width,
+                                  src_height, src_rowstride, src_channels,
+                                  src_has_alpha, 0, 0, 0, 0, 0, 0,
+                                  (double)dest_width / src_width,
+                                  (double)dest_height / src_height,
+                                  filter_level);
+                 }
+               scale_times[src_index][dest_index][filter_level] =
+                 stop_timing ("   scale\t\t", ITERS, dest_height * dest_width);
+             }
+
+           start_timing ();
+           for (i = 0; i < ITERS; i++)
+             {
+               _pixops_composite (dest_buf, dest_width, dest_height,
+                                  dest_rowstride, dest_channels,
+                                  dest_has_alpha, src_buf, src_width,
+                                  src_height, src_rowstride, src_channels,
+                                  src_has_alpha, 0, 0, 0, 0, 0, 0,
+                                  (double)dest_width / src_width,
+                                  (double)dest_height / src_height,
+                                  filter_level, 255);
+             }
+           composite_times[src_index][dest_index][filter_level] =
+             stop_timing ("   composite\t\t", ITERS,
+                          dest_height * dest_width);
+
+           start_timing ();
+           for (i = 0; i < ITERS; i++)
+             {
+               _pixops_composite_color (dest_buf, dest_width, dest_height,
+                                        dest_rowstride, dest_channels,
+                                        dest_has_alpha, src_buf, src_width,
+                                        src_height, src_rowstride,
+                                        src_channels, src_has_alpha, 0, 0,
+                                        0, 0, 0, 0,
+                                        (double)dest_width / src_width,
+                                        (double)dest_height / src_height,
+                                        filter_level, 255, 0, 0, 16,
+                                        0xaaaaaa, 0x555555);
+             }
+           composite_color_times[src_index][dest_index][filter_level] =
+             stop_timing ("   composite color\t", ITERS, dest_height * dest_width);
+
+           printf ("\n");
+         }
+       printf ("\n");
+
+       g_free (src_buf);
+       g_free (dest_buf);
+      }
+
+  printf ("SCALE\n=====\n\n");
+  dump_array (scale_times);
+
+  printf ("COMPOSITE\n=========\n\n");
+  dump_array (composite_times);
+
+  printf ("COMPOSITE_COLOR\n===============\n\n");
+  dump_array (composite_color_times);
+  return 0;
+}
diff --git a/gdk-pixbuf/queryloaders.c b/gdk-pixbuf/queryloaders.c
new file mode 100644 (file)
index 0000000..6087bd8
--- /dev/null
@@ -0,0 +1,389 @@
+/* -*- mode: C; c-file-style: "linux" -*- */
+/* GdkPixbuf library
+ * queryloaders.c:
+ *
+ * Copyright (C) 2002 The Free Software Foundation
+ *
+ * Author: Matthias Clasen <maclas@gmx.de>
+ *
+ * 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 <glib.h>
+#include <glib/gprintf.h>
+#include <gmodule.h>
+
+#include <errno.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "gdk-pixbuf/gdk-pixbuf.h"
+#include "gdk-pixbuf/gdk-pixbuf-private.h"
+
+#ifdef USE_LA_MODULES
+#define SOEXT ".la"
+#else
+#define SOEXT ("." G_MODULE_SUFFIX)
+#endif
+#define SOEXT_LEN (strlen (SOEXT))
+
+#ifdef G_OS_WIN32
+#include <windows.h>
+#endif
+
+static void
+print_escaped (GString *contents, const char *str)
+{
+        gchar *tmp = g_strescape (str, "");
+        g_string_append_printf (contents, "\"%s\" ", tmp);
+        g_free (tmp);
+}
+
+static int
+loader_sanity_check (const char *path, GdkPixbufFormat *info, GdkPixbufModule *vtable)
+{
+        const GdkPixbufModulePattern *pattern;
+        const char *error = "";
+
+        for (pattern = info->signature; pattern->prefix; pattern++)
+        {
+                int prefix_len = strlen (pattern->prefix);
+                if (prefix_len == 0)
+                {
+                        error = "empty pattern";
+
+                        goto error;
+                }
+                if (pattern->mask)
+                {
+                        int mask_len = strlen (pattern->mask);
+                        if (mask_len != prefix_len)
+                        {
+                                error = "mask length mismatch";
+
+                                goto error;
+                        }
+                        if (strspn (pattern->mask, " !xzn*") < mask_len)
+                        {
+                                error = "bad char in mask";
+
+                                goto error;
+                        }
+                }
+        }
+
+        if (!vtable->load && !vtable->begin_load && !vtable->load_animation)
+        {
+                error = "no load method implemented";
+
+                goto error;
+        }
+
+        if (vtable->begin_load && (!vtable->stop_load || !vtable->load_increment))
+        {
+                error = "incremental loading support incomplete";
+
+                goto error;
+        }
+
+        if ((info->flags & GDK_PIXBUF_FORMAT_WRITABLE) && !(vtable->save || vtable->save_to_callback))
+        {
+                error = "loader claims to support saving but doesn't implement save";
+                goto error;
+        }
+
+        return 1;
+
+ error:
+        g_fprintf (stderr, "Loader sanity check failed for %s: %s\n",
+                   path, error);
+
+        return 0;
+}
+
+static void
+write_loader_info (GString *contents, const char *path, GdkPixbufFormat *info)
+{
+        const GdkPixbufModulePattern *pattern;
+        char **mime;
+        char **ext;
+
+        g_string_append_printf (contents, "\"%s\"\n", path);
+        g_string_append_printf (contents, "\"%s\" %u \"%s\" \"%s\" \"%s\"\n",
+                  info->name,
+                  info->flags,
+                  info->domain ? info->domain : GETTEXT_PACKAGE,
+                  info->description,
+                  info->license ? info->license : "");
+        for (mime = info->mime_types; *mime; mime++) {
+                g_string_append_printf (contents, "\"%s\" ", *mime);
+        }
+        g_string_append (contents, "\"\"\n");
+        for (ext = info->extensions; *ext; ext++) {
+                g_string_append_printf (contents, "\"%s\" ", *ext);
+        }
+        g_string_append (contents, "\"\"\n");
+        for (pattern = info->signature; pattern->prefix; pattern++) {
+                print_escaped (contents, pattern->prefix);
+                print_escaped (contents, pattern->mask ? (const char *)pattern->mask : "");
+                g_string_append_printf (contents, "%d\n", pattern->relevance);
+        }
+        g_string_append_c (contents, '\n');
+}
+
+static void
+query_module (GString *contents, const char *dir, const char *file)
+{
+        char *path;
+        GModule *module;
+        void                    (*fill_info)     (GdkPixbufFormat *info);
+        void                    (*fill_vtable)   (GdkPixbufModule *module);
+        gpointer fill_info_ptr;
+        gpointer fill_vtable_ptr;
+
+        if (g_path_is_absolute (file))
+                path = g_strdup (file);
+        else
+                path = g_build_filename (dir, file, NULL);
+
+        module = g_module_open (path, 0);
+        if (module &&
+            g_module_symbol (module, "fill_info", &fill_info_ptr) &&
+            g_module_symbol (module, "fill_vtable", &fill_vtable_ptr)) {
+                GdkPixbufFormat *info;
+                GdkPixbufModule *vtable;
+
+#ifdef G_OS_WIN32
+                /* Replace backslashes in path with forward slashes, so that
+                 * it reads in without problems.
+                 */
+                {
+                        char *p = path;
+                        while (*p) {
+                                if (*p == '\\')
+                                        *p = '/';
+                                p++;
+                        }
+                }
+#endif
+                info = g_new0 (GdkPixbufFormat, 1);
+                vtable = g_new0 (GdkPixbufModule, 1);
+
+                vtable->module = module;
+
+                fill_info = fill_info_ptr;
+                fill_vtable = fill_vtable_ptr;
+
+                (*fill_info) (info);
+                (*fill_vtable) (vtable);
+
+                if (loader_sanity_check (path, info, vtable))
+                        write_loader_info (contents, path, info);
+
+                g_free (info);
+                g_free (vtable);
+        }
+        else {
+                if (module == NULL)
+                        g_fprintf (stderr, "g_module_open() failed for %s: %s\n", path,
+                                   g_module_error());
+                else
+                        g_fprintf (stderr, "Cannot load loader %s\n", path);
+        }
+        if (module)
+                g_module_close (module);
+        g_free (path);
+}
+
+#ifdef G_OS_WIN32
+
+static char *
+get_toplevel (void)
+{
+  static char *toplevel = NULL;
+
+  if (toplevel == NULL)
+          toplevel = g_win32_get_package_installation_directory_of_module (NULL);
+
+  return toplevel;
+}
+
+static char *
+get_libdir (void)
+{
+  static char *libdir = NULL;
+
+  if (libdir == NULL)
+          libdir = g_build_filename (get_toplevel (), "lib", NULL);
+
+  return libdir;
+}
+
+#undef GDK_PIXBUF_LIBDIR
+#define GDK_PIXBUF_LIBDIR get_libdir()
+
+#endif
+
+static gchar *
+gdk_pixbuf_get_module_file (void)
+{
+        gchar *result = g_strdup (g_getenv ("GDK_PIXBUF_MODULE_FILE"));
+
+        if (!result)
+                result = g_build_filename (GDK_PIXBUF_LIBDIR, "gdk-pixbuf-2.0", GDK_PIXBUF_BINARY_VERSION, "loaders.cache", NULL);
+
+        return result;
+}
+
+int main (int argc, char **argv)
+{
+        gint i;
+        gchar *prgname;
+        GString *contents;
+        gchar *cache_file = NULL;
+        gint first_file = 1;
+
+#ifdef G_OS_WIN32
+        gchar *libdir;
+        gchar *runtime_prefix;
+        gchar *slash;
+
+        if (g_ascii_strncasecmp (PIXBUF_LIBDIR, GDK_PIXBUF_PREFIX, strlen (GDK_PIXBUF_PREFIX)) == 0 &&
+            G_IS_DIR_SEPARATOR (PIXBUF_LIBDIR[strlen (GDK_PIXBUF_PREFIX)])) {
+                /* GDK_PIXBUF_PREFIX is a prefix of PIXBUF_LIBDIR, as it
+                 * normally is. Replace that prefix in PIXBUF_LIBDIR
+                 * with the installation directory on this machine.
+                 * We assume this invokation of
+                 * gdk-pixbuf-query-loaders is run from either a "bin"
+                 * subdirectory of the installation directory, or in
+                 * the installation directory itself.
+                 */
+                wchar_t fn[1000];
+                GetModuleFileNameW (NULL, fn, G_N_ELEMENTS (fn));
+                runtime_prefix = g_utf16_to_utf8 (fn, -1, NULL, NULL, NULL);
+                slash = strrchr (runtime_prefix, '\\');
+                *slash = '\0';
+                slash = strrchr (runtime_prefix, '\\');
+                /* If running from some weird location, or from the
+                 * build directory (either in the .libs folder where
+                 * libtool places the real executable when using a
+                 * wrapper, or directly from the gdk-pixbuf folder),
+                 * use the compile-time libdir.
+                 */
+                if (slash == NULL ||
+                    g_ascii_strcasecmp (slash + 1, ".libs") == 0 ||
+                    g_ascii_strcasecmp (slash + 1, "gdk-pixbuf") == 0) {
+                        libdir = PIXBUF_LIBDIR;
+                }
+                else {
+                        if (slash != NULL && g_ascii_strcasecmp (slash + 1, "bin") == 0) {
+                                *slash = '\0';
+                        }
+
+                        libdir = g_strconcat (runtime_prefix,
+                                              "/",
+                                              PIXBUF_LIBDIR + strlen (GDK_PIXBUF_PREFIX) + 1,
+                                              NULL);
+                }
+        }
+        else {
+                libdir = PIXBUF_LIBDIR;
+        }
+
+#undef PIXBUF_LIBDIR
+#define PIXBUF_LIBDIR libdir
+
+#endif
+
+        if (argc > 1 && strcmp (argv[1], "--update-cache") == 0) {
+                cache_file = gdk_pixbuf_get_module_file ();
+                first_file = 2;
+        }
+
+        contents = g_string_new ("");
+
+        prgname = g_get_prgname ();
+        g_string_append_printf (contents,
+                                "# GdkPixbuf Image Loader Modules file\n"
+                                "# Automatically generated file, do not edit\n"
+                                "# Created by %s from gdk-pixbuf-%s\n"
+                                "#\n",
+                                (prgname ? prgname : "gdk-pixbuf-query-loaders"),
+                                GDK_PIXBUF_VERSION);
+
+        if (argc == first_file) {
+#ifdef USE_GMODULE
+                const char *path;
+                GDir *dir;
+
+                path = g_getenv ("GDK_PIXBUF_MODULEDIR");
+#ifdef G_OS_WIN32
+                if (path != NULL && *path != '\0')
+                        path = g_locale_to_utf8 (path, -1, NULL, NULL, NULL);
+#endif
+                if (path == NULL || *path == '\0')
+                        path = PIXBUF_LIBDIR;
+
+                g_string_append_printf (contents, "# LoaderDir = %s\n#\n", path);
+
+                dir = g_dir_open (path, 0, NULL);
+                if (dir) {
+                        const char *dent;
+
+                        while ((dent = g_dir_read_name (dir))) {
+                                gint len = strlen (dent);
+                                if (len > SOEXT_LEN &&
+                                    strcmp (dent + len - SOEXT_LEN, SOEXT) == 0) {
+                                        query_module (contents, path, dent);
+                                }
+                        }
+                        g_dir_close (dir);
+                }
+#else
+                g_string_append_printf (contents, "# dynamic loading of modules not supported\n");
+#endif
+        }
+        else {
+                char *cwd = g_get_current_dir ();
+
+                for (i = 1; i < argc; i++) {
+                        char *infilename = argv[i];
+#ifdef G_OS_WIN32
+                        infilename = g_locale_to_utf8 (infilename,
+                                                       -1, NULL, NULL, NULL);
+#endif
+                        query_module (contents, cwd, infilename);
+                }
+                g_free (cwd);
+        }
+
+        if (cache_file) {
+                GError *err;
+
+                err = NULL;
+                if (!g_file_set_contents (cache_file, contents->str, -1, &err)) {
+                        g_fprintf (stderr, "%s\n", err->message);
+                }
+        }
+        else
+                g_print ("%s\n", contents->str);
+
+        return 0;
+}
diff --git a/gdk-pixbuf/test-gdk-pixbuf.c b/gdk-pixbuf/test-gdk-pixbuf.c
new file mode 100644 (file)
index 0000000..b2d565a
--- /dev/null
@@ -0,0 +1,241 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* GdkPixbuf library - test program
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Author: Federico Mena-Quintero <federico@gimp.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include "gdk-pixbuf.h"
+#include <glib-object.h>
+
+\f
+
+static void
+store_pixel (guchar *pixels,
+            int pixel,
+            gboolean alpha)
+{
+       if (alpha) {
+               pixels[0] = pixel >> 24;
+               pixels[1] = pixel >> 16;
+               pixels[2] = pixel >> 8;
+               pixels[3] = pixel;
+       } else {
+               pixels[0] = pixel >> 16;
+               pixels[1] = pixel >> 8;
+               pixels[2] = pixel;
+       }
+}
+
+static void
+fill_with_pixel (GdkPixbuf *pixbuf,
+                int pixel)
+{
+       int x, y;
+       
+       for (x = 0; x < gdk_pixbuf_get_width (pixbuf); x++) {
+               for (y = 0; y < gdk_pixbuf_get_height (pixbuf); y++) {
+                       store_pixel (gdk_pixbuf_get_pixels (pixbuf)
+                                    + y * gdk_pixbuf_get_rowstride (pixbuf)
+                                    + x * gdk_pixbuf_get_n_channels (pixbuf),
+                                    pixel,
+                                    gdk_pixbuf_get_has_alpha (pixbuf));
+               }
+       }
+}
+
+static int
+load_pixel (const guchar *pixels,
+           gboolean alpha)
+{
+       if (alpha)
+               return (((((pixels[0] << 8) | pixels[1]) << 8) | pixels[2]) << 8) | pixels[3];
+       else
+               return (((pixels[0] << 8) | pixels[1]) << 8) | pixels[2];
+}
+
+static gboolean
+simple_composite_test_one (GdkInterpType type,
+                          int source_pixel,
+                          gboolean source_alpha,
+                          int destination_pixel,
+                          gboolean destination_alpha,
+                          int expected_result)
+{
+       GdkPixbuf *source_pixbuf;
+       GdkPixbuf *destination_pixbuf;
+       int result_pixel;
+
+       source_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, source_alpha, 8, 32, 32);
+       destination_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, destination_alpha, 8, 32, 32);
+       
+       fill_with_pixel (source_pixbuf, source_pixel);
+       fill_with_pixel (destination_pixbuf, destination_pixel);
+
+       gdk_pixbuf_composite (source_pixbuf, destination_pixbuf,
+                             0, 0, 32, 32, 0, 0, 1, 1, type, 0xFF);
+
+       result_pixel = load_pixel (gdk_pixbuf_get_pixels (destination_pixbuf)
+                                  + 16 * gdk_pixbuf_get_rowstride (destination_pixbuf)
+                                  + 16 * gdk_pixbuf_get_n_channels (destination_pixbuf),
+                                  destination_alpha);
+         
+       g_object_unref (source_pixbuf);
+       g_object_unref (destination_pixbuf);
+
+       if (result_pixel != expected_result) {
+               char *interpolation_type, *source_string, *destination_string, *result_string, *expected_string;
+
+               switch (type) {
+               case GDK_INTERP_NEAREST:  interpolation_type = "GDK_INTERP_NEAREST"; break;
+               case GDK_INTERP_TILES:    interpolation_type = "GDK_INTERP_TILES"; break;
+               case GDK_INTERP_BILINEAR: interpolation_type = "GDK_INTERP_BILINEAR"; break;
+               case GDK_INTERP_HYPER:    interpolation_type = "GDK_INTERP_HYPER"; break;
+               default:                  interpolation_type = "???";
+               }
+
+               if (source_alpha) {
+                       source_string = g_strdup_printf ("0x%08X", source_pixel);
+               } else {
+                       source_string = g_strdup_printf ("0x%06X", source_pixel);
+               }
+
+               if (destination_alpha) {
+                       destination_string = g_strdup_printf ("0x%08X", destination_pixel);
+                       result_string = g_strdup_printf ("0x%08X", result_pixel);
+                       expected_string = g_strdup_printf ("0x%08X", expected_result);
+               } else {
+                       destination_string = g_strdup_printf ("0x%06X", destination_pixel);
+                       result_string = g_strdup_printf ("0x%06X", result_pixel);
+                       expected_string = g_strdup_printf ("0x%06X", expected_result);
+               }
+
+               g_message ("simple_composite_test (%s): composite %s on top of %s, expected %s, got %s",
+                          interpolation_type,
+                          source_string, destination_string, expected_string, result_string);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+static gboolean
+simple_composite_test_one_type (GdkInterpType type)
+{
+       gboolean success;
+
+       success = TRUE;
+
+       /* There are only a few trivial cases in here.
+        * But these were enough to expose the problems in the old composite code.
+        */
+
+       /* Non-alpha into non-alpha. */
+       success &= simple_composite_test_one (type, 0x000000, FALSE, 0x000000, FALSE, 0x000000);
+       success &= simple_composite_test_one (type, 0x000000, FALSE, 0xFFFFFF, FALSE, 0x000000);
+       success &= simple_composite_test_one (type, 0xFF0000, FALSE, 0x000000, FALSE, 0xFF0000);
+       success &= simple_composite_test_one (type, 0x00FF00, FALSE, 0x000000, FALSE, 0x00FF00);
+       success &= simple_composite_test_one (type, 0x0000FF, FALSE, 0x000000, FALSE, 0x0000FF);
+       success &= simple_composite_test_one (type, 0x000000, FALSE, 0xFF0000, FALSE, 0x000000);
+       success &= simple_composite_test_one (type, 0x000000, FALSE, 0x00FF00, FALSE, 0x000000);
+       success &= simple_composite_test_one (type, 0x000000, FALSE, 0x0000FF, FALSE, 0x000000);
+       success &= simple_composite_test_one (type, 0x00FF00, FALSE, 0xFFFFFF, FALSE, 0x00FF00);
+       success &= simple_composite_test_one (type, 0xFFFFFF, FALSE, 0xFFFFFF, FALSE, 0xFFFFFF);
+
+       /* Alpha into non-alpha. */
+       success &= simple_composite_test_one (type, 0x00000000, TRUE, 0x000000, FALSE, 0x000000);
+       success &= simple_composite_test_one (type, 0x00000000, TRUE, 0xFFFFFF, FALSE, 0xFFFFFF);
+       success &= simple_composite_test_one (type, 0x0000007F, TRUE, 0xFFFFFF, FALSE, 0x808080);
+       success &= simple_composite_test_one (type, 0x00000080, TRUE, 0xFFFFFF, FALSE, 0x7F7F7F);
+       success &= simple_composite_test_one (type, 0x000000FF, TRUE, 0xFFFFFF, FALSE, 0x000000);
+       success &= simple_composite_test_one (type, 0x000000FF, TRUE, 0xFFFFFF, FALSE, 0x000000);
+       success &= simple_composite_test_one (type, 0xFF0000FF, TRUE, 0x000000, FALSE, 0xFF0000);
+       success &= simple_composite_test_one (type, 0x00FF00FF, TRUE, 0x000000, FALSE, 0x00FF00);
+       success &= simple_composite_test_one (type, 0x0000FFFF, TRUE, 0x000000, FALSE, 0x0000FF);
+       success &= simple_composite_test_one (type, 0x00000000, TRUE, 0xFF0000, FALSE, 0xFF0000);
+       success &= simple_composite_test_one (type, 0x00000000, TRUE, 0x00FF00, FALSE, 0x00FF00);
+       success &= simple_composite_test_one (type, 0x00000000, TRUE, 0x0000FF, FALSE, 0x0000FF);
+       success &= simple_composite_test_one (type, 0x00FF0080, TRUE, 0xFFFFFF, FALSE, 0x7FFF7F);
+       success &= simple_composite_test_one (type, 0xFFFFFFFF, TRUE, 0xFFFFFF, FALSE, 0xFFFFFF);
+
+       /* Non-alpha into alpha. */
+       success &= simple_composite_test_one (type, 0x000000, FALSE, 0x00000000, TRUE, 0x000000FF);
+       success &= simple_composite_test_one (type, 0x000000, FALSE, 0xFFFFFFFF, TRUE, 0x000000FF);
+       success &= simple_composite_test_one (type, 0xFF0000, FALSE, 0x00000000, TRUE, 0xFF0000FF);
+       success &= simple_composite_test_one (type, 0x00FF00, FALSE, 0x00000000, TRUE, 0x00FF00FF);
+       success &= simple_composite_test_one (type, 0x0000FF, FALSE, 0x00000000, TRUE, 0x0000FFFF);
+       success &= simple_composite_test_one (type, 0x000000, FALSE, 0xFF0000FF, TRUE, 0x000000FF);
+       success &= simple_composite_test_one (type, 0x000000, FALSE, 0x00FF00FF, TRUE, 0x000000FF);
+       success &= simple_composite_test_one (type, 0x000000, FALSE, 0x0000FFFF, TRUE, 0x000000FF);
+       success &= simple_composite_test_one (type, 0x00FF00, FALSE, 0xFFFFFF00, TRUE, 0x00FF00FF);
+       success &= simple_composite_test_one (type, 0xFFFFFF, FALSE, 0xFFFFFFFF, TRUE, 0xFFFFFFFF);
+
+       /* Alpha into alpha. */
+       success &= simple_composite_test_one (type, 0x00000000, TRUE, 0x00000000, TRUE, 0x00000000);
+       success &= simple_composite_test_one (type, 0x00000000, TRUE, 0xFFFFFFFF, TRUE, 0xFFFFFFFF);
+       success &= simple_composite_test_one (type, 0x0000007F, TRUE, 0xFFFFFFFF, TRUE, 0x808080FF);
+       success &= simple_composite_test_one (type, 0x00000080, TRUE, 0xFFFFFFFF, TRUE, 0x7F7F7FFF);
+       success &= simple_composite_test_one (type, 0x000000FF, TRUE, 0xFFFFFFFF, TRUE, 0x000000FF);
+       success &= simple_composite_test_one (type, 0xFF0000FF, TRUE, 0x00000000, TRUE, 0xFF0000FF);
+       success &= simple_composite_test_one (type, 0x00FF00FF, TRUE, 0x00000000, TRUE, 0x00FF00FF);
+       success &= simple_composite_test_one (type, 0x0000FFFF, TRUE, 0x00000000, TRUE, 0x0000FFFF);
+       success &= simple_composite_test_one (type, 0x00000000, TRUE, 0xFF0000FF, TRUE, 0xFF0000FF);
+       success &= simple_composite_test_one (type, 0x00000000, TRUE, 0x00FF00FF, TRUE, 0x00FF00FF);
+       success &= simple_composite_test_one (type, 0x00000000, TRUE, 0x0000FFFF, TRUE, 0x0000FFFF);
+       success &= simple_composite_test_one (type, 0x00FF0080, TRUE, 0xFFFFFF00, TRUE, 0x00FF0080);
+       success &= simple_composite_test_one (type, 0xFF000080, TRUE, 0x00FF0040, TRUE, 0xCC32009F);
+       success &= simple_composite_test_one (type, 0xFFFFFFFF, TRUE, 0xFFFFFFFF, TRUE, 0xFFFFFFFF);
+
+       return success;
+}
+
+static gboolean
+simple_composite_test (void)
+{
+       gboolean success;
+
+       success = TRUE;
+
+       success &= simple_composite_test_one_type (GDK_INTERP_NEAREST);
+       success &= simple_composite_test_one_type (GDK_INTERP_TILES);
+       success &= simple_composite_test_one_type (GDK_INTERP_BILINEAR);
+       success &= simple_composite_test_one_type (GDK_INTERP_HYPER);
+
+       return success;
+}
+
+int
+main (int argc, char **argv)
+{
+       int result;
+
+       result = EXIT_SUCCESS;
+
+       g_type_init ();
+       
+       /* Run some tests. */
+       if (!simple_composite_test ()) {
+               result = EXIT_FAILURE;
+       }
+
+       return result;
+}
diff --git a/gdk-pixbuf/xpm-color-table.h b/gdk-pixbuf/xpm-color-table.h
new file mode 100644 (file)
index 0000000..637a27c
--- /dev/null
@@ -0,0 +1,1521 @@
+/* xpm-color-table.h: Generated by gen-color-table.pl from rgb.txt
+ *
+ *  Date: Tue Mar  8 03:54:56 2005
+ *
+ * Do not edit.   
+ */
+static const char color_names[] =
+  "alice blue\0"
+  "AliceBlue\0"
+  "antique white\0"
+  "AntiqueWhite\0"
+  "AntiqueWhite1\0"
+  "AntiqueWhite2\0"
+  "AntiqueWhite3\0"
+  "AntiqueWhite4\0"
+  "aquamarine\0"
+  "aquamarine1\0"
+  "aquamarine2\0"
+  "aquamarine3\0"
+  "aquamarine4\0"
+  "azure\0"
+  "azure1\0"
+  "azure2\0"
+  "azure3\0"
+  "azure4\0"
+  "beige\0"
+  "bisque\0"
+  "bisque1\0"
+  "bisque2\0"
+  "bisque3\0"
+  "bisque4\0"
+  "black\0"
+  "blanched almond\0"
+  "BlanchedAlmond\0"
+  "blue\0"
+  "blue violet\0"
+  "blue1\0"
+  "blue2\0"
+  "blue3\0"
+  "blue4\0"
+  "BlueViolet\0"
+  "brown\0"
+  "brown1\0"
+  "brown2\0"
+  "brown3\0"
+  "brown4\0"
+  "burlywood\0"
+  "burlywood1\0"
+  "burlywood2\0"
+  "burlywood3\0"
+  "burlywood4\0"
+  "cadet blue\0"
+  "CadetBlue\0"
+  "CadetBlue1\0"
+  "CadetBlue2\0"
+  "CadetBlue3\0"
+  "CadetBlue4\0"
+  "chartreuse\0"
+  "chartreuse1\0"
+  "chartreuse2\0"
+  "chartreuse3\0"
+  "chartreuse4\0"
+  "chocolate\0"
+  "chocolate1\0"
+  "chocolate2\0"
+  "chocolate3\0"
+  "chocolate4\0"
+  "coral\0"
+  "coral1\0"
+  "coral2\0"
+  "coral3\0"
+  "coral4\0"
+  "cornflower blue\0"
+  "CornflowerBlue\0"
+  "cornsilk\0"
+  "cornsilk1\0"
+  "cornsilk2\0"
+  "cornsilk3\0"
+  "cornsilk4\0"
+  "cyan\0"
+  "cyan1\0"
+  "cyan2\0"
+  "cyan3\0"
+  "cyan4\0"
+  "dark blue\0"
+  "dark cyan\0"
+  "dark goldenrod\0"
+  "dark gray\0"
+  "dark green\0"
+  "dark grey\0"
+  "dark khaki\0"
+  "dark magenta\0"
+  "dark olive green\0"
+  "dark orange\0"
+  "dark orchid\0"
+  "dark red\0"
+  "dark salmon\0"
+  "dark sea green\0"
+  "dark slate blue\0"
+  "dark slate gray\0"
+  "dark slate grey\0"
+  "dark turquoise\0"
+  "dark violet\0"
+  "DarkBlue\0"
+  "DarkCyan\0"
+  "DarkGoldenrod\0"
+  "DarkGoldenrod1\0"
+  "DarkGoldenrod2\0"
+  "DarkGoldenrod3\0"
+  "DarkGoldenrod4\0"
+  "DarkGray\0"
+  "DarkGreen\0"
+  "DarkGrey\0"
+  "DarkKhaki\0"
+  "DarkMagenta\0"
+  "DarkOliveGreen\0"
+  "DarkOliveGreen1\0"
+  "DarkOliveGreen2\0"
+  "DarkOliveGreen3\0"
+  "DarkOliveGreen4\0"
+  "DarkOrange\0"
+  "DarkOrange1\0"
+  "DarkOrange2\0"
+  "DarkOrange3\0"
+  "DarkOrange4\0"
+  "DarkOrchid\0"
+  "DarkOrchid1\0"
+  "DarkOrchid2\0"
+  "DarkOrchid3\0"
+  "DarkOrchid4\0"
+  "DarkRed\0"
+  "DarkSalmon\0"
+  "DarkSeaGreen\0"
+  "DarkSeaGreen1\0"
+  "DarkSeaGreen2\0"
+  "DarkSeaGreen3\0"
+  "DarkSeaGreen4\0"
+  "DarkSlateBlue\0"
+  "DarkSlateGray\0"
+  "DarkSlateGray1\0"
+  "DarkSlateGray2\0"
+  "DarkSlateGray3\0"
+  "DarkSlateGray4\0"
+  "DarkSlateGrey\0"
+  "DarkTurquoise\0"
+  "DarkViolet\0"
+  "deep pink\0"
+  "deep sky blue\0"
+  "DeepPink\0"
+  "DeepPink1\0"
+  "DeepPink2\0"
+  "DeepPink3\0"
+  "DeepPink4\0"
+  "DeepSkyBlue\0"
+  "DeepSkyBlue1\0"
+  "DeepSkyBlue2\0"
+  "DeepSkyBlue3\0"
+  "DeepSkyBlue4\0"
+  "dim gray\0"
+  "dim grey\0"
+  "DimGray\0"
+  "DimGrey\0"
+  "dodger blue\0"
+  "DodgerBlue\0"
+  "DodgerBlue1\0"
+  "DodgerBlue2\0"
+  "DodgerBlue3\0"
+  "DodgerBlue4\0"
+  "firebrick\0"
+  "firebrick1\0"
+  "firebrick2\0"
+  "firebrick3\0"
+  "firebrick4\0"
+  "floral white\0"
+  "FloralWhite\0"
+  "forest green\0"
+  "ForestGreen\0"
+  "gainsboro\0"
+  "ghost white\0"
+  "GhostWhite\0"
+  "gold\0"
+  "gold1\0"
+  "gold2\0"
+  "gold3\0"
+  "gold4\0"
+  "goldenrod\0"
+  "goldenrod1\0"
+  "goldenrod2\0"
+  "goldenrod3\0"
+  "goldenrod4\0"
+  "gray\0"
+  "gray0\0"
+  "gray1\0"
+  "gray10\0"
+  "gray100\0"
+  "gray11\0"
+  "gray12\0"
+  "gray13\0"
+  "gray14\0"
+  "gray15\0"
+  "gray16\0"
+  "gray17\0"
+  "gray18\0"
+  "gray19\0"
+  "gray2\0"
+  "gray20\0"
+  "gray21\0"
+  "gray22\0"
+  "gray23\0"
+  "gray24\0"
+  "gray25\0"
+  "gray26\0"
+  "gray27\0"
+  "gray28\0"
+  "gray29\0"
+  "gray3\0"
+  "gray30\0"
+  "gray31\0"
+  "gray32\0"
+  "gray33\0"
+  "gray34\0"
+  "gray35\0"
+  "gray36\0"
+  "gray37\0"
+  "gray38\0"
+  "gray39\0"
+  "gray4\0"
+  "gray40\0"
+  "gray41\0"
+  "gray42\0"
+  "gray43\0"
+  "gray44\0"
+  "gray45\0"
+  "gray46\0"
+  "gray47\0"
+  "gray48\0"
+  "gray49\0"
+  "gray5\0"
+  "gray50\0"
+  "gray51\0"
+  "gray52\0"
+  "gray53\0"
+  "gray54\0"
+  "gray55\0"
+  "gray56\0"
+  "gray57\0"
+  "gray58\0"
+  "gray59\0"
+  "gray6\0"
+  "gray60\0"
+  "gray61\0"
+  "gray62\0"
+  "gray63\0"
+  "gray64\0"
+  "gray65\0"
+  "gray66\0"
+  "gray67\0"
+  "gray68\0"
+  "gray69\0"
+  "gray7\0"
+  "gray70\0"
+  "gray71\0"
+  "gray72\0"
+  "gray73\0"
+  "gray74\0"
+  "gray75\0"
+  "gray76\0"
+  "gray77\0"
+  "gray78\0"
+  "gray79\0"
+  "gray8\0"
+  "gray80\0"
+  "gray81\0"
+  "gray82\0"
+  "gray83\0"
+  "gray84\0"
+  "gray85\0"
+  "gray86\0"
+  "gray87\0"
+  "gray88\0"
+  "gray89\0"
+  "gray9\0"
+  "gray90\0"
+  "gray91\0"
+  "gray92\0"
+  "gray93\0"
+  "gray94\0"
+  "gray95\0"
+  "gray96\0"
+  "gray97\0"
+  "gray98\0"
+  "gray99\0"
+  "green\0"
+  "green yellow\0"
+  "green1\0"
+  "green2\0"
+  "green3\0"
+  "green4\0"
+  "GreenYellow\0"
+  "grey\0"
+  "grey0\0"
+  "grey1\0"
+  "grey10\0"
+  "grey100\0"
+  "grey11\0"
+  "grey12\0"
+  "grey13\0"
+  "grey14\0"
+  "grey15\0"
+  "grey16\0"
+  "grey17\0"
+  "grey18\0"
+  "grey19\0"
+  "grey2\0"
+  "grey20\0"
+  "grey21\0"
+  "grey22\0"
+  "grey23\0"
+  "grey24\0"
+  "grey25\0"
+  "grey26\0"
+  "grey27\0"
+  "grey28\0"
+  "grey29\0"
+  "grey3\0"
+  "grey30\0"
+  "grey31\0"
+  "grey32\0"
+  "grey33\0"
+  "grey34\0"
+  "grey35\0"
+  "grey36\0"
+  "grey37\0"
+  "grey38\0"
+  "grey39\0"
+  "grey4\0"
+  "grey40\0"
+  "grey41\0"
+  "grey42\0"
+  "grey43\0"
+  "grey44\0"
+  "grey45\0"
+  "grey46\0"
+  "grey47\0"
+  "grey48\0"
+  "grey49\0"
+  "grey5\0"
+  "grey50\0"
+  "grey51\0"
+  "grey52\0"
+  "grey53\0"
+  "grey54\0"
+  "grey55\0"
+  "grey56\0"
+  "grey57\0"
+  "grey58\0"
+  "grey59\0"
+  "grey6\0"
+  "grey60\0"
+  "grey61\0"
+  "grey62\0"
+  "grey63\0"
+  "grey64\0"
+  "grey65\0"
+  "grey66\0"
+  "grey67\0"
+  "grey68\0"
+  "grey69\0"
+  "grey7\0"
+  "grey70\0"
+  "grey71\0"
+  "grey72\0"
+  "grey73\0"
+  "grey74\0"
+  "grey75\0"
+  "grey76\0"
+  "grey77\0"
+  "grey78\0"
+  "grey79\0"
+  "grey8\0"
+  "grey80\0"
+  "grey81\0"
+  "grey82\0"
+  "grey83\0"
+  "grey84\0"
+  "grey85\0"
+  "grey86\0"
+  "grey87\0"
+  "grey88\0"
+  "grey89\0"
+  "grey9\0"
+  "grey90\0"
+  "grey91\0"
+  "grey92\0"
+  "grey93\0"
+  "grey94\0"
+  "grey95\0"
+  "grey96\0"
+  "grey97\0"
+  "grey98\0"
+  "grey99\0"
+  "honeydew\0"
+  "honeydew1\0"
+  "honeydew2\0"
+  "honeydew3\0"
+  "honeydew4\0"
+  "hot pink\0"
+  "HotPink\0"
+  "HotPink1\0"
+  "HotPink2\0"
+  "HotPink3\0"
+  "HotPink4\0"
+  "indian red\0"
+  "IndianRed\0"
+  "IndianRed1\0"
+  "IndianRed2\0"
+  "IndianRed3\0"
+  "IndianRed4\0"
+  "ivory\0"
+  "ivory1\0"
+  "ivory2\0"
+  "ivory3\0"
+  "ivory4\0"
+  "khaki\0"
+  "khaki1\0"
+  "khaki2\0"
+  "khaki3\0"
+  "khaki4\0"
+  "lavender\0"
+  "lavender blush\0"
+  "LavenderBlush\0"
+  "LavenderBlush1\0"
+  "LavenderBlush2\0"
+  "LavenderBlush3\0"
+  "LavenderBlush4\0"
+  "lawn green\0"
+  "LawnGreen\0"
+  "lemon chiffon\0"
+  "LemonChiffon\0"
+  "LemonChiffon1\0"
+  "LemonChiffon2\0"
+  "LemonChiffon3\0"
+  "LemonChiffon4\0"
+  "light blue\0"
+  "light coral\0"
+  "light cyan\0"
+  "light goldenrod\0"
+  "light goldenrod yellow\0"
+  "light gray\0"
+  "light green\0"
+  "light grey\0"
+  "light pink\0"
+  "light salmon\0"
+  "light sea green\0"
+  "light sky blue\0"
+  "light slate blue\0"
+  "light slate gray\0"
+  "light slate grey\0"
+  "light steel blue\0"
+  "light yellow\0"
+  "LightBlue\0"
+  "LightBlue1\0"
+  "LightBlue2\0"
+  "LightBlue3\0"
+  "LightBlue4\0"
+  "LightCoral\0"
+  "LightCyan\0"
+  "LightCyan1\0"
+  "LightCyan2\0"
+  "LightCyan3\0"
+  "LightCyan4\0"
+  "LightGoldenrod\0"
+  "LightGoldenrod1\0"
+  "LightGoldenrod2\0"
+  "LightGoldenrod3\0"
+  "LightGoldenrod4\0"
+  "LightGoldenrodYellow\0"
+  "LightGray\0"
+  "LightGreen\0"
+  "LightGrey\0"
+  "LightPink\0"
+  "LightPink1\0"
+  "LightPink2\0"
+  "LightPink3\0"
+  "LightPink4\0"
+  "LightSalmon\0"
+  "LightSalmon1\0"
+  "LightSalmon2\0"
+  "LightSalmon3\0"
+  "LightSalmon4\0"
+  "LightSeaGreen\0"
+  "LightSkyBlue\0"
+  "LightSkyBlue1\0"
+  "LightSkyBlue2\0"
+  "LightSkyBlue3\0"
+  "LightSkyBlue4\0"
+  "LightSlateBlue\0"
+  "LightSlateGray\0"
+  "LightSlateGrey\0"
+  "LightSteelBlue\0"
+  "LightSteelBlue1\0"
+  "LightSteelBlue2\0"
+  "LightSteelBlue3\0"
+  "LightSteelBlue4\0"
+  "LightYellow\0"
+  "LightYellow1\0"
+  "LightYellow2\0"
+  "LightYellow3\0"
+  "LightYellow4\0"
+  "lime green\0"
+  "LimeGreen\0"
+  "linen\0"
+  "magenta\0"
+  "magenta1\0"
+  "magenta2\0"
+  "magenta3\0"
+  "magenta4\0"
+  "maroon\0"
+  "maroon1\0"
+  "maroon2\0"
+  "maroon3\0"
+  "maroon4\0"
+  "medium aquamarine\0"
+  "medium blue\0"
+  "medium orchid\0"
+  "medium purple\0"
+  "medium sea green\0"
+  "medium slate blue\0"
+  "medium spring green\0"
+  "medium turquoise\0"
+  "medium violet red\0"
+  "MediumAquamarine\0"
+  "MediumBlue\0"
+  "MediumOrchid\0"
+  "MediumOrchid1\0"
+  "MediumOrchid2\0"
+  "MediumOrchid3\0"
+  "MediumOrchid4\0"
+  "MediumPurple\0"
+  "MediumPurple1\0"
+  "MediumPurple2\0"
+  "MediumPurple3\0"
+  "MediumPurple4\0"
+  "MediumSeaGreen\0"
+  "MediumSlateBlue\0"
+  "MediumSpringGreen\0"
+  "MediumTurquoise\0"
+  "MediumVioletRed\0"
+  "midnight blue\0"
+  "MidnightBlue\0"
+  "mint cream\0"
+  "MintCream\0"
+  "misty rose\0"
+  "MistyRose\0"
+  "MistyRose1\0"
+  "MistyRose2\0"
+  "MistyRose3\0"
+  "MistyRose4\0"
+  "moccasin\0"
+  "navajo white\0"
+  "NavajoWhite\0"
+  "NavajoWhite1\0"
+  "NavajoWhite2\0"
+  "NavajoWhite3\0"
+  "NavajoWhite4\0"
+  "navy\0"
+  "navy blue\0"
+  "NavyBlue\0"
+  "old lace\0"
+  "OldLace\0"
+  "olive drab\0"
+  "OliveDrab\0"
+  "OliveDrab1\0"
+  "OliveDrab2\0"
+  "OliveDrab3\0"
+  "OliveDrab4\0"
+  "orange\0"
+  "orange red\0"
+  "orange1\0"
+  "orange2\0"
+  "orange3\0"
+  "orange4\0"
+  "OrangeRed\0"
+  "OrangeRed1\0"
+  "OrangeRed2\0"
+  "OrangeRed3\0"
+  "OrangeRed4\0"
+  "orchid\0"
+  "orchid1\0"
+  "orchid2\0"
+  "orchid3\0"
+  "orchid4\0"
+  "pale goldenrod\0"
+  "pale green\0"
+  "pale turquoise\0"
+  "pale violet red\0"
+  "PaleGoldenrod\0"
+  "PaleGreen\0"
+  "PaleGreen1\0"
+  "PaleGreen2\0"
+  "PaleGreen3\0"
+  "PaleGreen4\0"
+  "PaleTurquoise\0"
+  "PaleTurquoise1\0"
+  "PaleTurquoise2\0"
+  "PaleTurquoise3\0"
+  "PaleTurquoise4\0"
+  "PaleVioletRed\0"
+  "PaleVioletRed1\0"
+  "PaleVioletRed2\0"
+  "PaleVioletRed3\0"
+  "PaleVioletRed4\0"
+  "papaya whip\0"
+  "PapayaWhip\0"
+  "peach puff\0"
+  "PeachPuff\0"
+  "PeachPuff1\0"
+  "PeachPuff2\0"
+  "PeachPuff3\0"
+  "PeachPuff4\0"
+  "peru\0"
+  "pink\0"
+  "pink1\0"
+  "pink2\0"
+  "pink3\0"
+  "pink4\0"
+  "plum\0"
+  "plum1\0"
+  "plum2\0"
+  "plum3\0"
+  "plum4\0"
+  "powder blue\0"
+  "PowderBlue\0"
+  "purple\0"
+  "purple1\0"
+  "purple2\0"
+  "purple3\0"
+  "purple4\0"
+  "red\0"
+  "red1\0"
+  "red2\0"
+  "red3\0"
+  "red4\0"
+  "rosy brown\0"
+  "RosyBrown\0"
+  "RosyBrown1\0"
+  "RosyBrown2\0"
+  "RosyBrown3\0"
+  "RosyBrown4\0"
+  "royal blue\0"
+  "RoyalBlue\0"
+  "RoyalBlue1\0"
+  "RoyalBlue2\0"
+  "RoyalBlue3\0"
+  "RoyalBlue4\0"
+  "saddle brown\0"
+  "SaddleBrown\0"
+  "salmon\0"
+  "salmon1\0"
+  "salmon2\0"
+  "salmon3\0"
+  "salmon4\0"
+  "sandy brown\0"
+  "SandyBrown\0"
+  "sea green\0"
+  "SeaGreen\0"
+  "SeaGreen1\0"
+  "SeaGreen2\0"
+  "SeaGreen3\0"
+  "SeaGreen4\0"
+  "seashell\0"
+  "seashell1\0"
+  "seashell2\0"
+  "seashell3\0"
+  "seashell4\0"
+  "sienna\0"
+  "sienna1\0"
+  "sienna2\0"
+  "sienna3\0"
+  "sienna4\0"
+  "sky blue\0"
+  "SkyBlue\0"
+  "SkyBlue1\0"
+  "SkyBlue2\0"
+  "SkyBlue3\0"
+  "SkyBlue4\0"
+  "slate blue\0"
+  "slate gray\0"
+  "slate grey\0"
+  "SlateBlue\0"
+  "SlateBlue1\0"
+  "SlateBlue2\0"
+  "SlateBlue3\0"
+  "SlateBlue4\0"
+  "SlateGray\0"
+  "SlateGray1\0"
+  "SlateGray2\0"
+  "SlateGray3\0"
+  "SlateGray4\0"
+  "SlateGrey\0"
+  "snow\0"
+  "snow1\0"
+  "snow2\0"
+  "snow3\0"
+  "snow4\0"
+  "spring green\0"
+  "SpringGreen\0"
+  "SpringGreen1\0"
+  "SpringGreen2\0"
+  "SpringGreen3\0"
+  "SpringGreen4\0"
+  "steel blue\0"
+  "SteelBlue\0"
+  "SteelBlue1\0"
+  "SteelBlue2\0"
+  "SteelBlue3\0"
+  "SteelBlue4\0"
+  "tan\0"
+  "tan1\0"
+  "tan2\0"
+  "tan3\0"
+  "tan4\0"
+  "thistle\0"
+  "thistle1\0"
+  "thistle2\0"
+  "thistle3\0"
+  "thistle4\0"
+  "tomato\0"
+  "tomato1\0"
+  "tomato2\0"
+  "tomato3\0"
+  "tomato4\0"
+  "turquoise\0"
+  "turquoise1\0"
+  "turquoise2\0"
+  "turquoise3\0"
+  "turquoise4\0"
+  "violet\0"
+  "violet red\0"
+  "VioletRed\0"
+  "VioletRed1\0"
+  "VioletRed2\0"
+  "VioletRed3\0"
+  "VioletRed4\0"
+  "wheat\0"
+  "wheat1\0"
+  "wheat2\0"
+  "wheat3\0"
+  "wheat4\0"
+  "white\0"
+  "white smoke\0"
+  "WhiteSmoke\0"
+  "yellow\0"
+  "yellow green\0"
+  "yellow1\0"
+  "yellow2\0"
+  "yellow3\0"
+  "yellow4\0"
+  "YellowGreen\0";
+
+typedef struct {
+    guint16 name_offset;
+    guchar red;
+    guchar green;
+    guchar blue;
+} XPMColorEntry;
+
+static const XPMColorEntry xColors[] = {
+  { 0, 240, 248, 255 },
+  { 11, 240, 248, 255 },
+  { 21, 250, 235, 215 },
+  { 35, 250, 235, 215 },
+  { 48, 255, 239, 219 },
+  { 62, 238, 223, 204 },
+  { 76, 205, 192, 176 },
+  { 90, 139, 131, 120 },
+  { 104, 127, 255, 212 },
+  { 115, 127, 255, 212 },
+  { 127, 118, 238, 198 },
+  { 139, 102, 205, 170 },
+  { 151, 69, 139, 116 },
+  { 163, 240, 255, 255 },
+  { 169, 240, 255, 255 },
+  { 176, 224, 238, 238 },
+  { 183, 193, 205, 205 },
+  { 190, 131, 139, 139 },
+  { 197, 245, 245, 220 },
+  { 203, 255, 228, 196 },
+  { 210, 255, 228, 196 },
+  { 218, 238, 213, 183 },
+  { 226, 205, 183, 158 },
+  { 234, 139, 125, 107 },
+  { 242, 0, 0, 0 },
+  { 248, 255, 235, 205 },
+  { 264, 255, 235, 205 },
+  { 279, 0, 0, 255 },
+  { 284, 138, 43, 226 },
+  { 296, 0, 0, 255 },
+  { 302, 0, 0, 238 },
+  { 308, 0, 0, 205 },
+  { 314, 0, 0, 139 },
+  { 320, 138, 43, 226 },
+  { 331, 165, 42, 42 },
+  { 337, 255, 64, 64 },
+  { 344, 238, 59, 59 },
+  { 351, 205, 51, 51 },
+  { 358, 139, 35, 35 },
+  { 365, 222, 184, 135 },
+  { 375, 255, 211, 155 },
+  { 386, 238, 197, 145 },
+  { 397, 205, 170, 125 },
+  { 408, 139, 115, 85 },
+  { 419, 95, 158, 160 },
+  { 430, 95, 158, 160 },
+  { 440, 152, 245, 255 },
+  { 451, 142, 229, 238 },
+  { 462, 122, 197, 205 },
+  { 473, 83, 134, 139 },
+  { 484, 127, 255, 0 },
+  { 495, 127, 255, 0 },
+  { 507, 118, 238, 0 },
+  { 519, 102, 205, 0 },
+  { 531, 69, 139, 0 },
+  { 543, 210, 105, 30 },
+  { 553, 255, 127, 36 },
+  { 564, 238, 118, 33 },
+  { 575, 205, 102, 29 },
+  { 586, 139, 69, 19 },
+  { 597, 255, 127, 80 },
+  { 603, 255, 114, 86 },
+  { 610, 238, 106, 80 },
+  { 617, 205, 91, 69 },
+  { 624, 139, 62, 47 },
+  { 631, 100, 149, 237 },
+  { 647, 100, 149, 237 },
+  { 662, 255, 248, 220 },
+  { 671, 255, 248, 220 },
+  { 681, 238, 232, 205 },
+  { 691, 205, 200, 177 },
+  { 701, 139, 136, 120 },
+  { 711, 0, 255, 255 },
+  { 716, 0, 255, 255 },
+  { 722, 0, 238, 238 },
+  { 728, 0, 205, 205 },
+  { 734, 0, 139, 139 },
+  { 740, 0, 0, 139 },
+  { 750, 0, 139, 139 },
+  { 760, 184, 134, 11 },
+  { 775, 169, 169, 169 },
+  { 785, 0, 100, 0 },
+  { 796, 169, 169, 169 },
+  { 806, 189, 183, 107 },
+  { 817, 139, 0, 139 },
+  { 830, 85, 107, 47 },
+  { 847, 255, 140, 0 },
+  { 859, 153, 50, 204 },
+  { 871, 139, 0, 0 },
+  { 880, 233, 150, 122 },
+  { 892, 143, 188, 143 },
+  { 907, 72, 61, 139 },
+  { 923, 47, 79, 79 },
+  { 939, 47, 79, 79 },
+  { 955, 0, 206, 209 },
+  { 970, 148, 0, 211 },
+  { 982, 0, 0, 139 },
+  { 991, 0, 139, 139 },
+  { 1000, 184, 134, 11 },
+  { 1014, 255, 185, 15 },
+  { 1029, 238, 173, 14 },
+  { 1044, 205, 149, 12 },
+  { 1059, 139, 101, 8 },
+  { 1074, 169, 169, 169 },
+  { 1083, 0, 100, 0 },
+  { 1093, 169, 169, 169 },
+  { 1102, 189, 183, 107 },
+  { 1112, 139, 0, 139 },
+  { 1124, 85, 107, 47 },
+  { 1139, 202, 255, 112 },
+  { 1155, 188, 238, 104 },
+  { 1171, 162, 205, 90 },
+  { 1187, 110, 139, 61 },
+  { 1203, 255, 140, 0 },
+  { 1214, 255, 127, 0 },
+  { 1226, 238, 118, 0 },
+  { 1238, 205, 102, 0 },
+  { 1250, 139, 69, 0 },
+  { 1262, 153, 50, 204 },
+  { 1273, 191, 62, 255 },
+  { 1285, 178, 58, 238 },
+  { 1297, 154, 50, 205 },
+  { 1309, 104, 34, 139 },
+  { 1321, 139, 0, 0 },
+  { 1329, 233, 150, 122 },
+  { 1340, 143, 188, 143 },
+  { 1353, 193, 255, 193 },
+  { 1367, 180, 238, 180 },
+  { 1381, 155, 205, 155 },
+  { 1395, 105, 139, 105 },
+  { 1409, 72, 61, 139 },
+  { 1423, 47, 79, 79 },
+  { 1437, 151, 255, 255 },
+  { 1452, 141, 238, 238 },
+  { 1467, 121, 205, 205 },
+  { 1482, 82, 139, 139 },
+  { 1497, 47, 79, 79 },
+  { 1511, 0, 206, 209 },
+  { 1525, 148, 0, 211 },
+  { 1536, 255, 20, 147 },
+  { 1546, 0, 191, 255 },
+  { 1560, 255, 20, 147 },
+  { 1569, 255, 20, 147 },
+  { 1579, 238, 18, 137 },
+  { 1589, 205, 16, 118 },
+  { 1599, 139, 10, 80 },
+  { 1609, 0, 191, 255 },
+  { 1621, 0, 191, 255 },
+  { 1634, 0, 178, 238 },
+  { 1647, 0, 154, 205 },
+  { 1660, 0, 104, 139 },
+  { 1673, 105, 105, 105 },
+  { 1682, 105, 105, 105 },
+  { 1691, 105, 105, 105 },
+  { 1699, 105, 105, 105 },
+  { 1707, 30, 144, 255 },
+  { 1719, 30, 144, 255 },
+  { 1730, 30, 144, 255 },
+  { 1742, 28, 134, 238 },
+  { 1754, 24, 116, 205 },
+  { 1766, 16, 78, 139 },
+  { 1778, 178, 34, 34 },
+  { 1788, 255, 48, 48 },
+  { 1799, 238, 44, 44 },
+  { 1810, 205, 38, 38 },
+  { 1821, 139, 26, 26 },
+  { 1832, 255, 250, 240 },
+  { 1845, 255, 250, 240 },
+  { 1857, 34, 139, 34 },
+  { 1870, 34, 139, 34 },
+  { 1882, 220, 220, 220 },
+  { 1892, 248, 248, 255 },
+  { 1904, 248, 248, 255 },
+  { 1915, 255, 215, 0 },
+  { 1920, 255, 215, 0 },
+  { 1926, 238, 201, 0 },
+  { 1932, 205, 173, 0 },
+  { 1938, 139, 117, 0 },
+  { 1944, 218, 165, 32 },
+  { 1954, 255, 193, 37 },
+  { 1965, 238, 180, 34 },
+  { 1976, 205, 155, 29 },
+  { 1987, 139, 105, 20 },
+  { 1998, 190, 190, 190 },
+  { 2003, 0, 0, 0 },
+  { 2009, 3, 3, 3 },
+  { 2015, 26, 26, 26 },
+  { 2022, 255, 255, 255 },
+  { 2030, 28, 28, 28 },
+  { 2037, 31, 31, 31 },
+  { 2044, 33, 33, 33 },
+  { 2051, 36, 36, 36 },
+  { 2058, 38, 38, 38 },
+  { 2065, 41, 41, 41 },
+  { 2072, 43, 43, 43 },
+  { 2079, 46, 46, 46 },
+  { 2086, 48, 48, 48 },
+  { 2093, 5, 5, 5 },
+  { 2099, 51, 51, 51 },
+  { 2106, 54, 54, 54 },
+  { 2113, 56, 56, 56 },
+  { 2120, 59, 59, 59 },
+  { 2127, 61, 61, 61 },
+  { 2134, 64, 64, 64 },
+  { 2141, 66, 66, 66 },
+  { 2148, 69, 69, 69 },
+  { 2155, 71, 71, 71 },
+  { 2162, 74, 74, 74 },
+  { 2169, 8, 8, 8 },
+  { 2175, 77, 77, 77 },
+  { 2182, 79, 79, 79 },
+  { 2189, 82, 82, 82 },
+  { 2196, 84, 84, 84 },
+  { 2203, 87, 87, 87 },
+  { 2210, 89, 89, 89 },
+  { 2217, 92, 92, 92 },
+  { 2224, 94, 94, 94 },
+  { 2231, 97, 97, 97 },
+  { 2238, 99, 99, 99 },
+  { 2245, 10, 10, 10 },
+  { 2251, 102, 102, 102 },
+  { 2258, 105, 105, 105 },
+  { 2265, 107, 107, 107 },
+  { 2272, 110, 110, 110 },
+  { 2279, 112, 112, 112 },
+  { 2286, 115, 115, 115 },
+  { 2293, 117, 117, 117 },
+  { 2300, 120, 120, 120 },
+  { 2307, 122, 122, 122 },
+  { 2314, 125, 125, 125 },
+  { 2321, 13, 13, 13 },
+  { 2327, 127, 127, 127 },
+  { 2334, 130, 130, 130 },
+  { 2341, 133, 133, 133 },
+  { 2348, 135, 135, 135 },
+  { 2355, 138, 138, 138 },
+  { 2362, 140, 140, 140 },
+  { 2369, 143, 143, 143 },
+  { 2376, 145, 145, 145 },
+  { 2383, 148, 148, 148 },
+  { 2390, 150, 150, 150 },
+  { 2397, 15, 15, 15 },
+  { 2403, 153, 153, 153 },
+  { 2410, 156, 156, 156 },
+  { 2417, 158, 158, 158 },
+  { 2424, 161, 161, 161 },
+  { 2431, 163, 163, 163 },
+  { 2438, 166, 166, 166 },
+  { 2445, 168, 168, 168 },
+  { 2452, 171, 171, 171 },
+  { 2459, 173, 173, 173 },
+  { 2466, 176, 176, 176 },
+  { 2473, 18, 18, 18 },
+  { 2479, 179, 179, 179 },
+  { 2486, 181, 181, 181 },
+  { 2493, 184, 184, 184 },
+  { 2500, 186, 186, 186 },
+  { 2507, 189, 189, 189 },
+  { 2514, 191, 191, 191 },
+  { 2521, 194, 194, 194 },
+  { 2528, 196, 196, 196 },
+  { 2535, 199, 199, 199 },
+  { 2542, 201, 201, 201 },
+  { 2549, 20, 20, 20 },
+  { 2555, 204, 204, 204 },
+  { 2562, 207, 207, 207 },
+  { 2569, 209, 209, 209 },
+  { 2576, 212, 212, 212 },
+  { 2583, 214, 214, 214 },
+  { 2590, 217, 217, 217 },
+  { 2597, 219, 219, 219 },
+  { 2604, 222, 222, 222 },
+  { 2611, 224, 224, 224 },
+  { 2618, 227, 227, 227 },
+  { 2625, 23, 23, 23 },
+  { 2631, 229, 229, 229 },
+  { 2638, 232, 232, 232 },
+  { 2645, 235, 235, 235 },
+  { 2652, 237, 237, 237 },
+  { 2659, 240, 240, 240 },
+  { 2666, 242, 242, 242 },
+  { 2673, 245, 245, 245 },
+  { 2680, 247, 247, 247 },
+  { 2687, 250, 250, 250 },
+  { 2694, 252, 252, 252 },
+  { 2701, 0, 255, 0 },
+  { 2707, 173, 255, 47 },
+  { 2720, 0, 255, 0 },
+  { 2727, 0, 238, 0 },
+  { 2734, 0, 205, 0 },
+  { 2741, 0, 139, 0 },
+  { 2748, 173, 255, 47 },
+  { 2760, 190, 190, 190 },
+  { 2765, 0, 0, 0 },
+  { 2771, 3, 3, 3 },
+  { 2777, 26, 26, 26 },
+  { 2784, 255, 255, 255 },
+  { 2792, 28, 28, 28 },
+  { 2799, 31, 31, 31 },
+  { 2806, 33, 33, 33 },
+  { 2813, 36, 36, 36 },
+  { 2820, 38, 38, 38 },
+  { 2827, 41, 41, 41 },
+  { 2834, 43, 43, 43 },
+  { 2841, 46, 46, 46 },
+  { 2848, 48, 48, 48 },
+  { 2855, 5, 5, 5 },
+  { 2861, 51, 51, 51 },
+  { 2868, 54, 54, 54 },
+  { 2875, 56, 56, 56 },
+  { 2882, 59, 59, 59 },
+  { 2889, 61, 61, 61 },
+  { 2896, 64, 64, 64 },
+  { 2903, 66, 66, 66 },
+  { 2910, 69, 69, 69 },
+  { 2917, 71, 71, 71 },
+  { 2924, 74, 74, 74 },
+  { 2931, 8, 8, 8 },
+  { 2937, 77, 77, 77 },
+  { 2944, 79, 79, 79 },
+  { 2951, 82, 82, 82 },
+  { 2958, 84, 84, 84 },
+  { 2965, 87, 87, 87 },
+  { 2972, 89, 89, 89 },
+  { 2979, 92, 92, 92 },
+  { 2986, 94, 94, 94 },
+  { 2993, 97, 97, 97 },
+  { 3000, 99, 99, 99 },
+  { 3007, 10, 10, 10 },
+  { 3013, 102, 102, 102 },
+  { 3020, 105, 105, 105 },
+  { 3027, 107, 107, 107 },
+  { 3034, 110, 110, 110 },
+  { 3041, 112, 112, 112 },
+  { 3048, 115, 115, 115 },
+  { 3055, 117, 117, 117 },
+  { 3062, 120, 120, 120 },
+  { 3069, 122, 122, 122 },
+  { 3076, 125, 125, 125 },
+  { 3083, 13, 13, 13 },
+  { 3089, 127, 127, 127 },
+  { 3096, 130, 130, 130 },
+  { 3103, 133, 133, 133 },
+  { 3110, 135, 135, 135 },
+  { 3117, 138, 138, 138 },
+  { 3124, 140, 140, 140 },
+  { 3131, 143, 143, 143 },
+  { 3138, 145, 145, 145 },
+  { 3145, 148, 148, 148 },
+  { 3152, 150, 150, 150 },
+  { 3159, 15, 15, 15 },
+  { 3165, 153, 153, 153 },
+  { 3172, 156, 156, 156 },
+  { 3179, 158, 158, 158 },
+  { 3186, 161, 161, 161 },
+  { 3193, 163, 163, 163 },
+  { 3200, 166, 166, 166 },
+  { 3207, 168, 168, 168 },
+  { 3214, 171, 171, 171 },
+  { 3221, 173, 173, 173 },
+  { 3228, 176, 176, 176 },
+  { 3235, 18, 18, 18 },
+  { 3241, 179, 179, 179 },
+  { 3248, 181, 181, 181 },
+  { 3255, 184, 184, 184 },
+  { 3262, 186, 186, 186 },
+  { 3269, 189, 189, 189 },
+  { 3276, 191, 191, 191 },
+  { 3283, 194, 194, 194 },
+  { 3290, 196, 196, 196 },
+  { 3297, 199, 199, 199 },
+  { 3304, 201, 201, 201 },
+  { 3311, 20, 20, 20 },
+  { 3317, 204, 204, 204 },
+  { 3324, 207, 207, 207 },
+  { 3331, 209, 209, 209 },
+  { 3338, 212, 212, 212 },
+  { 3345, 214, 214, 214 },
+  { 3352, 217, 217, 217 },
+  { 3359, 219, 219, 219 },
+  { 3366, 222, 222, 222 },
+  { 3373, 224, 224, 224 },
+  { 3380, 227, 227, 227 },
+  { 3387, 23, 23, 23 },
+  { 3393, 229, 229, 229 },
+  { 3400, 232, 232, 232 },
+  { 3407, 235, 235, 235 },
+  { 3414, 237, 237, 237 },
+  { 3421, 240, 240, 240 },
+  { 3428, 242, 242, 242 },
+  { 3435, 245, 245, 245 },
+  { 3442, 247, 247, 247 },
+  { 3449, 250, 250, 250 },
+  { 3456, 252, 252, 252 },
+  { 3463, 240, 255, 240 },
+  { 3472, 240, 255, 240 },
+  { 3482, 224, 238, 224 },
+  { 3492, 193, 205, 193 },
+  { 3502, 131, 139, 131 },
+  { 3512, 255, 105, 180 },
+  { 3521, 255, 105, 180 },
+  { 3529, 255, 110, 180 },
+  { 3538, 238, 106, 167 },
+  { 3547, 205, 96, 144 },
+  { 3556, 139, 58, 98 },
+  { 3565, 205, 92, 92 },
+  { 3576, 205, 92, 92 },
+  { 3586, 255, 106, 106 },
+  { 3597, 238, 99, 99 },
+  { 3608, 205, 85, 85 },
+  { 3619, 139, 58, 58 },
+  { 3630, 255, 255, 240 },
+  { 3636, 255, 255, 240 },
+  { 3643, 238, 238, 224 },
+  { 3650, 205, 205, 193 },
+  { 3657, 139, 139, 131 },
+  { 3664, 240, 230, 140 },
+  { 3670, 255, 246, 143 },
+  { 3677, 238, 230, 133 },
+  { 3684, 205, 198, 115 },
+  { 3691, 139, 134, 78 },
+  { 3698, 230, 230, 250 },
+  { 3707, 255, 240, 245 },
+  { 3722, 255, 240, 245 },
+  { 3736, 255, 240, 245 },
+  { 3751, 238, 224, 229 },
+  { 3766, 205, 193, 197 },
+  { 3781, 139, 131, 134 },
+  { 3796, 124, 252, 0 },
+  { 3807, 124, 252, 0 },
+  { 3817, 255, 250, 205 },
+  { 3831, 255, 250, 205 },
+  { 3844, 255, 250, 205 },
+  { 3858, 238, 233, 191 },
+  { 3872, 205, 201, 165 },
+  { 3886, 139, 137, 112 },
+  { 3900, 173, 216, 230 },
+  { 3911, 240, 128, 128 },
+  { 3923, 224, 255, 255 },
+  { 3934, 238, 221, 130 },
+  { 3950, 250, 250, 210 },
+  { 3973, 211, 211, 211 },
+  { 3984, 144, 238, 144 },
+  { 3996, 211, 211, 211 },
+  { 4007, 255, 182, 193 },
+  { 4018, 255, 160, 122 },
+  { 4031, 32, 178, 170 },
+  { 4047, 135, 206, 250 },
+  { 4062, 132, 112, 255 },
+  { 4079, 119, 136, 153 },
+  { 4096, 119, 136, 153 },
+  { 4113, 176, 196, 222 },
+  { 4130, 255, 255, 224 },
+  { 4143, 173, 216, 230 },
+  { 4153, 191, 239, 255 },
+  { 4164, 178, 223, 238 },
+  { 4175, 154, 192, 205 },
+  { 4186, 104, 131, 139 },
+  { 4197, 240, 128, 128 },
+  { 4208, 224, 255, 255 },
+  { 4218, 224, 255, 255 },
+  { 4229, 209, 238, 238 },
+  { 4240, 180, 205, 205 },
+  { 4251, 122, 139, 139 },
+  { 4262, 238, 221, 130 },
+  { 4277, 255, 236, 139 },
+  { 4293, 238, 220, 130 },
+  { 4309, 205, 190, 112 },
+  { 4325, 139, 129, 76 },
+  { 4341, 250, 250, 210 },
+  { 4362, 211, 211, 211 },
+  { 4372, 144, 238, 144 },
+  { 4383, 211, 211, 211 },
+  { 4393, 255, 182, 193 },
+  { 4403, 255, 174, 185 },
+  { 4414, 238, 162, 173 },
+  { 4425, 205, 140, 149 },
+  { 4436, 139, 95, 101 },
+  { 4447, 255, 160, 122 },
+  { 4459, 255, 160, 122 },
+  { 4472, 238, 149, 114 },
+  { 4485, 205, 129, 98 },
+  { 4498, 139, 87, 66 },
+  { 4511, 32, 178, 170 },
+  { 4525, 135, 206, 250 },
+  { 4538, 176, 226, 255 },
+  { 4552, 164, 211, 238 },
+  { 4566, 141, 182, 205 },
+  { 4580, 96, 123, 139 },
+  { 4594, 132, 112, 255 },
+  { 4609, 119, 136, 153 },
+  { 4624, 119, 136, 153 },
+  { 4639, 176, 196, 222 },
+  { 4654, 202, 225, 255 },
+  { 4670, 188, 210, 238 },
+  { 4686, 162, 181, 205 },
+  { 4702, 110, 123, 139 },
+  { 4718, 255, 255, 224 },
+  { 4730, 255, 255, 224 },
+  { 4743, 238, 238, 209 },
+  { 4756, 205, 205, 180 },
+  { 4769, 139, 139, 122 },
+  { 4782, 50, 205, 50 },
+  { 4793, 50, 205, 50 },
+  { 4803, 250, 240, 230 },
+  { 4809, 255, 0, 255 },
+  { 4817, 255, 0, 255 },
+  { 4826, 238, 0, 238 },
+  { 4835, 205, 0, 205 },
+  { 4844, 139, 0, 139 },
+  { 4853, 176, 48, 96 },
+  { 4860, 255, 52, 179 },
+  { 4868, 238, 48, 167 },
+  { 4876, 205, 41, 144 },
+  { 4884, 139, 28, 98 },
+  { 4892, 102, 205, 170 },
+  { 4910, 0, 0, 205 },
+  { 4922, 186, 85, 211 },
+  { 4936, 147, 112, 219 },
+  { 4950, 60, 179, 113 },
+  { 4967, 123, 104, 238 },
+  { 4985, 0, 250, 154 },
+  { 5005, 72, 209, 204 },
+  { 5022, 199, 21, 133 },
+  { 5040, 102, 205, 170 },
+  { 5057, 0, 0, 205 },
+  { 5068, 186, 85, 211 },
+  { 5081, 224, 102, 255 },
+  { 5095, 209, 95, 238 },
+  { 5109, 180, 82, 205 },
+  { 5123, 122, 55, 139 },
+  { 5137, 147, 112, 219 },
+  { 5150, 171, 130, 255 },
+  { 5164, 159, 121, 238 },
+  { 5178, 137, 104, 205 },
+  { 5192, 93, 71, 139 },
+  { 5206, 60, 179, 113 },
+  { 5221, 123, 104, 238 },
+  { 5237, 0, 250, 154 },
+  { 5255, 72, 209, 204 },
+  { 5271, 199, 21, 133 },
+  { 5287, 25, 25, 112 },
+  { 5301, 25, 25, 112 },
+  { 5314, 245, 255, 250 },
+  { 5325, 245, 255, 250 },
+  { 5335, 255, 228, 225 },
+  { 5346, 255, 228, 225 },
+  { 5356, 255, 228, 225 },
+  { 5367, 238, 213, 210 },
+  { 5378, 205, 183, 181 },
+  { 5389, 139, 125, 123 },
+  { 5400, 255, 228, 181 },
+  { 5409, 255, 222, 173 },
+  { 5422, 255, 222, 173 },
+  { 5434, 255, 222, 173 },
+  { 5447, 238, 207, 161 },
+  { 5460, 205, 179, 139 },
+  { 5473, 139, 121, 94 },
+  { 5486, 0, 0, 128 },
+  { 5491, 0, 0, 128 },
+  { 5501, 0, 0, 128 },
+  { 5510, 253, 245, 230 },
+  { 5519, 253, 245, 230 },
+  { 5527, 107, 142, 35 },
+  { 5538, 107, 142, 35 },
+  { 5548, 192, 255, 62 },
+  { 5559, 179, 238, 58 },
+  { 5570, 154, 205, 50 },
+  { 5581, 105, 139, 34 },
+  { 5592, 255, 165, 0 },
+  { 5599, 255, 69, 0 },
+  { 5610, 255, 165, 0 },
+  { 5618, 238, 154, 0 },
+  { 5626, 205, 133, 0 },
+  { 5634, 139, 90, 0 },
+  { 5642, 255, 69, 0 },
+  { 5652, 255, 69, 0 },
+  { 5663, 238, 64, 0 },
+  { 5674, 205, 55, 0 },
+  { 5685, 139, 37, 0 },
+  { 5696, 218, 112, 214 },
+  { 5703, 255, 131, 250 },
+  { 5711, 238, 122, 233 },
+  { 5719, 205, 105, 201 },
+  { 5727, 139, 71, 137 },
+  { 5735, 238, 232, 170 },
+  { 5750, 152, 251, 152 },
+  { 5761, 175, 238, 238 },
+  { 5776, 219, 112, 147 },
+  { 5792, 238, 232, 170 },
+  { 5806, 152, 251, 152 },
+  { 5816, 154, 255, 154 },
+  { 5827, 144, 238, 144 },
+  { 5838, 124, 205, 124 },
+  { 5849, 84, 139, 84 },
+  { 5860, 175, 238, 238 },
+  { 5874, 187, 255, 255 },
+  { 5889, 174, 238, 238 },
+  { 5904, 150, 205, 205 },
+  { 5919, 102, 139, 139 },
+  { 5934, 219, 112, 147 },
+  { 5948, 255, 130, 171 },
+  { 5963, 238, 121, 159 },
+  { 5978, 205, 104, 137 },
+  { 5993, 139, 71, 93 },
+  { 6008, 255, 239, 213 },
+  { 6020, 255, 239, 213 },
+  { 6031, 255, 218, 185 },
+  { 6042, 255, 218, 185 },
+  { 6052, 255, 218, 185 },
+  { 6063, 238, 203, 173 },
+  { 6074, 205, 175, 149 },
+  { 6085, 139, 119, 101 },
+  { 6096, 205, 133, 63 },
+  { 6101, 255, 192, 203 },
+  { 6106, 255, 181, 197 },
+  { 6112, 238, 169, 184 },
+  { 6118, 205, 145, 158 },
+  { 6124, 139, 99, 108 },
+  { 6130, 221, 160, 221 },
+  { 6135, 255, 187, 255 },
+  { 6141, 238, 174, 238 },
+  { 6147, 205, 150, 205 },
+  { 6153, 139, 102, 139 },
+  { 6159, 176, 224, 230 },
+  { 6171, 176, 224, 230 },
+  { 6182, 160, 32, 240 },
+  { 6189, 155, 48, 255 },
+  { 6197, 145, 44, 238 },
+  { 6205, 125, 38, 205 },
+  { 6213, 85, 26, 139 },
+  { 6221, 255, 0, 0 },
+  { 6225, 255, 0, 0 },
+  { 6230, 238, 0, 0 },
+  { 6235, 205, 0, 0 },
+  { 6240, 139, 0, 0 },
+  { 6245, 188, 143, 143 },
+  { 6256, 188, 143, 143 },
+  { 6266, 255, 193, 193 },
+  { 6277, 238, 180, 180 },
+  { 6288, 205, 155, 155 },
+  { 6299, 139, 105, 105 },
+  { 6310, 65, 105, 225 },
+  { 6321, 65, 105, 225 },
+  { 6331, 72, 118, 255 },
+  { 6342, 67, 110, 238 },
+  { 6353, 58, 95, 205 },
+  { 6364, 39, 64, 139 },
+  { 6375, 139, 69, 19 },
+  { 6388, 139, 69, 19 },
+  { 6400, 250, 128, 114 },
+  { 6407, 255, 140, 105 },
+  { 6415, 238, 130, 98 },
+  { 6423, 205, 112, 84 },
+  { 6431, 139, 76, 57 },
+  { 6439, 244, 164, 96 },
+  { 6451, 244, 164, 96 },
+  { 6462, 46, 139, 87 },
+  { 6472, 46, 139, 87 },
+  { 6481, 84, 255, 159 },
+  { 6491, 78, 238, 148 },
+  { 6501, 67, 205, 128 },
+  { 6511, 46, 139, 87 },
+  { 6521, 255, 245, 238 },
+  { 6530, 255, 245, 238 },
+  { 6540, 238, 229, 222 },
+  { 6550, 205, 197, 191 },
+  { 6560, 139, 134, 130 },
+  { 6570, 160, 82, 45 },
+  { 6577, 255, 130, 71 },
+  { 6585, 238, 121, 66 },
+  { 6593, 205, 104, 57 },
+  { 6601, 139, 71, 38 },
+  { 6609, 135, 206, 235 },
+  { 6618, 135, 206, 235 },
+  { 6626, 135, 206, 255 },
+  { 6635, 126, 192, 238 },
+  { 6644, 108, 166, 205 },
+  { 6653, 74, 112, 139 },
+  { 6662, 106, 90, 205 },
+  { 6673, 112, 128, 144 },
+  { 6684, 112, 128, 144 },
+  { 6695, 106, 90, 205 },
+  { 6705, 131, 111, 255 },
+  { 6716, 122, 103, 238 },
+  { 6727, 105, 89, 205 },
+  { 6738, 71, 60, 139 },
+  { 6749, 112, 128, 144 },
+  { 6759, 198, 226, 255 },
+  { 6770, 185, 211, 238 },
+  { 6781, 159, 182, 205 },
+  { 6792, 108, 123, 139 },
+  { 6803, 112, 128, 144 },
+  { 6813, 255, 250, 250 },
+  { 6818, 255, 250, 250 },
+  { 6824, 238, 233, 233 },
+  { 6830, 205, 201, 201 },
+  { 6836, 139, 137, 137 },
+  { 6842, 0, 255, 127 },
+  { 6855, 0, 255, 127 },
+  { 6867, 0, 255, 127 },
+  { 6880, 0, 238, 118 },
+  { 6893, 0, 205, 102 },
+  { 6906, 0, 139, 69 },
+  { 6919, 70, 130, 180 },
+  { 6930, 70, 130, 180 },
+  { 6940, 99, 184, 255 },
+  { 6951, 92, 172, 238 },
+  { 6962, 79, 148, 205 },
+  { 6973, 54, 100, 139 },
+  { 6984, 210, 180, 140 },
+  { 6988, 255, 165, 79 },
+  { 6993, 238, 154, 73 },
+  { 6998, 205, 133, 63 },
+  { 7003, 139, 90, 43 },
+  { 7008, 216, 191, 216 },
+  { 7016, 255, 225, 255 },
+  { 7025, 238, 210, 238 },
+  { 7034, 205, 181, 205 },
+  { 7043, 139, 123, 139 },
+  { 7052, 255, 99, 71 },
+  { 7059, 255, 99, 71 },
+  { 7067, 238, 92, 66 },
+  { 7075, 205, 79, 57 },
+  { 7083, 139, 54, 38 },
+  { 7091, 64, 224, 208 },
+  { 7101, 0, 245, 255 },
+  { 7112, 0, 229, 238 },
+  { 7123, 0, 197, 205 },
+  { 7134, 0, 134, 139 },
+  { 7145, 238, 130, 238 },
+  { 7152, 208, 32, 144 },
+  { 7163, 208, 32, 144 },
+  { 7173, 255, 62, 150 },
+  { 7184, 238, 58, 140 },
+  { 7195, 205, 50, 120 },
+  { 7206, 139, 34, 82 },
+  { 7217, 245, 222, 179 },
+  { 7223, 255, 231, 186 },
+  { 7230, 238, 216, 174 },
+  { 7237, 205, 186, 150 },
+  { 7244, 139, 126, 102 },
+  { 7251, 255, 255, 255 },
+  { 7257, 245, 245, 245 },
+  { 7269, 245, 245, 245 },
+  { 7280, 255, 255, 0 },
+  { 7287, 154, 205, 50 },
+  { 7300, 255, 255, 0 },
+  { 7308, 238, 238, 0 },
+  { 7316, 205, 205, 0 },
+  { 7324, 139, 139, 0 },
+  { 7332, 154, 205, 50 }
+};
index fae3c05..1940096 100644 (file)
@@ -1,3 +1,6 @@
+* Sat May 19 07:41:32 UTC 2012 - tracy.graydon@intel.com
+- add missing source 
+
 * Sat May 19 07:39:14 UTC 2012 - tracy.graydon@intel.com
 - OBS/gerrit sync