source: trunk/third/gtk2/gdk-pixbuf/gdk-pixbuf-io.c @ 18785

Revision 18785, 30.2 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18784, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- mode: C; c-file-style: "linux" -*- */
2/* GdkPixbuf library - Main loading interface.
3 *
4 * Copyright (C) 1999 The Free Software Foundation
5 *
6 * Authors: Miguel de Icaza <miguel@gnu.org>
7 *          Federico Mena-Quintero <federico@gimp.org>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
23 */
24
25#include <config.h>
26#include <stdlib.h>
27#include <stdio.h>
28#include <string.h>
29#include <glib.h>
30#include <errno.h>
31#include "gdk-pixbuf-private.h"
32#include "gdk-pixbuf-io.h"
33
34#ifdef G_OS_WIN32
35#define STRICT
36#include <windows.h>
37#undef STRICT
38#endif
39
40static gint
41format_check (GdkPixbufModule *module, guchar *buffer, int size)
42{
43        int j;
44        gchar m;
45        GdkPixbufModulePattern *pattern;
46
47        for (pattern = module->info->signature; pattern->prefix; pattern++) {
48                for (j = 0; j < size && pattern->prefix[j] != 0; j++) {
49                        m = pattern->mask ? pattern->mask[j] : ' ';
50                        if (m == ' ') {
51                                if (buffer[j] != pattern->prefix[j])
52                                        break;
53                        }
54                        else if (m == '!') {
55                                if (buffer[j] == pattern->prefix[j])
56                                        break;
57                        }
58                        else if (m == 'z') {
59                                if (buffer[j] != 0)
60                                        break;
61                        }
62                        else if (m == 'n') {
63                                if (buffer[j] == 0)
64                                        break;
65                        }
66                }
67                if (pattern->prefix[j] == 0)
68                        return pattern->relevance;
69        }
70        return 0;
71}
72
73static GSList *file_formats = NULL;
74
75static void gdk_pixbuf_io_init ();
76
77static GSList *
78get_file_formats ()
79{
80        if (file_formats == NULL)
81                gdk_pixbuf_io_init ();
82       
83        return file_formats;
84}
85
86
87#ifdef USE_GMODULE
88
89static gboolean
90scan_string (const char **pos, GString *out)
91{
92        const char *p = *pos, *q = *pos;
93        char *tmp, *tmp2;
94        gboolean quoted;
95       
96        while (g_ascii_isspace (*p))
97                p++;
98       
99        if (!*p)
100                return FALSE;
101        else if (*p == '"') {
102                p++;
103                quoted = FALSE;
104                for (q = p; (*q != '"') || quoted; q++) {
105                        if (!*q)
106                                return FALSE;
107                        quoted = (*q == '\\') && !quoted;
108                }
109               
110                tmp = g_strndup (p, q - p);
111                tmp2 = g_strcompress (tmp);
112                g_string_truncate (out, 0);
113                g_string_append (out, tmp2);
114                g_free (tmp);
115                g_free (tmp2);
116        }
117       
118        q++;
119        *pos = q;
120       
121        return TRUE;
122}
123
124static gboolean
125scan_int (const char **pos, int *out)
126{
127        int i = 0;
128        char buf[32];
129        const char *p = *pos;
130       
131        while (g_ascii_isspace (*p))
132                p++;
133       
134        if (*p < '0' || *p > '9')
135                return FALSE;
136       
137        while ((*p >= '0') && (*p <= '9') && i < sizeof (buf)) {
138                buf[i] = *p;
139                i++;
140                p++;
141        }
142       
143        if (i == sizeof (buf))
144                return FALSE;
145        else
146                buf[i] = '\0';
147       
148        *out = atoi (buf);
149       
150        *pos = p;
151
152        return TRUE;
153}
154
155static gboolean
156skip_space (const char **pos)
157{
158        const char *p = *pos;
159       
160        while (g_ascii_isspace (*p))
161                p++;
162 
163        *pos = p;
164       
165        return !(*p == '\0');
166}
167 
168#ifdef G_OS_WIN32
169
170/* DllMain function needed to tuck away the gdk-pixbuf DLL name */
171G_WIN32_DLLMAIN_FOR_DLL_NAME (static, dll_name)
172
173static char *
174get_toplevel (void)
175{
176  static char *toplevel = NULL;
177
178  if (toplevel == NULL)
179    toplevel = g_win32_get_package_installation_subdirectory
180      (GETTEXT_PACKAGE, dll_name, "");
181
182  return toplevel;
183}
184
185static char *
186get_sysconfdir (void)
187{
188  static char *sysconfdir = NULL;
189
190  if (sysconfdir == NULL)
191    sysconfdir = g_win32_get_package_installation_subdirectory
192      (GETTEXT_PACKAGE, dll_name, "etc");
193
194  return sysconfdir;
195}
196
197#undef GTK_SYSCONFDIR
198#define GTK_SYSCONFDIR get_sysconfdir()
199
200static void
201correct_prefix (gchar **path)
202{
203  if (strncmp (*path, PREFIX "/", strlen (PREFIX "/")) == 0 ||
204      strncmp (*path, PREFIX "\\", strlen (PREFIX "\\")) == 0)
205    {
206      /* This is an entry put there by gdk-pixbuf-query-loaders on the
207       * packager's system. On Windows a prebuilt GTK+ package can be
208       * installed in a random location. The gdk-pixbuf.loaders file
209       * distributed in such a package contains paths from the package
210       * builder's machine. Replace the build-time prefix with the
211       * installation prefix on this machine.
212       */
213      gchar *tem = *path;
214      *path = g_strconcat (get_toplevel (), tem + strlen (PREFIX), NULL);
215      g_free (tem);
216    }
217}
218
219#endif
220
221static gchar *
222gdk_pixbuf_get_module_file (void)
223{
224  gchar *result = g_strdup (g_getenv ("GDK_PIXBUF_MODULE_FILE"));
225
226  if (!result)
227          result = g_build_filename (GTK_SYSCONFDIR, "gtk-2.0", "gdk-pixbuf.loaders", NULL);
228
229  return result;
230}
231
232static void
233gdk_pixbuf_io_init ()
234{
235        GIOChannel *channel;
236        gchar *line_buf;
237        gsize term;
238        GString *tmp_buf = g_string_new (NULL);
239        gboolean have_error = FALSE;
240        GdkPixbufModule *module = NULL;
241        gchar *filename = gdk_pixbuf_get_module_file ();
242        int flags;
243        int n_patterns = 0;
244        GdkPixbufModulePattern *pattern;
245        GError *error = NULL;
246
247        channel = g_io_channel_new_file (filename, "r",  &error);
248        if (!channel) {
249                g_warning ("Can not open pixbuf loader module file '%s': %s",
250                           filename, error->message);
251                return;
252        }
253       
254        while (!have_error && g_io_channel_read_line (channel, &line_buf, NULL, &term, NULL) == G_IO_STATUS_NORMAL) {
255                const char *p;
256               
257                p = line_buf;
258
259                line_buf[term] = 0;
260
261                if (!skip_space (&p)) {
262                                /* Blank line marking the end of a module
263                                 */
264                        if (module && *p != '#') {
265#ifdef G_OS_WIN32
266                                correct_prefix (&module->module_path);
267#endif
268                                file_formats = g_slist_prepend (file_formats, module);
269                                module = NULL;
270                        }
271                       
272                        goto next_line;
273                }
274
275                if (*p == '#')
276                        goto next_line;
277               
278                if (!module) {
279                                /* Read a module location
280                                 */
281                        module = g_new0 (GdkPixbufModule, 1);
282                        n_patterns = 0;
283                       
284                        if (!scan_string (&p, tmp_buf)) {
285                                g_warning ("Error parsing loader info in '%s'\n  %s",
286                                           filename, line_buf);
287                                have_error = TRUE;
288                        }
289                        module->module_path = g_strdup (tmp_buf->str);
290                }
291                else if (!module->module_name) {
292                        module->info = g_new0 (GdkPixbufFormat, 1);
293                        if (!scan_string (&p, tmp_buf)) {
294                                g_warning ("Error parsing loader info in '%s'\n  %s",
295                                           filename, line_buf);
296                                have_error = TRUE;
297                        }
298                        module->info->name =  g_strdup (tmp_buf->str);
299                        module->module_name = module->info->name;
300
301                        if (!scan_int (&p, &flags)) {
302                                g_warning ("Error parsing loader info in '%s'\n  %s",
303                                           filename, line_buf);
304                                have_error = TRUE;
305                        }
306                        module->info->flags = flags;
307                       
308                        if (!scan_string (&p, tmp_buf)) {
309                                g_warning ("Error parsing loader info in '%s'\n  %s",
310                                           filename, line_buf);
311                                have_error = TRUE;
312                        }                       
313                        if (tmp_buf->str[0] != 0)
314                                module->info->domain = g_strdup (tmp_buf->str);
315
316                        if (!scan_string (&p, tmp_buf)) {
317                                g_warning ("Error parsing loader info in '%s'\n  %s",
318                                           filename, line_buf);
319                                have_error = TRUE;
320                        }                       
321                        module->info->description = g_strdup (tmp_buf->str);
322                }
323                else if (!module->info->mime_types) {
324                        int n = 1;
325                        module->info->mime_types = g_new0 (gchar*, 1);
326                        while (scan_string (&p, tmp_buf)) {
327                                if (tmp_buf->str[0] != 0) {
328                                        module->info->mime_types =
329                                                g_realloc (module->info->mime_types, (n + 1) * sizeof (gchar*));
330                                        module->info->mime_types[n - 1] = g_strdup (tmp_buf->str);
331                                        module->info->mime_types[n] = 0;
332                                        n++;
333                                }
334                        }
335                }
336                else if (!module->info->extensions) {
337                        int n = 1;
338                        module->info->extensions = g_new0 (gchar*, 1);
339                        while (scan_string (&p, tmp_buf)) {
340                                if (tmp_buf->str[0] != 0) {
341                                        module->info->extensions =
342                                                g_realloc (module->info->extensions, (n + 1) * sizeof (gchar*));
343                                        module->info->extensions[n - 1] = g_strdup (tmp_buf->str);
344                                        module->info->extensions[n] = 0;
345                                        n++;
346                                }
347                        }
348                }
349                else {
350                        n_patterns++;
351                        module->info->signature = (GdkPixbufModulePattern *)
352                                g_realloc (module->info->signature, (n_patterns + 1) * sizeof (GdkPixbufModulePattern));
353                        pattern = module->info->signature + n_patterns;
354                        pattern->prefix = NULL;
355                        pattern->mask = NULL;
356                        pattern->relevance = 0;
357                        pattern--;
358                        if (!scan_string (&p, tmp_buf))
359                                goto context_error;
360                        pattern->prefix = g_strdup (tmp_buf->str);
361                       
362                        if (!scan_string (&p, tmp_buf))
363                                goto context_error;
364                        if (*tmp_buf->str)
365                                pattern->mask = g_strdup (tmp_buf->str);
366                        else
367                                pattern->mask = NULL;
368                       
369                        if (!scan_int (&p, &pattern->relevance))
370                                goto context_error;
371                       
372                        goto next_line;
373
374                context_error:
375                        g_free (pattern->prefix);
376                        g_free (pattern->mask);
377                        g_free (pattern);
378                        g_warning ("Error parsing loader info in '%s'\n  %s",
379                                   filename, line_buf);
380                        have_error = TRUE;
381                }
382        next_line:
383                g_free (line_buf);
384        }
385        g_string_free (tmp_buf, TRUE);
386        g_io_channel_unref (channel);
387        g_free (filename);
388}
389
390/* actually load the image handler - gdk_pixbuf_get_module only get a */
391/* reference to the module to load, it doesn't actually load it       */
392/* perhaps these actions should be combined in one function           */
393gboolean
394_gdk_pixbuf_load_module (GdkPixbufModule *image_module,
395                         GError         **error)
396{
397        char *path;
398        GModule *module;
399        gpointer sym;
400       
401        g_return_val_if_fail (image_module->module == NULL, FALSE);
402
403        path = image_module->module_path;
404        module = g_module_open (path, G_MODULE_BIND_LAZY);
405
406        if (!module) {
407                g_set_error (error,
408                             GDK_PIXBUF_ERROR,
409                             GDK_PIXBUF_ERROR_FAILED,
410                             _("Unable to load image-loading module: %s: %s"),
411                             path, g_module_error ());
412                return FALSE;
413        }
414
415        image_module->module = module;       
416       
417        if (g_module_symbol (module, "fill_vtable", &sym)) {
418                GdkPixbufModuleFillVtableFunc func = (GdkPixbufModuleFillVtableFunc) sym;
419                (* func) (image_module);
420                return TRUE;
421        } else {
422                g_set_error (error,
423                             GDK_PIXBUF_ERROR,
424                             GDK_PIXBUF_ERROR_FAILED,
425                             _("Image-loading module %s does not export the proper interface; perhaps it's from a different GTK version?"),
426                             path);
427                return FALSE;
428        }
429}
430#else
431
432#define module(type) \
433  extern void MODULE_ENTRY (type, fill_info)   (GdkPixbufFormat *info);   \
434  extern void MODULE_ENTRY (type, fill_vtable) (GdkPixbufModule *module)
435
436module (png);
437module (bmp);
438module (wbmp);
439module (gif);
440module (ico);
441module (ani);
442module (jpeg);
443module (pnm);
444module (ras);
445module (tiff);
446module (xpm);
447module (xbm);
448module (tga);
449
450gboolean
451_gdk_pixbuf_load_module (GdkPixbufModule *image_module,
452                         GError         **error)
453{
454        GdkPixbufModuleFillInfoFunc fill_info = NULL;
455        GdkPixbufModuleFillVtableFunc fill_vtable = NULL;
456
457        image_module->module = (void *) 1;
458
459        if (FALSE) {
460                /* Ugly hack so we can use else if unconditionally below ;-) */
461        }
462       
463#ifdef INCLUDE_png     
464        else if (strcmp (image_module->module_name, "png") == 0) {
465                fill_info = MODULE_ENTRY (png, fill_info);
466                fill_vtable = MODULE_ENTRY (png, fill_vtable);
467        }
468#endif
469
470#ifdef INCLUDE_bmp     
471        else if (strcmp (image_module->module_name, "bmp") == 0) {
472                fill_info = MODULE_ENTRY (bmp, fill_info);
473                fill_vtable = MODULE_ENTRY (bmp, fill_vtable);
474        }
475#endif
476
477#ifdef INCLUDE_wbmp
478        else if (strcmp (image_module->module_name, "wbmp") == 0) {
479                fill_info = MODULE_ENTRY (wbmp, fill_info);
480                fill_vtable = MODULE_ENTRY (wbmp, fill_vtable);
481        }
482#endif
483
484#ifdef INCLUDE_gif
485        else if (strcmp (image_module->module_name, "gif") == 0) {
486                fill_info = MODULE_ENTRY (gif, fill_info);
487                fill_vtable = MODULE_ENTRY (gif, fill_vtable);
488        }
489#endif
490
491#ifdef INCLUDE_ico
492        else if (strcmp (image_module->module_name, "ico") == 0) {
493                fill_info = MODULE_ENTRY (ico, fill_info);
494                fill_vtable = MODULE_ENTRY (ico, fill_vtable);
495        }
496#endif
497
498#ifdef INCLUDE_ani
499        else if (strcmp (image_module->module_name, "ani") == 0) {
500                fill_info = MODULE_ENTRY (ani, fill_info);
501                fill_vtable = MODULE_ENTRY (ani, fill_vtable);
502        }
503#endif
504
505#ifdef INCLUDE_jpeg
506        else if (strcmp (image_module->module_name, "jpeg") == 0) {
507                fill_info = MODULE_ENTRY (jpeg, fill_info);
508                fill_vtable = MODULE_ENTRY (jpeg, fill_vtable);
509        }
510#endif
511
512#ifdef INCLUDE_pnm
513        else if (strcmp (image_module->module_name, "pnm") == 0) {
514                fill_info = MODULE_ENTRY (pnm, fill_info);
515                fill_vtable = MODULE_ENTRY (pnm, fill_vtable);
516        }
517#endif
518
519#ifdef INCLUDE_ras
520        else if (strcmp (image_module->module_name, "ras") == 0) {
521                fill_info = MODULE_ENTRY (ras, fill_info);
522                fill_vtable = MODULE_ENTRY (ras, fill_vtable);
523        }
524#endif
525
526#ifdef INCLUDE_tiff
527        else if (strcmp (image_module->module_name, "tiff") == 0) {
528                fill_info = MODULE_ENTRY (tiff, fill_info);
529                fill_vtable = MODULE_ENTRY (tiff, fill_vtable);
530        }
531#endif
532
533#ifdef INCLUDE_xpm
534        else if (strcmp (image_module->module_name, "xpm") == 0) {
535                fill_info = MODULE_ENTRY (xpm, fill_info);
536                fill_vtable = MODULE_ENTRY (xpm, fill_vtable);
537        }
538#endif
539
540#ifdef INCLUDE_xbm
541        else if (strcmp (image_module->module_name, "xbm") == 0) {
542                fill_info = MODULE_ENTRY (xbm, fill_info);
543                fill_vtable = MODULE_ENTRY (xbm, fill_vtable);
544        }
545#endif
546
547#ifdef INCLUDE_tga
548        else if (strcmp (image_module->module_name, "tga") == 0) {
549                fill_info = MODULE_ENTRY (tga, fill_info);
550                fill_vtable = MODULE_ENTRY (tga, fill_vtable);
551        }
552#endif
553       
554        if (fill_vtable) {
555                (* fill_vtable) (image_module);
556                image_module->info = g_new0 (GdkPixbufFormat, 1);
557                (* fill_info) (image_module->info);
558
559                return TRUE;
560        } else {
561                g_set_error (error,
562                             GDK_PIXBUF_ERROR,
563                             GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
564                             _("Image type '%s' is not supported"),
565                             image_module->module_name);
566
567                return FALSE;
568        }
569}
570
571static void
572gdk_pixbuf_io_init ()
573{
574        gchar *included_formats[] = {
575                "ani", "png", "bmp", "wbmp", "gif",
576                "ico", "jpeg", "pnm", "ras", "tiff",
577                "xpm", "xbm", "tga",
578                NULL
579        };
580        gchar **name;
581        GdkPixbufModule *module = NULL;
582       
583        for (name = included_formats; *name; name++) {
584                module = g_new0 (GdkPixbufModule, 1);
585                module->module_name = *name;
586                if (_gdk_pixbuf_load_module (module, NULL))
587                        file_formats = g_slist_prepend (file_formats, module);
588                else
589                        g_free (module);
590        }
591}
592
593#endif
594
595
596
597GdkPixbufModule *
598_gdk_pixbuf_get_named_module (const char *name,
599                              GError **error)
600{
601        GSList *modules;
602
603        for (modules = get_file_formats (); modules; modules = g_slist_next (modules)) {
604                GdkPixbufModule *module = (GdkPixbufModule *)modules->data;
605                if (!strcmp (name, module->module_name))
606                        return module;
607        }
608
609        g_set_error (error,
610                     GDK_PIXBUF_ERROR,
611                     GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
612                     _("Image type '%s' is not supported"),
613                     name);
614       
615        return NULL;
616}
617
618GdkPixbufModule *
619_gdk_pixbuf_get_module (guchar *buffer, guint size,
620                        const gchar *filename,
621                        GError **error)
622{
623        GSList *modules;
624
625        gint score, best = 0;
626        GdkPixbufModule *selected = NULL;
627        for (modules = get_file_formats (); modules; modules = g_slist_next (modules)) {
628                GdkPixbufModule *module = (GdkPixbufModule *)modules->data;
629                score = format_check (module, buffer, size);
630                if (score > best) {
631                        best = score;
632                        selected = module;
633                }
634                if (score >= 100)
635                        break;
636        }
637        if (selected != NULL)
638                return selected;
639
640        if (filename)
641                g_set_error (error,
642                             GDK_PIXBUF_ERROR,
643                             GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
644                             _("Couldn't recognize the image file format for file '%s'"),
645                             filename);       
646        else
647                g_set_error (error,
648                             GDK_PIXBUF_ERROR,
649                             GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
650                             _("Unrecognized image file format"));
651
652       
653        return NULL;
654}
655
656
657static void
658prepared_notify (GdkPixbuf *pixbuf,
659                 GdkPixbufAnimation *anim,
660                 gpointer user_data)
661{
662        if (pixbuf != NULL)
663                g_object_ref (pixbuf);
664        *((GdkPixbuf **)user_data) = pixbuf;
665}
666
667GdkPixbuf *
668_gdk_pixbuf_generic_image_load (GdkPixbufModule *module,
669                                FILE *f,
670                                GError **error)
671{
672        guchar buffer[4096];
673        size_t length;
674        GdkPixbuf *pixbuf = NULL;
675        gpointer context;
676
677        if (module->load != NULL)
678                return (* module->load) (f, error);
679       
680        context = module->begin_load (NULL, prepared_notify, NULL, &pixbuf, error);
681       
682        if (!context)
683                return NULL;
684       
685        while (!feof (f)) {
686                length = fread (buffer, 1, sizeof (buffer), f);
687                if (length > 0)
688                        if (!module->load_increment (context, buffer, length, error)) {
689                                module->stop_load (context, NULL);
690                                if (pixbuf != NULL)
691                                        g_object_unref (pixbuf);
692                                return NULL;
693                        }
694        }
695
696        if (!module->stop_load (context, error)) {
697                if (pixbuf != NULL)
698                        g_object_unref (pixbuf);
699                return NULL;
700        }
701       
702        return pixbuf;
703}
704
705/**
706 * gdk_pixbuf_new_from_file:
707 * @filename: Name of file to load.
708 * @error: Return location for an error
709 *
710 * Creates a new pixbuf by loading an image from a file.  The file format is
711 * detected automatically. If %NULL is returned, then @error will be set.
712 * Possible errors are in the #GDK_PIXBUF_ERROR and #G_FILE_ERROR domains.
713 *
714 * Return value: A newly-created pixbuf with a reference count of 1, or %NULL if
715 * any of several error conditions occurred:  the file could not be opened,
716 * there was no loader for the file's format, there was not enough memory to
717 * allocate the image buffer, or the image file contained invalid data.
718 **/
719GdkPixbuf *
720gdk_pixbuf_new_from_file (const char *filename,
721                          GError    **error)
722{
723        GdkPixbuf *pixbuf;
724        int size;
725        FILE *f;
726        guchar buffer [128];
727        GdkPixbufModule *image_module;
728
729        g_return_val_if_fail (filename != NULL, NULL);
730
731        f = fopen (filename, "rb");
732        if (!f) {
733                g_set_error (error,
734                             G_FILE_ERROR,
735                             g_file_error_from_errno (errno),
736                             _("Failed to open file '%s': %s"),
737                             filename, g_strerror (errno));
738                return NULL;
739        }
740
741        size = fread (&buffer, 1, sizeof (buffer), f);
742        if (size == 0) {
743                g_set_error (error,
744                             GDK_PIXBUF_ERROR,
745                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
746                             _("Image file '%s' contains no data"),
747                             filename);
748               
749                fclose (f);
750                return NULL;
751        }
752
753        image_module = _gdk_pixbuf_get_module (buffer, size, filename, error);
754        if (image_module == NULL) {
755                fclose (f);
756                return NULL;
757        }
758
759        if (image_module->module == NULL)
760                if (!_gdk_pixbuf_load_module (image_module, error)) {
761                        fclose (f);
762                        return NULL;
763                }
764
765        fseek (f, 0, SEEK_SET);
766        pixbuf = _gdk_pixbuf_generic_image_load (image_module, f, error);
767        fclose (f);
768
769        if (pixbuf == NULL && error != NULL && *error == NULL) {
770                /* I don't trust these crufty longjmp()'ing image libs
771                 * to maintain proper error invariants, and I don't
772                 * want user code to segfault as a result. We need to maintain
773                 * the invariastable/gdk-pixbuf/nt that error gets set if NULL is returned.
774                 */
775               
776                g_warning ("Bug! gdk-pixbuf loader '%s' didn't set an error on failure.", image_module->module_name);
777                g_set_error (error,
778                             GDK_PIXBUF_ERROR,
779                             GDK_PIXBUF_ERROR_FAILED,
780                             _("Failed to load image '%s': reason not known, probably a corrupt image file"),
781                             filename);
782               
783        } else if (error != NULL && *error != NULL) {
784
785          /* Add the filename to the error message */
786          GError *e = *error;
787          gchar *old;
788         
789          old = e->message;
790
791          e->message = g_strdup_printf (_("Failed to load image '%s': %s"),
792                                        filename, old);
793
794          g_free (old);
795        }
796               
797        return pixbuf;
798}
799
800/**
801 * gdk_pixbuf_new_from_xpm_data:
802 * @data: Pointer to inline XPM data.
803 *
804 * Creates a new pixbuf by parsing XPM data in memory.  This data is commonly
805 * the result of including an XPM file into a program's C source.
806 *
807 * Return value: A newly-created pixbuf with a reference count of 1.
808 **/
809GdkPixbuf *
810gdk_pixbuf_new_from_xpm_data (const char **data)
811{
812        GdkPixbuf *(* load_xpm_data) (const char **data);
813        GdkPixbuf *pixbuf;
814        GError *error = NULL;
815        GdkPixbufModule *xpm_module = _gdk_pixbuf_get_named_module ("xpm", &error);
816        if (xpm_module == NULL) {
817                g_warning ("Error loading XPM image loader: %s", error->message);
818                g_error_free (error);
819                return NULL;
820        }
821
822        if (xpm_module->module == NULL) {
823                if (!_gdk_pixbuf_load_module (xpm_module, &error)) {
824                        g_warning ("Error loading XPM image loader: %s", error->message);
825                        g_error_free (error);
826                        return NULL;
827                }
828        }
829         
830        if (xpm_module->load_xpm_data == NULL) {
831                g_warning ("gdk-pixbuf XPM module lacks XPM data capability");
832                return NULL;
833        } else
834                load_xpm_data = xpm_module->load_xpm_data;
835
836        pixbuf = (* load_xpm_data) (data);
837        return pixbuf;
838}
839
840static void
841collect_save_options (va_list   opts,
842                      gchar  ***keys,
843                      gchar  ***vals)
844{
845  gchar *key;
846  gchar *val;
847  gchar *next;
848  gint count;
849
850  count = 0;
851  *keys = NULL;
852  *vals = NULL;
853 
854  next = va_arg (opts, gchar*);
855  while (next)
856    {
857      key = next;
858      val = va_arg (opts, gchar*);
859
860      ++count;
861
862      /* woo, slow */
863      *keys = g_realloc (*keys, sizeof(gchar*) * (count + 1));
864      *vals = g_realloc (*vals, sizeof(gchar*) * (count + 1));
865     
866      (*keys)[count-1] = g_strdup (key);
867      (*vals)[count-1] = g_strdup (val);
868
869      (*keys)[count] = NULL;
870      (*vals)[count] = NULL;
871     
872      next = va_arg (opts, gchar*);
873    }
874}
875
876static gboolean
877gdk_pixbuf_real_save (GdkPixbuf     *pixbuf,
878                      FILE          *filehandle,
879                      const char    *type,
880                      gchar        **keys,
881                      gchar        **values,
882                      GError       **error)
883{
884       GdkPixbufModule *image_module = NULL;       
885
886       image_module = _gdk_pixbuf_get_named_module (type, error);
887
888       if (image_module == NULL)
889               return FALSE;
890       
891       if (image_module->module == NULL)
892               if (!_gdk_pixbuf_load_module (image_module, error))
893                       return FALSE;
894
895       if (image_module->save == NULL) {
896               g_set_error (error,
897                            GDK_PIXBUF_ERROR,
898                            GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
899                            _("This build of gdk-pixbuf does not support saving the image format: %s"),
900                            type);
901               return FALSE;
902       }
903               
904       return (* image_module->save) (filehandle, pixbuf,
905                                      keys, values,
906                                      error);
907}
908
909 
910/**
911 * gdk_pixbuf_save:
912 * @pixbuf: a #GdkPixbuf.
913 * @filename: name of file to save.
914 * @type: name of file format.
915 * @error: return location for error, or %NULL
916 * @Varargs: list of key-value save options
917 *
918 * Saves pixbuf to a file in @type, which is currently "jpeg" or
919 * "png".  If @error is set, %FALSE will be returned. Possible errors include
920 * those in the #GDK_PIXBUF_ERROR domain and those in the #G_FILE_ERROR domain.
921 *
922 * The variable argument list should be %NULL-terminated; if not empty,
923 * it should contain pairs of strings that modify the save
924 * parameters. For example:
925 * <informalexample><programlisting>
926 * gdk_pixbuf_save (pixbuf, handle, "jpeg", &amp;error,
927 *                  "quality", "100", NULL);
928 * </programlisting></informalexample>
929 *
930 * Currently only few parameters exist. JPEG images can be saved with a
931 * "quality" parameter; its value should be in the range [0,100].
932 * Text chunks can be attached to PNG images by specifying parameters of
933 * the form "tEXt::key", where key is an ASCII string of length 1-79.
934 * The values are UTF-8 encoded strings.
935 *
936 * Return value: whether an error was set
937 **/
938
939gboolean
940gdk_pixbuf_save (GdkPixbuf  *pixbuf,
941                 const char *filename,
942                 const char *type,
943                 GError    **error,
944                 ...)
945{
946        gchar **keys = NULL;
947        gchar **values = NULL;
948        va_list args;
949        gboolean result;
950       
951        va_start (args, error);
952       
953        collect_save_options (args, &keys, &values);
954       
955        va_end (args);
956
957        result = gdk_pixbuf_savev (pixbuf, filename, type,
958                                   keys, values,
959                                   error);
960
961        g_strfreev (keys);
962        g_strfreev (values);
963
964        return result;
965}
966
967/**
968 * gdk_pixbuf_savev:
969 * @pixbuf: a #GdkPixbuf.
970 * @filename: name of file to save.
971 * @type: name of file format.
972 * @option_keys: name of options to set, %NULL-terminated
973 * @option_values: values for named options
974 * @error: return location for error, or %NULL
975 *
976 * Saves pixbuf to a file in @type, which is currently "jpeg" or "png".
977 * If @error is set, %FALSE will be returned. See gdk_pixbuf_save () for more
978 * details.
979 *
980 * Return value: whether an error was set
981 **/
982
983gboolean
984gdk_pixbuf_savev (GdkPixbuf  *pixbuf,
985                  const char *filename,
986                  const char *type,
987                  char      **option_keys,
988                  char      **option_values,
989                  GError    **error)
990{
991        FILE *f = NULL;
992        gboolean result;
993       
994       
995        g_return_val_if_fail (filename != NULL, FALSE);
996        g_return_val_if_fail (type != NULL, FALSE);
997       
998        f = fopen (filename, "wb");
999       
1000        if (f == NULL) {
1001                g_set_error (error,
1002                             G_FILE_ERROR,
1003                             g_file_error_from_errno (errno),
1004                             _("Failed to open '%s' for writing: %s"),
1005                             filename, g_strerror (errno));
1006                return FALSE;
1007        }
1008
1009       
1010       result = gdk_pixbuf_real_save (pixbuf, f, type,
1011                                      option_keys, option_values,
1012                                      error);
1013       
1014       
1015       if (!result) {
1016               g_return_val_if_fail (error == NULL || *error != NULL, FALSE);
1017               fclose (f);
1018               return FALSE;
1019       }
1020
1021       if (fclose (f) < 0) {
1022               g_set_error (error,
1023                            G_FILE_ERROR,
1024                            g_file_error_from_errno (errno),
1025                            _("Failed to close '%s' while writing image, all data may not have been saved: %s"),
1026                            filename, g_strerror (errno));
1027               return FALSE;
1028       }
1029       
1030       return TRUE;
1031}
1032
1033/**
1034 * gdk_pixbuf_format_get_name:
1035 * @format: a #GdkPixbufFormat
1036 *
1037 * Returns the name of the format.
1038 *
1039 * Return value: the name of the format.
1040 *
1041 * Since: 2.2
1042 */
1043gchar *
1044gdk_pixbuf_format_get_name (GdkPixbufFormat *format)
1045{
1046        g_return_val_if_fail (format != NULL, NULL);
1047
1048        return g_strdup (format->name);
1049}
1050
1051/**
1052 * gdk_pixbuf_format_get_description:
1053 * @format: a #GdkPixbufFormat
1054 *
1055 * Returns a description of the format.
1056 *
1057 * Return value: a description of the format.
1058 *
1059 * Since: 2.2
1060 */
1061gchar *
1062gdk_pixbuf_format_get_description (GdkPixbufFormat *format)
1063{
1064        gchar *domain;
1065        gchar *description;
1066        g_return_val_if_fail (format != NULL, NULL);
1067
1068        if (format->domain != NULL)
1069                domain = format->domain;
1070        else
1071                domain = GETTEXT_PACKAGE;
1072        description = dgettext (domain, format->description);
1073
1074        return g_strdup (description);
1075}
1076
1077/**
1078 * gdk_pixbuf_format_get_mime_types:
1079 * @format: a #GdkPixbufFormat
1080 *
1081 * Returns the mime types supported by the format.
1082 *
1083 * Return value: a %NULL-terminated array of mime types.
1084 *
1085 * Since: 2.2
1086 */
1087gchar **
1088gdk_pixbuf_format_get_mime_types (GdkPixbufFormat *format)
1089{
1090        g_return_val_if_fail (format != NULL, NULL);
1091
1092        return g_strdupv (format->mime_types);
1093}
1094
1095/**
1096 * gdk_pixbuf_format_get_extensions:
1097 * @format: a #GdkPixbufFormat
1098 *
1099 * Returns the filename extensions typically used for files in the
1100 * given format.
1101 *
1102 * Return value: a %NULL-terminated array of filename extensions.
1103 *
1104 * Since: 2.2
1105 */
1106gchar **
1107gdk_pixbuf_format_get_extensions (GdkPixbufFormat *format)
1108{
1109        g_return_val_if_fail (format != NULL, NULL);
1110
1111        return g_strdupv (format->extensions);
1112}
1113
1114/**
1115 * gdk_pixbuf_format_is_writable:
1116 * @format: a #GdkPixbufFormat
1117 *
1118 * Returns whether pixbufs can be saved in the given format.
1119 *
1120 * Return value: whether pixbufs can be saved in the given format.
1121 *
1122 * Since: 2.2
1123 */
1124gboolean
1125gdk_pixbuf_format_is_writable (GdkPixbufFormat *format)
1126{
1127        g_return_val_if_fail (format != NULL, FALSE);
1128
1129        return (format->flags & GDK_PIXBUF_FORMAT_WRITABLE) != 0;
1130}
1131
1132GdkPixbufFormat *
1133_gdk_pixbuf_get_format (GdkPixbufModule *module)
1134{
1135        g_return_val_if_fail (module != NULL, NULL);
1136
1137        return module->info;
1138}
1139
1140/**
1141 * gdk_pixbuf_get_formats:
1142 *
1143 * Obtains the available information about the image formats supported
1144 * by GdkPixbuf.
1145 *
1146 * Returns: A list of #GdkPixbufFormat<!-- -->s describing the supported
1147 * image formats.  The list should be freed when it is no longer needed,
1148 * but the structures themselves are owned by #GdkPixbuf and should not be
1149 * freed. 
1150 *
1151 * Since: 2.2
1152 */
1153GSList *
1154gdk_pixbuf_get_formats (void)
1155{
1156        GSList *result = NULL;
1157        GSList *modules;
1158
1159        for (modules = get_file_formats (); modules; modules = g_slist_next (modules)) {
1160                GdkPixbufModule *module = (GdkPixbufModule *)modules->data;
1161                GdkPixbufFormat *info = _gdk_pixbuf_get_format (module);
1162                result = g_slist_prepend (result, info);
1163        }
1164
1165        return result;
1166}
1167
1168
1169
1170
1171
Note: See TracBrowser for help on using the repository browser.