]> Pileus Git - ~andy/gtk/blob - gdk-pixbuf/gdk-pixbuf-io.c
When calling fread() in a loop, check for ferror() as well as for feof()
[~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
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <glib.h>
31 #include <errno.h>
32 #ifdef HAVE_UNISTD_H
33 #include <unistd.h>
34 #endif
35
36 #include "gdk-pixbuf-private.h"
37 #include "gdk-pixbuf-io.h"
38
39 #ifdef G_OS_WIN32
40 #define STRICT
41 #include <windows.h>
42 #undef STRICT
43 #endif
44
45 static gint 
46 format_check (GdkPixbufModule *module, guchar *buffer, int size)
47 {
48         int j;
49         gchar m;
50         GdkPixbufModulePattern *pattern;
51
52         for (pattern = module->info->signature; pattern->prefix; pattern++) {
53                 for (j = 0; j < size && pattern->prefix[j] != 0; j++) {
54                         m = pattern->mask ? pattern->mask[j] : ' ';
55                         if (m == ' ') {
56                                 if (buffer[j] != pattern->prefix[j])
57                                         break;
58                         }
59                         else if (m == '!') {
60                                 if (buffer[j] == pattern->prefix[j])
61                                         break;
62                         }
63                         else if (m == 'z') {
64                                 if (buffer[j] != 0)
65                                         break;
66                         }
67                         else if (m == 'n') {
68                                 if (buffer[j] == 0)
69                                         break;
70                         }
71                 } 
72                 if (pattern->prefix[j] == 0) 
73                         return pattern->relevance;
74         }
75         return 0;
76 }
77
78 static GSList *file_formats = NULL;
79
80 static void gdk_pixbuf_io_init ();
81
82 static GSList *
83 get_file_formats ()
84 {
85         if (file_formats == NULL)
86                 gdk_pixbuf_io_init ();
87         
88         return file_formats;
89 }
90
91
92 #ifdef USE_GMODULE 
93
94 static gboolean
95 scan_string (const char **pos, GString *out)
96 {
97         const char *p = *pos, *q = *pos;
98         char *tmp, *tmp2;
99         gboolean quoted;
100         
101         while (g_ascii_isspace (*p))
102                 p++;
103         
104         if (!*p)
105                 return FALSE;
106         else if (*p == '"') {
107                 p++;
108                 quoted = FALSE;
109                 for (q = p; (*q != '"') || quoted; q++) {
110                         if (!*q)
111                                 return FALSE;
112                         quoted = (*q == '\\') && !quoted;
113                 }
114                 
115                 tmp = g_strndup (p, q - p);
116                 tmp2 = g_strcompress (tmp);
117                 g_string_truncate (out, 0);
118                 g_string_append (out, tmp2);
119                 g_free (tmp);
120                 g_free (tmp2);
121         }
122         
123         q++;
124         *pos = q;
125         
126         return TRUE;
127 }
128
129 static gboolean
130 scan_int (const char **pos, int *out)
131 {
132         int i = 0;
133         char buf[32];
134         const char *p = *pos;
135         
136         while (g_ascii_isspace (*p))
137                 p++;
138         
139         if (*p < '0' || *p > '9')
140                 return FALSE;
141         
142         while ((*p >= '0') && (*p <= '9') && i < sizeof (buf)) {
143                 buf[i] = *p;
144                 i++;
145                 p++;
146         }
147         
148         if (i == sizeof (buf))
149                 return FALSE;
150         else
151                 buf[i] = '\0';
152         
153         *out = atoi (buf);
154         
155         *pos = p;
156
157         return TRUE;
158 }
159
160 static gboolean
161 skip_space (const char **pos)
162 {
163         const char *p = *pos;
164         
165         while (g_ascii_isspace (*p))
166                 p++;
167   
168         *pos = p;
169         
170         return !(*p == '\0');
171 }
172   
173 #ifdef G_OS_WIN32
174
175 /* DllMain function needed to tuck away the gdk-pixbuf DLL name */
176 G_WIN32_DLLMAIN_FOR_DLL_NAME (static, dll_name)
177
178 static char *
179 get_toplevel (void)
180 {
181   static char *toplevel = NULL;
182
183   if (toplevel == NULL)
184     toplevel = g_win32_get_package_installation_subdirectory
185       (GETTEXT_PACKAGE, dll_name, "");
186
187   return toplevel;
188 }
189
190 static char *
191 get_sysconfdir (void)
192 {
193   static char *sysconfdir = NULL;
194
195   if (sysconfdir == NULL)
196     sysconfdir = g_win32_get_package_installation_subdirectory
197       (GETTEXT_PACKAGE, dll_name, "etc");
198
199   return sysconfdir;
200 }
201
202 #undef GTK_SYSCONFDIR
203 #define GTK_SYSCONFDIR get_sysconfdir()
204
205 static void
206 correct_prefix (gchar **path)
207 {
208   if (strncmp (*path, GTK_PREFIX "/", strlen (GTK_PREFIX "/")) == 0 ||
209       strncmp (*path, GTK_PREFIX "\\", strlen (GTK_PREFIX "\\")) == 0)
210     {
211       /* This is an entry put there by gdk-pixbuf-query-loaders on the
212        * packager's system. On Windows a prebuilt GTK+ package can be
213        * installed in a random location. The gdk-pixbuf.loaders file
214        * distributed in such a package contains paths from the package
215        * builder's machine. Replace the build-time prefix with the
216        * installation prefix on this machine.
217        */
218       gchar *tem = *path;
219       *path = g_strconcat (get_toplevel (), tem + strlen (GTK_PREFIX), NULL);
220       g_free (tem);
221     }
222 }
223
224 #endif
225
226 static gchar *
227 gdk_pixbuf_get_module_file (void)
228 {
229   gchar *result = g_strdup (g_getenv ("GDK_PIXBUF_MODULE_FILE"));
230
231   if (!result)
232           result = g_build_filename (GTK_SYSCONFDIR, "gtk-2.0", "gdk-pixbuf.loaders", NULL);
233
234   return result;
235 }
236
237 static void 
238 gdk_pixbuf_io_init ()
239 {
240         GIOChannel *channel;
241         gchar *line_buf;
242         gsize term;
243         GString *tmp_buf = g_string_new (NULL);
244         gboolean have_error = FALSE;
245         GdkPixbufModule *module = NULL;
246         gchar *filename = gdk_pixbuf_get_module_file ();
247         int flags;
248         int n_patterns = 0;
249         GdkPixbufModulePattern *pattern;
250         GError *error = NULL;
251
252         channel = g_io_channel_new_file (filename, "r",  &error);
253         if (!channel) {
254                 g_warning ("Can not open pixbuf loader module file '%s': %s",
255                            filename, error->message);
256                 return;
257         }
258         
259         while (!have_error && g_io_channel_read_line (channel, &line_buf, NULL, &term, NULL) == G_IO_STATUS_NORMAL) {
260                 const char *p;
261                 
262                 p = line_buf;
263
264                 line_buf[term] = 0;
265
266                 if (!skip_space (&p)) {
267                                 /* Blank line marking the end of a module
268                                  */
269                         if (module && *p != '#') {
270 #ifdef G_OS_WIN32
271                                 correct_prefix (&module->module_path);
272 #endif
273                                 file_formats = g_slist_prepend (file_formats, module);
274                                 module = NULL;
275                         }
276                         
277                         goto next_line;
278                 }
279
280                 if (*p == '#') 
281                         goto next_line;
282                 
283                 if (!module) {
284                                 /* Read a module location
285                                  */
286                         module = g_new0 (GdkPixbufModule, 1);
287                         n_patterns = 0;
288                         
289                         if (!scan_string (&p, tmp_buf)) {
290                                 g_warning ("Error parsing loader info in '%s'\n  %s", 
291                                            filename, line_buf);
292                                 have_error = TRUE;
293                         }
294                         module->module_path = g_strdup (tmp_buf->str);
295                 }
296                 else if (!module->module_name) {
297                         module->info = g_new0 (GdkPixbufFormat, 1);
298                         if (!scan_string (&p, tmp_buf)) {
299                                 g_warning ("Error parsing loader info in '%s'\n  %s", 
300                                            filename, line_buf);
301                                 have_error = TRUE;
302                         }
303                         module->info->name =  g_strdup (tmp_buf->str);
304                         module->module_name = module->info->name;
305
306                         if (!scan_int (&p, &flags)) {
307                                 g_warning ("Error parsing loader info in '%s'\n  %s", 
308                                            filename, line_buf);
309                                 have_error = TRUE;
310                         }
311                         module->info->flags = flags;
312                         
313                         if (!scan_string (&p, tmp_buf)) {
314                                 g_warning ("Error parsing loader info in '%s'\n  %s", 
315                                            filename, line_buf);
316                                 have_error = TRUE;
317                         }                       
318                         if (tmp_buf->str[0] != 0)
319                                 module->info->domain = g_strdup (tmp_buf->str);
320
321                         if (!scan_string (&p, tmp_buf)) {
322                                 g_warning ("Error parsing loader info in '%s'\n  %s", 
323                                            filename, line_buf);
324                                 have_error = TRUE;
325                         }                       
326                         module->info->description = g_strdup (tmp_buf->str);
327                 }
328                 else if (!module->info->mime_types) {
329                         int n = 1;
330                         module->info->mime_types = g_new0 (gchar*, 1);
331                         while (scan_string (&p, tmp_buf)) {
332                                 if (tmp_buf->str[0] != 0) {
333                                         module->info->mime_types =
334                                                 g_realloc (module->info->mime_types, (n + 1) * sizeof (gchar*));
335                                         module->info->mime_types[n - 1] = g_strdup (tmp_buf->str);
336                                         module->info->mime_types[n] = 0;
337                                         n++;
338                                 }
339                         }
340                 }
341                 else if (!module->info->extensions) {
342                         int n = 1;
343                         module->info->extensions = g_new0 (gchar*, 1);
344                         while (scan_string (&p, tmp_buf)) {
345                                 if (tmp_buf->str[0] != 0) {
346                                         module->info->extensions =
347                                                 g_realloc (module->info->extensions, (n + 1) * sizeof (gchar*));
348                                         module->info->extensions[n - 1] = g_strdup (tmp_buf->str);
349                                         module->info->extensions[n] = 0;
350                                         n++;
351                                 }
352                         }
353                 }
354                 else {
355                         n_patterns++;
356                         module->info->signature = (GdkPixbufModulePattern *)
357                                 g_realloc (module->info->signature, (n_patterns + 1) * sizeof (GdkPixbufModulePattern));
358                         pattern = module->info->signature + n_patterns;
359                         pattern->prefix = NULL;
360                         pattern->mask = NULL;
361                         pattern->relevance = 0;
362                         pattern--;
363                         if (!scan_string (&p, tmp_buf))
364                                 goto context_error;
365                         pattern->prefix = g_strdup (tmp_buf->str);
366                         
367                         if (!scan_string (&p, tmp_buf))
368                                 goto context_error;
369                         if (*tmp_buf->str)
370                                 pattern->mask = g_strdup (tmp_buf->str);
371                         else
372                                 pattern->mask = NULL;
373                         
374                         if (!scan_int (&p, &pattern->relevance))
375                                 goto context_error;
376                         
377                         goto next_line;
378
379                 context_error:
380                         g_free (pattern->prefix);
381                         g_free (pattern->mask);
382                         g_free (pattern);
383                         g_warning ("Error parsing loader info in '%s'\n  %s", 
384                                    filename, line_buf);
385                         have_error = TRUE;
386                 }
387         next_line:
388                 g_free (line_buf);
389         }
390         g_string_free (tmp_buf, TRUE);
391         g_io_channel_unref (channel);
392         g_free (filename);
393 }
394
395 /* actually load the image handler - gdk_pixbuf_get_module only get a */
396 /* reference to the module to load, it doesn't actually load it       */
397 /* perhaps these actions should be combined in one function           */
398 gboolean
399 _gdk_pixbuf_load_module (GdkPixbufModule *image_module,
400                          GError         **error)
401 {
402         char *path;
403         GModule *module;
404         gpointer sym;
405         
406         g_return_val_if_fail (image_module->module == NULL, FALSE);
407
408         path = image_module->module_path;
409         module = g_module_open (path, G_MODULE_BIND_LAZY);
410
411         if (!module) {
412                 g_set_error (error,
413                              GDK_PIXBUF_ERROR,
414                              GDK_PIXBUF_ERROR_FAILED,
415                              _("Unable to load image-loading module: %s: %s"),
416                              path, g_module_error ());
417                 return FALSE;
418         }
419
420         image_module->module = module;        
421         
422         if (g_module_symbol (module, "fill_vtable", &sym)) {
423                 GdkPixbufModuleFillVtableFunc func = (GdkPixbufModuleFillVtableFunc) sym;
424                 (* func) (image_module);
425                 return TRUE;
426         } else {
427                 g_set_error (error,
428                              GDK_PIXBUF_ERROR,
429                              GDK_PIXBUF_ERROR_FAILED,
430                              _("Image-loading module %s does not export the proper interface; perhaps it's from a different GTK version?"),
431                              path);
432                 return FALSE;
433         }
434 }
435 #else
436
437 #define module(type) \
438   extern void MODULE_ENTRY (type, fill_info)   (GdkPixbufFormat *info);   \
439   extern void MODULE_ENTRY (type, fill_vtable) (GdkPixbufModule *module)
440
441 module (png);
442 module (bmp);
443 module (wbmp);
444 module (gif);
445 module (ico);
446 module (ani);
447 module (jpeg);
448 module (pnm);
449 module (ras);
450 module (tiff);
451 module (xpm);
452 module (xbm);
453 module (tga);
454 module (pcx);
455
456 gboolean
457 _gdk_pixbuf_load_module (GdkPixbufModule *image_module,
458                          GError         **error)
459 {
460         GdkPixbufModuleFillInfoFunc fill_info = NULL;
461         GdkPixbufModuleFillVtableFunc fill_vtable = NULL;
462
463         image_module->module = (void *) 1;
464
465         if (FALSE) {
466                 /* Ugly hack so we can use else if unconditionally below ;-) */
467         }
468         
469 #ifdef INCLUDE_png      
470         else if (strcmp (image_module->module_name, "png") == 0) {
471                 fill_info = MODULE_ENTRY (png, fill_info);
472                 fill_vtable = MODULE_ENTRY (png, fill_vtable);
473         }
474 #endif
475
476 #ifdef INCLUDE_bmp      
477         else if (strcmp (image_module->module_name, "bmp") == 0) {
478                 fill_info = MODULE_ENTRY (bmp, fill_info);
479                 fill_vtable = MODULE_ENTRY (bmp, fill_vtable);
480         }
481 #endif
482
483 #ifdef INCLUDE_wbmp
484         else if (strcmp (image_module->module_name, "wbmp") == 0) {
485                 fill_info = MODULE_ENTRY (wbmp, fill_info);
486                 fill_vtable = MODULE_ENTRY (wbmp, fill_vtable);
487         }
488 #endif
489
490 #ifdef INCLUDE_gif
491         else if (strcmp (image_module->module_name, "gif") == 0) {
492                 fill_info = MODULE_ENTRY (gif, fill_info);
493                 fill_vtable = MODULE_ENTRY (gif, fill_vtable);
494         }
495 #endif
496
497 #ifdef INCLUDE_ico
498         else if (strcmp (image_module->module_name, "ico") == 0) {
499                 fill_info = MODULE_ENTRY (ico, fill_info);
500                 fill_vtable = MODULE_ENTRY (ico, fill_vtable);
501         }
502 #endif
503
504 #ifdef INCLUDE_ani
505         else if (strcmp (image_module->module_name, "ani") == 0) {
506                 fill_info = MODULE_ENTRY (ani, fill_info);
507                 fill_vtable = MODULE_ENTRY (ani, fill_vtable);
508         }
509 #endif
510
511 #ifdef INCLUDE_jpeg
512         else if (strcmp (image_module->module_name, "jpeg") == 0) {
513                 fill_info = MODULE_ENTRY (jpeg, fill_info);
514                 fill_vtable = MODULE_ENTRY (jpeg, fill_vtable);
515         }
516 #endif
517
518 #ifdef INCLUDE_pnm
519         else if (strcmp (image_module->module_name, "pnm") == 0) {
520                 fill_info = MODULE_ENTRY (pnm, fill_info);
521                 fill_vtable = MODULE_ENTRY (pnm, fill_vtable);
522         }
523 #endif
524
525 #ifdef INCLUDE_ras
526         else if (strcmp (image_module->module_name, "ras") == 0) {
527                 fill_info = MODULE_ENTRY (ras, fill_info);
528                 fill_vtable = MODULE_ENTRY (ras, fill_vtable);
529         }
530 #endif
531
532 #ifdef INCLUDE_tiff
533         else if (strcmp (image_module->module_name, "tiff") == 0) {
534                 fill_info = MODULE_ENTRY (tiff, fill_info);
535                 fill_vtable = MODULE_ENTRY (tiff, fill_vtable);
536         }
537 #endif
538
539 #ifdef INCLUDE_xpm
540         else if (strcmp (image_module->module_name, "xpm") == 0) {
541                 fill_info = MODULE_ENTRY (xpm, fill_info);
542                 fill_vtable = MODULE_ENTRY (xpm, fill_vtable);
543         }
544 #endif
545
546 #ifdef INCLUDE_xbm
547         else if (strcmp (image_module->module_name, "xbm") == 0) {
548                 fill_info = MODULE_ENTRY (xbm, fill_info);
549                 fill_vtable = MODULE_ENTRY (xbm, fill_vtable);
550         }
551 #endif
552
553 #ifdef INCLUDE_tga
554         else if (strcmp (image_module->module_name, "tga") == 0) {
555                 fill_info = MODULE_ENTRY (tga, fill_info);
556                 fill_vtable = MODULE_ENTRY (tga, fill_vtable);
557         }
558 #endif
559         
560 #ifdef INCLUDE_pcx
561         else if (strcmp (image_module->module_name, "pcx") == 0) {
562                 fill_info = MODULE_ENTRY (pcx, fill_info);
563                 fill_vtable = MODULE_ENTRY (pcx, fill_vtable);
564         }
565 #endif
566         
567         if (fill_vtable) {
568                 (* fill_vtable) (image_module);
569                 image_module->info = g_new0 (GdkPixbufFormat, 1);
570                 (* fill_info) (image_module->info);
571
572                 return TRUE;
573         } else {
574                 g_set_error (error,
575                              GDK_PIXBUF_ERROR,
576                              GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
577                              _("Image type '%s' is not supported"),
578                              image_module->module_name);
579
580                 return FALSE;
581         }
582 }
583
584 static void 
585 gdk_pixbuf_io_init ()
586 {
587         gchar *included_formats[] = { 
588                 "ani", "png", "bmp", "wbmp", "gif", 
589                 "ico", "jpeg", "pnm", "ras", "tiff", 
590                 "xpm", "xbm", "tga", "pcx",
591                 NULL
592         };
593         gchar **name;
594         GdkPixbufModule *module = NULL;
595         
596         for (name = included_formats; *name; name++) {
597                 module = g_new0 (GdkPixbufModule, 1);
598                 module->module_name = *name;
599                 if (_gdk_pixbuf_load_module (module, NULL))
600                         file_formats = g_slist_prepend (file_formats, module);
601                 else
602                         g_free (module);
603         }
604 }
605
606 #endif
607
608 \f
609
610 GdkPixbufModule *
611 _gdk_pixbuf_get_named_module (const char *name,
612                               GError **error)
613 {
614         GSList *modules;
615
616         for (modules = get_file_formats (); modules; modules = g_slist_next (modules)) {
617                 GdkPixbufModule *module = (GdkPixbufModule *)modules->data;
618                 if (!strcmp (name, module->module_name))
619                         return module;
620         }
621
622         g_set_error (error,
623                      GDK_PIXBUF_ERROR,
624                      GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
625                      _("Image type '%s' is not supported"),
626                      name);
627         
628         return NULL;
629 }
630
631 GdkPixbufModule *
632 _gdk_pixbuf_get_module (guchar *buffer, guint size,
633                         const gchar *filename,
634                         GError **error)
635 {
636         GSList *modules;
637
638         gint score, best = 0;
639         GdkPixbufModule *selected = NULL;
640         for (modules = get_file_formats (); modules; modules = g_slist_next (modules)) {
641                 GdkPixbufModule *module = (GdkPixbufModule *)modules->data;
642                 score = format_check (module, buffer, size);
643                 if (score > best) {
644                         best = score; 
645                         selected = module;
646                 }
647                 if (score >= 100) 
648                         break;
649         }
650         if (selected != NULL)
651                 return selected;
652
653         if (filename)
654                 g_set_error (error,
655                              GDK_PIXBUF_ERROR,
656                              GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
657                              _("Couldn't recognize the image file format for file '%s'"),
658                              filename);        
659         else
660                 g_set_error (error,
661                              GDK_PIXBUF_ERROR,
662                              GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
663                              _("Unrecognized image file format"));
664
665         
666         return NULL;
667 }
668
669
670 static void
671 prepared_notify (GdkPixbuf *pixbuf, 
672                  GdkPixbufAnimation *anim, 
673                  gpointer user_data)
674 {
675         if (pixbuf != NULL)
676                 g_object_ref (pixbuf);
677         *((GdkPixbuf **)user_data) = pixbuf;
678 }
679
680 GdkPixbuf *
681 _gdk_pixbuf_generic_image_load (GdkPixbufModule *module,
682                                 FILE *f,
683                                 GError **error)
684 {
685         guchar buffer[4096];
686         size_t length;
687         GdkPixbuf *pixbuf = NULL;
688         GdkPixbufAnimation *animation = NULL;
689         gpointer context;
690
691         if (module->load != NULL)
692                 return (* module->load) (f, error);
693         
694         if (module->begin_load != NULL) {
695                 
696                 context = module->begin_load (NULL, prepared_notify, NULL, &pixbuf, error);
697         
698                 if (!context)
699                         return NULL;
700                 
701                 while (!feof (f) && !ferror (f)) {
702                         length = fread (buffer, 1, sizeof (buffer), f);
703                         if (length > 0)
704                                 if (!module->load_increment (context, buffer, length, error)) {
705                                         module->stop_load (context, NULL);
706                                         if (pixbuf != NULL)
707                                                 g_object_unref (pixbuf);
708                                         return NULL;
709                                 }
710                 }
711                 
712                 if (!module->stop_load (context, error)) {
713                         if (pixbuf != NULL)
714                                 g_object_unref (pixbuf);
715                         return NULL;
716                 }
717                 
718                 return pixbuf;
719         }
720         
721         if (module->load_animation != NULL) {
722                 animation = (* module->load_animation) (f, error);
723                 if (animation != NULL) {
724                         pixbuf = gdk_pixbuf_animation_get_static_image (animation);
725
726                         g_object_ref (pixbuf);
727
728                         g_object_unref (animation);
729                         
730                         return pixbuf;
731                 }
732         }
733
734         return NULL;
735 }
736
737 /**
738  * gdk_pixbuf_new_from_file:
739  * @filename: Name of file to load.
740  * @error: Return location for an error
741  *
742  * Creates a new pixbuf by loading an image from a file.  The file format is
743  * detected automatically. If %NULL is returned, then @error will be set.
744  * Possible errors are in the #GDK_PIXBUF_ERROR and #G_FILE_ERROR domains.
745  *
746  * Return value: A newly-created pixbuf with a reference count of 1, or %NULL if
747  * any of several error conditions occurred:  the file could not be opened,
748  * there was no loader for the file's format, there was not enough memory to
749  * allocate the image buffer, or the image file contained invalid data.
750  **/
751 GdkPixbuf *
752 gdk_pixbuf_new_from_file (const char *filename,
753                           GError    **error)
754 {
755         GdkPixbuf *pixbuf;
756         int size;
757         FILE *f;
758         guchar buffer [128];
759         GdkPixbufModule *image_module;
760
761         g_return_val_if_fail (filename != NULL, NULL);
762         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
763
764         f = fopen (filename, "rb");
765         if (!f) {
766                 g_set_error (error,
767                              G_FILE_ERROR,
768                              g_file_error_from_errno (errno),
769                              _("Failed to open file '%s': %s"),
770                              filename, g_strerror (errno));
771                 return NULL;
772         }
773
774         size = fread (&buffer, 1, sizeof (buffer), f);
775         if (size == 0) {
776                 g_set_error (error,
777                              GDK_PIXBUF_ERROR,
778                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
779                              _("Image file '%s' contains no data"),
780                              filename);
781                 
782                 fclose (f);
783                 return NULL;
784         }
785
786         image_module = _gdk_pixbuf_get_module (buffer, size, filename, error);
787         if (image_module == NULL) {
788                 fclose (f);
789                 return NULL;
790         }
791
792         if (image_module->module == NULL)
793                 if (!_gdk_pixbuf_load_module (image_module, error)) {
794                         fclose (f);
795                         return NULL;
796                 }
797
798         fseek (f, 0, SEEK_SET);
799         pixbuf = _gdk_pixbuf_generic_image_load (image_module, f, error);
800         fclose (f);
801
802         if (pixbuf == NULL && error != NULL && *error == NULL) {
803                 /* I don't trust these crufty longjmp()'ing image libs
804                  * to maintain proper error invariants, and I don't
805                  * want user code to segfault as a result. We need to maintain
806                  * the invariastable/gdk-pixbuf/nt that error gets set if NULL is returned.
807                  */
808                 
809                 g_warning ("Bug! gdk-pixbuf loader '%s' didn't set an error on failure.", image_module->module_name);
810                 g_set_error (error,
811                              GDK_PIXBUF_ERROR,
812                              GDK_PIXBUF_ERROR_FAILED,
813                              _("Failed to load image '%s': reason not known, probably a corrupt image file"),
814                              filename);
815                 
816         } else if (error != NULL && *error != NULL) {
817
818           /* Add the filename to the error message */
819           GError *e = *error;
820           gchar *old;
821           
822           old = e->message;
823
824           e->message = g_strdup_printf (_("Failed to load image '%s': %s"),
825                                         filename, old);
826
827           g_free (old);
828         }
829                 
830         return pixbuf;
831 }
832
833 static void
834 size_prepared_cb (GdkPixbufLoader *loader, 
835                   int              width,
836                   int              height,
837                   gpointer         data)
838 {
839         struct {
840                 int width;
841                 int height;
842         } *info = data;
843
844         g_return_if_fail (width > 0 && height > 0);
845
846         if ((double)height * (double)info->width >
847             (double)width * (double)info->height) {
848                 width = 0.5 + (double)width * (double)info->height / (double)height;
849                 height = info->height;
850         } else {
851                 height = 0.5 + (double)height * (double)info->width / (double)width;
852                 width = info->width;
853         }
854
855         gdk_pixbuf_loader_set_size (loader, width, height);
856 }
857
858 /**
859  * gdk_pixbuf_new_from_file_at_size:
860  * @filename: Name of file to load.
861  * @width: The width the image should have
862  * @height: The height the image should have
863  * @error: Return location for an error
864  *
865  * Creates a new pixbuf by loading an image from a file.  The file format is
866  * detected automatically. If %NULL is returned, then @error will be set.
867  * Possible errors are in the #GDK_PIXBUF_ERROR and #G_FILE_ERROR domains.
868  * The image will be scaled to fit in the requested size, preserving its aspect ratio.
869  *
870  * Return value: A newly-created pixbuf with a reference count of 1, or %NULL if
871  * any of several error conditions occurred:  the file could not be opened,
872  * there was no loader for the file's format, there was not enough memory to
873  * allocate the image buffer, or the image file contained invalid data.
874  *
875  * Since: 2.4
876  **/
877 GdkPixbuf *
878 gdk_pixbuf_new_from_file_at_size (const char *filename,
879                                   int         width, 
880                                   int         height,
881                                   GError    **error)
882 {
883         GdkPixbufLoader *loader;
884         GdkPixbuf       *pixbuf;
885
886         guchar buffer [4096];
887         int length;
888         FILE *f;
889         struct {
890                 gint width;
891                 gint height;
892         } info;
893
894         g_return_val_if_fail (filename != NULL, NULL);
895         g_return_val_if_fail (width > 0 && height > 0, NULL);
896
897         f = fopen (filename, "rb");
898         if (!f) {
899                 g_set_error (error,
900                              G_FILE_ERROR,
901                              g_file_error_from_errno (errno),
902                              _("Failed to open file '%s': %s"),
903                              filename, g_strerror (errno));
904                 return NULL;
905         }
906
907         loader = gdk_pixbuf_loader_new ();
908
909         info.width = width;
910         info.height = height;
911                 
912         g_signal_connect (loader, "size-prepared", G_CALLBACK (size_prepared_cb), &info);
913
914         while (!feof (f) && !ferror (f)) {
915                 length = fread (buffer, 1, sizeof (buffer), f);
916                 if (length > 0)
917                         if (!gdk_pixbuf_loader_write (loader, buffer, length, error)) {
918                                 gdk_pixbuf_loader_close (loader, NULL);
919                                 fclose (f);
920                                 g_object_unref (loader);
921                                 return NULL;
922                         }
923         }
924
925         fclose (f);
926
927         if (!gdk_pixbuf_loader_close (loader, error)) {
928                 g_object_unref (loader);
929                 return NULL;
930         }
931
932         pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
933
934         if (!pixbuf) {
935                 g_object_unref (loader);
936                 g_set_error (error,
937                              GDK_PIXBUF_ERROR,
938                              GDK_PIXBUF_ERROR_FAILED,
939                              _("Failed to load image '%s': reason not known, probably a corrupt image file"),
940                              filename);
941                 return NULL;
942         }
943
944         g_object_ref (pixbuf);
945
946         g_object_unref (loader);
947
948         return pixbuf;
949 }
950
951 static void
952 info_cb (GdkPixbufLoader *loader, 
953          int              width,
954          int              height,
955          gpointer         data)
956 {
957         struct {
958                 GdkPixbufFormat *format;
959                 int width;
960                 int height;
961         } *info = data;
962
963         g_return_if_fail (width > 0 && height > 0);
964
965         info->format = gdk_pixbuf_loader_get_format (loader);
966         info->width = width;
967         info->height = height;
968
969         gdk_pixbuf_loader_set_size (loader, 0, 0);
970 }
971
972 /**
973  * gdk_pixbuf_get_file_info:
974  * @filename: The name of the file to identify.
975  * @width: Return location for the width of the image, or %NULL
976  * @height: Return location for the height of the image, or %NULL
977  * 
978  * Parses an image file far enough to determine its format and size.
979  * 
980  * Returns: A #GdkPixbufFormat describing the image format of the file 
981  *    or %NULL if the image format wasn't recognized. The return value 
982  *    is owned by GdkPixbuf and should not be freed.
983  *
984  * Since: 2.4
985  **/
986 GdkPixbufFormat *
987 gdk_pixbuf_get_file_info (const gchar  *filename,
988                           gint         *width, 
989                           gint         *height)
990 {
991         GdkPixbufLoader *loader;
992         guchar buffer [4096];
993         int length;
994         FILE *f;
995         struct {
996                 GdkPixbufFormat *format;
997                 gint width;
998                 gint height;
999         } info;
1000
1001         g_return_val_if_fail (filename != NULL, NULL);
1002
1003         f = fopen (filename, "rb");
1004         if (!f)
1005                 return NULL;
1006
1007         loader = gdk_pixbuf_loader_new ();
1008
1009         info.format = NULL;
1010         info.width = -1;
1011         info.height = -1;
1012                 
1013         g_signal_connect (loader, "size-prepared", G_CALLBACK (info_cb), &info);
1014
1015         while (!feof (f) && !ferror (f)) {
1016                 length = fread (buffer, 1, sizeof (buffer), f);
1017                 if (length > 0) {
1018                         if (!gdk_pixbuf_loader_write (loader, buffer, length, NULL))
1019                                 break;
1020                 }
1021                 if (info.format != NULL)
1022                         break;
1023         }
1024
1025         fclose (f);
1026         gdk_pixbuf_loader_close (loader, NULL);
1027         g_object_unref (loader);
1028
1029         if (width) 
1030                 *width = info.width;
1031         if (height) 
1032                 *height = info.height;
1033
1034         return info.format;
1035 }
1036
1037 /**
1038  * gdk_pixbuf_new_from_xpm_data:
1039  * @data: Pointer to inline XPM data.
1040  *
1041  * Creates a new pixbuf by parsing XPM data in memory.  This data is commonly
1042  * the result of including an XPM file into a program's C source.
1043  *
1044  * Return value: A newly-created pixbuf with a reference count of 1.
1045  **/
1046 GdkPixbuf *
1047 gdk_pixbuf_new_from_xpm_data (const char **data)
1048 {
1049         GdkPixbuf *(* load_xpm_data) (const char **data);
1050         GdkPixbuf *pixbuf;
1051         GError *error = NULL;
1052         GdkPixbufModule *xpm_module = _gdk_pixbuf_get_named_module ("xpm", &error);
1053         if (xpm_module == NULL) {
1054                 g_warning ("Error loading XPM image loader: %s", error->message);
1055                 g_error_free (error);
1056                 return NULL;
1057         }
1058
1059         if (xpm_module->module == NULL) {
1060                 if (!_gdk_pixbuf_load_module (xpm_module, &error)) {
1061                         g_warning ("Error loading XPM image loader: %s", error->message);
1062                         g_error_free (error);
1063                         return NULL;
1064                 }
1065         }
1066           
1067         if (xpm_module->load_xpm_data == NULL) {
1068                 g_warning ("gdk-pixbuf XPM module lacks XPM data capability");
1069                 return NULL;
1070         } else
1071                 load_xpm_data = xpm_module->load_xpm_data;
1072
1073         pixbuf = (* load_xpm_data) (data);
1074         return pixbuf;
1075 }
1076
1077 static void
1078 collect_save_options (va_list   opts,
1079                       gchar  ***keys,
1080                       gchar  ***vals)
1081 {
1082   gchar *key;
1083   gchar *val;
1084   gchar *next;
1085   gint count;
1086
1087   count = 0;
1088   *keys = NULL;
1089   *vals = NULL;
1090   
1091   next = va_arg (opts, gchar*);
1092   while (next)
1093     {
1094       key = next;
1095       val = va_arg (opts, gchar*);
1096
1097       ++count;
1098
1099       /* woo, slow */
1100       *keys = g_realloc (*keys, sizeof(gchar*) * (count + 1));
1101       *vals = g_realloc (*vals, sizeof(gchar*) * (count + 1));
1102       
1103       (*keys)[count-1] = g_strdup (key);
1104       (*vals)[count-1] = g_strdup (val);
1105
1106       (*keys)[count] = NULL;
1107       (*vals)[count] = NULL;
1108       
1109       next = va_arg (opts, gchar*);
1110     }
1111 }
1112
1113 static gboolean
1114 save_to_file_callback (const gchar *buf,
1115                        gsize        count,
1116                        GError     **error,
1117                        gpointer     data)
1118 {
1119         FILE *filehandle = data;
1120         gsize n;
1121
1122         n = fwrite (buf, 1, count, filehandle);
1123         if (n != count) {
1124                 g_set_error (error,
1125                              G_FILE_ERROR,
1126                              g_file_error_from_errno (errno),
1127                              _("Error writing to image file: %s"),
1128                              g_strerror (errno));
1129                 return FALSE;
1130         }
1131         return TRUE;
1132 }
1133
1134 static gboolean
1135 gdk_pixbuf_real_save (GdkPixbuf     *pixbuf, 
1136                       FILE          *filehandle, 
1137                       const char    *type, 
1138                       gchar        **keys,
1139                       gchar        **values,
1140                       GError       **error)
1141 {
1142        GdkPixbufModule *image_module = NULL;       
1143
1144        image_module = _gdk_pixbuf_get_named_module (type, error);
1145
1146        if (image_module == NULL)
1147                return FALSE;
1148        
1149        if (image_module->module == NULL)
1150                if (!_gdk_pixbuf_load_module (image_module, error))
1151                        return FALSE;
1152
1153        if (image_module->save) {
1154                /* save normally */
1155                return (* image_module->save) (filehandle, pixbuf,
1156                                               keys, values,
1157                                               error);
1158        }
1159        else if (image_module->save_to_callback) {
1160                /* save with simple callback */
1161                return (* image_module->save_to_callback) (save_to_file_callback,
1162                                                           filehandle, pixbuf,
1163                                                           keys, values,
1164                                                           error);
1165        }
1166        else {
1167                /* can't save */
1168                g_set_error (error,
1169                             GDK_PIXBUF_ERROR,
1170                             GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
1171                             _("This build of gdk-pixbuf does not support saving the image format: %s"),
1172                             type);
1173                return FALSE;
1174        }
1175 }
1176
1177 #define TMP_FILE_BUF_SIZE 4096
1178
1179 static gboolean
1180 save_to_callback_with_tmp_file (GdkPixbufModule   *image_module,
1181                                 GdkPixbuf         *pixbuf,
1182                                 GdkPixbufSaveFunc  save_func,
1183                                 gpointer           user_data,
1184                                 gchar            **keys,
1185                                 gchar            **values,
1186                                 GError           **error)
1187 {
1188         int fd;
1189         FILE *f = NULL;
1190         gboolean retval = FALSE;
1191         gchar *buf = NULL;
1192         gsize n;
1193         gchar *filename = NULL;
1194
1195         buf = g_try_malloc (TMP_FILE_BUF_SIZE);
1196         if (buf == NULL) {
1197                 g_set_error (error,
1198                              GDK_PIXBUF_ERROR,
1199                              GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
1200                              _("Insufficient memory to save image to callback"));
1201                 goto end;
1202         }
1203
1204         fd = g_file_open_tmp ("gdkpixbuf-save-tmp.XXXXXX", &filename, error);
1205         if (fd == -1)
1206                 goto end;
1207         f = fdopen (fd, "wb+");
1208         if (f == NULL) {
1209                 g_set_error (error,
1210                              G_FILE_ERROR,
1211                              g_file_error_from_errno (errno),
1212                              _("Failed to open temporary file"));
1213                 goto end;
1214         }
1215         if (!(* image_module->save) (f, pixbuf, keys, values, error))
1216                 goto end;
1217         rewind (f);
1218         for (;;) {
1219                 n = fread (buf, 1, TMP_FILE_BUF_SIZE, f);
1220                 if (n > 0) {
1221                         if (!save_func (buf, n, error, user_data))
1222                                 goto end;
1223                 }
1224                 if (n != TMP_FILE_BUF_SIZE) 
1225                         break;
1226         }
1227         if (ferror (f)) {
1228                 g_set_error (error,
1229                              G_FILE_ERROR,
1230                              g_file_error_from_errno (errno),
1231                              _("Failed to read from temporary file"));
1232                 goto end;
1233         }
1234         retval = TRUE;
1235
1236  end:
1237         /* cleanup and return retval */
1238         if (f)
1239                 fclose (f);
1240         if (filename) {
1241                 unlink (filename);
1242                 g_free (filename);
1243         }
1244         g_free (buf);
1245
1246         return retval;
1247 }
1248
1249 static gboolean
1250 gdk_pixbuf_real_save_to_callback (GdkPixbuf         *pixbuf,
1251                                   GdkPixbufSaveFunc  save_func,
1252                                   gpointer           user_data,
1253                                   const char        *type, 
1254                                   gchar            **keys,
1255                                   gchar            **values,
1256                                   GError           **error)
1257 {
1258        GdkPixbufModule *image_module = NULL;       
1259
1260        image_module = _gdk_pixbuf_get_named_module (type, error);
1261
1262        if (image_module == NULL)
1263                return FALSE;
1264        
1265        if (image_module->module == NULL)
1266                if (!_gdk_pixbuf_load_module (image_module, error))
1267                        return FALSE;
1268
1269        if (image_module->save_to_callback) {
1270                /* save normally */
1271                return (* image_module->save_to_callback) (save_func, user_data, 
1272                                                           pixbuf, keys, values,
1273                                                           error);
1274        }
1275        else if (image_module->save) {
1276                /* use a temporary file */
1277                return save_to_callback_with_tmp_file (image_module, pixbuf,
1278                                                       save_func, user_data, 
1279                                                       keys, values,
1280                                                       error);
1281        }
1282        else {
1283                /* can't save */
1284                g_set_error (error,
1285                             GDK_PIXBUF_ERROR,
1286                             GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
1287                             _("This build of gdk-pixbuf does not support saving the image format: %s"),
1288                             type);
1289                return FALSE;
1290        }
1291 }
1292
1293  
1294 /**
1295  * gdk_pixbuf_save:
1296  * @pixbuf: a #GdkPixbuf.
1297  * @filename: name of file to save.
1298  * @type: name of file format.
1299  * @error: return location for error, or %NULL
1300  * @Varargs: list of key-value save options
1301  *
1302  * Saves pixbuf to a file in format @type. By default, "jpeg", "png" and 
1303  * "ico" are possible file formats to save in, but more formats may be
1304  * installed. The list of all writable formats can be determined in the 
1305  * following way:
1306  *
1307  * <informalexample><programlisting>
1308  * void add_if_writable (GdkPixbufFormat *data, GSList **list)
1309  * {
1310  *   if (gdk_pixbuf_format_is_writable (data))
1311  *     *list = g_slist_prepend (*list, data);
1312  * }
1313  * <!-- -->
1314  * GSList *formats = gdk_pixbuf_get_formats (<!-- -->);
1315  * GSList *writable_formats = NULL;
1316  * g_slist_foreach (formats, add_if_writable, &amp;writable_formats);
1317  * g_slist_free (formats);
1318  * </programlisting></informalexample>
1319  *
1320  * If @error is set, %FALSE will be returned. Possible errors include 
1321  * those in the #GDK_PIXBUF_ERROR domain and those in the #G_FILE_ERROR domain.
1322  *
1323  * The variable argument list should be %NULL-terminated; if not empty,
1324  * it should contain pairs of strings that modify the save
1325  * parameters. For example:
1326  * <informalexample><programlisting>
1327  * gdk_pixbuf_save (pixbuf, handle, "jpeg", &amp;error,
1328  *                  "quality", "100", NULL);
1329  * </programlisting></informalexample>
1330  *
1331  * Currently only few parameters exist. JPEG images can be saved with a 
1332  * "quality" parameter; its value should be in the range [0,100]. 
1333  * Text chunks can be attached to PNG images by specifying parameters of
1334  * the form "tEXt::key", where key is an ASCII string of length 1-79.
1335  * The values are UTF-8 encoded strings. 
1336  * ICO images can be saved in depth 16, 24, or 32, by using the "depth"
1337  * parameter. When the ICO saver is given "x_hot" and "y_hot" parameters,
1338  * it produces a CUR instead of an ICO.
1339  *
1340  * Return value: whether an error was set
1341  **/
1342
1343 gboolean
1344 gdk_pixbuf_save (GdkPixbuf  *pixbuf, 
1345                  const char *filename, 
1346                  const char *type, 
1347                  GError    **error,
1348                  ...)
1349 {
1350         gchar **keys = NULL;
1351         gchar **values = NULL;
1352         va_list args;
1353         gboolean result;
1354
1355         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1356         
1357         va_start (args, error);
1358         
1359         collect_save_options (args, &keys, &values);
1360         
1361         va_end (args);
1362
1363         result = gdk_pixbuf_savev (pixbuf, filename, type,
1364                                    keys, values,
1365                                    error);
1366
1367         g_strfreev (keys);
1368         g_strfreev (values);
1369
1370         return result;
1371 }
1372
1373 /**
1374  * gdk_pixbuf_savev:
1375  * @pixbuf: a #GdkPixbuf.
1376  * @filename: name of file to save.
1377  * @type: name of file format.
1378  * @option_keys: name of options to set, %NULL-terminated
1379  * @option_values: values for named options
1380  * @error: return location for error, or %NULL
1381  *
1382  * Saves pixbuf to a file in @type, which is currently "jpeg", "png" or "ico".
1383  * If @error is set, %FALSE will be returned. 
1384  * See gdk_pixbuf_save () for more details.
1385  *
1386  * Return value: whether an error was set
1387  **/
1388
1389 gboolean
1390 gdk_pixbuf_savev (GdkPixbuf  *pixbuf, 
1391                   const char *filename, 
1392                   const char *type,
1393                   char      **option_keys,
1394                   char      **option_values,
1395                   GError    **error)
1396 {
1397         FILE *f = NULL;
1398         gboolean result;
1399         
1400        
1401         g_return_val_if_fail (filename != NULL, FALSE);
1402         g_return_val_if_fail (type != NULL, FALSE);
1403         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1404        
1405         f = fopen (filename, "wb");
1406         
1407         if (f == NULL) {
1408                 g_set_error (error,
1409                              G_FILE_ERROR,
1410                              g_file_error_from_errno (errno),
1411                              _("Failed to open '%s' for writing: %s"),
1412                              filename, g_strerror (errno));
1413                 return FALSE;
1414         }
1415
1416        
1417        result = gdk_pixbuf_real_save (pixbuf, f, type,
1418                                       option_keys, option_values,
1419                                       error);
1420        
1421        
1422        if (!result) {
1423                g_return_val_if_fail (error == NULL || *error != NULL, FALSE);
1424                fclose (f);
1425                return FALSE;
1426        }
1427
1428        if (fclose (f) < 0) {
1429                g_set_error (error,
1430                             G_FILE_ERROR,
1431                             g_file_error_from_errno (errno),
1432                             _("Failed to close '%s' while writing image, all data may not have been saved: %s"),
1433                             filename, g_strerror (errno));
1434                return FALSE;
1435        }
1436        
1437        return TRUE;
1438 }
1439
1440 /**
1441  * gdk_pixbuf_save_to_callback:
1442  * @pixbuf: a #GdkPixbuf.
1443  * @save_func: a function that is called to save each block of data that
1444  *   the save routine generates.
1445  * @user_data: user data to pass to the save function.
1446  * @type: name of file format.
1447  * @error: return location for error, or %NULL
1448  * @Varargs: list of key-value save options
1449  *
1450  * Saves pixbuf in format @type by feeding the produced data to a 
1451  * callback. Can be used when you want to store the image to something 
1452  * other than a file, such as an in-memory buffer or a socket.  
1453  * If @error is set, %FALSE will be returned. Possible errors
1454  * include those in the #GDK_PIXBUF_ERROR domain and whatever the save
1455  * function generates.
1456  *
1457  * See gdk_pixbuf_save() for more details.
1458  *
1459  * Return value: whether an error was set
1460  *
1461  * Since: 2.4
1462  **/
1463 gboolean
1464 gdk_pixbuf_save_to_callback    (GdkPixbuf  *pixbuf,
1465                                 GdkPixbufSaveFunc save_func,
1466                                 gpointer user_data,
1467                                 const char *type, 
1468                                 GError    **error,
1469                                 ...)
1470 {
1471         gchar **keys = NULL;
1472         gchar **values = NULL;
1473         va_list args;
1474         gboolean result;
1475         
1476         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1477         
1478         va_start (args, error);
1479         
1480         collect_save_options (args, &keys, &values);
1481         
1482         va_end (args);
1483
1484         result = gdk_pixbuf_save_to_callbackv (pixbuf, save_func, user_data,
1485                                                type, keys, values,
1486                                                error);
1487
1488         g_strfreev (keys);
1489         g_strfreev (values);
1490
1491         return result;
1492 }
1493
1494 /**
1495  * gdk_pixbuf_save_to_callbackv:
1496  * @pixbuf: a #GdkPixbuf.
1497  * @save_func: a function that is called to save each block of data that
1498  *   the save routine generates.
1499  * @user_data: user data to pass to the save function.
1500  * @type: name of file format.
1501  * @option_keys: name of options to set, %NULL-terminated
1502  * @option_values: values for named options
1503  * @error: return location for error, or %NULL
1504  *
1505  * Saves pixbuf to a callback in format @type, which is currently "jpeg",
1506  * "png" or "ico".  If @error is set, %FALSE will be returned. See
1507  * gdk_pixbuf_save_to_callback () for more details.
1508  *
1509  * Return value: whether an error was set
1510  *
1511  * Since: 2.4
1512  **/
1513 gboolean
1514 gdk_pixbuf_save_to_callbackv   (GdkPixbuf  *pixbuf, 
1515                                 GdkPixbufSaveFunc save_func,
1516                                 gpointer user_data,
1517                                 const char *type,
1518                                 char      **option_keys,
1519                                 char      **option_values,
1520                                 GError    **error)
1521 {
1522         gboolean result;
1523         
1524        
1525         g_return_val_if_fail (save_func != NULL, FALSE);
1526         g_return_val_if_fail (type != NULL, FALSE);
1527         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1528        
1529        result = gdk_pixbuf_real_save_to_callback (pixbuf,
1530                                                   save_func, user_data, type,
1531                                                   option_keys, option_values,
1532                                                   error);
1533        
1534        if (!result) {
1535                g_return_val_if_fail (error == NULL || *error != NULL, FALSE);
1536                return FALSE;
1537        }
1538
1539        return TRUE;
1540 }
1541
1542 /**
1543  * gdk_pixbuf_save_to_buffer:
1544  * @pixbuf: a #GdkPixbuf.
1545  * @buffer: location to receive a pointer to the new buffer.
1546  * @buffer_size: location to receive the size of the new buffer.
1547  * @type: name of file format.
1548  * @error: return location for error, or %NULL
1549  * @Varargs: list of key-value save options
1550  *
1551  * Saves pixbuf to a new buffer in format @type, which is currently "jpeg",
1552  * "png" or "ico".  This is a convenience function that uses
1553  * gdk_pixbuf_save_to_callback() to do the real work. Note that the buffer 
1554  * is not nul-terminated and may contain embedded  nuls.
1555  * If @error is set, %FALSE will be returned and @string will be set to
1556  * %NULL. Possible errors include those in the #GDK_PIXBUF_ERROR
1557  * domain.
1558  *
1559  * See gdk_pixbuf_save() for more details.
1560  *
1561  * Return value: whether an error was set
1562  *
1563  * Since: 2.4
1564  **/
1565 gboolean
1566 gdk_pixbuf_save_to_buffer      (GdkPixbuf  *pixbuf,
1567                                 gchar     **buffer,
1568                                 gsize      *buffer_size,
1569                                 const char *type, 
1570                                 GError    **error,
1571                                 ...)
1572 {
1573         gchar **keys = NULL;
1574         gchar **values = NULL;
1575         va_list args;
1576         gboolean result;
1577         
1578         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1579         
1580         va_start (args, error);
1581         
1582         collect_save_options (args, &keys, &values);
1583         
1584         va_end (args);
1585
1586         result = gdk_pixbuf_save_to_bufferv (pixbuf, buffer, buffer_size,
1587                                              type, keys, values,
1588                                              error);
1589
1590         g_strfreev (keys);
1591         g_strfreev (values);
1592
1593         return result;
1594 }
1595
1596 struct SaveToBufferData {
1597         gchar *buffer;
1598         gsize len, max;
1599 };
1600
1601 static gboolean
1602 save_to_buffer_callback (const gchar *data,
1603                          gsize count,
1604                          GError **error,
1605                          gpointer user_data)
1606 {
1607         struct SaveToBufferData *sdata = user_data;
1608         gchar *new_buffer;
1609         gsize new_max;
1610
1611         if (sdata->len + count > sdata->max) {
1612                 new_max = MAX (sdata->max*2, sdata->len + count);
1613                 new_buffer = g_try_realloc (sdata->buffer, new_max);
1614                 if (!new_buffer) {
1615                         g_set_error (error,
1616                                      GDK_PIXBUF_ERROR,
1617                                      GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
1618                                      _("Insufficient memory to save image into a buffer"));
1619                         return FALSE;
1620                 }
1621                 sdata->buffer = new_buffer;
1622                 sdata->max = new_max;
1623         }
1624         memcpy (sdata->buffer + sdata->len, data, count);
1625         sdata->len += count;
1626         return TRUE;
1627 }
1628
1629 /**
1630  * gdk_pixbuf_save_to_bufferv:
1631  * @pixbuf: a #GdkPixbuf.
1632  * @buffer: location to receive a pointer to the new buffer.
1633  * @buffer_size: location to receive the size of the new buffer.
1634  * @type: name of file format.
1635  * @option_keys: name of options to set, %NULL-terminated
1636  * @option_values: values for named options
1637  * @error: return location for error, or %NULL
1638  *
1639  * Saves pixbuf to a new buffer in format @type, which is currently "jpeg",
1640  * "png" or "ico".  See gdk_pixbuf_save_to_buffer() for more details.
1641  *
1642  * Return value: whether an error was set
1643  *
1644  * Since: 2.4
1645  **/
1646 gboolean
1647 gdk_pixbuf_save_to_bufferv     (GdkPixbuf  *pixbuf,
1648                                 gchar     **buffer,
1649                                 gsize      *buffer_size,
1650                                 const char *type, 
1651                                 char      **option_keys,
1652                                 char      **option_values,
1653                                 GError    **error)
1654 {
1655         static const gint initial_max = 1024;
1656         struct SaveToBufferData sdata;
1657
1658         *buffer = NULL;
1659         *buffer_size = 0;
1660
1661         sdata.buffer = g_try_malloc (initial_max);
1662         sdata.max = initial_max;
1663         sdata.len = 0;
1664         if (!sdata.buffer) {
1665                 g_set_error (error,
1666                              GDK_PIXBUF_ERROR,
1667                              GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
1668                              _("Insufficient memory to save image into a buffer"));
1669                 return FALSE;
1670         }
1671
1672         if (!gdk_pixbuf_save_to_callbackv (pixbuf,
1673                                            save_to_buffer_callback, &sdata,
1674                                            type, option_keys, option_values,
1675                                            error)) {
1676                 g_free (sdata.buffer);
1677                 return FALSE;
1678         }
1679
1680         *buffer = sdata.buffer;
1681         *buffer_size = sdata.len;
1682         return TRUE;
1683 }
1684
1685 /**
1686  * gdk_pixbuf_format_get_name:
1687  * @format: a #GdkPixbufFormat
1688  *
1689  * Returns the name of the format.
1690  * 
1691  * Return value: the name of the format. 
1692  *
1693  * Since: 2.2
1694  */
1695 gchar *
1696 gdk_pixbuf_format_get_name (GdkPixbufFormat *format)
1697 {
1698         g_return_val_if_fail (format != NULL, NULL);
1699
1700         return g_strdup (format->name);
1701 }
1702
1703 /**
1704  * gdk_pixbuf_format_get_description:
1705  * @format: a #GdkPixbufFormat
1706  *
1707  * Returns a description of the format.
1708  * 
1709  * Return value: a description of the format.
1710  *
1711  * Since: 2.2
1712  */
1713 gchar *
1714 gdk_pixbuf_format_get_description (GdkPixbufFormat *format)
1715 {
1716         gchar *domain;
1717         gchar *description;
1718         g_return_val_if_fail (format != NULL, NULL);
1719
1720         if (format->domain != NULL) 
1721                 domain = format->domain;
1722         else 
1723                 domain = GETTEXT_PACKAGE;
1724         description = dgettext (domain, format->description);
1725
1726         return g_strdup (description);
1727 }
1728
1729 /**
1730  * gdk_pixbuf_format_get_mime_types:
1731  * @format: a #GdkPixbufFormat
1732  *
1733  * Returns the mime types supported by the format.
1734  * 
1735  * Return value: a %NULL-terminated array of mime types which must be freed with 
1736  * g_strfreev() when it is no longer needed.
1737  *
1738  * Since: 2.2
1739  */
1740 gchar **
1741 gdk_pixbuf_format_get_mime_types (GdkPixbufFormat *format)
1742 {
1743         g_return_val_if_fail (format != NULL, NULL);
1744
1745         return g_strdupv (format->mime_types);
1746 }
1747
1748 /**
1749  * gdk_pixbuf_format_get_extensions:
1750  * @format: a #GdkPixbufFormat
1751  *
1752  * Returns the filename extensions typically used for files in the 
1753  * given format.
1754  * 
1755  * Return value: a %NULL-terminated array of filename extensions which must be
1756  * freed with g_strfreev() when it is no longer needed.
1757  *
1758  * Since: 2.2
1759  */
1760 gchar **
1761 gdk_pixbuf_format_get_extensions (GdkPixbufFormat *format)
1762 {
1763         g_return_val_if_fail (format != NULL, NULL);
1764
1765         return g_strdupv (format->extensions);
1766 }
1767
1768 /**
1769  * gdk_pixbuf_format_is_writable:
1770  * @format: a #GdkPixbufFormat
1771  *
1772  * Returns whether pixbufs can be saved in the given format.
1773  * 
1774  * Return value: whether pixbufs can be saved in the given format.
1775  *
1776  * Since: 2.2
1777  */
1778 gboolean
1779 gdk_pixbuf_format_is_writable (GdkPixbufFormat *format)
1780 {
1781         g_return_val_if_fail (format != NULL, FALSE);
1782
1783         return (format->flags & GDK_PIXBUF_FORMAT_WRITABLE) != 0;
1784 }
1785
1786 GdkPixbufFormat *
1787 _gdk_pixbuf_get_format (GdkPixbufModule *module)
1788 {
1789         g_return_val_if_fail (module != NULL, NULL);
1790
1791         return module->info;
1792 }
1793
1794 /**
1795  * gdk_pixbuf_get_formats:
1796  *
1797  * Obtains the available information about the image formats supported
1798  * by GdkPixbuf.
1799  *
1800  * Returns: A list of #GdkPixbufFormat<!-- -->s describing the supported 
1801  * image formats.  The list should be freed when it is no longer needed, 
1802  * but the structures themselves are owned by #GdkPixbuf and should not be 
1803  * freed.  
1804  *
1805  * Since: 2.2
1806  */
1807 GSList *
1808 gdk_pixbuf_get_formats (void)
1809 {
1810         GSList *result = NULL;
1811         GSList *modules;
1812
1813         for (modules = get_file_formats (); modules; modules = g_slist_next (modules)) {
1814                 GdkPixbufModule *module = (GdkPixbufModule *)modules->data;
1815                 GdkPixbufFormat *info = _gdk_pixbuf_get_format (module);
1816                 result = g_slist_prepend (result, info);
1817         }
1818
1819         return result;
1820 }
1821
1822
1823
1824
1825