1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2/* GdkPixbuf library - Basic memory management
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 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
22 */
23
24/**
25 * GdkPixbuf:
26 *
27 * A pixel buffer.
28 *
29 * `GdkPixbuf` contains information about an image's pixel data,
30 * its color space, bits per sample, width and height, and the
31 * rowstride (the number of bytes between the start of one row
32 * and the start of the next).
33 *
34 * ## Creating new `GdkPixbuf`
35 *
36 * The most basic way to create a pixbuf is to wrap an existing pixel
37 * buffer with a [class@GdkPixbuf.Pixbuf] instance. You can use the
38 * [`ctor@GdkPixbuf.Pixbuf.new_from_data`] function to do this.
39 *
40 * Every time you create a new `GdkPixbuf` instance for some data, you
41 * will need to specify the destroy notification function that will be
42 * called when the data buffer needs to be freed; this will happen when
43 * a `GdkPixbuf` is finalized by the reference counting functions. If
44 * you have a chunk of static data compiled into your application, you
45 * can pass in `NULL` as the destroy notification function so that the
46 * data will not be freed.
47 *
48 * The [`ctor@GdkPixbuf.Pixbuf.new`] constructor function can be used
49 * as a convenience to create a pixbuf with an empty buffer; this is
50 * equivalent to allocating a data buffer using `malloc()` and then
51 * wrapping it with `gdk_pixbuf_new_from_data()`. The `gdk_pixbuf_new()`
52 * function will compute an optimal rowstride so that rendering can be
53 * performed with an efficient algorithm.
54 *
55 * As a special case, you can use the [`ctor@GdkPixbuf.Pixbuf.new_from_xpm_data`]
56 * function to create a pixbuf from inline XPM image data.
57 *
58 * You can also copy an existing pixbuf with the [method@Pixbuf.copy]
59 * function. This is not the same as just acquiring a reference to
60 * the old pixbuf instance: the copy function will actually duplicate
61 * the pixel data in memory and create a new [class@Pixbuf] instance
62 * for it.
63 *
64 * ## Reference counting
65 *
66 * `GdkPixbuf` structures are reference counted. This means that an
67 * application can share a single pixbuf among many parts of the
68 * code. When a piece of the program needs to use a pixbuf, it should
69 * acquire a reference to it by calling `g_object_ref()`; when it no
70 * longer needs the pixbuf, it should release the reference it acquired
71 * by calling `g_object_unref()`. The resources associated with a
72 * `GdkPixbuf` will be freed when its reference count drops to zero.
73 * Newly-created `GdkPixbuf` instances start with a reference count
74 * of one.
75 *
76 * ## Image Data
77 *
78 * Image data in a pixbuf is stored in memory in an uncompressed,
79 * packed format. Rows in the image are stored top to bottom, and
80 * in each row pixels are stored from left to right.
81 *
82 * There may be padding at the end of a row.
83 *
84 * The "rowstride" value of a pixbuf, as returned by [`method@GdkPixbuf.Pixbuf.get_rowstride`],
85 * indicates the number of bytes between rows.
86 *
87 * **NOTE**: If you are copying raw pixbuf data with `memcpy()` note that the
88 * last row in the pixbuf may not be as wide as the full rowstride, but rather
89 * just as wide as the pixel data needs to be; that is: it is unsafe to do
90 * `memcpy (dest, pixels, rowstride * height)` to copy a whole pixbuf. Use
91 * [method@GdkPixbuf.Pixbuf.copy] instead, or compute the width in bytes of the
92 * last row as:
93 *
94 * ```c
95 * last_row = width * ((n_channels * bits_per_sample + 7) / 8);
96 * ```
97 *
98 * The same rule applies when iterating over each row of a `GdkPixbuf` pixels
99 * array.
100 *
101 * The following code illustrates a simple `put_pixel()`
102 * function for RGB pixbufs with 8 bits per channel with an alpha
103 * channel.
104 *
105 * ```c
106 * static void
107 * put_pixel (GdkPixbuf *pixbuf,
108 * int x,
109 * int y,
110 * guchar red,
111 * guchar green,
112 * guchar blue,
113 * guchar alpha)
114 * {
115 * int n_channels = gdk_pixbuf_get_n_channels (pixbuf);
116 *
117 * // Ensure that the pixbuf is valid
118 * g_assert (gdk_pixbuf_get_colorspace (pixbuf) == GDK_COLORSPACE_RGB);
119 * g_assert (gdk_pixbuf_get_bits_per_sample (pixbuf) == 8);
120 * g_assert (gdk_pixbuf_get_has_alpha (pixbuf));
121 * g_assert (n_channels == 4);
122 *
123 * int width = gdk_pixbuf_get_width (pixbuf);
124 * int height = gdk_pixbuf_get_height (pixbuf);
125 *
126 * // Ensure that the coordinates are in a valid range
127 * g_assert (x >= 0 && x < width);
128 * g_assert (y >= 0 && y < height);
129 *
130 * int rowstride = gdk_pixbuf_get_rowstride (pixbuf);
131 *
132 * // The pixel buffer in the GdkPixbuf instance
133 * guchar *pixels = gdk_pixbuf_get_pixels (pixbuf);
134 *
135 * // The pixel we wish to modify
136 * guchar *p = pixels + y * rowstride + x * n_channels;
137 * p[0] = red;
138 * p[1] = green;
139 * p[2] = blue;
140 * p[3] = alpha;
141 * }
142 * ```
143 *
144 * ## Loading images
145 *
146 * The `GdkPixBuf` class provides a simple mechanism for loading
147 * an image from a file in synchronous and asynchronous fashion.
148 *
149 * For GUI applications, it is recommended to use the asynchronous
150 * stream API to avoid blocking the control flow of the application.
151 *
152 * Additionally, `GdkPixbuf` provides the [class@GdkPixbuf.PixbufLoader`]
153 * API for progressive image loading.
154 *
155 * ## Saving images
156 *
157 * The `GdkPixbuf` class provides methods for saving image data in
158 * a number of file formats. The formatted data can be written to a
159 * file or to a memory buffer. `GdkPixbuf` can also call a user-defined
160 * callback on the data, which allows to e.g. write the image
161 * to a socket or store it in a database.
162 */
163
164#include "config.h"
165
166#include <math.h>
167#include <stdlib.h>
168#include <string.h>
169
170#define GDK_PIXBUF_C_COMPILATION
171#include "gdk-pixbuf-private.h"
172#include "gdk-pixbuf-features.h"
173#include "gdk-pixbuf-enum-types.h"
174
175/* Include the marshallers */
176#include <glib-object.h>
177#include <gio/gio.h>
178#include "gdk-pixbuf-marshal.h"
179
180static void gdk_pixbuf_finalize (GObject *object);
181static void gdk_pixbuf_set_property (GObject *object,
182 guint prop_id,
183 const GValue *value,
184 GParamSpec *pspec);
185static void gdk_pixbuf_get_property (GObject *object,
186 guint prop_id,
187 GValue *value,
188 GParamSpec *pspec);
189static void gdk_pixbuf_constructed (GObject *object);
190
191
192enum
193{
194 PROP_0,
195 PROP_COLORSPACE,
196 PROP_N_CHANNELS,
197 PROP_HAS_ALPHA,
198 PROP_BITS_PER_SAMPLE,
199 PROP_WIDTH,
200 PROP_HEIGHT,
201 PROP_ROWSTRIDE,
202 PROP_PIXELS,
203 PROP_PIXEL_BYTES
204};
205
206static void gdk_pixbuf_icon_iface_init (GIconIface *iface);
207static void gdk_pixbuf_loadable_icon_iface_init (GLoadableIconIface *iface);
208
209G_DEFINE_TYPE_WITH_CODE (GdkPixbuf, gdk_pixbuf, G_TYPE_OBJECT,
210 G_IMPLEMENT_INTERFACE (G_TYPE_ICON, gdk_pixbuf_icon_iface_init)
211 G_IMPLEMENT_INTERFACE (G_TYPE_LOADABLE_ICON, gdk_pixbuf_loadable_icon_iface_init))
212
213static void
214gdk_pixbuf_init (GdkPixbuf *pixbuf)
215{
216 pixbuf->colorspace = GDK_COLORSPACE_RGB;
217 pixbuf->n_channels = 3;
218 pixbuf->bits_per_sample = 8;
219 pixbuf->has_alpha = FALSE;
220 pixbuf->storage = STORAGE_UNINITIALIZED;
221}
222
223static void
224gdk_pixbuf_class_init (GdkPixbufClass *klass)
225{
226 GObjectClass *object_class = G_OBJECT_CLASS (klass);
227
228 _gdk_pixbuf_init_gettext ();
229
230 object_class->finalize = gdk_pixbuf_finalize;
231 object_class->set_property = gdk_pixbuf_set_property;
232 object_class->get_property = gdk_pixbuf_get_property;
233 object_class->constructed = gdk_pixbuf_constructed;
234
235#define PIXBUF_PARAM_FLAGS G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY|\
236 G_PARAM_EXPLICIT_NOTIFY|\
237 G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
238 /**
239 * GdkPixbuf:n-channels:
240 *
241 * The number of samples per pixel.
242 *
243 * Currently, only 3 or 4 samples per pixel are supported.
244 */
245 g_object_class_install_property (oclass: object_class,
246 property_id: PROP_N_CHANNELS,
247 pspec: g_param_spec_int (name: "n-channels",
248 _("Number of Channels"),
249 _("The number of samples per pixel"),
250 minimum: 0,
251 G_MAXINT,
252 default_value: 3,
253 PIXBUF_PARAM_FLAGS));
254 /**
255 * GdkPixbuf:colorspace:
256 *
257 * The color space of the pixbuf.
258 *
259 * Currently, only `GDK_COLORSPACE_RGB` is supported.
260 */
261 g_object_class_install_property (oclass: object_class,
262 property_id: PROP_COLORSPACE,
263 pspec: g_param_spec_enum (name: "colorspace",
264 _("Colorspace"),
265 _("The colorspace in which the samples are interpreted"),
266 enum_type: GDK_TYPE_COLORSPACE,
267 default_value: GDK_COLORSPACE_RGB,
268 PIXBUF_PARAM_FLAGS));
269 /**
270 * GdkPixbuf:has-alpha:
271 *
272 * Whether the pixbuf has an alpha channel.
273 */
274 g_object_class_install_property (oclass: object_class,
275 property_id: PROP_HAS_ALPHA,
276 pspec: g_param_spec_boolean (name: "has-alpha",
277 _("Has Alpha"),
278 _("Whether the pixbuf has an alpha channel"),
279 FALSE,
280 PIXBUF_PARAM_FLAGS));
281 /**
282 * GdkPixbuf:bits-per-sample:
283 *
284 * The number of bits per sample.
285 *
286 * Currently only 8 bit per sample are supported.
287 */
288 g_object_class_install_property (oclass: object_class,
289 property_id: PROP_BITS_PER_SAMPLE,
290 pspec: g_param_spec_int (name: "bits-per-sample",
291 _("Bits per Sample"),
292 _("The number of bits per sample"),
293 minimum: 1,
294 maximum: 16,
295 default_value: 8,
296 PIXBUF_PARAM_FLAGS));
297 /**
298 * GdkPixbuf:width:
299 *
300 * The number of columns of the pixbuf.
301 */
302 g_object_class_install_property (oclass: object_class,
303 property_id: PROP_WIDTH,
304 pspec: g_param_spec_int (name: "width",
305 _("Width"),
306 _("The number of columns of the pixbuf"),
307 minimum: 1,
308 G_MAXINT,
309 default_value: 1,
310 PIXBUF_PARAM_FLAGS));
311 /**
312 * GdkPixbuf:height:
313 *
314 * The number of rows of the pixbuf.
315 */
316 g_object_class_install_property (oclass: object_class,
317 property_id: PROP_HEIGHT,
318 pspec: g_param_spec_int (name: "height",
319 _("Height"),
320 _("The number of rows of the pixbuf"),
321 minimum: 1,
322 G_MAXINT,
323 default_value: 1,
324 PIXBUF_PARAM_FLAGS));
325 /**
326 * GdkPixbuf:rowstride:
327 *
328 * The number of bytes between the start of a row and
329 * the start of the next row.
330 *
331 * This number must (obviously) be at least as large as the
332 * width of the pixbuf.
333 */
334 g_object_class_install_property (oclass: object_class,
335 property_id: PROP_ROWSTRIDE,
336 pspec: g_param_spec_int (name: "rowstride",
337 _("Rowstride"),
338 _("The number of bytes between the start of a row and the start of the next row"),
339 minimum: 1,
340 G_MAXINT,
341 default_value: 1,
342 PIXBUF_PARAM_FLAGS));
343 /**
344 * GdkPixbuf:pixels:
345 *
346 * A pointer to the pixel data of the pixbuf.
347 */
348 g_object_class_install_property (oclass: object_class,
349 property_id: PROP_PIXELS,
350 pspec: g_param_spec_pointer (name: "pixels",
351 _("Pixels"),
352 _("A pointer to the pixel data of the pixbuf"),
353 PIXBUF_PARAM_FLAGS));
354 /**
355 * GdkPixbuf::pixel-bytes:
356 *
357 * If set, this pixbuf was created from read-only #GBytes.
358 *
359 * Replaces GdkPixbuf::pixels.
360 *
361 * Since: 2.32
362 */
363 g_object_class_install_property (oclass: object_class,
364 property_id: PROP_PIXEL_BYTES,
365 pspec: g_param_spec_boxed (name: "pixel-bytes",
366 _("Pixel Bytes"),
367 _("Readonly pixel data"),
368 G_TYPE_BYTES,
369 PIXBUF_PARAM_FLAGS));
370}
371
372static void
373free_pixels (GdkPixbuf *pixbuf)
374{
375 g_assert (pixbuf->storage == STORAGE_PIXELS);
376
377 if (pixbuf->s.pixels.pixels && pixbuf->s.pixels.destroy_fn) {
378 (* pixbuf->s.pixels.destroy_fn) (pixbuf->s.pixels.pixels, pixbuf->s.pixels.destroy_fn_data);
379 }
380
381 pixbuf->s.pixels.pixels = NULL;
382}
383
384static void
385free_bytes (GdkPixbuf *pixbuf)
386{
387 g_assert (pixbuf->storage == STORAGE_BYTES);
388
389 g_clear_pointer (&pixbuf->s.bytes.bytes, g_bytes_unref);
390}
391
392static void
393gdk_pixbuf_finalize (GObject *object)
394{
395 GdkPixbuf *pixbuf = GDK_PIXBUF (object);
396
397 switch (pixbuf->storage) {
398 case STORAGE_PIXELS:
399 free_pixels (pixbuf);
400 break;
401
402 case STORAGE_BYTES:
403 free_bytes (pixbuf);
404 break;
405
406 default:
407 g_assert_not_reached ();
408 }
409
410 G_OBJECT_CLASS (gdk_pixbuf_parent_class)->finalize (object);
411}
412
413
414/**
415 * gdk_pixbuf_ref: (skip)
416 * @pixbuf: A pixbuf.
417 *
418 * Adds a reference to a pixbuf.
419 *
420 * Return value: The same as the @pixbuf argument.
421 *
422 * Deprecated: 2.0: Use g_object_ref().
423 **/
424GdkPixbuf *
425gdk_pixbuf_ref (GdkPixbuf *pixbuf)
426{
427 return (GdkPixbuf *) g_object_ref (pixbuf);
428}
429
430/**
431 * gdk_pixbuf_unref: (skip)
432 * @pixbuf: A pixbuf.
433 *
434 * Removes a reference from a pixbuf.
435 *
436 * Deprecated: 2.0: Use g_object_unref().
437 **/
438void
439gdk_pixbuf_unref (GdkPixbuf *pixbuf)
440{
441 g_object_unref (object: pixbuf);
442}
443
444static GBytes *
445gdk_pixbuf_make_bytes (GdkPixbuf *pixbuf,
446 GError **error)
447{
448 gchar *buffer;
449 gsize size;
450
451 if (!gdk_pixbuf_save_to_buffer (pixbuf, buffer: &buffer, buffer_size: &size, type: "png", error, NULL))
452 return NULL;
453
454 return g_bytes_new_take (data: buffer, size);
455}
456
457static GVariant *
458gdk_pixbuf_serialize (GIcon *icon)
459{
460 GError *error = NULL;
461 GVariant *result;
462 GBytes *bytes;
463
464 bytes = gdk_pixbuf_make_bytes (GDK_PIXBUF (icon), error: &error);
465 if (!bytes)
466 {
467 g_critical ("Unable to serialise GdkPixbuf to png (via g_icon_serialize()): %s", error->message);
468 g_error_free (error);
469 return NULL;
470 }
471 result = g_variant_new_from_bytes (G_VARIANT_TYPE_BYTESTRING, bytes, TRUE);
472 g_bytes_unref (bytes);
473
474 return g_variant_new (format_string: "(sv)", "bytes", result);
475}
476
477static GInputStream *
478gdk_pixbuf_load (GLoadableIcon *icon,
479 int size,
480 char **type,
481 GCancellable *cancellable,
482 GError **error)
483{
484 GInputStream *stream;
485 GBytes *bytes;
486
487 bytes = gdk_pixbuf_make_bytes (GDK_PIXBUF (icon), error);
488 if (!bytes)
489 return NULL;
490
491 stream = g_memory_input_stream_new_from_bytes (bytes);
492 g_bytes_unref (bytes);
493
494 if (type)
495 *type = g_strdup (str: "image/png");
496
497 return stream;
498}
499
500static void
501gdk_pixbuf_load_async (GLoadableIcon *icon,
502 int size,
503 GCancellable *cancellable,
504 GAsyncReadyCallback callback,
505 gpointer user_data)
506{
507 GTask *task;
508
509 task = g_task_new (source_object: icon, cancellable, callback, callback_data: user_data);
510 g_task_return_pointer (task, result: icon, NULL);
511 g_object_unref (object: task);
512}
513
514static GInputStream *
515gdk_pixbuf_load_finish (GLoadableIcon *icon,
516 GAsyncResult *res,
517 char **type,
518 GError **error)
519{
520 g_return_val_if_fail (g_task_is_valid (res, icon), NULL);
521
522 if (!g_task_propagate_pointer (G_TASK (res), error))
523 return NULL;
524
525 return gdk_pixbuf_load (icon, size: 0, type, NULL, error);
526}
527
528static void
529gdk_pixbuf_loadable_icon_iface_init (GLoadableIconIface *iface)
530{
531 iface->load = gdk_pixbuf_load;
532
533 /* In theory encoding a png could be time-consuming but we're talking
534 * about icons here, so assume it's probably going to be OK and handle
535 * the async variant of the call in-thread instead of having the
536 * default implementation dispatch it to a worker.
537 */
538 iface->load_async = gdk_pixbuf_load_async;
539 iface->load_finish = gdk_pixbuf_load_finish;
540}
541
542static void
543gdk_pixbuf_icon_iface_init (GIconIface *iface)
544{
545 iface->hash = (guint (*) (GIcon *)) g_direct_hash;
546 iface->equal = (gboolean (*) (GIcon *, GIcon *)) g_direct_equal;
547 iface->serialize = gdk_pixbuf_serialize;
548}
549
550/* Used as the destroy notification function for gdk_pixbuf_new() */
551static void
552free_buffer (guchar *pixels, gpointer data)
553{
554 g_free (mem: pixels);
555}
556
557/**
558 * gdk_pixbuf_calculate_rowstride:
559 * @colorspace: Color space for image
560 * @has_alpha: Whether the image should have transparency information
561 * @bits_per_sample: Number of bits per color sample
562 * @width: Width of image in pixels, must be > 0
563 * @height: Height of image in pixels, must be > 0
564 *
565 * Calculates the rowstride that an image created with those values would
566 * have.
567 *
568 * This function is useful for front-ends and backends that want to check
569 * image values without needing to create a `GdkPixbuf`.
570 *
571 * Return value: the rowstride for the given values, or -1 in case of error.
572 *
573 * Since: 2.36.8
574 */
575gint
576gdk_pixbuf_calculate_rowstride (GdkColorspace colorspace,
577 gboolean has_alpha,
578 int bits_per_sample,
579 int width,
580 int height)
581{
582 unsigned int channels;
583
584 g_return_val_if_fail (colorspace == GDK_COLORSPACE_RGB, -1);
585 g_return_val_if_fail (bits_per_sample == 8, -1);
586 g_return_val_if_fail (width > 0, -1);
587 g_return_val_if_fail (height > 0, -1);
588
589 channels = has_alpha ? 4 : 3;
590
591 /* Overflow? */
592 if (width > (G_MAXINT - 3) / channels)
593 return -1;
594
595 /* Always align rows to 32-bit boundaries */
596 return (width * channels + 3) & ~3;
597}
598
599/**
600 * gdk_pixbuf_new:
601 * @colorspace: Color space for image
602 * @has_alpha: Whether the image should have transparency information
603 * @bits_per_sample: Number of bits per color sample
604 * @width: Width of image in pixels, must be > 0
605 * @height: Height of image in pixels, must be > 0
606 *
607 * Creates a new `GdkPixbuf` structure and allocates a buffer for it.
608 *
609 * If the allocation of the buffer failed, this function will return `NULL`.
610 *
611 * The buffer has an optimal rowstride. Note that the buffer is not cleared;
612 * you will have to fill it completely yourself.
613 *
614 * Return value: (transfer full) (nullable): A newly-created pixel buffer
615 **/
616GdkPixbuf *
617gdk_pixbuf_new (GdkColorspace colorspace,
618 gboolean has_alpha,
619 int bits_per_sample,
620 int width,
621 int height)
622{
623 guchar *buf;
624 int rowstride;
625
626 rowstride = gdk_pixbuf_calculate_rowstride (colorspace,
627 has_alpha,
628 bits_per_sample,
629 width,
630 height);
631 if (rowstride <= 0)
632 return NULL;
633
634 buf = g_try_malloc0_n (n_blocks: height, n_block_bytes: rowstride);
635 if (!buf)
636 return NULL;
637
638 return gdk_pixbuf_new_from_data (data: buf, colorspace, has_alpha, bits_per_sample,
639 width, height, rowstride,
640 destroy_fn: free_buffer, NULL);
641}
642
643/**
644 * gdk_pixbuf_copy:
645 * @pixbuf: A pixbuf.
646 *
647 * Creates a new `GdkPixbuf` with a copy of the information in the specified
648 * `pixbuf`.
649 *
650 * Note that this does not copy the options set on the original `GdkPixbuf`,
651 * use gdk_pixbuf_copy_options() for this.
652 *
653 * Return value: (nullable) (transfer full): A newly-created pixbuf
654 **/
655GdkPixbuf *
656gdk_pixbuf_copy (const GdkPixbuf *pixbuf)
657{
658 guchar *buf;
659 int size;
660
661 g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
662
663 /* Calculate a semi-exact size. Here we copy with full rowstrides;
664 * maybe we should copy each row individually with the minimum
665 * rowstride?
666 */
667
668 size = gdk_pixbuf_get_byte_length (pixbuf);
669
670 buf = g_try_malloc (n_bytes: size);
671 if (!buf)
672 return NULL;
673
674 memcpy (dest: buf, src: gdk_pixbuf_read_pixels (pixbuf), n: size);
675
676 return gdk_pixbuf_new_from_data (data: buf,
677 colorspace: pixbuf->colorspace, has_alpha: pixbuf->has_alpha,
678 bits_per_sample: pixbuf->bits_per_sample,
679 width: pixbuf->width, height: pixbuf->height,
680 rowstride: pixbuf->rowstride,
681 destroy_fn: free_buffer,
682 NULL);
683}
684
685/**
686 * gdk_pixbuf_new_subpixbuf:
687 * @src_pixbuf: a `GdkPixbuf`
688 * @src_x: X coord in @src_pixbuf
689 * @src_y: Y coord in @src_pixbuf
690 * @width: width of region in @src_pixbuf
691 * @height: height of region in @src_pixbuf
692 *
693 * Creates a new pixbuf which represents a sub-region of `src_pixbuf`.
694 *
695 * The new pixbuf shares its pixels with the original pixbuf, so
696 * writing to one affects both. The new pixbuf holds a reference to
697 * `src_pixbuf`, so `src_pixbuf` will not be finalized until the new
698 * pixbuf is finalized.
699 *
700 * Note that if `src_pixbuf` is read-only, this function will force it
701 * to be mutable.
702 *
703 * Return value: (transfer full): a new pixbuf
704 **/
705GdkPixbuf*
706gdk_pixbuf_new_subpixbuf (GdkPixbuf *src_pixbuf,
707 int src_x,
708 int src_y,
709 int width,
710 int height)
711{
712 guchar *pixels;
713 GdkPixbuf *sub;
714
715 g_return_val_if_fail (GDK_IS_PIXBUF (src_pixbuf), NULL);
716 g_return_val_if_fail (src_x >= 0 && src_x + width <= src_pixbuf->width, NULL);
717 g_return_val_if_fail (src_y >= 0 && src_y + height <= src_pixbuf->height, NULL);
718
719 /* Note causes an implicit copy where src_pixbuf owns the data */
720 pixels = (gdk_pixbuf_get_pixels (pixbuf: src_pixbuf)
721 + src_y * src_pixbuf->rowstride
722 + src_x * src_pixbuf->n_channels);
723
724 sub = gdk_pixbuf_new_from_data (data: pixels,
725 colorspace: src_pixbuf->colorspace,
726 has_alpha: src_pixbuf->has_alpha,
727 bits_per_sample: src_pixbuf->bits_per_sample,
728 width, height,
729 rowstride: src_pixbuf->rowstride,
730 NULL, NULL);
731
732 /* Keep a reference to src_pixbuf */
733 g_object_ref (src_pixbuf);
734
735 g_object_set_qdata_full (G_OBJECT (sub),
736 quark: g_quark_from_static_string (string: "gdk-pixbuf-subpixbuf-src"),
737 data: src_pixbuf,
738 destroy: (GDestroyNotify) g_object_unref);
739
740 return sub;
741}
742
743
744
745/* Accessors */
746
747/**
748 * gdk_pixbuf_get_colorspace:
749 * @pixbuf: A pixbuf.
750 *
751 * Queries the color space of a pixbuf.
752 *
753 * Return value: Color space.
754 **/
755GdkColorspace
756gdk_pixbuf_get_colorspace (const GdkPixbuf *pixbuf)
757{
758 g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), GDK_COLORSPACE_RGB);
759
760 return pixbuf->colorspace;
761}
762
763/**
764 * gdk_pixbuf_get_n_channels:
765 * @pixbuf: A pixbuf.
766 *
767 * Queries the number of channels of a pixbuf.
768 *
769 * Return value: Number of channels.
770 **/
771int
772gdk_pixbuf_get_n_channels (const GdkPixbuf *pixbuf)
773{
774 g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), -1);
775
776 return pixbuf->n_channels;
777}
778
779/**
780 * gdk_pixbuf_get_has_alpha:
781 * @pixbuf: A pixbuf.
782 *
783 * Queries whether a pixbuf has an alpha channel (opacity information).
784 *
785 * Return value: `TRUE` if it has an alpha channel, `FALSE` otherwise.
786 **/
787gboolean
788gdk_pixbuf_get_has_alpha (const GdkPixbuf *pixbuf)
789{
790 g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), FALSE);
791
792 return pixbuf->has_alpha ? TRUE : FALSE;
793}
794
795/**
796 * gdk_pixbuf_get_bits_per_sample:
797 * @pixbuf: A pixbuf.
798 *
799 * Queries the number of bits per color sample in a pixbuf.
800 *
801 * Return value: Number of bits per color sample.
802 **/
803int
804gdk_pixbuf_get_bits_per_sample (const GdkPixbuf *pixbuf)
805{
806 g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), -1);
807
808 return pixbuf->bits_per_sample;
809}
810
811/**
812 * gdk_pixbuf_get_pixels:
813 * @pixbuf: A pixbuf.
814 *
815 * Queries a pointer to the pixel data of a pixbuf.
816 *
817 * This function will cause an implicit copy of the pixbuf data if the
818 * pixbuf was created from read-only data.
819 *
820 * Please see the section on [image data](class.Pixbuf.html#image-data) for information
821 * about how the pixel data is stored in memory.
822 *
823 * Return value: (array): A pointer to the pixbuf's pixel data.
824 **/
825guchar *
826gdk_pixbuf_get_pixels (const GdkPixbuf *pixbuf)
827{
828 return gdk_pixbuf_get_pixels_with_length (pixbuf, NULL);
829}
830
831static void
832downgrade_to_pixels (const GdkPixbuf *pixbuf)
833{
834 switch (pixbuf->storage) {
835 case STORAGE_PIXELS:
836 return;
837
838 case STORAGE_BYTES: {
839 GdkPixbuf *mut_pixbuf = (GdkPixbuf *) pixbuf;
840 gsize len;
841 Pixels pixels;
842
843 pixels.pixels = g_bytes_unref_to_data (bytes: pixbuf->s.bytes.bytes, size: &len);
844 pixels.destroy_fn = free_buffer;
845 pixels.destroy_fn_data = NULL;
846
847 mut_pixbuf->storage = STORAGE_PIXELS;
848 mut_pixbuf->s.pixels = pixels;
849 break;
850 }
851
852 default:
853 g_assert_not_reached ();
854 }
855}
856
857/**
858 * gdk_pixbuf_get_pixels_with_length: (rename-to gdk_pixbuf_get_pixels)
859 * @pixbuf: A pixbuf.
860 * @length: (out): The length of the binary data.
861 *
862 * Queries a pointer to the pixel data of a pixbuf.
863 *
864 * This function will cause an implicit copy of the pixbuf data if the
865 * pixbuf was created from read-only data.
866 *
867 * Please see the section on [image data](class.Pixbuf.html#image-data) for information
868 * about how the pixel data is stored in memory.
869 *
870 * Return value: (array length=length): A pointer to the pixbuf's
871 * pixel data.
872 *
873 * Since: 2.26
874 */
875guchar *
876gdk_pixbuf_get_pixels_with_length (const GdkPixbuf *pixbuf,
877 guint *length)
878{
879 g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
880
881 downgrade_to_pixels (pixbuf);
882 g_assert (pixbuf->storage == STORAGE_PIXELS);
883
884 if (length)
885 *length = gdk_pixbuf_get_byte_length (pixbuf);
886
887 return pixbuf->s.pixels.pixels;
888}
889
890/**
891 * gdk_pixbuf_read_pixels:
892 * @pixbuf: A pixbuf
893 *
894 * Provides a read-only pointer to the raw pixel data.
895 *
896 * This function allows skipping the implicit copy that must be made
897 * if gdk_pixbuf_get_pixels() is called on a read-only pixbuf.
898 *
899 * Returns: a read-only pointer to the raw pixel data
900 *
901 * Since: 2.32
902 */
903const guint8*
904gdk_pixbuf_read_pixels (const GdkPixbuf *pixbuf)
905{
906 g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
907
908 switch (pixbuf->storage) {
909 case STORAGE_PIXELS:
910 return pixbuf->s.pixels.pixels;
911
912 case STORAGE_BYTES: {
913 gsize len;
914 /* Ignore len; callers know the size via other variables */
915 return g_bytes_get_data (bytes: pixbuf->s.bytes.bytes, size: &len);
916 }
917
918 default:
919 g_assert_not_reached ();
920 return NULL;
921 }
922}
923
924/**
925 * gdk_pixbuf_read_pixel_bytes:
926 * @pixbuf: A pixbuf
927 *
928 * Provides a #GBytes buffer containing the raw pixel data; the data
929 * must not be modified.
930 *
931 * This function allows skipping the implicit copy that must be made
932 * if gdk_pixbuf_get_pixels() is called on a read-only pixbuf.
933 *
934 * Returns: (transfer full): A new reference to a read-only copy of
935 * the pixel data. Note that for mutable pixbufs, this function will
936 * incur a one-time copy of the pixel data for conversion into the
937 * returned #GBytes.
938 *
939 * Since: 2.32
940 */
941GBytes *
942gdk_pixbuf_read_pixel_bytes (const GdkPixbuf *pixbuf)
943{
944 g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
945
946 switch (pixbuf->storage) {
947 case STORAGE_PIXELS:
948 return g_bytes_new (data: pixbuf->s.pixels.pixels,
949 size: gdk_pixbuf_get_byte_length (pixbuf));
950
951 case STORAGE_BYTES:
952 return g_bytes_ref (bytes: pixbuf->s.bytes.bytes);
953
954 default:
955 g_assert_not_reached ();
956 }
957}
958
959/**
960 * gdk_pixbuf_get_width:
961 * @pixbuf: A pixbuf.
962 *
963 * Queries the width of a pixbuf.
964 *
965 * Return value: Width in pixels.
966 **/
967int
968gdk_pixbuf_get_width (const GdkPixbuf *pixbuf)
969{
970 g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), -1);
971
972 return pixbuf->width;
973}
974
975/**
976 * gdk_pixbuf_get_height:
977 * @pixbuf: A pixbuf.
978 *
979 * Queries the height of a pixbuf.
980 *
981 * Return value: Height in pixels.
982 **/
983int
984gdk_pixbuf_get_height (const GdkPixbuf *pixbuf)
985{
986 g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), -1);
987
988 return pixbuf->height;
989}
990
991/**
992 * gdk_pixbuf_get_rowstride:
993 * @pixbuf: A pixbuf.
994 *
995 * Queries the rowstride of a pixbuf, which is the number of bytes between
996 * the start of a row and the start of the next row.
997 *
998 * Return value: Distance between row starts.
999 **/
1000int
1001gdk_pixbuf_get_rowstride (const GdkPixbuf *pixbuf)
1002{
1003 g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), -1);
1004
1005 return pixbuf->rowstride;
1006}
1007
1008/**
1009 * gdk_pixbuf_get_byte_length:
1010 * @pixbuf: A pixbuf
1011 *
1012 * Returns the length of the pixel data, in bytes.
1013 *
1014 * Return value: The length of the pixel data.
1015 *
1016 * Since: 2.26
1017 */
1018gsize
1019gdk_pixbuf_get_byte_length (const GdkPixbuf *pixbuf)
1020{
1021 g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), -1);
1022
1023 return ((pixbuf->height - 1) * pixbuf->rowstride +
1024 pixbuf->width * ((pixbuf->n_channels * pixbuf->bits_per_sample + 7) / 8));
1025}
1026
1027
1028
1029/* General initialization hooks */
1030const guint gdk_pixbuf_major_version = GDK_PIXBUF_MAJOR;
1031const guint gdk_pixbuf_minor_version = GDK_PIXBUF_MINOR;
1032const guint gdk_pixbuf_micro_version = GDK_PIXBUF_MICRO;
1033
1034const char *gdk_pixbuf_version = GDK_PIXBUF_VERSION;
1035
1036/* Error quark */
1037GQuark
1038gdk_pixbuf_error_quark (void)
1039{
1040 return g_quark_from_static_string (string: "gdk-pixbuf-error-quark");
1041}
1042
1043/**
1044 * gdk_pixbuf_fill:
1045 * @pixbuf: a `GdkPixbuf`
1046 * @pixel: RGBA pixel to used to clear (`0xffffffff` is opaque white,
1047 * `0x00000000` transparent black)
1048 *
1049 * Clears a pixbuf to the given RGBA value, converting the RGBA value into
1050 * the pixbuf's pixel format.
1051 *
1052 * The alpha component will be ignored if the pixbuf doesn't have an alpha
1053 * channel.
1054 */
1055void
1056gdk_pixbuf_fill (GdkPixbuf *pixbuf,
1057 guint32 pixel)
1058{
1059 guchar *pixels;
1060 guint r, g, b, a;
1061 guchar *p;
1062 guint w, h;
1063
1064 g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
1065
1066 if (pixbuf->width == 0 || pixbuf->height == 0)
1067 return;
1068
1069 /* Force an implicit copy */
1070 pixels = gdk_pixbuf_get_pixels (pixbuf);
1071
1072 r = (pixel & 0xff000000) >> 24;
1073 g = (pixel & 0x00ff0000) >> 16;
1074 b = (pixel & 0x0000ff00) >> 8;
1075 a = (pixel & 0x000000ff);
1076
1077 h = pixbuf->height;
1078
1079 while (h--) {
1080 w = pixbuf->width;
1081 p = pixels;
1082
1083 switch (pixbuf->n_channels) {
1084 case 3:
1085 while (w--) {
1086 p[0] = r;
1087 p[1] = g;
1088 p[2] = b;
1089 p += 3;
1090 }
1091 break;
1092 case 4:
1093 while (w--) {
1094 p[0] = r;
1095 p[1] = g;
1096 p[2] = b;
1097 p[3] = a;
1098 p += 4;
1099 }
1100 break;
1101 default:
1102 break;
1103 }
1104
1105 pixels += pixbuf->rowstride;
1106 }
1107}
1108
1109
1110
1111/**
1112 * gdk_pixbuf_get_option:
1113 * @pixbuf: a `GdkPixbuf`
1114 * @key: a nul-terminated string.
1115 *
1116 * Looks up @key in the list of options that may have been attached to the
1117 * @pixbuf when it was loaded, or that may have been attached by another
1118 * function using gdk_pixbuf_set_option().
1119 *
1120 * For instance, the ANI loader provides "Title" and "Artist" options.
1121 * The ICO, XBM, and XPM loaders provide "x_hot" and "y_hot" hot-spot
1122 * options for cursor definitions. The PNG loader provides the tEXt ancillary
1123 * chunk key/value pairs as options. Since 2.12, the TIFF and JPEG loaders
1124 * return an "orientation" option string that corresponds to the embedded
1125 * TIFF/Exif orientation tag (if present). Since 2.32, the TIFF loader sets
1126 * the "multipage" option string to "yes" when a multi-page TIFF is loaded.
1127 * Since 2.32 the JPEG and PNG loaders set "x-dpi" and "y-dpi" if the file
1128 * contains image density information in dots per inch.
1129 * Since 2.36.6, the JPEG loader sets the "comment" option with the comment
1130 * EXIF tag.
1131 *
1132 * Return value: (transfer none) (nullable): the value associated with `key`
1133 **/
1134const gchar *
1135gdk_pixbuf_get_option (GdkPixbuf *pixbuf,
1136 const gchar *key)
1137{
1138 gchar **options;
1139 gint i;
1140
1141 g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
1142 g_return_val_if_fail (key != NULL, NULL);
1143
1144 options = g_object_get_qdata (G_OBJECT (pixbuf),
1145 quark: g_quark_from_static_string (string: "gdk_pixbuf_options"));
1146 if (options) {
1147 for (i = 0; options[2*i]; i++) {
1148 if (strcmp (s1: options[2*i], s2: key) == 0)
1149 return options[2*i+1];
1150 }
1151 }
1152
1153 return NULL;
1154}
1155
1156/**
1157 * gdk_pixbuf_get_options:
1158 * @pixbuf: a `GdkPixbuf`
1159 *
1160 * Returns a `GHashTable` with a list of all the options that may have been
1161 * attached to the `pixbuf` when it was loaded, or that may have been
1162 * attached by another function using [method@GdkPixbuf.Pixbuf.set_option].
1163 *
1164 * Return value: (transfer container) (element-type utf8 utf8): a #GHashTable
1165 * of key/values pairs
1166 *
1167 * Since: 2.32
1168 **/
1169GHashTable *
1170gdk_pixbuf_get_options (GdkPixbuf *pixbuf)
1171{
1172 GHashTable *ht;
1173 gchar **options;
1174
1175 g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
1176
1177 ht = g_hash_table_new (hash_func: g_str_hash, key_equal_func: g_str_equal);
1178
1179 options = g_object_get_qdata (G_OBJECT (pixbuf),
1180 quark: g_quark_from_static_string (string: "gdk_pixbuf_options"));
1181 if (options) {
1182 gint i;
1183
1184 for (i = 0; options[2*i]; i++)
1185 g_hash_table_insert (hash_table: ht, key: options[2*i], value: options[2*i+1]);
1186 }
1187
1188 return ht;
1189}
1190
1191/**
1192 * gdk_pixbuf_remove_option:
1193 * @pixbuf: a `GdkPixbuf`
1194 * @key: a nul-terminated string representing the key to remove.
1195 *
1196 * Removes the key/value pair option attached to a `GdkPixbuf`.
1197 *
1198 * Return value: `TRUE` if an option was removed, `FALSE` if not.
1199 *
1200 * Since: 2.36
1201 **/
1202gboolean
1203gdk_pixbuf_remove_option (GdkPixbuf *pixbuf,
1204 const gchar *key)
1205{
1206 GQuark quark;
1207 gchar **options;
1208 guint n;
1209 GPtrArray *array;
1210 gboolean found;
1211
1212 g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), FALSE);
1213 g_return_val_if_fail (key != NULL, FALSE);
1214
1215 quark = g_quark_from_static_string (string: "gdk_pixbuf_options");
1216
1217 options = g_object_get_qdata (G_OBJECT (pixbuf), quark);
1218 if (!options)
1219 return FALSE;
1220
1221 g_object_steal_qdata (G_OBJECT (pixbuf), quark);
1222
1223 /* There's at least a nul-terminator */
1224 array = g_ptr_array_new_full (reserved_size: 1, element_free_func: g_free);
1225
1226 found = FALSE;
1227 for (n = 0; options[2*n]; n++) {
1228 if (strcmp (s1: options[2*n], s2: key) != 0) {
1229 g_ptr_array_add (array, data: g_strdup (str: options[2*n])); /* key */
1230 g_ptr_array_add (array, data: g_strdup (str: options[2*n+1])); /* value */
1231 } else {
1232 found = TRUE;
1233 }
1234 }
1235
1236 if (array->len == 0) {
1237 g_ptr_array_unref (array);
1238 g_strfreev (str_array: options);
1239 return found;
1240 }
1241
1242 if (!found) {
1243 g_ptr_array_free (array, TRUE);
1244 g_object_set_qdata_full (G_OBJECT (pixbuf), quark,
1245 data: options, destroy: (GDestroyNotify) g_strfreev);
1246 return FALSE;
1247 }
1248
1249 g_ptr_array_add (array, NULL);
1250 g_object_set_qdata_full (G_OBJECT (pixbuf), quark,
1251 data: g_ptr_array_free (array, FALSE), destroy: (GDestroyNotify) g_strfreev);
1252 g_strfreev (str_array: options);
1253
1254 return TRUE;
1255}
1256
1257/**
1258 * gdk_pixbuf_set_option:
1259 * @pixbuf: a `GdkPixbuf`
1260 * @key: a nul-terminated string.
1261 * @value: a nul-terminated string.
1262 *
1263 * Attaches a key/value pair as an option to a `GdkPixbuf`.
1264 *
1265 * If `key` already exists in the list of options attached to the `pixbuf`,
1266 * the new value is ignored and `FALSE` is returned.
1267 *
1268 * Return value: `TRUE` on success
1269 *
1270 * Since: 2.2
1271 **/
1272gboolean
1273gdk_pixbuf_set_option (GdkPixbuf *pixbuf,
1274 const gchar *key,
1275 const gchar *value)
1276{
1277 GQuark quark;
1278 gchar **options;
1279 gint n = 0;
1280
1281 g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), FALSE);
1282 g_return_val_if_fail (key != NULL, FALSE);
1283 g_return_val_if_fail (value != NULL, FALSE);
1284
1285 quark = g_quark_from_static_string (string: "gdk_pixbuf_options");
1286
1287 options = g_object_get_qdata (G_OBJECT (pixbuf), quark);
1288
1289 if (options) {
1290 for (n = 0; options[2*n]; n++) {
1291 if (strcmp (s1: options[2*n], s2: key) == 0)
1292 return FALSE;
1293 }
1294
1295 g_object_steal_qdata (G_OBJECT (pixbuf), quark);
1296 options = g_renew (gchar *, options, 2*(n+1) + 1);
1297 } else {
1298 options = g_new (gchar *, 3);
1299 }
1300
1301 options[2*n] = g_strdup (str: key);
1302 options[2*n+1] = g_strdup (str: value);
1303 options[2*n+2] = NULL;
1304
1305 g_object_set_qdata_full (G_OBJECT (pixbuf), quark,
1306 data: options, destroy: (GDestroyNotify) g_strfreev);
1307
1308 return TRUE;
1309}
1310
1311/**
1312 * gdk_pixbuf_copy_options:
1313 * @src_pixbuf: the source pixbuf
1314 * @dest_pixbuf: the destination pixbuf
1315 *
1316 * Copies the key/value pair options attached to a `GdkPixbuf` to another
1317 * `GdkPixbuf`.
1318 *
1319 * This is useful to keep original metadata after having manipulated
1320 * a file. However be careful to remove metadata which you've already
1321 * applied, such as the "orientation" option after rotating the image.
1322 *
1323 * Return value: `TRUE` on success.
1324 *
1325 * Since: 2.36
1326 **/
1327gboolean
1328gdk_pixbuf_copy_options (GdkPixbuf *src_pixbuf,
1329 GdkPixbuf *dest_pixbuf)
1330{
1331 GQuark quark;
1332 gchar **options;
1333
1334 g_return_val_if_fail (GDK_IS_PIXBUF (src_pixbuf), FALSE);
1335 g_return_val_if_fail (GDK_IS_PIXBUF (dest_pixbuf), FALSE);
1336
1337 quark = g_quark_from_static_string (string: "gdk_pixbuf_options");
1338
1339 options = g_object_dup_qdata (G_OBJECT (src_pixbuf),
1340 quark,
1341 dup_func: (GDuplicateFunc) g_strdupv,
1342 NULL);
1343
1344 if (options == NULL)
1345 return TRUE;
1346
1347 g_object_set_qdata_full (G_OBJECT (dest_pixbuf), quark,
1348 data: options, destroy: (GDestroyNotify) g_strfreev);
1349
1350 return TRUE;
1351}
1352
1353static void
1354gdk_pixbuf_set_property (GObject *object,
1355 guint prop_id,
1356 const GValue *value,
1357 GParamSpec *pspec)
1358{
1359 GdkPixbuf *pixbuf = GDK_PIXBUF (object);
1360 gboolean notify = TRUE;
1361
1362 switch (prop_id) {
1363 case PROP_COLORSPACE:
1364 notify = pixbuf->colorspace != g_value_get_enum (value);
1365 pixbuf->colorspace = g_value_get_enum (value);
1366 break;
1367 case PROP_N_CHANNELS:
1368 notify = pixbuf->n_channels != g_value_get_int (value);
1369 pixbuf->n_channels = g_value_get_int (value);
1370 break;
1371 case PROP_HAS_ALPHA:
1372 notify = pixbuf->has_alpha != g_value_get_boolean (value);
1373 pixbuf->has_alpha = g_value_get_boolean (value);
1374 break;
1375 case PROP_BITS_PER_SAMPLE:
1376 notify = pixbuf->bits_per_sample != g_value_get_int (value);
1377 pixbuf->bits_per_sample = g_value_get_int (value);
1378 break;
1379 case PROP_WIDTH:
1380 notify = pixbuf->width != g_value_get_int (value);
1381 pixbuf->width = g_value_get_int (value);
1382 break;
1383 case PROP_HEIGHT:
1384 notify = pixbuf->height != g_value_get_int (value);
1385 pixbuf->height = g_value_get_int (value);
1386 break;
1387 case PROP_ROWSTRIDE:
1388 notify = pixbuf->rowstride != g_value_get_int (value);
1389 pixbuf->rowstride = g_value_get_int (value);
1390 break;
1391
1392 /* The following two are a bit strange. Both PROP_PIXELS and
1393 * PROP_PIXEL_BYTES are G_PARAM_CONSTRUCT_ONLY properties, which means
1394 * that GObject will generate default values for any missing one and
1395 * call us for *both*. So, we need to check whether the passed value is
1396 * not NULL before actually setting pixbuf->storage.
1397 */
1398 case PROP_PIXELS: {
1399 guchar *pixels = g_value_get_pointer (value);
1400
1401 if (pixels) {
1402 g_assert (pixbuf->storage == STORAGE_UNINITIALIZED);
1403
1404 pixbuf->storage = STORAGE_PIXELS;
1405 pixbuf->s.pixels.pixels = pixels;
1406 pixbuf->s.pixels.destroy_fn = NULL;
1407 pixbuf->s.pixels.destroy_fn_data = NULL;
1408 } else {
1409 notify = FALSE;
1410 }
1411
1412 break;
1413 }
1414
1415 case PROP_PIXEL_BYTES: {
1416 GBytes *bytes = g_value_get_boxed (value);
1417
1418 if (bytes) {
1419 g_assert (pixbuf->storage == STORAGE_UNINITIALIZED);
1420
1421 pixbuf->storage = STORAGE_BYTES;
1422 pixbuf->s.bytes.bytes = g_value_dup_boxed (value);
1423 } else {
1424 notify = FALSE;
1425 }
1426
1427 break;
1428 }
1429
1430 default:
1431 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1432 break;
1433 }
1434
1435 if (notify)
1436 g_object_notify_by_pspec (G_OBJECT (object), pspec);
1437}
1438
1439static void
1440gdk_pixbuf_get_property (GObject *object,
1441 guint prop_id,
1442 GValue *value,
1443 GParamSpec *pspec)
1444{
1445 GdkPixbuf *pixbuf = GDK_PIXBUF (object);
1446
1447 switch (prop_id) {
1448 case PROP_COLORSPACE:
1449 g_value_set_enum (value, v_enum: gdk_pixbuf_get_colorspace (pixbuf));
1450 break;
1451 case PROP_N_CHANNELS:
1452 g_value_set_int (value, v_int: gdk_pixbuf_get_n_channels (pixbuf));
1453 break;
1454 case PROP_HAS_ALPHA:
1455 g_value_set_boolean (value, v_boolean: gdk_pixbuf_get_has_alpha (pixbuf));
1456 break;
1457 case PROP_BITS_PER_SAMPLE:
1458 g_value_set_int (value, v_int: gdk_pixbuf_get_bits_per_sample (pixbuf));
1459 break;
1460 case PROP_WIDTH:
1461 g_value_set_int (value, v_int: gdk_pixbuf_get_width (pixbuf));
1462 break;
1463 case PROP_HEIGHT:
1464 g_value_set_int (value, v_int: gdk_pixbuf_get_height (pixbuf));
1465 break;
1466 case PROP_ROWSTRIDE:
1467 g_value_set_int (value, v_int: gdk_pixbuf_get_rowstride (pixbuf));
1468 break;
1469 case PROP_PIXELS:
1470 g_value_set_pointer (value, v_pointer: gdk_pixbuf_get_pixels (pixbuf));
1471 break;
1472 case PROP_PIXEL_BYTES:
1473 g_value_set_boxed (value, v_boxed: gdk_pixbuf_read_pixel_bytes (pixbuf));
1474 break;
1475 default:
1476 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1477 break;
1478 }
1479}
1480
1481static void
1482make_storage_invalid (GdkPixbuf *pixbuf)
1483{
1484 char *buf;
1485 gsize bufsize = 3;
1486
1487 buf = g_new0(char, bufsize);
1488
1489 pixbuf->storage = STORAGE_BYTES;
1490 pixbuf->s.bytes.bytes = g_bytes_new_with_free_func (data: buf, size: bufsize, free_func: g_free, NULL);
1491
1492 pixbuf->colorspace = GDK_COLORSPACE_RGB;
1493 pixbuf->n_channels = 3;
1494 pixbuf->bits_per_sample = 8;
1495 pixbuf->width = 1;
1496 pixbuf->height = 1;
1497 pixbuf->rowstride = 3;
1498 pixbuf->has_alpha = FALSE;
1499}
1500
1501static void
1502gdk_pixbuf_constructed (GObject *object)
1503{
1504 GdkPixbuf *pixbuf = GDK_PIXBUF (object);
1505
1506 G_OBJECT_CLASS (gdk_pixbuf_parent_class)->constructed (object);
1507
1508 switch (pixbuf->storage) {
1509 case STORAGE_UNINITIALIZED:
1510 /* This means that neither of the construct properties "pixels" nor "pixel-bytes"
1511 * was specified during a call to g_object_new().
1512 *
1513 * To avoid breaking ABI, we don't emit this warning. We'll want
1514 * to emit it once we can have fallible construction.
1515 *
1516 * g_warning ("pixbuf needs to be constructed with the 'pixels' or 'pixel-bytes' properties");
1517 */
1518
1519 make_storage_invalid (pixbuf);
1520 break;
1521
1522 case STORAGE_PIXELS:
1523 g_assert (pixbuf->s.pixels.pixels != NULL);
1524 break;
1525
1526 case STORAGE_BYTES: {
1527 gsize bytes_size;
1528 gint width, height;
1529 gboolean has_alpha;
1530
1531 g_assert (pixbuf->s.bytes.bytes != NULL);
1532
1533 bytes_size = g_bytes_get_size (bytes: pixbuf->s.bytes.bytes);
1534 width = pixbuf->width;
1535 height = pixbuf->height;
1536 has_alpha = pixbuf->has_alpha;
1537
1538 /* This is the same check as in gdk_pixbuf_new_from_bytes() */
1539 if (!(bytes_size >= width * height * (has_alpha ? 4 : 3))) {
1540 g_error ("GBytes is too small to fit the pixbuf's declared width and height");
1541 }
1542 break;
1543 }
1544
1545 default:
1546 g_assert_not_reached ();
1547 }
1548
1549 g_assert (pixbuf->storage != STORAGE_UNINITIALIZED);
1550}
1551

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