]> Pileus Git - ~andy/gtk/blob - gdk-pixbuf/gdk-pixbuf-io.c
gtk/makefile.mingw.in Updates.
[~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);
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 #define m_stop_load(type)  extern void mname(type,stop_load) (gpointer context);
361 #define m_load_increment(type)  extern gboolean mname(type,load_increment) (gpointer context, const guchar *buf, guint size);
362 #define m_load_animation(type)  extern GdkPixbufAnimation * mname(type,load_animation) (FILE *f);
363 #define m_save(type) \
364    extern gboolean mname(type,save) (FILE          *f, \
365                                      GdkPixbuf     *pixbuf, \
366                                      gchar        **keys, \
367                                      gchar        **values, \
368                                      GError       **error);
369
370 /* PNG */
371 m_load (png);
372 m_begin_load (png);
373 m_load_increment (png);
374 m_stop_load (png);
375 m_save (png);
376 /* BMP */
377 m_load (bmp);
378 m_begin_load (bmp);
379 m_load_increment (bmp);
380 m_stop_load (bmp);
381 /* WBMP */
382 m_load (wbmp);
383 m_begin_load (wbmp);
384 m_load_increment (wbmp);
385 m_stop_load (wbmp);
386 /* GIF */
387 m_load (gif);
388 m_begin_load (gif);
389 m_load_increment (gif);
390 m_stop_load (gif);
391 m_load_animation (gif);
392 /* ICO */
393 m_load (ico);
394 m_begin_load (ico);
395 m_load_increment (ico);
396 m_stop_load (ico);
397 /* JPEG */
398 m_load (jpeg);
399 m_begin_load (jpeg);
400 m_load_increment (jpeg);
401 m_stop_load (jpeg);
402 m_save (jpeg);
403 /* PNM */
404 m_load (pnm);
405 m_begin_load (pnm);
406 m_load_increment (pnm);
407 m_stop_load (pnm);
408 /* RAS */
409 m_load (ras);
410 m_begin_load (ras);
411 m_load_increment (ras);
412 m_stop_load (ras);
413 /* TIFF */
414 m_load (tiff);
415 m_begin_load (tiff);
416 m_load_increment (tiff);
417 m_stop_load (tiff);
418 /* XPM */
419 m_load (xpm);
420 m_load_xpm_data (xpm);
421
422 gboolean
423 gdk_pixbuf_load_module (GdkPixbufModule *image_module,
424                         GError         **error)
425 {
426         image_module->module = (void *) 1;
427         
428         if (strcmp (image_module->module_name, "png") == 0){
429                 image_module->load           = mname (png,load);
430                 image_module->begin_load     = mname (png,begin_load);
431                 image_module->load_increment = mname (png,load_increment);
432                 image_module->stop_load      = mname (png,stop_load);
433                 image_module->save           = mname (png,save);
434                 return TRUE;
435         }
436
437         if (strcmp (image_module->module_name, "bmp") == 0){
438                 image_module->load           = mname (bmp,load);
439                 image_module->begin_load     = mname (bmp,begin_load);
440                 image_module->load_increment = mname (bmp,load_increment);
441                 image_module->stop_load      = mname (bmp,stop_load);
442                 return TRUE;
443         }
444
445         if (strcmp (image_module->module_name, "wbmp") == 0){
446                 image_module->load           = mname (wbmp,load);
447                 image_module->begin_load     = mname (wbmp,begin_load);
448                 image_module->load_increment = mname (wbmp,load_increment);
449                 image_module->stop_load      = mname (wbmp,stop_load);
450                 return TRUE;
451         }
452
453         if (strcmp (image_module->module_name, "gif") == 0){
454                 image_module->load           = mname (gif,load);
455                 image_module->begin_load     = mname (gif,begin_load);
456                 image_module->load_increment = mname (gif,load_increment);
457                 image_module->stop_load      = mname (gif,stop_load);
458                 image_module->load_animation = mname (gif,load_animation);
459                 return TRUE;
460         }
461
462         if (strcmp (image_module->module_name, "ico") == 0){
463                 image_module->load           = mname (ico,load);
464                 image_module->begin_load     = mname (ico,begin_load);
465                 image_module->load_increment = mname (ico,load_increment);
466                 image_module->stop_load      = mname (ico,stop_load);
467                 return TRUE;
468         }
469
470         if (strcmp (image_module->module_name, "jpeg") == 0){
471                 image_module->load           = mname (jpeg,load);
472                 image_module->begin_load     = mname (jpeg,begin_load);
473                 image_module->load_increment = mname (jpeg,load_increment);
474                 image_module->stop_load      = mname (jpeg,stop_load);
475                 image_module->save           = mname (jpeg,save);
476                 return TRUE;
477         }
478         if (strcmp (image_module->module_name, "pnm") == 0){
479                 image_module->load           = mname (pnm,load);
480                 image_module->begin_load     = mname (pnm,begin_load);
481                 image_module->load_increment = mname (pnm,load_increment);
482                 image_module->stop_load      = mname (pnm,stop_load);
483                 return TRUE;
484         }
485         if (strcmp (image_module->module_name, "ras") == 0){
486                 image_module->load           = mname (ras,load);
487                 image_module->begin_load     = mname (ras,begin_load);
488                 image_module->load_increment = mname (ras,load_increment);
489                 image_module->stop_load      = mname (ras,stop_load);
490                 return TRUE;
491         }
492         if (strcmp (image_module->module_name, "tiff") == 0){
493                 image_module->load           = mname (tiff,load);
494                 image_module->begin_load     = mname (tiff,begin_load);
495                 image_module->load_increment = mname (tiff,load_increment);
496                 image_module->stop_load      = mname (tiff,stop_load);
497                 return TRUE;
498         }
499         if (strcmp (image_module->module_name, "xpm") == 0){
500                 image_module->load           = mname (xpm,load);
501                 image_module->load_xpm_data  = mname (xpm,load_xpm_data);
502                 return TRUE;
503         }
504
505         g_set_error (error,
506                      GDK_PIXBUF_ERROR,
507                      GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
508                      _("Image type '%s' is not supported"),
509                      image_module->module_name);
510
511         return FALSE;
512 }
513
514
515 #endif
516
517 \f
518
519 GdkPixbufModule *
520 gdk_pixbuf_get_named_module (const char *name,
521                              GError **error)
522 {
523         int i;
524
525         for (i = 0; file_formats [i].module_name; i++) {
526                 if (!strcmp(name, file_formats[i].module_name))
527                         return &(file_formats[i]);
528         }
529
530         g_set_error (error,
531                      GDK_PIXBUF_ERROR,
532                      GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
533                      _("Image type '%s' is not supported"),
534                      name);
535         
536         return NULL;
537 }
538
539 GdkPixbufModule *
540 gdk_pixbuf_get_module (guchar *buffer, guint size,
541                        const gchar *filename,
542                        GError **error)
543 {
544         int i;
545
546         for (i = 0; file_formats [i].module_name; i++) {
547                 if ((* file_formats [i].format_check) (buffer, size))
548                         return &(file_formats[i]);
549         }
550
551         if (filename)
552                 g_set_error (error,
553                              GDK_PIXBUF_ERROR,
554                              GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
555                              _("Couldn't recognize the image file format for file '%s'"),
556                              filename);        
557         else
558                 g_set_error (error,
559                              GDK_PIXBUF_ERROR,
560                              GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
561                              _("Unrecognized image file format"));
562
563         
564         return NULL;
565 }
566
567 /**
568  * gdk_pixbuf_new_from_file:
569  * @filename: Name of file to load.
570  * @error: Return location for an error
571  *
572  * Creates a new pixbuf by loading an image from a file.  The file format is
573  * detected automatically. If NULL is returned, then @error will be set.
574  * Possible errors are in the #GDK_PIXBUF_ERROR and #G_FILE_ERROR domains.
575  *
576  * Return value: A newly-created pixbuf with a reference count of 1, or NULL if
577  * any of several error conditions occurred:  the file could not be opened,
578  * there was no loader for the file's format, there was not enough memory to
579  * allocate the image buffer, or the image file contained invalid data.
580  **/
581 GdkPixbuf *
582 gdk_pixbuf_new_from_file (const char *filename,
583                           GError    **error)
584 {
585         GdkPixbuf *pixbuf;
586         int size;
587         FILE *f;
588         guchar buffer [128];
589         GdkPixbufModule *image_module;
590
591         g_return_val_if_fail (filename != NULL, NULL);
592
593         f = fopen (filename, "rb");
594         if (!f) {
595                 g_set_error (error,
596                              G_FILE_ERROR,
597                              g_file_error_from_errno (errno),
598                              _("Failed to open file '%s': %s"),
599                              filename, g_strerror (errno));
600                 return NULL;
601         }
602
603         size = fread (&buffer, 1, sizeof (buffer), f);
604         if (size == 0) {
605                 g_set_error (error,
606                              GDK_PIXBUF_ERROR,
607                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
608                              _("Image file '%s' contains no data"),
609                              filename);
610                 
611                 fclose (f);
612                 return NULL;
613         }
614
615         image_module = gdk_pixbuf_get_module (buffer, size, filename, error);
616         if (image_module == NULL) {
617                 fclose (f);
618                 return NULL;
619         }
620
621         if (image_module->module == NULL)
622                 if (!gdk_pixbuf_load_module (image_module, error)) {
623                         fclose (f);
624                         return NULL;
625                 }
626
627         if (image_module->load == NULL) {
628                 g_set_error (error,
629                              GDK_PIXBUF_ERROR,
630                              GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
631                              _("Don't know how to load the image in file '%s'"),
632                              filename);
633                 
634                 fclose (f);
635                 return NULL;
636         }
637
638         fseek (f, 0, SEEK_SET);
639         pixbuf = (* image_module->load) (f, error);
640         fclose (f);
641
642         if (pixbuf == NULL && error != NULL && *error == NULL) {
643                 /* I don't trust these crufty longjmp()'ing image libs
644                  * to maintain proper error invariants, and I don't
645                  * want user code to segfault as a result. We need to maintain
646                  * the invariant that error gets set if NULL is returned.
647                  */
648                 
649                 g_warning ("Bug! gdk-pixbuf loader '%s' didn't set an error on failure.", image_module->module_name);
650                 g_set_error (error,
651                              GDK_PIXBUF_ERROR,
652                              GDK_PIXBUF_ERROR_FAILED,
653                              _("Failed to load image '%s': reason not known, probably a corrupt image file"),
654                              filename);
655                 
656         } else if (error != NULL && *error != NULL) {
657
658           /* Add the filename to the error message */
659           GError *e = *error;
660           gchar *old;
661           
662           old = e->message;
663
664           e->message = g_strdup_printf (_("Failed to load image '%s': %s"),
665                                         filename, old);
666
667           g_free (old);
668         }
669                 
670         return pixbuf;
671 }
672
673 /**
674  * gdk_pixbuf_new_from_xpm_data:
675  * @data: Pointer to inline XPM data.
676  *
677  * Creates a new pixbuf by parsing XPM data in memory.  This data is commonly
678  * the result of including an XPM file into a program's C source.
679  *
680  * Return value: A newly-created pixbuf with a reference count of 1.
681  **/
682 GdkPixbuf *
683 gdk_pixbuf_new_from_xpm_data (const char **data)
684 {
685         GdkPixbuf *(* load_xpm_data) (const char **data);
686         GdkPixbuf *pixbuf;
687
688         if (file_formats[XPM_FILE_FORMAT_INDEX].module == NULL)
689                 gdk_pixbuf_load_module (&file_formats[XPM_FILE_FORMAT_INDEX], NULL);
690
691         if (file_formats[XPM_FILE_FORMAT_INDEX].module == NULL) {
692                 g_warning ("Can't find gdk-pixbuf module for parsing inline XPM data");
693                 return NULL;
694         } else if (file_formats[XPM_FILE_FORMAT_INDEX].load_xpm_data == NULL) {
695                 g_warning ("gdk-pixbuf XPM module lacks XPM data capability");
696                 return NULL;
697         } else
698                 load_xpm_data = file_formats[XPM_FILE_FORMAT_INDEX].load_xpm_data;
699
700         pixbuf = (* load_xpm_data) (data);
701         return pixbuf;
702 }
703
704 static void
705 collect_save_options (va_list   opts,
706                       gchar  ***keys,
707                       gchar  ***vals)
708 {
709   gchar *key;
710   gchar *val;
711   gchar *next;
712   gint count;
713
714   count = 0;
715   *keys = NULL;
716   *vals = NULL;
717   
718   next = va_arg (opts, gchar*);
719   while (next)
720     {
721       key = next;
722       val = va_arg (opts, gchar*);
723
724       ++count;
725
726       /* woo, slow */
727       *keys = g_realloc (*keys, sizeof(gchar*) * (count + 1));
728       *vals = g_realloc (*vals, sizeof(gchar*) * (count + 1));
729       
730       (*keys)[count-1] = g_strdup (key);
731       (*vals)[count-1] = g_strdup (val);
732
733       (*keys)[count] = NULL;
734       (*vals)[count] = NULL;
735       
736       next = va_arg (opts, gchar*);
737     }
738 }
739
740 static gboolean
741 gdk_pixbuf_real_save (GdkPixbuf     *pixbuf, 
742                       FILE          *filehandle, 
743                       const char    *type, 
744                       gchar        **keys,
745                       gchar        **values,
746                       GError       **error)
747 {
748        GdkPixbufModule *image_module = NULL;       
749
750        image_module = gdk_pixbuf_get_named_module (type, error);
751
752        if (image_module == NULL)
753                return FALSE;
754        
755        if (image_module->module == NULL)
756                if (!gdk_pixbuf_load_module (image_module, error))
757                        return FALSE;
758
759        if (image_module->save == NULL) {
760                g_set_error (error,
761                             GDK_PIXBUF_ERROR,
762                             GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
763                             _("This build of gdk-pixbuf does not support saving the image format: %s"),
764                             type);
765                return FALSE;
766        }
767                
768        return (* image_module->save) (filehandle, pixbuf,
769                                       keys, values,
770                                       error);
771 }
772
773  
774 /**
775  * gdk_pixbuf_save:
776  * @pixbuf: pointer to GdkPixbuf.
777  * @filename: Name of file to save.
778  * @type: name of file format.
779  * @error: return location for error, or NULL
780  * @Varargs: list of key-value save options
781  *
782  * Saves pixbuf to a file in @type, which is currently "jpeg" or
783  * "png".  If @error is set, FALSE will be returned. Possible errors include those
784  * in the #GDK_PIXBUF_ERROR domain and those in the #G_FILE_ERROR domain.
785  *
786  * The variable argument list should be NULL-terminated; if not empty,
787  * it should contain pairs of strings that modify the save
788  * parameters. For example:
789  *
790  * <programlisting>
791  * gdk_pixbuf_save (pixbuf, handle, "jpeg", &error,
792  *                  "quality", "100", NULL);
793  * </programlisting>
794  *
795  * The only save parameter that currently exists is the "quality" field
796  * for JPEG images; its value should be in the range [0,100].
797  *
798  * Return value: whether an error was set
799  **/
800
801 gboolean
802 gdk_pixbuf_save (GdkPixbuf  *pixbuf, 
803                  const char *filename, 
804                  const char *type, 
805                  GError    **error,
806                  ...)
807 {
808         gchar **keys = NULL;
809         gchar **values = NULL;
810         va_list args;
811         gboolean result;
812         
813         va_start (args, error);
814         
815         collect_save_options (args, &keys, &values);
816         
817         va_end (args);
818
819         result = gdk_pixbuf_savev (pixbuf, filename, type,
820                                    keys, values,
821                                    error);
822
823         g_strfreev (keys);
824         g_strfreev (values);
825
826         return result;
827 }
828
829 /**
830  * gdk_pixbuf_savev:
831  * @pixbuf: pointer to GdkPixbuf.
832  * @filename: Name of file to save.
833  * @type: name of file format.
834  * @option_keys: name of options to set, NULL-terminated
835  * @option_values: values for named options
836  * @error: return location for error, or NULL
837  *
838  * Saves pixbuf to a file in @type, which is currently "jpeg" or "png".
839  * If @error is set, FALSE will be returned. See gdk_pixbuf_save () for more
840  * details.
841  *
842  * Return value: whether an error was set
843  **/
844
845 gboolean
846 gdk_pixbuf_savev (GdkPixbuf  *pixbuf, 
847                   const char *filename, 
848                   const char *type,
849                   char      **option_keys,
850                   char      **option_values,
851                   GError    **error)
852 {
853         FILE *f = NULL;
854         gboolean result;
855         
856        
857         g_return_val_if_fail (filename != NULL, FALSE);
858         g_return_val_if_fail (type != NULL, FALSE);
859        
860         f = fopen (filename, "w");
861         
862         if (f == NULL) {
863                 g_set_error (error,
864                              G_FILE_ERROR,
865                              g_file_error_from_errno (errno),
866                              _("Failed to open '%s' for writing: %s"),
867                              filename, g_strerror (errno));
868                 return FALSE;
869         }
870
871        
872        result = gdk_pixbuf_real_save (pixbuf, f, type,
873                                       option_keys, option_values,
874                                       error);
875        
876        
877        if (!result) {
878                g_return_val_if_fail (error == NULL || *error != NULL, FALSE);
879                fclose (f);
880                return FALSE;
881        }
882
883        if (fclose (f) < 0) {
884                g_set_error (error,
885                             G_FILE_ERROR,
886                             g_file_error_from_errno (errno),
887                             _("Failed to close '%s' while writing image, all data may not have been saved: %s"),
888                             filename, g_strerror (errno));
889                return FALSE;
890        }
891        
892        return TRUE;
893 }