gdk-pixbuf-loader.c 27.3 KB
Newer Older
Matthias Clasen's avatar
Matthias Clasen committed
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2
/* GdkPixbuf library - Progressive loader object
3 4 5 6 7 8 9 10 11
 *
 * Copyright (C) 1999 The Free Software Foundation
 *
 * Authors: Mark Crichton <crichton@gimp.org>
 *          Miguel de Icaza <miguel@gnu.org>
 *          Federico Mena-Quintero <federico@gimp.org>
 *          Jonathan Blandford <jrb@redhat.com>
 *
 * This library is free software; you can redistribute it and/or
12
 * modify it under the terms of the GNU Lesser General Public
13 14 15 16 17 18
 * 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
19
 * Lesser General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU Lesser General Public
22 23 24 25 26
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

27
#include "config.h"
Owen Taylor's avatar
Owen Taylor committed
28 29
#include <string.h>

30
#include "gdk-pixbuf-private.h"
31
#include "gdk-pixbuf-animation.h"
32
#include "gdk-pixbuf-scaled-anim.h"
33
#include "gdk-pixbuf-io.h"
34
#include "gdk-pixbuf-loader.h"
35
#include "gdk-pixbuf-marshal.h"
36
#include "gdk-pixbuf-alias.h"
37

38
enum {
Matthias Clasen's avatar
Matthias Clasen committed
39 40 41 42 43
        SIZE_PREPARED,
        AREA_PREPARED,
        AREA_UPDATED,
        CLOSED,
        LAST_SIGNAL
44
};
45 46


Matthias Clasen's avatar
Matthias Clasen committed
47
static void gdk_pixbuf_loader_finalize (GObject *loader);
48

49
static guint    pixbuf_loader_signals[LAST_SIGNAL] = { 0 };
50

51
/* Internal data */
52

53
#define LOADER_HEADER_SIZE 1024
54

55 56
typedef struct
{
Matthias Clasen's avatar
Matthias Clasen committed
57 58
        GdkPixbufAnimation *animation;
        gboolean closed;
59
        gboolean holds_threadlock;
Matthias Clasen's avatar
Matthias Clasen committed
60 61 62 63 64 65 66 67
        guchar header_buf[LOADER_HEADER_SIZE];
        gint header_buf_offset;
        GdkPixbufModule *image_module;
        gpointer context;
        gint width;
        gint height;
        gboolean size_fixed;
        gboolean needs_scale;
68
} GdkPixbufLoaderPrivate;
69

Matthias Clasen's avatar
Matthias Clasen committed
70
G_DEFINE_TYPE (GdkPixbufLoader, gdk_pixbuf_loader, G_TYPE_OBJECT)
71 72

