diff options
Diffstat (limited to 'gdk-pixbuf/gdk-pixbuf-io.c')
-rw-r--r-- | gdk-pixbuf/gdk-pixbuf-io.c | 223 |
1 files changed, 213 insertions, 10 deletions
diff --git a/gdk-pixbuf/gdk-pixbuf-io.c b/gdk-pixbuf/gdk-pixbuf-io.c index a063f4d41e..0e3ca13f53 100644 --- a/gdk-pixbuf/gdk-pixbuf-io.c +++ b/gdk-pixbuf/gdk-pixbuf-io.c @@ -24,6 +24,7 @@ #include <config.h> #include <string.h> #include <glib.h> +#include <errno.h> #include "gdk-pixbuf-private.h" #include "gdk-pixbuf-io.h" @@ -185,17 +186,17 @@ pixbuf_check_wbmp (guchar *buffer, int size) } static GdkPixbufModule file_formats [] = { - { "png", pixbuf_check_png, NULL, NULL, NULL, NULL, NULL, NULL }, - { "jpeg", pixbuf_check_jpeg, NULL, NULL, NULL, NULL, NULL, NULL }, - { "tiff", pixbuf_check_tiff, NULL, NULL, NULL, NULL, NULL, NULL }, - { "gif", pixbuf_check_gif, NULL, NULL, NULL, NULL, NULL, NULL }, + { "png", pixbuf_check_png, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }, + { "jpeg", pixbuf_check_jpeg, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, + { "tiff", pixbuf_check_tiff, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, + { "gif", pixbuf_check_gif, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, #define XPM_FILE_FORMAT_INDEX 4 - { "xpm", pixbuf_check_xpm, NULL, NULL, NULL, NULL, NULL, NULL }, - { "pnm", pixbuf_check_pnm, NULL, NULL, NULL, NULL, NULL, NULL }, - { "ras", pixbuf_check_sunras, NULL, NULL, NULL, NULL, NULL, NULL }, - { "ico", pixbuf_check_ico, NULL, NULL, NULL, NULL, NULL, NULL }, - { "bmp", pixbuf_check_bmp, NULL, NULL, NULL, NULL, NULL, NULL }, - { "wbmp", pixbuf_check_wbmp, NULL, NULL, NULL, NULL, NULL, NULL }, + { "xpm", pixbuf_check_xpm, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, + { "pnm", pixbuf_check_pnm, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, + { "ras", pixbuf_check_sunras, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, + { "ico", pixbuf_check_ico, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, + { "bmp", pixbuf_check_bmp, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, + { "wbmp", pixbuf_check_wbmp, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } }; @@ -281,6 +282,7 @@ gdk_pixbuf_load_module (GdkPixbufModule *image_module) char *path; GModule *module; gpointer load_sym; + gpointer save_sym; char *name; g_return_if_fail (image_module->module == NULL); @@ -333,6 +335,9 @@ gdk_pixbuf_load_module (GdkPixbufModule *image_module) if (pixbuf_module_symbol (module, name, "image_load_animation", &load_sym)) image_module->load_animation = load_sym; + + if (pixbuf_module_symbol (module, name, "image_save", &save_sym)) + image_module->save = save_sym; } #else @@ -354,6 +359,7 @@ m_load (png); m_begin_load (png); m_load_increment (png); m_stop_load (png); +m_save (png); /* BMP */ m_load (bmp); m_begin_load (bmp); @@ -380,6 +386,7 @@ m_load (jpeg); m_begin_load (jpeg); m_load_increment (jpeg); m_stop_load (jpeg); +m_save (jpeg); /* PNM */ m_load (pnm); m_begin_load (pnm); @@ -409,6 +416,7 @@ gdk_pixbuf_load_module (GdkPixbufModule *image_module) image_module->begin_load = mname (png,begin_load); image_module->load_increment = mname (png,load_increment); image_module->stop_load = mname (png,stop_load); + image_module->save = mname (png,save); return; } @@ -450,6 +458,7 @@ gdk_pixbuf_load_module (GdkPixbufModule *image_module) image_module->begin_load = mname (jpeg,begin_load); image_module->load_increment = mname (jpeg,load_increment); image_module->stop_load = mname (jpeg,stop_load); + image_module->save = mname (jpeg,save); return; } if (strcmp (image_module->module_name, "pnm") == 0){ @@ -596,3 +605,197 @@ gdk_pixbuf_new_from_xpm_data (const char **data) pixbuf = (* load_xpm_data) (data); return pixbuf; } + +static void +collect_save_options (va_list opts, + gchar ***keys, + gchar ***vals) +{ + gchar *key; + gchar *val; + gchar *next; + gint count; + + count = 0; + *keys = NULL; + *vals = NULL; + + next = va_arg (opts, gchar*); + while (next) + { + key = next; + val = va_arg (opts, gchar*); + + ++count; + + /* woo, slow */ + *keys = g_realloc (*keys, sizeof(gchar*) * (count + 1)); + *vals = g_realloc (*vals, sizeof(gchar*) * (count + 1)); + + (*keys)[count-1] = g_strdup (key); + (*vals)[count-1] = g_strdup (val); + + (*keys)[count] = NULL; + (*vals)[count] = NULL; + + next = va_arg (opts, gchar*); + } +} + +static gboolean +gdk_pixbuf_real_save (GdkPixbuf *pixbuf, + FILE *filehandle, + const char *format, + gchar **keys, + gchar **values, + GError **error) +{ + int i; + GdkPixbufModule *image_module = NULL; + + for (i = 0; file_formats[i].module_name; i++) { + if (!strcmp (file_formats[i].module_name, format)) { + image_module = &(file_formats[i]); + break; + } + } + + if (!image_module) { + g_warning ("gdk-pixbuf does not support the format: %s", format); + return FALSE; + } + + if (image_module->module == NULL) + gdk_pixbuf_load_module (image_module); + + g_return_val_if_fail (image_module->save != NULL, FALSE); + + + + return (* image_module->save) (filehandle, pixbuf, + keys, values, + error); +} + + +/** + * gdk_pixbuf_save: + * @pixbuf: pointer to GdkPixbuf. + * @filename: Name of file to save. + * @format: name of file format. + * @error: return location for error, or NULL + * @Varargs: list of key-value save options + * + * Saves pixbuf to a file in @format, which is currently "jpeg" or + * "png". If @error is set, FALSE will be returned. Possible errors include those + * from #GdkPixbufErrorType and those from #GFileErrorType. + * + * The variable argument list should be NULL-terminated; if not empty, + * it should contain pairs of strings that modify the save + * parameters. For example: + * + * <programlisting> + * gdk_pixbuf_save (pixbuf, handle, "jpeg", &error, + * "quality", "100", NULL); + * </programlisting> + * + * The only save parameter that currently exists is the "quality" field + * for JPEG images; its value should be in the range [0,100]. + * + * Return value: whether an error was set + **/ + +gboolean +gdk_pixbuf_save (GdkPixbuf *pixbuf, + const char *filename, + const char *format, + GError **error, + ...) +{ + gchar **keys = NULL; + gchar **values = NULL; + va_list args; + gboolean result; + + va_start (args, error); + + collect_save_options (args, &keys, &values); + + va_end (args); + + result = gdk_pixbuf_savev (pixbuf, filename, format, + keys, values, + error); + + g_strfreev (keys); + g_strfreev (values); + + return result; +} + +/** + * gdk_pixbuf_savev: + * @pixbuf: pointer to GdkPixbuf. + * @filename: Name of file to save. + * @format: name of file format. + * @option_keys: name of options to set, NULL-terminated + * @option_values: values for named options + * @error: return location for error, or NULL + * + * Saves pixbuf to a file in @format, which is currently "jpeg" or "png". + * If @error is set, FALSE will be returned. See gdk_pixbuf_save () for more + * details. Possible errors include those from #GdkPixbufErrorType and + * those from #GFileErrorType. + * + * Return value: whether an error was set + **/ + +gboolean +gdk_pixbuf_savev (GdkPixbuf *pixbuf, + const char *filename, + const char *format, + char **option_keys, + char **option_values, + GError **error) +{ + FILE *f = NULL; + gboolean result; + + + g_return_val_if_fail (filename != NULL, FALSE); + g_return_val_if_fail (format != NULL, FALSE); + + f = fopen (filename, "w"); + + if (f == NULL) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_IO, + _("Failed to open '%s' for writing: %s"), + filename, g_strerror (errno)); + return FALSE; + } + + + result = gdk_pixbuf_real_save (pixbuf, f, format, + option_keys, option_values, + error); + + + if (!result) { + g_return_val_if_fail (error == NULL || *error != NULL, FALSE); + fclose (f); + return FALSE; + } + + if (fclose (f) < 0) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_IO, + _("Failed to close '%s' while writing image, all data may not have been saved: %s"), + filename, g_strerror (errno)); + return FALSE; + } + + return TRUE; +} |