[comp.windows.x] How to Get 90 degree Rotated Fonts?

khai@adi.com (S. Khai Mong) (10/05/90)

How would one get a font rotated +/-90 degrees in X so that I can draw
text running vertically?

The solution should be a run-time one.  The user specifies a given
font for an application and I wish to use that font for horz and vert
text.  I can't and don't want to define a new font.
--
Sao Khai Mong:   Applied Dynamics, 3800 Stone School Road, Ann Arbor, Mi48108
(313)973-1300    (uunet|sharkey)!amara!khai   khai@adi.com

mouse@LARRY.MCRCIM.MCGILL.EDU (10/06/90)

> How would one get a font rotated +/-90 degrees in X so that I can
> draw text running vertically?

In general, one doesn't.

> The solution should be a run-time one.  The user specifies a given
> font for an application and I wish to use that font for horz and vert
> text.  I can't and don't want to define a new font.

Then your only choice, as far as I can see, is to draw the text
horizontally into a bitmap (or pixmap), suck it over into the client
with XGetImage, rotate it "by hand", send it back, and blit it onto the
screen as graphics.  If the rotated text is highly variable, you may
want to do this for each character, though then displaying the text
will be slower - many blits instead of one.  (I used this technique in
my terminal emulator when I want double height and/or width text: grab
the character's bitmap, magnify it myself, send it back, and blit it
onto the screen.  Of course, if you do this much you should cache the
rotated bitmaps....)

There are various extensions around that can save you the trouble - for
example, any of the various PostScript support extensions present in
various (proprietary) servers would have no trouble.  But using one of
those loses compatibility with all the servers out there. that don't
support that particular extension.  (Sure as you do, you'll find you
want to make it run on an X terminal or something.)

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu

marbru@auto-trol.UUCP (Martin Brunecky) (10/07/90)

In article <KHAI.90Oct4144819@snapper.adi.com> khai@adi.com (S. Khai Mong) writes:
>How would one get a font rotated +/-90 degrees in X so that I can draw
>text running vertically?
>
>The solution should be a run-time one.  The user specifies a given
>font for an application and I wish to use that font for horz and vert
>text.  I can't and don't want to define a new font.
>--
>Sao Khai Mong:   Applied Dynamics, 3800 Stone School Road, Ann Arbor, Mi48108
>(313)973-1300    (uunet|sharkey)!amara!khai   khai@adi.com

    What about drawing all characters in your font into an off-screen bitmap,
    reading it with XGetImage, swapping rows/columns in each character,
    loading it back into (another) off-screen bitmap, and from there on
    use XCopyPlane for each character ?
   [ yeep, XPutFontBitmap would be much better, but there just ain't one,
     and the MIT guys don't like it, they want something really big and
     ugly - called "font server" ].
-- 
=*= Opinions presented here are solely of my own and not those of Auto-trol =*=
Martin Brunecky                   marbru@auto-trol.COM
(303) 252-2499                    {...}ncar!ico!auto-trol!marbru
Auto-trol Technology Corp. 12500 North Washington St., Denver, CO 80241-2404 

mleisher@nmsu.edu (Mark Leisher) (10/08/90)

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]

rws@EXPO.LCS.MIT.EDU (Bob Scheifler) (10/08/90)

   [ yeep, XPutFontBitmap would be much better, but there just ain't one,
     and the MIT guys don't like it, they want something really big and
     ugly - called "font server" ].

I used to think a font server might be sufficient for this, but no longer.
I think some form of font downloading is desirable, although I'm not sure
what the best form is.  The font server solves a different, but also
important problem, and it need be neither "big" nor "ugly".  Right now
resources within the Consortium are focused on the font server, because
the people involved feel it is a more important problem to solve.  I hope
that we will eventually find the resources to work on font downloading.

casey@gauss.llnl.gov (Casey Leedom) (10/08/90)

/ From: rws@EXPO.LCS.MIT.EDU (Bob Scheifler)
| 
| Right now resources within the Consortium are focused on the font server,
| because the people involved feel it is a more important problem to solve.  I
\ hope that we will eventually find the resources to work on font downloading.

  I sure hope so.  There are times when a particular application has need for a specific glyph set peculiar to itself and it seems unnecessarily complex to
require either that the font be loaded into a well known font server or that
the application have to become a font server itself.

  Actually, if the overhead for that second option were made small enough I
probably wouldn't object.  By "overhead" I mean application coding and
installation and administration primarily.  For instance, requiring that a
database of all potential font servers be maintained wouldn't not be nice.  A
dynamic mechanism where the application simply registers itself as a font server
would be much nicer.

  There are still of course the questions of how long application font servers
stay registered, does the display server promiscuously use application font
servers to try to satisfy font needs from other clients or would the application
font server only be used for windows associated with the application?  And
would the font service be associated with a specific instantiation of an
application or all currently running instantiations of an application?

  I don't envy you your task.

Casey

marbru@auto-trol.UUCP (Martin Brunecky) (10/08/90)

In article <9010080007.AA25121@expo.lcs.mit.edu> rws@EXPO.LCS.MIT.EDU (Bob Scheifler) writes:
>>
>>   [ yeep, XPutFontBitmap would be much better, but there just ain't one,
>>     and the MIT guys don't like it, they want something really big and
>>     ugly - called "font server" ].
>>
>I used to think a font server might be sufficient for this, but no longer.
>I think some form of font downloading is desirable, although I'm not sure
>what the best form is.  The font server solves a different, but also
>important problem, and it need be neither "big" nor "ugly".  Right now
>resources within the Consortium are focused on the font server, because
>the people involved feel it is a more important problem to solve.  I hope
>that we will eventually find the resources to work on font downloading.

   I agree that the font server may solve an important problem, but
   I am also worried that the font server will introduce about as many
   new problems as it will solve. In particular, I am worried about
   the management aspects of the beast -> where it runs, who starts it
   up, how to identify connection to it, in what filespace it lives etc.

   However, even the "font server" needs to load the fonts into the X server,
    (I don't think that a font server creating a .bdf file somewhere,
     executing vendor-specific .bdf->server-format converter, munging servers
     font search path ... is a viable solution).
   Just imagine this scenario using XTerms with font directories somewhere
   on some host machine with some limitations applicable to font loading...
   To an application writer, introducing a font of application-specific
   symbols, the font-server will not make the life any easier.

   So, even if you come with a great font server, it still needs something
   like "XDownloadFont" to truly portably interface with normal X servers.
   Without such an extension, I personally consider any "font server"
   semi-useless.
   
   Why not come with the "XDownloadFont" extension FIRST. Most likely,
   it will be more widely used than your font server, and it will be
   a common prerequisite for your font server as well.

 
-- 
=*= Opinions presented here are solely of my own and not those of Auto-trol =*=
Martin Brunecky                   marbru@auto-trol.COM
(303) 252-2499                    {...}ncar!ico!auto-trol!marbru
Auto-trol Technology Corp. 12500 North Washington St., Denver, CO 80241-2404