static void
73
gdk_pixbuf_loader_class_init (GdkPixbufLoaderClass *class)
74
{
Matthias Clasen's avatar
Matthias Clasen committed
75 76 77 78 79 80
        GObjectClass *object_class;
  
        object_class = (GObjectClass *) class;
  
        object_class->finalize = gdk_pixbuf_loader_finalize;

81 82 83 84 85 86 87 88 89 90 91 92
        /**
         * GdkPixbufLoader::size-prepared:
         * @loader: the object which received the signal.
         * @width: the original width of the image
         * @height: the original height of the image
         *
         * This signal is emitted when the pixbuf loader has been fed the
         * initial amount of data that is required to figure out the size
         * of the image that it will create.  Applications can call  
         * gdk_pixbuf_loader_set_size() in response to this signal to set
         * the desired size to which the image should be scaled.
         */
Matthias Clasen's avatar
Matthias Clasen committed
93 94 95 96 97 98
        pixbuf_loader_signals[SIZE_PREPARED] =
                g_signal_new ("size_prepared",
                              G_TYPE_FROM_CLASS (object_class),
                              G_SIGNAL_RUN_LAST,
                              G_STRUCT_OFFSET (GdkPixbufLoaderClass, size_prepared),
                              NULL, NULL,
Matthias Clasen's avatar
2.5.2  
Matthias Clasen committed
99
                              _gdk_pixbuf_marshal_VOID__INT_INT,
Matthias Clasen's avatar
Matthias Clasen committed
100 101 102 103
                              G_TYPE_NONE, 2, 
                              G_TYPE_INT,
                              G_TYPE_INT);
  
104 105 106 107 108 109 110 111 112
        /**
         * GdkPixbufLoader::area-prepared:
         * @loader: the object which received the signal.
         *
         * This signal is emitted when the pixbuf loader has allocated the 
         * pixbuf in the desired size.  After this signal is emitted, 
         * applications can call gdk_pixbuf_loader_get_pixbuf() to fetch 
         * the partially-loaded pixbuf.
         */
Matthias Clasen's avatar
Matthias Clasen committed
113 114 115 116 117 118
        pixbuf_loader_signals[AREA_PREPARED] =
                g_signal_new ("area_prepared",
                              G_TYPE_FROM_CLASS (object_class),
                              G_SIGNAL_RUN_LAST,
                              G_STRUCT_OFFSET (GdkPixbufLoaderClass, area_prepared),
                              NULL, NULL,
Matthias Clasen's avatar
2.5.2  
Matthias Clasen committed
119
                              _gdk_pixbuf_marshal_VOID__VOID,
Matthias Clasen's avatar
Matthias Clasen committed
120
                              G_TYPE_NONE, 0);
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135

        /**
         * GdkPixbufLoader::area-updated:
         * @loader: the object which received the signal.
         * @x: X offset of upper-left corner of the updated area.
         * @y: Y offset of upper-left corner of the updated area.
         * @width: Width of updated area.
         * @height: Height of updated area.
         *
         * This signal is emitted when a significant area of the image being
         * loaded has been updated.  Normally it means that a complete
         * scanline has been read in, but it could be a different area as
         * well.  Applications can use this signal to know when to repaint
         * areas of an image that is being loaded.
         */
Matthias Clasen's avatar
Matthias Clasen committed
136 137 138 139 140 141
        pixbuf_loader_signals[AREA_UPDATED] =
                g_signal_new ("area_updated",
                              G_TYPE_FROM_CLASS (object_class),
                              G_SIGNAL_RUN_LAST,
                              G_STRUCT_OFFSET (GdkPixbufLoaderClass, area_updated),
                              NULL, NULL,
Matthias Clasen's avatar
2.5.2  
Matthias Clasen committed
142
                              _gdk_pixbuf_marshal_VOID__INT_INT_INT_INT,
Matthias Clasen's avatar
Matthias Clasen committed
143 144 145 146 147 148
                              G_TYPE_NONE, 4,
                              G_TYPE_INT,
                              G_TYPE_INT,
                              G_TYPE_INT,
                              G_TYPE_INT);
  
149 150 151 152 153 154 155 156 157
        /**
         * GdkPixbufLoader::closed:
         * @loader: the object which received the signal.
         *
         * This signal is emitted when gdk_pixbuf_loader_close() is called.
         * It can be used by different parts of an application to receive
         * notification when an image loader is closed by the code that
         * drives it.
         */
Matthias Clasen's avatar
Matthias Clasen committed
158 159 160 161 162 163
        pixbuf_loader_signals[CLOSED] =
                g_signal_new ("closed",
                              G_TYPE_FROM_CLASS (object_class),
                              G_SIGNAL_RUN_LAST,
                              G_STRUCT_OFFSET (GdkPixbufLoaderClass, closed),
                              NULL, NULL,
Matthias Clasen's avatar
2.5.2  
Matthias Clasen committed
164
                              _gdk_pixbuf_marshal_VOID__VOID,
Matthias Clasen's avatar
Matthias Clasen committed
165
                              G_TYPE_NONE, 0);
166 167 168 169 170
}

static void
gdk_pixbuf_loader_init (GdkPixbufLoader *loader)
{
Matthias Clasen's avatar
Matthias Clasen committed
171
        GdkPixbufLoaderPrivate *priv;
172
  
Matthias Clasen's avatar
Matthias Clasen committed
173
        priv = g_new0 (GdkPixbufLoaderPrivate, 1);
174 175 176
        priv->width = -1;
        priv->height = -1;

Matthias Clasen's avatar
Matthias Clasen committed
177
        loader->priv = priv;
178 179 180
}

static void
181
gdk_pixbuf_loader_finalize (GObject *object)
182
{
Matthias Clasen's avatar
Matthias Clasen committed
183 184
        GdkPixbufLoader *loader;
        GdkPixbufLoaderPrivate *priv = NULL;
185
  
Matthias Clasen's avatar
Matthias Clasen committed
186 187
        loader = GDK_PIXBUF_LOADER (object);
        priv = loader->priv;
188

189
        if (!priv->closed) {
Matthias Clasen's avatar
Matthias Clasen committed
190
                g_warning ("GdkPixbufLoader finalized without calling gdk_pixbuf_loader_close() - this is not allowed. You must explicitly end the data stream to the loader before dropping the last reference.");
191 192 193 194
                if (priv->holds_threadlock) {
                        _gdk_pixbuf_unlock (priv->image_module);
                }
        }
Matthias Clasen's avatar
Matthias Clasen committed
195 196
        if (priv->animation)
                g_object_unref (priv->animation);
197
  
Matthias Clasen's avatar
Matthias Clasen committed
198
        g_free (priv);
199
  
Matthias Clasen's avatar
Matthias Clasen committed
200
        G_OBJECT_CLASS (gdk_pixbuf_loader_parent_class)->finalize (object);
201 202
}

