GDK's GdkRGB module allows you to copy a client-side
buffer of image data to a drawable. If you need to
manipulate images extensively, or copy image data to the
server, this is the correct way to do it. You can't
directly manipulate a
GdkPixmap because a pixmap is a server-side
object. Copying image data to the server with gdk_draw_point() would be unbelievably
slow, since each point would require a server request
(probably more than one, since you will need to change
the GC for each point).
Internally, GdkRGB uses an object called GdkImage to rapidly copy image data
to the server in a single request. This is still somewhat
slow---sizeable data does have to be copied---but GdkRGB
is highly tuned and uses shared memory if the client and
server happen to be on the same machine. So it's the
fastest way to perform this task, given the X
architecture. It will also handle some tricky issues for
you (such as adapting to the colormaps and visuals
available on a given X server).
The GdkRGB functions are in a separate header, gdk/gdkrgb.h. Before using any GdkRGB
functions, you must initialize the module with gdk_rgb_init() (Figure 24); this sets up the
visual and colormap GdkRGB will use, and some internal
data structures.
The drawable you intend to copy the RGB buffer to must
use GdkRGB's visual and colormap. If the drawable is a
part of a widget, the easiest way to ensure this is to
push the GdkRGB visual and colormap when you create the
widget:
GtkWidget* widget;
gtk_widget_push_visual(gdk_rgb_get_visual());
gtk_widget_push_colormap(gdk_rgb_get_cmap());
widget = gtk_whatever_new();
gtk_widget_pop_visual();
gtk_widget_pop_colormap();
|
The current version of GTK+ will be better-behaved if you
do this when creating the toplevel window containing the
drawable, instead of when creating the drawable itself.
However, in principle you can do it for only the
drawable.
GdkRGB understands several kinds of image data, including
24- and 32-bit RGB data, 8-bit grayscale, and 8-bit
indexes into an array of RGB values (a client-side GdkRgbCmap). This section
describes only the simplest, 24-bit RGB data; this kind
of buffer is rendered with
gdk_draw_rgb_image(). There are separate functions
to render the other buffer types, but all of them work in
essentially the same way.
A 24-bit RGB buffer is a one-dimensional array of bytes;
every byte triplet makes up a pixel (byte 0 is red, byte
1 is green, byte 2 is blue). Three numbers describe the
size of the array and the location of bytes within it:
-
The width is the number of
pixels (byte triplets) per row of the image.
-
The height is the number of
rows in the image.
-
The rowstride is the number
of bytes between rows. That is, for a buffer with
rowstride r, if row n starts at array index i row n+1
starts at array index i+r.
The rowstride is not necessarily three times the
buffer's width; GdkRGB is faster if both the source
pointer and the rowstride are aligned to a 4-byte
boundary. Specifying a rowstride allows you to use
padding to achieve this.
The x, y,
width, and height
arguments to
gdk_rgb_draw_image() define a region of the target
drawable to copy the RGB buffer to. The RGB buffer must
have at least width
columns and height rows.
Row 0, column 0 of the RGB buffer will be copied to point
(x, y) on the drawable.
Dithering simulates a larger number of colors on displays
with a limited palette. Dithering only matters on 8- and
16-bit displays; 24-bit displays do not have a limited
palette. The dither
argument is an enumerated type; it has three possible
values:
-
GDK_RGB_DITHER_NONE
specifies that no dithering will be done. It's
appropriate for text or line drawings with few
colors, but inappropriate for photographic images.
-
GDK_RGB_DITHER_NORMAL
specifies dithering on 8-bit displays, but not 16-bit
displays. This is usually the best
quality/performance tradeoff.
-
GDK_RGB_DITHER_MAX
specifies that dithering will always be done on 8-
and 16-bit displays. The quality gain on 16-bit
displays is probably not worth the speed
penalty.
The gc argument to gdk_draw_rgb_image() is simply
passed through to
gdk_draw_image() (recall that GdkRGB uses GdkImage internally). The gc components that make sense
are used (such as the clip mask, drawing function, and
subwindow mode).