1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ |
2 | /* GdkPixbuf library - Simple transformations of animations |
3 | * |
4 | * Copyright (C) Red Hat, Inc |
5 | * |
6 | * Authors: Matthias Clasen <mclasen@redhat.com> |
7 | * |
8 | * This library is free software; you can redistribute it and/or |
9 | * modify it under the terms of the GNU Lesser General Public |
10 | * License as published by the Free Software Foundation; either |
11 | * version 2 of the License, or (at your option) any later version. |
12 | * |
13 | * This library is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | * Lesser General Public License for more details. |
17 | * |
18 | * You should have received a copy of the GNU Lesser General Public |
19 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
20 | * |
21 | */ |
22 | |
23 | #include <glib.h> |
24 | |
25 | #include "gdk-pixbuf.h" |
26 | #include "gdk-pixbuf-io.h" |
27 | #include "gdk-pixbuf-scaled-anim.h" |
28 | |
29 | |
30 | struct _GdkPixbufScaledAnimClass |
31 | { |
32 | GdkPixbufAnimationClass parent_class; |
33 | }; |
34 | |
35 | struct _GdkPixbufScaledAnim |
36 | { |
37 | GdkPixbufAnimation parent_instance; |
38 | |
39 | GdkPixbufAnimation *anim; |
40 | gdouble xscale; |
41 | gdouble yscale; |
42 | gdouble tscale; |
43 | |
44 | GdkPixbuf *current; |
45 | }; |
46 | |
47 | struct _GdkPixbufScaledAnimIterClass |
48 | { |
49 | GdkPixbufAnimationClass parent_class; |
50 | }; |
51 | |
52 | struct _GdkPixbufScaledAnimIter |
53 | { |
54 | GdkPixbufAnimationIter parent_instance; |
55 | |
56 | GdkPixbufScaledAnim *scaled; |
57 | GdkPixbufAnimationIter *iter; |
58 | }; |
59 | |
60 | typedef struct _GdkPixbufScaledAnimIter GdkPixbufScaledAnimIter; |
61 | typedef struct _GdkPixbufScaledAnimIterClass GdkPixbufScaledAnimIterClass; |
62 | |
63 | GdkPixbufScaledAnim * |
64 | _gdk_pixbuf_scaled_anim_new (GdkPixbufAnimation *anim, |
65 | gdouble xscale, |
66 | gdouble yscale, |
67 | gdouble tscale) |
68 | { |
69 | GdkPixbufScaledAnim *scaled; |
70 | |
71 | scaled = g_object_new (GDK_TYPE_PIXBUF_SCALED_ANIM, NULL); |
72 | |
73 | scaled->anim = g_object_ref (anim); |
74 | scaled->xscale = xscale; |
75 | scaled->yscale = yscale; |
76 | scaled->tscale = tscale; |
77 | |
78 | return scaled; |
79 | } |
80 | |
81 | G_DEFINE_TYPE (GdkPixbufScaledAnim, gdk_pixbuf_scaled_anim, GDK_TYPE_PIXBUF_ANIMATION); |
82 | |
83 | static void |
84 | gdk_pixbuf_scaled_anim_init (GdkPixbufScaledAnim *scaled) |
85 | { |
86 | scaled->xscale = 1.0; |
87 | scaled->yscale = 1.0; |
88 | scaled->tscale = 1.0; |
89 | } |
90 | |
91 | static void |
92 | gdk_pixbuf_scaled_anim_finalize (GObject *object) |
93 | { |
94 | GdkPixbufScaledAnim *scaled = (GdkPixbufScaledAnim *)object; |
95 | |
96 | if (scaled->anim) { |
97 | g_object_unref (object: scaled->anim); |
98 | scaled->anim = NULL; |
99 | } |
100 | |
101 | if (scaled->current) { |
102 | g_object_unref (object: scaled->current); |
103 | scaled->current = NULL; |
104 | } |
105 | |
106 | G_OBJECT_CLASS (gdk_pixbuf_scaled_anim_parent_class)->finalize (object); |
107 | } |
108 | |
109 | static gboolean |
110 | is_static_image (GdkPixbufAnimation *anim) |
111 | { |
112 | GdkPixbufScaledAnim *scaled = (GdkPixbufScaledAnim *)anim; |
113 | |
114 | return gdk_pixbuf_animation_is_static_image (animation: scaled->anim); |
115 | } |
116 | |
117 | static GdkPixbuf * |
118 | get_scaled_pixbuf (GdkPixbufScaledAnim *scaled, |
119 | GdkPixbuf *pixbuf) |
120 | { |
121 | GQuark quark; |
122 | gchar **options; |
123 | |
124 | if (scaled->current) |
125 | g_object_unref (object: scaled->current); |
126 | |
127 | /* Preserve the options associated with the original pixbuf |
128 | (if present), mostly so that client programs can use the |
129 | "orientation" option (if present) to rotate the image |
130 | appropriately. gdk_pixbuf_scale_simple (and most other |
131 | gdk transform operations) does not preserve the attached |
132 | options when returning a new pixbuf. */ |
133 | |
134 | quark = g_quark_from_static_string (string: "gdk_pixbuf_options" ); |
135 | options = g_object_get_qdata (G_OBJECT (pixbuf), quark); |
136 | |
137 | /* Get a new scaled pixbuf */ |
138 | scaled->current = gdk_pixbuf_scale_simple (src: pixbuf, |
139 | MAX((int) ((gdouble) gdk_pixbuf_get_width (pixbuf) * scaled->xscale + .5), 1), |
140 | MAX((int) ((gdouble) gdk_pixbuf_get_height (pixbuf) * scaled->yscale + .5), 1), |
141 | interp_type: GDK_INTERP_BILINEAR); |
142 | |
143 | /* Copy the original pixbuf options to the scaled pixbuf */ |
144 | if (options && scaled->current) |
145 | g_object_set_qdata_full (G_OBJECT (scaled->current), quark, |
146 | data: g_strdupv (str_array: options), destroy: (GDestroyNotify) g_strfreev); |
147 | |
148 | return scaled->current; |
149 | } |
150 | |
151 | static GdkPixbuf * |
152 | get_static_image (GdkPixbufAnimation *anim) |
153 | { |
154 | GdkPixbufScaledAnim *scaled = (GdkPixbufScaledAnim *)anim; |
155 | GdkPixbuf *pixbuf; |
156 | |
157 | pixbuf = gdk_pixbuf_animation_get_static_image (animation: scaled->anim); |
158 | return get_scaled_pixbuf (scaled, pixbuf); |
159 | } |
160 | |
161 | static void |
162 | get_size (GdkPixbufAnimation *anim, |
163 | int *width, |
164 | int *height) |
165 | { |
166 | GdkPixbufScaledAnim *scaled = (GdkPixbufScaledAnim *)anim; |
167 | |
168 | GDK_PIXBUF_ANIMATION_GET_CLASS (scaled->anim)->get_size (scaled->anim, width, height); |
169 | if (width) |
170 | *width = (int)(*width * scaled->xscale + .5); |
171 | if (height) |
172 | *height = (int)(*height * scaled->yscale + .5); |
173 | } |
174 | |
175 | G_GNUC_BEGIN_IGNORE_DEPRECATIONS |
176 | static GdkPixbufAnimationIter * |
177 | get_iter (GdkPixbufAnimation *anim, |
178 | const GTimeVal *start_time) |
179 | { |
180 | GdkPixbufScaledAnim *scaled = (GdkPixbufScaledAnim *)anim; |
181 | GdkPixbufScaledAnimIter *iter; |
182 | |
183 | iter = g_object_new (GDK_TYPE_PIXBUF_SCALED_ANIM_ITER, NULL); |
184 | |
185 | iter->scaled = g_object_ref (scaled); |
186 | iter->iter = gdk_pixbuf_animation_get_iter (animation: scaled->anim, start_time); |
187 | |
188 | return (GdkPixbufAnimationIter*)iter; |
189 | } |
190 | G_GNUC_END_IGNORE_DEPRECATIONS |
191 | |
192 | static void |
193 | gdk_pixbuf_scaled_anim_class_init (GdkPixbufScaledAnimClass *klass) |
194 | { |
195 | GObjectClass *object_class; |
196 | GdkPixbufAnimationClass *anim_class; |
197 | |
198 | object_class = G_OBJECT_CLASS (klass); |
199 | anim_class = GDK_PIXBUF_ANIMATION_CLASS (klass); |
200 | |
201 | object_class->finalize = gdk_pixbuf_scaled_anim_finalize; |
202 | |
203 | anim_class->is_static_image = is_static_image; |
204 | anim_class->get_static_image = get_static_image; |
205 | anim_class->get_size = get_size; |
206 | anim_class->get_iter = get_iter; |
207 | } |
208 | |
209 | |
210 | G_DEFINE_TYPE (GdkPixbufScaledAnimIter, gdk_pixbuf_scaled_anim_iter, GDK_TYPE_PIXBUF_ANIMATION_ITER); |
211 | |
212 | static void |
213 | gdk_pixbuf_scaled_anim_iter_init (GdkPixbufScaledAnimIter *iter) |
214 | { |
215 | } |
216 | |
217 | static int |
218 | get_delay_time (GdkPixbufAnimationIter *iter) |
219 | { |
220 | GdkPixbufScaledAnimIter *scaled = (GdkPixbufScaledAnimIter *)iter; |
221 | int delay; |
222 | |
223 | delay = gdk_pixbuf_animation_iter_get_delay_time (iter: scaled->iter); |
224 | delay = (int)(delay * scaled->scaled->tscale); |
225 | |
226 | return delay; |
227 | } |
228 | |
229 | static GdkPixbuf * |
230 | get_pixbuf (GdkPixbufAnimationIter *iter) |
231 | { |
232 | GdkPixbufScaledAnimIter *scaled = (GdkPixbufScaledAnimIter *)iter; |
233 | GdkPixbuf *pixbuf; |
234 | |
235 | pixbuf = gdk_pixbuf_animation_iter_get_pixbuf (iter: scaled->iter); |
236 | return get_scaled_pixbuf (scaled: scaled->scaled, pixbuf); |
237 | } |
238 | |
239 | static gboolean |
240 | on_currently_loading_frame (GdkPixbufAnimationIter *iter) |
241 | { |
242 | GdkPixbufScaledAnimIter *scaled = (GdkPixbufScaledAnimIter *)iter; |
243 | |
244 | return gdk_pixbuf_animation_iter_on_currently_loading_frame (iter: scaled->iter); |
245 | } |
246 | |
247 | G_GNUC_BEGIN_IGNORE_DEPRECATIONS |
248 | static gboolean |
249 | advance (GdkPixbufAnimationIter *iter, |
250 | const GTimeVal *current_time) |
251 | { |
252 | GdkPixbufScaledAnimIter *scaled = (GdkPixbufScaledAnimIter *)iter; |
253 | |
254 | return gdk_pixbuf_animation_iter_advance (iter: scaled->iter, current_time); |
255 | } |
256 | G_GNUC_END_IGNORE_DEPRECATIONS |
257 | |
258 | static void |
259 | gdk_pixbuf_scaled_anim_iter_finalize (GObject *object) |
260 | { |
261 | GdkPixbufScaledAnimIter *iter = (GdkPixbufScaledAnimIter *)object; |
262 | |
263 | g_object_unref (object: iter->iter); |
264 | g_object_unref (object: iter->scaled); |
265 | |
266 | G_OBJECT_CLASS (gdk_pixbuf_scaled_anim_iter_parent_class)->finalize (object); |
267 | } |
268 | |
269 | static void |
270 | gdk_pixbuf_scaled_anim_iter_class_init (GdkPixbufScaledAnimIterClass *klass) |
271 | { |
272 | GObjectClass *object_class; |
273 | GdkPixbufAnimationIterClass *anim_iter_class; |
274 | |
275 | object_class = G_OBJECT_CLASS (klass); |
276 | anim_iter_class = GDK_PIXBUF_ANIMATION_ITER_CLASS (klass); |
277 | |
278 | object_class->finalize = gdk_pixbuf_scaled_anim_iter_finalize; |
279 | |
280 | anim_iter_class->get_delay_time = get_delay_time; |
281 | anim_iter_class->get_pixbuf = get_pixbuf; |
282 | anim_iter_class->on_currently_loading_frame = on_currently_loading_frame; |
283 | anim_iter_class->advance = advance; |
284 | } |
285 | |