1 /* GdkPixbuf library - Main loading interface.
3 * Copyright (C) 1999 The Free Software Foundation
5 * Authors: Miguel de Icaza <miguel@gnu.org>
6 * Federico Mena-Quintero <federico@gimp.org>
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.
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.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
28 #include "gdk-pixbuf-private.h"
29 #include "gdk-pixbuf-io.h"
34 pixbuf_check_png (guchar *buffer, int size)
39 if (buffer [0] != 0x89 ||
53 pixbuf_check_jpeg (guchar *buffer, int size)
58 if (buffer [0] != 0xff || buffer [1] != 0xd8)
65 pixbuf_check_tiff (guchar *buffer, int size)
70 if (buffer [0] == 'M' &&
76 if (buffer [0] == 'I' &&
86 pixbuf_check_gif (guchar *buffer, int size)
91 if (strncmp (buffer, "GIF8", 4) == 0)
98 pixbuf_check_xpm (guchar *buffer, int size)
103 if (strncmp (buffer, "/* XPM */", 9) == 0)
110 pixbuf_check_pnm (guchar *buffer, int size)
115 if (buffer [0] == 'P') {
116 if (buffer [1] == '1' ||
127 pixbuf_check_sunras (guchar *buffer, int size)
132 if (buffer [0] != 0x59 ||
133 buffer [1] != 0xA6 ||
134 buffer [2] != 0x6A ||
142 pixbuf_check_ico (guchar *buffer, int size)
144 /* Note that this may cause false positives, but .ico's don't
145 have a magic number.*/
148 if (buffer [0] != 0x0 ||
150 ((buffer [2] != 0x1)&&(buffer[2]!=0x2)) ||
160 pixbuf_check_bmp (guchar *buffer, int size)
165 if (buffer [0] != 'B' || buffer [1] != 'M')
172 pixbuf_check_wbmp (guchar *buffer, int size)
174 if(size < 10) /* at least */
177 if(buffer[0] == '\0' /* We only handle type 0 wbmp's for now */)
185 pixbuf_check_xbm (guchar *buffer, int size)
190 if (buffer [0] != '#'
197 || buffer [7] != ' ')
203 static GdkPixbufModule file_formats [] = {
204 { "png", pixbuf_check_png, NULL, NULL, NULL, NULL, NULL, NULL, NULL, },
205 { "jpeg", pixbuf_check_jpeg, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
206 { "tiff", pixbuf_check_tiff, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
207 { "gif", pixbuf_check_gif, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
208 #define XPM_FILE_FORMAT_INDEX 4
209 { "xpm", pixbuf_check_xpm, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
210 { "pnm", pixbuf_check_pnm, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
211 { "ras", pixbuf_check_sunras, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
212 { "ico", pixbuf_check_ico, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
213 { "bmp", pixbuf_check_bmp, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
214 { "wbmp", pixbuf_check_wbmp, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
215 { "xbm", pixbuf_check_xbm, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
216 { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
221 pixbuf_module_symbol (GModule *module, const char *module_name, const char *symbol_name, gpointer *symbol)
223 char *full_symbol_name = g_strconcat ("gdk_pixbuf__", module_name, "_", symbol_name, NULL);
224 gboolean return_value;
226 return_value = g_module_symbol (module, full_symbol_name, symbol);
227 g_free (full_symbol_name);
237 static char *libdir = NULL;
240 libdir = g_win32_get_package_installation_subdirectory
242 g_strdup_printf ("gdk_pixbug-%d.%d.dll",
243 GDK_PIXBUF_MAJOR, GDK_PIXBUF_MINOR),
249 #define PIXBUF_LIBDIR get_libdir ()
253 /* actually load the image handler - gdk_pixbuf_get_module only get a */
254 /* reference to the module to load, it doesn't actually load it */
255 /* perhaps these actions should be combined in one function */
257 gdk_pixbuf_load_module (GdkPixbufModule *image_module,
268 g_return_val_if_fail (image_module->module == NULL, FALSE);
270 name = image_module->module_name;
272 module_name = g_strconcat ("pixbufloader-", name, NULL);
274 /* This would be an exploit in an suid binary using gdk-pixbuf,
275 * but see http://www.gtk.org/setuid.html or the BugTraq
276 * archives for why you should report this as a bug against
277 * setuid apps using this library rather than the library
280 dir = g_getenv ("GDK_PIXBUF_MODULEDIR");
282 if (dir == NULL || *dir == '\0') {
284 path = g_module_build_path (PIXBUF_LIBDIR, module_name);
285 module = g_module_open (path, G_MODULE_BIND_LAZY);
287 path = g_module_build_path (dir, module_name);
288 module = g_module_open (path, G_MODULE_BIND_LAZY);
294 GDK_PIXBUF_ERROR_FAILED,
295 _("Unable to load image-loading module: %s: %s"),
296 path, g_module_error ());
297 g_free (module_name);
302 g_free (module_name);
304 image_module->module = module;
306 if (pixbuf_module_symbol (module, name, "fill_vtable", &sym)) {
307 ModuleFillVtableFunc func = sym;
308 (* func) (image_module);
313 GDK_PIXBUF_ERROR_FAILED,
314 _("Image-loading module %s does not export the proper interface; perhaps it's from a different GTK version?"),
325 #define mname(type,fn) gdk_pixbuf__ ## type ## _ ##fn
326 #define m_fill_vtable(type) extern void mname(type,fill_vtable) (GdkPixbufModule *module)
330 m_fill_vtable (wbmp);
333 m_fill_vtable (jpeg);
336 m_fill_vtable (tiff);
341 gdk_pixbuf_load_module (GdkPixbufModule *image_module,
344 ModuleFillVtableFunc fill_vtable = NULL;
345 image_module->module = (void *) 1;
348 /* Ugly hack so we can use else if unconditionally below ;-) */
352 else if (strcmp (image_module->module_name, "png") == 0){
353 fill_vtable = mname (png, fill_vtable);
358 else if (strcmp (image_module->module_name, "bmp") == 0){
359 fill_vtable = mname (bmp, fill_vtable);
364 else if (strcmp (image_module->module_name, "wbmp") == 0){
365 fill_vtable = mname (wbmp, fill_vtable);
370 else if (strcmp (image_module->module_name, "gif") == 0){
371 fill_vtable = mname (gif, fill_vtable);
376 else if (strcmp (image_module->module_name, "ico") == 0){
377 fill_vtable = mname (ico, fill_vtable);
382 else if (strcmp (image_module->module_name, "jpeg") == 0){
383 fill_vtable = mname (jpeg, fill_vtable);
388 else if (strcmp (image_module->module_name, "pnm") == 0){
389 fill_vtable = mname (pnm, fill_vtable);
394 else if (strcmp (image_module->module_name, "ras") == 0){
395 fill_vtable = mname (ras, fill_vtable);
400 else if (strcmp (image_module->module_name, "tiff") == 0){
401 fill_vtable = mname (tiff, fill_vtable);
406 else if (strcmp (image_module->module_name, "xpm") == 0){
407 fill_vtable = mname (xpm, fill_vtable);
412 else if (strcmp (image_module->module_name, "xbm") == 0){
413 fill_vtable = mname (xbm, fill_vtable);
419 (* fill_vtable) (image_module);
424 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
425 _("Image type '%s' is not supported"),
426 image_module->module_name);
438 gdk_pixbuf_get_named_module (const char *name,
443 for (i = 0; file_formats [i].module_name; i++) {
444 if (!strcmp(name, file_formats[i].module_name))
445 return &(file_formats[i]);
450 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
451 _("Image type '%s' is not supported"),
458 gdk_pixbuf_get_module (guchar *buffer, guint size,
459 const gchar *filename,
464 for (i = 0; file_formats [i].module_name; i++) {
465 if ((* file_formats [i].format_check) (buffer, size))
466 return &(file_formats[i]);
472 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
473 _("Couldn't recognize the image file format for file '%s'"),
478 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
479 _("Unrecognized image file format"));
486 * gdk_pixbuf_new_from_file:
487 * @filename: Name of file to load.
488 * @error: Return location for an error
490 * Creates a new pixbuf by loading an image from a file. The file format is
491 * detected automatically. If NULL is returned, then @error will be set.
492 * Possible errors are in the #GDK_PIXBUF_ERROR and #G_FILE_ERROR domains.
494 * Return value: A newly-created pixbuf with a reference count of 1, or NULL if
495 * any of several error conditions occurred: the file could not be opened,
496 * there was no loader for the file's format, there was not enough memory to
497 * allocate the image buffer, or the image file contained invalid data.
500 gdk_pixbuf_new_from_file (const char *filename,
507 GdkPixbufModule *image_module;
509 g_return_val_if_fail (filename != NULL, NULL);
511 f = fopen (filename, "rb");
515 g_file_error_from_errno (errno),
516 _("Failed to open file '%s': %s"),
517 filename, g_strerror (errno));
521 size = fread (&buffer, 1, sizeof (buffer), f);
525 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
526 _("Image file '%s' contains no data"),
533 image_module = gdk_pixbuf_get_module (buffer, size, filename, error);
534 if (image_module == NULL) {
539 if (image_module->module == NULL)
540 if (!gdk_pixbuf_load_module (image_module, error)) {
545 if (image_module->load == NULL) {
548 GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
549 _("Don't know how to load the image in file '%s'"),
556 fseek (f, 0, SEEK_SET);
557 pixbuf = (* image_module->load) (f, error);
560 if (pixbuf == NULL && error != NULL && *error == NULL) {
561 /* I don't trust these crufty longjmp()'ing image libs
562 * to maintain proper error invariants, and I don't
563 * want user code to segfault as a result. We need to maintain
564 * the invariant that error gets set if NULL is returned.
567 g_warning ("Bug! gdk-pixbuf loader '%s' didn't set an error on failure.", image_module->module_name);
570 GDK_PIXBUF_ERROR_FAILED,
571 _("Failed to load image '%s': reason not known, probably a corrupt image file"),
574 } else if (error != NULL && *error != NULL) {
576 /* Add the filename to the error message */
582 e->message = g_strdup_printf (_("Failed to load image '%s': %s"),
592 * gdk_pixbuf_new_from_xpm_data:
593 * @data: Pointer to inline XPM data.
595 * Creates a new pixbuf by parsing XPM data in memory. This data is commonly
596 * the result of including an XPM file into a program's C source.
598 * Return value: A newly-created pixbuf with a reference count of 1.
601 gdk_pixbuf_new_from_xpm_data (const char **data)
603 GdkPixbuf *(* load_xpm_data) (const char **data);
605 GError *error = NULL;
607 if (file_formats[XPM_FILE_FORMAT_INDEX].module == NULL) {
608 if (!gdk_pixbuf_load_module (&file_formats[XPM_FILE_FORMAT_INDEX], &error)) {
609 g_warning ("Error loading XPM image loader: %s", error->message);
610 g_error_free (error);
615 if (file_formats[XPM_FILE_FORMAT_INDEX].module == NULL) {
616 g_warning ("Can't find gdk-pixbuf module for parsing inline XPM data");
618 } else if (file_formats[XPM_FILE_FORMAT_INDEX].load_xpm_data == NULL) {
619 g_warning ("gdk-pixbuf XPM module lacks XPM data capability");
622 load_xpm_data = file_formats[XPM_FILE_FORMAT_INDEX].load_xpm_data;
624 pixbuf = (* load_xpm_data) (data);
629 collect_save_options (va_list opts,
642 next = va_arg (opts, gchar*);
646 val = va_arg (opts, gchar*);
651 *keys = g_realloc (*keys, sizeof(gchar*) * (count + 1));
652 *vals = g_realloc (*vals, sizeof(gchar*) * (count + 1));
654 (*keys)[count-1] = g_strdup (key);
655 (*vals)[count-1] = g_strdup (val);
657 (*keys)[count] = NULL;
658 (*vals)[count] = NULL;
660 next = va_arg (opts, gchar*);
665 gdk_pixbuf_real_save (GdkPixbuf *pixbuf,
672 GdkPixbufModule *image_module = NULL;
674 image_module = gdk_pixbuf_get_named_module (type, error);
676 if (image_module == NULL)
679 if (image_module->module == NULL)
680 if (!gdk_pixbuf_load_module (image_module, error))
683 if (image_module->save == NULL) {
686 GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
687 _("This build of gdk-pixbuf does not support saving the image format: %s"),
692 return (* image_module->save) (filehandle, pixbuf,
700 * @pixbuf: pointer to GdkPixbuf.
701 * @filename: Name of file to save.
702 * @type: name of file format.
703 * @error: return location for error, or NULL
704 * @Varargs: list of key-value save options
706 * Saves pixbuf to a file in @type, which is currently "jpeg" or
707 * "png". If @error is set, FALSE will be returned. Possible errors include those
708 * in the #GDK_PIXBUF_ERROR domain and those in the #G_FILE_ERROR domain.
710 * The variable argument list should be NULL-terminated; if not empty,
711 * it should contain pairs of strings that modify the save
712 * parameters. For example:
715 * gdk_pixbuf_save (pixbuf, handle, "jpeg", &error,
716 * "quality", "100", NULL);
719 * The only save parameter that currently exists is the "quality" field
720 * for JPEG images; its value should be in the range [0,100].
722 * Return value: whether an error was set
726 gdk_pixbuf_save (GdkPixbuf *pixbuf,
727 const char *filename,
733 gchar **values = NULL;
737 va_start (args, error);
739 collect_save_options (args, &keys, &values);
743 result = gdk_pixbuf_savev (pixbuf, filename, type,
755 * @pixbuf: pointer to GdkPixbuf.
756 * @filename: Name of file to save.
757 * @type: name of file format.
758 * @option_keys: name of options to set, NULL-terminated
759 * @option_values: values for named options
760 * @error: return location for error, or NULL
762 * Saves pixbuf to a file in @type, which is currently "jpeg" or "png".
763 * If @error is set, FALSE will be returned. See gdk_pixbuf_save () for more
766 * Return value: whether an error was set
770 gdk_pixbuf_savev (GdkPixbuf *pixbuf,
771 const char *filename,
774 char **option_values,
781 g_return_val_if_fail (filename != NULL, FALSE);
782 g_return_val_if_fail (type != NULL, FALSE);
784 f = fopen (filename, "wb");
789 g_file_error_from_errno (errno),
790 _("Failed to open '%s' for writing: %s"),
791 filename, g_strerror (errno));
796 result = gdk_pixbuf_real_save (pixbuf, f, type,
797 option_keys, option_values,
802 g_return_val_if_fail (error == NULL || *error != NULL, FALSE);
807 if (fclose (f) < 0) {
810 g_file_error_from_errno (errno),
811 _("Failed to close '%s' while writing image, all data may not have been saved: %s"),
812 filename, g_strerror (errno));