mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-28 06:21:14 +00:00
6ba75ff95b
2004-12-05 Tor Lillqvist <tml@iki.fi> * gdk-pixbuf-animation.c * gdk-pixbuf-io.c * io-xbm.c * io-xpm.c * make-inline-pixbuf.c * queryloaders.c: Use gstdio wrappers. Document that file names are in the GLib file name encoding. * gdk-pixbuf-csource.c * queryloaders.c: On Windows, convert command line arguments and environment variable values from locale encoding to UTF-8. * queryloaders.c: On Windows, use wide character API when available. * Makefile.am * gdk-pixbuf-core.h * gdk-pixbuf-io.c * gdk-pixbuf-animation.h * gdk-pixbuf-animation.c: Like in GLib, for DLL ABI stability on Windows, add binary compatibility versions of functions that take file names as arguments. They use the system codepage, not GLib file name encoding (which is UTF-8 on Windows). Use #defines to make newly compiled code use the "real" functions that use the GLib file name encoding scheme.
2143 lines
54 KiB
C
2143 lines
54 KiB
C
/* -*- 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 <glib.h>
|
||
#include <errno.h>
|
||
#ifdef HAVE_UNISTD_H
|
||
#include <unistd.h>
|
||
#endif
|
||
|
||
#include "gdk-pixbuf-alias.h"
|
||
#include "gdk-pixbuf-private.h"
|
||
#include "gdk-pixbuf-io.h"
|
||
|
||
#include <glib/gstdio.h>
|
||
|
||
#ifdef G_OS_WIN32
|
||
#define STRICT
|
||
#include <windows.h>
|
||
#undef STRICT
|
||
#endif
|
||
|
||
static gint
|
||
format_check (GdkPixbufModule *module, guchar *buffer, int size)
|
||
{
|
||
int j;
|
||
gchar m;
|
||
GdkPixbufModulePattern *pattern;
|
||
|
||
for (pattern = module->info->signature; pattern->prefix; pattern++) {
|
||
for (j = 0; j < size && pattern->prefix[j] != 0; j++) {
|
||
m = pattern->mask ? pattern->mask[j] : ' ';
|
||
if (m == ' ') {
|
||
if (buffer[j] != pattern->prefix[j])
|
||
break;
|
||
}
|
||
else if (m == '!') {
|
||
if (buffer[j] == pattern->prefix[j])
|
||
break;
|
||
}
|
||
else if (m == 'z') {
|
||
if (buffer[j] != 0)
|
||
break;
|
||
}
|
||
else if (m == 'n') {
|
||
if (buffer[j] == 0)
|
||
break;
|
||
}
|
||
}
|
||
if (pattern->prefix[j] == 0)
|
||
return pattern->relevance;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
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 ();
|
||
|
||
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 name */
|
||
G_WIN32_DLLMAIN_FOR_DLL_NAME (static, dll_name)
|
||
|
||
static char *
|
||
get_toplevel (void)
|
||
{
|
||
static char *toplevel = NULL;
|
||
|
||
if (toplevel == NULL)
|
||
toplevel = g_win32_get_package_installation_subdirectory
|
||
(GETTEXT_PACKAGE, dll_name, "");
|
||
|
||
return toplevel;
|
||
}
|
||
|
||
static char *
|
||
get_sysconfdir (void)
|
||
{
|
||
static char *sysconfdir = NULL;
|
||
|
||
if (sysconfdir == NULL)
|
||
sysconfdir = g_win32_get_package_installation_subdirectory
|
||
(GETTEXT_PACKAGE, dll_name, "etc");
|
||
|
||
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)
|
||
{
|
||
/* 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.
|
||
*/
|
||
gchar *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_SYSCONFDIR, "gtk-2.0", "gdk-pixbuf.loaders", NULL);
|
||
|
||
return result;
|
||
}
|
||
|
||
static void
|
||
gdk_pixbuf_io_init (void)
|
||
{
|
||
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;
|
||
|
||
channel = g_io_channel_new_file (filename, "r", &error);
|
||
if (!channel) {
|
||
g_warning ("Cannot open pixbuf loader module file '%s': %s",
|
||
filename, error->message);
|
||
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);
|
||
}
|
||
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);
|
||
}
|
||
|
||
/* 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)
|
||
{
|
||
char *path;
|
||
GModule *module;
|
||
gpointer sym;
|
||
|
||
g_return_val_if_fail (image_module->module == NULL, FALSE);
|
||
|
||
path = image_module->module_path;
|
||
module = g_module_open (path, G_MODULE_BIND_LAZY);
|
||
|
||
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)) {
|
||
GdkPixbufModuleFillVtableFunc func = (GdkPixbufModuleFillVtableFunc) sym;
|
||
(* func) (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;
|
||
}
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
#else /* !USE_GMODULE */
|
||
|
||
#define module(type) \
|
||
extern void MODULE_ENTRY (type, fill_info) (GdkPixbufFormat *info); \
|
||
extern void MODULE_ENTRY (type, fill_vtable) (GdkPixbufModule *module)
|
||
|
||
module (png);
|
||
module (bmp);
|
||
module (wbmp);
|
||
module (gif);
|
||
module (ico);
|
||
module (ani);
|
||
module (jpeg);
|
||
module (pnm);
|
||
module (ras);
|
||
module (tiff);
|
||
module (xpm);
|
||
module (xbm);
|
||
module (tga);
|
||
module (pcx);
|
||
|
||
gboolean
|
||
_gdk_pixbuf_load_module (GdkPixbufModule *image_module,
|
||
GError **error)
|
||
{
|
||
GdkPixbufModuleFillInfoFunc fill_info = NULL;
|
||
GdkPixbufModuleFillVtableFunc fill_vtable = NULL;
|
||
|
||
image_module->module = (void *) 1;
|
||
|
||
if (FALSE) {
|
||
/* Ugly hack so we can use else if unconditionally below ;-) */
|
||
}
|
||
|
||
#ifdef INCLUDE_png
|
||
else if (strcmp (image_module->module_name, "png") == 0) {
|
||
fill_info = MODULE_ENTRY (png, fill_info);
|
||
fill_vtable = MODULE_ENTRY (png, fill_vtable);
|
||
}
|
||
#endif
|
||
|
||
#ifdef INCLUDE_bmp
|
||
else if (strcmp (image_module->module_name, "bmp") == 0) {
|
||
fill_info = MODULE_ENTRY (bmp, fill_info);
|
||
fill_vtable = MODULE_ENTRY (bmp, fill_vtable);
|
||
}
|
||
#endif
|
||
|
||
#ifdef INCLUDE_wbmp
|
||
else if (strcmp (image_module->module_name, "wbmp") == 0) {
|
||
fill_info = MODULE_ENTRY (wbmp, fill_info);
|
||
fill_vtable = MODULE_ENTRY (wbmp, fill_vtable);
|
||
}
|
||
#endif
|
||
|
||
#ifdef INCLUDE_gif
|
||
else if (strcmp (image_module->module_name, "gif") == 0) {
|
||
fill_info = MODULE_ENTRY (gif, fill_info);
|
||
fill_vtable = MODULE_ENTRY (gif, fill_vtable);
|
||
}
|
||
#endif
|
||
|
||
#ifdef INCLUDE_ico
|
||
else if (strcmp (image_module->module_name, "ico") == 0) {
|
||
fill_info = MODULE_ENTRY (ico, fill_info);
|
||
fill_vtable = MODULE_ENTRY (ico, fill_vtable);
|
||
}
|
||
#endif
|
||
|
||
#ifdef INCLUDE_ani
|
||
else if (strcmp (image_module->module_name, "ani") == 0) {
|
||
fill_info = MODULE_ENTRY (ani, fill_info);
|
||
fill_vtable = MODULE_ENTRY (ani, fill_vtable);
|
||
}
|
||
#endif
|
||
|
||
#ifdef INCLUDE_jpeg
|
||
else if (strcmp (image_module->module_name, "jpeg") == 0) {
|
||
fill_info = MODULE_ENTRY (jpeg, fill_info);
|
||
fill_vtable = MODULE_ENTRY (jpeg, fill_vtable);
|
||
}
|
||
#endif
|
||
|
||
#ifdef INCLUDE_pnm
|
||
else if (strcmp (image_module->module_name, "pnm") == 0) {
|
||
fill_info = MODULE_ENTRY (pnm, fill_info);
|
||
fill_vtable = MODULE_ENTRY (pnm, fill_vtable);
|
||
}
|
||
#endif
|
||
|
||
#ifdef INCLUDE_ras
|
||
else if (strcmp (image_module->module_name, "ras") == 0) {
|
||
fill_info = MODULE_ENTRY (ras, fill_info);
|
||
fill_vtable = MODULE_ENTRY (ras, fill_vtable);
|
||
}
|
||
#endif
|
||
|
||
#ifdef INCLUDE_tiff
|
||
else if (strcmp (image_module->module_name, "tiff") == 0) {
|
||
fill_info = MODULE_ENTRY (tiff, fill_info);
|
||
fill_vtable = MODULE_ENTRY (tiff, fill_vtable);
|
||
}
|
||
#endif
|
||
|
||
#ifdef INCLUDE_xpm
|
||
else if (strcmp (image_module->module_name, "xpm") == 0) {
|
||
fill_info = MODULE_ENTRY (xpm, fill_info);
|
||
fill_vtable = MODULE_ENTRY (xpm, fill_vtable);
|
||
}
|
||
#endif
|
||
|
||
#ifdef INCLUDE_xbm
|
||
else if (strcmp (image_module->module_name, "xbm") == 0) {
|
||
fill_info = MODULE_ENTRY (xbm, fill_info);
|
||
fill_vtable = MODULE_ENTRY (xbm, fill_vtable);
|
||
}
|
||
#endif
|
||
|
||
#ifdef INCLUDE_tga
|
||
else if (strcmp (image_module->module_name, "tga") == 0) {
|
||
fill_info = MODULE_ENTRY (tga, fill_info);
|
||
fill_vtable = MODULE_ENTRY (tga, fill_vtable);
|
||
}
|
||
#endif
|
||
|
||
#ifdef INCLUDE_pcx
|
||
else if (strcmp (image_module->module_name, "pcx") == 0) {
|
||
fill_info = MODULE_ENTRY (pcx, fill_info);
|
||
fill_vtable = MODULE_ENTRY (pcx, fill_vtable);
|
||
}
|
||
#endif
|
||
|
||
if (fill_vtable) {
|
||
(* fill_vtable) (image_module);
|
||
image_module->info = g_new0 (GdkPixbufFormat, 1);
|
||
(* fill_info) (image_module->info);
|
||
|
||
return TRUE;
|
||
} 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;
|
||
}
|
||
}
|
||
|
||
static void
|
||
gdk_pixbuf_io_init ()
|
||
{
|
||
gchar *included_formats[] = {
|
||
"ani", "png", "bmp", "wbmp", "gif",
|
||
"ico", "jpeg", "pnm", "ras", "tiff",
|
||
"xpm", "xbm", "tga", "pcx",
|
||
NULL
|
||
};
|
||
gchar **name;
|
||
GdkPixbufModule *module = NULL;
|
||
|
||
for (name = included_formats; *name; name++) {
|
||
module = g_new0 (GdkPixbufModule, 1);
|
||
module->module_name = *name;
|
||
if (_gdk_pixbuf_load_module (module, NULL))
|
||
file_formats = g_slist_prepend (file_formats, module);
|
||
else
|
||
g_free (module);
|
||
}
|
||
}
|
||
|
||
#endif /* !USE_GMODULE */
|
||
|
||
|
||
|
||
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;
|
||
|
||
gint score, best = 0;
|
||
GdkPixbufModule *selected = NULL;
|
||
gchar *display_name = NULL;
|
||
|
||
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;
|
||
}
|
||
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 (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[4096];
|
||
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 [128];
|
||
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) {
|
||
g_set_error (error,
|
||
G_FILE_ERROR,
|
||
g_file_error_from_errno (errno),
|
||
_("Failed to open file '%s': %s"),
|
||
display_name,
|
||
g_strerror (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 (image_module->module == 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
|
||
|
||
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) {
|
||
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 {
|
||
width = info->width;
|
||
height = info->height;
|
||
}
|
||
|
||
gdk_pixbuf_loader_set_size (loader, width, height);
|
||
}
|
||
|
||
/**
|
||
* 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
|
||
* @height: The height the image should have
|
||
* @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.
|
||
*
|
||
* 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
|
||
|
||
/**
|
||
* 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
|
||
* @height: The height the image should have
|
||
* @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.
|
||
*
|
||
* 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 [4096];
|
||
int length;
|
||
FILE *f;
|
||
struct {
|
||
gint width;
|
||
gint height;
|
||
gboolean preserve_aspect_ratio;
|
||
} info;
|
||
|
||
g_return_val_if_fail (filename != NULL, NULL);
|
||
g_return_val_if_fail (width > 0 && height > 0, NULL);
|
||
|
||
f = g_fopen (filename, "rb");
|
||
if (!f) {
|
||
gchar *display_name = g_filename_display_name (filename);
|
||
g_set_error (error,
|
||
G_FILE_ERROR,
|
||
g_file_error_from_errno (errno),
|
||
_("Failed to open file '%s': %s"),
|
||
display_name,
|
||
g_strerror (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 (size_prepared_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, error)) {
|
||
gdk_pixbuf_loader_close (loader, NULL);
|
||
fclose (f);
|
||
g_object_unref (loader);
|
||
return NULL;
|
||
}
|
||
}
|
||
|
||
fclose (f);
|
||
|
||
if (!gdk_pixbuf_loader_close (loader, error)) {
|
||
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 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 [4096];
|
||
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;
|
||
|
||
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 (xpm_module->module == 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) {
|
||
g_set_error (error,
|
||
G_FILE_ERROR,
|
||
g_file_error_from_errno (errno),
|
||
_("Error writing to image file: %s"),
|
||
g_strerror (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 (image_module->module == NULL)
|
||
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 (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) {
|
||
g_set_error (error,
|
||
G_FILE_ERROR,
|
||
g_file_error_from_errno (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)) {
|
||
g_set_error (error,
|
||
G_FILE_ERROR,
|
||
g_file_error_from_errno (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 (image_module->module == NULL)
|
||
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: 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" and
|
||
* "ico" 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:
|
||
*
|
||
* <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 *writable_formats = NULL;
|
||
* 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.
|
||
*
|
||
* 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.
|
||
* 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;
|
||
}
|
||
|
||
/**
|
||
* 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: return location for error, or %NULL
|
||
*
|
||
* Saves pixbuf to a file in @type, which is currently "jpeg", "png" or "ico".
|
||
* 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) {
|
||
gchar *display_name = g_filename_display_name (filename);
|
||
g_set_error (error,
|
||
G_FILE_ERROR,
|
||
g_file_error_from_errno (errno),
|
||
_("Failed to open '%s' for writing: %s"),
|
||
display_name,
|
||
g_strerror (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);
|
||
return FALSE;
|
||
}
|
||
|
||
if (fclose (f) < 0) {
|
||
gchar *display_name = g_filename_display_name (filename);
|
||
g_set_error (error,
|
||
G_FILE_ERROR,
|
||
g_file_error_from_errno (errno),
|
||
_("Failed to close '%s' while writing image, all data may not have been saved: %s"),
|
||
display_name,
|
||
g_strerror (errno));
|
||
g_free (display_name);
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/**
|
||
* 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: 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: return location for error, or %NULL
|
||
*
|
||
* Saves pixbuf to a callback in format @type, which is currently "jpeg",
|
||
* "png" or "ico". 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: 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" or "ico". 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 @string 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 (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: return location for error, or %NULL
|
||
*
|
||
* Saves pixbuf to a new buffer in format @type, which is currently "jpeg",
|
||
* "png" or "ico". 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 (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;
|
||
}
|
||
|
||
/**
|
||
* 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;
|
||
gchar *description;
|
||
g_return_val_if_fail (format != NULL, NULL);
|
||
|
||
if (format->domain != NULL)
|
||
domain = format->domain;
|
||
else
|
||
domain = GETTEXT_PACKAGE;
|
||
description = 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.
|
||
*
|
||
* 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;
|
||
}
|
||
|
||
|
||
|
||
|
||
|