diff options
Diffstat (limited to 'gdk-pixbuf/gdk-pixbuf-io.c')
-rw-r--r-- | gdk-pixbuf/gdk-pixbuf-io.c | 2678 |
1 files changed, 0 insertions, 2678 deletions
diff --git a/gdk-pixbuf/gdk-pixbuf-io.c b/gdk-pixbuf/gdk-pixbuf-io.c deleted file mode 100644 index bd6a78722c..0000000000 --- a/gdk-pixbuf/gdk-pixbuf-io.c +++ /dev/null @@ -1,2678 +0,0 @@ -/* -*- mode: C; c-file-style: "linux" -*- */ -/* GdkPixbuf library - Main loading interface. - * - * Copyright (C) 1999 The Free Software Foundation - * - * Authors: Miguel de Icaza <miguel@gnu.org> - * Federico Mena-Quintero <federico@gimp.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 <stdlib.h> -#include <stdio.h> -#include <string.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> - -#ifdef G_OS_WIN32 -#define STRICT -#include <windows.h> -#undef STRICT -#endif - -#define SNIFF_BUFFER_SIZE 4096 -#define LOAD_BUFFER_SIZE 65536 - -#ifndef GDK_PIXBUF_USE_GIO_MIME -static gint -format_check (GdkPixbufModule *module, guchar *buffer, int size) -{ - int i, j; - gchar m; - GdkPixbufModulePattern *pattern; - gboolean anchored; - guchar *prefix; - gchar *mask; - - for (pattern = module->info->signature; pattern->prefix; pattern++) { - if (pattern->mask && pattern->mask[0] == '*') { - prefix = (guchar *)pattern->prefix + 1; - mask = pattern->mask + 1; - anchored = FALSE; - } - else { - prefix = (guchar *)pattern->prefix; - mask = pattern->mask; - anchored = TRUE; - } - for (i = 0; i < size; i++) { - for (j = 0; i + j < size && prefix[j] != 0; j++) { - m = mask ? mask[j] : ' '; - if (m == ' ') { - if (buffer[i + j] != prefix[j]) - break; - } - else if (m == '!') { - if (buffer[i + j] == prefix[j]) - break; - } - else if (m == 'z') { - if (buffer[i + j] != 0) - break; - } - else if (m == 'n') { - if (buffer[i + j] == 0) - break; - } - } - - if (prefix[j] == 0) - return pattern->relevance; - - if (anchored) - break; - } - } - return 0; -} -#endif - -G_LOCK_DEFINE_STATIC (init_lock); -G_LOCK_DEFINE_STATIC (threadunsafe_loader_lock); - -gboolean -_gdk_pixbuf_lock (GdkPixbufModule *image_module) -{ - if (g_threads_got_initialized && - !(image_module->info->flags & GDK_PIXBUF_FORMAT_THREADSAFE)) { - G_LOCK (threadunsafe_loader_lock); - - return TRUE; - } - - return FALSE; -} - -void -_gdk_pixbuf_unlock (GdkPixbufModule *image_module) -{ - if (!(image_module->info->flags & GDK_PIXBUF_FORMAT_THREADSAFE)) { - G_UNLOCK (threadunsafe_loader_lock); - } -} - -static GSList *file_formats = NULL; - -static void gdk_pixbuf_io_init (void); - -static GSList * -get_file_formats (void) -{ - G_LOCK (init_lock); - if (file_formats == NULL) - gdk_pixbuf_io_init (); - G_UNLOCK (init_lock); - - return file_formats; -} - - -#ifdef USE_GMODULE - -static gboolean -scan_string (const char **pos, GString *out) -{ - const char *p = *pos, *q = *pos; - char *tmp, *tmp2; - gboolean quoted; - - while (g_ascii_isspace (*p)) - p++; - - if (!*p) - return FALSE; - else if (*p == '"') { - p++; - quoted = FALSE; - for (q = p; (*q != '"') || quoted; q++) { - if (!*q) - return FALSE; - quoted = (*q == '\\') && !quoted; - } - - tmp = g_strndup (p, q - p); - tmp2 = g_strcompress (tmp); - g_string_truncate (out, 0); - g_string_append (out, tmp2); - g_free (tmp); - g_free (tmp2); - } - - q++; - *pos = q; - - return TRUE; -} - -static gboolean -scan_int (const char **pos, int *out) -{ - int i = 0; - char buf[32]; - const char *p = *pos; - - while (g_ascii_isspace (*p)) - p++; - - if (*p < '0' || *p > '9') - return FALSE; - - while ((*p >= '0') && (*p <= '9') && i < sizeof (buf)) { - buf[i] = *p; - i++; - p++; - } - - if (i == sizeof (buf)) - return FALSE; - else - buf[i] = '\0'; - - *out = atoi (buf); - - *pos = p; - - return TRUE; -} - -static gboolean -skip_space (const char **pos) -{ - const char *p = *pos; - - while (g_ascii_isspace (*p)) - p++; - - *pos = p; - - return !(*p == '\0'); -} - -#ifdef G_OS_WIN32 - -/* DllMain function needed to tuck away the gdk-pixbuf DLL handle */ - -static HMODULE gdk_pixbuf_dll; - -BOOL WINAPI -DllMain (HINSTANCE hinstDLL, - DWORD fdwReason, - LPVOID lpvReserved) -{ - switch (fdwReason) { - case DLL_PROCESS_ATTACH: - gdk_pixbuf_dll = (HMODULE) hinstDLL; - break; - } - - return TRUE; -} - -static char * -get_toplevel (void) -{ - static char *toplevel = NULL; - - if (toplevel == NULL) - toplevel = g_win32_get_package_installation_directory_of_module (gdk_pixbuf_dll); - - return toplevel; -} - -static char * -get_sysconfdir (void) -{ - static char *sysconfdir = NULL; - - if (sysconfdir == NULL) - sysconfdir = g_build_filename (get_toplevel (), "etc", NULL); - - return sysconfdir; -} - -#undef GTK_SYSCONFDIR -#define GTK_SYSCONFDIR get_sysconfdir() - -static void -correct_prefix (gchar **path) -{ - if (strncmp (*path, GTK_PREFIX "/", strlen (GTK_PREFIX "/")) == 0 || - strncmp (*path, GTK_PREFIX "\\", strlen (GTK_PREFIX "\\")) == 0) - { - gchar *tem = NULL; - if (strlen(*path) > 5 && strncmp (*path - 5, ".libs", 5) == 0) - { - /* We are being run from inside the build tree, and shouldn't mess about. */ - return; - } - - /* This is an entry put there by gdk-pixbuf-query-loaders on the - * packager's system. On Windows a prebuilt GTK+ package can be - * installed in a random location. The gdk-pixbuf.loaders file - * distributed in such a package contains paths from the package - * builder's machine. Replace the build-time prefix with the - * installation prefix on this machine. - */ - tem = *path; - *path = g_strconcat (get_toplevel (), tem + strlen (GTK_PREFIX), NULL); - g_free (tem); - } -} - -#endif /* G_OS_WIN32 */ - -static gchar * -gdk_pixbuf_get_module_file (void) -{ - gchar *result = g_strdup (g_getenv ("GDK_PIXBUF_MODULE_FILE")); - - if (!result) - result = g_build_filename (GTK_LIBDIR, "gtk-3.0", GTK_BINARY_VERSION, "loaders.cache", NULL); - - return result; -} - -#endif /* USE_GMODULE */ - - -static gboolean -gdk_pixbuf_load_module_unlocked (GdkPixbufModule *image_module, - GError **error); - -static void -gdk_pixbuf_io_init (void) -{ -#ifdef USE_GMODULE - GIOChannel *channel; - gchar *line_buf; - gsize term; - GString *tmp_buf = g_string_new (NULL); - gboolean have_error = FALSE; - GdkPixbufModule *module = NULL; - gchar *filename = gdk_pixbuf_get_module_file (); - int flags; - int n_patterns = 0; - GdkPixbufModulePattern *pattern; - GError *error = NULL; -#endif - GdkPixbufModule *builtin_module ; - - /* initialize on separate line to avoid compiler warnings in the - * common case of no compiled-in modules. - */ - builtin_module = NULL; - -#define load_one_builtin_module(format) \ - builtin_module = g_new0 (GdkPixbufModule, 1); \ - builtin_module->module_name = #format; \ - if (gdk_pixbuf_load_module_unlocked (builtin_module, NULL)) \ - file_formats = g_slist_prepend (file_formats, builtin_module);\ - else \ - g_free (builtin_module) - -#ifdef INCLUDE_ani - load_one_builtin_module (ani); -#endif -#ifdef INCLUDE_png - load_one_builtin_module (png); -#endif -#ifdef INCLUDE_bmp - load_one_builtin_module (bmp); -#endif -#ifdef INCLUDE_wbmp - load_one_builtin_module (wbmp); -#endif -#ifdef INCLUDE_gif - load_one_builtin_module (gif); -#endif -#ifdef INCLUDE_ico - load_one_builtin_module (ico); -#endif -#ifdef INCLUDE_jpeg - load_one_builtin_module (jpeg); -#endif -#ifdef INCLUDE_pnm - load_one_builtin_module (pnm); -#endif -#ifdef INCLUDE_ras - load_one_builtin_module (ras); -#endif -#ifdef INCLUDE_tiff - load_one_builtin_module (tiff); -#endif -#ifdef INCLUDE_xpm - load_one_builtin_module (xpm); -#endif -#ifdef INCLUDE_xbm - load_one_builtin_module (xbm); -#endif -#ifdef INCLUDE_tga - load_one_builtin_module (tga); -#endif -#ifdef INCLUDE_pcx - load_one_builtin_module (pcx); -#endif -#ifdef INCLUDE_icns - load_one_builtin_module (icns); -#endif -#ifdef INCLUDE_jasper - load_one_builtin_module (jasper); -#endif -#ifdef INCLUDE_qtif - load_one_builtin_module (qtif); -#endif -#ifdef INCLUDE_gdiplus - /* We don't bother having the GDI+ loaders individually selectable - * for building in or not. - */ - load_one_builtin_module (ico); - load_one_builtin_module (wmf); - load_one_builtin_module (emf); - load_one_builtin_module (bmp); - load_one_builtin_module (gif); - load_one_builtin_module (jpeg); - load_one_builtin_module (tiff); -#endif -#ifdef INCLUDE_gdip_png - /* Except the gdip-png loader which normally isn't built at all even */ - load_one_builtin_module (png); -#endif - -#undef load_one_builtin_module - -#ifdef USE_GMODULE - channel = g_io_channel_new_file (filename, "r", &error); - if (!channel) { - /* Don't bother warning if we have some built-in loaders */ - if (file_formats == NULL) - g_warning ("Cannot open pixbuf loader module file '%s': %s", - filename, error->message); - g_string_free (tmp_buf, TRUE); - g_free (filename); - return; - } - - while (!have_error && g_io_channel_read_line (channel, &line_buf, NULL, &term, NULL) == G_IO_STATUS_NORMAL) { - const char *p; - - p = line_buf; - - line_buf[term] = 0; - - if (!skip_space (&p)) { - /* Blank line marking the end of a module - */ - if (module && *p != '#') { -#ifdef G_OS_WIN32 - correct_prefix (&module->module_path); -#endif - file_formats = g_slist_prepend (file_formats, module); - module = NULL; - } - - goto next_line; - } - - if (*p == '#') - goto next_line; - - if (!module) { - /* Read a module location - */ - module = g_new0 (GdkPixbufModule, 1); - n_patterns = 0; - - if (!scan_string (&p, tmp_buf)) { - g_warning ("Error parsing loader info in '%s'\n %s", - filename, line_buf); - have_error = TRUE; - } - module->module_path = g_strdup (tmp_buf->str); - } - else if (!module->module_name) { - module->info = g_new0 (GdkPixbufFormat, 1); - if (!scan_string (&p, tmp_buf)) { - g_warning ("Error parsing loader info in '%s'\n %s", - filename, line_buf); - have_error = TRUE; - } - module->info->name = g_strdup (tmp_buf->str); - module->module_name = module->info->name; - - if (!scan_int (&p, &flags)) { - g_warning ("Error parsing loader info in '%s'\n %s", - filename, line_buf); - have_error = TRUE; - } - module->info->flags = flags; - - if (!scan_string (&p, tmp_buf)) { - g_warning ("Error parsing loader info in '%s'\n %s", - filename, line_buf); - have_error = TRUE; - } - if (tmp_buf->str[0] != 0) - module->info->domain = g_strdup (tmp_buf->str); - - if (!scan_string (&p, tmp_buf)) { - g_warning ("Error parsing loader info in '%s'\n %s", - filename, line_buf); - have_error = TRUE; - } - module->info->description = g_strdup (tmp_buf->str); - - if (scan_string (&p, tmp_buf)) { - module->info->license = g_strdup (tmp_buf->str); - } - } - else if (!module->info->mime_types) { - int n = 1; - module->info->mime_types = g_new0 (gchar*, 1); - while (scan_string (&p, tmp_buf)) { - if (tmp_buf->str[0] != 0) { - module->info->mime_types = - g_realloc (module->info->mime_types, (n + 1) * sizeof (gchar*)); - module->info->mime_types[n - 1] = g_strdup (tmp_buf->str); - module->info->mime_types[n] = NULL; - n++; - } - } - } - else if (!module->info->extensions) { - int n = 1; - module->info->extensions = g_new0 (gchar*, 1); - while (scan_string (&p, tmp_buf)) { - if (tmp_buf->str[0] != 0) { - module->info->extensions = - g_realloc (module->info->extensions, (n + 1) * sizeof (gchar*)); - module->info->extensions[n - 1] = g_strdup (tmp_buf->str); - module->info->extensions[n] = NULL; - n++; - } - } - } - else { - n_patterns++; - module->info->signature = (GdkPixbufModulePattern *) - g_realloc (module->info->signature, (n_patterns + 1) * sizeof (GdkPixbufModulePattern)); - pattern = module->info->signature + n_patterns; - pattern->prefix = NULL; - pattern->mask = NULL; - pattern->relevance = 0; - pattern--; - if (!scan_string (&p, tmp_buf)) - goto context_error; - pattern->prefix = g_strdup (tmp_buf->str); - - if (!scan_string (&p, tmp_buf)) - goto context_error; - if (*tmp_buf->str) - pattern->mask = g_strdup (tmp_buf->str); - else - pattern->mask = NULL; - - if (!scan_int (&p, &pattern->relevance)) - goto context_error; - - goto next_line; - - context_error: - g_free (pattern->prefix); - g_free (pattern->mask); - g_free (pattern); - g_warning ("Error parsing loader info in '%s'\n %s", - filename, line_buf); - have_error = TRUE; - } - next_line: - g_free (line_buf); - } - g_string_free (tmp_buf, TRUE); - g_io_channel_unref (channel); - g_free (filename); -#endif -} - - -#define module(type) \ - extern void _gdk_pixbuf__##type##_fill_info (GdkPixbufFormat *info); \ - extern void _gdk_pixbuf__##type##_fill_vtable (GdkPixbufModule *module) - -module (png); -module (jpeg); -module (gif); -module (ico); -module (ani); -module (ras); -module (xpm); -module (tiff); -module (pnm); -module (bmp); -module (wbmp); -module (xbm); -module (tga); -module (pcx); -module (icns); -module (jasper); -module (qtif); -module (gdip_ico); -module (gdip_wmf); -module (gdip_emf); -module (gdip_bmp); -module (gdip_gif); -module (gdip_jpeg); -module (gdip_png); -module (gdip_tiff); - -#undef module - -/* actually load the image handler - gdk_pixbuf_get_module only get a */ -/* reference to the module to load, it doesn't actually load it */ -/* perhaps these actions should be combined in one function */ -static gboolean -gdk_pixbuf_load_module_unlocked (GdkPixbufModule *image_module, - GError **error) -{ - GdkPixbufModuleFillInfoFunc fill_info = NULL; - GdkPixbufModuleFillVtableFunc fill_vtable = NULL; - - if (image_module->module != NULL) - return TRUE; - -#define try_module(format,id) \ - if (fill_info == NULL && \ - strcmp (image_module->module_name, #format) == 0) { \ - fill_info = _gdk_pixbuf__##id##_fill_info; \ - fill_vtable = _gdk_pixbuf__##id##_fill_vtable; \ - } -#ifdef INCLUDE_png - try_module (png,png); -#endif -#ifdef INCLUDE_bmp - try_module (bmp,bmp); -#endif -#ifdef INCLUDE_wbmp - try_module (wbmp,wbmp); -#endif -#ifdef INCLUDE_gif - try_module (gif,gif); -#endif -#ifdef INCLUDE_ico - try_module (ico,ico); -#endif -#ifdef INCLUDE_ani - try_module (ani,ani); -#endif -#ifdef INCLUDE_jpeg - try_module (jpeg,jpeg); -#endif -#ifdef INCLUDE_pnm - try_module (pnm,pnm); -#endif -#ifdef INCLUDE_ras - try_module (ras,ras); -#endif -#ifdef INCLUDE_tiff - try_module (tiff,tiff); -#endif -#ifdef INCLUDE_xpm - try_module (xpm,xpm); -#endif -#ifdef INCLUDE_xbm - try_module (xbm,xbm); -#endif -#ifdef INCLUDE_tga - try_module (tga,tga); -#endif -#ifdef INCLUDE_pcx - try_module (pcx,pcx); -#endif -#ifdef INCLUDE_icns - try_module (icns,icns); -#endif -#ifdef INCLUDE_jasper - try_module (jasper,jasper); -#endif -#ifdef INCLUDE_qtif - try_module (qtif,qtif); -#endif -#ifdef INCLUDE_gdiplus - try_module (ico,gdip_ico); - try_module (wmf,gdip_wmf); - try_module (emf,gdip_emf); - try_module (bmp,gdip_bmp); - try_module (gif,gdip_gif); - try_module (jpeg,gdip_jpeg); - try_module (tiff,gdip_tiff); -#endif -#ifdef INCLUDE_gdip_png - try_module (png,gdip_png); -#endif - -#undef try_module - - if (fill_vtable) { - image_module->module = (void *) 1; - (* fill_vtable) (image_module); - if (image_module->info == NULL) { - image_module->info = g_new0 (GdkPixbufFormat, 1); - (* fill_info) (image_module->info); - } - return TRUE; - } - else -#ifdef USE_GMODULE - { - char *path; - GModule *module; - gpointer sym; - - path = image_module->module_path; - module = g_module_open (path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); - - if (!module) { - g_set_error (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_FAILED, - _("Unable to load image-loading module: %s: %s"), - path, g_module_error ()); - return FALSE; - } - - image_module->module = module; - - if (g_module_symbol (module, "fill_vtable", &sym)) { - fill_vtable = (GdkPixbufModuleFillVtableFunc) sym; - (* fill_vtable) (image_module); - return TRUE; - } else { - g_set_error (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_FAILED, - _("Image-loading module %s does not export the proper interface; perhaps it's from a different GTK version?"), - path); - return FALSE; - } - } -#else - g_set_error (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_UNKNOWN_TYPE, - _("Image type '%s' is not supported"), - image_module->module_name); - return FALSE; -#endif /* !USE_GMODULE */ -} - - -gboolean -_gdk_pixbuf_load_module (GdkPixbufModule *image_module, - GError **error) -{ - gboolean ret; - gboolean locked = FALSE; - - /* be extra careful, maybe the module initializes - * the thread system - */ - if (g_threads_got_initialized) { - G_LOCK (init_lock); - locked = TRUE; - } - - ret = gdk_pixbuf_load_module_unlocked (image_module, error); - - if (locked) - G_UNLOCK (init_lock); - - return ret; -} - - - -GdkPixbufModule * -_gdk_pixbuf_get_named_module (const char *name, - GError **error) -{ - GSList *modules; - - for (modules = get_file_formats (); modules; modules = g_slist_next (modules)) { - GdkPixbufModule *module = (GdkPixbufModule *)modules->data; - - if (module->info->disabled) - continue; - - if (!strcmp (name, module->module_name)) - return module; - } - - g_set_error (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_UNKNOWN_TYPE, - _("Image type '%s' is not supported"), - name); - - return NULL; -} - -GdkPixbufModule * -_gdk_pixbuf_get_module (guchar *buffer, guint size, - const gchar *filename, - GError **error) -{ - GSList *modules; - - GdkPixbufModule *selected = NULL; - gchar *display_name = NULL; -#ifdef GDK_PIXBUF_USE_GIO_MIME - gchar *mime_type; - gchar **mimes; - gchar *type; - gint j; - gboolean uncertain; - - mime_type = g_content_type_guess (NULL, buffer, size, &uncertain); - if (uncertain) - mime_type = g_content_type_guess (filename, buffer, size, NULL); - - for (modules = get_file_formats (); modules; modules = g_slist_next (modules)) { - GdkPixbufModule *module = (GdkPixbufModule *)modules->data; - GdkPixbufFormat *info = module->info; - - if (info->disabled) - continue; - - mimes = info->mime_types; - for (j = 0; mimes[j] != NULL; j++) { - type = g_content_type_from_mime_type (mimes[j]); - if (g_ascii_strcasecmp (type, mime_type) == 0) { - g_free (type); - selected = module; - break; - } - g_free (type); - } - } - g_free (mime_type); -#else - gint score, best = 0; - - for (modules = get_file_formats (); modules; modules = g_slist_next (modules)) { - GdkPixbufModule *module = (GdkPixbufModule *)modules->data; - - if (module->info->disabled) - continue; - - score = format_check (module, buffer, size); - if (score > best) { - best = score; - selected = module; - } - if (score >= 100) - break; - } -#endif - - if (selected != NULL) - return selected; - - if (filename) - { - display_name = g_filename_display_name (filename); - g_set_error (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_UNKNOWN_TYPE, - _("Couldn't recognize the image file format for file '%s'"), - display_name); - g_free (display_name); - } - else - g_set_error_literal (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_UNKNOWN_TYPE, - _("Unrecognized image file format")); - - - return NULL; -} - - -static void -prepared_notify (GdkPixbuf *pixbuf, - GdkPixbufAnimation *anim, - gpointer user_data) -{ - if (pixbuf != NULL) - g_object_ref (pixbuf); - *((GdkPixbuf **)user_data) = pixbuf; -} - -GdkPixbuf * -_gdk_pixbuf_generic_image_load (GdkPixbufModule *module, - FILE *f, - GError **error) -{ - guchar buffer[LOAD_BUFFER_SIZE]; - size_t length; - GdkPixbuf *pixbuf = NULL; - GdkPixbufAnimation *animation = NULL; - gpointer context; - gboolean locked; - - locked = _gdk_pixbuf_lock (module); - - if (module->load != NULL) { - pixbuf = (* module->load) (f, error); - } else if (module->begin_load != NULL) { - - context = module->begin_load (NULL, prepared_notify, NULL, &pixbuf, error); - - if (!context) - goto out; - - while (!feof (f) && !ferror (f)) { - length = fread (buffer, 1, sizeof (buffer), f); - if (length > 0) - if (!module->load_increment (context, buffer, length, error)) { - module->stop_load (context, NULL); - if (pixbuf != NULL) { - g_object_unref (pixbuf); - pixbuf = NULL; - } - goto out; - } - } - - if (!module->stop_load (context, error)) { - if (pixbuf != NULL) { - g_object_unref (pixbuf); - pixbuf = NULL; - } - } - } else if (module->load_animation != NULL) { - animation = (* module->load_animation) (f, error); - if (animation != NULL) { - pixbuf = gdk_pixbuf_animation_get_static_image (animation); - - g_object_ref (pixbuf); - g_object_unref (animation); - } - } - - out: - if (locked) - _gdk_pixbuf_unlock (module); - return pixbuf; -} - -/** - * gdk_pixbuf_new_from_file: - * @filename: Name of file to load, in the GLib file name encoding - * @error: Return location for an error - * - * Creates a new pixbuf by loading an image from a file. The file format is - * detected automatically. If %NULL is returned, then @error will be set. - * Possible errors are in the #GDK_PIXBUF_ERROR and #G_FILE_ERROR domains. - * - * Return value: A newly-created pixbuf with a reference count of 1, or %NULL if - * any of several error conditions occurred: the file could not be opened, - * there was no loader for the file's format, there was not enough memory to - * allocate the image buffer, or the image file contained invalid data. - **/ -GdkPixbuf * -gdk_pixbuf_new_from_file (const char *filename, - GError **error) -{ - GdkPixbuf *pixbuf; - int size; - FILE *f; - guchar buffer[SNIFF_BUFFER_SIZE]; - GdkPixbufModule *image_module; - gchar *display_name; - - g_return_val_if_fail (filename != NULL, NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - display_name = g_filename_display_name (filename); - - f = g_fopen (filename, "rb"); - if (!f) { - gint save_errno = errno; - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (save_errno), - _("Failed to open file '%s': %s"), - display_name, - g_strerror (save_errno)); - g_free (display_name); - return NULL; - } - - size = fread (&buffer, 1, sizeof (buffer), f); - if (size == 0) { - g_set_error (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_CORRUPT_IMAGE, - _("Image file '%s' contains no data"), - display_name); - g_free (display_name); - fclose (f); - return NULL; - } - - image_module = _gdk_pixbuf_get_module (buffer, size, filename, error); - if (image_module == NULL) { - g_free (display_name); - fclose (f); - return NULL; - } - - if (!_gdk_pixbuf_load_module (image_module, error)) { - g_free (display_name); - fclose (f); - return NULL; - } - - fseek (f, 0, SEEK_SET); - pixbuf = _gdk_pixbuf_generic_image_load (image_module, f, error); - fclose (f); - - if (pixbuf == NULL && error != NULL && *error == NULL) { - - /* I don't trust these crufty longjmp()'ing image libs - * to maintain proper error invariants, and I don't - * want user code to segfault as a result. We need to maintain - * the invariant that error gets set if NULL is returned. - */ - - g_warning ("Bug! gdk-pixbuf loader '%s' didn't set an error on failure.", image_module->module_name); - g_set_error (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_FAILED, - _("Failed to load image '%s': reason not known, probably a corrupt image file"), - display_name); - } else if (error != NULL && *error != NULL) { - - /* Add the filename to the error message */ - GError *e = *error; - gchar *old; - - old = e->message; - e->message = g_strdup_printf (_("Failed to load image '%s': %s"), - display_name, - old); - g_free (old); - } - - g_free (display_name); - return pixbuf; -} - -#ifdef G_OS_WIN32 - -#undef gdk_pixbuf_new_from_file -GdkPixbuf * -gdk_pixbuf_new_from_file (const char *filename, - GError **error) -{ - gchar *utf8_filename = - g_locale_to_utf8 (filename, -1, NULL, NULL, error); - GdkPixbuf *retval; - - if (utf8_filename == NULL) - return NULL; - - retval = gdk_pixbuf_new_from_file_utf8 (utf8_filename, error); - - g_free (utf8_filename); - - return retval; -} -#endif - - -/** - * gdk_pixbuf_new_from_file_at_size: - * @filename: Name of file to load, in the GLib file name encoding - * @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 - * @error: Return location for an error - * - * Creates a new pixbuf by loading an image from a file. - * The file format is detected automatically. If %NULL is returned, then - * @error will be set. Possible errors are in the #GDK_PIXBUF_ERROR and - * #G_FILE_ERROR domains. - * - * The image will be scaled to fit in the requested size, preserving - * the image's aspect ratio. Note that the returned pixbuf may be smaller - * than @width x @height, if the aspect ratio requires it. To load - * and image at the requested size, regardless of aspect ratio, use - * gdk_pixbuf_new_from_file_at_scale(). - * - * Return value: A newly-created pixbuf with a reference count of 1, or - * %NULL if any of several error conditions occurred: the file could not - * be opened, there was no loader for the file's format, there was not - * enough memory to allocate the image buffer, or the image file contained - * invalid data. - * - * Since: 2.4 - **/ -GdkPixbuf * -gdk_pixbuf_new_from_file_at_size (const char *filename, - int width, - int height, - GError **error) -{ - return gdk_pixbuf_new_from_file_at_scale (filename, - width, height, - TRUE, error); -} - -#ifdef G_OS_WIN32 - -#undef gdk_pixbuf_new_from_file_at_size - -GdkPixbuf * -gdk_pixbuf_new_from_file_at_size (const char *filename, - int width, - int height, - GError **error) -{ - gchar *utf8_filename = - g_locale_to_utf8 (filename, -1, NULL, NULL, error); - GdkPixbuf *retval; - - if (utf8_filename == NULL) - return NULL; - - retval = gdk_pixbuf_new_from_file_at_size_utf8 (utf8_filename, - width, height, - error); - - g_free (utf8_filename); - - return retval; -} -#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; - } - - width = MAX (width, 1); - height = MAX (height, 1); - - 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 - * @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 - * @error: Return location for an error - * - * Creates a new pixbuf by loading an image from a file. The file format is - * detected automatically. If %NULL is returned, then @error will be set. - * Possible errors are in the #GDK_PIXBUF_ERROR and #G_FILE_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. Negative values for @width and @height are - * allowed since 2.8. - * - * Return value: A newly-created pixbuf with a reference count of 1, or %NULL - * if any of several error conditions occurred: the file could not be opened, - * there was no loader for the file's format, there was not enough memory to - * allocate the image buffer, or the image file contained invalid data. - * - * Since: 2.6 - **/ -GdkPixbuf * -gdk_pixbuf_new_from_file_at_scale (const char *filename, - int width, - int height, - gboolean preserve_aspect_ratio, - GError **error) -{ - - GdkPixbufLoader *loader; - GdkPixbuf *pixbuf; - guchar buffer[LOAD_BUFFER_SIZE]; - int length; - FILE *f; - AtScaleData info; - GdkPixbufAnimation *animation; - GdkPixbufAnimationIter *iter; - gboolean has_frame; - - g_return_val_if_fail (filename != NULL, NULL); - g_return_val_if_fail (width > 0 || width == -1, NULL); - g_return_val_if_fail (height > 0 || height == -1, NULL); - - f = g_fopen (filename, "rb"); - if (!f) { - gint save_errno = errno; - gchar *display_name = g_filename_display_name (filename); - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (save_errno), - _("Failed to open file '%s': %s"), - display_name, - g_strerror (save_errno)); - g_free (display_name); - return NULL; - } - - 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); - - has_frame = FALSE; - while (!has_frame && !feof (f) && !ferror (f)) { - length = fread (buffer, 1, sizeof (buffer), f); - if (length > 0) - if (!gdk_pixbuf_loader_write (loader, buffer, length, error)) { - gdk_pixbuf_loader_close (loader, NULL); - fclose (f); - g_object_unref (loader); - return NULL; - } - - animation = gdk_pixbuf_loader_get_animation (loader); - if (animation) { - iter = gdk_pixbuf_animation_get_iter (animation, NULL); - if (!gdk_pixbuf_animation_iter_on_currently_loading_frame (iter)) { - has_frame = TRUE; - } - g_object_unref (iter); - } - } - - fclose (f); - - if (!gdk_pixbuf_loader_close (loader, error) && !has_frame) { - g_object_unref (loader); - return NULL; - } - - pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); - - if (!pixbuf) { - gchar *display_name = g_filename_display_name (filename); - g_object_unref (loader); - g_set_error (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_FAILED, - _("Failed to load image '%s': reason not known, probably a corrupt image file"), - display_name); - g_free (display_name); - return NULL; - } - - g_object_ref (pixbuf); - - g_object_unref (loader); - - return pixbuf; -} - -#ifdef G_OS_WIN32 - -#undef gdk_pixbuf_new_from_file_at_scale - -GdkPixbuf * -gdk_pixbuf_new_from_file_at_scale (const char *filename, - int width, - int height, - gboolean preserve_aspect_ratio, - GError **error) -{ - gchar *utf8_filename = - g_locale_to_utf8 (filename, -1, NULL, NULL, error); - GdkPixbuf *retval; - - if (utf8_filename == NULL) - return NULL; - - retval = gdk_pixbuf_new_from_file_at_scale_utf8 (utf8_filename, - width, height, - preserve_aspect_ratio, - error); - - g_free (utf8_filename); - - return retval; -} -#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.14 - */ -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.14 - **/ -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, - int height, - gpointer data) -{ - struct { - GdkPixbufFormat *format; - int width; - int height; - } *info = data; - - g_return_if_fail (width > 0 && height > 0); - - info->format = gdk_pixbuf_loader_get_format (loader); - info->width = width; - info->height = height; - - gdk_pixbuf_loader_set_size (loader, 0, 0); -} - -/** - * gdk_pixbuf_get_file_info: - * @filename: The name of the file to identify. - * @width: Return location for the width of the image, or %NULL - * @height: Return location for the height of the image, or %NULL - * - * Parses an image file far enough to determine its format and size. - * - * Returns: A #GdkPixbufFormat describing the image format of the file - * or %NULL if the image format wasn't recognized. The return value - * is owned by GdkPixbuf and should not be freed. - * - * Since: 2.4 - **/ -GdkPixbufFormat * -gdk_pixbuf_get_file_info (const gchar *filename, - gint *width, - gint *height) -{ - GdkPixbufLoader *loader; - guchar buffer[SNIFF_BUFFER_SIZE]; - int length; - FILE *f; - struct { - GdkPixbufFormat *format; - gint width; - gint height; - } info; - - g_return_val_if_fail (filename != NULL, NULL); - - f = g_fopen (filename, "rb"); - if (!f) - return NULL; - - loader = gdk_pixbuf_loader_new (); - - info.format = NULL; - info.width = -1; - info.height = -1; - - g_signal_connect (loader, "size-prepared", G_CALLBACK (info_cb), &info); - - while (!feof (f) && !ferror (f)) { - length = fread (buffer, 1, sizeof (buffer), f); - if (length > 0) { - if (!gdk_pixbuf_loader_write (loader, buffer, length, NULL)) - break; - } - if (info.format != NULL) - break; - } - - fclose (f); - gdk_pixbuf_loader_close (loader, NULL); - g_object_unref (loader); - - if (width) - *width = info.width; - if (height) - *height = info.height; - - return info.format; -} - -/** - * gdk_pixbuf_new_from_xpm_data: - * @data: Pointer to inline XPM data. - * - * Creates a new pixbuf by parsing XPM data in memory. This data is commonly - * the result of including an XPM file into a program's C source. - * - * Return value: A newly-created pixbuf with a reference count of 1. - **/ -GdkPixbuf * -gdk_pixbuf_new_from_xpm_data (const char **data) -{ - GdkPixbuf *(* load_xpm_data) (const char **data); - GdkPixbuf *pixbuf; - GError *error = NULL; - GdkPixbufModule *xpm_module; - gboolean locked; - - g_return_val_if_fail (data != NULL, NULL); - - xpm_module = _gdk_pixbuf_get_named_module ("xpm", &error); - if (xpm_module == NULL) { - g_warning ("Error loading XPM image loader: %s", error->message); - g_error_free (error); - return NULL; - } - - if (!_gdk_pixbuf_load_module (xpm_module, &error)) { - g_warning ("Error loading XPM image loader: %s", error->message); - g_error_free (error); - return NULL; - } - - locked = _gdk_pixbuf_lock (xpm_module); - - if (xpm_module->load_xpm_data == NULL) { - g_warning ("gdk-pixbuf XPM module lacks XPM data capability"); - pixbuf = NULL; - } else { - load_xpm_data = xpm_module->load_xpm_data; - pixbuf = (* load_xpm_data) (data); - } - - if (locked) - _gdk_pixbuf_unlock (xpm_module); - 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 -save_to_file_callback (const gchar *buf, - gsize count, - GError **error, - gpointer data) -{ - FILE *filehandle = data; - gsize n; - - n = fwrite (buf, 1, count, filehandle); - if (n != count) { - gint save_errno = errno; - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (save_errno), - _("Error writing to image file: %s"), - g_strerror (save_errno)); - return FALSE; - } - return TRUE; -} - -static gboolean -gdk_pixbuf_real_save (GdkPixbuf *pixbuf, - FILE *filehandle, - const char *type, - gchar **keys, - gchar **values, - GError **error) -{ - gboolean ret; - GdkPixbufModule *image_module = NULL; - gboolean locked; - - image_module = _gdk_pixbuf_get_named_module (type, error); - - if (image_module == NULL) - return FALSE; - - if (!_gdk_pixbuf_load_module (image_module, error)) - return FALSE; - - locked = _gdk_pixbuf_lock (image_module); - - if (image_module->save) { - /* save normally */ - ret = (* image_module->save) (filehandle, pixbuf, - keys, values, - error); - } else if (image_module->save_to_callback) { - /* save with simple callback */ - ret = (* image_module->save_to_callback) (save_to_file_callback, - filehandle, pixbuf, - keys, values, - error); - } else { - /* can't save */ - g_set_error (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION, - _("This build of gdk-pixbuf does not support saving the image format: %s"), - type); - ret = FALSE; - } - - if (locked) - _gdk_pixbuf_unlock (image_module); - return ret; -} - -#define TMP_FILE_BUF_SIZE 4096 - -static gboolean -save_to_callback_with_tmp_file (GdkPixbufModule *image_module, - GdkPixbuf *pixbuf, - GdkPixbufSaveFunc save_func, - gpointer user_data, - gchar **keys, - gchar **values, - GError **error) -{ - int fd; - FILE *f = NULL; - gboolean retval = FALSE; - gchar *buf = NULL; - gsize n; - gchar *filename = NULL; - gboolean locked; - - buf = g_try_malloc (TMP_FILE_BUF_SIZE); - if (buf == NULL) { - g_set_error_literal (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, - _("Insufficient memory to save image to callback")); - goto end; - } - - fd = g_file_open_tmp ("gdkpixbuf-save-tmp.XXXXXX", &filename, error); - if (fd == -1) - goto end; - f = fdopen (fd, "wb+"); - if (f == NULL) { - gint save_errno = errno; - g_set_error_literal (error, - G_FILE_ERROR, - g_file_error_from_errno (save_errno), - _("Failed to open temporary file")); - goto end; - } - - locked = _gdk_pixbuf_lock (image_module); - retval = (image_module->save) (f, pixbuf, keys, values, error); - if (locked) - _gdk_pixbuf_unlock (image_module); - if (!retval) - goto end; - - rewind (f); - for (;;) { - n = fread (buf, 1, TMP_FILE_BUF_SIZE, f); - if (n > 0) { - if (!save_func (buf, n, error, user_data)) - goto end; - } - if (n != TMP_FILE_BUF_SIZE) - break; - } - if (ferror (f)) { - gint save_errno = errno; - g_set_error_literal (error, - G_FILE_ERROR, - g_file_error_from_errno (save_errno), - _("Failed to read from temporary file")); - goto end; - } - retval = TRUE; - - end: - /* cleanup and return retval */ - if (f) - fclose (f); - if (filename) { - g_unlink (filename); - g_free (filename); - } - g_free (buf); - - return retval; -} - -static gboolean -gdk_pixbuf_real_save_to_callback (GdkPixbuf *pixbuf, - GdkPixbufSaveFunc save_func, - gpointer user_data, - const char *type, - gchar **keys, - gchar **values, - GError **error) -{ - gboolean ret; - GdkPixbufModule *image_module = NULL; - gboolean locked; - - image_module = _gdk_pixbuf_get_named_module (type, error); - - if (image_module == NULL) - return FALSE; - - if (!_gdk_pixbuf_load_module (image_module, error)) - return FALSE; - - locked = _gdk_pixbuf_lock (image_module); - - if (image_module->save_to_callback) { - /* save normally */ - ret = (* image_module->save_to_callback) (save_func, user_data, - pixbuf, keys, values, - error); - } else if (image_module->save) { - /* use a temporary file */ - ret = save_to_callback_with_tmp_file (image_module, pixbuf, - save_func, user_data, - keys, values, - error); - } else { - /* can't save */ - g_set_error (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION, - _("This build of gdk-pixbuf does not support saving the image format: %s"), - type); - ret = FALSE; - } - - if (locked) - _gdk_pixbuf_unlock (image_module); - return ret; -} - - -/** - * gdk_pixbuf_save: - * @pixbuf: a #GdkPixbuf. - * @filename: name of file to save. - * @type: name of file format. - * @error: (allow-none): return location for error, or %NULL - * @Varargs: list of key-value save options - * - * Saves pixbuf to a file in format @type. By default, "jpeg", "png", "ico" - * and "bmp" are possible file formats to save in, but more formats may be - * installed. The list of all writable formats can be determined in the - * following way: - * - * |[ - * 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 *writable_formats = NULL; - * g_slist_foreach (formats, add_if_writable, &writable_formats); - * g_slist_free (formats); - * ]| - * - * 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. - * - * The variable argument list should be %NULL-terminated; if not empty, - * it should contain pairs of strings that modify the save - * parameters. For example: - * <informalexample><programlisting> - * gdk_pixbuf_save (pixbuf, handle, "jpeg", &error, - * "quality", "100", NULL); - * </programlisting></informalexample> - * - * Currently only few parameters exist. JPEG images can be saved with a - * "quality" parameter; its value should be in the range [0,100]. - * - * Text chunks can be attached to PNG images by specifying parameters of - * the form "tEXt::key", where key is an ASCII string of length 1-79. - * The values are UTF-8 encoded strings. The PNG compression level can - * be specified using the "compression" parameter; it's value is in an - * integer in the range of [0,9]. - * - * ICC color profiles can also be embedded into PNG and TIFF images. - * The "icc-profile" value should be the complete ICC profile encoded - * into base64. - * - * <informalexample><programlisting> - * gchar *contents; - * gchar *contents_encode; - * gsize length; - * g_file_get_contents ("/home/hughsie/.color/icc/L225W.icm", &contents, &length, NULL); - * contents_encode = g_base64_encode ((const guchar *) contents, length); - * gdk_pixbuf_save (pixbuf, handle, "png", &error, - * "icc-profile", contents_encode, - * NULL); - * </programlisting></informalexample> - * - * TIFF images recognize a "compression" option which acceps an integer value. - * Among the codecs are 1 None, 2 Huffman, 5 LZW, 7 JPEG and 8 Deflate, see - * the libtiff documentation and tiff.h for all supported codec values. - * - * ICO images can be saved in depth 16, 24, or 32, by using the "depth" - * parameter. When the ICO saver is given "x_hot" and "y_hot" parameters, - * it produces a CUR instead of an ICO. - * - * Return value: whether an error was set - **/ - -gboolean -gdk_pixbuf_save (GdkPixbuf *pixbuf, - const char *filename, - const char *type, - GError **error, - ...) -{ - gchar **keys = NULL; - gchar **values = NULL; - va_list args; - gboolean result; - - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - va_start (args, error); - - collect_save_options (args, &keys, &values); - - va_end (args); - - result = gdk_pixbuf_savev (pixbuf, filename, type, - keys, values, - error); - - g_strfreev (keys); - g_strfreev (values); - - return result; -} - -#ifdef G_OS_WIN32 - -#undef gdk_pixbuf_save - -gboolean -gdk_pixbuf_save (GdkPixbuf *pixbuf, - const char *filename, - const char *type, - GError **error, - ...) -{ - char *utf8_filename; - gchar **keys = NULL; - gchar **values = NULL; - va_list args; - gboolean result; - - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, error); - - if (utf8_filename == NULL) - return FALSE; - - va_start (args, error); - - collect_save_options (args, &keys, &values); - - va_end (args); - - result = gdk_pixbuf_savev_utf8 (pixbuf, utf8_filename, type, - keys, values, - error); - - g_free (utf8_filename); - - g_strfreev (keys); - g_strfreev (values); - - return result; -} - -#endif - -/** - * gdk_pixbuf_savev: - * @pixbuf: a #GdkPixbuf. - * @filename: name of file to save. - * @type: name of file format. - * @option_keys: name of options to set, %NULL-terminated - * @option_values: values for named options - * @error: (allow-none): return location for error, or %NULL - * - * Saves pixbuf to a file in @type, which is currently "jpeg", "png", "tiff", "ico" or "bmp". - * If @error is set, %FALSE will be returned. - * See gdk_pixbuf_save () for more details. - * - * Return value: whether an error was set - **/ - -gboolean -gdk_pixbuf_savev (GdkPixbuf *pixbuf, - const char *filename, - const char *type, - 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 (type != NULL, FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - f = g_fopen (filename, "wb"); - - if (f == NULL) { - gint save_errno = errno; - gchar *display_name = g_filename_display_name (filename); - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (save_errno), - _("Failed to open '%s' for writing: %s"), - display_name, - g_strerror (save_errno)); - g_free (display_name); - return FALSE; - } - - - result = gdk_pixbuf_real_save (pixbuf, f, type, - option_keys, option_values, - error); - - - if (!result) { - g_return_val_if_fail (error == NULL || *error != NULL, FALSE); - fclose (f); - g_unlink (filename); - return FALSE; - } - - if (fclose (f) < 0) { - gint save_errno = errno; - gchar *display_name = g_filename_display_name (filename); - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (save_errno), - _("Failed to close '%s' while writing image, all data may not have been saved: %s"), - display_name, - g_strerror (save_errno)); - g_free (display_name); - return FALSE; - } - - return TRUE; -} - -#ifdef G_OS_WIN32 - -#undef gdk_pixbuf_savev - -gboolean -gdk_pixbuf_savev (GdkPixbuf *pixbuf, - const char *filename, - const char *type, - char **option_keys, - char **option_values, - GError **error) -{ - char *utf8_filename; - gboolean retval; - - g_return_val_if_fail (filename != NULL, FALSE); - - utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, error); - - if (utf8_filename == NULL) - return FALSE; - - retval = gdk_pixbuf_savev_utf8 (pixbuf, utf8_filename, type, - option_keys, option_values, error); - - g_free (utf8_filename); - - return retval; -} - -#endif - -/** - * gdk_pixbuf_save_to_callback: - * @pixbuf: a #GdkPixbuf. - * @save_func: a function that is called to save each block of data that - * the save routine generates. - * @user_data: user data to pass to the save function. - * @type: name of file format. - * @error: (allow-none): return location for error, or %NULL - * @Varargs: list of key-value save options - * - * Saves pixbuf in format @type by feeding the produced data to a - * callback. Can be used when you want to store the image to something - * other than a file, such as an in-memory buffer or a socket. - * If @error is set, %FALSE will be returned. Possible errors - * include those in the #GDK_PIXBUF_ERROR domain and whatever the save - * function generates. - * - * See gdk_pixbuf_save() for more details. - * - * Return value: whether an error was set - * - * Since: 2.4 - **/ -gboolean -gdk_pixbuf_save_to_callback (GdkPixbuf *pixbuf, - GdkPixbufSaveFunc save_func, - gpointer user_data, - const char *type, - GError **error, - ...) -{ - gchar **keys = NULL; - gchar **values = NULL; - va_list args; - gboolean result; - - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - va_start (args, error); - - collect_save_options (args, &keys, &values); - - va_end (args); - - result = gdk_pixbuf_save_to_callbackv (pixbuf, save_func, user_data, - type, keys, values, - error); - - g_strfreev (keys); - g_strfreev (values); - - return result; -} - -/** - * gdk_pixbuf_save_to_callbackv: - * @pixbuf: a #GdkPixbuf. - * @save_func: a function that is called to save each block of data that - * the save routine generates. - * @user_data: user data to pass to the save function. - * @type: name of file format. - * @option_keys: name of options to set, %NULL-terminated - * @option_values: values for named options - * @error: (allow-none): return location for error, or %NULL - * - * Saves pixbuf to a callback in format @type, which is currently "jpeg", - * "png", "tiff", "ico" or "bmp". If @error is set, %FALSE will be returned. See - * gdk_pixbuf_save_to_callback () for more details. - * - * Return value: whether an error was set - * - * Since: 2.4 - **/ -gboolean -gdk_pixbuf_save_to_callbackv (GdkPixbuf *pixbuf, - GdkPixbufSaveFunc save_func, - gpointer user_data, - const char *type, - char **option_keys, - char **option_values, - GError **error) -{ - gboolean result; - - - g_return_val_if_fail (save_func != NULL, FALSE); - g_return_val_if_fail (type != NULL, FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - result = gdk_pixbuf_real_save_to_callback (pixbuf, - save_func, user_data, type, - option_keys, option_values, - error); - - if (!result) { - g_return_val_if_fail (error == NULL || *error != NULL, FALSE); - return FALSE; - } - - return TRUE; -} - -/** - * gdk_pixbuf_save_to_buffer: - * @pixbuf: a #GdkPixbuf. - * @buffer: location to receive a pointer to the new buffer. - * @buffer_size: location to receive the size of the new buffer. - * @type: name of file format. - * @error: (allow-none): return location for error, or %NULL - * @Varargs: list of key-value save options - * - * Saves pixbuf to a new buffer in format @type, which is currently "jpeg", - * "png", "tiff", "ico" or "bmp". This is a convenience function that uses - * gdk_pixbuf_save_to_callback() to do the real work. Note that the buffer - * is not nul-terminated and may contain embedded nuls. - * If @error is set, %FALSE will be returned and @buffer will be set to - * %NULL. Possible errors include those in the #GDK_PIXBUF_ERROR - * domain. - * - * See gdk_pixbuf_save() for more details. - * - * Return value: whether an error was set - * - * Since: 2.4 - **/ -gboolean -gdk_pixbuf_save_to_buffer (GdkPixbuf *pixbuf, - gchar **buffer, - gsize *buffer_size, - const char *type, - GError **error, - ...) -{ - gchar **keys = NULL; - gchar **values = NULL; - va_list args; - gboolean result; - - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - va_start (args, error); - - collect_save_options (args, &keys, &values); - - va_end (args); - - result = gdk_pixbuf_save_to_bufferv (pixbuf, buffer, buffer_size, - type, keys, values, - error); - - g_strfreev (keys); - g_strfreev (values); - - return result; -} - -struct SaveToBufferData { - gchar *buffer; - gsize len, max; -}; - -static gboolean -save_to_buffer_callback (const gchar *data, - gsize count, - GError **error, - gpointer user_data) -{ - struct SaveToBufferData *sdata = user_data; - gchar *new_buffer; - gsize new_max; - - if (sdata->len + count > sdata->max) { - new_max = MAX (sdata->max*2, sdata->len + count); - new_buffer = g_try_realloc (sdata->buffer, new_max); - if (!new_buffer) { - g_set_error_literal (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, - _("Insufficient memory to save image into a buffer")); - return FALSE; - } - sdata->buffer = new_buffer; - sdata->max = new_max; - } - memcpy (sdata->buffer + sdata->len, data, count); - sdata->len += count; - return TRUE; -} - -/** - * gdk_pixbuf_save_to_bufferv: - * @pixbuf: a #GdkPixbuf. - * @buffer: location to receive a pointer to the new buffer. - * @buffer_size: location to receive the size of the new buffer. - * @type: name of file format. - * @option_keys: name of options to set, %NULL-terminated - * @option_values: values for named options - * @error: (allow-none): 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. - * - * Return value: whether an error was set - * - * Since: 2.4 - **/ -gboolean -gdk_pixbuf_save_to_bufferv (GdkPixbuf *pixbuf, - gchar **buffer, - gsize *buffer_size, - const char *type, - char **option_keys, - char **option_values, - GError **error) -{ - static const gint initial_max = 1024; - struct SaveToBufferData sdata; - - *buffer = NULL; - *buffer_size = 0; - - sdata.buffer = g_try_malloc (initial_max); - sdata.max = initial_max; - sdata.len = 0; - if (!sdata.buffer) { - g_set_error_literal (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, - _("Insufficient memory to save image into a buffer")); - return FALSE; - } - - if (!gdk_pixbuf_save_to_callbackv (pixbuf, - save_to_buffer_callback, &sdata, - type, option_keys, option_values, - error)) { - g_free (sdata.buffer); - return FALSE; - } - - *buffer = sdata.buffer; - *buffer_size = sdata.len; - return TRUE; -} - -typedef struct { - GOutputStream *stream; - GCancellable *cancellable; -} SaveToStreamData; - -static gboolean -save_to_stream (const gchar *buffer, - gsize count, - GError **error, - gpointer data) -{ - SaveToStreamData *sdata = (SaveToStreamData *)data; - gsize remaining; - gssize written; - GError *my_error = NULL; - - remaining = count; - written = 0; - while (remaining > 0) { - buffer += written; - remaining -= written; - written = g_output_stream_write (sdata->stream, - buffer, remaining, - sdata->cancellable, - &my_error); - if (written < 0) { - if (!my_error) { - g_set_error_literal (error, - G_IO_ERROR, 0, - _("Error writing to image stream")); - } - else { - g_propagate_error (error, my_error); - } - return FALSE; - } - } - - return TRUE; -} - -/** - * 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: (allow-none): 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.14 - */ -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; - - res = gdk_pixbuf_save_to_callbackv (pixbuf, save_to_stream, - &data, type, - keys, values, - error); - - g_strfreev (keys); - g_strfreev (values); - - return res; -} - -/** - * gdk_pixbuf_format_get_name: - * @format: a #GdkPixbufFormat - * - * Returns the name of the format. - * - * Return value: the name of the format. - * - * Since: 2.2 - */ -gchar * -gdk_pixbuf_format_get_name (GdkPixbufFormat *format) -{ - g_return_val_if_fail (format != NULL, NULL); - - return g_strdup (format->name); -} - -/** - * gdk_pixbuf_format_get_description: - * @format: a #GdkPixbufFormat - * - * Returns a description of the format. - * - * Return value: a description of the format. - * - * Since: 2.2 - */ -gchar * -gdk_pixbuf_format_get_description (GdkPixbufFormat *format) -{ - gchar *domain; - const gchar *description; - g_return_val_if_fail (format != NULL, NULL); - - if (format->domain != NULL) - domain = format->domain; - else - domain = GETTEXT_PACKAGE; - description = g_dgettext (domain, format->description); - - return g_strdup (description); -} - -/** - * gdk_pixbuf_format_get_mime_types: - * @format: a #GdkPixbufFormat - * - * Returns the mime types supported by the format. - * - * Return value: a %NULL-terminated array of mime types which must be freed with - * g_strfreev() when it is no longer needed. - * - * Since: 2.2 - */ -gchar ** -gdk_pixbuf_format_get_mime_types (GdkPixbufFormat *format) -{ - g_return_val_if_fail (format != NULL, NULL); - - return g_strdupv (format->mime_types); -} - -/** - * gdk_pixbuf_format_get_extensions: - * @format: a #GdkPixbufFormat - * - * Returns the filename extensions typically used for files in the - * given format. - * - * Return value: a %NULL-terminated array of filename extensions which must be - * freed with g_strfreev() when it is no longer needed. - * - * Since: 2.2 - */ -gchar ** -gdk_pixbuf_format_get_extensions (GdkPixbufFormat *format) -{ - g_return_val_if_fail (format != NULL, NULL); - - return g_strdupv (format->extensions); -} - -/** - * gdk_pixbuf_format_is_writable: - * @format: a #GdkPixbufFormat - * - * Returns whether pixbufs can be saved in the given format. - * - * Return value: whether pixbufs can be saved in the given format. - * - * Since: 2.2 - */ -gboolean -gdk_pixbuf_format_is_writable (GdkPixbufFormat *format) -{ - g_return_val_if_fail (format != NULL, FALSE); - - return (format->flags & GDK_PIXBUF_FORMAT_WRITABLE) != 0; -} - -/** - * gdk_pixbuf_format_is_scalable: - * @format: a #GdkPixbufFormat - * - * Returns whether this image format is scalable. If a file is in a - * scalable format, it is preferable to load it at the desired size, - * rather than loading it at the default size and scaling the - * resulting pixbuf to the desired size. - * - * Return value: whether this image format is scalable. - * - * Since: 2.6 - */ -gboolean -gdk_pixbuf_format_is_scalable (GdkPixbufFormat *format) -{ - g_return_val_if_fail (format != NULL, FALSE); - - return (format->flags & GDK_PIXBUF_FORMAT_SCALABLE) != 0; -} - -/** - * gdk_pixbuf_format_is_disabled: - * @format: a #GdkPixbufFormat - * - * Returns whether this image format is disabled. See - * gdk_pixbuf_format_set_disabled(). - * - * Return value: whether this image format is disabled. - * - * Since: 2.6 - */ -gboolean -gdk_pixbuf_format_is_disabled (GdkPixbufFormat *format) -{ - g_return_val_if_fail (format != NULL, FALSE); - - return format->disabled; -} - -/** - * gdk_pixbuf_format_set_disabled: - * @format: a #GdkPixbufFormat - * @disabled: %TRUE to disable the format @format - * - * Disables or enables an image format. If a format is disabled, - * gdk-pixbuf won't use the image loader for this format to load - * images. Applications can use this to avoid using image loaders - * with an inappropriate license, see gdk_pixbuf_format_get_license(). - * - * Since: 2.6 - */ -void -gdk_pixbuf_format_set_disabled (GdkPixbufFormat *format, - gboolean disabled) -{ - g_return_if_fail (format != NULL); - - format->disabled = disabled != FALSE; -} - -/** - * gdk_pixbuf_format_get_license: - * @format: a #GdkPixbufFormat - * - * Returns information about the license of the image loader for the format. The - * returned string should be a shorthand for a wellknown license, e.g. "LGPL", - * "GPL", "QPL", "GPL/QPL", or "other" to indicate some other license. This - * string should be freed with g_free() when it's no longer needed. - * - * Returns: a string describing the license of @format. - * - * Since: 2.6 - */ -gchar* -gdk_pixbuf_format_get_license (GdkPixbufFormat *format) -{ - g_return_val_if_fail (format != NULL, NULL); - - return g_strdup (format->license); -} - -GdkPixbufFormat * -_gdk_pixbuf_get_format (GdkPixbufModule *module) -{ - g_return_val_if_fail (module != NULL, NULL); - - return module->info; -} - -/** - * gdk_pixbuf_get_formats: - * - * Obtains the available information about the image formats supported - * by GdkPixbuf. - * - * Returns: A list of #GdkPixbufFormat<!-- -->s describing the supported - * image formats. The list should be freed when it is no longer needed, - * but the structures themselves are owned by #GdkPixbuf and should not be - * freed. - * - * Since: 2.2 - */ -GSList * -gdk_pixbuf_get_formats (void) -{ - GSList *result = NULL; - GSList *modules; - - for (modules = get_file_formats (); modules; modules = g_slist_next (modules)) { - GdkPixbufModule *module = (GdkPixbufModule *)modules->data; - GdkPixbufFormat *info = _gdk_pixbuf_get_format (module); - result = g_slist_prepend (result, info); - } - - return result; -} - - -#define __GDK_PIXBUF_IO_C__ -#include "gdk-pixbuf-aliasdef.c" |