203 204 205 206 207 208 209 210 211 212 213 214 215
/**
 * gdk_pixbuf_loader_set_size:
 * @loader: A pixbuf loader.
 * @width: The desired width of the image being loaded.
 * @height: The desired height of the image being loaded.
 *
 * Causes the image to be scaled while it is loaded. The desired
 * image size can be determined relative to the original size of
 * the image by calling gdk_pixbuf_loader_set_size() from a
 * signal handler for the ::size_prepared signal.
 *
 * Attempts to set the desired image size  are ignored after the 
 * emission of the ::size_prepared signal.
Matthias Clasen's avatar
Matthias Clasen committed
216 217
 *
 * Since: 2.2
218 219 220 221 222 223
 */
void 
gdk_pixbuf_loader_set_size (GdkPixbufLoader *loader,
			    gint             width,
			    gint             height)
{
Matthias Clasen's avatar
Matthias Clasen committed
224
        GdkPixbufLoaderPrivate *priv = GDK_PIXBUF_LOADER (loader)->priv;
225
        g_return_if_fail (width >= 0 && height >= 0);
Matthias Clasen's avatar
Matthias Clasen committed
226 227 228 229 230 231

        if (!priv->size_fixed) 
                {
                        priv->width = width;
                        priv->height = height;
                }
232 233 234 235 236
}

static void
gdk_pixbuf_loader_size_func (gint *width, gint *height, gpointer loader)
{
Matthias Clasen's avatar
Matthias Clasen committed
237
        GdkPixbufLoaderPrivate *priv = GDK_PIXBUF_LOADER (loader)->priv;
238

Matthias Clasen's avatar
Matthias Clasen committed
239
        /* allow calling gdk_pixbuf_loader_set_size() before the signal */
240
        if (priv->width == -1 && priv->height == -1) 
Matthias Clasen's avatar
Matthias Clasen committed
241 242 243 244
                {
                        priv->width = *width;
                        priv->height = *height;
                }
245

Matthias Clasen's avatar
Matthias Clasen committed
246 247
        g_signal_emit (loader, pixbuf_loader_signals[SIZE_PREPARED], 0, *width, *height);
        priv->size_fixed = TRUE;
248

Matthias Clasen's avatar
Matthias Clasen committed
249 250
        *width = priv->width;
        *height = priv->height;
251 252
}

253
static void
Havoc Pennington's avatar
Havoc Pennington committed
254 255 256
gdk_pixbuf_loader_prepare (GdkPixbuf          *pixbuf,
                           GdkPixbufAnimation *anim,
			   gpointer            loader)
257
{
Matthias Clasen's avatar
Matthias Clasen committed
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
        GdkPixbufLoaderPrivate *priv = GDK_PIXBUF_LOADER (loader)->priv;
        g_return_if_fail (pixbuf != NULL);

        if (!priv->size_fixed) 
                {
                        /* Defend against lazy loaders which don't call size_func */
                        gint width = gdk_pixbuf_get_width (pixbuf);
                        gint height = gdk_pixbuf_get_height (pixbuf);
                        
                        gdk_pixbuf_loader_size_func (&width, &height, loader);
                }

        priv->needs_scale = FALSE;
        if (priv->width > 0 && priv->height > 0 &&
            (priv->width != gdk_pixbuf_get_width (pixbuf) ||
             priv->height != gdk_pixbuf_get_height (pixbuf)))
                priv->needs_scale = TRUE;

        if (anim)
                g_object_ref (anim);
        else
                anim = gdk_pixbuf_non_anim_new (pixbuf);
  
281
	if (priv->needs_scale) {
282
		priv->animation  = GDK_PIXBUF_ANIMATION (_gdk_pixbuf_scaled_anim_new (anim,
283 284
                                         (double) priv->width / gdk_pixbuf_get_width (pixbuf),
                                         (double) priv->height / gdk_pixbuf_get_height (pixbuf),
285
					  1.0));
286 287 288 289
			g_object_unref (anim);
	}
	else
        	priv->animation = anim;
Matthias Clasen's avatar
Matthias Clasen committed
290 291 292
  
        if (!priv->needs_scale)
                g_signal_emit (loader, pixbuf_loader_signals[AREA_PREPARED], 0);
293 294
}

