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