Add stream i/o functions for gdk-pixbuf

svn path=/trunk/; revision=19373
This commit is contained in:
Matthias Clasen 2008-01-16 02:24:47 +00:00
parent 8243e3d415
commit 65cdbb25a8
8 changed files with 359 additions and 61 deletions

View File

@ -1,3 +1,10 @@
2008-01-14 Matthias Clasen <mclasen@redhat.com>
* gtk/gtk-docs.sgml:
* gdk-pixbuf/gdk-pixbuf.sgml: Add indices for 2.16
* gdk-pixbuf/gdk-pixbuf-sections.txt: Add stream i/o functions.
2008-01-10 Sven Neumann <sven@gimp.org>
* gtk/tmpl/gtkeditable.sgml: corrected documentation for
@ -8,6 +15,20 @@
* gtk/tmpl/gtkcalendar.sgml: Move documentation for
GtkCalendarDisplayOptions to gtk/gtkcalendar.c.
2007-12-27 Mathias Hasselmann <mathias@openismus.com>
* gtk/tmpl/gtkcalendar.sgml: Move documentation for
GtkCalendarDisplayOptions to gtk/gtkcalendar.c.
2007-12-27 Mathias Hasselmann <mathias@openismus.com>
* docs/reference/gtk/gtk-sections.txt: Add new GtkCalendar symbols.
2007-12-27 Mathias Hasselmann <mathias@openismus.com>
* gtk/tmpl/gtkcalendar.sgml: Move documentation for
GtkCalendarDisplayOptions to gtk/gtkcalendar.c.
2007-12-27 Mathias Hasselmann <mathias@openismus.com>
* reference/gtk/gtk-sections.txt: Add new GtkCalendar symbols.

View File

@ -65,6 +65,8 @@ gdk_pixbuf_new_from_file
gdk_pixbuf_new_from_file_at_size
gdk_pixbuf_new_from_file_at_scale
gdk_pixbuf_get_file_info
gdk_pixbuf_new_from_stream
gdk_pixbuf_new_from_stream_at_scale
</SECTION>
<SECTION>
@ -76,6 +78,7 @@ gdk_pixbuf_save_to_callback
gdk_pixbuf_save_to_callbackv
gdk_pixbuf_save_to_buffer
gdk_pixbuf_save_to_bufferv
gdk_pixbuf_save_to_stream
</SECTION>
<SECTION>

View File

@ -148,6 +148,9 @@
<index role="2.8">
<title>Index of new symbols in 2.8</title>
</index>
<index role="2.16">
<title>Index of new symbols in 2.16</title>
</index>
&Porting-From-Imlib;

View File

@ -686,4 +686,7 @@ that is, GUI components such as #GtkButton or #GtkTextView.
<index role="2.12">
<title>Index of new symbols in 2.12</title>
</index>
<index role="2.16">
<title>Index of new symbols in 2.16</title>
</index>
</book>

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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