295
static void
296
gdk_pixbuf_loader_update (GdkPixbuf *pixbuf,
Havoc Pennington's avatar
Havoc Pennington committed
297 298 299 300
			  gint       x,
			  gint       y,
			  gint       width,
			  gint       height,
301
			  gpointer   loader)
302
{
Matthias Clasen's avatar
Matthias Clasen committed
303 304 305 306 307 308 309 310 311 312
        GdkPixbufLoaderPrivate *priv = GDK_PIXBUF_LOADER (loader)->priv;
  
        if (!priv->needs_scale)
                g_signal_emit (loader,
                               pixbuf_loader_signals[AREA_UPDATED],
                               0,
                               x, y,
                               /* sanity check in here.  Defend against an errant loader */
                               MIN (width, gdk_pixbuf_animation_get_width (priv->animation)),
                               MIN (height, gdk_pixbuf_animation_get_height (priv->animation)));
313 314
}

315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
/* Defense against broken loaders; DO NOT take this as a GError example! */
static void
gdk_pixbuf_loader_ensure_error (GdkPixbufLoader *loader,
                                GError         **error)
{ 
        GdkPixbufLoaderPrivate *priv = loader->priv;

        if (error == NULL || *error != NULL)
                return;

        g_warning ("Bug! loader '%s' didn't set an error on failure",
                   priv->image_module->module_name);
        g_set_error (error,
                     GDK_PIXBUF_ERROR,
                     GDK_PIXBUF_ERROR_FAILED,
                     _("Internal error: Image loader module '%s' failed to"
                       " complete an operation, but didn't give a reason for"
                       " the failure"),
                     priv->image_module->module_name);
}

336
static gint
Havoc Pennington's avatar
Havoc Pennington committed
337 338 339
gdk_pixbuf_loader_load_module (GdkPixbufLoader *loader,
                               const char      *image_type,
                               GError         **error)
340
{
Matthias Clasen's avatar
Matthias Clasen committed
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
        GdkPixbufLoaderPrivate *priv = loader->priv;

        if (image_type)
                {
                        priv->image_module = _gdk_pixbuf_get_named_module (image_type,
                                                                           error);
                }
        else
                {
                        priv->image_module = _gdk_pixbuf_get_module (priv->header_buf,
                                                                     priv->header_buf_offset,
                                                                     NULL,
                                                                     error);
                }
  
        if (priv->image_module == NULL)
                return 0;
  
        if (priv->image_module->module == NULL)
                if (!_gdk_pixbuf_load_module (priv->image_module, error))
                        return 0;
  
        if (priv->image_module->module == NULL)
                return 0;
  
        if ((priv->image_module->begin_load == NULL) ||
            (priv->image_module->stop_load == NULL) ||
            (priv->image_module->load_increment == NULL))
                {
                        g_set_error (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
                                     _("Incremental loading of image type '%s' is not supported"),
                                     priv->image_module->module_name);

                        return 0;
                }

379
	if (!priv->holds_threadlock) {
380
                priv->holds_threadlock = _gdk_pixbuf_lock (priv->image_module);
381 382
        }

Matthias Clasen's avatar
Matthias Clasen committed
383 384 385 386 387 388 389 390
        priv->context = priv->image_module->begin_load (gdk_pixbuf_loader_size_func,
                                                        gdk_pixbuf_loader_prepare,
                                                        gdk_pixbuf_loader_update,
                                                        loader,
                                                        error);
  
        if (priv->context == NULL)
                {
391
                        gdk_pixbuf_loader_ensure_error (loader, error);
Matthias Clasen's avatar
Matthias Clasen committed
392 393
                        return 0;
                }
394
  
Matthias Clasen's avatar
Matthias Clasen committed
395 396 397
        if (priv->header_buf_offset
            && priv->image_module->load_increment (priv->context, priv->header_buf, priv->header_buf_offset, error))
                return priv->header_buf_offset;
398
  
Matthias Clasen's avatar
Matthias Clasen committed
399
        return 0;
400 401 402
}

static int
403 404
gdk_pixbuf_loader_eat_header_write (GdkPixbufLoader *loader,
				    const guchar    *buf,
Havoc Pennington's avatar
Havoc Pennington committed
405 406
				    gsize            count,
                                    GError         **error)
