1 /*
2 * (SLIK) SimpLIstic sKin functions
3 * (C) 2002 John Ellis
4 *
5 * Author: John Ellis
6 *
7 * This software is released under the GNU General Public License (GNU GPL).
8 * Please read the included file COPYING for more information.
9 * This software comes with no warranty of any kind, use at your own risk!
10 */
11
12 #include <stdlib.h>
13 #include <math.h>
14
15 #include <glib.h>
16 #include <gdk-pixbuf/gdk-pixbuf.h>
17
18 #include "ui_pixbuf_ops.h"
19
20
21 /*
22 * Copies src to dest, optionally applying alpha
23 * but takes into account the source's alpha channel,
24 * no source alpha results in a simple copy.
25 */
_pixbuf_copy_area_alpha(GdkPixbuf * src,gint sx,gint sy,GdkPixbuf * dest,gint dx,gint dy,gint w,gint h,gint apply_alpha,gint alpha_modifier,gint alpha_too)26 static void _pixbuf_copy_area_alpha(GdkPixbuf *src, gint sx, gint sy,
27 GdkPixbuf *dest, gint dx, gint dy,
28 gint w, gint h, gint apply_alpha,
29 gint alpha_modifier, gint alpha_too)
30 {
31 gint s_alpha;
32 gint d_alpha;
33 gint sw, sh, srs;
34 gint dw, dh, drs;
35 guchar *s_pix;
36 guchar *d_pix;
37 guchar *sp;
38 guchar *dp;
39 guchar r, g, b, a;
40 gint i, j;
41
42 if (!src || !dest) return;
43
44 sw = gdk_pixbuf_get_width(src);
45 sh = gdk_pixbuf_get_height(src);
46
47 if (sx < 0 || sx + w > sw) return;
48 if (sy < 0 || sy + h > sh) return;
49
50 dw = gdk_pixbuf_get_width(dest);
51 dh = gdk_pixbuf_get_height(dest);
52
53 if (dx < 0 || dx + w > dw) return;
54 if (dy < 0 || dy + h > dh) return;
55
56 s_alpha = gdk_pixbuf_get_has_alpha(src);
57 d_alpha = gdk_pixbuf_get_has_alpha(dest);
58 srs = gdk_pixbuf_get_rowstride(src);
59 drs = gdk_pixbuf_get_rowstride(dest);
60 s_pix = gdk_pixbuf_get_pixels(src);
61 d_pix = gdk_pixbuf_get_pixels(dest);
62
63 if (s_alpha && apply_alpha)
64 {
65 for (i = 0; i < h; i++)
66 {
67 sp = s_pix + (sy + i) * srs + sx * 4;
68 dp = d_pix + (dy + i) * drs + (dx * (d_alpha ? 4 : 3));
69 for (j = 0; j < w; j++)
70 {
71 r = *(sp++);
72 g = *(sp++);
73 b = *(sp++);
74 a = (*(sp++) * alpha_modifier) >> 8;
75 *dp = (r * a + *dp * (256-a)) >> 8;
76 dp++;
77 *dp = (g * a + *dp * (256-a)) >> 8;
78 dp++;
79 *dp = (b * a + *dp * (256-a)) >> 8;
80 dp++;
81 if (d_alpha) dp++;
82 }
83 }
84 }
85 else if (alpha_too && s_alpha && d_alpha)
86 {
87 /* I wonder if using memcopy would be faster? */
88 for (i = 0; i < h; i++)
89 {
90 sp = s_pix + (sy + i) * srs + (sx * 4);
91 dp = d_pix + (dy + i) * drs + (dx * 4);
92 for (j = 0; j < w; j++)
93 {
94 *(dp++) = *(sp++); /* r */
95 *(dp++) = *(sp++); /* g */
96 *(dp++) = *(sp++); /* b */
97 *(dp++) = *(sp++); /* a */
98 }
99 }
100 }
101 else
102 {
103 /* I wonder if using memcopy would be faster? */
104 for (i = 0; i < h; i++)
105 {
106 sp = s_pix + (sy + i) * srs + (sx * (s_alpha ? 4 : 3));
107 dp = d_pix + (dy + i) * drs + (dx * (d_alpha ? 4 : 3));
108 for (j = 0; j < w; j++)
109 {
110 *(dp++) = *(sp++); /* r */
111 *(dp++) = *(sp++); /* g */
112 *(dp++) = *(sp++); /* b */
113 if (s_alpha) sp++; /* a (?) */
114 if (d_alpha) dp++; /* a (?) */
115 }
116 }
117 }
118 }
119
120 /*
121 * Copies src to dest, ignoring alpha
122 */
pixbuf_copy_area(GdkPixbuf * src,gint sx,gint sy,GdkPixbuf * dest,gint dx,gint dy,gint w,gint h,gint alpha_too)123 void pixbuf_copy_area(GdkPixbuf *src, gint sx, gint sy,
124 GdkPixbuf *dest, gint dx, gint dy,
125 gint w, gint h, gint alpha_too)
126 {
127 _pixbuf_copy_area_alpha(src, sx, sy, dest, dx, dy, w, h, FALSE, 0, alpha_too);
128 }
129
130 /*
131 * Copies src to dest, applying alpha
132 * no source alpha results in a simple copy.
133 */
pixbuf_copy_area_alpha(GdkPixbuf * src,gint sx,gint sy,GdkPixbuf * dest,gint dx,gint dy,gint w,gint h,gint alpha_modifier)134 void pixbuf_copy_area_alpha(GdkPixbuf *src, gint sx, gint sy,
135 GdkPixbuf *dest, gint dx, gint dy,
136 gint w, gint h, gint alpha_modifier)
137 {
138 _pixbuf_copy_area_alpha(src, sx, sy, dest, dx, dy, w, h, TRUE, alpha_modifier, FALSE);
139 }
140
141 /*
142 * like above, but uses a clip region and/or mask
143 */
pixbuf_copy_area_alpha_with_clipping(GdkPixbuf * src,gint sx,gint sy,GdkPixbuf * dest,gint dx,gint dy,gint w,gint h,gint alpha_modifier,gint clip_x,gint clip_y,gint clip_w,gint clip_h,GdkPixbuf * clip_pb)144 void pixbuf_copy_area_alpha_with_clipping(GdkPixbuf *src, gint sx, gint sy,
145 GdkPixbuf *dest, gint dx, gint dy,
146 gint w, gint h, gint alpha_modifier,
147 gint clip_x, gint clip_y, gint clip_w, gint clip_h, GdkPixbuf *clip_pb)
148 {
149 gint s_alpha;
150 gint d_alpha;
151 gint sw, sh, srs, s_step;
152 gint dw, dh, drs, d_step;
153 guchar *s_pix;
154 guchar *d_pix;
155 guchar *sp;
156 guchar *dp;
157 guchar *clip_pix;
158 gint clip_rs;
159 gint cx, cy;
160 guchar *cp;
161 guchar r, g, b, a;
162 gint i, j;
163 gint clip_x2, clip_y2;
164
165 if (!src || !dest) return;
166
167 if (clip_pb && gdk_pixbuf_get_has_alpha(clip_pb))
168 {
169 clip_w = MIN(clip_w, (gdk_pixbuf_get_width(clip_pb)));
170 clip_h = MIN(clip_h, (gdk_pixbuf_get_height(clip_pb)));
171 clip_pix = gdk_pixbuf_get_pixels(clip_pb);
172 clip_rs = gdk_pixbuf_get_rowstride(clip_pb);
173 }
174 else
175 {
176 clip_pix = NULL;
177 clip_rs = 0;
178 }
179
180 sw = gdk_pixbuf_get_width(src);
181 sh = gdk_pixbuf_get_height(src);
182
183 dw = gdk_pixbuf_get_width(dest);
184 dh = gdk_pixbuf_get_height(dest);
185
186 if (sx < 0 || sx + w > sw) return;
187 if (sy < 0 || sy + h > sh) return;
188
189 cx = clip_x;
190 cy = clip_y;
191
192 clip_x = MAX(clip_x, dx);
193 clip_y = MAX(clip_y, dy);
194
195 clip_w -= clip_x - cx;
196 clip_h -= clip_y - cy;
197
198 clip_x2 = MIN((clip_x + clip_w), (dx + w));
199 clip_y2 = MIN((clip_y + clip_h), (dy + h));
200
201 if (clip_x > dw || clip_y > dh || clip_x2 < 0 || clip_y2 < 0) return;
202
203 if (clip_x < 0) clip_x = 0;
204 if (clip_y < 0) clip_y = 0;
205 if (clip_x2 >= dw) clip_x2 = dw -1;
206 if (clip_y2 >= dh) clip_y2 = dh -1;
207
208 cx = clip_x - cx;
209 cy = clip_y - cy;
210
211 sx += clip_x - dx;
212 sy += clip_y - dy;
213 dx = clip_x;
214 dy = clip_y;
215 w = clip_x2 - clip_x;
216 h = clip_y2 - clip_y;
217
218 if (sx < 0 || sx + w > sw) return;
219 if (sy < 0 || sy + h > sh) return;
220
221 s_alpha = gdk_pixbuf_get_has_alpha(src);
222 d_alpha = gdk_pixbuf_get_has_alpha(dest);
223 srs = gdk_pixbuf_get_rowstride(src);
224 drs = gdk_pixbuf_get_rowstride(dest);
225 s_pix = gdk_pixbuf_get_pixels(src);
226 d_pix = gdk_pixbuf_get_pixels(dest);
227
228 s_step = (s_alpha) ? 4 : 3;
229 d_step = (d_alpha) ? 4 : 3;
230
231 cp = 0;
232
233 for (i = 0; i < h; i++)
234 {
235 sp = s_pix + (sy + i) * srs + sx * s_step;
236 dp = d_pix + (dy + i) * drs + (dx * d_step);
237 if (clip_pix) cp = clip_pix + (cy + i) * clip_rs + cx * 4;
238 for (j = 0; j < w; j++)
239 {
240 if (!clip_pix || *(cp+3) )
241 {
242 r = *(sp++);
243 g = *(sp++);
244 b = *(sp++);
245 a = (s_alpha) ? ((*(sp++) * alpha_modifier) >> 8) : 255;
246 *dp = (r * a + *dp * (256-a)) >> 8;
247 dp++;
248 *dp = (g * a + *dp * (256-a)) >> 8;
249 dp++;
250 *dp = (b * a + *dp * (256-a)) >> 8;
251 dp++;
252 if (d_alpha) dp++;
253 }
254 else
255 {
256 sp += s_step;
257 dp += d_step;
258 }
259 cp += 4;
260 }
261 }
262 }
263
264 /*
265 * Copies src to dest, filling area by tiling ot stretching if dest size > src size
266 */
_pixbuf_copy_fill_alpha(GdkPixbuf * src,gint sx,gint sy,gint sw,gint sh,GdkPixbuf * dest,gint dx,gint dy,gint dw,gint dh,gint stretch,gint apply_alpha,gint alpha_modifier,gint alpha_too,gint offset_x,gint offset_y)267 static void _pixbuf_copy_fill_alpha(GdkPixbuf *src, gint sx, gint sy, gint sw, gint sh,
268 GdkPixbuf *dest, gint dx, gint dy, gint dw, gint dh,
269 gint stretch, gint apply_alpha, gint alpha_modifier, gint alpha_too,
270 gint offset_x, gint offset_y)
271 {
272 if (sw < 1 || sh < 1 || dw < 1 || dh < 1) return;
273
274 if (sw == dw && sh == dh && offset_x == 0 && offset_y == 0)
275 {
276 _pixbuf_copy_area_alpha(src, sx, sy, dest, dx, dy, sw, sh,
277 apply_alpha, alpha_modifier, alpha_too);
278 return;
279 }
280 if (stretch)
281 {
282 if (sw < 1 || sh < 1) return;
283 if (dw < 1 || dh < 1) return;
284
285 /* uh, is it this hard to figure out the offset? or is pixbuf_scale just plain broken
286 * when offets are not 0 ?
287 * (also note stretch does not support offsets)
288 */
289
290 if (apply_alpha)
291 {
292 gdk_pixbuf_composite(src, dest, dx, dy, dw, dh,
293 (double)dx - (sx * (dw / sw)), (double)dy - (sy * (dh / sh)),
294 (double) dw / sw, (double) dh / sh, GDK_INTERP_NEAREST,
295 alpha_modifier);
296 }
297 else
298 {
299 gdk_pixbuf_scale(src, dest, dx, dy, dw, dh,
300 (double)dx - (sx * (dw / sw)), (double)dy - (sy * (dh / sh)),
301 (double) dw / sw, (double) dh / sh, GDK_INTERP_NEAREST);
302 }
303 return;
304 }
305 else
306 {
307 gint x, y;
308
309 /* tile */
310
311 if (offset_x != 0) offset_x = offset_x % sw;
312 if (offset_y != 0) offset_y = offset_y % sh;
313
314 for (x = dx; x < dx + dw; x += sw)
315 for (y = dy; y < dy + dh; y += sh)
316 {
317 gint w, h;
318 gint ox, oy;
319
320 w = sw;
321 h = sh;
322 ox = sx;
323 oy = sy;
324 if (x == dx && offset_x > 0)
325 {
326 ox += offset_x;
327 w -= offset_x;
328 }
329 if (y == dy && offset_y > 0)
330 {
331 oy += offset_y;
332 h -= offset_y;
333 }
334 if (x + w > dx + dw) w = dx + dw - x;
335 if (y + h > dy + dh) h = dy + dh - y;
336 if (w > 0 && h > 0)
337 {
338 _pixbuf_copy_area_alpha(src, ox, oy, dest, x, y, w, h,
339 apply_alpha, alpha_modifier, alpha_too);
340 }
341 }
342 }
343 }
344
pixbuf_copy_fill(GdkPixbuf * src,gint sx,gint sy,gint sw,gint sh,GdkPixbuf * dest,gint dx,gint dy,gint dw,gint dh,gint stretch,gint alpha_too)345 void pixbuf_copy_fill(GdkPixbuf *src, gint sx, gint sy, gint sw, gint sh,
346 GdkPixbuf *dest, gint dx, gint dy, gint dw, gint dh,
347 gint stretch, gint alpha_too)
348 {
349 _pixbuf_copy_fill_alpha(src, sx, sy, sw, sh,
350 dest, dx, dy, dw, dh,
351 stretch, FALSE, 0, alpha_too, 0, 0);
352 }
353
pixbuf_copy_fill_alpha(GdkPixbuf * src,gint sx,gint sy,gint sw,gint sh,GdkPixbuf * dest,gint dx,gint dy,gint dw,gint dh,gint stretch,gint alpha_modifier)354 void pixbuf_copy_fill_alpha(GdkPixbuf *src, gint sx, gint sy, gint sw, gint sh,
355 GdkPixbuf *dest, gint dx, gint dy, gint dw, gint dh,
356 gint stretch, gint alpha_modifier)
357 {
358 _pixbuf_copy_fill_alpha(src, sx, sy, sw, sh,
359 dest, dx, dy, dw, dh,
360 stretch, TRUE, alpha_modifier, FALSE, 0, 0);
361 }
362
pixbuf_copy_fill_alpha_offset(GdkPixbuf * src,gint sx,gint sy,gint sw,gint sh,GdkPixbuf * dest,gint dx,gint dy,gint dw,gint dh,gint stretch,gint alpha_modifier,gint offset_x,gint offset_y)363 void pixbuf_copy_fill_alpha_offset(GdkPixbuf *src, gint sx, gint sy, gint sw, gint sh,
364 GdkPixbuf *dest, gint dx, gint dy, gint dw, gint dh,
365 gint stretch, gint alpha_modifier,
366 gint offset_x, gint offset_y)
367 {
368 _pixbuf_copy_fill_alpha(src, sx, sy, sw, sh,
369 dest, dx, dy, dw, dh,
370 stretch, TRUE, alpha_modifier, FALSE,
371 offset_x, offset_y);
372 }
373
_pixbuf_copy_fill_border(GdkPixbuf * src,GdkPixbuf * dest,gint dx,gint dy,gint dw,gint dh,gint border_left,gint left_stretch,gint border_right,gint right_stretch,gint border_top,gint top_stretch,gint border_bottom,gint bottom_stretch,gint stretch_center,gint apply_alpha,gint alpha_modifier,gint alpha_too)374 static void _pixbuf_copy_fill_border(GdkPixbuf *src, GdkPixbuf *dest,
375 gint dx, gint dy, gint dw, gint dh,
376 gint border_left, gint left_stretch,
377 gint border_right, gint right_stretch,
378 gint border_top, gint top_stretch,
379 gint border_bottom, gint bottom_stretch,
380 gint stretch_center,
381 gint apply_alpha, gint alpha_modifier, gint alpha_too)
382 {
383 gint sw, sh;
384 gint n, m;
385
386 if (!src || !dest) return;
387
388 sw = gdk_pixbuf_get_width(src);
389 sh = gdk_pixbuf_get_height(src);
390
391 /* corners */
392 _pixbuf_copy_area_alpha(src, 0, 0,
393 dest, dx, dy,
394 border_left, border_top,
395 apply_alpha, alpha_modifier, alpha_too);
396 _pixbuf_copy_area_alpha(src, sw - border_right, 0,
397 dest, dx + dw - border_right, dy,
398 border_right, border_top,
399 apply_alpha, alpha_modifier, alpha_too);
400 _pixbuf_copy_area_alpha(src, 0, sh - border_bottom,
401 dest, dx, dy + dh - border_bottom,
402 border_left, border_bottom,
403 apply_alpha, alpha_modifier, alpha_too);
404 _pixbuf_copy_area_alpha(src, sw - border_right, sh - border_bottom,
405 dest, dx + dw - border_right, dy + dh - border_bottom,
406 border_right, border_bottom,
407 apply_alpha, alpha_modifier, alpha_too);
408
409 /* sides */
410 n = border_top + border_bottom; /* vert borders tot. */
411 m = border_left + border_right; /* horz borders tot. */
412
413 _pixbuf_copy_fill_alpha(src, 0, border_top, border_left, sh - n,
414 dest, dx, dy + border_top, border_left, dh - n,
415 left_stretch,
416 apply_alpha, alpha_modifier, alpha_too, 0, 0);
417 _pixbuf_copy_fill_alpha(src, sw - border_right, border_top, border_right, sh - n,
418 dest, dx + dw - border_right, dy + border_top, border_right, dh - n,
419 right_stretch,
420 apply_alpha, alpha_modifier, alpha_too, 0, 0);
421 _pixbuf_copy_fill_alpha(src, border_left, 0, sw - m, border_top,
422 dest, dx + border_left, dy, dw - m, border_top,
423 top_stretch,
424 apply_alpha, alpha_modifier, alpha_too, 0, 0);
425 _pixbuf_copy_fill_alpha(src, border_left, sh - border_bottom, sw - m, border_bottom,
426 dest, dx + border_left, dy + dh - border_bottom, dw - m, border_bottom,
427 bottom_stretch,
428 apply_alpha, alpha_modifier, alpha_too, 0, 0);
429
430 /* center field */
431 _pixbuf_copy_fill_alpha(src, border_left, border_top, sw - m, sh - n,
432 dest, dx + border_left, dy + border_top, dw - m, dh - n,
433 stretch_center,
434 apply_alpha, alpha_modifier, alpha_too, 0, 0);
435 }
436
pixbuf_copy_fill_border(GdkPixbuf * src,GdkPixbuf * dest,gint x,gint y,gint width,gint height,gint border_left,gint left_stretch,gint border_right,gint right_stretch,gint border_top,gint top_stretch,gint border_bottom,gint bottom_stretch,gint stretch_center,gint alpha_too)437 void pixbuf_copy_fill_border(GdkPixbuf *src, GdkPixbuf *dest,
438 gint x, gint y, gint width, gint height,
439 gint border_left, gint left_stretch,
440 gint border_right, gint right_stretch,
441 gint border_top, gint top_stretch,
442 gint border_bottom, gint bottom_stretch,
443 gint stretch_center, gint alpha_too)
444 {
445 _pixbuf_copy_fill_border(src, dest,
446 x, y, width, height,
447 border_left, left_stretch,
448 border_right, right_stretch,
449 border_top, top_stretch,
450 border_bottom, bottom_stretch,
451 stretch_center,
452 FALSE, 0, alpha_too);
453 }
454
pixbuf_copy_fill_border_alpha(GdkPixbuf * src,GdkPixbuf * dest,gint x,gint y,gint width,gint height,gint border_left,gint left_stretch,gint border_right,gint right_stretch,gint border_top,gint top_stretch,gint border_bottom,gint bottom_stretch,gint stretch_center,gint alpha_modifier)455 void pixbuf_copy_fill_border_alpha(GdkPixbuf *src, GdkPixbuf *dest,
456 gint x, gint y, gint width, gint height,
457 gint border_left, gint left_stretch,
458 gint border_right, gint right_stretch,
459 gint border_top, gint top_stretch,
460 gint border_bottom, gint bottom_stretch,
461 gint stretch_center,
462 gint alpha_modifier)
463 {
464 _pixbuf_copy_fill_border(src, dest,
465 x, y, width, height,
466 border_left, left_stretch,
467 border_right, right_stretch,
468 border_top, top_stretch,
469 border_bottom, bottom_stretch,
470 stretch_center,
471 TRUE, alpha_modifier, FALSE);
472 }
473
474 /*
475 * Copies src channel to dest.
476 * channel is 0, 1, 2, or 3 for
477 * red, green, blue, alpha, respectively
478 * obviously, if channel 3 is given and both do not have alpha, nothing happens.
479 */
pixbuf_copy_channel(GdkPixbuf * src,gint sx,gint sy,GdkPixbuf * dest,gint dx,gint dy,gint w,gint h,guint channel)480 void pixbuf_copy_channel(GdkPixbuf *src, gint sx, gint sy,
481 GdkPixbuf *dest, gint dx, gint dy,
482 gint w, gint h, guint channel)
483 {
484 gint s_alpha;
485 gint d_alpha;
486 gint sw, sh, srs;
487 gint dw, dh, drs;
488 guchar *s_pix;
489 guchar *d_pix;
490 guchar *sp;
491 guchar *dp;
492 gint i, j;
493 gint s_step;
494 gint d_step;
495
496 if (!src || !dest) return;
497
498 sw = gdk_pixbuf_get_width(src);
499 sh = gdk_pixbuf_get_height(src);
500
501 if (sx < 0 || sx + w > sw) return;
502 if (sy < 0 || sy + h > sh) return;
503
504 dw = gdk_pixbuf_get_width(dest);
505 dh = gdk_pixbuf_get_height(dest);
506
507 if (dx < 0 || dx + w > dw) return;
508 if (dy < 0 || dy + h > dh) return;
509
510 s_alpha = gdk_pixbuf_get_has_alpha(src);
511 d_alpha = gdk_pixbuf_get_has_alpha(dest);
512 srs = gdk_pixbuf_get_rowstride(src);
513 drs = gdk_pixbuf_get_rowstride(dest);
514 s_pix = gdk_pixbuf_get_pixels(src);
515 d_pix = gdk_pixbuf_get_pixels(dest);
516
517 if (channel < 0 ||
518 (channel > 2 && (!s_alpha || !d_alpha)) ) return;
519 if (channel > 2) channel = 3;
520
521 s_step = s_alpha ? 4 : 3;
522 d_step = d_alpha ? 4 : 3;
523
524 for (i = 0; i < h; i++)
525 {
526 sp = s_pix + (sy + i) * srs + (sx * s_step) + channel;
527 dp = d_pix + (dy + i) * drs + (dx * d_step) + channel;
528 for (j = 0; j < w; j++)
529 {
530 *dp = *sp;
531 dp += d_step;
532 sp += s_step;
533 }
534 }
535
536 }
537
buf_pixel_get(guchar * buf,gint x,gint y,guint8 * r,guint8 * g,guint8 * b,guint8 * a,gint has_alpha,gint rowstride)538 static void buf_pixel_get(guchar *buf, gint x, gint y, guint8 *r, guint8 *g, guint8 *b, guint8 *a,
539 gint has_alpha, gint rowstride)
540 {
541 guchar *p;
542
543 p = buf + (y * rowstride) + (x * (has_alpha ? 4 : 3));
544
545 *r = *(p++);
546 *g = *(p++);
547 *b = *(p++);
548 *a = has_alpha ? *p : 255;
549 }
550
buf_pixel_set(guchar * buf,gint x,gint y,guint8 r,guint8 g,guint8 b,guint8 a,gint has_alpha,gint rowstride)551 static void buf_pixel_set(guchar *buf, gint x, gint y, guint8 r, guint8 g, guint8 b, guint8 a,
552 gint has_alpha, gint rowstride)
553 {
554 guchar *p;
555
556 p = buf + (y * rowstride) + (x * (has_alpha ? 4 : 3));
557
558 *p = (r * a + *p * (256 - a)) >> 8;
559 p++;
560 *p = (g * a + *p * (256 - a)) >> 8;
561 p++;
562 *p = (b * a + *p * (256 - a)) >> 8;
563 }
564
565 /*
566 *---------------------------------------------------------------------------
567 * The rotation code was borrowed from the afterstep clock (asclock), rot.c
568 * and it has been adapted a bit.
569 * Update 3/11/2000: Updated to work with GdkPixbuf buffers, and includes
570 * source alpha channel support. Starting to look nothing like original code.
571 * Only the pixel x, y location lines have remained the same.
572 * Update 5/15/2000: Remove all division.. now use bitshifts, optimizations,
573 * the with_clipping version no longer resembles the original at all.
574 *
575 * Still slower than it should be, IMHO.
576 *---------------------------------------------------------------------------
577 */
578
579 #define PI 3.14159
580
581 /*
582 * Copies src to dest rotated, applying source alpha,
583 * rotation is in degrees.
584 * this version only works well if the source's center offset pixel is not
585 * transparent (alpha value = 0) and is a basic shape.
586 */
pixbuf_copy_rotate_alpha(GdkPixbuf * src,gint offset_x,gint offset_y,GdkPixbuf * dest,gint center_x,gint center_y,double theta)587 void pixbuf_copy_rotate_alpha(GdkPixbuf *src, gint offset_x, gint offset_y,
588 GdkPixbuf *dest, gint center_x, gint center_y,
589 double theta)
590 {
591 guchar *s_buf;
592 gint s_w, s_h;
593 gint s_alpha, s_rs;
594 gint s_step;
595
596 guchar *d_buf;
597 gint d_w, d_h;
598 gint d_alpha, d_rs;
599
600 int done, miss, missed=0;
601 int goup;
602 int goleft;
603
604 int x, y;
605 double xoff, yoff;
606
607 s_buf = gdk_pixbuf_get_pixels(src);
608 s_alpha = gdk_pixbuf_get_has_alpha(src);
609 s_rs = gdk_pixbuf_get_rowstride(src);
610 s_w = gdk_pixbuf_get_width(src);
611 s_h = gdk_pixbuf_get_height(src);
612 s_step = s_alpha ? 4 : 3;
613
614 d_buf = gdk_pixbuf_get_pixels(dest);
615 d_alpha = gdk_pixbuf_get_has_alpha(dest);
616 d_rs = gdk_pixbuf_get_rowstride(dest);
617 d_w = gdk_pixbuf_get_width(dest);
618 d_h = gdk_pixbuf_get_height(dest);
619
620 theta = - theta * PI / 180.0;
621
622 xoff = center_x;
623 yoff = center_y;
624
625 done = FALSE;
626 miss = FALSE;
627
628 goup=TRUE;
629 goleft=TRUE;
630 x = center_x;
631 y = center_y;
632 while(!done)
633 {
634 double ex, ey;
635 int oldx, oldy;
636
637 /* transform into old coordinate system */
638 ex = offset_x-0.25 + ((x-xoff) * cos(theta) - (y-yoff) * sin(theta));
639 ey = offset_y-0.25 + ((x-xoff) * sin(theta) + (y-yoff) * cos(theta));
640 oldx = floor(ex);
641 oldy = floor(ey);
642
643 if(oldx >= -1 && oldx < s_w && oldy >= -1 && oldy < s_h)
644 {
645 if(x >= 0 && y >= 0 && x < d_w && y < d_h)
646 {
647 guchar tr, tg, tb, ta;
648 guchar ag, bg, cg, dg;
649 guchar *pp;
650
651 /* calculate the strength of the according pixels */
652 dg = (guchar)((ex - oldx) * (ey - oldy) * 255.0);
653 cg = (guchar)((oldx + 1 - ex) * (ey - oldy) * 255.0);
654 bg = (guchar)((ex - oldx) * (oldy + 1 - ey) * 255.0);
655 ag = (guchar)((oldx + 1 - ex) * (oldy + 1 - ey) * 255.0);
656
657 tr = 0;
658 tg = 0;
659 tb = 0;
660 ta = 0;
661
662 pp = s_buf + (oldy * s_rs) + (oldx * s_step);
663
664 if(oldx >= 0 && oldy >= 0)
665 {
666 guchar *pw;
667 guchar a;
668
669 pw = pp;
670 a = s_alpha ? *(pw + 3) : 255;
671 tr += (ag * *pw * a >> 16);
672 pw++;
673 tg += (ag * *pw * a >> 16);
674 pw++;
675 tb += (ag * *pw * a >> 16);
676 ta += (ag * a >> 8);
677 }
678 if(oldx + 1 < s_w && oldy >= 0)
679 {
680 guchar *pw;
681 guchar a;
682
683 pw = pp + s_step;
684 a = s_alpha ? *(pw + 3) : 255;
685 tr += (bg * *pw * a >> 16);
686 pw++;
687 tg += (bg * *pw * a >> 16);
688 pw++;
689 tb += (bg * *pw * a >> 16);
690 ta += (bg * a >> 8);
691 }
692 if(oldx >= 0 && oldy + 1 < s_h)
693 {
694 guchar *pw;
695 guchar a;
696
697 pw = pp + s_rs;
698 a = s_alpha ? *(pw + 3) : 255;
699 tr += (cg * *pw * a >> 16);
700 pw++;
701 tg += (cg * *pw * a >> 16);
702 pw++;
703 tb += (cg * *pw * a >> 16);
704 ta += (cg * a >> 8);
705 }
706 if(oldx + 1 < s_w && oldy + 1 < s_h)
707 {
708 guchar *pw;
709 guchar a;
710
711 pw = pp + s_rs + s_step;
712 a = s_alpha ? *(pw + 3) : 255;
713 tr += (dg * *pw * a >> 16);
714 pw++;
715 tg += (dg * *pw * a >> 16);
716 pw++;
717 tb += (dg * *pw * a >> 16);
718 ta += (dg * a >> 8);
719 }
720 buf_pixel_set(d_buf, x, y, tr, tg, tb, ta, d_alpha, d_rs);
721 }
722 missed = 0;
723 miss = FALSE;
724 }
725 else
726 {
727 miss = TRUE;
728 missed++;
729 if(missed >= 15)
730 {
731 if(goup)
732 {
733 goup=FALSE;
734 goleft=FALSE;
735 x = center_x;
736 y = center_y;
737 }
738 else
739 {
740 done = TRUE;
741 }
742 }
743 }
744 if(miss && (missed == 1))
745 {
746 goleft = !goleft;
747 if(goup)
748 y--;
749 else
750 y++;
751
752 }
753 else
754 {
755 if(goleft)
756 x--;
757 else
758 x++;
759 }
760 }
761 }
762
763
764 /*
765 * Copies src to dest rotated, applying source alpha,
766 * rotation is in degrees.
767 * the clipping is the part of dest to apply src, this may be
768 * a little slower than above, but has less 'eccentricities'.
769 */
pixbuf_copy_rotate_alpha_with_clipping(GdkPixbuf * src,gint offset_x,gint offset_y,GdkPixbuf * dest,gint center_x,gint center_y,double theta,gint clip_x,gint clip_y,gint clip_w,gint clip_h,GdkPixbuf * clip_pb)770 void pixbuf_copy_rotate_alpha_with_clipping(GdkPixbuf *src, gint offset_x, gint offset_y,
771 GdkPixbuf *dest, gint center_x, gint center_y,
772 double theta,
773 gint clip_x, gint clip_y, gint clip_w, gint clip_h,
774 GdkPixbuf *clip_pb)
775 {
776 guchar *s_buf;
777 gint s_w, s_h;
778 gint s_alpha, s_rs;
779 gint s_step;
780
781 guchar *d_buf;
782 gint d_w, d_h;
783 gint d_alpha, d_rs;
784
785 guchar *clip_buf;
786 guchar *clip_pp;
787 gint clip_rs;
788
789 gint x, y;
790 double xoff, yoff;
791
792 gint clip_x2;
793 gint clip_y2;
794
795 s_buf = gdk_pixbuf_get_pixels(src);
796 s_alpha = gdk_pixbuf_get_has_alpha(src);
797 s_rs = gdk_pixbuf_get_rowstride(src);
798 s_w = gdk_pixbuf_get_width(src);
799 s_h = gdk_pixbuf_get_height(src);
800 s_step = s_alpha ? 4 : 3;
801
802 d_buf = gdk_pixbuf_get_pixels(dest);
803 d_alpha = gdk_pixbuf_get_has_alpha(dest);
804 d_rs = gdk_pixbuf_get_rowstride(dest);
805 d_w = gdk_pixbuf_get_width(dest);
806 d_h = gdk_pixbuf_get_height(dest);
807
808 theta = - theta * PI / 180.0;
809
810 xoff = center_x;
811 yoff = center_y;
812
813 clip_x2 = clip_x + clip_w;
814 clip_y2 = clip_y + clip_h;
815
816 if (clip_pb && gdk_pixbuf_get_has_alpha(clip_pb))
817 {
818 clip_buf = gdk_pixbuf_get_pixels(clip_pb);
819 clip_rs = gdk_pixbuf_get_rowstride(clip_pb);
820 }
821 else
822 {
823 clip_buf = NULL;
824 clip_rs = 0;
825 }
826
827 clip_pp = NULL;
828
829 if (clip_x < 0 || clip_x >= d_w) return;
830 if (clip_y < 0 || clip_y >= d_h) return;
831 if (clip_x2 >= d_w) clip_x2 = d_w -1;
832 if (clip_y2 >= d_h) clip_y2 = d_h -1;
833
834 for (y = clip_y; y < clip_y2; y++)
835 {
836 if (clip_buf) clip_pp = clip_buf + ((y - clip_y) * clip_rs) + 3;
837 for (x = clip_x; x < clip_x2; x++)
838 {
839 double ex, ey;
840 int oldx, oldy;
841
842 /* transform into old coordinate system */
843 ex = offset_x-0.25 + ((x-xoff) * cos(theta) - (y-yoff) * sin(theta));
844 ey = offset_y-0.25 + ((x-xoff) * sin(theta) + (y-yoff) * cos(theta));
845 oldx = floor(ex);
846 oldy = floor(ey);
847
848 if(oldx >= -1 && oldx < s_w && oldy >= -1 && oldy < s_h &&
849 (!clip_pp || *(clip_pp + ((x - clip_x) * 4))) )
850 {
851 guchar tr, tg, tb, ta;
852 guchar ag, bg, cg, dg;
853 guchar *pp;
854
855 /* calculate the strength of the according pixels */
856 dg = (guchar)((ex - oldx) * (ey - oldy) * 255.0);
857 cg = (guchar)((oldx + 1 - ex) * (ey - oldy) * 255.0);
858 bg = (guchar)((ex - oldx) * (oldy + 1 - ey) * 255.0);
859 ag = (guchar)((oldx + 1 - ex) * (oldy + 1 - ey) * 255.0);
860
861 tr = 0;
862 tg = 0;
863 tb = 0;
864 ta = 0;
865
866 pp = s_buf + (oldy * s_rs) + (oldx * s_step);
867
868 if(oldx >= 0 && oldy >= 0)
869 {
870 guchar *pw;
871 guchar a;
872
873 pw = pp;
874 a = s_alpha ? *(pw + 3) : 255;
875 tr += (ag * *pw * a >> 16);
876 pw++;
877 tg += (ag * *pw * a >> 16);
878 pw++;
879 tb += (ag * *pw * a >> 16);
880 ta += (ag * a >> 8);
881 }
882 if(oldx + 1 < s_w && oldy >= 0)
883 {
884 guchar *pw;
885 guchar a;
886
887 pw = pp + s_step;
888 a = s_alpha ? *(pw + 3) : 255;
889 tr += (bg * *pw * a >> 16);
890 pw++;
891 tg += (bg * *pw * a >> 16);
892 pw++;
893 tb += (bg * *pw * a >> 16);
894 ta += (bg * a >> 8);
895 }
896 if(oldx >= 0 && oldy + 1 < s_h)
897 {
898 guchar *pw;
899 guchar a;
900
901 pw = pp + s_rs;
902 a = s_alpha ? *(pw + 3) : 255;
903 tr += (cg * *pw * a >> 16);
904 pw++;
905 tg += (cg * *pw * a >> 16);
906 pw++;
907 tb += (cg * *pw * a >> 16);
908 ta += (cg * a >> 8);
909 }
910 if(oldx + 1 < s_w && oldy + 1 < s_h)
911 {
912 guchar *pw;
913 guchar a;
914
915 pw = pp + s_rs + s_step;
916 a = s_alpha ? *(pw + 3) : 255;
917 tr += (dg * *pw * a >> 16);
918 pw++;
919 tg += (dg * *pw * a >> 16);
920 pw++;
921 tb += (dg * *pw * a >> 16);
922 ta += (dg * a >> 8);
923 }
924 buf_pixel_set(d_buf, x, y, tr, tg, tb, ta, d_alpha, d_rs);
925 }
926 }
927 }
928 }
929
930 /*
931 * These rotate in increments of 90 degrees, and are analogous to the non
932 * rotated pixbuf_copy_area{_alpha} utils.
933 */
934
_pixbuf_copy_area_alpha_rotate_90(GdkPixbuf * src,gint sx,gint sy,GdkPixbuf * dest,gint dx,gint dy,gint w,gint h,gint apply_alpha,gint alpha_modifier,gint alpha_too,gint rotation)935 static void _pixbuf_copy_area_alpha_rotate_90(GdkPixbuf *src, gint sx, gint sy,
936 GdkPixbuf *dest, gint dx, gint dy,
937 gint w, gint h, gint apply_alpha,
938 gint alpha_modifier, gint alpha_too, gint rotation)
939 {
940 gint s_alpha, s_step;
941 gint d_alpha, d_step;
942 gint sw, sh, srs;
943 gint dw, dh, drs;
944 guchar *s_pix;
945 guchar *d_pix;
946 guchar *sp;
947 guchar *dp;
948 gint i, j;
949
950 if (!src || !dest) return;
951
952 sw = gdk_pixbuf_get_width(src);
953 sh = gdk_pixbuf_get_height(src);
954
955 if (sx < 0 || sx + w > sw) return;
956 if (sy < 0 || sy + h > sh) return;
957
958 dw = gdk_pixbuf_get_width(dest);
959 dh = gdk_pixbuf_get_height(dest);
960
961 if (rotation == 90 || rotation == 270)
962 {
963 if (dx < 0 || dx + h > dw) return;
964 if (dy < 0 || dy + w > dh) return;
965 }
966 else
967 {
968 if (dx < 0 || dx + w > dw) return;
969 if (dy < 0 || dy + h > dh) return;
970 }
971
972 s_alpha = gdk_pixbuf_get_has_alpha(src);
973 d_alpha = gdk_pixbuf_get_has_alpha(dest);
974 srs = gdk_pixbuf_get_rowstride(src);
975 drs = gdk_pixbuf_get_rowstride(dest);
976 s_pix = gdk_pixbuf_get_pixels(src);
977 d_pix = gdk_pixbuf_get_pixels(dest);
978
979 s_step = s_alpha ? 4 : 3;
980 d_step = d_alpha ? 4 : 3;
981
982 if (s_alpha && apply_alpha)
983 {
984 guchar a;
985 switch (rotation)
986 {
987 case 90:
988 for (i = 0; i < w; i++)
989 {
990 sp = s_pix + sy * srs + (sx + i) * s_step;
991 dp = d_pix + (dy + i) * drs + (dx + h - 1) * d_step;
992 for (j = 0; j < h; j++)
993 {
994 a = (*(sp+3) * alpha_modifier) >> 8;
995 *dp = (*sp * a + *dp * (256-a)) >> 8;
996 *(dp+1) = (*(sp+1) * a + *(dp+1) * (256-a)) >> 8;
997 *(dp+2) = (*(sp+2) * a + *(dp+2) * (256-a)) >> 8;
998 sp += srs;
999 dp -= d_step;
1000 }
1001 }
1002 break;
1003 case 180:
1004 for (i = 0; i < h; i++)
1005 {
1006 sp = s_pix + (sy + i) * srs + sx * s_step;
1007 dp = d_pix + (dy + h - i - 1) * drs + (dx + w - 1) * d_step;
1008 for (j = 0; j < w; j++)
1009 {
1010 a = (*(sp+3) * alpha_modifier) >> 8;
1011 *dp = (*sp * a + *dp * (256-a)) >> 8;
1012 *(dp+1) = (*(sp+1) * a + *(dp+1) * (256-a)) >> 8;
1013 *(dp+2) = (*(sp+2) * a + *(dp+2) * (256-a)) >> 8;
1014 sp += s_step;
1015 dp -= d_step;
1016 }
1017 }
1018 break;
1019 case 270:
1020 for (i = 0; i < w; i++)
1021 {
1022 sp = s_pix + sy * srs + (sx + i) * s_step;
1023 dp = d_pix + (dy + w - i - 1) * drs + dx * d_step;
1024 for (j = 0; j < h; j++)
1025 {
1026 a = (*(sp+3) * alpha_modifier) >> 8;
1027 *dp = (*sp * a + *dp * (256-a)) >> 8;
1028 *(dp+1) = (*(sp+1) * a + *(dp+1) * (256-a)) >> 8;
1029 *(dp+2) = (*(sp+2) * a + *(dp+2) * (256-a)) >> 8;
1030 sp += srs;
1031 dp += d_step;
1032 }
1033 }
1034 break;
1035 }
1036 }
1037 else
1038 {
1039 alpha_too = (alpha_too && s_alpha && d_alpha);
1040
1041 switch (rotation)
1042 {
1043 case 90:
1044 for (i = 0; i < w; i++)
1045 {
1046 sp = s_pix + sy * srs + (sx + i) * s_step;
1047 dp = d_pix + (dy + i) * drs + (dx + h - 1) * d_step;
1048 for (j = 0; j < h; j++)
1049 {
1050 *(dp) = *(sp); /* r */
1051 *(dp+1) = *(sp+1); /* g */
1052 *(dp+2) = *(sp+2); /* b */
1053 if (alpha_too) /* a ? */
1054 {
1055 *(dp+3) = *(sp+3);
1056 }
1057 sp += srs;
1058 dp -= d_step;
1059 }
1060 }
1061 break;
1062 case 180:
1063 for (i = 0; i < h; i++)
1064 {
1065 sp = s_pix + (sy + i) * srs + sx * s_step;
1066 dp = d_pix + (dy + h - i - 1) * drs + (dx + w - 1) * d_step;
1067 for (j = 0; j < w; j++)
1068 {
1069 *(dp) = *(sp); /* r */
1070 *(dp+1) = *(sp+1); /* g */
1071 *(dp+2) = *(sp+2); /* b */
1072 if (alpha_too) /* a ? */
1073 {
1074 *(dp+3) = *(sp+3);
1075 }
1076 sp += s_step;
1077 dp -= d_step;
1078 }
1079 }
1080 break;
1081 case 270:
1082 for (i = 0; i < w; i++)
1083 {
1084 sp = s_pix + sy * srs + (sx + i) * s_step;
1085 dp = d_pix + (dy + w - i - 1) * drs + dx * d_step;
1086 for (j = 0; j < h; j++)
1087 {
1088 *(dp) = *(sp); /* r */
1089 *(dp+1) = *(sp+1); /* g */
1090 *(dp+2) = *(sp+2); /* b */
1091 if (alpha_too) /* a ? */
1092 {
1093 *(dp+3) = *(sp+3);
1094 }
1095 sp += srs;
1096 dp += d_step;
1097 }
1098 }
1099 break;
1100 }
1101 }
1102 }
1103
pixbuf_copy_area_rotate_90(GdkPixbuf * src,gint sx,gint sy,GdkPixbuf * dest,gint dx,gint dy,gint w,gint h,gint alpha_too,gint rotation)1104 void pixbuf_copy_area_rotate_90(GdkPixbuf *src, gint sx, gint sy,
1105 GdkPixbuf *dest, gint dx, gint dy,
1106 gint w, gint h, gint alpha_too, gint rotation)
1107 {
1108 _pixbuf_copy_area_alpha_rotate_90(src, sx, sy, dest, dx, dy,
1109 w, h, FALSE, 0, alpha_too, rotation);
1110 }
1111
pixbuf_copy_area_rotate_90_alpha(GdkPixbuf * src,gint sx,gint sy,GdkPixbuf * dest,gint dx,gint dy,gint w,gint h,gint alpha_modifier,gint rotation)1112 void pixbuf_copy_area_rotate_90_alpha(GdkPixbuf *src, gint sx, gint sy,
1113 GdkPixbuf *dest, gint dx, gint dy,
1114 gint w, gint h, gint alpha_modifier, gint rotation)
1115 {
1116 _pixbuf_copy_area_alpha_rotate_90(src, sx, sy, dest, dx, dy,
1117 w, h, TRUE, alpha_modifier, FALSE, rotation);
1118 }
1119
1120
1121 /*
1122 * Fills region of pixbuf at x,y over w,h
1123 * with colors red (r), green (g), blue (b)
1124 * applying alpha (a), use a=255 for solid.
1125 */
pixbuf_draw_rect_fill(GdkPixbuf * pb,gint x,gint y,gint w,gint h,gint r,gint g,gint b,gint a)1126 void pixbuf_draw_rect_fill(GdkPixbuf *pb,
1127 gint x, gint y, gint w, gint h,
1128 gint r, gint g, gint b, gint a)
1129 {
1130 gint p_alpha;
1131 gint pw, ph, prs;
1132 guchar *p_pix;
1133 guchar *pp;
1134 gint i, j;
1135
1136 if (!pb) return;
1137
1138 pw = gdk_pixbuf_get_width(pb);
1139 ph = gdk_pixbuf_get_height(pb);
1140
1141 if (x < 0 || x + w > pw) return;
1142 if (y < 0 || y + h > ph) return;
1143
1144 p_alpha = gdk_pixbuf_get_has_alpha(pb);
1145 prs = gdk_pixbuf_get_rowstride(pb);
1146 p_pix = gdk_pixbuf_get_pixels(pb);
1147
1148 for (i = 0; i < h; i++)
1149 {
1150 pp = p_pix + (y + i) * prs + (x * (p_alpha ? 4 : 3));
1151 for (j = 0; j < w; j++)
1152 {
1153 *pp = (r * a + *pp * (256-a)) >> 8;
1154 pp++;
1155 *pp = (g * a + *pp * (256-a)) >> 8;
1156 pp++;
1157 *pp = (b * a + *pp * (256-a)) >> 8;
1158 pp++;
1159 if (p_alpha) pp++;
1160 }
1161 }
1162 }
1163
pixbuf_draw_rect(GdkPixbuf * pb,gint x,gint y,gint w,gint h,gint r,gint g,gint b,gint a,gint left,gint right,gint top,gint bottom)1164 void pixbuf_draw_rect(GdkPixbuf *pb,
1165 gint x, gint y, gint w, gint h,
1166 gint r, gint g, gint b, gint a,
1167 gint left, gint right, gint top, gint bottom)
1168 {
1169 pixbuf_draw_rect_fill(pb, x + left, y, w - left - right, top,
1170 r, g, b ,a);
1171 pixbuf_draw_rect_fill(pb, x + w - right, y, right, h,
1172 r, g, b ,a);
1173 pixbuf_draw_rect_fill(pb, x + left, y + h - bottom, w - left - right, bottom,
1174 r, g, b ,a);
1175 pixbuf_draw_rect_fill(pb, x, y, left, h,
1176 r, g, b ,a);
1177 }
1178
pixel_shift(gint p,gint saturation,gint adjustment,gint strength)1179 guchar pixel_shift(gint p, gint saturation, gint adjustment, gint strength)
1180 {
1181 gint t;
1182
1183 if (adjustment >= 128)
1184 {
1185 t = CLAMP(saturation + saturation * (adjustment - 128) / 127, 0, 255);
1186 }
1187 else
1188 {
1189 t = saturation * adjustment / 128;
1190 }
1191 p = (p * (255-strength) + t * strength) / 255;
1192
1193 return (guchar)p;
1194 }
1195
1196 /*
1197 * Shifts color hue in region, attempting to maintain intensity.
1198 */
pixbuf_draw_rect_shift(GdkPixbuf * pb,gint x,gint y,gint w,gint h,gint r,gint g,gint b,gint strength)1199 void pixbuf_draw_rect_shift(GdkPixbuf *pb,
1200 gint x, gint y, gint w, gint h,
1201 gint r, gint g, gint b, gint strength)
1202 {
1203 gint p_alpha;
1204 gint pw, ph, prs;
1205 guchar *p_pix;
1206 guchar *pp;
1207 gint i, j;
1208
1209 if (!pb) return;
1210
1211 pw = gdk_pixbuf_get_width(pb);
1212 ph = gdk_pixbuf_get_height(pb);
1213
1214 if (x < 0 || x + w > pw) return;
1215 if (y < 0 || y + h > ph) return;
1216
1217 p_alpha = gdk_pixbuf_get_has_alpha(pb);
1218 prs = gdk_pixbuf_get_rowstride(pb);
1219 p_pix = gdk_pixbuf_get_pixels(pb);
1220
1221 for (i = 0; i < h; i++)
1222 {
1223 pp = p_pix + (y + i) * prs + (x * (p_alpha ? 4 : 3));
1224 for (j = 0; j < w; j++)
1225 {
1226 gint s;
1227
1228 s = (pp[0] + pp[1] + pp[2]) / 3;
1229
1230 *pp = pixel_shift(*pp, s, r, strength);
1231 pp++;
1232 *pp = pixel_shift(*pp, s, g, strength);
1233 pp++;
1234 *pp = pixel_shift(*pp, s, b, strength);
1235 pp++;
1236 if (p_alpha) pp++;
1237 }
1238 }
1239 }
1240
pixel_adjust(gint p,gint a)1241 static guchar pixel_adjust(gint p, gint a)
1242 {
1243 p += a;
1244 if (p < 0) p = 0;
1245 if (p > 255) p = 255;
1246
1247 return (guchar)p;
1248 }
1249
1250 /*
1251 * Adjust the alpha of region of pixbuf at x,y over w,h
1252 * by amount a, use negative to decrease alpha
1253 */
pixbuf_alpha_adjust(GdkPixbuf * pb,gint x,gint y,gint w,gint h,gint a)1254 void pixbuf_alpha_adjust(GdkPixbuf *pb, gint x, gint y, gint w, gint h, gint a)
1255 {
1256 gint pw, ph, prs;
1257 guchar *p_pix;
1258 guchar *pp;
1259 gint i, j;
1260
1261 if (!pb || !gdk_pixbuf_get_has_alpha(pb)) return;
1262
1263 pw = gdk_pixbuf_get_width(pb);
1264 ph = gdk_pixbuf_get_height(pb);
1265
1266 if (x < 0 || x + w > pw) return;
1267 if (y < 0 || y + h > ph) return;
1268
1269 prs = gdk_pixbuf_get_rowstride(pb);
1270 p_pix = gdk_pixbuf_get_pixels(pb);
1271
1272 for (i = 0; i < h; i++)
1273 {
1274 pp = p_pix + (y + i) * prs + (x * 4);
1275 for (j = 0; j < w; j++)
1276 {
1277 pp++;
1278 pp++;
1279 pp++;
1280 *pp = pixel_adjust(*pp, a);
1281 pp++;
1282 }
1283 }
1284 }
1285
1286 /* force alpha to 0 or 255, cutoff is level threshhold */
pixbuf_alpha_force_to_bw(GdkPixbuf * pb,guint8 threshhold)1287 void pixbuf_alpha_force_to_bw(GdkPixbuf *pb, guint8 threshhold)
1288 {
1289 gint pw, ph, prs;
1290 guchar *p_pix;
1291 guchar *pp;
1292 gint i, j;
1293
1294 if (!pb || !gdk_pixbuf_get_has_alpha(pb)) return;
1295
1296 pw = gdk_pixbuf_get_width(pb);
1297 ph = gdk_pixbuf_get_height(pb);
1298
1299 prs = gdk_pixbuf_get_rowstride(pb);
1300 p_pix = gdk_pixbuf_get_pixels(pb);
1301
1302 for (i = 0; i < ph; i++)
1303 {
1304 pp = p_pix + i * prs + 3;
1305 for (j = 0; j < pw; j++)
1306 {
1307 *pp = (*pp < threshhold) ? 0 : 255;
1308 pp += 4;
1309 }
1310 }
1311 }
1312
pixbuf_pixel_get(GdkPixbuf * pb,gint x,gint y,gint * r,gint * g,gint * b,gint * a)1313 void pixbuf_pixel_get(GdkPixbuf *pb, gint x, gint y, gint *r, gint *g, gint *b, gint *a)
1314 {
1315 guint8 nr, ng, nb, na;
1316
1317 if (x < 0 || x >= gdk_pixbuf_get_width(pb) ||
1318 y < 0 || y >= gdk_pixbuf_get_height(pb))
1319 {
1320 nr = ng = nb = na = 0;
1321 }
1322 else
1323 {
1324 guchar *buf;
1325 gint has_alpha;
1326 gint rowstride;
1327 buf = gdk_pixbuf_get_pixels(pb);
1328 has_alpha = gdk_pixbuf_get_has_alpha(pb);
1329 rowstride = gdk_pixbuf_get_rowstride(pb);
1330 buf_pixel_get(buf, x, y, &nr, &ng, &nb, &na, has_alpha, rowstride);
1331 }
1332
1333 if (r) *r = (gint)nr;
1334 if (g) *g = (gint)ng;
1335 if (b) *b = (gint)nb;
1336 if (a) *a = (gint)na;
1337 }
1338
pixbuf_pixel_is_visible(GdkPixbuf * pb,gint x,gint y)1339 gint pixbuf_pixel_is_visible(GdkPixbuf *pb, gint x, gint y)
1340 {
1341 guint8 nr, ng, nb, na;
1342
1343 if (x < 0 || x >= gdk_pixbuf_get_width(pb) ||
1344 y < 0 || y >= gdk_pixbuf_get_height(pb)) return FALSE;
1345
1346 if (!gdk_pixbuf_get_has_alpha(pb)) return FALSE;
1347
1348 buf_pixel_get(gdk_pixbuf_get_pixels(pb), x, y, &nr, &ng, &nb, &na,
1349 TRUE, gdk_pixbuf_get_rowstride(pb));
1350
1351 return ( (na > 0) );
1352 }
1353
pixbuf_copy_point_real(GdkPixbuf * src,gint sx,gint sy,GdkPixbuf * dest,gint dx,gint dy,gint use_alpha,gint at_alpha,gint alpha)1354 static void pixbuf_copy_point_real(GdkPixbuf *src, gint sx, gint sy,
1355 GdkPixbuf *dest, gint dx, gint dy,
1356 gint use_alpha, gint at_alpha, gint alpha)
1357 {
1358 guint8 r, g, b, a;
1359
1360 if (sx < 0 || sx >= gdk_pixbuf_get_width(src)) return;
1361 if (sy < 0 || sy >= gdk_pixbuf_get_height(src)) return;
1362
1363 if (dx < 0 || dx >= gdk_pixbuf_get_width(dest)) return;
1364 if (dy < 0 || dy >= gdk_pixbuf_get_height(dest)) return;
1365
1366 buf_pixel_get(gdk_pixbuf_get_pixels(src), sx, sy, &r, &g, &b, &a,
1367 gdk_pixbuf_get_has_alpha(src), gdk_pixbuf_get_rowstride(src));
1368
1369 if (at_alpha)
1370 {
1371 buf_pixel_set(gdk_pixbuf_get_pixels(dest), dx, dy, r, g, b, alpha * a >> 8,
1372 gdk_pixbuf_get_has_alpha(dest), gdk_pixbuf_get_rowstride(dest));
1373 }
1374 else
1375 {
1376 buf_pixel_set(gdk_pixbuf_get_pixels(dest), dx, dy, r, g, b, use_alpha ? a : 255,
1377 gdk_pixbuf_get_has_alpha(dest), gdk_pixbuf_get_rowstride(dest));
1378 }
1379 }
1380
pixbuf_copy_point(GdkPixbuf * src,gint sx,gint sy,GdkPixbuf * dest,gint dx,gint dy,gint use_alpha)1381 void pixbuf_copy_point(GdkPixbuf *src, gint sx, gint sy,
1382 GdkPixbuf *dest, gint dx, gint dy, gint use_alpha)
1383 {
1384 pixbuf_copy_point_real(src, sx, sy, dest, dx, dy, use_alpha, FALSE, 0);
1385 }
1386
pixbuf_copy_point_at_alpha(GdkPixbuf * src,gint sx,gint sy,GdkPixbuf * dest,gint dx,gint dy,gint alpha)1387 void pixbuf_copy_point_at_alpha(GdkPixbuf *src, gint sx, gint sy,
1388 GdkPixbuf *dest, gint dx, gint dy, gint alpha)
1389 {
1390 pixbuf_copy_point_real(src, sx, sy, dest, dx, dy, FALSE, TRUE, alpha);
1391 }
1392
pixbuf_copy_line(GdkPixbuf * src,gint sx1,gint sy1,gint sx2,gint sy2,GdkPixbuf * dest,gint dx,gint dy,gint use_alpha)1393 void pixbuf_copy_line(GdkPixbuf *src, gint sx1, gint sy1, gint sx2, gint sy2,
1394 GdkPixbuf *dest, gint dx, gint dy, gint use_alpha)
1395 {
1396 guint8 r, g, b, a;
1397 guchar *s_pix, *d_pix;
1398 gint s_alpha, d_alpha;
1399 gint srs, drs;
1400
1401 gint xd, yd;
1402
1403 gfloat xstep, ystep;
1404
1405 gfloat i, j;
1406 gint n, nt;
1407
1408 if (sx1 == sx2 && sy1 == sy2);
1409
1410 if (sx1 < 0 || sx1 >= gdk_pixbuf_get_width(src)) return;
1411 if (sy1 < 0 || sy1 >= gdk_pixbuf_get_height(src)) return;
1412 if (sx2 < 0 || sx2 >= gdk_pixbuf_get_width(src)) return;
1413 if (sy2 < 0 || sy2 >= gdk_pixbuf_get_height(src)) return;
1414
1415 if (dx < 0 || dx >= gdk_pixbuf_get_width(dest)) return;
1416 if (dy < 0 || dy >= gdk_pixbuf_get_height(dest)) return;
1417
1418 xd = sx2 - sx1;
1419 yd = sy2 - sy1;
1420
1421 if (dx + xd < 0 || dx + xd >= gdk_pixbuf_get_width(dest)) return;
1422 if (dy + yd < 0 || dy + yd >= gdk_pixbuf_get_height(dest)) return;
1423
1424 s_pix = gdk_pixbuf_get_pixels(src);
1425 srs = gdk_pixbuf_get_rowstride(src);
1426 s_alpha = gdk_pixbuf_get_has_alpha(src);
1427
1428 d_pix = gdk_pixbuf_get_pixels(dest);
1429 drs = gdk_pixbuf_get_rowstride(dest);
1430 d_alpha = gdk_pixbuf_get_has_alpha(dest);
1431
1432 nt = sqrt(xd * xd + yd * yd);
1433 xstep = (float)xd / nt;
1434 ystep = (float)yd / nt;
1435
1436 i = j = 0.0;
1437 for (n = 0; n < nt; n++)
1438 {
1439 buf_pixel_get(s_pix, sx1 + (gint)j, sy1 + (gint)i, &r, &g, &b, &a, s_alpha, srs);
1440 buf_pixel_set(d_pix, dx + (gint)j, dy + (gint)i, r, g, b, use_alpha ? a : 255, d_alpha, drs);
1441 i += ystep;
1442 j += xstep;
1443 }
1444 }
1445