gdk-pixbuf-io.c 8.34 KB
Newer Older
1
/* GdkPixbuf library - Main loading interface.
Arturo Espinosa's avatar
Arturo Espinosa committed
2
 *
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 * Copyright (C) 1999 The Free Software Foundation
 *
 * Authors: Miguel de Icaza <miguel@gnu.org>
 *          Federico Mena-Quintero <federico@gimp.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
Arturo Espinosa's avatar
Arturo Espinosa committed
22
 */
23

Arturo Espinosa's avatar
Arturo Espinosa committed
24
#include <config.h>
25
#include <string.h>
26
#include <glib.h>
27
#include "gdk-pixbuf-io.h"
Arturo Espinosa's avatar
Arturo Espinosa committed
28

29 30


31
static gboolean
32
pixbuf_check_png (guchar *buffer, int size)
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
{
	if (size < 28)
		return FALSE;

	if (buffer [0] != 0x89 ||
	    buffer [1] != 'P' ||
	    buffer [2] != 'N' ||
	    buffer [3] != 'G' ||
	    buffer [4] != 0x0d ||
	    buffer [5] != 0x0a ||
	    buffer [6] != 0x1a ||
	    buffer [7] != 0x0a)
		return FALSE;

	return TRUE;
}

static gboolean
51
pixbuf_check_jpeg (guchar *buffer, int size)
52 53 54 55 56 57
{
	if (size < 10)
		return FALSE;

	if (buffer [0] != 0xff || buffer [1] != 0xd8)
		return FALSE;
58

59 60 61 62
	return TRUE;
}

static gboolean
63
pixbuf_check_tiff (guchar *buffer, int size)
64 65 66 67
{
	if (size < 10)
		return FALSE;

68 69 70
	if (buffer [0] == 'M' &&
	    buffer [1] == 'M' &&
	    buffer [2] == 0   &&
Mark Crichton's avatar
Mark Crichton committed
71
	    buffer [3] == 0x2a)
72 73
		return TRUE;

74 75 76
	if (buffer [0] == 'I' &&
	    buffer [1] == 'I' &&
	    buffer [2] == 0x2a &&
Mark Crichton's avatar
Mark Crichton committed
77
	    buffer [3] == 0)
78
		return TRUE;
79

80 81 82 83
	return FALSE;
}

static gboolean
84
pixbuf_check_gif (guchar *buffer, int size)
85 86 87
{
	if (size < 20)
		return FALSE;
88

89 90
	if (strncmp (buffer, "GIF8", 4) == 0)
		return TRUE;
91

92 93 94 95
	return FALSE;
}

static gboolean
96
pixbuf_check_xpm (guchar *buffer, int size)
97 98 99
{
	if (size < 20)
		return FALSE;
100

101 102
	if (strncmp (buffer, "/* XPM */", 9) == 0)
		return TRUE;
103

104 105 106 107
	return FALSE;
}

static gboolean
108
pixbuf_check_pnm (guchar *buffer, int size)
109 110 111 112
{
	if (size < 20)
		return FALSE;

113
	if (buffer [0] == 'P') {
114 115 116 117 118 119 120 121 122 123
		if (buffer [1] == '1' ||
		    buffer [1] == '2' ||
		    buffer [1] == '3' ||
		    buffer [1] == '4' ||
		    buffer [1] == '5' ||
		    buffer [1] == '6')
			return TRUE;
	}
	return FALSE;
}
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
static gboolean
pixbuf_check_sunras (guchar *buffer, int size)
{
	if (size < 32)
		return FALSE;

	if (buffer [0] != 0x59 ||
	    buffer [1] != 0xA6 ||
	    buffer [2] != 0x6A ||
	    buffer [3] != 0x95)
		return FALSE;

	return TRUE;
}

139 140 141 142 143 144 145 146 147
static gboolean
pixbuf_check_ico (guchar *buffer, int size)
{
	/* Note that this may cause false positives, but .ico's don't
	   have a magic number.*/
	if (size < 6)
		return FALSE;
	if (buffer [0] != 0x0 ||
	    buffer [1] != 0x0 ||
148
	    ((buffer [2] != 0x1)&&(buffer[2]!=0x2)) ||
149 150 151 152 153 154 155
	    buffer [3] != 0x0 ||
	    buffer [5] != 0x0 )
		return FALSE;

	return TRUE;
}

