mleisher@nmsu.edu (Mark Leisher) (10/08/90)
Archive-name: xrot/07-Oct-90 Original-posting-by: mleisher@nmsu.edu (Mark Leisher) Original-subject: Re: How to Get 90 degree Rotated Fonts? (code) Reposted-by: emv@math.lsa.umich.edu (Edward Vielmetti) [Reposted from comp.windows.x. Comments on this service to emv@math.lsa.umich.edu (Edward Vielmetti).] Below is some code I pulled off of this very group(some time ago). I think I played with it a little, but never seriously. ------------ Cut Here ---------------------- #!/bin/sh # This is a shell archive (produced by shar 3.49) # To extract the files from this archive, save it to a file, remove # everything above the "!/bin/sh" line above, and type "sh file_name". # # made 10/07/1990 18:43 UTC by mleisher@aigyptos # Source directory /tmp_mnt/home/thrinakia1/mleisher/x_stuff # # existing files will NOT be overwritten unless -c is specified # # This shar contains: # length mode name # ------ ---------- ------------------------------------------ # 8067 -rw-rw-r-- rotate-text90.c # # ============= rotate-text90.c ============== if test -f 'rotate-text90.c' -a X"$1" != X"-c"; then echo 'x - skipping rotate-text90.c (File already exists)' else echo 'x - extracting rotate-text90.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'rotate-text90.c' && /* Notes : X * Text90() draws a text string rotated by 90 degrees on the given X * drawable and given gc. The gc is not modified. Text90() respects X * the Foreground, ClipMask, and ClipOrigin components of the X * gc. You must pass the Fontstruct separately because Text90() X * needs to determine text extents from the gc alone. X * X * The general scheme is as follows. First make a 1 bit deep pixmap X * and render the text using the usual XDrawString() function. X * Then use XGetImage() to pull that back to the client, XCreateImage() X * another XImage and put the rotated points from the gotten image X * into it. XPutImage() the rotated image back to another 1 bit X * deep pixmap on the server. Now, if there were not a ClipMask X * set in the gc, we could use this pixmap with the rotated image X * ('rot_pm') as a ClipMask in gc and use FillRectangle on the X * given drawable. But this would ignore and destroy the ClipMask X * in the given gc. So we make another pixmap ('deep_pm'), as deep X * as the given drawable, XCopyArea() the relevant stuff in the X * drawable into deep_pm, then using 'rot_pm' as a ClipMask X * call XFillRectangle to bleed the rotated text onto 'deep_pm', X * then XCopyArea 'deep_pm' back onto the given drawable, using X * the given 'gc' so its ClipMask is respected. Whew. X * X * The XImage structure needs a Visual when you create it with X * XCreateImage. I am making an XImage which should be identical X * except in shape to the that I got from XGetImage but the gotten X * one contains no information about the Visual. I punt and use X * the default Visual of the default Screen -- I am only making X * a 1 bit deep pixmap so what difference can it make?. X * X * I need to pass a drawable_depth to Text90 because there is no X * way to ask a drawable how deep it is. X * X * If we knew that there were no ClipMask in the given gc we could X * skip the 2 CopyArea()s, but there is no way to determine this X * without passing yet another argument to Text90 (an argument whose X * value is probably not known by the caller). X * X * Text90 allocates and frees quite a few X objects. If your server X * has memory leaks you will find out about them using this. Perhaps X * one could cache these things as statics to Text90. X * X * I have included a test main() program. To use it : X * cc -o xrot xrot.c -lX11 -lm X * xrot xpos ypos X * where xpos and ypos give the position of the string. X * X * If any one has a better way of doing this, please tell me about it. X * X * Bill Dunlap X * Dept. of Statistics, GN-22 X * University of Washington X * Seattle, WA 98195 X * bill@stat.washington.edu X */ #include <stdio.h> #include <X11/Xlib.h> #include <X11/Xutil.h> X void Text90() ; static void BailOut() ; static Display *dpy ; static Window win ; static XFontStruct *fontstruct ; static GC win_gc ; static XGCValues xgcv ; extern char *malloc() ; X /* ARGSUSED */ main(argc, argv) int argc ; char **argv ; { X unsigned long fg, bg ; X int x, y ; X if (!(--argc>0 && sscanf(*++argv, "%d", &x)==1)) X x = 20 ; X if (!(--argc>0 && sscanf(*++argv, "%d", &y)==1)) X y = 20 ; X dpy = XOpenDisplay((char *)NULL) ; X if (!dpy) BailOut("XOpenDisplay") ; X fg = BlackPixel(dpy, DefaultScreen(dpy)) ; X bg = WhitePixel(dpy, DefaultScreen(dpy)) ; #define WIN_WIDTH 500 #define WIN_HEIGHT 100 X win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), X 200, 200, /* position */ X WIN_WIDTH, WIN_HEIGHT, /* size */ X 2, /* border width */ X fg, /* border color */ X bg) ; /* background color */ X if (!win) BailOut("XCreateSimpleWindow") ; #define STRING "This is a test" X fontstruct = XLoadQueryFont(dpy, "fixed") ; X if (!fontstruct) BailOut("XLoadQueryFont") ; X xgcv.foreground = fg ; X xgcv.background = bg ; X xgcv.line_width = 4 ; X win_gc = XCreateGC(dpy, win, X GCForeground|GCBackground|GCLineWidth, X &xgcv) ; X if (!win_gc) BailOut("XCreateGC(win_gc)") ; X XSelectInput(dpy, win, ExposureMask) ; X XMapWindow(dpy, win) ; X while (1) { X XRectangle rect ; X XEvent event ; X XWindowAttributes xwa ; X XNextEvent(dpy, &event) ; X if (!(event.type == Expose && ((XExposeEvent *)&event)->count == 0)) X continue ; X if (!XGetWindowAttributes(dpy, win, &xwa)) X break ; X XClearWindow(dpy, win) ; #define MARGIN 5 X rect.x = MARGIN ; rect.y = MARGIN ; X rect.width = xwa.width - 2 * MARGIN ; X rect.height = xwa.height - 2 * MARGIN ; X XSetClipRectangles(dpy, win_gc, 0, 0, &rect, 1, Unsorted) ; X XDrawLine(dpy, win, win_gc, 0, 0, xwa.width, xwa.height) ; X XDrawLine(dpy, win, win_gc, xwa.width, 0, 0, xwa.height) ; X Text90(dpy, win, xwa.depth, win_gc, x, y, STRING, strlen(STRING), fontstruct) ; X } X exit(0) ; } X static void BailOut(msg) char *msg ; { X fprintf(stderr, "Error in %s -- bailing out\n", msg) ; X exit(1) ; } X void Text90(dpy, drawable, drawable_depth, gc, x, y, string, length, fontstruct) Display *dpy ; Drawable drawable ; int drawable_depth ; GC gc ; int x, y ; char *string ; int length ; XXFontStruct *fontstruct ; { X Pixmap pm, rot_pm, deep_pm ; X GC pm_gc, deep_gc ; X XImage *image, *rot_image ; X int row, col ; X char *d ; X int rot_bytes_per_line ; X XCharStruct xcs ; X int width, height ; X int direction, font_ascent, font_descent ; X XTextExtents(fontstruct, string, length, X &direction, &font_ascent, &font_descent, X &xcs) ; X width = xcs.width ; X height = font_ascent + font_descent ; X pm = XCreatePixmap(dpy, win, width, height, 1) ; X if (!pm) BailOut("XCreatePixmap") ; X rot_pm = XCreatePixmap(dpy, drawable, height, width, 1) ; X if (!rot_pm) BailOut("XCreatePixmap") ; X xgcv.foreground = 1 ; /* yes, 1, this will be a mask */ X xgcv.background = 0 ; X xgcv.font = fontstruct->fid ; X pm_gc = XCreateGC(dpy, pm, X GCForeground|GCBackground|GCFont, X &xgcv) ; X if (!pm_gc) BailOut("XCreateGC(pm_gc)") ; X XDrawString(dpy, pm, pm_gc, 0, font_ascent, string, length) ; X image = XGetImage(dpy, pm, 0, 0, width, height, AllPlanes, XYPixmap) ; X if (!image) BailOut("XGetImage") ; #define roundup(n, mod) ( (n)%(mod) ? (1+(n)/(mod))*mod : n ) X rot_bytes_per_line = roundup(image->height, image->bitmap_pad)/(image->bitmap_pad/8) ; X d = (char *)malloc(rot_bytes_per_line * image->width) ; X if (!d) BailOut("malloc") ; X rot_image = XCreateImage(dpy, X DefaultVisual(dpy, 0), /* I want the same as is in image */ X image->depth, X image->format, X image->xoffset, X d, X image->height, image->width, /* yes, reverse these */ X image->bitmap_pad, X rot_bytes_per_line) ; X if (!rot_image) BailOut("XCreateImage") ; X /* rotate image 90 degrees clockwise */ X for(row=0 ; row<image->height ; row++) { X for(col=0 ; col<image->width ; col++) { X (void)XPutPixel(rot_image, row, rot_image->height-1-col, X XGetPixel(image, col, row)) ; X } X } X XPutImage(dpy, rot_pm, pm_gc, rot_image, X 0, 0, /* source origin */ X 0, 0, /* dest origin */ X rot_image->width, rot_image->height) ; X /* Now the pixmap rot_pm contains a mask of the rotated text */ X X deep_pm = XCreatePixmap(dpy, drawable, X rot_image->width, rot_image->height, drawable_depth) ; X if (!deep_pm) BailOut("XCreatePixmap(deep_pm)") ; X deep_gc = XCreateGC(dpy, deep_pm, 0L, &xgcv) ; X if (!deep_gc) BailOut("XCreateGC(deep_gc)") ; X XCopyArea(dpy, drawable, deep_pm, deep_gc, X x, y, /* source origin */ X rot_image->width, rot_image->height, /* size */ X 0, 0) ; /* destination origin */ X XCopyGC(dpy, gc, GCForeground, deep_gc) ; X XSetClipMask(dpy, deep_gc, rot_pm) ; X XFillRectangle(dpy, deep_pm, deep_gc, 0, 0, X rot_image->width, rot_image->height) ; X XCopyArea(dpy, deep_pm, drawable, gc, X 0, 0, /* source origin */ X rot_image->width, rot_image->height, /* size */ X x, y) ; /* destination origin */ X X /* I set these things to NULL after freeing to prepare for X * caching them */ X free(d) ; d = (char *)NULL ; X XFreeGC(dpy, pm_gc) ; pm_gc = (GC)NULL ; X XFreeGC(dpy, deep_gc) ; deep_gc = (GC)NULL ; X XFreePixmap(dpy, pm) ; pm = (Pixmap)NULL ; X XFreePixmap(dpy, deep_pm) ; deep_pm = (Pixmap)NULL ; X XFreePixmap(dpy, rot_pm) ; rot_pm = (Pixmap)NULL ; X XDestroyImage(image) ; image = (XImage *)NULL ; X XDestroyImage(rot_image) ; rot_image = (XImage *)NULL ; X /* did I free everything? */ X return ; } SHAR_EOF chmod 0664 rotate-text90.c || echo 'restore of rotate-text90.c failed' Wc_c="`wc -c < 'rotate-text90.c'`" test 8067 -eq "$Wc_c" || echo 'rotate-text90.c: original size 8067, current size' "$Wc_c" fi exit 0 -- ----------------------------------------------------------------------------- mleisher@nmsu.edu "I laughed. Mark Leisher I cried. Computing Research Lab I fell down. New Mexico State University It changed my life." Las Cruces, NM - Rich [Cowboy Feng's Space Bar and Grille]