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!
14 #include "pixbuf_util.h"
16 #include "icons/icons_inline.h"
20 *-----------------------------------------------------------------------------
22 *-----------------------------------------------------------------------------
25 gboolean pixbuf_to_file_as_png (GdkPixbuf *pixbuf, const char *filename)
30 if (!pixbuf || !filename) return FALSE;
32 ret = gdk_pixbuf_save(pixbuf, filename, "png", &error,
33 "tEXt::Software", "GQview "VERSION, NULL);
37 printf("Error saving png file: %s\n", error->message);
45 *-----------------------------------------------------------------------------
47 *-----------------------------------------------------------------------------
50 gboolean pixbuf_to_file_as_jpg(GdkPixbuf *pixbuf, const gchar *filename, gint quality)
56 if (!pixbuf || !filename) return FALSE;
58 if (quality == -1) quality = 75;
59 if (quality < 1 || quality > 100)
61 printf("Jpeg not saved, invalid quality %d\n", quality);
65 qbuf = g_strdup_printf("%d", quality);
66 ret = gdk_pixbuf_save(pixbuf, filename, "jpeg", &error, "quality", qbuf, NULL);
71 printf("Error saving jpeg to %s\n%s\n", filename, error->message);
79 *-----------------------------------------------------------------------------
81 *-----------------------------------------------------------------------------
84 typedef struct _PixbufInline PixbufInline;
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 },
102 GdkPixbuf *pixbuf_inline(const gchar *key)
106 if (!key) return NULL;
109 while (inline_pixbuf_data[i].key)
111 if (strcmp(inline_pixbuf_data[i].key, key) == 0)
113 return gdk_pixbuf_new_from_inline(-1, inline_pixbuf_data[i].data, FALSE, NULL);
118 printf("warning: inline pixbuf key \"%s\" not found.\n", key);
124 *-----------------------------------------------------------------------------
126 *-----------------------------------------------------------------------------
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)
137 for (i = 0; i < h; i++)
139 sp = src + ((i + y) * src_row_stride) + (x * bytes_per_pixel);
140 for (j = 0; j < w; j++)
142 if (counter_clockwise)
144 dp = dest + ((w - j - 1) * dest_row_stride) + (i * bytes_per_pixel);
148 dp = dest + (j * dest_row_stride) + ((h - i - 1) * bytes_per_pixel);
150 *(dp++) = *(sp++); /* r */
151 *(dp++) = *(sp++); /* g */
152 *(dp++) = *(sp++); /* b */
153 if (bytes_per_pixel == 4) *(dp) = *(sp++); /* a */
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)
166 for (i = 0; i < h; i++)
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);
174 #define ROTATE_BUFFER_WIDTH 48
175 #define ROTATE_BUFFER_HEIGHT 48
178 * Returns a copy of pixbuf src rotated 90 degrees clockwise or 90 counterclockwise
181 GdkPixbuf *pixbuf_copy_rotate_90(GdkPixbuf *src, gint counter_clockwise)
200 if (!src) return NULL;
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);
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);
214 a = (has_alpha ? 4 : 3);
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);
221 for (i = 0; i < sh; i+= ROTATE_BUFFER_WIDTH)
223 w = MIN(ROTATE_BUFFER_WIDTH, (sh - i));
224 for (j = 0; j < sw; j += ROTATE_BUFFER_HEIGHT)
228 h = MIN(ROTATE_BUFFER_HEIGHT, (sw - j));
229 pixbuf_copy_block_rotate(s_pix, srs, j, i,
231 a, counter_clockwise);
233 if (counter_clockwise)
243 pixbuf_copy_block(b_pix, brs, w, h,
244 d_pix, drs, x, y, a);
248 gdk_pixbuf_unref(buffer);
251 /* this is the simple version of rotation (roughly 2-4x slower) */
253 for (i = 0; i < sh; i++)
255 sp = s_pix + (i * srs);
256 for (j = 0; j < sw; j++)
258 if (counter_clockwise)
260 dp = d_pix + ((dh - j - 1) * drs) + (i * a);
264 dp = d_pix + (j * drs) + ((dw - i - 1) * a);
267 *(dp++) = *(sp++); /* r */
268 *(dp++) = *(sp++); /* g */
269 *(dp++) = *(sp++); /* b */
270 if (has_alpha) *(dp) = *(sp++); /* a */
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.
283 GdkPixbuf *pixbuf_copy_mirror(GdkPixbuf *src, gint mirror, gint flip)
296 if (!src) return NULL;
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);
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);
308 a = has_alpha ? 4 : 3;
310 for (i = 0; i < h; i++)
312 sp = s_pix + (i * srs);
315 dp = d_pix + ((h - i - 1) * drs);
319 dp = d_pix + (i * drs);
324 for (j = 0; j < w; j++)
326 *(dp++) = *(sp++); /* r */
327 *(dp++) = *(sp++); /* g */
328 *(dp++) = *(sp++); /* b */
329 if (has_alpha) *(dp) = *(sp++); /* a */
335 for (j = 0; j < w; j++)
337 *(dp++) = *(sp++); /* r */
338 *(dp++) = *(sp++); /* g */
339 *(dp++) = *(sp++); /* b */
340 if (has_alpha) *(dp++) = *(sp++); /* a */
350 *-----------------------------------------------------------------------------
352 *-----------------------------------------------------------------------------
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.
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)
372 pw = gdk_pixbuf_get_width(pb);
373 ph = gdk_pixbuf_get_height(pb);
375 if (x < 0 || x + w > pw) return;
376 if (y < 0 || y + h > ph) return;
378 p_alpha = gdk_pixbuf_get_has_alpha(pb);
379 prs = gdk_pixbuf_get_rowstride(pb);
380 p_pix = gdk_pixbuf_get_pixels(pb);
382 for (i = 0; i < h; i++)
384 pp = p_pix + (y + i) * prs + (x * (p_alpha ? 4 : 3));
385 for (j = 0; j < w; j++)
387 *pp = (r * a + *pp * (256-a)) >> 8;
389 *pp = (g * a + *pp * (256-a)) >> 8;
391 *pp = (b * a + *pp * (256-a)) >> 8;
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)
403 pixbuf_draw_rect_fill(pb, x + left, y, w - left - right, top,
405 pixbuf_draw_rect_fill(pb, x + w - right, y, right, h,
407 pixbuf_draw_rect_fill(pb, x + left, y + h - bottom, w - left - right, bottom,
409 pixbuf_draw_rect_fill(pb, x, y, left, h,
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)
425 pw = gdk_pixbuf_get_width(pb);
426 ph = gdk_pixbuf_get_height(pb);
428 if (x < 0 || x + w > pw) return;
429 if (y < 0 || y + h > ph) return;
431 p_alpha = gdk_pixbuf_get_has_alpha(pb);
432 prs = gdk_pixbuf_get_rowstride(pb);
433 p_pix = gdk_pixbuf_get_pixels(pb);
435 for (i = 0; i < h; i++)
437 pp = p_pix + (y + i) * prs + (x * (p_alpha ? 4 : 3));
438 for (j = 0; j < w; j++)
443 if (p_alpha) { *pp = a; pp++; }
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)
453 pixbuf_set_rect_fill(pb, x + left, y, w - left - right, top,
455 pixbuf_set_rect_fill(pb, x + w - right, y, right, h,
457 pixbuf_set_rect_fill(pb, x + left, y + h - bottom, w - left - right, bottom,
459 pixbuf_set_rect_fill(pb, x, y, left, h,
463 void pixbuf_pixel_set(GdkPixbuf *pb, gint x, gint y, gint r, gint g, gint b, gint a)
470 if (x < 0 || x >= gdk_pixbuf_get_width(pb) ||
471 y < 0 || y >= gdk_pixbuf_get_height(pb)) return;
473 buf = gdk_pixbuf_get_pixels(pb);
474 has_alpha = gdk_pixbuf_get_has_alpha(pb);
475 rowstride = gdk_pixbuf_get_rowstride(pb);
477 p = buf + (y * rowstride) + (x * (has_alpha ? 4 : 3));
481 if (has_alpha) *p = a;
486 *-----------------------------------------------------------------------------
487 * pixbuf text rendering
488 *-----------------------------------------------------------------------------
491 static void pixbuf_copy_font(GdkPixbuf *src, gint sx, gint sy,
492 GdkPixbuf *dest, gint dx, gint dy,
494 guint8 r, guint8 g, guint8 b, guint8 a)
509 if (!src || !dest) return;
511 sw = gdk_pixbuf_get_width(src);
512 sh = gdk_pixbuf_get_height(src);
514 if (sx < 0 || sx + w > sw) return;
515 if (sy < 0 || sy + h > sh) return;
517 dw = gdk_pixbuf_get_width(dest);
518 dh = gdk_pixbuf_get_height(dest);
520 if (dx < 0 || dx + w > dw) return;
521 if (dy < 0 || dy + h > dh) return;
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);
530 s_step = (s_alpha) ? 4 : 3;
531 d_step = (d_alpha) ? 4 : 3;
533 for (i = 0; i < h; i++)
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++)
543 asub = a * sp[0] / 255;
544 *dp = (r * asub + *dp * (256-asub)) >> 8;
546 asub = a * sp[1] / 255;
547 *dp = (g * asub + *dp * (256-asub)) >> 8;
549 asub = a * sp[2] / 255;
550 *dp = (b * asub + *dp * (256-asub)) >> 8;
555 *dp = MAX(*dp, a * ((sp[0] + sp[1] + sp[2]) / 3) / 255);
569 void pixbuf_draw_layout(GdkPixbuf *pixbuf, PangoLayout *layout, GtkWidget *widget,
571 guint8 r, guint8 g, guint8 b, guint8 a)
580 if (!widget || !widget->window) return;
582 pango_layout_get_pixel_size(layout, &w, &h);
583 pixmap = gdk_pixmap_new(widget->window, w, h, -1);
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);
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),
596 g_object_unref(pixmap);
600 dw = gdk_pixbuf_get_width(pixbuf);
601 dh = gdk_pixbuf_get_height(pixbuf);
617 if (x + w > dw) w = dw - x;
618 if (y + h > dh) h = dh - y;
620 pixbuf_copy_font(buffer, sx, sy,
624 g_object_unref(buffer);