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

source code of gtk/subprojects/gdk-pixbuf/gdk-pixbuf/gdk-pixbuf-io.c