407
{
Matthias Clasen's avatar
Matthias Clasen committed
408 409
        gint n_bytes;
        GdkPixbufLoaderPrivate *priv = loader->priv;
410
  
Matthias Clasen's avatar
Matthias Clasen committed
411 412
        n_bytes = MIN(LOADER_HEADER_SIZE - priv->header_buf_offset, count);
        memcpy (priv->header_buf + priv->header_buf_offset, buf, n_bytes);
413
  
Matthias Clasen's avatar
Matthias Clasen committed
414
        priv->header_buf_offset += n_bytes;
415
  
Matthias Clasen's avatar
Matthias Clasen committed
416 417 418 419 420
        if (priv->header_buf_offset >= LOADER_HEADER_SIZE)
                {
                        if (gdk_pixbuf_loader_load_module (loader, NULL, error) == 0)
                                return 0;
                }
421
  
Matthias Clasen's avatar
Matthias Clasen committed
422
        return n_bytes;
423 424
}

425 426
/**
 * gdk_pixbuf_loader_write:
427
 * @loader: A pixbuf loader.
Federico Mena Quintero's avatar
Federico Mena Quintero committed
428 429
 * @buf: Pointer to image data.
 * @count: Length of the @buf buffer in bytes.
Havoc Pennington's avatar
Havoc Pennington committed
430
 * @error: return location for errors
431
 *
Havoc Pennington's avatar
Havoc Pennington committed
432
 * This will cause a pixbuf loader to parse the next @count bytes of
Matthias Clasen's avatar
Matthias Clasen committed
433 434 435
 * an image.  It will return %TRUE if the data was loaded successfully,
 * and %FALSE if an error occurred.  In the latter case, the loader
 * will be closed, and will not accept further writes. If %FALSE is
Havoc Pennington's avatar
Havoc Pennington committed
436
 * returned, @error will be set to an error from the #GDK_PIXBUF_ERROR
437
 * or #G_FILE_ERROR domains.
438
 *
Matthias Clasen's avatar
Matthias Clasen committed
439
 * Return value: %TRUE if the write was successful, or %FALSE if the loader
Federico Mena Quintero's avatar
Federico Mena Quintero committed
440
 * cannot parse the buffer.
441 442
 **/
gboolean
443 444
gdk_pixbuf_loader_write (GdkPixbufLoader *loader,
			 const guchar    *buf,
Havoc Pennington's avatar
Havoc Pennington committed
445 446
			 gsize            count,
                         GError         **error)
447
{
Matthias Clasen's avatar
Matthias Clasen committed
448
        GdkPixbufLoaderPrivate *priv;
449
  
Matthias Clasen's avatar
Matthias Clasen committed
450 451
        g_return_val_if_fail (loader != NULL, FALSE);
        g_return_val_if_fail (GDK_IS_PIXBUF_LOADER (loader), FALSE);
452
  
Matthias Clasen's avatar
Matthias Clasen committed
453
        g_return_val_if_fail (buf != NULL, FALSE);
454
        g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
455
  
Matthias Clasen's avatar
Matthias Clasen committed
456
        priv = loader->priv;
457

Matthias Clasen's avatar
Matthias Clasen committed
458 459
        /* we expect it's not to be closed */
        g_return_val_if_fail (priv->closed == FALSE, FALSE);
460
  
461
        if (count > 0 && priv->image_module == NULL)
Matthias Clasen's avatar
Matthias Clasen committed
462 463
                {
                        gint eaten;
464
      
Matthias Clasen's avatar
Matthias Clasen committed
465 466
                        eaten = gdk_pixbuf_loader_eat_header_write (loader, buf, count, error);
                        if (eaten <= 0)
467
                               goto fail; 
468
      
Matthias Clasen's avatar
Matthias Clasen committed
469 470 471 472 473 474
                        count -= eaten;
                        buf += eaten;
                }
  
        if (count > 0 && priv->image_module->load_increment)
                {
475 476 477
                        if (!priv->image_module->load_increment (priv->context, buf, count,
                                                                 error))
				goto fail;
Matthias Clasen's avatar
Matthias Clasen committed
478
                }
Havoc Pennington's avatar
Havoc Pennington committed
479
      
Matthias Clasen's avatar
Matthias Clasen committed
480
        return TRUE;
481 482 483

 fail:
        gdk_pixbuf_loader_ensure_error (loader, error);
484
        gdk_pixbuf_loader_close (loader, NULL);
485

486
        return FALSE;
487 488
}

489 490 491 492 493 494 495 496 497 498
/**
 * gdk_pixbuf_loader_new:
 *
 * Creates a new pixbuf loader object.
 *
 * Return value: A newly-created pixbuf loader.
 **/
GdkPixbufLoader *
gdk_pixbuf_loader_new (void)
{
Matthias Clasen's avatar
Matthias Clasen committed
499
        return g_object_new (GDK_TYPE_PIXBUF_LOADER, NULL);
500 501 502 503
}

