diff options
Diffstat (limited to 'pig/pig-pixbuf-loader.c')
-rw-r--r-- | pig/pig-pixbuf-loader.c | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/pig/pig-pixbuf-loader.c b/pig/pig-pixbuf-loader.c new file mode 100644 index 0000000..8514626 --- /dev/null +++ b/pig/pig-pixbuf-loader.c @@ -0,0 +1,237 @@ +/* Pig + * Copyright (C) 2011 Benjamin Otte <otte@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "pig-pixbuf-loader-private.h" + +#include <glib/gi18n.h> + +#include "pig-loader-private.h" +#include "pig-pixbuf-shared-private.h" + +struct _PigPixbufLoaderPrivate { + cairo_surface_t *surface; + + /* only valid while loading */ + GdkPixbufLoader *loader; +}; + +static char ** +pig_pixbuf_loader_get_mime_types (void) +{ + GPtrArray *mime_types; + GSList *formats, *walk; + + mime_types = g_ptr_array_new (); + formats = gdk_pixbuf_get_formats (); + + for (walk = formats; walk; walk = walk->next) + { + GdkPixbufFormat *format = walk->data; + char **format_types; + guint i; + + format_types = gdk_pixbuf_format_get_mime_types (format); + if (format_types == NULL) + continue; + + for (i = 0; format_types[i]; i++) + { + g_ptr_array_add (mime_types, format_types[i]); + } + + g_free (format_types); + } + + g_ptr_array_add (mime_types, NULL); + + g_slist_free (formats); + + return (char **) g_ptr_array_free (mime_types, FALSE); +} + +static void +pig_pixbuf_loader_finish_load (PigPixbufLoader *loader) +{ + PigPixbufLoaderPrivate *priv = loader->priv; + + g_object_unref (priv->loader); + priv->loader = NULL; +} + +static gboolean +pig_pixbuf_loader_write (PigLoader * loader, + const guchar *data, + gsize size, + GError ** error) +{ + PigPixbufLoader *pixbuf_loader = PIG_PIXBUF_LOADER (loader); + + if (!gdk_pixbuf_loader_write (pixbuf_loader->priv->loader, + data, + size, + error)) + { + pig_pixbuf_loader_finish_load (pixbuf_loader); + return FALSE; + } + + return TRUE; +} + +static gboolean +pig_pixbuf_loader_close (PigLoader * loader, + GError ** error) +{ + PigPixbufLoader *pixbuf_loader = PIG_PIXBUF_LOADER (loader); + gboolean result; + + result = gdk_pixbuf_loader_close (pixbuf_loader->priv->loader, + error); + + pig_pixbuf_loader_finish_load (pixbuf_loader); + + return result; +} + +static void +pig_pixbuf_loader_loader_init (PigLoaderInterface *iface) +{ + /* XXX: This will leak when the class is unreffed, omg! */ + iface->mime_types = (const char const **) pig_pixbuf_loader_get_mime_types (); + + iface->write = pig_pixbuf_loader_write; + iface->close = pig_pixbuf_loader_close; +} + +G_DEFINE_TYPE_WITH_CODE (PigPixbufLoader, _pig_pixbuf_loader, PIG_TYPE_PICTURE, + G_IMPLEMENT_INTERFACE (PIG_TYPE_LOADER, pig_pixbuf_loader_loader_init)) + +static void +pig_pixbuf_loader_dispose (GObject *object) +{ + PigPixbufLoader *loader = PIG_PIXBUF_LOADER (object); + PigPixbufLoaderPrivate *priv = loader->priv; + + if (priv->surface) + { + cairo_surface_destroy (priv->surface); + priv->surface = NULL; + } + if (priv->loader) + { + g_object_unref (priv->loader); + priv->loader = NULL; + } + + G_OBJECT_CLASS (_pig_pixbuf_loader_parent_class)->dispose (object); +} + +static cairo_surface_t * +pig_pixbuf_loader_ref_surface (PigPicture *picture) +{ + PigPixbufLoader *loader = PIG_PIXBUF_LOADER (picture); + PigPixbufLoaderPrivate *priv = loader->priv; + + if (priv->surface == NULL) + return cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + pig_picture_get_width (PIG_PICTURE (loader)), + pig_picture_get_height (PIG_PICTURE (loader))); + + return cairo_surface_reference (priv->surface); +} + +static void +_pig_pixbuf_loader_class_init (PigPixbufLoaderClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + PigPictureClass *picture_class = PIG_PICTURE_CLASS (klass); + + object_class->dispose = pig_pixbuf_loader_dispose; + + picture_class->ref_surface = pig_pixbuf_loader_ref_surface; + + g_type_class_add_private (klass, sizeof (PigPixbufLoaderPrivate)); +} + +static void +pig_pixbuf_loader_size_prepared (GdkPixbufLoader *loader, + int width, + int height, + PigPixbufLoader *picture) +{ + g_assert (picture->priv->surface == NULL); + + pig_picture_resized (PIG_PICTURE (picture), width, height); +} + +static void +pig_pixbuf_loader_area_updated (GdkPixbufLoader *loader, + int x, + int y, + int width, + int height, + PigPixbufLoader *picture) +{ + PigPixbufLoaderPrivate *priv = loader->priv; + + if (priv->surface == NULL) + { + priv->surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + pig_picture_get_width (PIG_PICTURE (loader)), + pig_picture_get_height (PIG_PICTURE (loader))); + } + + _pig_pixbuf_copy_to_surface (priv->surface, + gdk_pixbuf_loader_get_pixbuf (loader), + x, y, width, height); +} + +static GdkPixbufLoader * +pig_pixbuf_loader_create_loader (PigPixbufLoader *loader) +{ + GdkPixbufLoader *pixbuf_loader; + + pixbuf_loader = gdk_pixbuf_loader_new (); + g_signal_connect (pixbuf_loader, + "size-prepared", + G_CALLBACK (pig_pixbuf_loader_size_prepared), + loader); + g_signal_connect (pixbuf_loader, + "area-updated", + G_CALLBACK (pig_pixbuf_loader_area_updated), + loader); + + return pixbuf_loader; +} + +static void +_pig_pixbuf_loader_init (PigPixbufLoader *picture) +{ + PigPixbufLoaderPrivate *priv; + + picture->priv = G_TYPE_INSTANCE_GET_PRIVATE (picture, + PIG_TYPE_PIXBUF_LOADER, + PigPixbufLoaderPrivate); + priv = picture->priv; + + priv->loader = pig_pixbuf_loader_create_loader (picture); +} + |