156 157 158 159 160 161 162 163 164 165 166 167 168

static gboolean
pixbuf_check_bmp (guchar *buffer, int size)
{
	if (size < 20)
		return FALSE;

	if (buffer [0] != 'B' || buffer [1] != 'M')
		return FALSE;

	return TRUE;
}

169

170
GdkPixbufModule file_formats [] = {
171 172 173 174
	{ "png",  pixbuf_check_png, NULL,  NULL, NULL, NULL, NULL, NULL },
	{ "jpeg", pixbuf_check_jpeg, NULL, NULL, NULL, NULL, NULL, NULL },
	{ "tiff", pixbuf_check_tiff, NULL, NULL, NULL, NULL, NULL, NULL },
	{ "gif",  pixbuf_check_gif, NULL,  NULL, NULL, NULL, NULL, NULL },
175
#define XPM_FILE_FORMAT_INDEX 4
176
	{ "xpm",  pixbuf_check_xpm, NULL,  NULL, NULL, NULL, NULL, NULL },
177
	{ "pnm",  pixbuf_check_pnm, NULL,  NULL, NULL, NULL, NULL, NULL },
178
	{ "ras",  pixbuf_check_sunras, NULL,  NULL, NULL, NULL, NULL, NULL },
179
	{ "ico",  pixbuf_check_ico, NULL,  NULL, NULL, NULL, NULL, NULL },
180
	{ "bmp",  pixbuf_check_bmp, NULL,  NULL, NULL, NULL, NULL, NULL },
181
	{ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
Arturo Espinosa's avatar
Arturo Espinosa committed
182 183
};

184 185 186 187 188 189

/* actually load the image handler - gdk_pixbuf_get_module only get a */
/* reference to the module to load, it doesn't actually load it       */
/* perhaps these actions should be combined in one function           */
void
gdk_pixbuf_load_module (GdkPixbufModule *image_module)
Arturo Espinosa's avatar
Arturo Espinosa committed
190
{
Mark Crichton's avatar
Mark Crichton committed
191
	char *module_name;
192 193
	char *path;
	GModule *module;
194
	gpointer load_sym;
195

196
        g_return_if_fail (image_module->module == NULL);
197 198

	module_name = g_strconcat ("pixbuf-", image_module->module_name, NULL);
199
	path = g_module_build_path (PIXBUF_LIBDIR, module_name);
200

201
	module = g_module_open (path, G_MODULE_BIND_LAZY);
202
	if (!module) {
203
                /* Debug feature, check in present working directory */
204 205 206
                g_free (path);
                path = g_module_build_path ("", module_name);
                module = g_module_open (path, G_MODULE_BIND_LAZY);
207 208

                if (!module) {
209
                        g_warning ("Unable to load module: %s: %s", path, g_module_error ());
210
                        g_free (module_name);
211
                        g_free (path);
212 213
                        return;
                }
214
                g_free (path);
215 216 217 218 219
	} else {
                g_free (path);
        }

        g_free (module_name);
220

221
	image_module->module = module;
222 223

	if (g_module_symbol (module, "image_load", &load_sym))
224
		image_module->load = load_sym;
225 226

        if (g_module_symbol (module, "image_load_xpm_data", &load_sym))
227
		image_module->load_xpm_data = load_sym;
228 229 230 231 232 233 234 235 236

        if (g_module_symbol (module, "image_begin_load", &load_sym))
		image_module->begin_load = load_sym;

        if (g_module_symbol (module, "image_stop_load", &load_sym))
		image_module->stop_load = load_sym;

        if (g_module_symbol (module, "image_load_increment", &load_sym))
		image_module->load_increment = load_sym;
237 238 239

        if (g_module_symbol (module, "image_load_animation", &load_sym))
		image_module->load_animation = load_sym;
Arturo Espinosa's avatar
Arturo Espinosa committed
240 241
}

242 243


244
GdkPixbufModule *
245
gdk_pixbuf_get_module (guchar *buffer, guint size)
246
{
247
	int i;
248 249 250 251 252

	for (i = 0; file_formats [i].module_name; i++) {
		if ((* file_formats [i].format_check) (buffer, size))
			return &(file_formats[i]);
	}
253

254 255 256
	return NULL;
}

Federico Mena Quintero's avatar
Federico Mena Quintero committed
257 258 259
/**
 * gdk_pixbuf_new_from_file:
 * @filename: Name of file to load.
260
 *
Federico Mena Quintero's avatar
Federico Mena Quintero committed
261 262
 * Creates a new pixbuf by loading an image from a file.  The file format is
 * detected automatically.
263 264 265 266 267
 *
 * Return value: A newly-created pixbuf with a reference count of 1, or NULL if
 * any of several error conditions occurred:  the file could not be opened,
 * there was no loader for the file's format, there was not enough memory to
 * allocate the image buffer, or the image file contained invalid data.
Federico Mena Quintero's avatar
Federico Mena Quintero committed
268
 **/
269
GdkPixbuf *
270
gdk_pixbuf_new_from_file (const char *filename)
Arturo Espinosa's avatar
Arturo Espinosa committed
271
{
272
	GdkPixbuf *pixbuf;
273
	int size;
Arturo Espinosa's avatar
Arturo Espinosa committed
274
	FILE *f;
275
	guchar buffer [128];
276
	GdkPixbufModule *image_module;
Arturo Espinosa's avatar
Arturo Espinosa committed
277

278 279
	g_return_val_if_fail (filename != NULL, NULL);

280
	f = fopen (filename, "r");
Arturo Espinosa's avatar
Arturo Espinosa committed
281 282
	if (!f)
		return NULL;
283

284 285
	size = fread (&buffer, 1, sizeof (buffer), f);
	if (size == 0) {
286
		fclose (f);
Arturo Espinosa's avatar
Arturo Espinosa committed
287
		return NULL;
288
	}
Arturo Espinosa's avatar
Arturo Espinosa committed
289

290
	image_module = gdk_pixbuf_get_module (buffer, size);
291 292
	if (!image_module) {
		g_warning ("Unable to find handler for file: %s", filename);
293
		fclose (f);
294 295
		return NULL;
	}
296

297 298
	if (image_module->module == NULL)
		gdk_pixbuf_load_module (image_module);
299

300 301 302
	if (image_module->load == NULL) {
		fclose (f);
		return NULL;
Arturo Espinosa's avatar
Arturo Espinosa committed
303 304
	}

305 306
	fseek (f, 0, SEEK_SET);
	pixbuf = (* image_module->load) (f);
307
	fclose (f);
308 309 310 311 312

	if (pixbuf)
		g_assert (pixbuf->ref_count > 0);

	return pixbuf;
Arturo Espinosa's avatar
Arturo Espinosa committed
313
}
314

315 316
/**
 * gdk_pixbuf_new_from_xpm_data:
Federico Mena Quintero's avatar
Federico Mena Quintero committed
317
 * @data: Pointer to inline XPM data.
318
 *
319 320
 * Creates a new pixbuf by parsing XPM data in memory.  This data is commonly
 * the result of including an XPM file into a program's C source.
321
 *
322 323
 * Return value: A newly-created pixbuf with a reference count of 1.
 **/
324
GdkPixbuf *
325
gdk_pixbuf_new_from_xpm_data (const char **data)
326
{
327 328
	GdkPixbuf *(* load_xpm_data) (const char **data);
	GdkPixbuf *pixbuf;
329

330 331
	if (file_formats[XPM_FILE_FORMAT_INDEX].module == NULL)
		gdk_pixbuf_load_module (&file_formats[XPM_FILE_FORMAT_INDEX]);
332

333 334
	if (file_formats[XPM_FILE_FORMAT_INDEX].module == NULL) {
		g_warning ("Can't find gdk-pixbuf module for parsing inline XPM data");
335
		return NULL;
336 337
	} else if (file_formats[XPM_FILE_FORMAT_INDEX].load_xpm_data == NULL) {
		g_warning ("gdk-pixbuf XPM module lacks XPM data capability");
338
		return NULL;
339 340
	} else
		load_xpm_data = file_formats[XPM_FILE_FORMAT_INDEX].load_xpm_data;
341

342 343
	pixbuf = (* load_xpm_data) (data);
	return pixbuf;
344
}