1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2/* GdkPixbuf library - Progressive loader object
3 *
4 * Copyright (C) 1999 The Free Software Foundation
5 *
6 * Authors: Mark Crichton <crichton@gimp.org>
7 * Miguel de Icaza <miguel@gnu.org>
8 * Federico Mena-Quintero <federico@gimp.org>
9 * Jonathan Blandford <jrb@redhat.com>
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * 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 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
23 */
24
25#include "config.h"
26#include <string.h>
27
28#include "gdk-pixbuf-private.h"
29#include "gdk-pixbuf-animation.h"
30#include "gdk-pixbuf-scaled-anim.h"
31#include "gdk-pixbuf-loader.h"
32#include "gdk-pixbuf-marshal.h"
33
34/**
35 * GdkPixbufLoader:
36 *
37 * Incremental image loader.
38 *
39 * `GdkPixbufLoader` provides a way for applications to drive the
40 * process of loading an image, by letting them send the image data
41 * directly to the loader instead of having the loader read the data
42 * from a file. Applications can use this functionality instead of
43 * `gdk_pixbuf_new_from_file()` or `gdk_pixbuf_animation_new_from_file()`
44 * when they need to parse image data in small chunks. For example,
45 * it should be used when reading an image from a (potentially) slow
46 * network connection, or when loading an extremely large file.
47 *
48 * To use `GdkPixbufLoader` to load an image, create a new instance,
49 * and call [method@GdkPixbuf.PixbufLoader.write] to send the data
50 * to it. When done, [method@GdkPixbuf.PixbufLoader.close] should be
51 * called to end the stream and finalize everything.
52 *
53 * The loader will emit three important signals throughout the process:
54 *
55 * - [signal@GdkPixbuf.PixbufLoader::size-prepared] will be emitted as
56 * soon as the image has enough information to determine the size of
57 * the image to be used. If you want to scale the image while loading
58 * it, you can call [method@GdkPixbuf.PixbufLoader.set_size] in
59 * response to this signal.
60 * - [signal@GdkPixbuf.PixbufLoader::area-prepared] will be emitted as
61 * soon as the pixbuf of the desired has been allocated. You can obtain
62 * the `GdkPixbuf` instance by calling [method@GdkPixbuf.PixbufLoader.get_pixbuf].
63 * If you want to use it, simply acquire a reference to it. You can
64 * also call `gdk_pixbuf_loader_get_pixbuf()` later to get the same
65 * pixbuf.
66 * - [signal@GdkPixbuf.PixbufLoader::area-updated] will be emitted every
67 * time a region is updated. This way you can update a partially
68 * completed image. Note that you do not know anything about the
69 * completeness of an image from the updated area. For example, in an
70 * interlaced image you will need to make several passes before the
71 * image is done loading.
72 *
73 * ## Loading an animation
74 *
75 * Loading an animation is almost as easy as loading an image. Once the
76 * first [signal@GdkPixbuf.PixbufLoader::area-prepared] signal has been
77 * emitted, you can call [method@GdkPixbuf.PixbufLoader.get_animation] to
78 * get the [class@GdkPixbuf.PixbufAnimation] instance, and then call
79 * and [method@GdkPixbuf.PixbufAnimation.get_iter] to get a
80 * [class@GdkPixbuf.PixbufAnimationIter] to retrieve the pixbuf for the
81 * desired time stamp.
82 */
83
84
85enum {
86 SIZE_PREPARED,
87 AREA_PREPARED,
88 AREA_UPDATED,
89 CLOSED,
90 LAST_SIGNAL
91};
92
93
94static void gdk_pixbuf_loader_finalize (GObject *loader);
95
96static guint pixbuf_loader_signals[LAST_SIGNAL] = { 0 };
97
98/* Internal data */
99
100typedef struct
101{
102 GdkPixbufAnimation *animation;
103 gboolean closed;
104 guchar header_buf[SNIFF_BUFFER_SIZE];
105 gint header_buf_offset;
106 GdkPixbufModule *image_module;
107 gpointer context;
108 gint original_width;
109 gint original_height;
110 gint width;
111 gint height;
112 gboolean size_fixed;
113 gboolean needs_scale;
114 gchar *filename;
115} GdkPixbufLoaderPrivate;
116
117G_DEFINE_TYPE (GdkPixbufLoader, gdk_pixbuf_loader, G_TYPE_OBJECT)
118
119
120static void
121gdk_pixbuf_loader_class_init (GdkPixbufLoaderClass *class)
122{
123 GObjectClass *object_class;
124
125 object_class = (GObjectClass *) class;
126
127 object_class->finalize = gdk_pixbuf_loader_finalize;
128
129 /**
130 * GdkPixbufLoader::size-prepared:
131 * @loader: the object which received the signal.
132 * @width: the original width of the image
133 * @height: the original height of the image
134 *
135 * This signal is emitted when the pixbuf loader has been fed the
136 * initial amount of data that is required to figure out the size
137 * of the image that it will create.
138 *
139 * Applications can call gdk_pixbuf_loader_set_size() in response
140 * to this signal to set the desired size to which the image
141 * should be scaled.
142 */
143 pixbuf_loader_signals[SIZE_PREPARED] =
144 g_signal_new (signal_name: "size-prepared",
145 G_TYPE_FROM_CLASS (object_class),
146 signal_flags: G_SIGNAL_RUN_LAST,
147 G_STRUCT_OFFSET (GdkPixbufLoaderClass, size_prepared),
148 NULL, NULL,
149 c_marshaller: _gdk_pixbuf_marshal_VOID__INT_INT,
150 G_TYPE_NONE, n_params: 2,
151 G_TYPE_INT,
152 G_TYPE_INT);
153
154 /**
155 * GdkPixbufLoader::area-prepared:
156 * @loader: the object which received the signal.
157 *
158 * This signal is emitted when the pixbuf loader has allocated the
159 * pixbuf in the desired size.
160 *
161 * After this signal is emitted, applications can call
162 * gdk_pixbuf_loader_get_pixbuf() to fetch the partially-loaded
163 * pixbuf.
164 */
165 pixbuf_loader_signals[AREA_PREPARED] =
166 g_signal_new (signal_name: "area-prepared",
167 G_TYPE_FROM_CLASS (object_class),
168 signal_flags: G_SIGNAL_RUN_LAST,
169 G_STRUCT_OFFSET (GdkPixbufLoaderClass, area_prepared),
170 NULL, NULL,
171 c_marshaller: _gdk_pixbuf_marshal_VOID__VOID,
172 G_TYPE_NONE, n_params: 0);
173
174 /**
175 * GdkPixbufLoader::area-updated:
176 * @loader: the object which received the signal.
177 * @x: X offset of upper-left corner of the updated area.
178 * @y: Y offset of upper-left corner of the updated area.
179 * @width: Width of updated area.
180 * @height: Height of updated area.
181 *
182 * This signal is emitted when a significant area of the image being
183 * loaded has been updated.
184 *
185 * Normally it means that a complete scanline has been read in, but
186 * it could be a different area as well.
187 *
188 * Applications can use this signal to know when to repaint
189 * areas of an image that is being loaded.
190 */
191 pixbuf_loader_signals[AREA_UPDATED] =
192 g_signal_new (signal_name: "area-updated",
193 G_TYPE_FROM_CLASS (object_class),
194 signal_flags: G_SIGNAL_RUN_LAST,
195 G_STRUCT_OFFSET (GdkPixbufLoaderClass, area_updated),
196 NULL, NULL,
197 c_marshaller: _gdk_pixbuf_marshal_VOID__INT_INT_INT_INT,
198 G_TYPE_NONE, n_params: 4,
199 G_TYPE_INT,
200 G_TYPE_INT,
201 G_TYPE_INT,
202 G_TYPE_INT);
203
204 /**
205 * GdkPixbufLoader::closed:
206 * @loader: the object which received the signal.
207 *
208 * This signal is emitted when gdk_pixbuf_loader_close() is called.
209 *
210 * It can be used by different parts of an application to receive
211 * notification when an image loader is closed by the code that
212 * drives it.
213 */
214 pixbuf_loader_signals[CLOSED] =
215 g_signal_new (signal_name: "closed",
216 G_TYPE_FROM_CLASS (object_class),
217 signal_flags: G_SIGNAL_RUN_LAST,
218 G_STRUCT_OFFSET (GdkPixbufLoaderClass, closed),
219 NULL, NULL,
220 c_marshaller: _gdk_pixbuf_marshal_VOID__VOID,
221 G_TYPE_NONE, n_params: 0);
222}
223
224static void
225gdk_pixbuf_loader_init (GdkPixbufLoader *loader)
226{
227 GdkPixbufLoaderPrivate *priv;
228
229 priv = g_new0 (GdkPixbufLoaderPrivate, 1);
230 priv->original_width = -1;
231 priv->original_height = -1;
232 priv->width = -1;
233 priv->height = -1;
234
235 loader->priv = priv;
236}
237
238static void
239gdk_pixbuf_loader_finalize (GObject *object)
240{
241 GdkPixbufLoader *loader;
242 GdkPixbufLoaderPrivate *priv = NULL;
243
244 loader = GDK_PIXBUF_LOADER (object);
245 priv = loader->priv;
246
247 if (!priv->closed) {
248 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.");
249 }
250 if (priv->animation)
251 g_object_unref (object: priv->animation);
252
253 g_free (mem: priv->filename);
254
255 g_free (mem: priv);
256
257 G_OBJECT_CLASS (gdk_pixbuf_loader_parent_class)->finalize (object);
258}
259
260/**
261 * gdk_pixbuf_loader_set_size:
262 * @loader: A pixbuf loader.
263 * @width: The desired width of the image being loaded.
264 * @height: The desired height of the image being loaded.
265 *
266 * Causes the image to be scaled while it is loaded.
267 *
268 * The desired image size can be determined relative to the original
269 * size of the image by calling gdk_pixbuf_loader_set_size() from a
270 * signal handler for the ::size-prepared signal.
271 *
272 * Attempts to set the desired image size are ignored after the
273 * emission of the ::size-prepared signal.
274 *
275 * Since: 2.2
276 */
277void
278gdk_pixbuf_loader_set_size (GdkPixbufLoader *loader,
279 gint width,
280 gint height)
281{
282 GdkPixbufLoaderPrivate *priv;
283
284 g_return_if_fail (GDK_IS_PIXBUF_LOADER (loader));
285 g_return_if_fail (width >= 0 && height >= 0);
286
287 priv = GDK_PIXBUF_LOADER (loader)->priv;
288
289 if (!priv->size_fixed)
290 {
291 priv->width = width;
292 priv->height = height;
293 }
294}
295
296static void
297gdk_pixbuf_loader_size_func (gint *width, gint *height, gpointer loader)
298{
299 GdkPixbufLoaderPrivate *priv = GDK_PIXBUF_LOADER (loader)->priv;
300
301 priv->original_width = *width;
302 priv->original_height = *height;
303
304 /* allow calling gdk_pixbuf_loader_set_size() before the signal */
305 if (priv->width == -1 && priv->height == -1)
306 {
307 priv->width = *width;
308 priv->height = *height;
309 }
310
311 g_signal_emit (instance: loader, signal_id: pixbuf_loader_signals[SIZE_PREPARED], detail: 0, *width, *height);
312 priv->size_fixed = TRUE;
313
314 *width = priv->width;
315 *height = priv->height;
316}
317
318static void
319gdk_pixbuf_loader_prepare (GdkPixbuf *pixbuf,
320 GdkPixbufAnimation *anim,
321 gpointer loader)
322{
323 GdkPixbufLoaderPrivate *priv = GDK_PIXBUF_LOADER (loader)->priv;
324 gint width, height;
325 g_return_if_fail (pixbuf != NULL);
326
327 width = anim ? gdk_pixbuf_animation_get_width (animation: anim) :
328 gdk_pixbuf_get_width (pixbuf);
329 height = anim ? gdk_pixbuf_animation_get_height (animation: anim) :
330 gdk_pixbuf_get_height (pixbuf);
331
332 if (!priv->size_fixed)
333 {
334 gint w = width;
335 gint h = height;
336 /* Defend against lazy loaders which don't call size_func */
337 gdk_pixbuf_loader_size_func (width: &w, height: &h, loader);
338 }
339
340 priv->needs_scale = FALSE;
341 if (priv->width > 0 && priv->height > 0 &&
342 (priv->width != width || priv->height != height))
343 priv->needs_scale = TRUE;
344
345 if (anim)
346 g_object_ref (anim);
347 else {
348 if (priv->original_width > 0) {
349 char *original_width_str = NULL;
350
351 original_width_str = g_strdup_printf (format: "%d", priv->original_width);
352 gdk_pixbuf_set_option (pixbuf, key: "original-width", value: original_width_str);
353 g_free (mem: original_width_str);
354 }
355
356 if (priv->original_height > 0) {
357 char *original_height_str = NULL;
358
359 original_height_str = g_strdup_printf (format: "%d", priv->original_height);
360 gdk_pixbuf_set_option (pixbuf, key: "original-height", value: original_height_str);
361 g_free (mem: original_height_str);
362 }
363
364 anim = gdk_pixbuf_non_anim_new (pixbuf);
365 }
366
367 if (priv->needs_scale && width != 0 && height != 0) {
368 priv->animation = GDK_PIXBUF_ANIMATION (_gdk_pixbuf_scaled_anim_new (anim,
369 (double) priv->width / width,
370 (double) priv->height / height,
371 1.0));
372 g_object_unref (object: anim);
373 }
374 else
375 priv->animation = anim;
376
377 if (!priv->needs_scale)
378 g_signal_emit (instance: loader, signal_id: pixbuf_loader_signals[AREA_PREPARED], detail: 0);
379}
380
381static void
382gdk_pixbuf_loader_update (GdkPixbuf *pixbuf,
383 gint x,
384 gint y,
385 gint width,
386 gint height,
387 gpointer loader)
388{
389 GdkPixbufLoaderPrivate *priv = GDK_PIXBUF_LOADER (loader)->priv;
390
391 if (!priv->needs_scale)
392 g_signal_emit (instance: loader,
393 signal_id: pixbuf_loader_signals[AREA_UPDATED],
394 detail: 0,
395 x, y,
396 /* sanity check in here. Defend against an errant loader */
397 MIN (width, gdk_pixbuf_animation_get_width (priv->animation)),
398 MIN (height, gdk_pixbuf_animation_get_height (priv->animation)));
399}
400
401/* Defense against broken loaders; DO NOT take this as a GError example! */
402static void
403gdk_pixbuf_loader_ensure_error (GdkPixbufLoader *loader,
404 GError **error)
405{
406 GdkPixbufLoaderPrivate *priv = loader->priv;
407
408 if (error == NULL || *error != NULL)
409 return;
410
411 g_warning ("Bug! loader '%s' didn't set an error on failure",
412 priv->image_module->module_name);
413 g_set_error (err: error,
414 GDK_PIXBUF_ERROR,
415 code: GDK_PIXBUF_ERROR_FAILED,
416 _("Internal error: Image loader module “%s” failed to"
417 " complete an operation, but didn’t give a reason for"
418 " the failure"),
419 priv->image_module->module_name);
420}
421
422static gint
423gdk_pixbuf_loader_load_module (GdkPixbufLoader *loader,
424 const char *image_type,
425 GError **error)
426{
427 GdkPixbufLoaderPrivate *priv = loader->priv;
428
429 if (image_type)
430 {
431 priv->image_module = _gdk_pixbuf_get_named_module (name: image_type,
432 error);
433 }
434 else
435 {
436 priv->image_module = _gdk_pixbuf_get_module (buffer: priv->header_buf,
437 size: priv->header_buf_offset,
438 filename: priv->filename,
439 error);
440 }
441
442 if (priv->image_module == NULL)
443 return 0;
444
445 if (!_gdk_pixbuf_load_module (image_module: priv->image_module, error))
446 return 0;
447
448 if (priv->image_module->module == NULL)
449 return 0;
450
451 if ((priv->image_module->begin_load == NULL) ||
452 (priv->image_module->stop_load == NULL) ||
453 (priv->image_module->load_increment == NULL))
454 {
455 g_set_error (err: error,
456 GDK_PIXBUF_ERROR,
457 code: GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
458 _("Incremental loading of image type “%s” is not supported"),
459 priv->image_module->module_name);
460
461 return 0;
462 }
463
464 priv->context = priv->image_module->begin_load (gdk_pixbuf_loader_size_func,
465 gdk_pixbuf_loader_prepare,
466 gdk_pixbuf_loader_update,
467 loader,
468 error);
469
470 if (priv->context == NULL)
471 {
472 gdk_pixbuf_loader_ensure_error (loader, error);
473 return 0;
474 }
475
476 if (priv->header_buf_offset
477 && priv->image_module->load_increment (priv->context, priv->header_buf, priv->header_buf_offset, error))
478 return priv->header_buf_offset;
479
480 return 0;
481}
482
483static int
484gdk_pixbuf_loader_eat_header_write (GdkPixbufLoader *loader,
485 const guchar *buf,
486 gsize count,
487 GError **error)
488{
489 gint n_bytes;
490 GdkPixbufLoaderPrivate *priv = loader->priv;
491
492 n_bytes = MIN(SNIFF_BUFFER_SIZE - priv->header_buf_offset, count);
493 memcpy (dest: priv->header_buf + priv->header_buf_offset, src: buf, n: n_bytes);
494
495 priv->header_buf_offset += n_bytes;
496
497 if (priv->header_buf_offset >= SNIFF_BUFFER_SIZE)
498 {
499 if (gdk_pixbuf_loader_load_module (loader, NULL, error) == 0)
500 return 0;
501 }
502
503 return n_bytes;
504}
505
506/**
507 * gdk_pixbuf_loader_write:
508 * @loader: A pixbuf loader.
509 * @buf: (array length=count): Pointer to image data.
510 * @count: Length of the @buf buffer in bytes.
511 * @error: return location for errors
512 *
513 * Parses the next `count` bytes in the given image buffer.
514 *
515 * Return value: `TRUE` if the write was successful, or
516 * `FALSE` if the loader cannot parse the buffer
517 **/
518gboolean
519gdk_pixbuf_loader_write (GdkPixbufLoader *loader,
520 const guchar *buf,
521 gsize count,
522 GError **error)
523{
524 GdkPixbufLoaderPrivate *priv;
525
526 g_return_val_if_fail (GDK_IS_PIXBUF_LOADER (loader), FALSE);
527
528 g_return_val_if_fail (buf != NULL, FALSE);
529 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
530
531 priv = loader->priv;
532
533 /* we expect it's not to be closed */
534 g_return_val_if_fail (priv->closed == FALSE, FALSE);
535
536 if (count > 0 && priv->image_module == NULL)
537 {
538 gint eaten;
539
540 eaten = gdk_pixbuf_loader_eat_header_write (loader, buf, count, error);
541 if (eaten <= 0)
542 goto fail;
543
544 count -= eaten;
545 buf += eaten;
546 }
547
548 /* By this point, we expect the image_module to have been loaded. */
549 g_assert (count == 0 || priv->image_module != NULL);
550
551 if (count > 0 && priv->image_module->load_increment != NULL)
552 {
553 if (!priv->image_module->load_increment (priv->context, buf, count,
554 error))
555 goto fail;
556 }
557
558 return TRUE;
559
560 fail:
561 gdk_pixbuf_loader_ensure_error (loader, error);
562 gdk_pixbuf_loader_close (loader, NULL);
563
564 return FALSE;
565}
566
567/**
568 * gdk_pixbuf_loader_write_bytes:
569 * @loader: A pixbuf loader.
570 * @buffer: The image data as a `GBytes` buffer.
571 * @error: return location for errors
572 *
573 * Parses the next contents of the given image buffer.
574 *
575 * Return value: `TRUE` if the write was successful, or `FALSE` if
576 * the loader cannot parse the buffer
577 *
578 * Since: 2.30
579 */
580gboolean
581gdk_pixbuf_loader_write_bytes (GdkPixbufLoader *loader,
582 GBytes *buffer,
583 GError **error)
584{
585 g_return_val_if_fail (GDK_IS_PIXBUF_LOADER (loader), FALSE);
586
587 g_return_val_if_fail (buffer != NULL, FALSE);
588 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
589
590 return gdk_pixbuf_loader_write (loader,
591 buf: g_bytes_get_data (bytes: buffer, NULL),
592 count: g_bytes_get_size (bytes: buffer),
593 error);
594}
595
596/**
597 * gdk_pixbuf_loader_new:
598 *
599 * Creates a new pixbuf loader object.
600 *
601 * Return value: A newly-created pixbuf loader.
602 **/
603GdkPixbufLoader *
604gdk_pixbuf_loader_new (void)
605{
606 return g_object_new (GDK_TYPE_PIXBUF_LOADER, NULL);
607}
608
609/**
610 * gdk_pixbuf_loader_new_with_type:
611 * @image_type: name of the image format to be loaded with the image
612 * @error: (allow-none): return location for an allocated #GError, or `NULL` to ignore errors
613 *
614 * Creates a new pixbuf loader object that always attempts to parse
615 * image data as if it were an image of type @image_type, instead of
616 * identifying the type automatically.
617 *
618 * This function is useful if you want an error if the image isn't the
619 * expected type; for loading image formats that can't be reliably
620 * identified by looking at the data; or if the user manually forces
621 * a specific type.
622 *
623 * The list of supported image formats depends on what image loaders
624 * are installed, but typically "png", "jpeg", "gif", "tiff" and
625 * "xpm" are among the supported formats. To obtain the full list of
626 * supported image formats, call gdk_pixbuf_format_get_name() on each
627 * of the #GdkPixbufFormat structs returned by gdk_pixbuf_get_formats().
628 *
629 * Return value: A newly-created pixbuf loader.
630 **/
631GdkPixbufLoader *
632gdk_pixbuf_loader_new_with_type (const char *image_type,
633 GError **error)
634{
635 GdkPixbufLoader *retval;
636 GError *tmp;
637 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
638
639 retval = g_object_new (GDK_TYPE_PIXBUF_LOADER, NULL);
640
641 tmp = NULL;
642 gdk_pixbuf_loader_load_module (loader: retval, image_type, error: &tmp);
643 if (tmp != NULL)
644 {
645 g_propagate_error (dest: error, src: tmp);
646 gdk_pixbuf_loader_close (loader: retval, NULL);
647 g_object_unref (object: retval);
648 return NULL;
649 }
650
651 return retval;
652}
653
654/**
655 * gdk_pixbuf_loader_new_with_mime_type:
656 * @mime_type: the mime type to be loaded
657 * @error: (allow-none): return location for an allocated #GError, or `NULL` to ignore errors
658 *
659 * Creates a new pixbuf loader object that always attempts to parse
660 * image data as if it were an image of MIME type @mime_type, instead of
661 * identifying the type automatically.
662 *
663 * This function is useful if you want an error if the image isn't the
664 * expected MIME type; for loading image formats that can't be reliably
665 * identified by looking at the data; or if the user manually forces a
666 * specific MIME type.
667 *
668 * The list of supported mime types depends on what image loaders
669 * are installed, but typically "image/png", "image/jpeg", "image/gif",
670 * "image/tiff" and "image/x-xpixmap" are among the supported mime types.
671 * To obtain the full list of supported mime types, call
672 * gdk_pixbuf_format_get_mime_types() on each of the #GdkPixbufFormat
673 * structs returned by gdk_pixbuf_get_formats().
674 *
675 * Return value: A newly-created pixbuf loader.
676 *
677 * Since: 2.4
678 **/
679GdkPixbufLoader *
680gdk_pixbuf_loader_new_with_mime_type (const char *mime_type,
681 GError **error)
682{
683 const char * image_type = NULL;
684 char ** mimes;
685
686 GdkPixbufLoader *retval;
687 GError *tmp;
688
689 GSList * formats;
690 GdkPixbufFormat *info;
691 int i, j, length;
692
693 formats = gdk_pixbuf_get_formats ();
694 length = g_slist_length (list: formats);
695
696 for (i = 0; i < length && image_type == NULL; i++) {
697 info = (GdkPixbufFormat *)g_slist_nth_data (list: formats, n: i);
698 mimes = info->mime_types;
699
700 for (j = 0; mimes[j] != NULL; j++)
701 if (g_ascii_strcasecmp (s1: mimes[j], s2: mime_type) == 0) {
702 image_type = info->name;
703 break;
704 }
705 }
706
707 g_slist_free (list: formats);
708
709 retval = g_object_new (GDK_TYPE_PIXBUF_LOADER, NULL);
710
711 tmp = NULL;
712 gdk_pixbuf_loader_load_module (loader: retval, image_type, error: &tmp);
713 if (tmp != NULL)
714 {
715 g_propagate_error (dest: error, src: tmp);
716 gdk_pixbuf_loader_close (loader: retval, NULL);
717 g_object_unref (object: retval);
718 return NULL;
719 }
720
721 return retval;
722}
723
724GdkPixbufLoader *
725_gdk_pixbuf_loader_new_with_filename (const char *filename)
726{
727 GdkPixbufLoader *retval;
728 GdkPixbufLoaderPrivate *priv;
729
730 retval = g_object_new (GDK_TYPE_PIXBUF_LOADER, NULL);
731 priv = retval->priv;
732 priv->filename = g_strdup (str: filename);
733
734 return retval;
735}
736
737/**
738 * gdk_pixbuf_loader_get_pixbuf:
739 * @loader: A pixbuf loader.
740 *
741 * Queries the #GdkPixbuf that a pixbuf loader is currently creating.
742 *
743 * In general it only makes sense to call this function after the
744 * [signal@GdkPixbuf.PixbufLoader::area-prepared] signal has been
745 * emitted by the loader; this means that enough data has been read
746 * to know the size of the image that will be allocated.
747 *
748 * If the loader has not received enough data via gdk_pixbuf_loader_write(),
749 * then this function returns `NULL`.
750 *
751 * The returned pixbuf will be the same in all future calls to the loader,
752 * so if you want to keep using it, you should acquire a reference to it.
753 *
754 * Additionally, if the loader is an animation, it will return the "static
755 * image" of the animation (see gdk_pixbuf_animation_get_static_image()).
756 *
757 * Return value: (transfer none) (nullable): The pixbuf that the loader is
758 * creating
759 **/
760GdkPixbuf *
761gdk_pixbuf_loader_get_pixbuf (GdkPixbufLoader *loader)
762{
763 GdkPixbufLoaderPrivate *priv;
764
765 g_return_val_if_fail (GDK_IS_PIXBUF_LOADER (loader), NULL);
766
767 priv = loader->priv;
768
769 if (priv->animation)
770 return gdk_pixbuf_animation_get_static_image (animation: priv->animation);
771 else
772 return NULL;
773}
774
775/**
776 * gdk_pixbuf_loader_get_animation:
777 * @loader: A pixbuf loader
778 *
779 * Queries the #GdkPixbufAnimation that a pixbuf loader is currently creating.
780 *
781 * In general it only makes sense to call this function after the
782 * [signal@GdkPixbuf.PixbufLoader::area-prepared] signal has been emitted by
783 * the loader.
784 *
785 * If the loader doesn't have enough bytes yet, and hasn't emitted the `area-prepared`
786 * signal, this function will return `NULL`.
787 *
788 * Return value: (transfer none) (nullable): The animation that the loader is
789 * currently loading
790 */
791GdkPixbufAnimation *
792gdk_pixbuf_loader_get_animation (GdkPixbufLoader *loader)
793{
794 GdkPixbufLoaderPrivate *priv;
795
796 g_return_val_if_fail (GDK_IS_PIXBUF_LOADER (loader), NULL);
797
798 priv = loader->priv;
799
800 return priv->animation;
801}
802
803/**
804 * gdk_pixbuf_loader_close:
805 * @loader: A pixbuf loader.
806 * @error: (allow-none): return location for a #GError, or `NULL` to ignore errors
807 *
808 * Informs a pixbuf loader that no further writes with
809 * gdk_pixbuf_loader_write() will occur, so that it can free its
810 * internal loading structures.
811 *
812 * This function also tries to parse any data that hasn't yet been parsed;
813 * if the remaining data is partial or corrupt, an error will be returned.
814 *
815 * If `FALSE` is returned, `error` will be set to an error from the
816 * `GDK_PIXBUF_ERROR` or `G_FILE_ERROR` domains.
817 *
818 * If you're just cancelling a load rather than expecting it to be finished,
819 * passing `NULL` for `error` to ignore it is reasonable.
820 *
821 * Remember that this function does not release a reference on the loader, so
822 * you will need to explicitly release any reference you hold.
823 *
824 * Returns: `TRUE` if all image data written so far was successfully
825 * passed out via the update_area signal
826 */
827gboolean
828gdk_pixbuf_loader_close (GdkPixbufLoader *loader,
829 GError **error)
830{
831 GdkPixbufLoaderPrivate *priv;
832 gboolean retval = TRUE;
833
834 g_return_val_if_fail (GDK_IS_PIXBUF_LOADER (loader), TRUE);
835 g_return_val_if_fail (error == NULL || *error == NULL, TRUE);
836
837 priv = loader->priv;
838
839 if (priv->closed)
840 return TRUE;
841
842 /* We have less than SNIFF_BUFFER_SIZE bytes in the image.
843 * Flush it, and keep going.
844 */
845 if (priv->image_module == NULL)
846 {
847 GError *tmp = NULL;
848 gdk_pixbuf_loader_load_module (loader, NULL, error: &tmp);
849 if (tmp != NULL)
850 {
851 g_propagate_error (dest: error, src: tmp);
852 retval = FALSE;
853 }
854 }
855
856 if (priv->image_module && priv->image_module->stop_load && priv->context)
857 {
858 GError *tmp = NULL;
859 if (!priv->image_module->stop_load (priv->context, &tmp) || tmp)
860 {
861 /* don't call gdk_pixbuf_loader_ensure_error()
862 * here, since we might not get an error in the
863 * gdk_pixbuf_get_file_info() case
864 */
865 if (tmp) {
866 if (error && *error == NULL)
867 g_propagate_error (dest: error, src: tmp);
868 else
869 g_error_free (error: tmp);
870 }
871 retval = FALSE;
872 }
873 }
874
875 priv->closed = TRUE;
876
877 if (priv->needs_scale)
878 {
879
880 g_signal_emit (instance: loader, signal_id: pixbuf_loader_signals[AREA_PREPARED], detail: 0);
881 g_signal_emit (instance: loader, signal_id: pixbuf_loader_signals[AREA_UPDATED], detail: 0,
882 0, 0, priv->width, priv->height);
883 }
884
885
886 g_signal_emit (instance: loader, signal_id: pixbuf_loader_signals[CLOSED], detail: 0);
887
888 return retval;
889}
890
891/**
892 * gdk_pixbuf_loader_get_format:
893 * @loader: A pixbuf loader.
894 *
895 * Obtains the available information about the format of the
896 * currently loading image file.
897 *
898 * Returns: (nullable) (transfer none): A #GdkPixbufFormat
899 *
900 * Since: 2.2
901 */
902GdkPixbufFormat *
903gdk_pixbuf_loader_get_format (GdkPixbufLoader *loader)
904{
905 GdkPixbufLoaderPrivate *priv;
906
907 g_return_val_if_fail (GDK_IS_PIXBUF_LOADER (loader), NULL);
908
909 priv = loader->priv;
910
911 if (priv->image_module)
912 return _gdk_pixbuf_get_format (image_module: priv->image_module);
913 else
914 return NULL;
915}
916

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