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