summaryrefslogtreecommitdiff
path: root/gdk-pixbuf
diff options
context:
space:
mode:
authorTor Lillqvist <tml@novell.com>2008-03-20 23:24:45 +0000
committerTor Lillqvist <tml@src.gnome.org>2008-03-20 23:24:45 +0000
commit6d15bbbe1da2a30a2bf4b519cd03bf3bc80ccfaf (patch)
tree7f865e3e03fc46190ca21516069defda81150860 /gdk-pixbuf
parent84fa2c6194c90ddaa05c353ab75fe89750f47677 (diff)
downloadgtk+-6d15bbbe1da2a30a2bf4b519cd03bf3bc80ccfaf.tar.gz
Import the GDI+ gdk-pixbuf loaders for Windows by Dominic Lachowicz and
2008-03-21 Tor Lillqvist <tml@novell.com> Import the GDI+ gdk-pixbuf loaders for Windows by Dominic Lachowicz and Alberto Ruiz into the GTK+ tree, from the gdip-pixbuf-loader module. * configure.in: Add switch --disable-gdiplus-loaders that disables building of the GDI+ loaders. When including loaders in the gdk-pixbuf library, either build in abll the GDI+ ones or none of them. Use just -DINCLUDE_gdiplus in $INCLUDED_LOADER_DEFINE to signal building them in. Add Automake conditionals BUILD_GDIPLUS_LOADERS to indicate whether the GDI+ loaders should be built and INCLUDE_GDIPLUS to indicate whether they should be built-in. For the rest of the changes, see gdk-pixbuf/ChangeLog. In gdk-pixbuf: * Makefile.am: Add the bits and pieces for the GDI+ loaders. When building GDI+ loaders don't build the traditional ones for the same formats. Always build the traditional PNG loader, though, as it isn't possible to read and write PNG tEXt chunks through GDI+, and GIMP at least needs that functionality in the gdk-pixbuf PNG loader. Either build all the GDI+ loaders (except the PNG one) into libgdk-pixbuf, or build them all as DLLs. I don't see any reason to enable cherry-picking among them whether to build in or not. * io-gdip-animation.c * io-gdip-animation.h * io-gdip-bmp.c * io-gdip-emf.c * io-gdip-gif.c * io-gdip-ico.c * io-gdip-jpeg.c * io-gdip-native.h * io-gdip-png.c * io-gdip-propertytags.h * io-gdip-tiff.c * io-gdip-utils.c * io-gdip-utils.h * io-gdip-wmf.c: New files. Note that io-gdip-png.c is not currently used. * gdk-pixbuf-io.c: Add the bits and pieces for built-in GDI+ loaders. svn path=/trunk/; revision=19914
Diffstat (limited to 'gdk-pixbuf')
-rw-r--r--gdk-pixbuf/ChangeLog36
-rw-r--r--gdk-pixbuf/Makefile.am216
-rw-r--r--gdk-pixbuf/gdk-pixbuf-io.c70
-rw-r--r--gdk-pixbuf/io-gdip-animation.c383
-rw-r--r--gdk-pixbuf/io-gdip-animation.h117
-rw-r--r--gdk-pixbuf/io-gdip-bmp.c87
-rw-r--r--gdk-pixbuf/io-gdip-emf.c64
-rw-r--r--gdk-pixbuf/io-gdip-gif.c85
-rw-r--r--gdk-pixbuf/io-gdip-ico.c64
-rw-r--r--gdk-pixbuf/io-gdip-jpeg.c141
-rw-r--r--gdk-pixbuf/io-gdip-native.h235
-rw-r--r--gdk-pixbuf/io-gdip-png.c138
-rw-r--r--gdk-pixbuf/io-gdip-propertytags.h228
-rw-r--r--gdk-pixbuf/io-gdip-tiff.c87
-rw-r--r--gdk-pixbuf/io-gdip-utils.c996
-rw-r--r--gdk-pixbuf/io-gdip-utils.h52
-rw-r--r--gdk-pixbuf/io-gdip-wmf.c63
17 files changed, 3016 insertions, 46 deletions
diff --git a/gdk-pixbuf/ChangeLog b/gdk-pixbuf/ChangeLog
index d8e689776c..2205d3d2c0 100644
--- a/gdk-pixbuf/ChangeLog
+++ b/gdk-pixbuf/ChangeLog
@@ -1,3 +1,39 @@
+2008-03-21 Tor Lillqvist <tml@novell.com>
+
+ Import the GDI+ gdk-pixbuf loaders for Windows by Dominic
+ Lachowicz and Alberto Ruiz into the GTK+ tree, from the
+ gdip-pixbuf-loader module.
+
+ * Makefile.am: Add the bits and pieces for the GDI+ loaders. When
+ building GDI+ loaders don't build the traditional ones for the
+ same formats. Always build the traditional PNG loader, though, as
+ it isn't possible to read and write PNG tEXt chunks through GDI+,
+ and GIMP at least needs that functionality in the gdk-pixbuf PNG
+ loader.
+
+ Either build all the GDI+ loaders (except the PNG one) into
+ libgdk-pixbuf, or build them all as DLLs. I don't see any reason
+ to enable cherry-picking among them whether to build in or not.
+
+ * io-gdip-animation.c
+ * io-gdip-animation.h
+ * io-gdip-bmp.c
+ * io-gdip-emf.c
+ * io-gdip-gif.c
+ * io-gdip-ico.c
+ * io-gdip-jpeg.c
+ * io-gdip-native.h
+ * io-gdip-png.c
+ * io-gdip-propertytags.h
+ * io-gdip-tiff.c
+ * io-gdip-utils.c
+ * io-gdip-utils.h
+ * io-gdip-wmf.c: New files. Note that io-gdip-png.c is not
+ currently used.
+
+ * gdk-pixbuf-io.c: Add the bits and pieces for built-in GDI+
+ loaders.
+
2008-03-11 Claudio Saavedra <csaavedra@alumnos.utalca.cl>
* io-bmp.c: (gdk_pixbuf__bmp_image_stop_load): Set a
diff --git a/gdk-pixbuf/Makefile.am b/gdk-pixbuf/Makefile.am
index 263c968fc6..d90aa43ca7 100644
--- a/gdk-pixbuf/Makefile.am
+++ b/gdk-pixbuf/Makefile.am
@@ -13,6 +13,8 @@ gdk_pixbuf_symbols = -export-symbols 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 $@
@@ -64,10 +66,10 @@ module_libs = libgdk_pixbuf-$(GTK_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)
-libstatic_pixbufloader_png_la_SOURCES = io-png.c
#
# The BMP loader
@@ -189,26 +191,163 @@ libpixbufloader_jasper_la_SOURCES = io-jasper.c
libpixbufloader_jasper_la_LDFLAGS = -avoid-version -module $(no_undefined)
libpixbufloader_jasper_la_LIBADD = $(LIBJASPER) $(module_libs)
-if HAVE_PNG
-if INCLUDE_PNG
-STATIC_PNG_LIB = libstatic-pixbufloader-png.la
+if BUILD_GDIPLUS_LOADERS
+
+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_png_la_SOURCES = \
+ io-gdip-png.c
+
+libstatic_pixbufloader_gdip_tiff_la_SOURCES = \
+ io-gdip-tiff.c
+
else
-PNG_LIB = libpixbufloader-png.la
-endif
+
+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
+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
+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
+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
+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
+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
+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_png_la_LDFLAGS = -avoid-version -module -no-undefined
+libpixbufloader_gdip_png_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-png.c
+libpixbufloader_gdip_png_la_LIBADD = $(module_libs) $(libole32)
+
+libpixbufloader_gdip_tiff_la_LDFLAGS = -avoid-version -module -no-undefined
+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_WBMP
-STATIC_WBMP_LIB = libstatic-pixbufloader-wbmp.la
-else
-WBMP_LIB = libpixbufloader-wbmp.la
-endif
-
if INCLUDE_GIF
STATIC_GIF_LIB = libstatic-pixbufloader-gif.la
else
@@ -221,12 +360,6 @@ else
ICO_LIB = libpixbufloader-ico.la
endif
-if INCLUDE_ANI
-STATIC_ANI_LIB = libstatic-pixbufloader-ani.la
-else
-ANI_LIB = libpixbufloader-ani.la
-endif
-
if HAVE_JPEG
if INCLUDE_JPEG
STATIC_JPEG_LIB = libstatic-pixbufloader-jpeg.la
@@ -235,6 +368,37 @@ 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
@@ -247,14 +411,6 @@ else
RAS_LIB = libpixbufloader-ras.la
endif
-if HAVE_TIFF
-if INCLUDE_TIFF
-STATIC_TIFF_LIB = libstatic-pixbufloader-tiff.la
-else
-TIFF_LIB = libpixbufloader-tiff.la
-endif
-endif
-
if INCLUDE_XPM
STATIC_XPM_LIB = libstatic-pixbufloader-xpm.la
else
@@ -311,7 +467,8 @@ loader_LTLIBRARIES = \
$(TGA_LIB) \
$(ICNS_LIB) \
$(PCX_LIB) \
- $(JASPER_LIB)
+ $(JASPER_LIB) \
+ $(GDIPLUS_LIBS)
endif
@@ -332,7 +489,8 @@ noinst_LTLIBRARIES = \
$(STATIC_TGA_LIB) \
$(STATIC_ICNS_LIB) \
$(STATIC_PCX_LIB) \
- $(STATIC_JASPER_LIB)
+ $(STATIC_JASPER_LIB) \
+ $(STATIC_GDIPLUS_LIBS)
builtin_objs = @INCLUDED_LOADER_OBJ@
@@ -394,7 +552,7 @@ libgdk_pixbuf_2_0_la_LDFLAGS = \
$(gdk_pixbuf_symbols)
-libgdk_pixbuf_2_0_la_LIBADD = pixops/libpixops.la $(builtin_objs) $(GDK_PIXBUF_DEP_LIBS)
+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)
gdk_pixbuf_headers = \
diff --git a/gdk-pixbuf/gdk-pixbuf-io.c b/gdk-pixbuf/gdk-pixbuf-io.c
index 0255cbfb40..9214ce4cd6 100644
--- a/gdk-pixbuf/gdk-pixbuf-io.c
+++ b/gdk-pixbuf/gdk-pixbuf-io.c
@@ -363,6 +363,22 @@ gdk_pixbuf_io_init (void)
#ifdef INCLUDE_pcx
load_one_builtin_module (pcx);
#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
@@ -576,6 +592,14 @@ module (wbmp);
module (xbm);
module (tga);
module (pcx);
+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
@@ -588,53 +612,65 @@ _gdk_pixbuf_load_module (GdkPixbufModule *image_module,
GdkPixbufModuleFillInfoFunc fill_info = NULL;
GdkPixbufModuleFillVtableFunc fill_vtable = NULL;
-#define try_module(format) \
+#define try_module(format,id) \
if (fill_info == NULL && \
strcmp (image_module->module_name, #format) == 0) { \
- fill_info = _gdk_pixbuf__##format##_fill_info; \
- fill_vtable = _gdk_pixbuf__##format##_fill_vtable; \
+ fill_info = _gdk_pixbuf__##id##_fill_info; \
+ fill_vtable = _gdk_pixbuf__##id##_fill_vtable; \
}
#ifdef INCLUDE_png
- try_module (png);
+ try_module (png,png);
#endif
#ifdef INCLUDE_bmp
- try_module (bmp);
+ try_module (bmp,bmp);
#endif
#ifdef INCLUDE_wbmp
- try_module (wbmp);
+ try_module (wbmp,wbmp);
#endif
#ifdef INCLUDE_gif
- try_module (gif);
+ try_module (gif,gif);
#endif
#ifdef INCLUDE_ico
- try_module (ico);
+ try_module (ico,ico);
#endif
#ifdef INCLUDE_ani
- try_module (ani);
+ try_module (ani,ani);
#endif
#ifdef INCLUDE_jpeg
- try_module (jpeg);
+ try_module (jpeg,jpeg);
#endif
#ifdef INCLUDE_pnm
- try_module (pnm);
+ try_module (pnm,pnm);
#endif
#ifdef INCLUDE_ras
- try_module (ras);
+ try_module (ras,ras);
#endif
#ifdef INCLUDE_tiff
- try_module (tiff);
+ try_module (tiff,tiff);
#endif
#ifdef INCLUDE_xpm
- try_module (xpm);
+ try_module (xpm,xpm);
#endif
#ifdef INCLUDE_xbm
- try_module (xbm);
+ try_module (xbm,xbm);
#endif
#ifdef INCLUDE_tga
- try_module (tga);
+ try_module (tga,tga);
#endif
#ifdef INCLUDE_pcx
- try_module (pcx);
+ try_module (pcx,pcx);
+#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
diff --git a/gdk-pixbuf/io-gdip-animation.c b/gdk-pixbuf/io-gdip-animation.c
new file mode 100644
index 0000000000..14cd034bc2
--- /dev/null
+++ b/gdk-pixbuf/io-gdip-animation.c
@@ -0,0 +1,383 @@
+/* -*- 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_class_init (GdkPixbufGdipAnimClass *klass);
+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);
+
+static gpointer parent_class;
+
+GType
+gdk_pixbuf_gdip_anim_get_type (void)
+{
+ static GType object_type = 0;
+
+ if (!object_type) {
+ static const GTypeInfo object_info = {
+ sizeof (GdkPixbufGdipAnimClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gdk_pixbuf_gdip_anim_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (GdkPixbufGdipAnim),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) NULL,
+ };
+
+ object_type = g_type_from_name ("GdkPixbufGdipAnim");
+ if (object_type == 0) {
+ object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION,
+ g_intern_static_string ("GdkPixbufGdipAnim"),
+ &object_info, 0);
+ }
+ }
+
+ return object_type;
+}
+
+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);
+
+ parent_class = g_type_class_peek_parent (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 (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_class_init (GdkPixbufGdipAnimIterClass *klass);
+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);
+
+static gpointer iter_parent_class;
+
+GType
+gdk_pixbuf_gdip_anim_iter_get_type (void)
+{
+ static GType object_type = 0;
+
+ if (!object_type) {
+ static const GTypeInfo object_info = {
+ sizeof (GdkPixbufGdipAnimIterClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gdk_pixbuf_gdip_anim_iter_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (GdkPixbufGdipAnimIter),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) NULL,
+ };
+
+ object_type = g_type_from_name ("GdkPixbufGdipAnimIter");
+ if (object_type == 0) {
+ object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION_ITER,
+ g_intern_static_string ("GdkPixbufGdipAnimIter"),
+ &object_info, 0);
+ }
+ }
+
+ return object_type;
+}
+
+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);
+
+ iter_parent_class = g_type_class_peek_parent (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 (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
index 0000000000..01e827876d
--- /dev/null
+++ b/gdk-pixbuf/io-gdip-animation.h
@@ -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
index 0000000000..40f6a5f536
--- /dev/null
+++ b/gdk-pixbuf/io-gdip-bmp.c
@@ -0,0 +1,87 @@
+/* -*- 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"
+
+static gboolean
+gdk_pixbuf__gdip_image_save_BMP_to_callback (GdkPixbufSaveFunc save_func,
+ gpointer user_data,
+ GdkPixbuf *pixbuf,
+ gchar **keys,
+ gchar **values,
+ GError **error)
+{
+ return gdip_save_pixbuf (pixbuf, L"image/bmp", NULL, save_func, user_data, error);
+}
+
+static gboolean
+gdk_pixbuf__gdip_image_save_BMP (FILE *f,
+ GdkPixbuf *pixbuf,
+ gchar **keys,
+ gchar **values,
+ GError **error)
+{
+ return gdk_pixbuf__gdip_image_save_BMP_to_callback (gdip_save_to_file_callback, f, pixbuf, keys, values, error);
+}
+
+#ifndef INCLUDE_gdiplus
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
+#else
+#define MODULE_ENTRY(function) void _gdk_pixbuf__gdip_bmp_ ## function
+#endif
+
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
+{
+ gdip_fill_vtable (module);
+
+ module->save_to_callback = gdk_pixbuf__gdip_image_save_BMP_to_callback;
+ module->save = gdk_pixbuf__gdip_image_save_BMP; /* for gtk < 2.14, you need to implement both. otherwise gdk-pixbuf-queryloaders fails */
+}
+
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
+{
+ static GdkPixbufModulePattern signature[] = {
+ { "BM", NULL, 100 }, /* BMP */
+ { 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 = _("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-emf.c b/gdk-pixbuf/io-gdip-emf.c
new file mode 100644
index 0000000000..07ee0b0200
--- /dev/null
+++ b/gdk-pixbuf/io-gdip-emf.c
@@ -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
index 0000000000..f991a9d3de
--- /dev/null
+++ b/gdk-pixbuf/io-gdip-gif.c
@@ -0,0 +1,85 @@
+/* -*- 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"
+
+static gboolean
+gdk_pixbuf__gdip_image_save_GIF_to_callback (GdkPixbufSaveFunc save_func,
+ gpointer user_data,
+ GdkPixbuf *pixbuf,
+ gchar **keys,
+ gchar **values,
+ GError **error)
+{
+ return gdip_save_pixbuf (pixbuf, L"image/gif", NULL, save_func, user_data, error);
+}
+
+static gboolean
+gdk_pixbuf__gdip_image_save_GIF (FILE *f,
+ GdkPixbuf *pixbuf,
+ gchar **keys,
+ gchar **values,
+ GError **error)
+{
+ return gdk_pixbuf__gdip_image_save_GIF_to_callback (gdip_save_to_file_callback, f, pixbuf, keys, values, error);
+}
+
+#ifndef INCLUDE_gdiplus
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
+#else
+#define MODULE_ENTRY(function) void _gdk_pixbuf__gdip_gif_ ## function
+#endif
+
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
+{
+ gdip_fill_vtable (module);
+
+ module->save_to_callback = gdk_pixbuf__gdip_image_save_GIF_to_callback;
+ module->save = gdk_pixbuf__gdip_image_save_GIF; /* for gtk < 2.14, you need to implement both. otherwise gdk-pixbuf-queryloaders fails */
+}
+
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
+{
+ static GdkPixbufModulePattern signature[] = {
+ { "GIF8", NULL, 100 }, /* GIF */
+ { NULL, NULL, 0 }
+ };
+
+ static gchar *mime_types[] = {
+ "image/gif",
+ NULL
+ };
+
+ static gchar *extensions[] = {
+ "gif",
+ NULL
+ };
+
+ info->name = "gif";
+ info->signature = signature;
+ info->description = _("The GIF 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-ico.c b/gdk-pixbuf/io-gdip-ico.c
new file mode 100644
index 0000000000..8538b58111
--- /dev/null
+++ b/gdk-pixbuf/io-gdip-ico.c
@@ -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
index 0000000000..8bd3058606
--- /dev/null
+++ b/gdk-pixbuf/io-gdip-jpeg.c
@@ -0,0 +1,141 @@
+/* -*- 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 "io-gdip-utils.h"
+
+DEFINE_GUID(EncoderQuality, 0x1d5be4b5,0xfa4a,0x452d,0x9c,0xdd,0x5d,0xb3,0x51,0x05,0xe7,0xeb);
+
+static gboolean
+gdk_pixbuf__gdip_image_save_JPEG_to_callback (GdkPixbufSaveFunc save_func,
+ gpointer user_data,
+ GdkPixbuf *pixbuf,
+ gchar **keys,
+ gchar **values,
+ GError **error)
+{
+ EncoderParameters encoder_params;
+ LONG quality = 75; /* default; must be between 0 and 100 */
+
+ 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."),
+ (int)quality);
+
+ return FALSE;
+ }
+ } else {
+ g_warning ("Unrecognized parameter (%s) passed to JPEG saver.", *kiter);
+ }
+
+ ++kiter;
+ ++viter;
+ }
+ }
+
+ encoder_params.Count = 1;
+ encoder_params.Parameter[0].Guid = EncoderQuality;
+ encoder_params.Parameter[0].Type = EncoderParameterValueTypeLong;
+ encoder_params.Parameter[0].NumberOfValues = 1;
+ encoder_params.Parameter[0].Value = &quality;
+
+ return gdip_save_pixbuf (pixbuf, L"image/jpeg", &encoder_params, save_func, user_data, error);
+}
+
+static gboolean
+gdk_pixbuf__gdip_image_save_JPEG (FILE *f,
+ GdkPixbuf *pixbuf,
+ gchar **keys,
+ gchar **values,
+ GError **error)
+{
+ return gdk_pixbuf__gdip_image_save_JPEG_to_callback (gdip_save_to_file_callback, f, pixbuf, keys, values, error);
+}
+
+#ifndef INCLUDE_gdiplus
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
+#else
+#define MODULE_ENTRY(function) void _gdk_pixbuf__gdip_jpeg_ ## function
+#endif
+
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
+{
+ gdip_fill_vtable (module);
+
+ module->save_to_callback = gdk_pixbuf__gdip_image_save_JPEG_to_callback;
+ module->save = gdk_pixbuf__gdip_image_save_JPEG; /* for gtk < 2.14, you need to implement both. otherwise gdk-pixbuf-queryloaders fails */
+}
+
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
+{
+ static GdkPixbufModulePattern signature[] = {
+ { "\xff\xd8", NULL, 100 }, /* JPEG */
+ { 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 = _("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-gdip-native.h b/gdk-pixbuf/io-gdip-native.h
new file mode 100644
index 0000000000..f5787ea835
--- /dev/null
+++ b/gdk-pixbuf/io-gdip-native.h
@@ -0,0 +1,235 @@
+/* -*- 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;
+
+#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
+
+typedef GpStatus (WINGDIPAPI* GdiplusStartupFunc) (gpointer, const gpointer, gpointer);
+typedef GpStatus (WINGDIPAPI* GdipCreateBitmapFromStreamFunc) (gpointer, GpBitmap**);
+typedef GpStatus (WINGDIPAPI* GdipBitmapGetPixelFunc) (GpBitmap*, gint x, gint y, ARGB*);
+typedef GpStatus (WINGDIPAPI* GdipGetImageWidthFunc) (GpImage*, guint*);
+typedef GpStatus (WINGDIPAPI* GdipGetImageHeightFunc) (GpImage*, guint*);
+typedef GpStatus (WINGDIPAPI* GdipDisposeImageFunc) (GpImage*);
+typedef GpStatus (WINGDIPAPI* GdipGetImageFlagsFunc) (GpImage *, guint*);
+typedef GpStatus (WINGDIPAPI* GdipImageGetFrameCountFunc) (GpImage *image, const GUID* dimensionID, UINT* count);
+typedef GpStatus (WINGDIPAPI* GdipImageSelectActiveFrameFunc) (GpImage *image, const GUID* dimensionID, UINT frameIndex);
+typedef GpStatus (WINGDIPAPI* GdipGetPropertyItemSizeFunc) (GpImage *image, int propId, guint* size);
+typedef GpStatus (WINGDIPAPI* GdipGetPropertyItemFunc) (GpImage *image, int propId, guint propSize, PropertyItem* buffer);
+typedef GpStatus (WINGDIPAPI* GdipGetPropertyCountFunc) (GpImage *image, guint* numOfProperty);
+typedef GpStatus (WINGDIPAPI* GdipGetPropertyIdListFunc) (GpImage *image, guint numOfProperty, PROPID* list);
+typedef GpStatus (WINGDIPAPI* GdipCreateBitmapFromScan0Func) (INT width, INT height, INT stride, PixelFormat format, BYTE* scan0,
+ GpBitmap** bitmap);
+typedef GpStatus (WINGDIPAPI* GdipSaveImageToStreamFunc) (GpImage *image, IStream* stream, const CLSID* clsidEncoder,
+ const EncoderParameters* encoderParams);
+
+typedef GpStatus (WINGDIPAPI* GdipGetImageEncodersFunc) (UINT numEncoders, UINT size, ImageCodecInfo *encoders);
+typedef GpStatus (WINGDIPAPI* GdipGetImageEncodersSizeFunc) (UINT *numEncoders, UINT *size);
+typedef GpStatus (WINGDIPAPI* GdipBitmapSetPixelFunc) (GpBitmap* bitmap, INT x, INT y, ARGB color);
+
+typedef GpStatus (WINGDIPAPI* GdipDrawImageIFunc) (GpGraphics *graphics, GpImage *image, INT x, INT y);
+typedef GpStatus (WINGDIPAPI* GdipGetImageGraphicsContextFunc) (GpImage *image, GpGraphics **graphics);
+typedef GpStatus (WINGDIPAPI* GdipFlushFunc) (GpGraphics *graphics, INT intention);
+typedef GpStatus (WINGDIPAPI* GdipGraphicsClearFunc) (GpGraphics *graphics, ARGB color);
+typedef GpStatus (WINGDIPAPI* GdipBitmapSetResolutionFunc) (GpBitmap* bitmap, float xdpi, float ydpi);
+typedef GpStatus (WINGDIPAPI* GdipGetImageHorizontalResolutionFunc) (GpImage *image, float *resolution);
+typedef GpStatus (WINGDIPAPI* GdipGetImageVerticalResolutionFunc) (GpImage *image, float *resolution);
+typedef GpStatus (WINGDIPAPI* GdipLoadImageFromStreamFunc) (IStream* stream, GpImage **image);
+typedef GpStatus (WINGDIPAPI* GdipDeleteGraphicsFunc) (GpGraphics *graphics);
+
+#endif
diff --git a/gdk-pixbuf/io-gdip-png.c b/gdk-pixbuf/io-gdip-png.c
new file mode 100644
index 0000000000..8b094bfca4
--- /dev/null
+++ b/gdk-pixbuf/io-gdip-png.c
@@ -0,0 +1,138 @@
+/* -*- 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 "io-gdip-utils.h"
+
+DEFINE_GUID(EncoderCompression, 0xe09d739d,0xccd4,0x44ee,0x8e,0xba,0x3f,0xbf,0x8b,0xe4,0xfc,0x58);
+
+static gboolean
+gdk_pixbuf__gdip_image_save_PNG_to_callback (GdkPixbufSaveFunc save_func,
+ gpointer user_data,
+ GdkPixbuf *pixbuf,
+ gchar **keys,
+ gchar **values,
+ GError **error)
+{
+ EncoderParameters encoder_params;
+ LONG compression = 5;
+
+ if (keys && *keys) {
+ gchar **kiter = keys;
+ gchar **viter = values;
+
+ while (*kiter) {
+ if (strncmp (*kiter, "tEXt::", 6) == 0) {
+ /* TODO: support exif data and the like */
+ }
+ 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);
+ return FALSE;
+ }
+ 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."),
+ (int)compression);
+ return FALSE;
+ }
+ } else {
+ g_warning ("Unrecognized parameter (%s) passed to PNG saver.", *kiter);
+ }
+
+ ++kiter;
+ ++viter;
+ }
+ }
+
+ encoder_params.Count = 1;
+ encoder_params.Parameter[0].Guid = EncoderCompression;
+ encoder_params.Parameter[0].Type = EncoderParameterValueTypeLong;
+ encoder_params.Parameter[0].NumberOfValues = 1;
+ encoder_params.Parameter[0].Value = &compression;
+
+ return gdip_save_pixbuf (pixbuf, L"image/png", &encoder_params, save_func, user_data, error);
+}
+
+static gboolean
+gdk_pixbuf__gdip_image_save_PNG (FILE *f,
+ GdkPixbuf *pixbuf,
+ gchar **keys,
+ gchar **values,
+ GError **error)
+{
+ return gdk_pixbuf__gdip_image_save_PNG_to_callback (gdip_save_to_file_callback, f, pixbuf, keys, values, error);
+}
+
+#ifndef INCLUDE_gdip_png
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
+#else
+#define MODULE_ENTRY(function) void _gdk_pixbuf__gdip_png_ ## function
+#endif
+
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
+{
+ gdip_fill_vtable (module);
+
+ module->save_to_callback = gdk_pixbuf__gdip_image_save_PNG_to_callback;
+ module->save = gdk_pixbuf__gdip_image_save_PNG; /* for gtk < 2.14, you need to implement both. otherwise gdk-pixbuf-queryloaders fails */
+}
+
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
+{
+ static GdkPixbufModulePattern signature[] = {
+ { "\x89PNG\r\n\x1a\x0a", NULL, 100 }, /* PNG */
+ { NULL, NULL, 0 }
+ };
+
+ static gchar *mime_types[] = {
+ "image/png",
+ NULL
+ };
+
+ static gchar *extensions[] = {
+ "png",
+ NULL
+ };
+
+ info->name = "png";
+ info->signature = signature;
+ info->description = _("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-gdip-propertytags.h b/gdk-pixbuf/io-gdip-propertytags.h
new file mode 100644
index 0000000000..95243bfe1a
--- /dev/null
+++ b/gdk-pixbuf/io-gdip-propertytags.h
@@ -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
index 0000000000..7e0a1898ea
--- /dev/null
+++ b/gdk-pixbuf/io-gdip-tiff.c
@@ -0,0 +1,87 @@
+/* -*- 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"
+
+static gboolean
+gdk_pixbuf__gdip_image_save_TIFF_to_callback (GdkPixbufSaveFunc save_func,
+ gpointer user_data,
+ GdkPixbuf *pixbuf,
+ gchar **keys,
+ gchar **values,
+ GError **error)
+{
+ return gdip_save_pixbuf (pixbuf, L"image/tiff", NULL, save_func, user_data, error);
+}
+
+static gboolean
+gdk_pixbuf__gdip_image_save_TIFF (FILE *f,
+ GdkPixbuf *pixbuf,
+ gchar **keys,
+ gchar **values,
+ GError **error)
+{
+ return gdk_pixbuf__gdip_image_save_TIFF_to_callback (gdip_save_to_file_callback, f, pixbuf, keys, values, error);
+}
+
+#ifndef INCLUDE_gdiplus
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
+#else
+#define MODULE_ENTRY(function) void _gdk_pixbuf__gdip_tiff_ ## function
+#endif
+
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
+{
+ gdip_fill_vtable (module);
+
+ module->save_to_callback = gdk_pixbuf__gdip_image_save_TIFF_to_callback;
+ module->save = gdk_pixbuf__gdip_image_save_TIFF; /* for gtk < 2.14, you need to implement both. otherwise gdk-pixbuf-queryloaders fails */
+}
+
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
+{
+ static GdkPixbufModulePattern signature[] = {
+ { "MM \x2a", " z ", 100 }, /* TIFF */
+ { "II\x2a ", " z", 100 }, /* TIFF */
+ { NULL, NULL, 0 }
+ };
+
+ static gchar *mime_types[] = {
+ "image/tiff",
+ NULL
+ };
+
+ static gchar *extensions[] = {
+ "tiff",
+ "tif",
+ NULL
+ };
+
+ info->name = "tiff";
+ info->signature = signature;
+ info->description = "The TIFF 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-utils.c b/gdk-pixbuf/io-gdip-utils.c
new file mode 100644
index 0000000000..392c3bfc6a
--- /dev/null
+++ b/gdk-pixbuf/io-gdip-utils.c
@@ -0,0 +1,996 @@
+/* -*- 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
+
+static GdiplusStartupFunc GdiplusStartup;
+static GdipCreateBitmapFromStreamFunc GdipCreateBitmapFromStream;
+static GdipBitmapGetPixelFunc GdipBitmapGetPixel;
+static GdipGetImageHeightFunc GdipGetImageHeight;
+static GdipDisposeImageFunc GdipDisposeImage;
+static GdipGetImageFlagsFunc GdipGetImageFlags;
+static GdipGetImageWidthFunc GdipGetImageWidth;
+static GdipImageGetFrameCountFunc GdipImageGetFrameCount;
+static GdipImageSelectActiveFrameFunc GdipImageSelectActiveFrame;
+static GdipGetPropertyItemSizeFunc GdipGetPropertyItemSize;
+static GdipGetPropertyItemFunc GdipGetPropertyItem;
+static GdipGetPropertyCountFunc GdipGetPropertyCount;
+static GdipGetPropertyIdListFunc GdipGetPropertyIdList;
+static GdipCreateBitmapFromScan0Func GdipCreateBitmapFromScan0;
+static GdipSaveImageToStreamFunc GdipSaveImageToStream;
+static GdipBitmapSetPixelFunc GdipBitmapSetPixel;
+static GdipDrawImageIFunc GdipDrawImageI;
+static GdipGetImageGraphicsContextFunc GdipGetImageGraphicsContext;
+static GdipFlushFunc GdipFlush;
+static GdipGraphicsClearFunc GdipGraphicsClear;
+static GdipBitmapSetResolutionFunc GdipBitmapSetResolution;
+static GdipGetImageHorizontalResolutionFunc GdipGetImageHorizontalResolution;
+static GdipGetImageVerticalResolutionFunc GdipGetImageVerticalResolution;
+static GdipLoadImageFromStreamFunc GdipLoadImageFromStream;
+static GdipDeleteGraphicsFunc GdipDeleteGraphics;
+static GdipGetImageEncodersFunc GdipGetImageEncoders;
+static GdipGetImageEncodersSizeFunc GdipGetImageEncodersSize;
+
+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 (error, GDK_PIXBUF_ERROR, code, msg);
+}
+
+static gboolean
+gdip_init (void)
+{
+ GdiplusStartupInput input;
+ ULONG_PTR gdiplusToken = 0;
+ static HINSTANCE gdipluslib = NULL;
+
+ if (!gdipluslib)
+ gdipluslib = LoadLibrary ("gdiplus.dll");
+ else
+ return TRUE; /* gdip_init() is idempotent */
+
+ if (!gdipluslib)
+ return FALSE;
+
+#define LOOKUP(func) \
+ G_STMT_START { \
+ func = (func##Func) GetProcAddress (gdipluslib, #func); \
+ if (!func) {\
+ g_warning ("Couldn't find GDI+ function %s\n", #func); \
+ return FALSE; \
+ } \
+ } G_STMT_END
+
+ LOOKUP (GdiplusStartup);
+ LOOKUP (GdipCreateBitmapFromStream);
+ LOOKUP (GdipBitmapGetPixel);
+ LOOKUP (GdipGetImageHeight);
+ LOOKUP (GdipDisposeImage);
+ LOOKUP (GdipGetImageFlags);
+ LOOKUP (GdipGetImageWidth);
+ LOOKUP (GdipImageGetFrameCount);
+ LOOKUP (GdipImageSelectActiveFrame);
+ LOOKUP (GdipGetPropertyItemSize);
+ LOOKUP (GdipGetPropertyItem);
+ LOOKUP (GdipGetPropertyCount);
+ LOOKUP (GdipGetPropertyIdList);
+ LOOKUP (GdipCreateBitmapFromScan0);
+ LOOKUP (GdipSaveImageToStream);
+ LOOKUP (GdipBitmapSetPixel);
+ LOOKUP (GdipDrawImageI);
+ LOOKUP (GdipGetImageGraphicsContext);
+ LOOKUP (GdipFlush);
+ LOOKUP (GdipGraphicsClear);
+ LOOKUP (GdipBitmapSetResolution);
+ LOOKUP (GdipGetImageHorizontalResolution);
+ LOOKUP (GdipGetImageVerticalResolution);
+ LOOKUP (GdipLoadImageFromStream);
+ LOOKUP (GdipDeleteGraphics);
+ LOOKUP (GdipGetImageEncoders);
+ LOOKUP (GdipGetImageEncodersSize);
+
+#undef LOOKUP
+
+ 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 (const gchar *buffer, size_t size, GError **error)
+{
+ HRESULT hr;
+ HGLOBAL hg = NULL;
+ GpBitmap *bitmap = NULL;
+ IStream *stream = NULL;
+ GpStatus status;
+
+ hg = gdip_buffer_to_hglobal (buffer, size, 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;
+ }
+
+ status = GdipCreateBitmapFromStream (stream, &bitmap);
+
+ if (Ok != status)
+ gdip_set_error_from_gpstatus (error, GDK_PIXBUF_ERROR_FAILED, status);
+
+ IStream_Release (stream);
+ GlobalFree (hg);
+
+ return bitmap;
+}
+
+static GpImage *
+gdip_buffer_to_image (const gchar *buffer, size_t size, GError **error)
+{
+ HRESULT hr;
+ HGLOBAL hg = NULL;
+ GpImage *image = NULL;
+ IStream *stream = NULL;
+ GpStatus status;
+
+ hg = gdip_buffer_to_hglobal (buffer, size, 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;
+ }
+
+ status = GdipLoadImageFromStream (stream, &image);
+
+ if (Ok != status)
+ gdip_set_error_from_gpstatus (error, GDK_PIXBUF_ERROR_FAILED, status);
+
+ IStream_Release (stream);
+ GlobalFree (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 *delay)
+{
+ guint item_size;
+ 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)) {
+ /* PropertyTagFrameDelay. Time delay, in hundredths of a second, between two frames in an animated GIF image. */
+ *delay = *((long *)item->value);
+ 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;
+}
+
+/*************************************************************************/
+/*************************************************************************/
+
+struct _GdipContext {
+ GdkPixbufModuleUpdatedFunc updated_func;
+ GdkPixbufModulePreparedFunc prepared_func;
+ GdkPixbufModuleSizeFunc size_func;
+
+ gpointer user_data;
+
+ GByteArray *buffer;
+};
+typedef struct _GdipContext GdipContext;
+
+static void
+destroy_gdipcontext (GdipContext *context)
+{
+ if (context != NULL) {
+ 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)
+{
+ 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)
+ 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;
+ guchar *b = cursor + (y * rowstride + (x * n_channels));
+
+ if (Ok != GdipBitmapGetPixel (bitmap, x, y, &pixel)) {
+ 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);
+
+ if (!pixbuf) {
+ if (animation != NULL)
+ g_object_unref (G_OBJECT (animation));
+
+ destroy_gdipcontext (context);
+ g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't create pixbuf"));
+ 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, &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;
+ frame->elapsed = animation->total_time;
+
+ /* Some GIFs apparently have delay time of 0,
+ * that crashes everything so set it to "fast".
+ * Also, timeouts less than 20 or so just lock up
+ * the app or make the animation choppy, so fix them.
+ */
+ if (frame->delay_time < 20)
+ frame->delay_time = 20; /* 20 = "fast" */
+
+ 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));
+
+ destroy_gdipcontext (context);
+
+ return TRUE;
+}
+
+static gboolean
+gdk_pixbuf__gdip_image_stop_load (gpointer data, GError **error)
+{
+ GdipContext *context = (GdipContext *)data;
+ GpBitmap *bitmap = NULL;
+ GByteArray *image_buffer = context->buffer;
+
+ bitmap = gdip_buffer_to_bitmap ((gchar *)image_buffer->data, image_buffer->len, error);
+
+ if (!bitmap) {
+ destroy_gdipcontext (context);
+ g_set_error (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;
+ GByteArray *image_buffer = context->buffer;
+
+ GpImage *metafile;
+ GpGraphics *graphics;
+ GpBitmap *bitmap;
+ GpStatus status;
+ float metafile_xres, metafile_yres;
+ guint width, height;
+
+ metafile = gdip_buffer_to_image ((gchar *)image_buffer->data, image_buffer->len, error);
+ if (!metafile) {
+ destroy_gdipcontext (context);
+ g_set_error (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 (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 (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
index 0000000000..14681c1e26
--- /dev/null
+++ b/gdk-pixbuf/io-gdip-utils.h
@@ -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
index 0000000000..3c89d4a3d7
--- /dev/null
+++ b/gdk-pixbuf/io-gdip-wmf.c
@@ -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";
+}