/**
 * gdk_pixbuf_loader_new_with_type:
Havoc Pennington's avatar
docs  
Havoc Pennington committed
504 505
 * @image_type: name of the image format to be loaded with the image
 * @error: return location for an allocated #GError, or %NULL to ignore errors
506
 *
Havoc Pennington's avatar
docs  
Havoc Pennington committed
507 508 509 510 511 512
 * Creates a new pixbuf loader object that always attempts to parse
 * image data as if it were an image of type @image_type, instead of
 * identifying the type automatically. Useful if you want an error if
 * the image isn't the expected type, for loading image formats
 * that can't be reliably identified by looking at the data, or if
 * the user manually forces a specific type.
513
 *
514 515 516 517 518 519
 * The list of supported image formats depends on what image loaders
 * are installed, but typically "png", "jpeg", "gif", "tiff" and 
 * "xpm" are among the supported formats. To obtain the full list of
 * supported image formats, call gdk_pixbuf_format_get_name() on each 
 * of the #GdkPixbufFormat structs returned by gdk_pixbuf_get_formats().
 *
520 521 522
 * Return value: A newly-created pixbuf loader.
 **/
GdkPixbufLoader *
Havoc Pennington's avatar
Havoc Pennington committed
523 524
gdk_pixbuf_loader_new_with_type (const char *image_type,
                                 GError    **error)
525
{
Matthias Clasen's avatar
Matthias Clasen committed
526 527
        GdkPixbufLoader *retval;
        GError *tmp;
528
        g_return_val_if_fail (error == NULL || *error == NULL, NULL);
Havoc Pennington's avatar
Havoc Pennington committed
529
  
Matthias Clasen's avatar
Matthias Clasen committed
530
        retval = g_object_new (GDK_TYPE_PIXBUF_LOADER, NULL);
531

Matthias Clasen's avatar
Matthias Clasen committed
532
        tmp = NULL;
533
        gdk_pixbuf_loader_load_module (retval, image_type, &tmp);
Matthias Clasen's avatar
Matthias Clasen committed
534 535 536
        if (tmp != NULL)
                {
                        g_propagate_error (error, tmp);
537
                        gdk_pixbuf_loader_close (retval, NULL);
Matthias Clasen's avatar
Matthias Clasen committed
538 539 540
                        g_object_unref (retval);
                        return NULL;
                }
541

Matthias Clasen's avatar
Matthias Clasen committed
542
        return retval;
543 544
}

545 546 547 548 549 550 551 552 553 554 555 556
/**
 * gdk_pixbuf_loader_new_with_mime_type:
 * @mime_type: the mime type to be loaded 
 * @error: return location for an allocated #GError, or %NULL to ignore errors
 *
 * Creates a new pixbuf loader object that always attempts to parse
 * image data as if it were an image of mime type @mime_type, instead of
 * identifying the type automatically. Useful if you want an error if
 * the image isn't the expected mime type, for loading image formats
 * that can't be reliably identified by looking at the data, or if
 * the user manually forces a specific mime type.
 *
557 558 559 560 561 562 563
 * The list of supported mime types depends on what image loaders
 * are installed, but typically "image/png", "image/jpeg", "image/gif", 
 * "image/tiff" and "image/x-xpixmap" are among the supported mime types. 
 * To obtain the full list of supported mime types, call 
 * gdk_pixbuf_format_get_mime_types() on each of the #GdkPixbufFormat 
 * structs returned by gdk_pixbuf_get_formats().
 *
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
 * Return value: A newly-created pixbuf loader.
 * Since: 2.4
 **/
GdkPixbufLoader *
gdk_pixbuf_loader_new_with_mime_type (const char *mime_type,
                                      GError    **error)
{
        const char * image_type = NULL;
        char ** mimes;

        GdkPixbufLoader *retval;
        GError *tmp;
  
        GSList * formats;
        GdkPixbufFormat *info;
        int i, j, length;

        formats = gdk_pixbuf_get_formats ();
        length = g_slist_length (formats);

        for (i = 0; i < length && image_type == NULL; i++) {
                info = (GdkPixbufFormat *)g_slist_nth_data (formats, i);
                mimes = info->mime_types;
                
                for (j = 0; mimes[j] != NULL; j++)
589
                        if (g_ascii_strcasecmp (mimes[j], mime_type) == 0) {
590 591 592 593 594 595 596 597 598 599
                                image_type = info->name;
                                break;
                        }
        }

        g_slist_free (formats);

        retval = g_object_new (GDK_TYPE_PIXBUF_LOADER, NULL);

        tmp = NULL;
600
        gdk_pixbuf_loader_load_module (retval, image_type, &tmp);
601 602 603
        if (tmp != NULL)
                {
                        g_propagate_error (error, tmp);
604
                        gdk_pixbuf_loader_close (retval, NULL);
605 606 607 608 609 610 611
                        g_object_unref (retval);
                        return NULL;
                }

        return retval;
}

