comparison src/pixbuf_util.c @ 9:d907d608745f

Sync to GQview 1.5.9 release. ######## DO NOT BASE ENHANCEMENTS OR TRANSLATION UPDATES ON CODE IN THIS CVS! This CVS is never up to date with current development and is provided solely for reference purposes, please use the latest official release package when making any changes or translation updates. ########
author gqview
date Sat, 26 Feb 2005 00:13:35 +0000
parents
children 147f4c4b9025
comparison
equal deleted inserted replaced
8:e0d0593d519e 9:d907d608745f
1 /*
2 * GQview
3 * (C) 2004 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
13 #include "gqview.h"
14 #include "pixbuf_util.h"
15
16 #include "icons/icons_inline.h"
17
18
19 /*
20 *-----------------------------------------------------------------------------
21 * png save
22 *-----------------------------------------------------------------------------
23 */
24
25 gboolean pixbuf_to_file_as_png (GdkPixbuf *pixbuf, const char *filename)
26 {
27 GError *error = NULL;
28 gint ret;
29
30 if (!pixbuf || !filename) return FALSE;
31
32 ret = gdk_pixbuf_save(pixbuf, filename, "png", &error,
33 "tEXt::Software", "GQview "VERSION, NULL);
34
35 if (error)
36 {
37 printf("Error saving png file: %s\n", error->message);
38 g_error_free(error);
39 }
40
41 return ret;
42 }
43
44 /*
45 *-----------------------------------------------------------------------------
46 * jpeg save
47 *-----------------------------------------------------------------------------
48 */
49
50 gboolean pixbuf_to_file_as_jpg(GdkPixbuf *pixbuf, const gchar *filename, gint quality)
51 {
52 GError *error = NULL;
53 gchar *qbuf;
54 gboolean ret;
55
56 if (!pixbuf || !filename) return FALSE;
57
58 if (quality == -1) quality = 75;
59 if (quality < 1 || quality > 100)
60 {
61 printf("Jpeg not saved, invalid quality %d\n", quality);
62 return FALSE;
63 }
64
65 qbuf = g_strdup_printf("%d", quality);
66 ret = gdk_pixbuf_save(pixbuf, filename, "jpeg", &error, "quality", qbuf, NULL);
67 g_free(qbuf);
68
69 if (error)
70 {
71 printf("Error saving jpeg to %s\n%s\n", filename, error->message);
72 g_error_free(error);
73 }
74
75 return ret;
76 }
77
78 /*
79 *-----------------------------------------------------------------------------
80 * pixbuf from inline
81 *-----------------------------------------------------------------------------
82 */
83
84 typedef struct _PixbufInline PixbufInline;
85 struct _PixbufInline
86 {
87 const gchar *key;
88 const guint8 *data;
89 };
90
91 static PixbufInline inline_pixbuf_data[] = {
92 { PIXBUF_INLINE_FOLDER_CLOSED, folder_closed },
93 { PIXBUF_INLINE_FOLDER_LOCKED, folder_locked },
94 { PIXBUF_INLINE_FOLDER_OPEN, folder_open },
95 { PIXBUF_INLINE_FOLDER_UP, folder_up },
96 { PIXBUF_INLINE_SCROLLER, icon_scroller },
97 { PIXBUF_INLINE_BROKEN, icon_broken },
98 { PIXBUF_INLINE_LOGO, gqview_logo },
99 { NULL, NULL }
100 };
101
102 GdkPixbuf *pixbuf_inline(const gchar *key)
103 {
104 gint i;
105
106 if (!key) return NULL;
107
108 i = 0;
109 while (inline_pixbuf_data[i].key)
110 {
111 if (strcmp(inline_pixbuf_data[i].key, key) == 0)
112 {
113 return gdk_pixbuf_new_from_inline(-1, inline_pixbuf_data[i].data, FALSE, NULL);
114 }
115 i++;
116 }
117
118 printf("warning: inline pixbuf key \"%s\" not found.\n", key);
119
120 return NULL;
121 }
122
123 /*
124 *-----------------------------------------------------------------------------
125 * pixbuf rotation
126 *-----------------------------------------------------------------------------
127 */
128
129 static void pixbuf_copy_block_rotate(guchar *src, gint src_row_stride, gint x, gint y,
130 guchar *dest, gint dest_row_stride, gint w, gint h,
131 gint bytes_per_pixel, gint counter_clockwise)
132 {
133 gint i, j;
134 guchar *sp;
135 guchar *dp;
136
137 for (i = 0; i < h; i++)
138 {
139 sp = src + ((i + y) * src_row_stride) + (x * bytes_per_pixel);
140 for (j = 0; j < w; j++)
141 {
142 if (counter_clockwise)
143 {
144 dp = dest + ((w - j - 1) * dest_row_stride) + (i * bytes_per_pixel);
145 }
146 else
147 {
148 dp = dest + (j * dest_row_stride) + ((h - i - 1) * bytes_per_pixel);
149 }
150 *(dp++) = *(sp++); /* r */
151 *(dp++) = *(sp++); /* g */
152 *(dp++) = *(sp++); /* b */
153 if (bytes_per_pixel == 4) *(dp) = *(sp++); /* a */
154 }
155 }
156
157 }
158
159 static void pixbuf_copy_block(guchar *src, gint src_row_stride, gint w, gint h,
160 guchar *dest, gint dest_row_stride, gint x, gint y, gint bytes_per_pixel)
161 {
162 gint i;
163 guchar *sp;
164 guchar *dp;
165
166 for (i = 0; i < h; i++)
167 {
168 sp = src + (i * src_row_stride);
169 dp = dest + ((y + i) * dest_row_stride) + (x * bytes_per_pixel);
170 memcpy(dp, sp, w * bytes_per_pixel);
171 }
172 }
173
174 #define ROTATE_BUFFER_WIDTH 48
175 #define ROTATE_BUFFER_HEIGHT 48
176
177 /*
178 * Returns a copy of pixbuf src rotated 90 degrees clockwise or 90 counterclockwise
179 *
180 */
181 GdkPixbuf *pixbuf_copy_rotate_90(GdkPixbuf *src, gint counter_clockwise)
182 {
183 GdkPixbuf *dest;
184 gint has_alpha;
185 gint sw, sh, srs;
186 gint dw, dh, drs;
187 guchar *s_pix;
188 guchar *d_pix;
189 #if 0
190 guchar *sp;
191 guchar *dp;
192 #endif
193 gint i, j;
194 gint a;
195 GdkPixbuf *buffer;
196 guchar *b_pix;
197 gint brs;
198 gint w, h;
199
200 if (!src) return NULL;
201
202 sw = gdk_pixbuf_get_width(src);
203 sh = gdk_pixbuf_get_height(src);
204 has_alpha = gdk_pixbuf_get_has_alpha(src);
205 srs = gdk_pixbuf_get_rowstride(src);
206 s_pix = gdk_pixbuf_get_pixels(src);
207
208 dw = sh;
209 dh = sw;
210 dest = gdk_pixbuf_new(GDK_COLORSPACE_RGB, has_alpha, 8, dw, dh);
211 drs = gdk_pixbuf_get_rowstride(dest);
212 d_pix = gdk_pixbuf_get_pixels(dest);
213
214 a = (has_alpha ? 4 : 3);
215
216 buffer = gdk_pixbuf_new(GDK_COLORSPACE_RGB, has_alpha, 8,
217 ROTATE_BUFFER_WIDTH, ROTATE_BUFFER_HEIGHT);
218 b_pix = gdk_pixbuf_get_pixels(buffer);
219 brs = gdk_pixbuf_get_rowstride(buffer);
220
221 for (i = 0; i < sh; i+= ROTATE_BUFFER_WIDTH)
222 {
223 w = MIN(ROTATE_BUFFER_WIDTH, (sh - i));
224 for (j = 0; j < sw; j += ROTATE_BUFFER_HEIGHT)
225 {
226 gint x, y;
227
228 h = MIN(ROTATE_BUFFER_HEIGHT, (sw - j));
229 pixbuf_copy_block_rotate(s_pix, srs, j, i,
230 b_pix, brs, h, w,
231 a, counter_clockwise);
232
233 if (counter_clockwise)
234 {
235 x = i;
236 y = sw - h - j;
237 }
238 else
239 {
240 x = sh - w - i;
241 y = j;
242 }
243 pixbuf_copy_block(b_pix, brs, w, h,
244 d_pix, drs, x, y, a);
245 }
246 }
247
248 gdk_pixbuf_unref(buffer);
249
250 #if 0
251 /* this is the simple version of rotation (roughly 2-4x slower) */
252
253 for (i = 0; i < sh; i++)
254 {
255 sp = s_pix + (i * srs);
256 for (j = 0; j < sw; j++)
257 {
258 if (counter_clockwise)
259 {
260 dp = d_pix + ((dh - j - 1) * drs) + (i * a);
261 }
262 else
263 {
264 dp = d_pix + (j * drs) + ((dw - i - 1) * a);
265 }
266
267 *(dp++) = *(sp++); /* r */
268 *(dp++) = *(sp++); /* g */
269 *(dp++) = *(sp++); /* b */
270 if (has_alpha) *(dp) = *(sp++); /* a */
271 }
272 }
273 #endif
274
275 return dest;
276 }
277
278 /*
279 * Returns a copy of pixbuf mirrored and or flipped.
280 * TO do a 180 degree rotations set both mirror and flipped TRUE
281 * if mirror and flip are FALSE, result is a simple copy.
282 */
283 GdkPixbuf *pixbuf_copy_mirror(GdkPixbuf *src, gint mirror, gint flip)
284 {
285 GdkPixbuf *dest;
286 gint has_alpha;
287 gint w, h, srs;
288 gint drs;
289 guchar *s_pix;
290 guchar *d_pix;
291 guchar *sp;
292 guchar *dp;
293 gint i, j;
294 gint a;
295
296 if (!src) return NULL;
297
298 w = gdk_pixbuf_get_width(src);
299 h = gdk_pixbuf_get_height(src);
300 has_alpha = gdk_pixbuf_get_has_alpha(src);
301 srs = gdk_pixbuf_get_rowstride(src);
302 s_pix = gdk_pixbuf_get_pixels(src);
303
304 dest = gdk_pixbuf_new(GDK_COLORSPACE_RGB, has_alpha, 8, w, h);
305 drs = gdk_pixbuf_get_rowstride(dest);
306 d_pix = gdk_pixbuf_get_pixels(dest);
307
308 a = has_alpha ? 4 : 3;
309
310 for (i = 0; i < h; i++)
311 {
312 sp = s_pix + (i * srs);
313 if (flip)
314 {
315 dp = d_pix + ((h - i - 1) * drs);
316 }
317 else
318 {
319 dp = d_pix + (i * drs);
320 }
321 if (mirror)
322 {
323 dp += (w - 1) * a;
324 for (j = 0; j < w; j++)
325 {
326 *(dp++) = *(sp++); /* r */
327 *(dp++) = *(sp++); /* g */
328 *(dp++) = *(sp++); /* b */
329 if (has_alpha) *(dp) = *(sp++); /* a */
330 dp -= (a + 3);
331 }
332 }
333 else
334 {
335 for (j = 0; j < w; j++)
336 {
337 *(dp++) = *(sp++); /* r */
338 *(dp++) = *(sp++); /* g */
339 *(dp++) = *(sp++); /* b */
340 if (has_alpha) *(dp++) = *(sp++); /* a */
341 }
342 }
343 }
344
345 return dest;
346 }
347
348
349 /*
350 *-----------------------------------------------------------------------------
351 * pixbuf drawing
352 *-----------------------------------------------------------------------------
353 */
354
355 /*
356 * Fills region of pixbuf at x,y over w,h
357 * with colors red (r), green (g), blue (b)
358 * applying alpha (a), use a=255 for solid.
359 */
360 void pixbuf_draw_rect_fill(GdkPixbuf *pb,
361 gint x, gint y, gint w, gint h,
362 gint r, gint g, gint b, gint a)
363 {
364 gint p_alpha;
365 gint pw, ph, prs;
366 guchar *p_pix;
367 guchar *pp;
368 gint i, j;
369
370 if (!pb) return;
371
372 pw = gdk_pixbuf_get_width(pb);
373 ph = gdk_pixbuf_get_height(pb);
374
375 if (x < 0 || x + w > pw) return;
376 if (y < 0 || y + h > ph) return;
377
378 p_alpha = gdk_pixbuf_get_has_alpha(pb);
379 prs = gdk_pixbuf_get_rowstride(pb);
380 p_pix = gdk_pixbuf_get_pixels(pb);
381
382 for (i = 0; i < h; i++)
383 {
384 pp = p_pix + (y + i) * prs + (x * (p_alpha ? 4 : 3));
385 for (j = 0; j < w; j++)
386 {
387 *pp = (r * a + *pp * (256-a)) >> 8;
388 pp++;
389 *pp = (g * a + *pp * (256-a)) >> 8;
390 pp++;
391 *pp = (b * a + *pp * (256-a)) >> 8;
392 pp++;
393 if (p_alpha) pp++;
394 }
395 }
396 }
397
398 void pixbuf_draw_rect(GdkPixbuf *pb,
399 gint x, gint y, gint w, gint h,
400 gint r, gint g, gint b, gint a,
401 gint left, gint right, gint top, gint bottom)
402 {
403 pixbuf_draw_rect_fill(pb, x + left, y, w - left - right, top,
404 r, g, b ,a);
405 pixbuf_draw_rect_fill(pb, x + w - right, y, right, h,
406 r, g, b ,a);
407 pixbuf_draw_rect_fill(pb, x + left, y + h - bottom, w - left - right, bottom,
408 r, g, b ,a);
409 pixbuf_draw_rect_fill(pb, x, y, left, h,
410 r, g, b ,a);
411 }
412
413 void pixbuf_set_rect_fill(GdkPixbuf *pb,
414 gint x, gint y, gint w, gint h,
415 gint r, gint g, gint b, gint a)
416 {
417 gint p_alpha;
418 gint pw, ph, prs;
419 guchar *p_pix;
420 guchar *pp;
421 gint i, j;
422
423 if (!pb) return;
424
425 pw = gdk_pixbuf_get_width(pb);
426 ph = gdk_pixbuf_get_height(pb);
427
428 if (x < 0 || x + w > pw) return;
429 if (y < 0 || y + h > ph) return;
430
431 p_alpha = gdk_pixbuf_get_has_alpha(pb);
432 prs = gdk_pixbuf_get_rowstride(pb);
433 p_pix = gdk_pixbuf_get_pixels(pb);
434
435 for (i = 0; i < h; i++)
436 {
437 pp = p_pix + (y + i) * prs + (x * (p_alpha ? 4 : 3));
438 for (j = 0; j < w; j++)
439 {
440 *pp = r; pp++;
441 *pp = g; pp++;
442 *pp = b; pp++;
443 if (p_alpha) { *pp = a; pp++; }
444 }
445 }
446 }
447
448 void pixbuf_set_rect(GdkPixbuf *pb,
449 gint x, gint y, gint w, gint h,
450 gint r, gint g, gint b, gint a,
451 gint left, gint right, gint top, gint bottom)
452 {
453 pixbuf_set_rect_fill(pb, x + left, y, w - left - right, top,
454 r, g, b ,a);
455 pixbuf_set_rect_fill(pb, x + w - right, y, right, h,
456 r, g, b ,a);
457 pixbuf_set_rect_fill(pb, x + left, y + h - bottom, w - left - right, bottom,
458 r, g, b ,a);
459 pixbuf_set_rect_fill(pb, x, y, left, h,
460 r, g, b ,a);
461 }
462
463 void pixbuf_pixel_set(GdkPixbuf *pb, gint x, gint y, gint r, gint g, gint b, gint a)
464 {
465 guchar *buf;
466 gint has_alpha;
467 gint rowstride;
468 guchar *p;
469
470 if (x < 0 || x >= gdk_pixbuf_get_width(pb) ||
471 y < 0 || y >= gdk_pixbuf_get_height(pb)) return;
472
473 buf = gdk_pixbuf_get_pixels(pb);
474 has_alpha = gdk_pixbuf_get_has_alpha(pb);
475 rowstride = gdk_pixbuf_get_rowstride(pb);
476
477 p = buf + (y * rowstride) + (x * (has_alpha ? 4 : 3));
478 *p = r; p++;
479 *p = g; p++;
480 *p = b; p++;
481 if (has_alpha) *p = a;
482 }
483
484
485 /*
486 *-----------------------------------------------------------------------------
487 * pixbuf text rendering
488 *-----------------------------------------------------------------------------
489 */
490
491 static void pixbuf_copy_font(GdkPixbuf *src, gint sx, gint sy,
492 GdkPixbuf *dest, gint dx, gint dy,
493 gint w, gint h,
494 guint8 r, guint8 g, guint8 b, guint8 a)
495 {
496 gint sw, sh, srs;
497 gint s_alpha;
498 gint s_step;
499 guchar *s_pix;
500 gint dw, dh, drs;
501 gint d_alpha;
502 gint d_step;
503 guchar *d_pix;
504
505 guchar *sp;
506 guchar *dp;
507 gint i, j;
508
509 if (!src || !dest) return;
510
511 sw = gdk_pixbuf_get_width(src);
512 sh = gdk_pixbuf_get_height(src);
513
514 if (sx < 0 || sx + w > sw) return;
515 if (sy < 0 || sy + h > sh) return;
516
517 dw = gdk_pixbuf_get_width(dest);
518 dh = gdk_pixbuf_get_height(dest);
519
520 if (dx < 0 || dx + w > dw) return;
521 if (dy < 0 || dy + h > dh) return;
522
523 s_alpha = gdk_pixbuf_get_has_alpha(src);
524 d_alpha = gdk_pixbuf_get_has_alpha(dest);
525 srs = gdk_pixbuf_get_rowstride(src);
526 drs = gdk_pixbuf_get_rowstride(dest);
527 s_pix = gdk_pixbuf_get_pixels(src);
528 d_pix = gdk_pixbuf_get_pixels(dest);
529
530 s_step = (s_alpha) ? 4 : 3;
531 d_step = (d_alpha) ? 4 : 3;
532
533 for (i = 0; i < h; i++)
534 {
535 sp = s_pix + (sy + i) * srs + sx * s_step;
536 dp = d_pix + (dy + i) * drs + dx * d_step;
537 for (j = 0; j < w; j++)
538 {
539 if (*sp)
540 {
541 guint8 asub;
542
543 asub = a * sp[0] / 255;
544 *dp = (r * asub + *dp * (256-asub)) >> 8;
545 dp++;
546 asub = a * sp[1] / 255;
547 *dp = (g * asub + *dp * (256-asub)) >> 8;
548 dp++;
549 asub = a * sp[2] / 255;
550 *dp = (b * asub + *dp * (256-asub)) >> 8;
551 dp++;
552
553 if (d_alpha)
554 {
555 *dp = MAX(*dp, a * ((sp[0] + sp[1] + sp[2]) / 3) / 255);
556 dp++;
557 }
558 }
559 else
560 {
561 dp += d_step;
562 }
563
564 sp += s_step;
565 }
566 }
567 }
568
569 void pixbuf_draw_layout(GdkPixbuf *pixbuf, PangoLayout *layout, GtkWidget *widget,
570 gint x, gint y,
571 guint8 r, guint8 g, guint8 b, guint8 a)
572 {
573 GdkPixmap *pixmap;
574 GdkPixbuf *buffer;
575 gint w, h;
576 GdkGC *gc;
577 gint sx, sy;
578 gint dw, dh;
579
580 if (!widget || !widget->window) return;
581
582 pango_layout_get_pixel_size(layout, &w, &h);
583 pixmap = gdk_pixmap_new(widget->window, w, h, -1);
584
585 gc = gdk_gc_new(widget->window);
586 gdk_gc_copy(gc, widget->style->black_gc);
587 gdk_draw_rectangle(pixmap, gc, TRUE, 0, 0, w, h);
588 gdk_gc_copy(gc, widget->style->white_gc);
589 gdk_draw_layout(pixmap, gc, 0, 0, layout);
590 g_object_unref(gc);
591
592 buffer = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, w, h);
593 gdk_pixbuf_get_from_drawable(buffer, pixmap,
594 gdk_drawable_get_colormap(widget->window),
595 0, 0, 0, 0, w, h);
596 g_object_unref(pixmap);
597
598 sx = 0;
599 sy = 0;
600 dw = gdk_pixbuf_get_width(pixbuf);
601 dh = gdk_pixbuf_get_height(pixbuf);
602
603 if (x < 0)
604 {
605 w += x;
606 sx = -x;
607 x = 0;
608 }
609
610 if (y < 0)
611 {
612 h += y;
613 sy = -y;
614 y = 0;
615 }
616
617 if (x + w > dw) w = dw - x;
618 if (y + h > dh) h = dh - y;
619
620 pixbuf_copy_font(buffer, 0, 0,
621 pixbuf, x, y, w, h,
622 r, g, b, a);
623
624 g_object_unref(buffer);
625 }
626