]> gitweb.michael.orlitzky.com - libsvgtiny-pixbuf.git/blob - gdk_pixbuf_get_from_surface.h
Makefile.am,configure.ac: stop using GTK4
[libsvgtiny-pixbuf.git] / gdk_pixbuf_get_from_surface.h
1 /* This file contains gdk_pixbuf_get_from_surface() and its
2 * dependencies, copy & pasted from gdk/deprecated/gdkpixbuf.c.
3 * Having it inline means that we don't have to link against a
4 * specific version of GTK, risking that (say) a gtk4-linked
5 * pixbuf loader gets used on a gtk3 desktop environment.
6 */
7 static cairo_format_t
8 gdk_cairo_format_for_content (cairo_content_t content)
9 {
10 switch (content)
11 {
12 case CAIRO_CONTENT_COLOR:
13 return CAIRO_FORMAT_RGB24;
14 case CAIRO_CONTENT_ALPHA:
15 return CAIRO_FORMAT_A8;
16 case CAIRO_CONTENT_COLOR_ALPHA:
17 default:
18 return CAIRO_FORMAT_ARGB32;
19 }
20 }
21
22
23 static cairo_surface_t *
24 gdk_cairo_surface_coerce_to_image (cairo_surface_t *surface,
25 cairo_content_t content,
26 int src_x,
27 int src_y,
28 int width,
29 int height)
30 {
31 cairo_surface_t *copy;
32 cairo_t *cr;
33
34 copy = cairo_image_surface_create (gdk_cairo_format_for_content (content),
35 width,
36 height);
37
38 cr = cairo_create (copy);
39 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
40 cairo_set_source_surface (cr, surface, -src_x, -src_y);
41 cairo_paint (cr);
42 cairo_destroy (cr);
43
44 return copy;
45 }
46
47
48 static void
49 convert_alpha (guchar *dest_data,
50 int dest_stride,
51 guchar *src_data,
52 int src_stride,
53 int src_x,
54 int src_y,
55 int width,
56 int height)
57 {
58 int x, y;
59
60 src_data += src_stride * src_y + src_x * 4;
61
62 for (y = 0; y < height; y++) {
63 guint32 *src = (guint32 *) src_data;
64
65 for (x = 0; x < width; x++) {
66 guint alpha = src[x] >> 24;
67
68 if (alpha == 0)
69 {
70 dest_data[x * 4 + 0] = 0;
71 dest_data[x * 4 + 1] = 0;
72 dest_data[x * 4 + 2] = 0;
73 }
74 else
75 {
76 dest_data[x * 4 + 0] = (((src[x] & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
77 dest_data[x * 4 + 1] = (((src[x] & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
78 dest_data[x * 4 + 2] = (((src[x] & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
79 }
80 dest_data[x * 4 + 3] = alpha;
81 }
82
83 src_data += src_stride;
84 dest_data += dest_stride;
85 }
86 }
87
88 static void
89 convert_no_alpha (guchar *dest_data,
90 int dest_stride,
91 guchar *src_data,
92 int src_stride,
93 int src_x,
94 int src_y,
95 int width,
96 int height)
97 {
98 int x, y;
99
100 src_data += src_stride * src_y + src_x * 4;
101
102 for (y = 0; y < height; y++) {
103 guint32 *src = (guint32 *) src_data;
104
105 for (x = 0; x < width; x++) {
106 dest_data[x * 3 + 0] = src[x] >> 16;
107 dest_data[x * 3 + 1] = src[x] >> 8;
108 dest_data[x * 3 + 2] = src[x];
109 }
110
111 src_data += src_stride;
112 dest_data += dest_stride;
113 }
114 }
115
116 /**
117 * gdk_pixbuf_get_from_surface:
118 * @surface: surface to copy from
119 * @src_x: Source X coordinate within @surface
120 * @src_y: Source Y coordinate within @surface
121 * @width: Width in pixels of region to get
122 * @height: Height in pixels of region to get
123 *
124 * Transfers image data from a `cairo_surface_t` and converts it
125 * to a `GdkPixbuf`.
126 *
127 * This allows you to efficiently read individual pixels from cairo surfaces.
128 *
129 * This function will create an RGB pixbuf with 8 bits per channel.
130 * The pixbuf will contain an alpha channel if the @surface contains one.
131 *
132 * Returns: (nullable) (transfer full): A newly-created pixbuf with a
133 * reference count of 1
134 *
135 * Deprecated: 4.12: Use [class@Gdk.Texture] and subclasses instead
136 * cairo surfaces and pixbufs
137 */
138 GdkPixbuf *
139 gdk_pixbuf_get_from_surface (cairo_surface_t *surface,
140 int src_x,
141 int src_y,
142 int width,
143 int height)
144 {
145 cairo_content_t content;
146 GdkPixbuf *dest;
147
148 /* General sanity checks */
149 g_return_val_if_fail (surface != NULL, NULL);
150 g_return_val_if_fail (width > 0 && height > 0, NULL);
151
152 content = cairo_surface_get_content (surface) | CAIRO_CONTENT_COLOR;
153 dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
154 !!(content & CAIRO_CONTENT_ALPHA),
155 8,
156 width, height);
157
158 if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE &&
159 cairo_image_surface_get_format (surface) == gdk_cairo_format_for_content (content))
160 surface = cairo_surface_reference (surface);
161 else
162 {
163 surface = gdk_cairo_surface_coerce_to_image (surface, content,
164 src_x, src_y,
165 width, height);
166 src_x = 0;
167 src_y = 0;
168 }
169 cairo_surface_flush (surface);
170 if (cairo_surface_status (surface) || dest == NULL)
171 {
172 cairo_surface_destroy (surface);
173 g_clear_object (&dest);
174 return NULL;
175 }
176
177 if (gdk_pixbuf_get_has_alpha (dest))
178 convert_alpha (gdk_pixbuf_get_pixels (dest),
179 gdk_pixbuf_get_rowstride (dest),
180 cairo_image_surface_get_data (surface),
181 cairo_image_surface_get_stride (surface),
182 src_x, src_y,
183 width, height);
184 else
185 convert_no_alpha (gdk_pixbuf_get_pixels (dest),
186 gdk_pixbuf_get_rowstride (dest),
187 cairo_image_surface_get_data (surface),
188 cairo_image_surface_get_stride (surface),
189 src_x, src_y,
190 width, height);
191
192 cairo_surface_destroy (surface);
193 return dest;
194 }