612 613
/**
 * gdk_pixbuf_loader_get_pixbuf:
614
 * @loader: A pixbuf loader.
615
 *
Matthias Clasen's avatar
Matthias Clasen committed
616
 * Queries the #GdkPixbuf that a pixbuf loader is currently creating.
617
 * In general it only makes sense to call this function after the
Havoc Pennington's avatar
Havoc Pennington committed
618 619 620
 * "area_prepared" signal has been emitted by the loader; this means
 * that enough data has been read to know the size of the image that
 * will be allocated.  If the loader has not received enough data via
Havoc Pennington's avatar
Havoc Pennington committed
621
 * gdk_pixbuf_loader_write(), then this function returns %NULL.  The
Havoc Pennington's avatar
Havoc Pennington committed
622
 * returned pixbuf will be the same in all future calls to the loader,
623
 * so simply calling g_object_ref() should be sufficient to continue
Havoc Pennington's avatar
Havoc Pennington committed
624
 * using it.  Additionally, if the loader is an animation, it will
Havoc Pennington's avatar
Havoc Pennington committed
625 626
 * return the "static image" of the animation
 * (see gdk_pixbuf_animation_get_static_image()).
Havoc Pennington's avatar
Havoc Pennington committed
627
 * 
Havoc Pennington's avatar
Havoc Pennington committed
628
 * Return value: The #GdkPixbuf that the loader is creating, or %NULL if not
Federico Mena Quintero's avatar
Federico Mena Quintero committed
629
 * enough data has been read to determine how to create the image buffer.
630 631 632 633
 **/
GdkPixbuf *
gdk_pixbuf_loader_get_pixbuf (GdkPixbufLoader *loader)
{
Matthias Clasen's avatar
Matthias Clasen committed
634
        GdkPixbufLoaderPrivate *priv;
635
  
Matthias Clasen's avatar
Matthias Clasen committed
636 637
        g_return_val_if_fail (loader != NULL, NULL);
        g_return_val_if_fail (GDK_IS_PIXBUF_LOADER (loader), NULL);
638
  
Matthias Clasen's avatar
Matthias Clasen committed
639
        priv = loader->priv;
Havoc Pennington's avatar
Havoc Pennington committed
640

Matthias Clasen's avatar
Matthias Clasen committed
641 642 643 644
        if (priv->animation)
                return gdk_pixbuf_animation_get_static_image (priv->animation);
        else
                return NULL;
645 646
}

647 648 649
/**
 * gdk_pixbuf_loader_get_animation:
 * @loader: A pixbuf loader
650
 *
Matthias Clasen's avatar
Matthias Clasen committed
651
 * Queries the #GdkPixbufAnimation that a pixbuf loader is currently creating.
652
 * In general it only makes sense to call this function after the "area_prepared"
Havoc Pennington's avatar
Havoc Pennington committed
653
 * signal has been emitted by the loader. If the loader doesn't have enough
Matthias Clasen's avatar
Matthias Clasen committed
654 655
 * bytes yet (hasn't emitted the "area_prepared" signal) this function will 
 * return %NULL.
656
 *
Matthias Clasen's avatar
Matthias Clasen committed
657
 * Return value: The #GdkPixbufAnimation that the loader is loading, or %NULL if
658
 not enough data has been read to determine the information.
659
**/
660 661 662
GdkPixbufAnimation *
gdk_pixbuf_loader_get_animation (GdkPixbufLoader *loader)
{
Matthias Clasen's avatar
Matthias Clasen committed
663
        GdkPixbufLoaderPrivate *priv;
664
  
Matthias Clasen's avatar
Matthias Clasen committed
665 666
        g_return_val_if_fail (loader != NULL, NULL);
        g_return_val_if_fail (GDK_IS_PIXBUF_LOADER (loader), NULL);
667
  
Matthias Clasen's avatar
Matthias Clasen committed
668
        priv = loader->priv;
669
  
Matthias Clasen's avatar
Matthias Clasen committed
670
        return priv->animation;
671 672
}

673 674
/**
 * gdk_pixbuf_loader_close:
675
 * @loader: A pixbuf loader.
676 677 678 679 680 681
 * @error: return location for a #GError, or %NULL to ignore errors
 *
 * Informs a pixbuf loader that no further writes with
 * gdk_pixbuf_loader_write() will occur, so that it can free its
 * internal loading structures. Also, tries to parse any data that
 * hasn't yet been parsed; if the remaining data is partial or
Matthias Clasen's avatar
Matthias Clasen committed
682
 * corrupt, an error will be returned.  If %FALSE is returned, @error
683 684 685 686
 * will be set to an error from the #GDK_PIXBUF_ERROR or #G_FILE_ERROR
 * domains. If you're just cancelling a load rather than expecting it
 * to be finished, passing %NULL for @error to ignore it is
 * reasonable.
687
 *
688 689
 * Returns: %TRUE if all image data written so far was successfully
            passed out via the update_area signal
690
 **/
