diff options
author | Matthias Clasen <matthiasc@src.gnome.org> | 2008-01-16 02:24:47 +0000 |
---|---|---|
committer | Matthias Clasen <matthiasc@src.gnome.org> | 2008-01-16 02:24:47 +0000 |
commit | 65cdbb25a80ace47ca1108f0caea9c5cc4e34849 (patch) | |
tree | 2705535d0f34d13109c3f71876c1234d45c10205 /gdk-pixbuf | |
parent | 8243e3d4152193addb53c2b9cffc1b48e144efc8 (diff) | |
download | gtk+-65cdbb25a80ace47ca1108f0caea9c5cc4e34849.tar.gz |
Add stream i/o functions for gdk-pixbuf
svn path=/trunk/; revision=19373
Diffstat (limited to 'gdk-pixbuf')
-rw-r--r-- | gdk-pixbuf/ChangeLog | 8 | ||||
-rw-r--r-- | gdk-pixbuf/gdk-pixbuf-core.h | 19 | ||||
-rw-r--r-- | gdk-pixbuf/gdk-pixbuf-io.c | 360 | ||||
-rw-r--r-- | gdk-pixbuf/gdk-pixbuf.symbols | 3 |
4 files changed, 329 insertions, 61 deletions
diff --git a/gdk-pixbuf/ChangeLog b/gdk-pixbuf/ChangeLog index 560eeff38c..620a8bf845 100644 --- a/gdk-pixbuf/ChangeLog +++ b/gdk-pixbuf/ChangeLog @@ -1,3 +1,11 @@ +2008-01-15 Matthias Clasen <mclasne@redhat.com> + + * gdk-pixbuf.symbols: + * gdk-pixbuf-core.h: + * gdk-pixbuf-io.c (gdk_pixbuf_new_from_stream): + (gdk_pixbuf_new_from_stream_at_scale): + (gdk_pixbuf_save_to_stream): New stream i/o functions. + 2008-01-14 Michael Natterer <mitch@imendio.com> * gdk-pixbuf-loader.c (gdk_pixbuf_loader_prepare): cast the return diff --git a/gdk-pixbuf/gdk-pixbuf-core.h b/gdk-pixbuf/gdk-pixbuf-core.h index 4ae589526b..04f89b0008 100644 --- a/gdk-pixbuf/gdk-pixbuf-core.h +++ b/gdk-pixbuf/gdk-pixbuf-core.h @@ -28,6 +28,7 @@ #include <glib.h> #include <glib-object.h> +#include <gio/gio.h> G_BEGIN_DECLS @@ -214,6 +215,24 @@ gboolean gdk_pixbuf_save_to_bufferv (GdkPixbuf *pixbuf, char **option_values, GError **error); +GdkPixbuf *gdk_pixbuf_new_from_stream (GInputStream *stream, + GCancellable *cancellable, + GError **error); + +GdkPixbuf *gdk_pixbuf_new_from_stream_at_scale (GInputStream *stream, + gint width, + gint height, + gboolean preserve_aspect_ratio, + GCancellable *cancellable, + GError **error); + +gboolean gdk_pixbuf_save_to_stream (GdkPixbuf *pixbuf, + GOutputStream *stream, + const char *type, + GCancellable *cancellable, + GError **error, + ...); + /* Adding an alpha channel */ GdkPixbuf *gdk_pixbuf_add_alpha (const GdkPixbuf *pixbuf, gboolean substitute_color, guchar r, guchar g, guchar b); diff --git a/gdk-pixbuf/gdk-pixbuf-io.c b/gdk-pixbuf/gdk-pixbuf-io.c index 1dbbd26cf9..61b7991db7 100644 --- a/gdk-pixbuf/gdk-pixbuf-io.c +++ b/gdk-pixbuf/gdk-pixbuf-io.c @@ -27,14 +27,17 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> -#include <glib.h> #include <errno.h> #ifdef HAVE_UNISTD_H #include <unistd.h> #endif +#include <glib.h> +#include <gio/gio.h> + #include "gdk-pixbuf-private.h" #include "gdk-pixbuf-io.h" +#include "gdk-pixbuf-loader.h" #include "gdk-pixbuf-alias.h" #include <glib/gstdio.h> @@ -45,6 +48,9 @@ #undef STRICT #endif +#define SNIFF_BUFFER_SIZE 4096 +#define LOAD_BUFFER_SIZE 65536 + static gint format_check (GdkPixbufModule *module, guchar *buffer, int size) { @@ -755,7 +761,7 @@ _gdk_pixbuf_generic_image_load (GdkPixbufModule *module, FILE *f, GError **error) { - guchar buffer[4096]; + guchar buffer[LOAD_BUFFER_SIZE]; size_t length; GdkPixbuf *pixbuf = NULL; GdkPixbufAnimation *animation = NULL; @@ -829,7 +835,7 @@ gdk_pixbuf_new_from_file (const char *filename, GdkPixbuf *pixbuf; int size; FILE *f; - guchar buffer[1024]; + guchar buffer[SNIFF_BUFFER_SIZE]; GdkPixbufModule *image_module; gchar *display_name; @@ -934,49 +940,6 @@ gdk_pixbuf_new_from_file (const char *filename, } #endif -static void -size_prepared_cb (GdkPixbufLoader *loader, - int width, - int height, - gpointer data) -{ - struct { - gint width; - gint height; - gboolean preserve_aspect_ratio; - } *info = data; - - g_return_if_fail (width > 0 && height > 0); - - if (info->preserve_aspect_ratio && - (info->width > 0 || info->height > 0)) { - if (info->width < 0) - { - width = width * (double)info->height/(double)height; - height = info->height; - } - else if (info->height < 0) - { - height = height * (double)info->width/(double)width; - width = info->width; - } - else if ((double)height * (double)info->width > - (double)width * (double)info->height) { - width = 0.5 + (double)width * (double)info->height / (double)height; - height = info->height; - } else { - height = 0.5 + (double)height * (double)info->width / (double)width; - width = info->width; - } - } else { - if (info->width > 0) - width = info->width; - if (info->height > 0) - height = info->height; - } - - gdk_pixbuf_loader_set_size (loader, width, height); -} /** * gdk_pixbuf_new_from_file_at_size: @@ -1037,6 +1000,52 @@ gdk_pixbuf_new_from_file_at_size (const char *filename, } #endif +typedef struct { + gint width; + gint height; + gboolean preserve_aspect_ratio; +} AtScaleData; + +static void +at_scale_size_prepared_cb (GdkPixbufLoader *loader, + int width, + int height, + gpointer data) +{ + AtScaleData *info = data; + + g_return_if_fail (width > 0 && height > 0); + + if (info->preserve_aspect_ratio && + (info->width > 0 || info->height > 0)) { + if (info->width < 0) + { + width = width * (double)info->height/(double)height; + height = info->height; + } + else if (info->height < 0) + { + height = height * (double)info->width/(double)width; + width = info->width; + } + else if ((double)height * (double)info->width > + (double)width * (double)info->height) { + width = 0.5 + (double)width * (double)info->height / (double)height; + height = info->height; + } else { + height = 0.5 + (double)height * (double)info->width / (double)width; + width = info->width; + } + } else { + if (info->width > 0) + width = info->width; + if (info->height > 0) + height = info->height; + } + + gdk_pixbuf_loader_set_size (loader, width, height); +} + /** * gdk_pixbuf_new_from_file_at_scale: * @filename: Name of file to load, in the GLib file name encoding @@ -1075,15 +1084,10 @@ gdk_pixbuf_new_from_file_at_scale (const char *filename, GdkPixbufLoader *loader; GdkPixbuf *pixbuf; - - guchar buffer [4096]; + guchar buffer[LOAD_BUFFER_SIZE]; int length; FILE *f; - struct { - gint width; - gint height; - gboolean preserve_aspect_ratio; - } info; + AtScaleData info; GdkPixbufAnimation *animation; GdkPixbufAnimationIter *iter; gboolean has_frame; @@ -1112,7 +1116,8 @@ gdk_pixbuf_new_from_file_at_scale (const char *filename, info.height = height; info.preserve_aspect_ratio = preserve_aspect_ratio; - g_signal_connect (loader, "size-prepared", G_CALLBACK (size_prepared_cb), &info); + g_signal_connect (loader, "size-prepared", + G_CALLBACK (at_scale_size_prepared_cb), &info); has_frame = FALSE; while (!has_frame && !feof (f) && !ferror (f)) { @@ -1193,6 +1198,157 @@ gdk_pixbuf_new_from_file_at_scale (const char *filename, #endif +static GdkPixbuf * +load_from_stream (GdkPixbufLoader *loader, + GInputStream *stream, + GCancellable *cancellable, + GError **error) +{ + GdkPixbuf *pixbuf; + gssize n_read; + guchar buffer[LOAD_BUFFER_SIZE]; + gboolean res; + + res = TRUE; + while (1) { + n_read = g_input_stream_read (stream, + buffer, + sizeof (buffer), + cancellable, + error); + if (n_read < 0) { + res = FALSE; + error = NULL; /* Ignore further errors */ + break; + } + + if (n_read == 0) + break; + + if (!gdk_pixbuf_loader_write (loader, + buffer, + n_read, + error)) { + res = FALSE; + error = NULL; + break; + } + } + + if (!gdk_pixbuf_loader_close (loader, error)) { + res = FALSE; + error = NULL; + } + + pixbuf = NULL; + if (res) { + pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); + if (pixbuf) + g_object_ref (pixbuf); + } + + return pixbuf; +} + + +/** + * gdk_pixbuf_new_from_stream_at_scale: + * @stream: a #GInputStream to load the pixbuf from + * @width: The width the image should have or -1 to not constrain the width + * @height: The height the image should have or -1 to not constrain the height + * @preserve_aspect_ratio: %TRUE to preserve the image's aspect ratio + * @cancellable: optional #GCancellable object, %NULL to ignore + * @error: Return location for an error + * + * Creates a new pixbuf by loading an image from an input stream. + * + * The file format is detected automatically. If %NULL is returned, then + * @error will be set. The @cancellable can be used to abort the operation + * from another thread. If the operation was cancelled, the error + * %GIO_ERROR_CANCELLED will be returned. Other possible errors are in + * the #GDK_PIXBUF_ERROR and %G_IO_ERROR domains. + * + * The image will be scaled to fit in the requested size, optionally + * preserving the image's aspect ratio. When preserving the aspect ratio, + * a @width of -1 will cause the image to be scaled to the exact given + * height, and a @height of -1 will cause the image to be scaled to the + * exact given width. When not preserving aspect ratio, a @width or + * @height of -1 means to not scale the image at all in that dimension. + * + * The stream is not closed. + * + * Return value: A newly-created pixbuf, or %NULL if any of several error + * conditions occurred: the file could not be opened, the image format is + * not supported, there was not enough memory to allocate the image buffer, + * the stream contained invalid data, or the operation was cancelled. + * + * Since: 2.16 + */ +GdkPixbuf * +gdk_pixbuf_new_from_stream_at_scale (GInputStream *stream, + gint width, + gint height, + gboolean preserve_aspect_ratio, + GCancellable *cancellable, + GError **error) +{ + GdkPixbufLoader *loader; + GdkPixbuf *pixbuf; + AtScaleData info; + + loader = gdk_pixbuf_loader_new (); + + info.width = width; + info.height = height; + info.preserve_aspect_ratio = preserve_aspect_ratio; + + g_signal_connect (loader, "size-prepared", + G_CALLBACK (at_scale_size_prepared_cb), &info); + + pixbuf = load_from_stream (loader, stream, cancellable, error); + g_object_unref (loader); + + return pixbuf; +} + +/** + * gdk_pixbuf_new_from_stream: + * @stream: a #GInputStream to load the pixbuf from + * @cancellable: optional #GCancellable object, %NULL to ignore + * @error: Return location for an error + * + * Creates a new pixbuf by loading an image from an input stream. + * + * The file format is detected automatically. If %NULL is returned, then + * @error will be set. The @cancellable can be used to abort the operation + * from another thread. If the operation was cancelled, the error + * %GIO_ERROR_CANCELLED will be returned. Other possible errors are in + * the #GDK_PIXBUF_ERROR and %G_IO_ERROR domains. + * + * The stream is not closed. + * + * Return value: A newly-created pixbuf, or %NULL if any of several error + * conditions occurred: the file could not be opened, the image format is + * not supported, there was not enough memory to allocate the image buffer, + * the stream contained invalid data, or the operation was cancelled. + * + * Since: 2.16 + **/ +GdkPixbuf * +gdk_pixbuf_new_from_stream (GInputStream *stream, + GCancellable *cancellable, + GError **error) +{ + GdkPixbuf *pixbuf; + GdkPixbufLoader *loader; + + loader = gdk_pixbuf_loader_new (); + pixbuf = load_from_stream (loader, stream, cancellable, error); + g_object_unref (loader); + + return pixbuf; +} + static void info_cb (GdkPixbufLoader *loader, int width, @@ -1234,7 +1390,7 @@ gdk_pixbuf_get_file_info (const gchar *filename, gint *height) { GdkPixbufLoader *loader; - guchar buffer [4096]; + guchar buffer[SNIFF_BUFFER_SIZE]; int length; FILE *f; struct { @@ -1579,18 +1735,18 @@ gdk_pixbuf_real_save_to_callback (GdkPixbuf *pixbuf, * installed. The list of all writable formats can be determined in the * following way: * - * <informalexample><programlisting> + * |[ * void add_if_writable (GdkPixbufFormat *data, GSList **list) * { * if (gdk_pixbuf_format_is_writable (data)) * *list = g_slist_prepend (*list, data); * } - * <!-- --> - * GSList *formats = gdk_pixbuf_get_formats (<!-- -->); + * + * GSList *formats = gdk_pixbuf_get_formats (); * GSList *writable_formats = NULL; - * g_slist_foreach (formats, add_if_writable, &writable_formats); + * g_slist_foreach (formats, add_if_writable, &writable_formats); * g_slist_free (formats); - * </programlisting></informalexample> + * ]| * * If @error is set, %FALSE will be returned. Possible errors include * those in the #GDK_PIXBUF_ERROR domain and those in the #G_FILE_ERROR domain. @@ -1999,7 +2155,8 @@ save_to_buffer_callback (const gchar *data, * @error: return location for error, or %NULL * * Saves pixbuf to a new buffer in format @type, which is currently "jpeg", - * "tiff", "png", "ico" or "bmp". See gdk_pixbuf_save_to_buffer() for more details. + * "tiff", "png", "ico" or "bmp". See gdk_pixbuf_save_to_buffer() + * for more details. * * Return value: whether an error was set * @@ -2044,6 +2201,87 @@ gdk_pixbuf_save_to_bufferv (GdkPixbuf *pixbuf, return TRUE; } +typedef struct { + GOutputStream *stream; + GCancellable *cancellable; +} SaveToStreamData; + +static gboolean +save_to_stream (const gchar *buffer, + gsize count, + GCancellable *cancellable, + GError **error, + gpointer data) +{ + SaveToStreamData *sdata = (SaveToStreamData *)data; + + g_output_stream_write (sdata->stream, + buffer, count, + sdata->cancellable, + error); +} + +/** + * gdk_pixbuf_save_to_stream: + * @pixbuf: a #GdkPixbuf + * @stream: a #GOutputStream to save the pixbuf to + * @type: name of file format + * @cancellable: optional #GCancellable object, %NULL to ignore + * @error: return location for error, or %NULL + * @Varargs: list of key-value save options + * + * Saves @pixbuf to an output stream. + * + * Supported file formats are currently "jpeg", "tiff", "png", "ico" or + * "bmp". See gdk_pixbuf_save_to_buffer() for more details. + * + * The @cancellable can be used to abort the operation from another + * thread. If the operation was cancelled, the error %GIO_ERROR_CANCELLED + * will be returned. Other possible errors are in the #GDK_PIXBUF_ERROR + * and %G_IO_ERROR domains. + * + * The stream is not closed. + * + * Returns: %TRUE if the pixbuf was saved successfully, %FALSE if an + * error was set. + * + * Since: 2.16 + */ +gboolean +gdk_pixbuf_save_to_stream (GdkPixbuf *pixbuf, + GOutputStream *stream, + const char *type, + GCancellable *cancellable, + GError **error, + ...) +{ + gboolean res; + gchar **keys = NULL; + gchar **values = NULL; + va_list args; + SaveToStreamData data; + + va_start (args, error); + collect_save_options (args, &keys, &values); + va_end (args); + + data.stream = stream; + data.cancellable = cancellable; + + if (!gdk_pixbuf_save_to_callbackv (pixbuf, save_to_stream, + &data, type, + keys, values, + error)) { + error = NULL; /* Ignore further errors */ + res = FALSE; + } + + g_strfreev (keys); + g_strfreev (values); + + return res; +} + /** * gdk_pixbuf_format_get_name: * @format: a #GdkPixbufFormat diff --git a/gdk-pixbuf/gdk-pixbuf.symbols b/gdk-pixbuf/gdk-pixbuf.symbols index fa9e906d7d..37b6a9b8bd 100644 --- a/gdk-pixbuf/gdk-pixbuf.symbols +++ b/gdk-pixbuf/gdk-pixbuf.symbols @@ -56,6 +56,8 @@ gdk_pixbuf_new_from_file_at_scale PRIVATE gdk_pixbuf_new_from_file_at_scale_utf8 #endif gdk_pixbuf_new_from_xpm_data +gdk_pixbuf_new_from_stream +gdk_pixbuf_new_from_stream_at_scale gdk_pixbuf_save PRIVATE G_GNUC_NULL_TERMINATED #ifdef G_OS_WIN32 gdk_pixbuf_save_utf8 @@ -68,6 +70,7 @@ gdk_pixbuf_savev PRIVATE #ifdef G_OS_WIN32 gdk_pixbuf_savev_utf8 #endif +gdk_pixbuf_save_to_stream #endif #endif |