[alt.sources] [xpert] Re: How to Get 90 degree Rotated Fonts?

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]