summaryrefslogtreecommitdiff
path: root/gdk-pixbuf
diff options
context:
space:
mode:
authorMatthias Clasen <matthiasc@src.gnome.org>2008-01-16 02:24:47 +0000
committerMatthias Clasen <matthiasc@src.gnome.org>2008-01-16 02:24:47 +0000
commit65cdbb25a80ace47ca1108f0caea9c5cc4e34849 (patch)
tree2705535d0f34d13109c3f71876c1234d45c10205 /gdk-pixbuf
parent8243e3d4152193addb53c2b9cffc1b48e144efc8 (diff)
downloadgdk-pixbuf-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/ChangeLog8
-rw-r--r--gdk-pixbuf/gdk-pixbuf-core.h19
-rw-r--r--gdk-pixbuf/gdk-pixbuf-io.c360
-rw-r--r--gdk-pixbuf/gdk-pixbuf.symbols3
4 files changed, 329 insertions, 61 deletions
diff --git a/gdk-pixbuf/ChangeLog b/gdk-pixbuf/ChangeLog
index 560eeff38..620a8bf84 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 4ae589526..04f89b000 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 1dbbd26cf..61b7991db 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, &amp;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 fa9e906d7..37b6a9b8b 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