Mercurial > geeqie
annotate src/pixbuf_util.c @ 16:651c8313449f
store sourceforge CVS notice in CVS
author | gqview |
---|---|
date | Thu, 03 Mar 2005 19:33:25 +0000 |
parents | 147f4c4b9025 |
children | a41ecbb26a96 |
rev | line source |
---|---|
9 | 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 | |
12
147f4c4b9025
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
620 pixbuf_copy_font(buffer, sx, sy, |
9 | 621 pixbuf, x, y, w, h, |
622 r, g, b, a); | |
623 | |
624 g_object_unref(buffer); | |
625 } | |
626 |