Re: drawing text and GdkPixbuf
- From: Ramiro Estrugo <ramiro fateware com>
- To: Darin Adler <darin eazel com>
- Cc: Gnome Developers <gnome-devel-list gnome org>
- Subject: Re: drawing text and GdkPixbuf
- Date: Tue, 02 May 2000 20:21:53 -0700
Darin Adler wrote:
>
> Here's the situation. I have a GdkPixbuf. I want to draw some text and
> overlay it on top of the existing stuff in the pixbuf within a particular
> rectangle. How can I do that? Can I create a GdkBitmap and draw into that
> and then composite that into the GdkPixbuf somehow? Is this whole thing just
> a misguided X novice problem?
>
> Do I have to suck fonts out of the X server like the GnomeCanvasText canvas
> item does?
>
> -- Darin
>
I wrote a hack to do this for a paint program i wrote a long time ago.
Attatched is a patch for nautilus-gdk-pixbuf-extensions.[ch] that adds a
function to draw text into a gdk_pixbuf.
It works by drawing the text into a pixmap, capturing that information,
matching a given color to what gdk_rgb expects, and coping the bits that
match into the pixbuf.
It would be nice to get rid of gdk_rgb hacks in the patch above. Try it
and if it does what you want we can simplify it.
Also, it can be faster by caching a lot of stuff. Right now gcs are
allocated everytime you draw the text. This is also to fix once (if!)
the patch actually works for you.
-re
Index: nautilus-gdk-pixbuf-extensions.c
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-extensions/nautilus-gdk-pixbuf-extensions.c,v
retrieving revision 1.3
diff -u -r1.3 nautilus-gdk-pixbuf-extensions.c
--- nautilus-gdk-pixbuf-extensions.c 2000/04/13 18:24:19 1.3
+++ nautilus-gdk-pixbuf-extensions.c 2000/05/03 03:16:23
@@ -315,3 +315,325 @@
}
}
}
+
+/* Access the individual RGB components */
+#define NAUTILUS_COLOR_GET_R(_rgba) (((_rgba) >> 16) & 0xff)
+#define NAUTILUS_COLOR_GET_G(_rgba) (((_rgba) >> 8) & 0xff)
+#define NAUTILUS_COLOR_GET_B(_rgba) (((_rgba) >> 0) & 0xff)
+#define NAUTILUS_COLOR_GET_A(_rgba) (((_rgba) >> 24) & 0xff)
+
+#define NAUTILUS_COLOR_EQUAL_RGB(_a, _b) \
+( (NAUTILUS_COLOR_GET_R (_a) == NAUTILUS_COLOR_GET_R (_b)) && \
+ (NAUTILUS_COLOR_GET_G (_a) == NAUTILUS_COLOR_GET_G (_b)) && \
+ (NAUTILUS_COLOR_GET_B (_a) == NAUTILUS_COLOR_GET_B (_b)))
+
+/* Pack RGB values into a 32 bit word. Assume A=255 */
+#define NAUTILUS_COLOR_PACK_RGB(_r, _g, _b) \
+( (255 << 24) | \
+ ((_r) << 16) | \
+ ((_g) << 8) | \
+ ((_b) << 0) )
+
+#define PIXBUF_POKE_RGB(_offset, _color) \
+G_STMT_START { \
+*((_offset) + 0) = NAUTILUS_COLOR_GET_R (_color); \
+*((_offset) + 1) = NAUTILUS_COLOR_GET_G (_color); \
+*((_offset) + 2) = NAUTILUS_COLOR_GET_B (_color); \
+} G_STMT_END
+
+#define NAUTILUS_COLOR_WHITE NAUTILUS_COLOR_PACK_RGB (255, 255, 255)
+
+static GdkGC * nautilus_gdk_create_drawing_gc (GdkWindow *window,
+ guint32 color);
+static guint32 nautilus_gdk_rgb_get_rendered_value_for_rgb (GdkWindow *window,
+ GdkColormap *colormap,
+ guint32 value);
+static void nautilus_gdk_pixbuf_copy_bits_from_gdk_drawable (GdkPixbuf *pixbuf,
+ GdkDrawable *drawable,
+ GdkWindow *window,
+ GdkColormap *colormap,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ int width,
+ int height,
+ guint32 color);
+
+/**
+ * nautilus_gdk_create_drawing_gc
+ * @window: A window (or drawable)
+ * @color: RGB packed color to use for gdk_rgb drawing.
+ *
+ * Create a drawing gc given an rgb packed color.
+ * Returns a newly allocated gc.
+ **/
+static GdkGC *
+nautilus_gdk_create_drawing_gc (GdkWindow *window, guint32 color)
+{
+ GdkGC *drawing_gc;
+
+ g_return_val_if_fail (window != NULL, NULL);
+
+ drawing_gc = gdk_gc_new (window);
+
+ gdk_gc_set_function (drawing_gc, GDK_COPY);
+
+ gdk_rgb_gc_set_foreground (drawing_gc, color);
+
+ return drawing_gc;
+}
+
+/**
+ * nautilus_gdk_rgb_get_rendered_value_for_rgb
+ * @window: A window (or drawable)
+ * @colormap: A colormap that matches the above window.
+ * @guint32: A RGB packed color.
+ *
+ * gdk_rgb doesnt always use RGB values as given. Sometimes it will munge them
+ * to conform to a color cube or limit color usage. This function can be used to
+ * find out exactly what the value that gdk_rgb ends up using is.
+ * Returns a RGB packed color value as known to gdk_rgb.
+ **/
+static guint32
+nautilus_gdk_rgb_get_rendered_value_for_rgb (GdkWindow *window, GdkColormap *colormap, guint32 value)
+{
+ GdkPixmap *pixmap;
+ GdkGC *gc;
+ GdkPixbuf *capture;
+ guchar *pixels;
+ guint32 rv;
+ guchar *p;
+
+ pixmap = gdk_pixmap_new (window, 1, 1, -1);
+
+ g_assert (pixmap != NULL);
+
+ gc = nautilus_gdk_create_drawing_gc (window, value);
+
+ g_assert (gc != NULL);
+
+ gdk_draw_point (window, gc, 0, 0);
+
+ capture = gdk_pixbuf_get_from_drawable (NULL, window, colormap, 0, 0, 0, 0, 1, 1);
+
+ g_assert (capture != NULL);
+
+ pixels = gdk_pixbuf_get_pixels (capture);
+
+ p = pixels;
+
+ rv = NAUTILUS_COLOR_PACK_RGB (*(p + 0), *(p + 1), *(p + 2));
+
+ gdk_pixbuf_unref (capture);
+ gdk_gc_unref (gc);
+ gdk_pixmap_unref (pixmap);
+
+ return rv;
+}
+
+/**
+ * nautilus_gdk_rgb_get_rendered_value_for_rgb
+ * @pixbuf: A gdk_pixbuf to munge.
+ * @drawable: The drawable to copy into the pixbuf.
+ * @source_x: Source X coordinate on the drawable.
+ * @source_y: Source Y coordinate on the drawable.
+ * @dest_x: Dest X coordinate on the pixbuf.
+ * @dest_y: Dest Y coordinate on the pixbuf.
+ * @width: Copy width.
+ * @height: Copy height.
+ * @color: The color to to copy from the drawable.
+ *
+ * Copy bits of a specific color from a drawable to a gdk-pixbuf.
+ **/
+static void
+nautilus_gdk_pixbuf_copy_bits_from_gdk_drawable (GdkPixbuf *pixbuf,
+ GdkDrawable *drawable,
+ GdkWindow *window,
+ GdkColormap *colormap,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ int width,
+ int height,
+ guint32 color)
+{
+ GdkPixbuf *capture;
+ guint32 rendered_color;
+ int capture_x;
+ int capture_y;
+
+ guchar *capture_pixels;
+ guint capture_rowstride;
+ guint capture_pixel_offset;
+
+ guchar *dest_pixels;
+ guint dest_rowstride;
+ guint dest_pixel_offset;
+ guint dest_width;
+ guint dest_height;
+
+ g_return_if_fail (pixbuf != NULL);
+ g_return_if_fail (drawable != NULL);
+ g_return_if_fail (window != NULL);
+ g_return_if_fail (colormap != NULL);
+ g_return_if_fail (width > 0);
+ g_return_if_fail (height > 0);
+
+ capture = gdk_pixbuf_get_from_drawable (NULL,
+ drawable,
+ colormap,
+ source_x,
+ source_y,
+ 0,
+ 0,
+ width,
+ height);
+
+ g_assert (capture != NULL);
+
+ capture_pixels = gdk_pixbuf_get_pixels (capture);
+ capture_rowstride = gdk_pixbuf_get_rowstride (capture);
+ capture_pixel_offset = gdk_pixbuf_get_has_alpha (capture) ? 4 : 3;
+
+ dest_pixels = gdk_pixbuf_get_pixels (pixbuf);
+ dest_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ dest_pixel_offset = gdk_pixbuf_get_has_alpha (pixbuf) ? 4 : 3;
+ dest_width = gdk_pixbuf_get_width (pixbuf);
+ dest_height = gdk_pixbuf_get_height (pixbuf);
+
+ rendered_color = nautilus_gdk_rgb_get_rendered_value_for_rgb (window, colormap, color);
+
+ for (capture_y = 0; capture_y < height; capture_y++)
+ {
+ guchar *row_offset = capture_pixels + capture_y * capture_rowstride;
+
+ for (capture_x = 0; capture_x < width; capture_x++)
+ {
+ guchar *offset = row_offset + capture_x * capture_pixel_offset;
+
+ guint32 peek = NAUTILUS_COLOR_PACK_RGB (*(offset + 0),
+ *(offset + 1),
+ *(offset + 2));
+
+ if (NAUTILUS_COLOR_EQUAL_RGB (peek, rendered_color))
+ {
+ int x = dest_x + capture_x;
+ int y = dest_y + capture_y;
+
+ if (x < dest_width && y < dest_height)
+ {
+ guchar *dest_offset = dest_pixels + y * dest_rowstride + x * dest_pixel_offset;
+
+ PIXBUF_POKE_RGB (dest_offset, rendered_color);
+ }
+ }
+ }
+ }
+
+ gdk_pixbuf_unref (capture);
+}
+
+/**
+ * nautilus_gdk_pixbuf_draw_text
+ * @pixbuf: A gdk_pixbuf to munge.
+ * @font: Font to use.
+ * @window: Window where pixbuf will eventually be copied to.
+ * @colormap: Colormap for the above window.
+ * @x: X coordinate for text drawing.
+ * @y: Y coordinate for text drawing.
+ * @text: The text.
+ * @text_length: The length of the text in characters.
+ * @color: The color to draw the text in.
+ *
+ * Draw text into a gdk_pixbuf using the given coordinates, font and color.
+ *
+ * The window and colormap parameters are needed so that all rendering
+ * operations occur using values that are coherent with what gdk_rgb
+ * uses.
+ **/
+void
+nautilus_gdk_pixbuf_draw_text (GdkPixbuf *pixbuf,
+ GdkFont *font,
+ GdkWindow *window,
+ GdkColormap *colormap,
+ int x,
+ int y,
+ const char *text,
+ guint text_length,
+ guint32 color)
+{
+ GdkPixmap *pixmap;
+ GdkGC *text_gc;
+ GdkGC *clear_gc;
+ int width;
+ int height;
+ int lbearing;
+ int rbearing;
+ int ascent;
+ int descent;
+
+ g_return_if_fail (pixbuf != NULL);
+ g_return_if_fail (font != NULL);
+ g_return_if_fail (window != NULL);
+ g_return_if_fail (colormap != NULL);
+ g_return_if_fail (text != NULL);
+
+ gdk_text_extents (font,
+ text,
+ strlen (text),
+ &lbearing,
+ &rbearing,
+ &width,
+ &ascent,
+ &descent);
+
+ height = ascent + descent;
+
+ g_assert (width > 0);
+ g_assert (height > 0);
+
+ pixmap = gdk_pixmap_new (window, width, height, -1);
+
+ text_gc = nautilus_gdk_create_drawing_gc (window, color);
+
+ g_assert (text_gc != NULL);
+
+ clear_gc = nautilus_gdk_create_drawing_gc (window, NAUTILUS_COLOR_WHITE);
+
+ g_assert (clear_gc != NULL);
+
+ gdk_draw_rectangle (pixmap,
+ clear_gc,
+ TRUE,
+ 0,
+ 0,
+ width,
+ height);
+
+ gdk_draw_text (pixmap,
+ font,
+ text_gc,
+ 0,
+ ascent,
+ text,
+ strlen (text));
+
+ nautilus_gdk_pixbuf_copy_bits_from_gdk_drawable (pixbuf,
+ pixmap,
+ window,
+ colormap,
+ 0,
+ 0,
+ x,
+ y,
+ width,
+ height,
+ color);
+
+ gdk_gc_unref (text_gc);
+ gdk_gc_unref (clear_gc);
+ gdk_pixmap_unref (pixmap);
+}
+
Index: nautilus-gdk-pixbuf-extensions.h
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-extensions/nautilus-gdk-pixbuf-extensions.h,v
retrieving revision 1.1
diff -u -r1.1 nautilus-gdk-pixbuf-extensions.h
--- nautilus-gdk-pixbuf-extensions.h 2000/04/04 01:00:06 1.1
+++ nautilus-gdk-pixbuf-extensions.h 2000/05/03 03:16:23
@@ -38,15 +38,18 @@
void nautilus_gdk_pixbuf_list_unref (GList *pixbuf_list);
void nautilus_gdk_pixbuf_list_free (GList *pixbuf_list);
+
/* Loading a GdkPixbuf with a URI. */
GdkPixbuf * nautilus_gdk_pixbuf_load (const char *uri);
+
/* Same thing async. */
NautilusPixbufLoadHandle *nautilus_gdk_pixbuf_load_async (const char *uri,
NautilusPixbufLoadCallback callback,
gpointer callback_data);
void nautilus_cancel_gdk_pixbuf_load (NautilusPixbufLoadHandle *handle);
+
/* Draw a GdkPixbuf tiled. */
void nautilus_gdk_pixbuf_render_to_drawable_tiled (GdkPixbuf *pixbuf,
GdkDrawable *drawable,
@@ -55,5 +58,14 @@
GdkRgbDither dither,
int x_dither,
int y_dither);
+void nautilus_gdk_pixbuf_draw_text (GdkPixbuf *pixbuf,
+ GdkFont *font,
+ GdkWindow *window,
+ GdkColormap *colormap,
+ int x,
+ int y,
+ const char *text,
+ guint text_length,
+ guint32 color);
#endif /* NAUTILUS_GDK_PIXBUF_EXTENSIONS_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]