]> Pileus Git - ~andy/gtk/blob - gdk-pixbuf/gdk-pixbuf-io.c
b050c25f7ed32c08f5371385a0592543aacdadf7
[~andy/gtk] / gdk-pixbuf / gdk-pixbuf-io.c
1 /* GdkPixbuf library - Main loading interface.
2  *
3  * Copyright (C) 1999 The Free Software Foundation
4  *
5  * Authors: Miguel de Icaza <miguel@gnu.org>
6  *          Federico Mena-Quintero <federico@gimp.org>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 #include <config.h>
25 #include <string.h>
26 #include <glib.h>
27 #include <errno.h>
28 #include "gdk-pixbuf-private.h"
29 #include "gdk-pixbuf-io.h"
30
31 #ifdef G_OS_WIN32
32 #define STRICT
33 #include <windows.h>
34 #endif
35
36 \f
37
38 static gboolean
39 pixbuf_check_png (guchar *buffer, int size)
40 {
41         if (size < 28)
42                 return FALSE;
43
44         if (buffer [0] != 0x89 ||
45             buffer [1] != 'P' ||
46             buffer [2] != 'N' ||
47             buffer [3] != 'G' ||
48             buffer [4] != 0x0d ||
49             buffer [5] != 0x0a ||
50             buffer [6] != 0x1a ||
51             buffer [7] != 0x0a)
52                 return FALSE;
53
54         return TRUE;
55 }
56
57 static gboolean
58 pixbuf_check_jpeg (guchar *buffer, int size)
59 {
60         if (size < 10)
61                 return FALSE;
62
63         if (buffer [0] != 0xff || buffer [1] != 0xd8)
64                 return FALSE;
65
66         return TRUE;
67 }
68
69 static gboolean
70 pixbuf_check_tiff (guchar *buffer, int size)
71 {
72         if (size < 10)
73                 return FALSE;
74
75         if (buffer [0] == 'M' &&
76             buffer [1] == 'M' &&
77             buffer [2] == 0   &&
78             buffer [3] == 0x2a)
79                 return TRUE;
80
81         if (buffer [0] == 'I' &&
82             buffer [1] == 'I' &&
83             buffer [2] == 0x2a &&
84             buffer [3] == 0)
85                 return TRUE;
86
87         return FALSE;
88 }
89
90 static gboolean
91 pixbuf_check_gif (guchar *buffer, int size)
92 {
93         if (size < 20)
94                 return FALSE;
95
96         if (strncmp (buffer, "GIF8", 4) == 0)
97                 return TRUE;
98
99         return FALSE;
100 }
101
102 static gboolean
103 pixbuf_check_xpm (guchar *buffer, int size)
104 {
105         if (size < 20)
106                 return FALSE;
107
108         if (strncmp (buffer, "/* XPM */", 9) == 0)
109                 return TRUE;
110
111         return FALSE;
112 }
113
114 static gboolean
115 pixbuf_check_pnm (guchar *buffer, int size)
116 {
117         if (size < 20)
118                 return FALSE;
119
120         if (buffer [0] == 'P') {
121                 if (buffer [1] == '1' ||
122                     buffer [1] == '2' ||
123                     buffer [1] == '3' ||
124                     buffer [1] == '4' ||
125                     buffer [1] == '5' ||
126                     buffer [1] == '6')
127                         return TRUE;
128         }
129         return FALSE;
130 }
131 static gboolean
132 pixbuf_check_sunras (guchar *buffer, int size)
133 {
134         if (size < 32)
135                 return FALSE;
136
137         if (buffer [0] != 0x59 ||
138             buffer [1] != 0xA6 ||
139             buffer [2] != 0x6A ||
140             buffer [3] != 0x95)
141                 return FALSE;
142
143         return TRUE;
144 }
145
146 static gboolean
147 pixbuf_check_ico (guchar *buffer, int size)
148 {
149         /* Note that this may cause false positives, but .ico's don't
150            have a magic number.*/
151         if (size < 6)
152                 return FALSE;
153         if (buffer [0] != 0x0 ||
154             buffer [1] != 0x0 ||
155             ((buffer [2] != 0x1)&&(buffer[2]!=0x2)) ||
156             buffer [3] != 0x0 ||
157             buffer [5] != 0x0 )
158                 return FALSE;
159
160         return TRUE;
161 }
162
163
164 static gboolean
165 pixbuf_check_bmp (guchar *buffer, int size)
166 {
167         if (size < 20)
168                 return FALSE;
169
170         if (buffer [0] != 'B' || buffer [1] != 'M')
171                 return FALSE;
172
173         return TRUE;
174 }
175
176 static gboolean
177 pixbuf_check_wbmp (guchar *buffer, int size)
178 {
179   if(size < 10) /* at least */
180     return FALSE;
181
182   if(buffer[0] == '\0' /* We only handle type 0 wbmp's for now */)
183     return TRUE;
184
185   return FALSE;
186 }
187
188 static GdkPixbufModule file_formats [] = {
189         { "png",  pixbuf_check_png, NULL,  NULL, NULL, NULL, NULL, NULL, NULL, },
190         { "jpeg", pixbuf_check_jpeg, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
191         { "tiff", pixbuf_check_tiff, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
192         { "gif",  pixbuf_check_gif, NULL,  NULL, NULL, NULL, NULL, NULL, NULL },
193 #define XPM_FILE_FORMAT_INDEX 4
194         { "xpm",  pixbuf_check_xpm, NULL,  NULL, NULL, NULL, NULL, NULL, NULL },
195         { "pnm",  pixbuf_check_pnm, NULL,  NULL, NULL, NULL, NULL, NULL, NULL },
196         { "ras",  pixbuf_check_sunras, NULL,  NULL, NULL, NULL, NULL, NULL, NULL },
197         { "ico",  pixbuf_check_ico, NULL,  NULL, NULL, NULL, NULL, NULL, NULL },
198         { "bmp",  pixbuf_check_bmp, NULL,  NULL, NULL, NULL, NULL, NULL, NULL },
199         { "wbmp", pixbuf_check_wbmp, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
200         { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
201 };
202
203 #ifdef USE_GMODULE 
204 static gboolean
205 pixbuf_module_symbol (GModule *module, const char *module_name, const char *symbol_name, gpointer *symbol)
206 {
207         char *full_symbol_name = g_strconcat ("gdk_pixbuf__", module_name, "_", symbol_name, NULL);
208         gboolean return_value;
209
210         return_value = g_module_symbol (module, full_symbol_name, symbol);
211         g_free (full_symbol_name);
212         
213         return return_value;
214 }
215
216 #ifdef G_OS_WIN32
217
218 /* What would be the right place for this function? Also
219  * gtk needs this function (to find the gtkrc and themes).
220  * But it seems stupid for the gdk-pixbuf DLL to depend
221  * on the gtk DLL. Should it be in the gdk DLL? Or should we
222  * have a small static library at the top gtk+ level?
223  */
224
225 static gchar *
226 gtk_win32_get_installation_directory (void)
227 {
228   static gboolean been_here = FALSE;
229   static gchar gtk_installation_dir[200];
230   gchar win_dir[100];
231   HKEY reg_key = NULL;
232   DWORD type;
233   DWORD nbytes = sizeof (gtk_installation_dir);
234
235   if (been_here)
236     return gtk_installation_dir;
237
238   been_here = TRUE;
239
240   if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\GNU\\GTk+", 0,
241                     KEY_QUERY_VALUE, &reg_key) != ERROR_SUCCESS
242       || RegQueryValueEx (reg_key, "InstallationDirectory", 0,
243                           &type, gtk_installation_dir, &nbytes) != ERROR_SUCCESS
244       || type != REG_SZ)
245     {
246       /* Uh oh. Use hard-coded %WinDir%\gtk+ value */
247       GetWindowsDirectory (win_dir, sizeof (win_dir));
248       sprintf (gtk_installation_dir, "%s\\gtk+", win_dir);
249     }
250
251   if (reg_key != NULL)
252     RegCloseKey (reg_key);
253
254   return gtk_installation_dir;
255 }
256
257 static char *
258 get_libdir (void)
259 {
260   static char *libdir = NULL;
261
262   if (libdir == NULL)
263     libdir = g_strdup_printf (gtk_win32_get_installation_directory (),
264                               G_DIR_SEPARATOR_S,
265                               "loaders",
266                               NULL);
267
268   return libdir;
269 }
270
271 #define PIXBUF_LIBDIR get_libdir ()
272
273 #endif
274
275 /* actually load the image handler - gdk_pixbuf_get_module only get a */
276 /* reference to the module to load, it doesn't actually load it       */
277 /* perhaps these actions should be combined in one function           */
278 gboolean
279 gdk_pixbuf_load_module (GdkPixbufModule *image_module,
280                         GError         **error)
281 {
282         char *module_name;
283         char *path;
284         GModule *module;
285         gpointer load_sym;
286         gpointer save_sym;
287         char *name;
288         
289         g_return_val_if_fail (image_module->module == NULL, FALSE);
290
291         name = image_module->module_name;
292         
293         module_name = g_strconcat ("pixbufloader-", name, NULL);
294         path = g_module_build_path (PIXBUF_LIBDIR, module_name);
295
296         module = g_module_open (path, G_MODULE_BIND_LAZY);
297         if (!module) {
298                 /* Debug feature, check in GDK_PIXBUF_MODULEDIR, or working directory */
299                 char *dir = g_getenv ("GDK_PIXBUF_MODULEDIR");
300                 if (!dir)
301                         dir = "";
302           
303                 g_free (path);
304                 path = g_module_build_path (dir, module_name);
305                 module = g_module_open (path, G_MODULE_BIND_LAZY);
306
307                 if (!module) {
308                         g_set_error (error,
309                                      GDK_PIXBUF_ERROR,
310                                      GDK_PIXBUF_ERROR_FAILED,
311                                      _("Unable to load image-loading module: %s: %s"),
312                                      path, g_module_error ());
313                         g_free (module_name);
314                         g_free (path);
315                         return FALSE;
316                 }
317                 g_free (path);
318         } else {
319                 g_free (path);
320         }
321
322         g_free (module_name);
323
324         image_module->module = module;
325
326         if (pixbuf_module_symbol (module, name, "image_load", &load_sym))
327                 image_module->load = load_sym;
328
329         if (pixbuf_module_symbol (module, name, "image_load_xpm_data", &load_sym))
330                 image_module->load_xpm_data = load_sym;
331
332         if (pixbuf_module_symbol (module, name, "image_begin_load", &load_sym))
333                 image_module->begin_load = load_sym;
334
335         if (pixbuf_module_symbol (module, name, "image_stop_load", &load_sym))
336                 image_module->stop_load = load_sym;
337
338         if (pixbuf_module_symbol (module, name, "image_load_increment", &load_sym))
339                 image_module->load_increment = load_sym;
340
341         if (pixbuf_module_symbol (module, name, "image_load_animation", &load_sym))
342                 image_module->load_animation = load_sym;
343
344         if (pixbuf_module_symbol (module, name, "image_save", &save_sym))
345           image_module->save = save_sym;
346
347         return TRUE;
348 }
349 #else
350
351 #define mname(type,fn) gdk_pixbuf__ ## type ## _image_ ##fn
352 #define m_load(type)  extern GdkPixbuf * mname(type,load) (FILE *f, GError **error);
353 #define m_load_xpm_data(type)  extern GdkPixbuf * mname(type,load_xpm_data) (const char **data);
354 #define m_begin_load(type)  \
355    extern gpointer mname(type,begin_load) (ModulePreparedNotifyFunc prepare_func, \
356                                  ModuleUpdatedNotifyFunc update_func, \
357                                  ModuleFrameDoneNotifyFunc frame_done_func,\
358                                  ModuleAnimationDoneNotifyFunc anim_done_func,\
359                                  gpointer user_data,\
360                                  GError **error);
361 #define m_stop_load(type)  extern void mname(type,stop_load) (gpointer context);
362 #define m_load_increment(type)  extern gboolean mname(type,load_increment) (gpointer context, const guchar *buf, guint size, GError **error);
363 #define m_load_animation(type)  extern GdkPixbufAnimation * mname(type,load_animation) (FILE *f, GError **error);
364 #define m_save(type) \
365    extern gboolean mname(type,save) (FILE          *f, \
366                                      GdkPixbuf     *pixbuf, \
367                                      gchar        **keys, \
368                                      gchar        **values, \
369                                      GError       **error);
370
371 /* PNG */
372 m_load (png);
373 m_begin_load (png);
374 m_load_increment (png);
375 m_stop_load (png);
376 m_save (png);
377 /* BMP */
378 m_load (bmp);
379 m_begin_load (bmp);
380 m_load_increment (bmp);
381 m_stop_load (bmp);
382 /* WBMP */
383 m_load (wbmp);
384 m_begin_load (wbmp);
385 m_load_increment (wbmp);
386 m_stop_load (wbmp);
387 /* GIF */
388 m_load (gif);
389 m_begin_load (gif);
390 m_load_increment (gif);
391 m_stop_load (gif);
392 m_load_animation (gif);
393 /* ICO */
394 m_load (ico);
395 m_begin_load (ico);
396 m_load_increment (ico);
397 m_stop_load (ico);
398 /* JPEG */
399 m_load (jpeg);
400 m_begin_load (jpeg);
401 m_load_increment (jpeg);
402 m_stop_load (jpeg);
403 m_save (jpeg);
404 /* PNM */
405 m_load (pnm);
406 m_begin_load (pnm);
407 m_load_increment (pnm);
408 m_stop_load (pnm);
409 /* RAS */
410 m_load (ras);
411 m_begin_load (ras);
412 m_load_increment (ras);
413 m_stop_load (ras);
414 /* TIFF */
415 m_load (tiff);
416 m_begin_load (tiff);
417 m_load_increment (tiff);
418 m_stop_load (tiff);
419 /* XPM */
420 m_load (xpm);
421 m_load_xpm_data (xpm);
422
423 gboolean
424 gdk_pixbuf_load_module (GdkPixbufModule *image_module,
425                         GError         **error)
426 {
427         image_module->module = (void *) 1;
428
429 #ifdef INCLUDE_png      
430         if (strcmp (image_module->module_name, "png") == 0){
431                 image_module->load           = mname (png,load);
432                 image_module->begin_load     = mname (png,begin_load);
433                 image_module->load_increment = mname (png,load_increment);
434                 image_module->stop_load      = mname (png,stop_load);
435                 image_module->save           = mname (png,save);
436                 return TRUE;
437         }
438 #endif
439
440 #ifdef INCLUDE_bmp      
441         if (strcmp (image_module->module_name, "bmp") == 0){
442                 image_module->load           = mname (bmp,load);
443                 image_module->begin_load     = mname (bmp,begin_load);
444                 image_module->load_increment = mname (bmp,load_increment);
445                 image_module->stop_load      = mname (bmp,stop_load);
446                 return TRUE;
447         }
448 #endif
449
450 #ifdef INCLUDE_wbmp
451         if (strcmp (image_module->module_name, "wbmp") == 0){
452                 image_module->load           = mname (wbmp,load);
453                 image_module->begin_load     = mname (wbmp,begin_load);
454                 image_module->load_increment = mname (wbmp,load_increment);
455                 image_module->stop_load      = mname (wbmp,stop_load);
456                 return TRUE;
457         }
458 #endif
459
460 #ifdef INCLUDE_gif
461         if (strcmp (image_module->module_name, "gif") == 0){
462                 image_module->load           = mname (gif,load);
463                 image_module->begin_load     = mname (gif,begin_load);
464                 image_module->load_increment = mname (gif,load_increment);
465                 image_module->stop_load      = mname (gif,stop_load);
466                 image_module->load_animation = mname (gif,load_animation);
467                 return TRUE;
468         }
469 #endif
470
471 #ifdef INCLUDE_ico
472         if (strcmp (image_module->module_name, "ico") == 0){
473                 image_module->load           = mname (ico,load);
474                 image_module->begin_load     = mname (ico,begin_load);
475                 image_module->load_increment = mname (ico,load_increment);
476                 image_module->stop_load      = mname (ico,stop_load);
477                 return TRUE;
478         }
479 #endif
480
481 #ifdef INCLUDE_jpeg
482         if (strcmp (image_module->module_name, "jpeg") == 0){
483                 image_module->load           = mname (jpeg,load);
484                 image_module->begin_load     = mname (jpeg,begin_load);
485                 image_module->load_increment = mname (jpeg,load_increment);
486                 image_module->stop_load      = mname (jpeg,stop_load);
487                 image_module->save           = mname (jpeg,save);
488                 return TRUE;
489         }
490 #endif
491
492 #ifdef INCLUDE_pnm
493         if (strcmp (image_module->module_name, "pnm") == 0){
494                 image_module->load           = mname (pnm,load);
495                 image_module->begin_load     = mname (pnm,begin_load);
496                 image_module->load_increment = mname (pnm,load_increment);
497                 image_module->stop_load      = mname (pnm,stop_load);
498                 return TRUE;
499         }
500 #endif
501
502 #ifdef INCLUDE_ras
503         if (strcmp (image_module->module_name, "ras") == 0){
504                 image_module->load           = mname (ras,load);
505                 image_module->begin_load     = mname (ras,begin_load);
506                 image_module->load_increment = mname (ras,load_increment);
507                 image_module->stop_load      = mname (ras,stop_load);
508                 return TRUE;
509         }
510 #endif
511
512 #ifdef INCLUDE_tiff
513         if (strcmp (image_module->module_name, "tiff") == 0){
514                 image_module->load           = mname (tiff,load);
515                 image_module->begin_load     = mname (tiff,begin_load);
516                 image_module->load_increment = mname (tiff,load_increment);
517                 image_module->stop_load      = mname (tiff,stop_load);
518                 return TRUE;
519         }
520 #endif
521
522 #ifdef INCLUDE_xpm
523         if (strcmp (image_module->module_name, "xpm") == 0){
524                 image_module->load           = mname (xpm,load);
525                 image_module->load_xpm_data  = mname (xpm,load_xpm_data);
526                 return TRUE;
527         }
528 #endif
529
530         g_set_error (error,
531                      GDK_PIXBUF_ERROR,
532                      GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
533                      _("Image type '%s' is not supported"),
534                      image_module->module_name);
535
536         return FALSE;
537 }
538
539
540 #endif
541
542 \f
543
544 GdkPixbufModule *
545 gdk_pixbuf_get_named_module (const char *name,
546                              GError **error)
547 {
548         int i;
549
550         for (i = 0; file_formats [i].module_name; i++) {
551                 if (!strcmp(name, file_formats[i].module_name))
552                         return &(file_formats[i]);
553         }
554
555         g_set_error (error,
556                      GDK_PIXBUF_ERROR,
557                      GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
558                      _("Image type '%s' is not supported"),
559                      name);
560         
561         return NULL;
562 }
563
564 GdkPixbufModule *
565 gdk_pixbuf_get_module (guchar *buffer, guint size,
566                        const gchar *filename,
567                        GError **error)
568 {
569         int i;
570
571         for (i = 0; file_formats [i].module_name; i++) {
572                 if ((* file_formats [i].format_check) (buffer, size))
573                         return &(file_formats[i]);
574         }
575
576         if (filename)
577                 g_set_error (error,
578                              GDK_PIXBUF_ERROR,
579                              GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
580                              _("Couldn't recognize the image file format for file '%s'"),
581                              filename);        
582         else
583                 g_set_error (error,
584                              GDK_PIXBUF_ERROR,
585                              GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
586                              _("Unrecognized image file format"));
587
588         
589         return NULL;
590 }
591
592 /**
593  * gdk_pixbuf_new_from_file:
594  * @filename: Name of file to load.
595  * @error: Return location for an error
596  *
597  * Creates a new pixbuf by loading an image from a file.  The file format is
598  * detected automatically. If NULL is returned, then @error will be set.
599  * Possible errors are in the #GDK_PIXBUF_ERROR and #G_FILE_ERROR domains.
600  *
601  * Return value: A newly-created pixbuf with a reference count of 1, or NULL if
602  * any of several error conditions occurred:  the file could not be opened,
603  * there was no loader for the file's format, there was not enough memory to
604  * allocate the image buffer, or the image file contained invalid data.
605  **/
606 GdkPixbuf *
607 gdk_pixbuf_new_from_file (const char *filename,
608                           GError    **error)
609 {
610         GdkPixbuf *pixbuf;
611         int size;
612         FILE *f;
613         guchar buffer [128];
614         GdkPixbufModule *image_module;
615
616         g_return_val_if_fail (filename != NULL, NULL);
617
618         f = fopen (filename, "rb");
619         if (!f) {
620                 g_set_error (error,
621                              G_FILE_ERROR,
622                              g_file_error_from_errno (errno),
623                              _("Failed to open file '%s': %s"),
624                              filename, g_strerror (errno));
625                 return NULL;
626         }
627
628         size = fread (&buffer, 1, sizeof (buffer), f);
629         if (size == 0) {
630                 g_set_error (error,
631                              GDK_PIXBUF_ERROR,
632                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
633                              _("Image file '%s' contains no data"),
634                              filename);
635                 
636                 fclose (f);
637                 return NULL;
638         }
639
640         image_module = gdk_pixbuf_get_module (buffer, size, filename, error);
641         if (image_module == NULL) {
642                 fclose (f);
643                 return NULL;
644         }
645
646         if (image_module->module == NULL)
647                 if (!gdk_pixbuf_load_module (image_module, error)) {
648                         fclose (f);
649                         return NULL;
650                 }
651
652         if (image_module->load == NULL) {
653                 g_set_error (error,
654                              GDK_PIXBUF_ERROR,
655                              GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
656                              _("Don't know how to load the image in file '%s'"),
657                              filename);
658                 
659                 fclose (f);
660                 return NULL;
661         }
662
663         fseek (f, 0, SEEK_SET);
664         pixbuf = (* image_module->load) (f, error);
665         fclose (f);
666
667         if (pixbuf == NULL && error != NULL && *error == NULL) {
668                 /* I don't trust these crufty longjmp()'ing image libs
669                  * to maintain proper error invariants, and I don't
670                  * want user code to segfault as a result. We need to maintain
671                  * the invariant that error gets set if NULL is returned.
672                  */
673                 
674                 g_warning ("Bug! gdk-pixbuf loader '%s' didn't set an error on failure.", image_module->module_name);
675                 g_set_error (error,
676                              GDK_PIXBUF_ERROR,
677                              GDK_PIXBUF_ERROR_FAILED,
678                              _("Failed to load image '%s': reason not known, probably a corrupt image file"),
679                              filename);
680                 
681         } else if (error != NULL && *error != NULL) {
682
683           /* Add the filename to the error message */
684           GError *e = *error;
685           gchar *old;
686           
687           old = e->message;
688
689           e->message = g_strdup_printf (_("Failed to load image '%s': %s"),
690                                         filename, old);
691
692           g_free (old);
693         }
694                 
695         return pixbuf;
696 }
697
698 /**
699  * gdk_pixbuf_new_from_xpm_data:
700  * @data: Pointer to inline XPM data.
701  *
702  * Creates a new pixbuf by parsing XPM data in memory.  This data is commonly
703  * the result of including an XPM file into a program's C source.
704  *
705  * Return value: A newly-created pixbuf with a reference count of 1.
706  **/
707 GdkPixbuf *
708 gdk_pixbuf_new_from_xpm_data (const char **data)
709 {
710         GdkPixbuf *(* load_xpm_data) (const char **data);
711         GdkPixbuf *pixbuf;
712
713         if (file_formats[XPM_FILE_FORMAT_INDEX].module == NULL)
714                 gdk_pixbuf_load_module (&file_formats[XPM_FILE_FORMAT_INDEX], NULL);
715
716         if (file_formats[XPM_FILE_FORMAT_INDEX].module == NULL) {
717                 g_warning ("Can't find gdk-pixbuf module for parsing inline XPM data");
718                 return NULL;
719         } else if (file_formats[XPM_FILE_FORMAT_INDEX].load_xpm_data == NULL) {
720                 g_warning ("gdk-pixbuf XPM module lacks XPM data capability");
721                 return NULL;
722         } else
723                 load_xpm_data = file_formats[XPM_FILE_FORMAT_INDEX].load_xpm_data;
724
725         pixbuf = (* load_xpm_data) (data);
726         return pixbuf;
727 }
728
729 static void
730 collect_save_options (va_list   opts,
731                       gchar  ***keys,
732                       gchar  ***vals)
733 {
734   gchar *key;
735   gchar *val;
736   gchar *next;
737   gint count;
738
739   count = 0;
740   *keys = NULL;
741   *vals = NULL;
742   
743   next = va_arg (opts, gchar*);
744   while (next)
745     {
746       key = next;
747       val = va_arg (opts, gchar*);
748
749       ++count;
750
751       /* woo, slow */
752       *keys = g_realloc (*keys, sizeof(gchar*) * (count + 1));
753       *vals = g_realloc (*vals, sizeof(gchar*) * (count + 1));
754       
755       (*keys)[count-1] = g_strdup (key);
756       (*vals)[count-1] = g_strdup (val);
757
758       (*keys)[count] = NULL;
759       (*vals)[count] = NULL;
760       
761       next = va_arg (opts, gchar*);
762     }
763 }
764
765 static gboolean
766 gdk_pixbuf_real_save (GdkPixbuf     *pixbuf, 
767                       FILE          *filehandle, 
768                       const char    *type, 
769                       gchar        **keys,
770                       gchar        **values,
771                       GError       **error)
772 {
773        GdkPixbufModule *image_module = NULL;       
774
775        image_module = gdk_pixbuf_get_named_module (type, error);
776
777        if (image_module == NULL)
778                return FALSE;
779        
780        if (image_module->module == NULL)
781                if (!gdk_pixbuf_load_module (image_module, error))
782                        return FALSE;
783
784        if (image_module->save == NULL) {
785                g_set_error (error,
786                             GDK_PIXBUF_ERROR,
787                             GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
788                             _("This build of gdk-pixbuf does not support saving the image format: %s"),
789                             type);
790                return FALSE;
791        }
792                
793        return (* image_module->save) (filehandle, pixbuf,
794                                       keys, values,
795                                       error);
796 }
797
798  
799 /**
800  * gdk_pixbuf_save:
801  * @pixbuf: pointer to GdkPixbuf.
802  * @filename: Name of file to save.
803  * @type: name of file format.
804  * @error: return location for error, or NULL
805  * @Varargs: list of key-value save options
806  *
807  * Saves pixbuf to a file in @type, which is currently "jpeg" or
808  * "png".  If @error is set, FALSE will be returned. Possible errors include those
809  * in the #GDK_PIXBUF_ERROR domain and those in the #G_FILE_ERROR domain.
810  *
811  * The variable argument list should be NULL-terminated; if not empty,
812  * it should contain pairs of strings that modify the save
813  * parameters. For example:
814  *
815  * <programlisting>
816  * gdk_pixbuf_save (pixbuf, handle, "jpeg", &error,
817  *                  "quality", "100", NULL);
818  * </programlisting>
819  *
820  * The only save parameter that currently exists is the "quality" field
821  * for JPEG images; its value should be in the range [0,100].
822  *
823  * Return value: whether an error was set
824  **/
825
826 gboolean
827 gdk_pixbuf_save (GdkPixbuf  *pixbuf, 
828                  const char *filename, 
829                  const char *type, 
830                  GError    **error,
831                  ...)
832 {
833         gchar **keys = NULL;
834         gchar **values = NULL;
835         va_list args;
836         gboolean result;
837         
838         va_start (args, error);
839         
840         collect_save_options (args, &keys, &values);
841         
842         va_end (args);
843
844         result = gdk_pixbuf_savev (pixbuf, filename, type,
845                                    keys, values,
846                                    error);
847
848         g_strfreev (keys);
849         g_strfreev (values);
850
851         return result;
852 }
853
854 /**
855  * gdk_pixbuf_savev:
856  * @pixbuf: pointer to GdkPixbuf.
857  * @filename: Name of file to save.
858  * @type: name of file format.
859  * @option_keys: name of options to set, NULL-terminated
860  * @option_values: values for named options
861  * @error: return location for error, or NULL
862  *
863  * Saves pixbuf to a file in @type, which is currently "jpeg" or "png".
864  * If @error is set, FALSE will be returned. See gdk_pixbuf_save () for more
865  * details.
866  *
867  * Return value: whether an error was set
868  **/
869
870 gboolean
871 gdk_pixbuf_savev (GdkPixbuf  *pixbuf, 
872                   const char *filename, 
873                   const char *type,
874                   char      **option_keys,
875                   char      **option_values,
876                   GError    **error)
877 {
878         FILE *f = NULL;
879         gboolean result;
880         
881        
882         g_return_val_if_fail (filename != NULL, FALSE);
883         g_return_val_if_fail (type != NULL, FALSE);
884        
885         f = fopen (filename, "wb");
886         
887         if (f == NULL) {
888                 g_set_error (error,
889                              G_FILE_ERROR,
890                              g_file_error_from_errno (errno),
891                              _("Failed to open '%s' for writing: %s"),
892                              filename, g_strerror (errno));
893                 return FALSE;
894         }
895
896        
897        result = gdk_pixbuf_real_save (pixbuf, f, type,
898                                       option_keys, option_values,
899                                       error);
900        
901        
902        if (!result) {
903                g_return_val_if_fail (error == NULL || *error != NULL, FALSE);
904                fclose (f);
905                return FALSE;
906        }
907
908        if (fclose (f) < 0) {
909                g_set_error (error,
910                             G_FILE_ERROR,
911                             g_file_error_from_errno (errno),
912                             _("Failed to close '%s' while writing image, all data may not have been saved: %s"),
913                             filename, g_strerror (errno));
914                return FALSE;
915        }
916        
917        return TRUE;
918 }