How do you draw clipped text?
|
28-Feb-01 14:00 GMT
|
Question: Can I use a clip mask use with
"XDrawImageString()" to mask out part of a character. If so,
how do I do it. If a clip mask won't work, is there another
technique? I would like to clip off the top few pixels of
each character
This is an unusual requirement, but I can see where the
required techniques could lead to some interesting effects.
There is more than one way to go about masking off a portion
of a character, although they all ultimately revolve around
the manipulation of the graphics context (GC) which is
passed to the XDrawImageString() routine. The various
techniques for clipping drawing requests are:
-
Create a Clip Mask (an X Bitmap). Each bit in the
bitmap indicates which pixels in the drawable are to be
affected by subsequent graphic drawing requests.
Once created, the bitmap is applied to the graphics context
through the routine XSetClipMask().
-
Create a Clip Rectangle. The rectangle specifies a
boundary such that any attempt to draw outside the confines of
the rectangle are ignored. Multiple rectangles can be
specified for more complex clipping.
Once specified, the rectangles are applied to the graphics
context through the routine XSetClipRectangles().
-
Create a Clip Region. This is roughly similar to the
specification of a set of clip rectangles above, except that
it is often slightly more convenient when performing clipping
operations because it is possible to perform union and
intersection operations on the region in order to restrict
graphical operations to the areas currently exposed.
Once created, the Region is applied to the graphics contexts
through the routine XSetClipRegion().
Which technique to adopt would depend on all kinds of
circumstances, to be determined by the nature of the graphical
drawing to hand. In this instance, the simplest method is
going to involve a simple rectangle which describes a bounding
box around the portions of text to be drawn.
The following routine draws a string such that the top
clip_size pixels of the text are masked off. The
graphics context is pre-created with suitable styles, and the
routine to perform this is available in the example codes
which can be downloaded below.
static void draw_clipped_string(Widget w, /* The drawable */
GC gc, /* The graphics context */
char *string, /* The string to draw */
XFontStruct *the_font, /* The font to draw in */
int x, /* X coordinate of string */
int y, /* Y coordinate of string */
int clip_size) /* Top pixels to hide */
{
XRectangle rectangle ;
int ascent ;
int descent ;
int direction ;
XCharStruct overall ;
int length = strlen(string) ;
/* Calculate the bounding box around the text to be drawn */
XTextExtents(the_font, string, length, &direction, &ascent, &descent, &overall) ;
/* Construct a rectangle with the top clip_size pixels masked off */
/* This uses the font metrics in order to calculate the clip rectangle */
rectangle.x = x ;
rectangle.y = y - overall.ascent + clip_size ;
rectangle.width = (overall.rbearing - overall.lbearing) ;
rectangle.height = (overall.ascent + overall.descent - clip_size) ;
/* Set the clip rectangle */
XSetClipRectangles(XtDisplay(w), gc, 0, 0, &rectangle, 1, Unsorted) ;
/* Now draw the string */
XDrawImageString(XtDisplay(w), XtWindow(w), gc, x, y, string, length) ;
}
We would invoke the routine something along the lines of the following:
extern GC gc ;
extern XFontStruct *the_font ;
extern Widget drawable ;
draw_clipped_string(drawable, gc, "Clipped text", the_font, 50, 50, 5) ;
The effect of the routine can be seen in the following screen shot.
The sources consist of:
- cliptext.c - the generated source code for the interface
- cliptext_stubs.c - the event handler, action code for the drawing area
- cliptext.h - a header file with the extern widget declarations
- cliptext.res - an X resource file with external font/color specifications
- Makefile - a general purpose Makefile for the application. Its configured for Solaris, but at the top of the file are rules for various platforms: simply comment out the Solaris section, and uncomment your platform as required.
- cliptext.xd - the X-Designer design save file. Feel free to ignore this.
Alternatively download a tar archive, cliptext.tar, of all the above source files. If you are using Netscape
Navigator you may have to hold down the Shift key when you click on the file name in order to ensure that you
are prompted to save the file.
As an example of where this could be used for interesting effects, consider the following
two-tone output from another example program:
For this to work, we only need to modify the drawing routine
very slightly. We draw the string twice in different colors,
each time masking off either the top or bottom half of the
image string.
static void draw_twotone_string(Widget w, /* The drawable */
GC gc, /* The graphics context */
char *string, /* The string to draw */
XFontStruct *font, /* The font to draw in */
Pixel top, /* The top font color */
Pixel bottom, /* The bottom font color */
int x, /* X coordinate of string */
int y) /* Y coordinate of string */
{
XRectangle rectangle ;
int ascent ;
int descent ;
int direction ;
XCharStruct overall ;
XGCValues values ;
int length = strlen(string) ;
/* Calculate the bounding box around the text to be drawn */
XTextExtents(font, string, length, &direction, &ascent, &descent, &overall) ;
/* Construct a rectangle to draw the top half of the string */
rectangle.x = x ;
rectangle.y = y - overall.ascent ;
rectangle.width = (overall.rbearing - overall.lbearing) ;
rectangle.height = (overall.ascent + overall.descent) / 2 ;
XSetClipRectangles(XtDisplay(w), gc, 0, 0, &rectangle, 1, Unsorted) ;
values.foreground = top ;
XChangeGC(XtDisplay(w), gc, GCForeground, &values) ;
XDrawImageString(XtDisplay(w), XtWindow(w), gc, x, y, string, length) ;
/* Construct a rectangle to draw the bottom half of the string */
rectangle.y = y - overall.ascent + ((overall.ascent + overall.descent) / 2) ;
rectangle.height = (overall.ascent + overall.descent) / 2 ;
XSetClipRectangles(XtDisplay(w), gc, 0, 0, &rectangle, 1, Unsorted) ;
values.foreground = bottom ;
XChangeGC(XtDisplay(w), gc, GCForeground, &values) ;
XDrawImageString(XtDisplay(w), XtWindow(w), gc, x, y, string, length) ;
}
We would invoke this routine something along the following lines:
extern GC gc ;
extern XFontStruct *the_font ;
extern Widget drawable ;
extern Pixel top_color ;
extern Pixel bottom_color ;
draw_twotone_string(w, gc, "Two-tone Text", the_font, top_color, bottom_color, 50, 50);
The sources consist of:
- halffont.c - the generated source code for the interface
- halffont_stubs.c - the drawing code
- halffont.h - a header file with the extern widget declarations
- halffont.res - an X resource file with external font/color specifications
- Makefile - a
general purpose Makefile for the application. It is configured
for Solaris, but at the top of the file are rules for various
platforms: simply comment out the Solaris section, and
uncomment your platform as required.
- halffont.xd - the X-Designer design save file. Feel free to ignore this.
Alternatively download a tar archive, halffont.tar, of all the above source files. If you are using Netscape
Navigator you may have to hold down the Shift key when you click on the file name in order to ensure that you
are prompted to save the file.
The above code assumes that a constant font has been applied into the graphics context, although the
routines do pass the XFontStruct through so that metrics can be calculated. A more general solution
would check whether the font has changed, and thereafter modify the graphics context accordingly. This
would guarantee that the metrics and the graphics context are in step.
There are several places where optimizations can be effective. In particular, the routine XChangeGC()
is relatively expensive, involving as it does a round trip to the X server. There may be some money in
caching multiple application contexts in each of the relevant color/fonts required, rather than dynamically
modifying the single graphics contexts every time the string is drawn in a distinct color or font. This
is left as an exercise for the reader.
The routines described above are all listed in the Xlib Reference library. The following is
considered to be the amongst the very best material on the subject:
Xlib Reference Manual,
Volume 2,
O'Reilly and Associates,
ISBN 1-56592-006-6
Buy it from Amazon.com or Amazon.co.uk
Xlib Programming Manual,
Volume 1,
O'Reilly and Associates,
ISBN 1-56592-002-3
Buy it from Amazon.com or Amazon.co.uk
The definitive single volume tome on Xlib programming is:
X Window System,
The Complete Reference to Xlib, X Protocol, ICCCM, XLFD,
Robert W. Scheifler and James Gettys,
ISBN 1-55558-088-2
Buy it from Amazon.com or Amazon.co.uk
Sponsored
by X-Designer - The Leading X/Motif GUI Builder
- Click to download a FREE evaluation
Goto top of page
|