691 692 693
gboolean
gdk_pixbuf_loader_close (GdkPixbufLoader *loader,
                         GError         **error)
694
{
Matthias Clasen's avatar
Matthias Clasen committed
695 696 697 698 699
        GdkPixbufLoaderPrivate *priv;
        gboolean retval = TRUE;
  
        g_return_val_if_fail (loader != NULL, TRUE);
        g_return_val_if_fail (GDK_IS_PIXBUF_LOADER (loader), TRUE);
700
        g_return_val_if_fail (error == NULL || *error == NULL, TRUE);
Matthias Clasen's avatar
Matthias Clasen committed
701 702 703
  
        priv = loader->priv;
  
704 705
        if (priv->closed)
                return TRUE;
Matthias Clasen's avatar
Matthias Clasen committed
706
  
707 708 709
        /* We have less the LOADER_HEADER_SIZE bytes in the image.  
         * Flush it, and keep going. 
         */
Matthias Clasen's avatar
Matthias Clasen committed
710 711 712 713 714 715 716 717 718 719 720 721 722
        if (priv->image_module == NULL)
                {
                        GError *tmp = NULL;
                        gdk_pixbuf_loader_load_module (loader, NULL, &tmp);
                        if (tmp != NULL)
                                {
                                        g_propagate_error (error, tmp);
                                        retval = FALSE;
                                }
                }  

        if (priv->image_module && priv->image_module->stop_load && priv->context) 
                {
723 724
                        GError *tmp = NULL;
                        if (!priv->image_module->stop_load (priv->context, &tmp) || tmp)
725
                                {
726 727 728 729 730 731
					/* don't call gdk_pixbuf_loader_ensure_error()
 					 * here, since we might not get an error in the
 					 * gdk_pixbuf_get_file_info() case
 					 */
					if (tmp)
						g_propagate_error (error, tmp);
732 733
                                        retval = FALSE;
                                }
Matthias Clasen's avatar
Matthias Clasen committed
734 735 736
                }
  
        priv->closed = TRUE;
737
	if (priv->image_module && priv->holds_threadlock) {
738 739 740
                _gdk_pixbuf_unlock (priv->image_module);
                priv->holds_threadlock = FALSE;
        }
Matthias Clasen's avatar
Matthias Clasen committed
741 742 743

        if (priv->needs_scale) 
                {
744

Matthias Clasen's avatar
Matthias Clasen committed
745 746 747 748 749 750 751 752 753
                        g_signal_emit (loader, pixbuf_loader_signals[AREA_PREPARED], 0);
                        g_signal_emit (loader, pixbuf_loader_signals[AREA_UPDATED], 0, 
                                       0, 0, priv->width, priv->height);
                }

        
        g_signal_emit (loader, pixbuf_loader_signals[CLOSED], 0);

        return retval;
754
}
755

756 757 758 759 760 761 762 763 764
/**
 * gdk_pixbuf_loader_get_format:
 * @loader: A pixbuf loader.
 *
 * Obtains the available information about the format of the 
 * currently loading image file.
 *
 * Returns: A #GdkPixbufFormat or %NULL. The return value is owned 
 * by GdkPixbuf and should not be freed.
Matthias Clasen's avatar
Matthias Clasen committed
765 766
 * 
 * Since: 2.2
767 768 769 770
 */
GdkPixbufFormat *
gdk_pixbuf_loader_get_format (GdkPixbufLoader *loader)
{
Matthias Clasen's avatar
Matthias Clasen committed
771
        GdkPixbufLoaderPrivate *priv;
772
  
Matthias Clasen's avatar
Matthias Clasen committed
773 774
        g_return_val_if_fail (loader != NULL, NULL);
        g_return_val_if_fail (GDK_IS_PIXBUF_LOADER (loader), NULL);
775
  
Matthias Clasen's avatar
Matthias Clasen committed
776
        priv = loader->priv;
777

Matthias Clasen's avatar
Matthias Clasen committed
778 779 780 781
        if (priv->image_module)
                return _gdk_pixbuf_get_format (priv->image_module);
        else
                return NULL;
782
}
783 784


785 786
#define __GDK_PIXBUF_LOADER_C__
#include "gdk-pixbuf-aliasdef.c"
787