Mercurial > geeqie.yaz
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 |