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, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include "config.h"
23 
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <errno.h>
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31 
32 #include <glib.h>
33 #include <gio/gio.h>
34 
35 #include "gdk-pixbuf-private.h"
36 #include "gdk-pixbuf-loader.h"
37 #include "gdk-pixdata.h"
38 
39 #include <glib/gstdio.h>
40 
41 #ifdef G_OS_WIN32
42 #define STRICT
43 #include <windows.h>
44 #undef STRICT
45 #endif
46 #ifdef OS_DARWIN
47 #include <mach-o/dyld.h>
48 #endif
49 
50 /**
51  * SECTION:file-loading
52  * @Short_description: Loading a pixbuf from a file.
53  * @Title: File Loading
54  * @See_also: #GdkPixbufLoader.
55  *
56  * The GdkPixBuf library provides a simple mechanism for loading
57  * an image from a file in synchronous fashion.  This means that the
58  * library takes control of the application while the file is being
59  * loaded; from the user's point of view, the application will block
60  * until the image is done loading.
61  *
62  *
63  * This interface can be used by applications in which blocking is
64  * acceptable while an image is being loaded.  It can also be used to
65  * load small images in general.  Applications that need progressive
66  * loading can use the #GdkPixbufLoader functionality instead.
67  */
68 
69 /**
70  * SECTION:file-saving
71  * @Short_description: Saving a pixbuf to a file.
72  * @Title: File saving
73  *
74  * These functions allow to save a #GdkPixbuf in a number of
75  * file formats. The formatted data can be written to a file
76  * or to a memory buffer. GdkPixBuf can also call a user-defined
77  * callback on the data, which allows to e.g. write the image
78  * to a socket or store it in a database.
79  */
80 
81 /**
82  * SECTION:module_interface
83  * @Short_description: Extending GdkPixBuf
84  * @Title: Module Interface
85  *
86  * If GdkPixBuf has been compiled with GModule support, it can be extended by
87  * modules which can load (and perhaps also save) new image and animation
88  * formats. Each loadable module must export a
89  * #GdkPixbufModuleFillInfoFunc function named `fill_info` and
90  * a #GdkPixbufModuleFillVtableFunc function named
91  * `fill_vtable`.
92  *
93  * In order to make format-checking work before actually loading the modules
94  * (which may require dlopening image libraries), modules export their
95  * signatures (and other information) via the `fill_info` function. An
96  * external utility, gdk-pixbuf-query-loaders, uses this to create a text
97  * file containing a list of all available loaders and  their signatures.
98  * This file is then read at runtime by GdkPixBuf to obtain the list of
99  * available loaders and their signatures.
100  *
101  * Modules may only implement a subset of the functionality available via
102  * #GdkPixbufModule. If a particular functionality is not implemented, the
103  * `fill_vtable` function will simply not set the corresponding
104  * function pointers of the #GdkPixbufModule structure. If a module supports
105  * incremental loading (i.e. provides #begin_load, #stop_load and
106  * #load_increment), it doesn't have to implement #load, since GdkPixBuf can
107  * supply a generic #load implementation wrapping the incremental loading.
108  *
109  * Installing a module is a two-step process:
110  * - copy the module file(s) to the loader directory (normally
111  *   `$libdir/gdk-pixbuf-2.0/$version/loaders`, unless overridden by the
112  *   environment variable `GDK_PIXBUF_MODULEDIR`)
113  * - call gdk-pixbuf-query-loaders to update the module file (normally
114  *   `$libdir/gdk-pixbuf-2.0/$version/loaders.cache`, unless overridden by the
115  *   environment variable `GDK_PIXBUF_MODULE_FILE`)
116  *
117  * The GdkPixBuf interfaces needed for implementing modules are contained in
118  * `gdk-pixbuf-io.h` (and `gdk-pixbuf-animation.h` if the module supports
119  * animations). They are not covered by the same stability guarantees as the
120  * regular  GdkPixBuf API. To underline this fact, they are protected by
121  * `#ifdef GDK_PIXBUF_ENABLE_BACKEND`.
122  */
123 
124 
125 static gint
format_check(GdkPixbufModule * module,guchar * buffer,int size)126 format_check (GdkPixbufModule *module, guchar *buffer, int size)
127 {
128         int i, j;
129         gchar m;
130         GdkPixbufModulePattern *pattern;
131         gboolean anchored;
132         guchar *prefix;
133         gchar *mask;
134 
135         for (pattern = module->info->signature; pattern->prefix; pattern++) {
136                 if (pattern->mask && pattern->mask[0] == '*') {
137                         prefix = (guchar *)pattern->prefix + 1;
138                         mask = pattern->mask + 1;
139                         anchored = FALSE;
140                 }
141                 else {
142                         prefix = (guchar *)pattern->prefix;
143                         mask = pattern->mask;
144                         anchored = TRUE;
145                 }
146                 for (i = 0; i < size; i++) {
147                         for (j = 0; i + j < size && prefix[j] != 0; j++) {
148                                 m = mask ? mask[j] : ' ';
149                                 if (m == ' ') {
150                                         if (buffer[i + j] != prefix[j])
151                                                 break;
152                                 }
153                                 else if (m == '!') {
154                                         if (buffer[i + j] == prefix[j])
155                                                 break;
156                                 }
157                                 else if (m == 'z') {
158                                         if (buffer[i + j] != 0)
159                                                 break;
160                                 }
161                                 else if (m == 'n') {
162                                         if (buffer[i + j] == 0)
163                                                 break;
164                                 }
165                         }
166 
167                         if (prefix[j] == 0)
168                                 return pattern->relevance;
169 
170                         if (anchored)
171                                 break;
172                 }
173         }
174         return 0;
175 }
176 
177 G_LOCK_DEFINE_STATIC (init_lock);
178 
179 static gboolean file_formats_inited;
180 static GSList *file_formats = NULL;
181 
182 static gboolean gdk_pixbuf_io_init (void);
183 
184 static GSList *
get_file_formats(void)185 get_file_formats (void)
186 {
187         G_LOCK (init_lock);
188         if (file_formats == NULL ||
189             !file_formats_inited)
190                 file_formats_inited = gdk_pixbuf_io_init ();
191         G_UNLOCK (init_lock);
192 
193         return file_formats;
194 }
195 
196 #ifdef G_OS_WIN32
197 
198 /* DllMain function needed to tuck away the gdk-pixbuf DLL handle */
199 
200 static HMODULE gdk_pixbuf_dll;
201 
202 BOOL WINAPI
DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)203 DllMain (HINSTANCE hinstDLL,
204          DWORD     fdwReason,
205          LPVOID    lpvReserved)
206 {
207         switch (fdwReason) {
208         case DLL_PROCESS_ATTACH:
209                 gdk_pixbuf_dll = (HMODULE) hinstDLL;
210                 break;
211         }
212 
213   return TRUE;
214 }
215 #endif
216 
217 
218 #ifdef GDK_PIXBUF_RELOCATABLE
219 
220 gchar *
gdk_pixbuf_get_toplevel(void)221 gdk_pixbuf_get_toplevel (void)
222 {
223   static gchar *toplevel = NULL;
224 
225   if (toplevel == NULL) {
226 #if defined(G_OS_WIN32)
227     toplevel = g_win32_get_package_installation_directory_of_module (gdk_pixbuf_dll);
228 #elif defined(OS_DARWIN)
229     char pathbuf[PATH_MAX + 1];
230     uint32_t  bufsize = sizeof(pathbuf);
231     gchar *bin_dir;
232 
233     _NSGetExecutablePath(pathbuf, &bufsize);
234     bin_dir = g_dirname(pathbuf);
235     toplevel = g_build_path (G_DIR_SEPARATOR_S, bin_dir, "..", NULL);
236     g_free (bin_dir);
237 #elif defined (OS_LINUX)
238     gchar *exe_path, *bin_dir;
239 
240     exe_path = g_file_read_link ("/proc/self/exe", NULL);
241     bin_dir = g_dirname(exe_path);
242     toplevel = g_build_path (G_DIR_SEPARATOR_S, bin_dir, "..", NULL);
243     g_free (exe_path);
244     g_free (bin_dir);
245 #else
246 #error "Relocations not supported for this platform"
247 #endif
248   }
249   return toplevel;
250 }
251 
252 #endif  /* GDK_PIXBUF_RELOCATABLE */
253 
254 
255 #ifdef USE_GMODULE
256 
257 static gboolean
scan_string(const char ** pos,GString * out)258 scan_string (const char **pos, GString *out)
259 {
260         const char *p = *pos, *q = *pos;
261         char *tmp, *tmp2;
262         gboolean quoted;
263 
264         while (g_ascii_isspace (*p))
265                 p++;
266 
267         if (!*p)
268                 return FALSE;
269         else if (*p == '"') {
270                 p++;
271                 quoted = FALSE;
272                 for (q = p; (*q != '"') || quoted; q++) {
273                         if (!*q)
274                                 return FALSE;
275                         quoted = (*q == '\\') && !quoted;
276                 }
277 
278                 tmp = g_strndup (p, q - p);
279                 tmp2 = g_strcompress (tmp);
280                 g_string_truncate (out, 0);
281                 g_string_append (out, tmp2);
282                 g_free (tmp);
283                 g_free (tmp2);
284         }
285 
286         q++;
287         *pos = q;
288 
289         return TRUE;
290 }
291 
292 static gboolean
scan_int(const char ** pos,int * out)293 scan_int (const char **pos, int *out)
294 {
295         int i = 0;
296         char buf[32];
297         const char *p = *pos;
298 
299         while (g_ascii_isspace (*p))
300                 p++;
301 
302         if (*p < '0' || *p > '9')
303                 return FALSE;
304 
305         while ((*p >= '0') && (*p <= '9') && i < sizeof (buf)) {
306                 buf[i] = *p;
307                 i++;
308                 p++;
309         }
310 
311         if (i == sizeof (buf))
312                 return FALSE;
313         else
314                 buf[i] = '\0';
315 
316         *out = atoi (buf);
317 
318         *pos = p;
319 
320         return TRUE;
321 }
322 
323 static gboolean
skip_space(const char ** pos)324 skip_space (const char **pos)
325 {
326         const char *p = *pos;
327 
328         while (g_ascii_isspace (*p))
329                 p++;
330 
331         *pos = p;
332 
333         return !(*p == '\0');
334 }
335 
336 #ifdef GDK_PIXBUF_RELOCATABLE
337 
338 static char *
get_libdir(void)339 get_libdir (void)
340 {
341   static char *libdir = NULL;
342 
343   if (libdir == NULL)
344           libdir = g_build_filename (gdk_pixbuf_get_toplevel (), "lib", NULL);
345 
346   return libdir;
347 }
348 
349 #undef GDK_PIXBUF_LIBDIR
350 #define GDK_PIXBUF_LIBDIR get_libdir()
351 
352 #endif  /* GDK_PIXBUF_RELOCATABLE */
353 
354 /* In case we have a relative module path in the loaders cache
355  * prepend the toplevel dir */
356 static gchar *
build_module_path(const gchar * path)357 build_module_path (const gchar *path)
358 {
359 #ifdef GDK_PIXBUF_RELOCATABLE
360         if (g_path_is_absolute (path)) {
361                 return g_strdup (path);
362         } else {
363                 return g_build_filename (gdk_pixbuf_get_toplevel (), path, NULL);
364         }
365 #else
366         return g_strdup (path);
367 #endif
368 }
369 
370 static gchar *
gdk_pixbuf_get_module_file(void)371 gdk_pixbuf_get_module_file (void)
372 {
373   gchar *result = g_strdup (g_getenv ("GDK_PIXBUF_MODULE_FILE"));
374 
375   if (!result)
376           result = g_build_filename (GDK_PIXBUF_LIBDIR, "gdk-pixbuf-2.0", GDK_PIXBUF_BINARY_VERSION, "loaders.cache", NULL);
377 
378   return result;
379 }
380 
381 #endif  /* USE_GMODULE */
382 
383 
384 static gboolean
385 gdk_pixbuf_load_module_unlocked (GdkPixbufModule *image_module,
386                                  GError         **error);
387 
388 static gboolean
gdk_pixbuf_io_init_modules(const char * filename,GError ** error)389 gdk_pixbuf_io_init_modules (const char  *filename,
390                             GError     **error)
391 {
392 #ifdef USE_GMODULE
393         GIOChannel *channel;
394         gchar *line_buf;
395         gsize term;
396         GString *tmp_buf = g_string_new (NULL);
397         gboolean have_error = FALSE;
398         GdkPixbufModule *module = NULL;
399         int flags;
400         int n_patterns = 0;
401         GdkPixbufModulePattern *pattern;
402         GError *local_error = NULL;
403         guint num_formats;
404 
405         channel = g_io_channel_new_file (filename, "r",  &local_error);
406         if (!channel) {
407                 g_set_error (error,
408                              G_IO_ERROR,
409                              G_IO_ERROR_INVALID_ARGUMENT,
410                              "Cannot open pixbuf loader module file '%s': %s\n\n"
411                              "This likely means that your installation is broken.\n"
412                              "Try running the command\n"
413                              "  gdk-pixbuf-query-loaders > %s\n"
414                              "to make things work again for the time being.",
415                              filename, local_error->message, filename);
416                 g_clear_error (&local_error);
417                 g_string_free (tmp_buf, TRUE);
418                 return FALSE;
419         }
420 
421         num_formats = g_slist_length (file_formats);
422 
423         while (!have_error && g_io_channel_read_line (channel, &line_buf, NULL, &term, NULL) == G_IO_STATUS_NORMAL) {
424                 const char *p;
425 
426                 p = line_buf;
427 
428                 line_buf[term] = 0;
429 
430                 if (!skip_space (&p)) {
431                                 /* Blank line marking the end of a module
432                                  */
433                         if (module && *p != '#') {
434                                 file_formats = g_slist_prepend (file_formats, module);
435                                 module = NULL;
436                         }
437 
438                         goto next_line;
439                 }
440 
441                 if (*p == '#')
442                         goto next_line;
443 
444                 if (!module) {
445                                 /* Read a module location
446                                  */
447                         module = g_new0 (GdkPixbufModule, 1);
448                         n_patterns = 0;
449 
450                         if (!scan_string (&p, tmp_buf)) {
451                                 g_warning ("Error parsing loader info in '%s'\n  %s",
452                                            filename, line_buf);
453                                 have_error = TRUE;
454                         }
455                         module->module_path = build_module_path (tmp_buf->str);
456                 }
457                 else if (!module->module_name) {
458                         module->info = g_new0 (GdkPixbufFormat, 1);
459                         if (!scan_string (&p, tmp_buf)) {
460                                 g_warning ("Error parsing loader info in '%s'\n  %s",
461                                            filename, line_buf);
462                                 have_error = TRUE;
463                         }
464                         module->info->name =  g_strdup (tmp_buf->str);
465                         module->module_name = module->info->name;
466 
467                         if (!scan_int (&p, &flags)) {
468                                 g_warning ("Error parsing loader info in '%s'\n  %s",
469                                            filename, line_buf);
470                                 have_error = TRUE;
471                         }
472                         module->info->flags = flags;
473 
474                         if (!scan_string (&p, tmp_buf)) {
475                                 g_warning ("Error parsing loader info in '%s'\n  %s",
476                                            filename, line_buf);
477                                 have_error = TRUE;
478                         }
479                         if (tmp_buf->str[0] != 0)
480                                 module->info->domain = g_strdup (tmp_buf->str);
481 
482                         if (!scan_string (&p, tmp_buf)) {
483                                 g_warning ("Error parsing loader info in '%s'\n  %s",
484                                            filename, line_buf);
485                                 have_error = TRUE;
486                         }
487                         module->info->description = g_strdup (tmp_buf->str);
488 
489                         if (scan_string (&p, tmp_buf)) {
490                                 module->info->license = g_strdup (tmp_buf->str);
491                         }
492                 }
493                 else if (!module->info->mime_types) {
494                         int n = 1;
495                         module->info->mime_types = g_new0 (gchar*, 1);
496                         while (scan_string (&p, tmp_buf)) {
497                                 if (tmp_buf->str[0] != 0) {
498                                         module->info->mime_types =
499                                                 g_realloc (module->info->mime_types, (n + 1) * sizeof (gchar*));
500                                         module->info->mime_types[n - 1] = g_strdup (tmp_buf->str);
501                                         module->info->mime_types[n] = NULL;
502                                         n++;
503                                 }
504                         }
505                 }
506                 else if (!module->info->extensions) {
507                         int n = 1;
508                         module->info->extensions = g_new0 (gchar*, 1);
509                         while (scan_string (&p, tmp_buf)) {
510                                 if (tmp_buf->str[0] != 0) {
511                                         module->info->extensions =
512                                                 g_realloc (module->info->extensions, (n + 1) * sizeof (gchar*));
513                                         module->info->extensions[n - 1] = g_strdup (tmp_buf->str);
514                                         module->info->extensions[n] = NULL;
515                                         n++;
516                                 }
517                         }
518                 }
519                 else {
520                         n_patterns++;
521                         module->info->signature = (GdkPixbufModulePattern *)
522                                 g_realloc (module->info->signature, (n_patterns + 1) * sizeof (GdkPixbufModulePattern));
523                         pattern = module->info->signature + n_patterns;
524                         pattern->prefix = NULL;
525                         pattern->mask = NULL;
526                         pattern->relevance = 0;
527                         pattern--;
528                         if (!scan_string (&p, tmp_buf))
529                                 goto context_error;
530                         pattern->prefix = g_strdup (tmp_buf->str);
531 
532                         if (!scan_string (&p, tmp_buf))
533                                 goto context_error;
534                         if (*tmp_buf->str)
535                                 pattern->mask = g_strdup (tmp_buf->str);
536                         else
537                                 pattern->mask = NULL;
538 
539                         if (!scan_int (&p, &pattern->relevance))
540                                 goto context_error;
541 
542                         goto next_line;
543 
544                 context_error:
545                         g_free (pattern->prefix);
546                         g_free (pattern->mask);
547                         g_free (pattern);
548                         g_warning ("Error parsing loader info in '%s'\n  %s",
549                                    filename, line_buf);
550                         have_error = TRUE;
551                 }
552         next_line:
553                 g_free (line_buf);
554         }
555         g_string_free (tmp_buf, TRUE);
556         g_io_channel_unref (channel);
557 
558         if (g_slist_length (file_formats) <= num_formats) {
559                 g_set_error (error,
560                              G_IO_ERROR,
561                              G_IO_ERROR_NOT_INITIALIZED,
562                              "No new GdkPixbufModule loaded from '%s'",
563                              filename);
564                 return FALSE;
565         }
566 #endif
567         return TRUE;
568 }
569 
570 /**
571  * gdk_pixbuf_init_modules:
572  * @path: Path to directory where the loaders.cache is installed
573  * @error: return location for a #GError
574  *
575  * Initalizes the gdk-pixbuf loader modules referenced by the loaders.cache
576  * file present inside that directory.
577  *
578  * This is to be used by applications that want to ship certain loaders
579  * in a different location from the system ones.
580  *
581  * This is needed when the OS or runtime ships a minimal number of loaders
582  * so as to reduce the potential attack surface of carefully crafted image
583  * files, especially for uncommon file types. Applications that require
584  * broader image file types coverage, such as image viewers, would be
585  * expected to ship the gdk-pixbuf modules in a separate location, bundled
586  * with the application in a separate directory from the OS or runtime-
587  * provided modules.
588  *
589  * Since: 2.40
590  */
591 gboolean
gdk_pixbuf_init_modules(const char * path,GError ** error)592 gdk_pixbuf_init_modules (const char  *path,
593 			 GError     **error)
594 {
595 	char *filename;
596 	gboolean ret;
597 
598 	g_return_val_if_fail (path != NULL, FALSE);
599 	filename = g_build_filename (path, "loaders.cache", NULL);
600 	ret = gdk_pixbuf_io_init_modules (filename, error);
601 	g_free (filename);
602 	return ret;
603 }
604 
605 static void
gdk_pixbuf_io_init_builtin(void)606 gdk_pixbuf_io_init_builtin (void)
607 {
608 #define load_one_builtin_module(format)                                 G_STMT_START { \
609         GdkPixbufModule *__builtin_module = g_new0 (GdkPixbufModule, 1);               \
610         __builtin_module->module_name = #format;                                       \
611         if (gdk_pixbuf_load_module_unlocked (__builtin_module, NULL))                  \
612                 file_formats = g_slist_prepend (file_formats, __builtin_module);       \
613         else                                                                           \
614                 g_free (__builtin_module);                              } G_STMT_END
615 
616 #ifdef INCLUDE_ani
617         load_one_builtin_module (ani);
618 #endif
619 #ifdef INCLUDE_png
620         load_one_builtin_module (png);
621 #endif
622 #ifdef INCLUDE_bmp
623         load_one_builtin_module (bmp);
624 #endif
625 #ifdef INCLUDE_gif
626         load_one_builtin_module (gif);
627 #endif
628 #ifdef INCLUDE_ico
629         load_one_builtin_module (ico);
630 #endif
631 #ifdef INCLUDE_jpeg
632         load_one_builtin_module (jpeg);
633 #endif
634 #ifdef INCLUDE_pnm
635         load_one_builtin_module (pnm);
636 #endif
637 #ifdef INCLUDE_tiff
638         load_one_builtin_module (tiff);
639 #endif
640 #ifdef INCLUDE_xpm
641         load_one_builtin_module (xpm);
642 #endif
643 #ifdef INCLUDE_xbm
644         load_one_builtin_module (xbm);
645 #endif
646 #ifdef INCLUDE_tga
647         load_one_builtin_module (tga);
648 #endif
649 #ifdef INCLUDE_icns
650         load_one_builtin_module (icns);
651 #endif
652 #ifdef INCLUDE_jasper
653         load_one_builtin_module (jasper);
654 #endif
655 #ifdef INCLUDE_qtif
656         load_one_builtin_module (qtif);
657 #endif
658 #ifdef INCLUDE_gdiplus
659         /* We don't bother having the GDI+ loaders individually selectable
660          * for building in or not.
661          */
662         load_one_builtin_module (ico);
663         load_one_builtin_module (wmf);
664         load_one_builtin_module (emf);
665         load_one_builtin_module (bmp);
666         load_one_builtin_module (gif);
667         load_one_builtin_module (jpeg);
668         load_one_builtin_module (tiff);
669 #endif
670 #ifdef INCLUDE_gdip_png
671         /* Except the gdip-png loader which normally isn't built at all even */
672         load_one_builtin_module (png);
673 #endif
674 
675 #undef load_one_builtin_module
676 }
677 
678 static gboolean
gdk_pixbuf_io_init(void)679 gdk_pixbuf_io_init (void)
680 {
681 	char *module_file;
682 	gboolean ret;
683 
684 	gdk_pixbuf_io_init_builtin ();
685 	module_file = gdk_pixbuf_get_module_file ();
686 	ret = gdk_pixbuf_io_init_modules (module_file, NULL);
687 	g_free (module_file);
688 	return ret;
689 }
690 
691 #define module(type) \
692   extern void _gdk_pixbuf__##type##_fill_info   (GdkPixbufFormat *info);   \
693   extern void _gdk_pixbuf__##type##_fill_vtable (GdkPixbufModule *module)
694 
695 module (png);
696 module (jpeg);
697 module (gif);
698 module (ico);
699 module (ani);
700 module (xpm);
701 module (tiff);
702 module (pnm);
703 module (bmp);
704 module (xbm);
705 module (tga);
706 module (icns);
707 module (jasper);
708 module (qtif);
709 module (gdip_ico);
710 module (gdip_wmf);
711 module (gdip_emf);
712 module (gdip_bmp);
713 module (gdip_gif);
714 module (gdip_jpeg);
715 module (gdip_png);
716 module (gdip_tiff);
717 
718 #undef module
719 
720 /* actually load the image handler - gdk_pixbuf_get_module only get a */
721 /* reference to the module to load, it doesn't actually load it       */
722 /* perhaps these actions should be combined in one function           */
723 static gboolean
gdk_pixbuf_load_module_unlocked(GdkPixbufModule * image_module,GError ** error)724 gdk_pixbuf_load_module_unlocked (GdkPixbufModule *image_module,
725                                  GError         **error)
726 {
727         GdkPixbufModuleFillInfoFunc fill_info = NULL;
728         GdkPixbufModuleFillVtableFunc fill_vtable = NULL;
729 
730         if (image_module->module != NULL)
731                return TRUE;
732 
733 #define try_module(format,id)                                           \
734         if (fill_info == NULL &&                                        \
735             strcmp (image_module->module_name, #format) == 0) {         \
736                 fill_info = _gdk_pixbuf__##id##_fill_info;              \
737                 fill_vtable = _gdk_pixbuf__##id##_fill_vtable;  \
738         }
739 
740 #ifdef INCLUDE_gdiplus
741         try_module (ico,gdip_ico);
742         try_module (wmf,gdip_wmf);
743         try_module (emf,gdip_emf);
744         try_module (bmp,gdip_bmp);
745         try_module (gif,gdip_gif);
746         try_module (jpeg,gdip_jpeg);
747         try_module (tiff,gdip_tiff);
748 #endif
749 #ifdef INCLUDE_gdip_png
750         try_module (png,gdip_png);
751 #endif
752 #ifdef INCLUDE_png
753         try_module (png,png);
754 #endif
755 #ifdef INCLUDE_bmp
756         try_module (bmp,bmp);
757 #endif
758 #ifdef INCLUDE_gif
759         try_module (gif,gif);
760 #endif
761 #ifdef INCLUDE_ico
762         try_module (ico,ico);
763 #endif
764 #ifdef INCLUDE_ani
765         try_module (ani,ani);
766 #endif
767 #ifdef INCLUDE_jpeg
768         try_module (jpeg,jpeg);
769 #endif
770 #ifdef INCLUDE_pnm
771         try_module (pnm,pnm);
772 #endif
773 #ifdef INCLUDE_tiff
774         try_module (tiff,tiff);
775 #endif
776 #ifdef INCLUDE_xpm
777         try_module (xpm,xpm);
778 #endif
779 #ifdef INCLUDE_xbm
780         try_module (xbm,xbm);
781 #endif
782 #ifdef INCLUDE_tga
783         try_module (tga,tga);
784 #endif
785 #ifdef INCLUDE_icns
786         try_module (icns,icns);
787 #endif
788 #ifdef INCLUDE_jasper
789         try_module (jasper,jasper);
790 #endif
791 #ifdef INCLUDE_qtif
792         try_module (qtif,qtif);
793 #endif
794 
795 #undef try_module
796 
797         if (fill_vtable) {
798                 image_module->module = (void *) 1;
799                 (* fill_vtable) (image_module);
800                 if (image_module->info == NULL) {
801                         image_module->info = g_new0 (GdkPixbufFormat, 1);
802                         (* fill_info) (image_module->info);
803                 }
804                 return TRUE;
805         }
806         else
807 #ifdef USE_GMODULE
808         {
809                 char *path;
810                 GModule *module;
811                 gpointer sym;
812 
813                 path = image_module->module_path;
814                 module = g_module_open (path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
815 
816                 if (!module) {
817                         g_set_error (error,
818                                      GDK_PIXBUF_ERROR,
819                                      GDK_PIXBUF_ERROR_FAILED,
820                                      _("Unable to load image-loading module: %s: %s"),
821                                      path, g_module_error ());
822                         return FALSE;
823                 }
824 
825                 image_module->module = module;
826 
827                 if (g_module_symbol (module, "fill_vtable", &sym)) {
828                         fill_vtable = (GdkPixbufModuleFillVtableFunc) sym;
829                         (* fill_vtable) (image_module);
830                         return TRUE;
831                 } else {
832                         g_set_error (error,
833                                      GDK_PIXBUF_ERROR,
834                                      GDK_PIXBUF_ERROR_FAILED,
835                                      _("Image-loading module %s does not export the proper interface; perhaps it’s from a different gdk-pixbuf version?"),
836                                      path);
837                         return FALSE;
838                 }
839         }
840 #else
841         g_set_error (error,
842                      GDK_PIXBUF_ERROR,
843                      GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
844                      _("Image type “%s” is not supported"),
845                      image_module->module_name);
846         return FALSE;
847 #endif  /* !USE_GMODULE */
848 }
849 
850 
851 gboolean
_gdk_pixbuf_load_module(GdkPixbufModule * image_module,GError ** error)852 _gdk_pixbuf_load_module (GdkPixbufModule *image_module,
853                          GError         **error)
854 {
855         gboolean ret;
856 
857         G_LOCK (init_lock);
858 
859         ret = gdk_pixbuf_load_module_unlocked (image_module, error);
860 
861         G_UNLOCK (init_lock);
862 
863         return ret;
864 }
865 
866 
867 
868 GdkPixbufModule *
_gdk_pixbuf_get_named_module(const char * name,GError ** error)869 _gdk_pixbuf_get_named_module (const char *name,
870                               GError **error)
871 {
872         GSList *modules;
873 
874         for (modules = get_file_formats (); modules; modules = g_slist_next (modules)) {
875                 GdkPixbufModule *module = (GdkPixbufModule *)modules->data;
876 
877                 if (module->info->disabled)
878                         continue;
879 
880                 if (!strcmp (name, module->module_name))
881                         return module;
882         }
883 
884         g_set_error (error,
885                      GDK_PIXBUF_ERROR,
886                      GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
887                      _("Image type “%s” is not supported"),
888                      name);
889 
890         return NULL;
891 }
892 
893 GdkPixbufModule *
_gdk_pixbuf_get_module(guchar * buffer,guint size,const gchar * filename,GError ** error)894 _gdk_pixbuf_get_module (guchar *buffer, guint size,
895                         const gchar *filename,
896                         GError **error)
897 {
898         GSList *modules;
899 
900         GdkPixbufModule *selected = NULL;
901         gchar *display_name = NULL;
902 #ifdef GDK_PIXBUF_USE_GIO_MIME
903         gchar *mime_type;
904         gchar **mimes;
905         gchar *type;
906         gint j;
907         gboolean uncertain;
908 
909         mime_type = g_content_type_guess (NULL, buffer, size, &uncertain);
910         if ((uncertain || g_str_equal (mime_type, "text/plain") || g_str_equal (mime_type, "application/gzip")) && filename != NULL) {
911                 g_free (mime_type);
912                 mime_type = g_content_type_guess (filename, buffer, size, NULL);
913         }
914 
915         for (modules = get_file_formats (); modules; modules = g_slist_next (modules)) {
916                 GdkPixbufModule *module = (GdkPixbufModule *)modules->data;
917                 GdkPixbufFormat *info = module->info;
918 
919                 if (info->disabled)
920                         continue;
921 
922                 mimes = info->mime_types;
923                 for (j = 0; mimes[j] != NULL; j++) {
924                         type = g_content_type_from_mime_type (mimes[j]);
925                         if (g_content_type_equals (type, mime_type)) {
926                                 g_free (type);
927                                 selected = module;
928                                 break;
929                         }
930                         g_free (type);
931                 }
932 
933                 if (selected != NULL)
934                         break;
935 
936 		/* Make sure the builtin GdkPixdata support works even without mime sniffing */
937 		if (strcmp (info->name, "GdkPixdata") == 0 &&
938 		    format_check (module, buffer, size) == 100) {
939 			selected = module;
940 			break;
941 		}
942         }
943         g_free (mime_type);
944 #else
945         gint score, best = 0;
946 
947         for (modules = get_file_formats (); modules; modules = g_slist_next (modules)) {
948                 GdkPixbufModule *module = (GdkPixbufModule *)modules->data;
949 
950                 if (module->info->disabled)
951                         continue;
952 
953                 score = format_check (module, buffer, size);
954                 if (score > best) {
955                         best = score;
956                         selected = module;
957                 }
958                 if (score >= 100)
959                         break;
960         }
961 #endif
962 
963         if (selected != NULL)
964                 return selected;
965 
966         if (filename)
967         {
968                 display_name = g_filename_display_name (filename);
969                 g_set_error (error,
970                              GDK_PIXBUF_ERROR,
971                              GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
972                              _("Couldn’t recognize the image file format for file “%s”"),
973                              display_name);
974                 g_free (display_name);
975         }
976         else
977                 g_set_error_literal (error,
978                                      GDK_PIXBUF_ERROR,
979                                      GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
980                                      _("Unrecognized image file format"));
981 
982 
983         return NULL;
984 }
985 
986 static
987 GdkPixbufModule *
_gdk_pixbuf_get_module_for_file(FILE * f,const gchar * filename,GError ** error)988 _gdk_pixbuf_get_module_for_file (FILE *f, const gchar *filename, GError **error)
989 {
990         guchar buffer[SNIFF_BUFFER_SIZE];
991         int size;
992 
993         size = fread (&buffer, 1, sizeof (buffer), f);
994         if (size == 0) {
995 		gchar *display_name;
996         	display_name = g_filename_display_name (filename);
997                 g_set_error (error,
998                              GDK_PIXBUF_ERROR,
999                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
1000                              _("Image file “%s” contains no data"),
1001                              display_name);
1002                 g_free (display_name);
1003                 return NULL;
1004         }
1005 
1006 	return _gdk_pixbuf_get_module (buffer, size, filename, error);
1007 }
1008 
1009 static void
prepared_notify(GdkPixbuf * pixbuf,GdkPixbufAnimation * anim,gpointer user_data)1010 prepared_notify (GdkPixbuf *pixbuf,
1011                  GdkPixbufAnimation *anim,
1012                  gpointer user_data)
1013 {
1014         if (pixbuf != NULL)
1015                 g_object_ref (pixbuf);
1016         *((GdkPixbuf **)user_data) = pixbuf;
1017 }
1018 
1019 static GdkPixbuf *
generic_load_incrementally(GdkPixbufModule * module,FILE * f,GError ** error)1020 generic_load_incrementally (GdkPixbufModule *module, FILE *f, GError **error)
1021 {
1022         GdkPixbuf *pixbuf = NULL;
1023 	gpointer context;
1024 
1025 	context = module->begin_load (NULL, prepared_notify, NULL, &pixbuf, error);
1026 
1027 	if (!context)
1028 		goto out;
1029 
1030 	while (!feof (f) && !ferror (f)) {
1031 		guchar buffer[LOAD_BUFFER_SIZE];
1032 		size_t length;
1033 
1034 		length = fread (buffer, 1, sizeof (buffer), f);
1035 		if (length > 0) {
1036 			if (!module->load_increment (context, buffer, length, error)) {
1037 				module->stop_load (context, NULL);
1038 				if (pixbuf != NULL) {
1039 					g_object_unref (pixbuf);
1040 					pixbuf = NULL;
1041 				}
1042 				goto out;
1043 			}
1044 		}
1045 	}
1046 
1047 	if (!module->stop_load (context, error)) {
1048 		if (pixbuf != NULL) {
1049 			g_object_unref (pixbuf);
1050 			pixbuf = NULL;
1051 		}
1052 	}
1053 
1054 out:
1055 	return pixbuf;
1056 }
1057 
1058 GdkPixbuf *
_gdk_pixbuf_generic_image_load(GdkPixbufModule * module,FILE * f,GError ** error)1059 _gdk_pixbuf_generic_image_load (GdkPixbufModule *module, FILE *f, GError **error)
1060 {
1061         GdkPixbuf *pixbuf = NULL;
1062 
1063         if (module->load != NULL) {
1064                 pixbuf = (* module->load) (f, error);
1065         } else if (module->begin_load != NULL) {
1066         	pixbuf = generic_load_incrementally (module, f, error);
1067         } else if (module->load_animation != NULL) {
1068 		GdkPixbufAnimation *animation;
1069 
1070                 animation = (* module->load_animation) (f, error);
1071                 if (animation != NULL) {
1072                         pixbuf = gdk_pixbuf_animation_get_static_image (animation);
1073 
1074                         g_object_ref (pixbuf);
1075                         g_object_unref (animation);
1076                 }
1077         }
1078 
1079         return pixbuf;
1080 }
1081 
1082 /**
1083  * gdk_pixbuf_new_from_file:
1084  * @filename: (type filename): Name of file to load, in the GLib file
1085  *     name encoding
1086  * @error: Return location for an error
1087  *
1088  * Creates a new pixbuf by loading an image from a file.  The file format is
1089  * detected automatically. If %NULL is returned, then @error will be set.
1090  * Possible errors are in the #GDK_PIXBUF_ERROR and #G_FILE_ERROR domains.
1091  *
1092  * Return value: A newly-created pixbuf with a reference count of 1, or %NULL if
1093  * any of several error conditions occurred:  the file could not be opened,
1094  * there was no loader for the file's format, there was not enough memory to
1095  * allocate the image buffer, or the image file contained invalid data.
1096  **/
1097 GdkPixbuf *
gdk_pixbuf_new_from_file(const char * filename,GError ** error)1098 gdk_pixbuf_new_from_file (const char *filename,
1099                           GError    **error)
1100 {
1101         GdkPixbuf *pixbuf;
1102         FILE *f;
1103         GdkPixbufModule *image_module;
1104 
1105         g_return_val_if_fail (filename != NULL, NULL);
1106         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1107 
1108         f = g_fopen (filename, "rb");
1109         if (!f) {
1110                 gint save_errno = errno;
1111 		gchar *display_name;
1112         	display_name = g_filename_display_name (filename);
1113                 g_set_error (error,
1114                              G_FILE_ERROR,
1115                              g_file_error_from_errno (save_errno),
1116                              _("Failed to open file “%s”: %s"),
1117                              display_name,
1118                              g_strerror (save_errno));
1119                 g_free (display_name);
1120                 return NULL;
1121         }
1122 
1123         image_module = _gdk_pixbuf_get_module_for_file (f, filename, error);
1124         if (image_module == NULL) {
1125                 fclose (f);
1126                 return NULL;
1127         }
1128 
1129         if (!_gdk_pixbuf_load_module (image_module, error)) {
1130                 fclose (f);
1131                 return NULL;
1132         }
1133 
1134         fseek (f, 0, SEEK_SET);
1135         pixbuf = _gdk_pixbuf_generic_image_load (image_module, f, error);
1136         fclose (f);
1137 
1138         if (pixbuf == NULL && error != NULL && *error == NULL) {
1139 
1140                 /* I don't trust these crufty longjmp()'ing image libs
1141                  * to maintain proper error invariants, and I don't
1142                  * want user code to segfault as a result. We need to maintain
1143                  * the invariant that error gets set if NULL is returned.
1144                  */
1145 
1146 		gchar *display_name;
1147         	display_name = g_filename_display_name (filename);
1148                 g_warning ("Bug! gdk-pixbuf loader '%s' didn't set an error on failure.", image_module->module_name);
1149                 g_set_error (error,
1150                              GDK_PIXBUF_ERROR,
1151                              GDK_PIXBUF_ERROR_FAILED,
1152                              _("Failed to load image “%s”: reason not known, probably a corrupt image file"),
1153                              display_name);
1154 		g_free (display_name);
1155         } else if (error != NULL && *error != NULL) {
1156 		/* Add the filename to the error message */
1157 		GError *e = *error;
1158 		gchar  *old;
1159 		gchar *display_name;
1160 
1161         	display_name = g_filename_display_name (filename);
1162 		old = e->message;
1163 		e->message = g_strdup_printf (_("Failed to load image “%s”: %s"),
1164 					      display_name,
1165 					      old);
1166 		g_free (old);
1167 		g_free (display_name);
1168         }
1169 
1170         return pixbuf;
1171 }
1172 
1173 #ifdef G_OS_WIN32
1174 
1175 /**
1176  * gdk_pixbuf_new_from_file_utf8:
1177  * @filename: (type filename): Name of file to load, in the GLib file name encoding
1178  * @error: Return location for an error
1179  *
1180  * Same as gdk_pixbuf_new_from_file()
1181  *
1182  * Return value: A newly-created pixbuf with a reference count of 1, or %NULL if
1183  * any of several error conditions occurred:  the file could not be opened,
1184  * there was no loader for the file's format, there was not enough memory to
1185  * allocate the image buffer, or the image file contained invalid data.
1186  **/
1187 GdkPixbuf *
gdk_pixbuf_new_from_file_utf8(const char * filename,GError ** error)1188 gdk_pixbuf_new_from_file_utf8 (const char *filename,
1189                                 GError    **error)
1190 {
1191     return gdk_pixbuf_new_from_file (filename, error);
1192 }
1193 
1194 #endif
1195 
1196 
1197 /**
1198  * gdk_pixbuf_new_from_file_at_size:
1199  * @filename: (type filename): Name of file to load, in the GLib file
1200  *     name encoding
1201  * @width: The width the image should have or -1 to not constrain the width
1202  * @height: The height the image should have or -1 to not constrain the height
1203  * @error: Return location for an error
1204  *
1205  * Creates a new pixbuf by loading an image from a file.
1206  * The file format is detected automatically. If %NULL is returned, then
1207  * @error will be set. Possible errors are in the #GDK_PIXBUF_ERROR and
1208  * #G_FILE_ERROR domains.
1209  *
1210  * The image will be scaled to fit in the requested size, preserving
1211  * the image's aspect ratio. Note that the returned pixbuf may be smaller
1212  * than @width x @height, if the aspect ratio requires it. To load
1213  * and image at the requested size, regardless of aspect ratio, use
1214  * gdk_pixbuf_new_from_file_at_scale().
1215  *
1216  * Return value: A newly-created pixbuf with a reference count of 1, or
1217  * %NULL if any of several error conditions occurred:  the file could not
1218  * be opened, there was no loader for the file's format, there was not
1219  * enough memory to allocate the image buffer, or the image file contained
1220  * invalid data.
1221  *
1222  * Since: 2.4
1223  **/
1224 GdkPixbuf *
gdk_pixbuf_new_from_file_at_size(const char * filename,int width,int height,GError ** error)1225 gdk_pixbuf_new_from_file_at_size (const char *filename,
1226                                   int         width,
1227                                   int         height,
1228                                   GError    **error)
1229 {
1230         return gdk_pixbuf_new_from_file_at_scale (filename,
1231                                                   width, height,
1232                                                   TRUE, error);
1233 }
1234 
1235 #ifdef G_OS_WIN32
1236 
1237 /**
1238  * gdk_pixbuf_new_from_file_at_size_utf8:
1239  * @filename: (type filename): Name of file to load, in the GLib file name encoding
1240  * @width: The width the image should have or -1 to not constrain the width
1241  * @height: The height the image should have or -1 to not constrain the height
1242  * @error: Return location for an error
1243  *
1244  * Same as gdk_pixbuf_new_from_file_at_size()
1245  *
1246  * Return value: A newly-created pixbuf with a reference count of 1, or
1247  * %NULL if any of several error conditions occurred:  the file could not
1248  * be opened, there was no loader for the file's format, there was not
1249  * enough memory to allocate the image buffer, or the image file contained
1250  * invalid data.
1251  *
1252  * Since: 2.4
1253  **/
1254 GdkPixbuf *
gdk_pixbuf_new_from_file_at_size_utf8(const char * filename,int width,int height,GError ** error)1255 gdk_pixbuf_new_from_file_at_size_utf8 (const char *filename,
1256                                        int         width,
1257                                        int         height,
1258                                        GError    **error)
1259 {
1260     return gdk_pixbuf_new_from_file_at_size (filename, width, height, error);
1261 }
1262 
1263 #endif
1264 
1265 typedef struct {
1266         gint width;
1267         gint height;
1268         gboolean preserve_aspect_ratio;
1269 } AtScaleData;
1270 
1271 static void
at_scale_data_async_data_free(AtScaleData * data)1272 at_scale_data_async_data_free (AtScaleData *data)
1273 {
1274 	g_slice_free (AtScaleData, data);
1275 }
1276 
1277 static void
at_scale_size_prepared_cb(GdkPixbufLoader * loader,int width,int height,gpointer data)1278 at_scale_size_prepared_cb (GdkPixbufLoader *loader,
1279                            int              width,
1280                            int              height,
1281                            gpointer         data)
1282 {
1283         AtScaleData *info = data;
1284 
1285         g_return_if_fail (width > 0 && height > 0);
1286 
1287         if (info->preserve_aspect_ratio &&
1288             (info->width > 0 || info->height > 0)) {
1289                 if (info->width < 0)
1290                 {
1291                         width = width * (double)info->height/(double)height;
1292                         height = info->height;
1293                 }
1294                 else if (info->height < 0)
1295                 {
1296                         height = height * (double)info->width/(double)width;
1297                         width = info->width;
1298                 }
1299                 else if ((double)height * (double)info->width >
1300                          (double)width * (double)info->height) {
1301                         width = 0.5 + (double)width * (double)info->height / (double)height;
1302                         height = info->height;
1303                 } else {
1304                         height = 0.5 + (double)height * (double)info->width / (double)width;
1305                         width = info->width;
1306                 }
1307         } else {
1308                 if (info->width > 0)
1309                         width = info->width;
1310                 if (info->height > 0)
1311                         height = info->height;
1312         }
1313 
1314         width = MAX (width, 1);
1315         height = MAX (height, 1);
1316 
1317         gdk_pixbuf_loader_set_size (loader, width, height);
1318 }
1319 
1320 /**
1321  * gdk_pixbuf_new_from_file_at_scale:
1322  * @filename: (type filename): Name of file to load, in the GLib file
1323  *     name encoding
1324  * @width: The width the image should have or -1 to not constrain the width
1325  * @height: The height the image should have or -1 to not constrain the height
1326  * @preserve_aspect_ratio: %TRUE to preserve the image's aspect ratio
1327  * @error: Return location for an error
1328  *
1329  * Creates a new pixbuf by loading an image from a file.  The file format is
1330  * detected automatically. If %NULL is returned, then @error will be set.
1331  * Possible errors are in the #GDK_PIXBUF_ERROR and #G_FILE_ERROR domains.
1332  * The image will be scaled to fit in the requested size, optionally preserving
1333  * the image's aspect ratio.
1334  *
1335  * When preserving the aspect ratio, a @width of -1 will cause the image
1336  * to be scaled to the exact given height, and a @height of -1 will cause
1337  * the image to be scaled to the exact given width. When not preserving
1338  * aspect ratio, a @width or @height of -1 means to not scale the image
1339  * at all in that dimension. Negative values for @width and @height are
1340  * allowed since 2.8.
1341  *
1342  * Return value: A newly-created pixbuf with a reference count of 1, or %NULL
1343  * if any of several error conditions occurred:  the file could not be opened,
1344  * there was no loader for the file's format, there was not enough memory to
1345  * allocate the image buffer, or the image file contained invalid data.
1346  *
1347  * Since: 2.6
1348  **/
1349 GdkPixbuf *
gdk_pixbuf_new_from_file_at_scale(const char * filename,int width,int height,gboolean preserve_aspect_ratio,GError ** error)1350 gdk_pixbuf_new_from_file_at_scale (const char *filename,
1351                                    int         width,
1352                                    int         height,
1353                                    gboolean    preserve_aspect_ratio,
1354                                    GError    **error)
1355 {
1356 
1357         GdkPixbufLoader *loader;
1358         GdkPixbuf       *pixbuf;
1359         guchar buffer[LOAD_BUFFER_SIZE];
1360         int length;
1361         FILE *f;
1362         AtScaleData info;
1363         GdkPixbufAnimation *animation;
1364         GdkPixbufAnimationIter *iter;
1365         gboolean has_frame;
1366 
1367         g_return_val_if_fail (filename != NULL, NULL);
1368         g_return_val_if_fail (width > 0 || width == -1, NULL);
1369         g_return_val_if_fail (height > 0 || height == -1, NULL);
1370 
1371         f = g_fopen (filename, "rb");
1372         if (!f) {
1373                 gint save_errno = errno;
1374                 gchar *display_name = g_filename_display_name (filename);
1375                 g_set_error (error,
1376                              G_FILE_ERROR,
1377                              g_file_error_from_errno (save_errno),
1378                              _("Failed to open file “%s”: %s"),
1379                              display_name,
1380                              g_strerror (save_errno));
1381                 g_free (display_name);
1382                 return NULL;
1383         }
1384 
1385         loader = _gdk_pixbuf_loader_new_with_filename (filename);
1386 
1387         info.width = width;
1388         info.height = height;
1389         info.preserve_aspect_ratio = preserve_aspect_ratio;
1390 
1391         g_signal_connect (loader, "size-prepared",
1392                           G_CALLBACK (at_scale_size_prepared_cb), &info);
1393 
1394         has_frame = FALSE;
1395         while (!has_frame && !feof (f) && !ferror (f)) {
1396                 length = fread (buffer, 1, sizeof (buffer), f);
1397                 if (length > 0)
1398                         if (!gdk_pixbuf_loader_write (loader, buffer, length, error)) {
1399                                 gdk_pixbuf_loader_close (loader, NULL);
1400                                 fclose (f);
1401                                 g_object_unref (loader);
1402                                 return NULL;
1403                         }
1404 
1405                 animation = gdk_pixbuf_loader_get_animation (loader);
1406                 if (animation) {
1407                         iter = gdk_pixbuf_animation_get_iter (animation, NULL);
1408                         if (!gdk_pixbuf_animation_iter_on_currently_loading_frame (iter)) {
1409                                 has_frame = TRUE;
1410                         }
1411                         g_object_unref (iter);
1412                 }
1413         }
1414 
1415         fclose (f);
1416 
1417         if (!gdk_pixbuf_loader_close (loader, error) && !has_frame) {
1418                 g_object_unref (loader);
1419                 return NULL;
1420         }
1421 
1422         pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1423 
1424         if (!pixbuf) {
1425                 gchar *display_name = g_filename_display_name (filename);
1426                 g_object_unref (loader);
1427                 g_set_error (error,
1428                              GDK_PIXBUF_ERROR,
1429                              GDK_PIXBUF_ERROR_FAILED,
1430                              _("Failed to load image “%s”: reason not known, probably a corrupt image file"),
1431                              display_name);
1432                 g_free (display_name);
1433                 return NULL;
1434         }
1435 
1436         g_object_ref (pixbuf);
1437 
1438         g_object_unref (loader);
1439 
1440         return pixbuf;
1441 }
1442 
1443 #ifdef G_OS_WIN32
1444 
1445 /**
1446  * gdk_pixbuf_new_from_file_at_scale_utf8:
1447  * @filename: (type filename): Name of file to load, in the GLib file name encoding
1448  * @width: The width the image should have or -1 to not constrain the width
1449  * @height: The height the image should have or -1 to not constrain the height
1450  * @preserve_aspect_ratio: %TRUE to preserve the image's aspect ratio
1451  * @error: Return location for an error
1452  *
1453  * Same as gdk_pixbuf_new_from_file_at_scale().
1454  *
1455  * Return value: A newly-created pixbuf with a reference count of 1, or %NULL
1456  * if any of several error conditions occurred:  the file could not be opened,
1457  * there was no loader for the file's format, there was not enough memory to
1458  * allocate the image buffer, or the image file contained invalid data.
1459  *
1460  * Since: 2.6
1461  **/
1462 GdkPixbuf *
gdk_pixbuf_new_from_file_at_scale_utf8(const char * filename,int width,int height,gboolean preserve_aspect_ratio,GError ** error)1463 gdk_pixbuf_new_from_file_at_scale_utf8 (const char *filename,
1464                                         int         width,
1465                                         int         height,
1466                                         gboolean    preserve_aspect_ratio,
1467                                         GError    **error)
1468 {
1469     return gdk_pixbuf_new_from_file_at_scale (filename, width, height,
1470                                               preserve_aspect_ratio, error);
1471 }
1472 #endif
1473 
1474 
1475 static GdkPixbuf *
load_from_stream(GdkPixbufLoader * loader,GInputStream * stream,GCancellable * cancellable,GError ** error)1476 load_from_stream (GdkPixbufLoader  *loader,
1477                   GInputStream     *stream,
1478                   GCancellable     *cancellable,
1479                   GError          **error)
1480 {
1481         GdkPixbuf *pixbuf;
1482         gssize n_read;
1483         guchar buffer[LOAD_BUFFER_SIZE];
1484 
1485         while (1) {
1486                 n_read = g_input_stream_read (stream,
1487                                               buffer,
1488                                               sizeof (buffer),
1489                                               cancellable,
1490                                               error);
1491                 if (n_read < 0) {
1492                         gdk_pixbuf_loader_close (loader, NULL);
1493                         return NULL;
1494                 }
1495 
1496                 if (n_read == 0)
1497                         break;
1498 
1499                 if (!gdk_pixbuf_loader_write (loader,
1500                                               buffer,
1501                                               n_read,
1502                                               error)) {
1503                         gdk_pixbuf_loader_close (loader, NULL);
1504                         return NULL;
1505                 }
1506         }
1507 
1508         if (!gdk_pixbuf_loader_close (loader, error))
1509                 return NULL;
1510 
1511         pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1512         if (pixbuf == NULL)
1513                 return NULL;
1514 
1515         return g_object_ref (pixbuf);
1516 }
1517 
1518 
1519 /**
1520  * gdk_pixbuf_new_from_stream_at_scale:
1521  * @stream:  a #GInputStream to load the pixbuf from
1522  * @width: The width the image should have or -1 to not constrain the width
1523  * @height: The height the image should have or -1 to not constrain the height
1524  * @preserve_aspect_ratio: %TRUE to preserve the image's aspect ratio
1525  * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore
1526  * @error: Return location for an error
1527  *
1528  * Creates a new pixbuf by loading an image from an input stream.
1529  *
1530  * The file format is detected automatically. If %NULL is returned, then
1531  * @error will be set. The @cancellable can be used to abort the operation
1532  * from another thread. If the operation was cancelled, the error
1533  * %G_IO_ERROR_CANCELLED will be returned. Other possible errors are in
1534  * the #GDK_PIXBUF_ERROR and %G_IO_ERROR domains.
1535  *
1536  * The image will be scaled to fit in the requested size, optionally
1537  * preserving the image's aspect ratio.
1538  *
1539  * When preserving the aspect ratio, a @width of -1 will cause the image to be
1540  * scaled to the exact given height, and a @height of -1 will cause the image
1541  * to be scaled to the exact given width. If both @width and @height are
1542  * given, this function will behave as if the smaller of the two values
1543  * is passed as -1.
1544  *
1545  * When not preserving aspect ratio, a @width or @height of -1 means to not
1546  * scale the image at all in that dimension.
1547  *
1548  * The stream is not closed.
1549  *
1550  * Return value: A newly-created pixbuf, or %NULL if any of several error
1551  * conditions occurred: the file could not be opened, the image format is
1552  * not supported, there was not enough memory to allocate the image buffer,
1553  * the stream contained invalid data, or the operation was cancelled.
1554  *
1555  * Since: 2.14
1556  */
1557 GdkPixbuf *
gdk_pixbuf_new_from_stream_at_scale(GInputStream * stream,gint width,gint height,gboolean preserve_aspect_ratio,GCancellable * cancellable,GError ** error)1558 gdk_pixbuf_new_from_stream_at_scale (GInputStream  *stream,
1559                                      gint           width,
1560                                      gint           height,
1561                                      gboolean       preserve_aspect_ratio,
1562                                      GCancellable  *cancellable,
1563                                      GError       **error)
1564 {
1565         GdkPixbufLoader *loader;
1566         GdkPixbuf *pixbuf;
1567         AtScaleData info;
1568 
1569         loader = gdk_pixbuf_loader_new ();
1570         info.width = width;
1571         info.height = height;
1572         info.preserve_aspect_ratio = preserve_aspect_ratio;
1573 
1574         g_signal_connect (loader, "size-prepared",
1575                           G_CALLBACK (at_scale_size_prepared_cb), &info);
1576 
1577         pixbuf = load_from_stream (loader, stream, cancellable, error);
1578         g_object_unref (loader);
1579 
1580         return pixbuf;
1581 }
1582 
1583 
1584 static void
load_from_stream_async_cb(GObject * stream,GAsyncResult * res,gpointer data)1585 load_from_stream_async_cb (GObject      *stream,
1586                            GAsyncResult *res,
1587                            gpointer      data)
1588 {
1589         GTask *task = data;
1590         GdkPixbufLoader *loader;
1591         GdkPixbuf *pixbuf;
1592         GError *error = NULL;
1593         GBytes *bytes = NULL;
1594 
1595         loader = g_task_get_task_data (task);
1596 
1597         bytes = g_input_stream_read_bytes_finish (G_INPUT_STREAM (stream), res, &error);
1598 
1599         if (bytes == NULL) {
1600                 gdk_pixbuf_loader_close (loader, NULL);
1601                 g_task_return_error (task, error);
1602         } else if (g_bytes_get_size (bytes) > 0) {
1603                 if (!gdk_pixbuf_loader_write (loader,
1604                                               g_bytes_get_data (bytes, NULL),
1605                                               g_bytes_get_size (bytes),
1606                                               &error)) {
1607                         gdk_pixbuf_loader_close (loader, NULL);
1608                         g_task_return_error (task, error);
1609                         goto out;
1610                 }
1611                 g_input_stream_read_bytes_async (G_INPUT_STREAM (stream),
1612                                                  LOAD_BUFFER_SIZE,
1613                                                  G_PRIORITY_DEFAULT,
1614                                                  g_task_get_cancellable (task),
1615                                                  load_from_stream_async_cb,
1616                                                  g_object_ref (task));
1617 
1618         } else {
1619                 if (!gdk_pixbuf_loader_close (loader, &error)) {
1620                         g_task_return_error (task, error);
1621                         goto out;
1622                 }
1623 
1624                 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1625                 g_task_return_pointer (task, g_object_ref (pixbuf), g_object_unref);
1626         }
1627 
1628 out:
1629         g_bytes_unref (bytes);
1630         g_object_unref (task);
1631 }
1632 
1633 
1634 /**
1635  * gdk_pixbuf_new_from_stream_at_scale_async:
1636  * @stream: a #GInputStream from which to load the pixbuf
1637  * @width: the width the image should have or -1 to not constrain the width
1638  * @height: the height the image should have or -1 to not constrain the height
1639  * @preserve_aspect_ratio: %TRUE to preserve the image's aspect ratio
1640  * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore
1641  * @callback: a #GAsyncReadyCallback to call when the pixbuf is loaded
1642  * @user_data: the data to pass to the callback function
1643  *
1644  * Creates a new pixbuf by asynchronously loading an image from an input stream.
1645  *
1646  * For more details see gdk_pixbuf_new_from_stream_at_scale(), which is the synchronous
1647  * version of this function.
1648  *
1649  * When the operation is finished, @callback will be called in the main thread.
1650  * You can then call gdk_pixbuf_new_from_stream_finish() to get the result of the operation.
1651  *
1652  * Since: 2.24
1653  **/
1654 void
gdk_pixbuf_new_from_stream_at_scale_async(GInputStream * stream,gint width,gint height,gboolean preserve_aspect_ratio,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1655 gdk_pixbuf_new_from_stream_at_scale_async (GInputStream        *stream,
1656 					   gint                 width,
1657 					   gint                 height,
1658 					   gboolean             preserve_aspect_ratio,
1659 					   GCancellable        *cancellable,
1660 					   GAsyncReadyCallback  callback,
1661 					   gpointer             user_data)
1662 {
1663 	GTask *task;
1664 	AtScaleData *data;
1665         GdkPixbufLoader *loader;
1666 
1667 	g_return_if_fail (G_IS_INPUT_STREAM (stream));
1668 	g_return_if_fail (callback != NULL);
1669 	g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
1670 
1671 	data = g_slice_new (AtScaleData);
1672 	data->width = width;
1673 	data->height = height;
1674 	data->preserve_aspect_ratio = preserve_aspect_ratio;
1675 
1676         loader = gdk_pixbuf_loader_new ();
1677         g_signal_connect (loader, "size-prepared",
1678                           G_CALLBACK (at_scale_size_prepared_cb), data);
1679         g_object_set_data_full (G_OBJECT (loader),
1680                                 "gdk-pixbuf-please-kill-me-later",
1681                                 data,
1682                                 (GDestroyNotify) at_scale_data_async_data_free);
1683 
1684 	task = g_task_new (stream, cancellable, callback, user_data);
1685 	g_task_set_source_tag (task, gdk_pixbuf_new_from_stream_at_scale_async);
1686 	g_task_set_task_data (task, loader, g_object_unref);
1687 
1688         g_input_stream_read_bytes_async (stream,
1689                                          LOAD_BUFFER_SIZE,
1690                                          G_PRIORITY_DEFAULT,
1691                                          cancellable,
1692                                          load_from_stream_async_cb,
1693                                          task);
1694 }
1695 
1696 /**
1697  * gdk_pixbuf_new_from_stream:
1698  * @stream:  a #GInputStream to load the pixbuf from
1699  * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore
1700  * @error: Return location for an error
1701  *
1702  * Creates a new pixbuf by loading an image from an input stream.
1703  *
1704  * The file format is detected automatically. If %NULL is returned, then
1705  * @error will be set. The @cancellable can be used to abort the operation
1706  * from another thread. If the operation was cancelled, the error
1707  * %G_IO_ERROR_CANCELLED will be returned. Other possible errors are in
1708  * the #GDK_PIXBUF_ERROR and %G_IO_ERROR domains.
1709  *
1710  * The stream is not closed.
1711  *
1712  * Return value: A newly-created pixbuf, or %NULL if any of several error
1713  * conditions occurred: the file could not be opened, the image format is
1714  * not supported, there was not enough memory to allocate the image buffer,
1715  * the stream contained invalid data, or the operation was cancelled.
1716  *
1717  * Since: 2.14
1718  **/
1719 GdkPixbuf *
gdk_pixbuf_new_from_stream(GInputStream * stream,GCancellable * cancellable,GError ** error)1720 gdk_pixbuf_new_from_stream (GInputStream  *stream,
1721                             GCancellable  *cancellable,
1722                             GError       **error)
1723 {
1724         GdkPixbuf *pixbuf;
1725         GdkPixbufLoader *loader;
1726 
1727         loader = gdk_pixbuf_loader_new ();
1728         pixbuf = load_from_stream (loader, stream, cancellable, error);
1729         g_object_unref (loader);
1730 
1731         return pixbuf;
1732 }
1733 
1734 GdkPixbuf *
_gdk_pixbuf_new_from_resource_try_pixdata(const char * resource_path)1735 _gdk_pixbuf_new_from_resource_try_pixdata (const char *resource_path)
1736 {
1737 	gsize data_size;
1738 	GBytes *bytes;
1739 
1740 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
1741 	/* We specialize GdkPixdata files, making these a reference to the
1742 	 * compiled-in resource data, whether uncompressed and mmap'ed, or
1743 	 * compressed, and uncompressed on-the-fly.
1744          */
1745 	if (g_resources_get_info  (resource_path, 0, &data_size, NULL, NULL) &&
1746 	    data_size > sizeof(guint32) &&
1747 	    (bytes = g_resources_lookup_data (resource_path, 0, NULL)) != NULL) {
1748 		GdkPixbuf*pixbuf = NULL;
1749 		const guint8 *stream = g_bytes_get_data (bytes, NULL);
1750 		GdkPixdata pixdata;
1751 		guint32 magic;
1752 
1753 		magic = (stream[0] << 24) + (stream[1] << 16) + (stream[2] << 8) + stream[3];
1754 		if (magic == GDK_PIXBUF_MAGIC_NUMBER &&
1755 		    gdk_pixdata_deserialize (&pixdata, data_size, stream, NULL)) {
1756 			pixbuf = gdk_pixbuf_from_pixdata (&pixdata, FALSE, NULL);
1757 		}
1758 
1759 		if (pixbuf) {
1760 			/* Free the GBytes with the pixbuf */
1761 			g_object_set_data_full (G_OBJECT (pixbuf), "gdk-pixbuf-resource-bytes", bytes, (GDestroyNotify) g_bytes_unref);
1762 			return pixbuf;
1763 		} else {
1764 			g_bytes_unref (bytes);
1765 		}
1766 	}
1767 G_GNUC_END_IGNORE_DEPRECATIONS
1768 
1769         return NULL;
1770 }
1771 
1772 /**
1773  * gdk_pixbuf_new_from_resource:
1774  * @resource_path: the path of the resource file
1775  * @error: Return location for an error
1776  *
1777  * Creates a new pixbuf by loading an image from an resource.
1778  *
1779  * The file format is detected automatically. If %NULL is returned, then
1780  * @error will be set.
1781  *
1782  * Return value: A newly-created pixbuf, or %NULL if any of several error
1783  * conditions occurred: the file could not be opened, the image format is
1784  * not supported, there was not enough memory to allocate the image buffer,
1785  * the stream contained invalid data, or the operation was cancelled.
1786  *
1787  * Since: 2.26
1788  **/
1789 GdkPixbuf *
gdk_pixbuf_new_from_resource(const gchar * resource_path,GError ** error)1790 gdk_pixbuf_new_from_resource (const gchar  *resource_path,
1791 			      GError      **error)
1792 {
1793 	GInputStream *stream;
1794 	GdkPixbuf *pixbuf;
1795 
1796         pixbuf = _gdk_pixbuf_new_from_resource_try_pixdata (resource_path);
1797         if (pixbuf)
1798                 return pixbuf;
1799 
1800 	stream = g_resources_open_stream (resource_path, 0, error);
1801 	if (stream == NULL)
1802 		return NULL;
1803 
1804 	pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, error);
1805 	g_object_unref (stream);
1806 	return pixbuf;
1807 }
1808 
1809 /**
1810  * gdk_pixbuf_new_from_resource_at_scale:
1811  * @resource_path: the path of the resource file
1812  * @width: The width the image should have or -1 to not constrain the width
1813  * @height: The height the image should have or -1 to not constrain the height
1814  * @preserve_aspect_ratio: %TRUE to preserve the image's aspect ratio
1815  * @error: Return location for an error
1816  *
1817  * Creates a new pixbuf by loading an image from an resource.
1818  *
1819  * The file format is detected automatically. If %NULL is returned, then
1820  * @error will be set.
1821  *
1822  * The image will be scaled to fit in the requested size, optionally
1823  * preserving the image's aspect ratio. When preserving the aspect ratio,
1824  * a @width of -1 will cause the image to be scaled to the exact given
1825  * height, and a @height of -1 will cause the image to be scaled to the
1826  * exact given width. When not preserving aspect ratio, a @width or
1827  * @height of -1 means to not scale the image at all in that dimension.
1828  *
1829  * The stream is not closed.
1830  *
1831  * Return value: A newly-created pixbuf, or %NULL if any of several error
1832  * conditions occurred: the file could not be opened, the image format is
1833  * not supported, there was not enough memory to allocate the image buffer,
1834  * the stream contained invalid data, or the operation was cancelled.
1835  *
1836  * Since: 2.26
1837  */
1838 GdkPixbuf *
gdk_pixbuf_new_from_resource_at_scale(const char * resource_path,int width,int height,gboolean preserve_aspect_ratio,GError ** error)1839 gdk_pixbuf_new_from_resource_at_scale (const char *resource_path,
1840 				       int         width,
1841 				       int         height,
1842 				       gboolean    preserve_aspect_ratio,
1843 				       GError    **error)
1844 {
1845 	GInputStream *stream;
1846 	GdkPixbuf *pixbuf;
1847 
1848 	stream = g_resources_open_stream (resource_path, 0, error);
1849 	if (stream == NULL)
1850 		return NULL;
1851 
1852 	pixbuf = gdk_pixbuf_new_from_stream_at_scale (stream, width, height, preserve_aspect_ratio, NULL, error);
1853 	g_object_unref (stream);
1854 	return pixbuf;
1855 }
1856 
1857 /**
1858  * gdk_pixbuf_new_from_stream_async:
1859  * @stream: a #GInputStream from which to load the pixbuf
1860  * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore
1861  * @callback: a #GAsyncReadyCallback to call when the pixbuf is loaded
1862  * @user_data: the data to pass to the callback function
1863  *
1864  * Creates a new pixbuf by asynchronously loading an image from an input stream.
1865  *
1866  * For more details see gdk_pixbuf_new_from_stream(), which is the synchronous
1867  * version of this function.
1868  *
1869  * When the operation is finished, @callback will be called in the main thread.
1870  * You can then call gdk_pixbuf_new_from_stream_finish() to get the result of the operation.
1871  *
1872  * Since: 2.24
1873  **/
1874 void
gdk_pixbuf_new_from_stream_async(GInputStream * stream,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1875 gdk_pixbuf_new_from_stream_async (GInputStream        *stream,
1876 				  GCancellable        *cancellable,
1877 				  GAsyncReadyCallback  callback,
1878 				  gpointer             user_data)
1879 {
1880 	GTask *task;
1881 
1882 	g_return_if_fail (G_IS_INPUT_STREAM (stream));
1883 	g_return_if_fail (callback != NULL);
1884 	g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
1885 
1886 	task = g_task_new (stream, cancellable, callback, user_data);
1887 	g_task_set_source_tag (task, gdk_pixbuf_new_from_stream_async);
1888         g_task_set_task_data (task, gdk_pixbuf_loader_new (), g_object_unref);
1889 
1890         g_input_stream_read_bytes_async (stream,
1891                                          LOAD_BUFFER_SIZE,
1892                                          G_PRIORITY_DEFAULT,
1893                                          cancellable,
1894                                          load_from_stream_async_cb,
1895                                          task);
1896 }
1897 
1898 /**
1899  * gdk_pixbuf_new_from_stream_finish:
1900  * @async_result: a #GAsyncResult
1901  * @error: a #GError, or %NULL
1902  *
1903  * Finishes an asynchronous pixbuf creation operation started with
1904  * gdk_pixbuf_new_from_stream_async().
1905  *
1906  * Return value: a #GdkPixbuf or %NULL on error. Free the returned
1907  * object with g_object_unref().
1908  *
1909  * Since: 2.24
1910  **/
1911 GdkPixbuf *
gdk_pixbuf_new_from_stream_finish(GAsyncResult * async_result,GError ** error)1912 gdk_pixbuf_new_from_stream_finish (GAsyncResult  *async_result,
1913 				   GError       **error)
1914 {
1915 	GTask *task;
1916 
1917 	g_return_val_if_fail (G_IS_TASK (async_result), NULL);
1918 	g_return_val_if_fail (!error || (error && !*error), NULL);
1919 
1920 	task = G_TASK (async_result);
1921 
1922 	g_warn_if_fail (g_task_get_source_tag (task) == gdk_pixbuf_new_from_stream_async ||
1923 			g_task_get_source_tag (task) == gdk_pixbuf_new_from_stream_at_scale_async);
1924 
1925 	return g_task_propagate_pointer (task, error);
1926 }
1927 
1928 static void
info_cb(GdkPixbufLoader * loader,int width,int height,gpointer data)1929 info_cb (GdkPixbufLoader *loader,
1930          int              width,
1931          int              height,
1932          gpointer         data)
1933 {
1934         struct {
1935                 GdkPixbufFormat *format;
1936                 int width;
1937                 int height;
1938         } *info = data;
1939 
1940         g_return_if_fail (width > 0 && height > 0);
1941 
1942         info->format = gdk_pixbuf_loader_get_format (loader);
1943         info->width = width;
1944         info->height = height;
1945 
1946         gdk_pixbuf_loader_set_size (loader, 0, 0);
1947 }
1948 
1949 /**
1950  * gdk_pixbuf_get_file_info:
1951  * @filename: (type filename): The name of the file to identify.
1952  * @width: (optional) (out): Return location for the width of the
1953  *     image, or %NULL
1954  * @height: (optional) (out): Return location for the height of the
1955  *     image, or %NULL
1956  *
1957  * Parses an image file far enough to determine its format and size.
1958  *
1959  * Returns: (nullable) (transfer none): A #GdkPixbufFormat describing
1960  *    the image format of the file or %NULL if the image format wasn't
1961  *    recognized. The return value is owned by #GdkPixbuf and should
1962  *    not be freed.
1963  *
1964  * Since: 2.4
1965  **/
1966 GdkPixbufFormat *
gdk_pixbuf_get_file_info(const gchar * filename,gint * width,gint * height)1967 gdk_pixbuf_get_file_info (const gchar  *filename,
1968                           gint         *width,
1969                           gint         *height)
1970 {
1971         GdkPixbufLoader *loader;
1972         guchar buffer[SNIFF_BUFFER_SIZE];
1973         int length;
1974         FILE *f;
1975         struct {
1976                 GdkPixbufFormat *format;
1977                 gint width;
1978                 gint height;
1979         } info;
1980 
1981         g_return_val_if_fail (filename != NULL, NULL);
1982 
1983         f = g_fopen (filename, "rb");
1984         if (!f)
1985                 return NULL;
1986 
1987         loader = _gdk_pixbuf_loader_new_with_filename (filename);
1988 
1989         info.format = NULL;
1990         info.width = -1;
1991         info.height = -1;
1992 
1993         g_signal_connect (loader, "size-prepared", G_CALLBACK (info_cb), &info);
1994 
1995         while (!feof (f) && !ferror (f)) {
1996                 length = fread (buffer, 1, sizeof (buffer), f);
1997                 if (length > 0) {
1998                         if (!gdk_pixbuf_loader_write (loader, buffer, length, NULL))
1999                                 break;
2000                 }
2001                 if (info.format != NULL)
2002                         break;
2003         }
2004 
2005         fclose (f);
2006         gdk_pixbuf_loader_close (loader, NULL);
2007         g_object_unref (loader);
2008 
2009         if (width)
2010                 *width = info.width;
2011         if (height)
2012                 *height = info.height;
2013 
2014         return info.format;
2015 }
2016 
2017 typedef struct {
2018         gchar *filename;
2019         gint width;
2020         gint height;
2021 } GetFileInfoAsyncData;
2022 
2023 static void
get_file_info_async_data_free(GetFileInfoAsyncData * data)2024 get_file_info_async_data_free (GetFileInfoAsyncData *data)
2025 {
2026         g_free (data->filename);
2027         g_slice_free (GetFileInfoAsyncData, data);
2028 }
2029 
2030 static void
get_file_info_thread(GTask * task,gpointer source_object,GetFileInfoAsyncData * data,GCancellable * cancellable)2031 get_file_info_thread (GTask                *task,
2032                       gpointer              source_object,
2033                       GetFileInfoAsyncData *data,
2034                       GCancellable         *cancellable)
2035 {
2036         GdkPixbufFormat *format;
2037 
2038         format = gdk_pixbuf_get_file_info (data->filename, &data->width, &data->height);
2039         if (format == NULL) {
2040                 g_task_return_new_error (task,
2041                                          GDK_PIXBUF_ERROR,
2042                                          GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
2043                                          "Failed to recognize image format");
2044         } else {
2045                 g_task_return_pointer (task,
2046                                        gdk_pixbuf_format_copy (format),
2047                                        (GDestroyNotify) gdk_pixbuf_format_free);
2048         }
2049 }
2050 
2051 /**
2052  * gdk_pixbuf_get_file_info_async:
2053  * @filename: (type filename): The name of the file to identify
2054  * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore
2055  * @callback: a #GAsyncReadyCallback to call when the file info is available
2056  * @user_data: the data to pass to the callback function
2057  *
2058  * Asynchronously parses an image file far enough to determine its
2059  * format and size.
2060  *
2061  * For more details see gdk_pixbuf_get_file_info(), which is the synchronous
2062  * version of this function.
2063  *
2064  * When the operation is finished, @callback will be called in the
2065  * main thread. You can then call gdk_pixbuf_get_file_info_finish() to
2066  * get the result of the operation.
2067  *
2068  * Since: 2.32
2069  **/
2070 void
gdk_pixbuf_get_file_info_async(const gchar * filename,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)2071 gdk_pixbuf_get_file_info_async  (const gchar          *filename,
2072                                  GCancellable         *cancellable,
2073                                  GAsyncReadyCallback   callback,
2074                                  gpointer              user_data)
2075 {
2076         GetFileInfoAsyncData *data;
2077         GTask *task;
2078 
2079         g_return_if_fail (filename != NULL);
2080         g_return_if_fail (callback != NULL);
2081         g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
2082 
2083         data = g_slice_new0 (GetFileInfoAsyncData);
2084         data->filename = g_strdup (filename);
2085 
2086         task = g_task_new (NULL, cancellable, callback, user_data);
2087         g_task_set_return_on_cancel (task, TRUE);
2088         g_task_set_source_tag (task, gdk_pixbuf_get_file_info_async);
2089         g_task_set_task_data (task, data, (GDestroyNotify) get_file_info_async_data_free);
2090         g_task_run_in_thread (task, (GTaskThreadFunc) get_file_info_thread);
2091         g_object_unref (task);
2092 }
2093 
2094 /**
2095  * gdk_pixbuf_get_file_info_finish:
2096  * @async_result: a #GAsyncResult
2097  * @width: (out): Return location for the width of the image, or %NULL
2098  * @height: (out): Return location for the height of the image, or %NULL
2099  * @error: a #GError, or %NULL
2100  *
2101  * Finishes an asynchronous pixbuf parsing operation started with
2102  * gdk_pixbuf_get_file_info_async().
2103  *
2104  * Returns: (transfer none): A #GdkPixbufFormat describing the image
2105  *    format of the file or %NULL if the image format wasn't
2106  *    recognized. The return value is owned by GdkPixbuf and should
2107  *    not be freed.
2108  *
2109  * Since: 2.32
2110  **/
2111 GdkPixbufFormat *
gdk_pixbuf_get_file_info_finish(GAsyncResult * async_result,gint * width,gint * height,GError ** error)2112 gdk_pixbuf_get_file_info_finish (GAsyncResult         *async_result,
2113                                  gint                 *width,
2114                                  gint                 *height,
2115                                  GError              **error)
2116 {
2117         GetFileInfoAsyncData *data;
2118         GTask *task;
2119 
2120         g_return_val_if_fail (g_task_is_valid (async_result, NULL), NULL);
2121 
2122         task = G_TASK (async_result);
2123 
2124         g_return_val_if_fail (!error || (error && !*error), NULL);
2125         g_warn_if_fail (g_task_get_source_tag (task) == gdk_pixbuf_get_file_info_async);
2126 
2127         data = g_task_get_task_data (task);
2128 
2129         if (!g_task_had_error (task)) {
2130                 if (width)
2131                         *width = data->width;
2132                 if (height)
2133                         *height = data->height;
2134         }
2135 
2136         return g_task_propagate_pointer (task, error);
2137 }
2138 
2139 /**
2140  * gdk_pixbuf_new_from_xpm_data:
2141  * @data: (array zero-terminated=1): Pointer to inline XPM data.
2142  *
2143  * Creates a new pixbuf by parsing XPM data in memory.  This data is commonly
2144  * the result of including an XPM file into a program's C source.
2145  *
2146  * Return value: A newly-created pixbuf with a reference count of 1.
2147  **/
2148 GdkPixbuf *
gdk_pixbuf_new_from_xpm_data(const char ** data)2149 gdk_pixbuf_new_from_xpm_data (const char **data)
2150 {
2151         GdkPixbuf *(* load_xpm_data) (const char **data);
2152         GdkPixbuf *pixbuf;
2153         GError *error = NULL;
2154         GdkPixbufModule *xpm_module;
2155 
2156         g_return_val_if_fail (data != NULL, NULL);
2157 
2158         xpm_module = _gdk_pixbuf_get_named_module ("xpm", &error);
2159         if (xpm_module == NULL) {
2160                 g_warning ("Error loading XPM image loader: %s", error->message);
2161                 g_error_free (error);
2162                 return NULL;
2163         }
2164 
2165         if (!_gdk_pixbuf_load_module (xpm_module, &error)) {
2166                 g_warning ("Error loading XPM image loader: %s", error->message);
2167                 g_error_free (error);
2168                 return NULL;
2169         }
2170 
2171         if (xpm_module->load_xpm_data == NULL) {
2172                 g_warning ("gdk-pixbuf XPM module lacks XPM data capability");
2173                 pixbuf = NULL;
2174         } else {
2175                 load_xpm_data = xpm_module->load_xpm_data;
2176                 pixbuf = (* load_xpm_data) (data);
2177         }
2178 
2179         return pixbuf;
2180 }
2181 
2182 static void
collect_save_options(va_list opts,gchar *** keys,gchar *** vals)2183 collect_save_options (va_list   opts,
2184                       gchar  ***keys,
2185                       gchar  ***vals)
2186 {
2187   gchar *key;
2188   gchar *val;
2189   gchar *next;
2190   gint count;
2191 
2192   count = 0;
2193   *keys = NULL;
2194   *vals = NULL;
2195 
2196   next = va_arg (opts, gchar*);
2197   while (next)
2198     {
2199       key = next;
2200       val = va_arg (opts, gchar*);
2201 
2202       ++count;
2203 
2204       /* woo, slow */
2205       *keys = g_realloc (*keys, sizeof(gchar*) * (count + 1));
2206       *vals = g_realloc (*vals, sizeof(gchar*) * (count + 1));
2207 
2208       (*keys)[count-1] = g_strdup (key);
2209       (*vals)[count-1] = g_strdup (val);
2210 
2211       (*keys)[count] = NULL;
2212       (*vals)[count] = NULL;
2213 
2214       next = va_arg (opts, gchar*);
2215     }
2216 }
2217 
2218 static gboolean
save_to_file_callback(const gchar * buf,gsize count,GError ** error,gpointer data)2219 save_to_file_callback (const gchar *buf,
2220                        gsize        count,
2221                        GError     **error,
2222                        gpointer     data)
2223 {
2224         FILE *filehandle = data;
2225         gsize n;
2226 
2227         n = fwrite (buf, 1, count, filehandle);
2228         if (n != count) {
2229                 gint save_errno = errno;
2230                 g_set_error (error,
2231                              G_FILE_ERROR,
2232                              g_file_error_from_errno (save_errno),
2233                              _("Error writing to image file: %s"),
2234                              g_strerror (save_errno));
2235                 return FALSE;
2236         }
2237         return TRUE;
2238 }
2239 
2240 static gboolean
gdk_pixbuf_real_save(GdkPixbuf * pixbuf,FILE * filehandle,const char * type,gchar ** keys,gchar ** values,GError ** error)2241 gdk_pixbuf_real_save (GdkPixbuf     *pixbuf,
2242                       FILE          *filehandle,
2243                       const char    *type,
2244                       gchar        **keys,
2245                       gchar        **values,
2246                       GError       **error)
2247 {
2248         gboolean ret;
2249         GdkPixbufModule *image_module = NULL;
2250 
2251         image_module = _gdk_pixbuf_get_named_module (type, error);
2252 
2253         if (image_module == NULL)
2254                 return FALSE;
2255 
2256         if (!_gdk_pixbuf_load_module (image_module, error))
2257                 return FALSE;
2258 
2259         if (image_module->save) {
2260                 /* save normally */
2261                 ret = (* image_module->save) (filehandle, pixbuf,
2262                                               keys, values,
2263                                               error);
2264         } else if (image_module->save_to_callback) {
2265                 /* save with simple callback */
2266                 ret = (* image_module->save_to_callback) (save_to_file_callback,
2267                                                           filehandle, pixbuf,
2268                                                           keys, values,
2269                                                           error);
2270         } else {
2271                 /* can't save */
2272                 g_set_error (error,
2273                              GDK_PIXBUF_ERROR,
2274                              GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
2275                              _("This build of gdk-pixbuf does not support saving the image format: %s"),
2276                              type);
2277                 ret = FALSE;
2278         }
2279 
2280         return ret;
2281 }
2282 
2283 #define TMP_FILE_BUF_SIZE 4096
2284 
2285 static gboolean
save_to_callback_with_tmp_file(GdkPixbufModule * image_module,GdkPixbuf * pixbuf,GdkPixbufSaveFunc save_func,gpointer user_data,gchar ** keys,gchar ** values,GError ** error)2286 save_to_callback_with_tmp_file (GdkPixbufModule   *image_module,
2287                                 GdkPixbuf         *pixbuf,
2288                                 GdkPixbufSaveFunc  save_func,
2289                                 gpointer           user_data,
2290                                 gchar            **keys,
2291                                 gchar            **values,
2292                                 GError           **error)
2293 {
2294         int fd;
2295         FILE *f = NULL;
2296         gboolean retval = FALSE;
2297         gchar *buf = NULL;
2298         gsize n;
2299         gchar *filename = NULL;
2300 
2301         buf = g_try_malloc (TMP_FILE_BUF_SIZE);
2302         if (buf == NULL) {
2303                 g_set_error_literal (error,
2304                                      GDK_PIXBUF_ERROR,
2305                                      GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
2306                                      _("Insufficient memory to save image to callback"));
2307                 goto end;
2308         }
2309 
2310         fd = g_file_open_tmp ("gdkpixbuf-save-tmp.XXXXXX", &filename, error);
2311         if (fd == -1)
2312                 goto end;
2313         f = fdopen (fd, "wb+");
2314         if (f == NULL) {
2315                 gint save_errno = errno;
2316                 g_set_error_literal (error,
2317                                      G_FILE_ERROR,
2318                                      g_file_error_from_errno (save_errno),
2319                                      _("Failed to open temporary file"));
2320                 goto end;
2321         }
2322 
2323         retval = (image_module->save) (f, pixbuf, keys, values, error);
2324         if (!retval)
2325                 goto end;
2326 
2327         rewind (f);
2328         for (;;) {
2329                 n = fread (buf, 1, TMP_FILE_BUF_SIZE, f);
2330                 if (n > 0) {
2331                         if (!save_func (buf, n, error, user_data))
2332                                 goto end;
2333                 }
2334                 if (n != TMP_FILE_BUF_SIZE)
2335                         break;
2336         }
2337         if (ferror (f)) {
2338                 gint save_errno = errno;
2339                 g_set_error_literal (error,
2340                                      G_FILE_ERROR,
2341                                      g_file_error_from_errno (save_errno),
2342                                      _("Failed to read from temporary file"));
2343                 goto end;
2344         }
2345         retval = TRUE;
2346 
2347  end:
2348         /* cleanup and return retval */
2349         if (f)
2350                 fclose (f);
2351         if (filename) {
2352                 g_unlink (filename);
2353                 g_free (filename);
2354         }
2355         g_free (buf);
2356 
2357         return retval;
2358 }
2359 
2360 static gboolean
gdk_pixbuf_real_save_to_callback(GdkPixbuf * pixbuf,GdkPixbufSaveFunc save_func,gpointer user_data,const char * type,gchar ** keys,gchar ** values,GError ** error)2361 gdk_pixbuf_real_save_to_callback (GdkPixbuf         *pixbuf,
2362                                   GdkPixbufSaveFunc  save_func,
2363                                   gpointer           user_data,
2364                                   const char        *type,
2365                                   gchar            **keys,
2366                                   gchar            **values,
2367                                   GError           **error)
2368 {
2369         gboolean ret;
2370         GdkPixbufModule *image_module = NULL;
2371 
2372         image_module = _gdk_pixbuf_get_named_module (type, error);
2373 
2374         if (image_module == NULL)
2375                 return FALSE;
2376 
2377         if (!_gdk_pixbuf_load_module (image_module, error))
2378                 return FALSE;
2379 
2380         if (image_module->save_to_callback) {
2381                 /* save normally */
2382                 ret = (* image_module->save_to_callback) (save_func, user_data,
2383                                                           pixbuf, keys, values,
2384                                                           error);
2385         } else if (image_module->save) {
2386                 /* use a temporary file */
2387                 ret = save_to_callback_with_tmp_file (image_module, pixbuf,
2388                                                       save_func, user_data,
2389                                                       keys, values,
2390                                                       error);
2391         } else {
2392                 /* can't save */
2393                 g_set_error (error,
2394                              GDK_PIXBUF_ERROR,
2395                              GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
2396                              _("This build of gdk-pixbuf does not support saving the image format: %s"),
2397                              type);
2398                 ret = FALSE;
2399         }
2400 
2401         return ret;
2402 }
2403 
2404 
2405 /**
2406  * gdk_pixbuf_save:
2407  * @pixbuf: a #GdkPixbuf.
2408  * @filename: (type filename): name of file to save.
2409  * @type: name of file format.
2410  * @error: (allow-none): return location for error, or %NULL
2411  * @...: list of key-value save options, followed by %NULL
2412  *
2413  * Saves pixbuf to a file in format @type. By default, "jpeg", "png", "ico"
2414  * and "bmp" are possible file formats to save in, but more formats may be
2415  * installed. The list of all writable formats can be determined in the
2416  * following way:
2417  *
2418  * |[
2419  * void add_if_writable (GdkPixbufFormat *data, GSList **list)
2420  * {
2421  *   if (gdk_pixbuf_format_is_writable (data))
2422  *     *list = g_slist_prepend (*list, data);
2423  * }
2424  *
2425  * GSList *formats = gdk_pixbuf_get_formats ();
2426  * GSList *writable_formats = NULL;
2427  * g_slist_foreach (formats, add_if_writable, &writable_formats);
2428  * g_slist_free (formats);
2429  * ]|
2430  *
2431  * If @error is set, %FALSE will be returned. Possible errors include
2432  * those in the #GDK_PIXBUF_ERROR domain and those in the #G_FILE_ERROR domain.
2433  *
2434  * The variable argument list should be %NULL-terminated; if not empty,
2435  * it should contain pairs of strings that modify the save
2436  * parameters. For example:
2437  * |[
2438  * gdk_pixbuf_save (pixbuf, handle, "jpeg", &error, "quality", "100", NULL);
2439  * ]|
2440  *
2441  * Currently only few parameters exist. JPEG images can be saved with a
2442  * "quality" parameter; its value should be in the range [0,100]. JPEG
2443  * and PNG density can be set by setting the "x-dpi" and "y-dpi" parameters
2444  * to the appropriate values in dots per inch.
2445  *
2446  * Text chunks can be attached to PNG images by specifying parameters of
2447  * the form "tEXt::key", where key is an ASCII string of length 1-79.
2448  * The values are UTF-8 encoded strings. The PNG compression level can
2449  * be specified using the "compression" parameter; it's value is in an
2450  * integer in the range of [0,9].
2451  *
2452  * ICC color profiles can also be embedded into PNG, JPEG and TIFF images.
2453  * The "icc-profile" value should be the complete ICC profile encoded
2454  * into base64.
2455  *
2456  * |[
2457  * gchar *contents;
2458  * gchar *contents_encode;
2459  * gsize length;
2460  * g_file_get_contents ("/home/hughsie/.color/icc/L225W.icm", &contents, &length, NULL);
2461  * contents_encode = g_base64_encode ((const guchar *) contents, length);
2462  * gdk_pixbuf_save (pixbuf, handle, "png", &error, "icc-profile", contents_encode, NULL);
2463  * ]|
2464  *
2465  * TIFF images recognize: (1) a "bits-per-sample" option (integer) which
2466  * can be either 1 for saving bi-level CCITTFAX4 images, or 8 for saving
2467  * 8-bits per sample; (2) a "compression" option (integer) which can be
2468  * 1 for no compression, 2 for Huffman, 5 for LZW, 7 for JPEG and 8 for
2469  * DEFLATE (see the libtiff documentation and tiff.h for all supported
2470  * codec values); (3) an "icc-profile" option (zero-terminated string)
2471  * containing a base64 encoded ICC color profile.
2472  *
2473  * ICO images can be saved in depth 16, 24, or 32, by using the "depth"
2474  * parameter. When the ICO saver is given "x_hot" and "y_hot" parameters,
2475  * it produces a CUR instead of an ICO.
2476  *
2477  * Return value: whether an error was set
2478  **/
2479 gboolean
gdk_pixbuf_save(GdkPixbuf * pixbuf,const char * filename,const char * type,GError ** error,...)2480 gdk_pixbuf_save (GdkPixbuf  *pixbuf,
2481                  const char *filename,
2482                  const char *type,
2483                  GError    **error,
2484                  ...)
2485 {
2486         gchar **keys = NULL;
2487         gchar **values = NULL;
2488         va_list args;
2489         gboolean result;
2490 
2491         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2492 
2493         va_start (args, error);
2494 
2495         collect_save_options (args, &keys, &values);
2496 
2497         va_end (args);
2498 
2499         result = gdk_pixbuf_savev (pixbuf, filename, type,
2500                                    keys, values,
2501                                    error);
2502 
2503         g_strfreev (keys);
2504         g_strfreev (values);
2505 
2506         return result;
2507 }
2508 
2509 /**
2510  * gdk_pixbuf_savev:
2511  * @pixbuf: a #GdkPixbuf.
2512  * @filename: (type filename): name of file to save.
2513  * @type: name of file format.
2514  * @option_keys: (array zero-terminated=1): name of options to set, %NULL-terminated
2515  * @option_values: (array zero-terminated=1): values for named options
2516  * @error: (allow-none): return location for error, or %NULL
2517  *
2518  * Saves pixbuf to a file in @type, which is currently "jpeg", "png", "tiff", "ico" or "bmp".
2519  * If @error is set, %FALSE will be returned.
2520  * See gdk_pixbuf_save () for more details.
2521  *
2522  * Return value: whether an error was set
2523  **/
2524 
2525 gboolean
gdk_pixbuf_savev(GdkPixbuf * pixbuf,const char * filename,const char * type,char ** option_keys,char ** option_values,GError ** error)2526 gdk_pixbuf_savev (GdkPixbuf  *pixbuf,
2527                   const char *filename,
2528                   const char *type,
2529                   char      **option_keys,
2530                   char      **option_values,
2531                   GError    **error)
2532 {
2533         FILE *f = NULL;
2534         gboolean result;
2535 
2536         g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), FALSE);
2537         g_return_val_if_fail (gdk_pixbuf_get_width (pixbuf) >= 0, FALSE);
2538         g_return_val_if_fail (gdk_pixbuf_get_height (pixbuf) >= 0, FALSE);
2539         g_return_val_if_fail (gdk_pixbuf_get_n_channels (pixbuf) >= 0, FALSE);
2540         g_return_val_if_fail (filename != NULL, FALSE);
2541         g_return_val_if_fail (type != NULL, FALSE);
2542         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2543 
2544         f = g_fopen (filename, "wb");
2545 
2546         if (f == NULL) {
2547                 gint save_errno = errno;
2548                 gchar *display_name = g_filename_display_name (filename);
2549                 g_set_error (error,
2550                              G_FILE_ERROR,
2551                              g_file_error_from_errno (save_errno),
2552                              _("Failed to open “%s” for writing: %s"),
2553                              display_name,
2554                              g_strerror (save_errno));
2555                 g_free (display_name);
2556                 return FALSE;
2557         }
2558 
2559 
2560        result = gdk_pixbuf_real_save (pixbuf, f, type,
2561                                       option_keys, option_values,
2562                                       error);
2563 
2564 
2565        if (!result) {
2566                g_return_val_if_fail (error == NULL || *error != NULL, FALSE);
2567                fclose (f);
2568                g_unlink (filename);
2569                return FALSE;
2570        }
2571 
2572        if (fclose (f) < 0) {
2573                gint save_errno = errno;
2574                gchar *display_name = g_filename_display_name (filename);
2575                g_set_error (error,
2576                             G_FILE_ERROR,
2577                             g_file_error_from_errno (save_errno),
2578                             _("Failed to close “%s” while writing image, all data may not have been saved: %s"),
2579                             display_name,
2580                             g_strerror (save_errno));
2581                g_free (display_name);
2582                return FALSE;
2583        }
2584 
2585        return TRUE;
2586 }
2587 
2588 #ifdef G_OS_WIN32
2589 
2590 /**
2591  * gdk_pixbuf_savev_utf8:
2592  * @pixbuf: a #GdkPixbuf.
2593  * @filename: name of file to save.
2594  * @type: name of file format.
2595  * @option_keys: (array zero-terminated=1): name of options to set, %NULL-terminated
2596  * @option_values: (array zero-terminated=1): values for named options
2597  * @error: (allow-none): return location for error, or %NULL
2598  *
2599  * Same as gdk_pixbuf_savev()
2600  *
2601  * Return value: whether an error was set
2602  **/
2603 gboolean
gdk_pixbuf_savev_utf8(GdkPixbuf * pixbuf,const char * filename,const char * type,char ** option_keys,char ** option_values,GError ** error)2604 gdk_pixbuf_savev_utf8 (GdkPixbuf  *pixbuf,
2605                        const char *filename,
2606                        const char *type,
2607                        char      **option_keys,
2608                        char      **option_values,
2609                        GError    **error)
2610 {
2611     return gdk_pixbuf_savev (pixbuf, filename, type, option_keys,
2612                              option_values, error);
2613 }
2614 
2615 #endif
2616 
2617 /**
2618  * gdk_pixbuf_save_to_callback:
2619  * @pixbuf: a #GdkPixbuf.
2620  * @save_func: (scope call): a function that is called to save each block of data that
2621  *   the save routine generates.
2622  * @user_data: user data to pass to the save function.
2623  * @type: name of file format.
2624  * @error: (allow-none): return location for error, or %NULL
2625  * @...: list of key-value save options
2626  *
2627  * Saves pixbuf in format @type by feeding the produced data to a
2628  * callback. Can be used when you want to store the image to something
2629  * other than a file, such as an in-memory buffer or a socket.
2630  * If @error is set, %FALSE will be returned. Possible errors
2631  * include those in the #GDK_PIXBUF_ERROR domain and whatever the save
2632  * function generates.
2633  *
2634  * See gdk_pixbuf_save() for more details.
2635  *
2636  * Return value: whether an error was set
2637  *
2638  * Since: 2.4
2639  **/
2640 gboolean
gdk_pixbuf_save_to_callback(GdkPixbuf * pixbuf,GdkPixbufSaveFunc save_func,gpointer user_data,const char * type,GError ** error,...)2641 gdk_pixbuf_save_to_callback    (GdkPixbuf  *pixbuf,
2642                                 GdkPixbufSaveFunc save_func,
2643                                 gpointer user_data,
2644                                 const char *type,
2645                                 GError    **error,
2646                                 ...)
2647 {
2648         gchar **keys = NULL;
2649         gchar **values = NULL;
2650         va_list args;
2651         gboolean result;
2652 
2653         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2654 
2655         va_start (args, error);
2656 
2657         collect_save_options (args, &keys, &values);
2658 
2659         va_end (args);
2660 
2661         result = gdk_pixbuf_save_to_callbackv (pixbuf, save_func, user_data,
2662                                                type, keys, values,
2663                                                error);
2664 
2665         g_strfreev (keys);
2666         g_strfreev (values);
2667 
2668         return result;
2669 }
2670 
2671 /**
2672  * gdk_pixbuf_save_to_callbackv:
2673  * @pixbuf: a #GdkPixbuf.
2674  * @save_func: (scope call): a function that is called to save each block of data that
2675  *   the save routine generates.
2676  * @user_data: (closure): user data to pass to the save function.
2677  * @type: name of file format.
2678  * @option_keys: (array zero-terminated=1) (element-type utf8): name of options to set, %NULL-terminated
2679  * @option_values: (array zero-terminated=1) (element-type utf8): values for named options
2680  * @error: (allow-none): return location for error, or %NULL
2681  *
2682  * Saves pixbuf to a callback in format @type, which is currently "jpeg",
2683  * "png", "tiff", "ico" or "bmp".  If @error is set, %FALSE will be returned. See
2684  * gdk_pixbuf_save_to_callback () for more details.
2685  *
2686  * Return value: whether an error was set
2687  *
2688  * Since: 2.4
2689  **/
2690 gboolean
gdk_pixbuf_save_to_callbackv(GdkPixbuf * pixbuf,GdkPixbufSaveFunc save_func,gpointer user_data,const char * type,char ** option_keys,char ** option_values,GError ** error)2691 gdk_pixbuf_save_to_callbackv   (GdkPixbuf  *pixbuf,
2692                                 GdkPixbufSaveFunc save_func,
2693                                 gpointer user_data,
2694                                 const char *type,
2695                                 char      **option_keys,
2696                                 char      **option_values,
2697                                 GError    **error)
2698 {
2699         gboolean result;
2700 
2701         g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), FALSE);
2702         g_return_val_if_fail (gdk_pixbuf_get_width (pixbuf) >= 0, FALSE);
2703         g_return_val_if_fail (gdk_pixbuf_get_height (pixbuf) >= 0, FALSE);
2704         g_return_val_if_fail (gdk_pixbuf_get_n_channels (pixbuf) >= 0, FALSE);
2705         g_return_val_if_fail (save_func != NULL, FALSE);
2706         g_return_val_if_fail (type != NULL, FALSE);
2707         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2708 
2709        result = gdk_pixbuf_real_save_to_callback (pixbuf,
2710                                                   save_func, user_data, type,
2711                                                   option_keys, option_values,
2712                                                   error);
2713 
2714        if (!result) {
2715                g_return_val_if_fail (error == NULL || *error != NULL, FALSE);
2716                return FALSE;
2717        }
2718 
2719        return TRUE;
2720 }
2721 
2722 /**
2723  * gdk_pixbuf_save_to_buffer:
2724  * @pixbuf: a #GdkPixbuf.
2725  * @buffer: (array length=buffer_size) (out) (element-type guint8): location to receive a pointer
2726  *   to the new buffer.
2727  * @buffer_size: location to receive the size of the new buffer.
2728  * @type: name of file format.
2729  * @error: (allow-none): return location for error, or %NULL
2730  * @...: list of key-value save options
2731  *
2732  * Saves pixbuf to a new buffer in format @type, which is currently "jpeg",
2733  * "png", "tiff", "ico" or "bmp".  This is a convenience function that uses
2734  * gdk_pixbuf_save_to_callback() to do the real work. Note that the buffer
2735  * is not nul-terminated and may contain embedded  nuls.
2736  * If @error is set, %FALSE will be returned and @buffer will be set to
2737  * %NULL. Possible errors include those in the #GDK_PIXBUF_ERROR
2738  * domain.
2739  *
2740  * See gdk_pixbuf_save() for more details.
2741  *
2742  * Return value: whether an error was set
2743  *
2744  * Since: 2.4
2745  **/
2746 gboolean
gdk_pixbuf_save_to_buffer(GdkPixbuf * pixbuf,gchar ** buffer,gsize * buffer_size,const char * type,GError ** error,...)2747 gdk_pixbuf_save_to_buffer      (GdkPixbuf  *pixbuf,
2748                                 gchar     **buffer,
2749                                 gsize      *buffer_size,
2750                                 const char *type,
2751                                 GError    **error,
2752                                 ...)
2753 {
2754         gchar **keys = NULL;
2755         gchar **values = NULL;
2756         va_list args;
2757         gboolean result;
2758 
2759         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2760 
2761         va_start (args, error);
2762 
2763         collect_save_options (args, &keys, &values);
2764 
2765         va_end (args);
2766 
2767         result = gdk_pixbuf_save_to_bufferv (pixbuf, buffer, buffer_size,
2768                                              type, keys, values,
2769                                              error);
2770 
2771         g_strfreev (keys);
2772         g_strfreev (values);
2773 
2774         return result;
2775 }
2776 
2777 struct SaveToBufferData {
2778         gchar *buffer;
2779         gsize len, max;
2780 };
2781 
2782 static gboolean
save_to_buffer_callback(const gchar * data,gsize count,GError ** error,gpointer user_data)2783 save_to_buffer_callback (const gchar *data,
2784                          gsize count,
2785                          GError **error,
2786                          gpointer user_data)
2787 {
2788         struct SaveToBufferData *sdata = user_data;
2789         gchar *new_buffer;
2790         gsize new_max;
2791 
2792         if (sdata->len + count > sdata->max) {
2793                 new_max = MAX (sdata->max*2, sdata->len + count);
2794                 new_buffer = g_try_realloc (sdata->buffer, new_max);
2795                 if (!new_buffer) {
2796                         g_set_error_literal (error,
2797                                              GDK_PIXBUF_ERROR,
2798                                              GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
2799                                              _("Insufficient memory to save image into a buffer"));
2800                         return FALSE;
2801                 }
2802                 sdata->buffer = new_buffer;
2803                 sdata->max = new_max;
2804         }
2805         memcpy (sdata->buffer + sdata->len, data, count);
2806         sdata->len += count;
2807         return TRUE;
2808 }
2809 
2810 /**
2811  * gdk_pixbuf_save_to_bufferv:
2812  * @pixbuf: a #GdkPixbuf.
2813  * @buffer: (array length=buffer_size) (out) (element-type guint8):
2814  *   location to receive a pointer to the new buffer.
2815  * @buffer_size: location to receive the size of the new buffer.
2816  * @type: name of file format.
2817  * @option_keys: (array zero-terminated=1): name of options to set, %NULL-terminated
2818  * @option_values: (array zero-terminated=1): values for named options
2819  * @error: (allow-none): return location for error, or %NULL
2820  *
2821  * Saves pixbuf to a new buffer in format @type, which is currently "jpeg",
2822  * "tiff", "png", "ico" or "bmp".  See gdk_pixbuf_save_to_buffer()
2823  * for more details.
2824  *
2825  * Return value: whether an error was set
2826  *
2827  * Since: 2.4
2828  **/
2829 gboolean
gdk_pixbuf_save_to_bufferv(GdkPixbuf * pixbuf,gchar ** buffer,gsize * buffer_size,const char * type,char ** option_keys,char ** option_values,GError ** error)2830 gdk_pixbuf_save_to_bufferv     (GdkPixbuf  *pixbuf,
2831                                 gchar     **buffer,
2832                                 gsize      *buffer_size,
2833                                 const char *type,
2834                                 char      **option_keys,
2835                                 char      **option_values,
2836                                 GError    **error)
2837 {
2838         static const gint initial_max = 1024;
2839         struct SaveToBufferData sdata;
2840 
2841         *buffer = NULL;
2842         *buffer_size = 0;
2843 
2844         sdata.buffer = g_try_malloc (initial_max);
2845         sdata.max = initial_max;
2846         sdata.len = 0;
2847         if (!sdata.buffer) {
2848                 g_set_error_literal (error,
2849                                      GDK_PIXBUF_ERROR,
2850                                      GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
2851                                      _("Insufficient memory to save image into a buffer"));
2852                 return FALSE;
2853         }
2854 
2855         if (!gdk_pixbuf_save_to_callbackv (pixbuf,
2856                                            save_to_buffer_callback, &sdata,
2857                                            type, option_keys, option_values,
2858                                            error)) {
2859                 g_free (sdata.buffer);
2860                 return FALSE;
2861         }
2862 
2863         *buffer = sdata.buffer;
2864         *buffer_size = sdata.len;
2865         return TRUE;
2866 }
2867 
2868 typedef struct {
2869         GOutputStream *stream;
2870         GCancellable  *cancellable;
2871 } SaveToStreamData;
2872 
2873 static gboolean
save_to_stream(const gchar * buffer,gsize count,GError ** error,gpointer data)2874 save_to_stream (const gchar  *buffer,
2875                 gsize         count,
2876                 GError      **error,
2877                 gpointer      data)
2878 {
2879         SaveToStreamData *sdata = (SaveToStreamData *)data;
2880         gsize remaining;
2881         gssize written;
2882         GError *my_error = NULL;
2883 
2884         remaining = count;
2885         written = 0;
2886         while (remaining > 0) {
2887                 buffer += written;
2888                 remaining -= written;
2889                 written = g_output_stream_write (sdata->stream,
2890                                                  buffer, remaining,
2891                                                  sdata->cancellable,
2892                                                  &my_error);
2893                 if (written < 0) {
2894                         if (!my_error) {
2895                                 g_set_error_literal (error,
2896                                                      G_IO_ERROR, 0,
2897                                                      _("Error writing to image stream"));
2898                         }
2899                         else {
2900                                 g_propagate_error (error, my_error);
2901                         }
2902                         return FALSE;
2903                 }
2904         }
2905 
2906         return TRUE;
2907 }
2908 
2909 /**
2910  * gdk_pixbuf_save_to_streamv:
2911  * @pixbuf: a #GdkPixbuf
2912  * @stream: a #GOutputStream to save the pixbuf to
2913  * @type: name of file format
2914  * @option_keys: (array zero-terminated=1): name of options to set, %NULL-terminated
2915  * @option_values: (array zero-terminated=1): values for named options
2916  * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore
2917  * @error: (allow-none): return location for error, or %NULL
2918  *
2919  * Saves @pixbuf to an output stream.
2920  *
2921  * Supported file formats are currently "jpeg", "tiff", "png", "ico" or
2922  * "bmp". See gdk_pixbuf_save_to_stream() for more details.
2923  *
2924  * Returns: %TRUE if the pixbuf was saved successfully, %FALSE if an
2925  *     error was set.
2926  *
2927  * Since: 2.36
2928  */
2929 gboolean
gdk_pixbuf_save_to_streamv(GdkPixbuf * pixbuf,GOutputStream * stream,const char * type,char ** option_keys,char ** option_values,GCancellable * cancellable,GError ** error)2930 gdk_pixbuf_save_to_streamv (GdkPixbuf      *pixbuf,
2931                             GOutputStream  *stream,
2932                             const char     *type,
2933                             char          **option_keys,
2934                             char          **option_values,
2935                             GCancellable   *cancellable,
2936                             GError        **error)
2937 {
2938         SaveToStreamData data;
2939 
2940         data.stream = stream;
2941         data.cancellable = cancellable;
2942 
2943         return gdk_pixbuf_save_to_callbackv (pixbuf, save_to_stream,
2944                                              &data, type,
2945                                              option_keys, option_values,
2946                                              error);
2947 }
2948 
2949 /**
2950  * gdk_pixbuf_save_to_stream:
2951  * @pixbuf: a #GdkPixbuf
2952  * @stream: a #GOutputStream to save the pixbuf to
2953  * @type: name of file format
2954  * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore
2955  * @error: (allow-none): return location for error, or %NULL
2956  * @...: list of key-value save options
2957  *
2958  * Saves @pixbuf to an output stream.
2959  *
2960  * Supported file formats are currently "jpeg", "tiff", "png", "ico" or
2961  * "bmp". See gdk_pixbuf_save_to_buffer() for more details.
2962  *
2963  * The @cancellable can be used to abort the operation from another
2964  * thread. If the operation was cancelled, the error %G_IO_ERROR_CANCELLED
2965  * will be returned. Other possible errors are in the #GDK_PIXBUF_ERROR
2966  * and %G_IO_ERROR domains.
2967  *
2968  * The stream is not closed.
2969  *
2970  * Returns: %TRUE if the pixbuf was saved successfully, %FALSE if an
2971  *     error was set.
2972  *
2973  * Since: 2.14
2974  */
2975 gboolean
gdk_pixbuf_save_to_stream(GdkPixbuf * pixbuf,GOutputStream * stream,const char * type,GCancellable * cancellable,GError ** error,...)2976 gdk_pixbuf_save_to_stream (GdkPixbuf      *pixbuf,
2977                            GOutputStream  *stream,
2978                            const char     *type,
2979                            GCancellable   *cancellable,
2980                            GError        **error,
2981                            ...)
2982 {
2983         gboolean res;
2984         gchar **keys = NULL;
2985         gchar **values = NULL;
2986         va_list args;
2987 
2988         va_start (args, error);
2989         collect_save_options (args, &keys, &values);
2990         va_end (args);
2991 
2992         res = gdk_pixbuf_save_to_streamv (pixbuf, stream, type,
2993                                           keys, values,
2994                                           cancellable, error);
2995 
2996         g_strfreev (keys);
2997         g_strfreev (values);
2998 
2999         return res;
3000 }
3001 
3002 typedef struct {
3003 	GOutputStream *stream;
3004 	gchar *type;
3005 	gchar **keys;
3006 	gchar **values;
3007 } SaveToStreamAsyncData;
3008 
3009 static void
save_to_stream_async_data_free(SaveToStreamAsyncData * data)3010 save_to_stream_async_data_free (SaveToStreamAsyncData *data)
3011 {
3012 	if (data->stream)
3013 		g_object_unref (data->stream);
3014 	g_strfreev (data->keys);
3015 	g_strfreev (data->values);
3016 	g_free (data->type);
3017 	g_slice_free (SaveToStreamAsyncData, data);
3018 }
3019 
3020 static void
save_to_stream_thread(GTask * task,GdkPixbuf * pixbuf,SaveToStreamAsyncData * data,GCancellable * cancellable)3021 save_to_stream_thread (GTask                 *task,
3022 		       GdkPixbuf             *pixbuf,
3023 		       SaveToStreamAsyncData *data,
3024 		       GCancellable          *cancellable)
3025 {
3026 	SaveToStreamData sync_data;
3027 	gboolean retval;
3028 	GError *error = NULL;
3029 
3030 	sync_data.stream = data->stream;
3031 	sync_data.cancellable = cancellable;
3032 
3033 	retval = gdk_pixbuf_save_to_callbackv (pixbuf, save_to_stream,
3034 					       &sync_data, data->type,
3035 					       data->keys, data->values,
3036 					       &error);
3037 
3038 	if (retval == FALSE) {
3039 		g_task_return_error (task, error);
3040 	} else {
3041 		g_task_return_boolean (task, TRUE);
3042 	}
3043 }
3044 
3045 /**
3046  * gdk_pixbuf_save_to_streamv_async:
3047  * @pixbuf: a #GdkPixbuf
3048  * @stream: a #GOutputStream to which to save the pixbuf
3049  * @type: name of file format
3050  * @option_keys: (array zero-terminated=1): name of options to set, %NULL-terminated
3051  * @option_values: (array zero-terminated=1): values for named options
3052  * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore
3053  * @callback: a #GAsyncReadyCallback to call when the pixbuf is saved
3054  * @user_data: the data to pass to the callback function
3055  *
3056  * Saves @pixbuf to an output stream asynchronously.
3057  *
3058  * For more details see gdk_pixbuf_save_to_streamv(), which is the synchronous
3059  * version of this function.
3060  *
3061  * When the operation is finished, @callback will be called in the main thread.
3062  * You can then call gdk_pixbuf_save_to_stream_finish() to get the result of the operation.
3063  *
3064  * Since: 2.36
3065  **/
3066 void
gdk_pixbuf_save_to_streamv_async(GdkPixbuf * pixbuf,GOutputStream * stream,const gchar * type,gchar ** option_keys,gchar ** option_values,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)3067 gdk_pixbuf_save_to_streamv_async (GdkPixbuf           *pixbuf,
3068                                   GOutputStream       *stream,
3069                                   const gchar         *type,
3070                                   gchar              **option_keys,
3071                                   gchar              **option_values,
3072                                   GCancellable        *cancellable,
3073                                   GAsyncReadyCallback  callback,
3074                                   gpointer             user_data)
3075 {
3076         GTask *task;
3077         SaveToStreamAsyncData *data;
3078 
3079         g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
3080         g_return_if_fail (gdk_pixbuf_get_width (pixbuf) >= 0);
3081         g_return_if_fail (gdk_pixbuf_get_height (pixbuf) >= 0);
3082         g_return_if_fail (gdk_pixbuf_get_n_channels (pixbuf) >= 0);
3083         g_return_if_fail (G_IS_OUTPUT_STREAM (stream));
3084         g_return_if_fail (type != NULL);
3085         g_return_if_fail (callback != NULL);
3086         g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
3087 
3088         data = g_slice_new (SaveToStreamAsyncData);
3089         data->stream = g_object_ref (stream);
3090         data->type = g_strdup (type);
3091         data->keys = g_strdupv (option_keys);
3092         data->values = g_strdupv (option_values);
3093 
3094         task = g_task_new (pixbuf, cancellable, callback, user_data);
3095         g_task_set_source_tag (task, gdk_pixbuf_save_to_streamv_async);
3096         g_task_set_task_data (task, data, (GDestroyNotify) save_to_stream_async_data_free);
3097         g_task_run_in_thread (task, (GTaskThreadFunc) save_to_stream_thread);
3098         g_object_unref (task);
3099 }
3100 
3101 /**
3102  * gdk_pixbuf_save_to_stream_async:
3103  * @pixbuf: a #GdkPixbuf
3104  * @stream: a #GOutputStream to which to save the pixbuf
3105  * @type: name of file format
3106  * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore
3107  * @callback: a #GAsyncReadyCallback to call when the pixbuf is saved
3108  * @user_data: the data to pass to the callback function
3109  * @...: list of key-value save options
3110  *
3111  * Saves @pixbuf to an output stream asynchronously.
3112  *
3113  * For more details see gdk_pixbuf_save_to_stream(), which is the synchronous
3114  * version of this function.
3115  *
3116  * When the operation is finished, @callback will be called in the main thread.
3117  * You can then call gdk_pixbuf_save_to_stream_finish() to get the result of the operation.
3118  *
3119  * Since: 2.24
3120  **/
3121 void
gdk_pixbuf_save_to_stream_async(GdkPixbuf * pixbuf,GOutputStream * stream,const gchar * type,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data,...)3122 gdk_pixbuf_save_to_stream_async (GdkPixbuf           *pixbuf,
3123 				 GOutputStream       *stream,
3124 				 const gchar         *type,
3125 				 GCancellable        *cancellable,
3126 				 GAsyncReadyCallback  callback,
3127 				 gpointer             user_data,
3128 				 ...)
3129 {
3130         gchar **keys = NULL;
3131         gchar **values = NULL;
3132         va_list args;
3133 
3134         g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
3135         g_return_if_fail (gdk_pixbuf_get_width (pixbuf) >= 0);
3136         g_return_if_fail (gdk_pixbuf_get_height (pixbuf) >= 0);
3137         g_return_if_fail (gdk_pixbuf_get_n_channels (pixbuf) >= 0);
3138         g_return_if_fail (G_IS_OUTPUT_STREAM (stream));
3139         g_return_if_fail (type != NULL);
3140         g_return_if_fail (callback != NULL);
3141         g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
3142 
3143         va_start (args, user_data);
3144         collect_save_options (args, &keys, &values);
3145         va_end (args);
3146 
3147         gdk_pixbuf_save_to_streamv_async (pixbuf, stream, type,
3148                                           keys, values,
3149                                           cancellable, callback, user_data);
3150         g_strfreev (keys);
3151         g_strfreev (values);
3152 }
3153 
3154 /**
3155  * gdk_pixbuf_save_to_stream_finish:
3156  * @async_result: a #GAsyncResult
3157  * @error: a #GError, or %NULL
3158  *
3159  * Finishes an asynchronous pixbuf save operation started with
3160  * gdk_pixbuf_save_to_stream_async().
3161  *
3162  * Return value: %TRUE if the pixbuf was saved successfully, %FALSE if an error was set.
3163  *
3164  * Since: 2.24
3165  **/
3166 gboolean
gdk_pixbuf_save_to_stream_finish(GAsyncResult * async_result,GError ** error)3167 gdk_pixbuf_save_to_stream_finish (GAsyncResult  *async_result,
3168 				  GError       **error)
3169 {
3170 	GTask *task;
3171 
3172 	/* Can not use g_task_is_valid because our GTask has a
3173 	 * source_object which is not available to us anymore.
3174 	 */
3175 	g_return_val_if_fail (G_IS_TASK (async_result), FALSE);
3176 
3177 	task = G_TASK (async_result);
3178 
3179 	g_return_val_if_fail (!error || (error && !*error), FALSE);
3180 	g_warn_if_fail (g_task_get_source_tag (task) == gdk_pixbuf_save_to_stream_async ||
3181 			g_task_get_source_tag (task) == gdk_pixbuf_save_to_streamv_async);
3182 
3183 	return g_task_propagate_boolean (task, error);
3184 }
3185 
3186 /**
3187  * gdk_pixbuf_format_get_name:
3188  * @format: a #GdkPixbufFormat
3189  *
3190  * Returns the name of the format.
3191  *
3192  * Return value: the name of the format.
3193  *
3194  * Since: 2.2
3195  */
3196 gchar *
gdk_pixbuf_format_get_name(GdkPixbufFormat * format)3197 gdk_pixbuf_format_get_name (GdkPixbufFormat *format)
3198 {
3199         g_return_val_if_fail (format != NULL, NULL);
3200 
3201         return g_strdup (format->name);
3202 }
3203 
3204 /**
3205  * gdk_pixbuf_format_get_description:
3206  * @format: a #GdkPixbufFormat
3207  *
3208  * Returns a description of the format.
3209  *
3210  * Return value: a description of the format.
3211  *
3212  * Since: 2.2
3213  */
3214 gchar *
gdk_pixbuf_format_get_description(GdkPixbufFormat * format)3215 gdk_pixbuf_format_get_description (GdkPixbufFormat *format)
3216 {
3217         gchar *domain;
3218         const gchar *description;
3219         g_return_val_if_fail (format != NULL, NULL);
3220 
3221         if (format->domain != NULL)
3222                 domain = format->domain;
3223         else
3224                 domain = GETTEXT_PACKAGE;
3225         description = g_dgettext (domain, format->description);
3226 
3227         return g_strdup (description);
3228 }
3229 
3230 /**
3231  * gdk_pixbuf_format_get_mime_types:
3232  * @format: a #GdkPixbufFormat
3233  *
3234  * Returns the mime types supported by the format.
3235  *
3236  * Return value: (transfer full): a %NULL-terminated array of mime types which must be freed with
3237  * g_strfreev() when it is no longer needed.
3238  *
3239  * Since: 2.2
3240  */
3241 gchar **
gdk_pixbuf_format_get_mime_types(GdkPixbufFormat * format)3242 gdk_pixbuf_format_get_mime_types (GdkPixbufFormat *format)
3243 {
3244         g_return_val_if_fail (format != NULL, NULL);
3245 
3246         return g_strdupv (format->mime_types);
3247 }
3248 
3249 /**
3250  * gdk_pixbuf_format_get_extensions:
3251  * @format: a #GdkPixbufFormat
3252  *
3253  * Returns the filename extensions typically used for files in the
3254  * given format.
3255  *
3256  * Return value: (transfer full): a %NULL-terminated array of filename extensions which must be
3257  * freed with g_strfreev() when it is no longer needed.
3258  *
3259  * Since: 2.2
3260  */
3261 gchar **
gdk_pixbuf_format_get_extensions(GdkPixbufFormat * format)3262 gdk_pixbuf_format_get_extensions (GdkPixbufFormat *format)
3263 {
3264         g_return_val_if_fail (format != NULL, NULL);
3265 
3266         return g_strdupv (format->extensions);
3267 }
3268 
3269 /**
3270  * gdk_pixbuf_format_is_writable:
3271  * @format: a #GdkPixbufFormat
3272  *
3273  * Returns whether pixbufs can be saved in the given format.
3274  *
3275  * Return value: whether pixbufs can be saved in the given format.
3276  *
3277  * Since: 2.2
3278  */
3279 gboolean
gdk_pixbuf_format_is_writable(GdkPixbufFormat * format)3280 gdk_pixbuf_format_is_writable (GdkPixbufFormat *format)
3281 {
3282         g_return_val_if_fail (format != NULL, FALSE);
3283 
3284         return (format->flags & GDK_PIXBUF_FORMAT_WRITABLE) != 0;
3285 }
3286 
3287 /**
3288  * gdk_pixbuf_format_is_scalable:
3289  * @format: a #GdkPixbufFormat
3290  *
3291  * Returns whether this image format is scalable. If a file is in a
3292  * scalable format, it is preferable to load it at the desired size,
3293  * rather than loading it at the default size and scaling the
3294  * resulting pixbuf to the desired size.
3295  *
3296  * Return value: whether this image format is scalable.
3297  *
3298  * Since: 2.6
3299  */
3300 gboolean
gdk_pixbuf_format_is_scalable(GdkPixbufFormat * format)3301 gdk_pixbuf_format_is_scalable (GdkPixbufFormat *format)
3302 {
3303         g_return_val_if_fail (format != NULL, FALSE);
3304 
3305         return (format->flags & GDK_PIXBUF_FORMAT_SCALABLE) != 0;
3306 }
3307 
3308 /**
3309  * gdk_pixbuf_format_is_disabled:
3310  * @format: a #GdkPixbufFormat
3311  *
3312  * Returns whether this image format is disabled. See
3313  * gdk_pixbuf_format_set_disabled().
3314  *
3315  * Return value: whether this image format is disabled.
3316  *
3317  * Since: 2.6
3318  */
3319 gboolean
gdk_pixbuf_format_is_disabled(GdkPixbufFormat * format)3320 gdk_pixbuf_format_is_disabled (GdkPixbufFormat *format)
3321 {
3322         g_return_val_if_fail (format != NULL, FALSE);
3323 
3324         return format->disabled;
3325 }
3326 
3327 /**
3328  * gdk_pixbuf_format_set_disabled:
3329  * @format: a #GdkPixbufFormat
3330  * @disabled: %TRUE to disable the format @format
3331  *
3332  * Disables or enables an image format. If a format is disabled,
3333  * gdk-pixbuf won't use the image loader for this format to load
3334  * images. Applications can use this to avoid using image loaders
3335  * with an inappropriate license, see gdk_pixbuf_format_get_license().
3336  *
3337  * Since: 2.6
3338  */
3339 void
gdk_pixbuf_format_set_disabled(GdkPixbufFormat * format,gboolean disabled)3340 gdk_pixbuf_format_set_disabled (GdkPixbufFormat *format,
3341                                 gboolean         disabled)
3342 {
3343         g_return_if_fail (format != NULL);
3344 
3345         format->disabled = disabled != FALSE;
3346 }
3347 
3348 /**
3349  * gdk_pixbuf_format_get_license:
3350  * @format: a #GdkPixbufFormat
3351  *
3352  * Returns information about the license of the image loader for the format. The
3353  * returned string should be a shorthand for a wellknown license, e.g. "LGPL",
3354  * "GPL", "QPL", "GPL/QPL", or "other" to indicate some other license.  This
3355  * string should be freed with g_free() when it's no longer needed.
3356  *
3357  * Returns: a string describing the license of @format.
3358  *
3359  * Since: 2.6
3360  */
3361 gchar*
gdk_pixbuf_format_get_license(GdkPixbufFormat * format)3362 gdk_pixbuf_format_get_license (GdkPixbufFormat *format)
3363 {
3364         g_return_val_if_fail (format != NULL, NULL);
3365 
3366         return g_strdup (format->license);
3367 }
3368 
3369 GdkPixbufFormat *
_gdk_pixbuf_get_format(GdkPixbufModule * module)3370 _gdk_pixbuf_get_format (GdkPixbufModule *module)
3371 {
3372         g_return_val_if_fail (module != NULL, NULL);
3373 
3374         return module->info;
3375 }
3376 
3377 /**
3378  * gdk_pixbuf_get_formats:
3379  *
3380  * Obtains the available information about the image formats supported
3381  * by GdkPixbuf.
3382  *
3383  * Returns: (transfer container) (element-type GdkPixbufFormat): A list of
3384  * #GdkPixbufFormats describing the supported image formats. The list should
3385  * be freed when it is no longer needed, but the structures themselves are
3386  * owned by #GdkPixbuf and should not be freed.
3387  *
3388  * Since: 2.2
3389  */
3390 GSList *
gdk_pixbuf_get_formats(void)3391 gdk_pixbuf_get_formats (void)
3392 {
3393         GSList *result = NULL;
3394         GSList *modules;
3395 
3396         for (modules = get_file_formats (); modules; modules = g_slist_next (modules)) {
3397                 GdkPixbufModule *module = (GdkPixbufModule *)modules->data;
3398                 GdkPixbufFormat *info = _gdk_pixbuf_get_format (module);
3399                 result = g_slist_prepend (result, info);
3400         }
3401 
3402         return result;
3403 }
3404 
3405 /**
3406  * gdk_pixbuf_format_copy:
3407  * @format: a #GdkPixbufFormat
3408  *
3409  * Creates a copy of @format
3410  *
3411  * Return value: the newly allocated copy of a #GdkPixbufFormat. Use
3412  *   gdk_pixbuf_format_free() to free the resources when done
3413  *
3414  * Since: 2.22
3415  */
3416 GdkPixbufFormat *
gdk_pixbuf_format_copy(const GdkPixbufFormat * format)3417 gdk_pixbuf_format_copy (const GdkPixbufFormat *format)
3418 {
3419         if (G_LIKELY (format != NULL))
3420                 return g_slice_dup (GdkPixbufFormat, format);
3421 
3422         return NULL;
3423 }
3424 
3425 /**
3426  * gdk_pixbuf_format_free:
3427  * @format: a #GdkPixbufFormat
3428  *
3429  * Frees the resources allocated when copying a #GdkPixbufFormat
3430  * using gdk_pixbuf_format_copy()
3431  *
3432  * Since: 2.22
3433  */
3434 void
gdk_pixbuf_format_free(GdkPixbufFormat * format)3435 gdk_pixbuf_format_free (GdkPixbufFormat *format)
3436 {
3437         if (G_LIKELY (format != NULL))
3438                 g_slice_free (GdkPixbufFormat, format);
3439 }
3440 
3441 /**
3442  * gdk_pixbuf_format_is_save_option_supported:
3443  * @format: a #GdkPixbufFormat
3444  * @option_key: the name of an option
3445  *
3446  * Returns %TRUE if the save option specified by @option_key is supported when
3447  * saving a pixbuf using the module implementing @format.
3448  * See gdk_pixbuf_save() for more information about option keys.
3449  *
3450  * Returns: %TRUE if the specified option is supported
3451  *
3452  * Since: 2.36
3453  */
3454 gboolean
gdk_pixbuf_format_is_save_option_supported(GdkPixbufFormat * format,const gchar * option_key)3455 gdk_pixbuf_format_is_save_option_supported (GdkPixbufFormat *format,
3456                                             const gchar *option_key)
3457 {
3458         GdkPixbufModule *module;
3459 
3460         g_return_val_if_fail (format != NULL, FALSE);
3461         g_return_val_if_fail (option_key != NULL, FALSE);
3462 
3463         module = _gdk_pixbuf_get_named_module (format->name, NULL);
3464         if (!module)
3465                 return FALSE;
3466 
3467         if (!_gdk_pixbuf_load_module (module, NULL))
3468                 return FALSE;
3469 
3470         if (!module->is_save_option_supported)
3471                 return FALSE;
3472 
3473         return (* module->is_save_option_supported) (option_key);
3474 }
3475 
3476 G_DEFINE_BOXED_TYPE (GdkPixbufFormat, gdk_pixbuf_format,
3477 		     gdk_pixbuf_format_copy,
3478 		     gdk_pixbuf_format_free)
3479