[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
patch for text scaling and rotation
From: |
S. V. Ramanan |
Subject: |
patch for text scaling and rotation |
Date: |
Mon, 25 Mar 2002 13:36:42 -0500 |
User-agent: |
Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:0.9.2) Gecko/20010726 Netscape6/6.1 |
Hi,
I have modified (slightly) Alan Richardson's xvertext package
(available at http://www.x.org/pub/contrib/libraries/xvertext.5.0.shar.Z,
as stated in the X FAQ) for text scaling and rotation. While they work
for me, I have not done extensive testing, and no testing at all
in drawing with alpha.
Attached are files "rotated.h" and " rotated.c"
ramanan
__________________________________________________________________
1. Put the files "rotated.c" and "rotated.h" in
core/xgps/Source/SharedX/
2. In the file
core/xgps/Source/GNUmakefile
add "SharedX/rotated.c" to "libgnustep-xgps_C_FILES"
3. In the file
core/xgps/Source/XGFont.m
add the following method:
- (void) draw: (const char*) s lenght: (int) len
onDisplay: (Display*) xdpy drawable: (Drawable) draw
with: (GC) xgcntxt at: (XPoint) xp
rotate: (float) angle scale: (NSSize) scale
{
// This font must already be active!
XRotDrawString(xdpy, font_info,draw,xgcntxt,
xp.x, xp.y, angle, scale.width, scale.height,
s);
}
and the include line
#include "SharedX/rotated.h"
4. In the file
core/xgps/Headers/gnustep/xgps/XGContextPrivate.h
add the following method definition to the GSFontInfo (XBackend)
interface methods
- (void) draw: (const char*) s lenght: (int) len
onDisplay: (Display*) xdpy drawable: (Drawable) draw
with: (GC) xgcntxt at: (XPoint) xp
rotate: (float) angle scale: (NSSize) scale;
5. In the file
core/xgps/Source/XGGState.m
in the method (void)DPSshow:(const char *)s, add the folowing variable
float angle;
and the line
angle = [ctm rotationAngle]
and change the calls to the method draw:::::: to draw:::::::: thusly:
[font_info draw: s lenght: len
onDisplay: XDPY drawable: draw
with: xgcntxt at: xp rotate:angle scale:scale];
Do likewise for the draw::::::: method calls in the
method _showString::::::: in the same file (XGGState.m)
/* ********************************************************************** */
/* xvertext 5.0, Copyright (c) 1993 Alan Richardson (mppa3@uk.ac.sussex.syma)
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both the
* copyright notice and this permission notice appear in supporting
* documentation. All work developed as a consequence of the use of
* this program should duly acknowledge such use. No representations are
* made about the suitability of this software for any purpose. It is
* provided "as is" without express or implied warranty.
*/
/* Modified 25 Mar 02 by S. V. Ramanan for GNUStep
* 1. independent x and y scaling added
* 2. image cache-ing removed
* 3. user-stippling, background and alignment removed
*/
/* ********************************************************************** */
/* BETTER: xvertext now does rotation at any angle!!
*
* BEWARE: function arguments have CHANGED since version 2.0!!
*/
/* ********************************************************************** */
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "rotated.h"
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
/* ---------------------------------------------------------------------- */
/* A structure holding everything needed for a rotated string */
typedef struct rotated_text_item_template {
Pixmap bitmap;
int cols_in;
int rows_in;
int cols_out;
int rows_out;
} RotatedTextItem;
/* ---------------------------------------------------------------------- */
/* A structure holding current magnification and bounding box padding */
static struct style_template {
float magx;
float magy;
} style={
1.,
1.
};
/* ---------------------------------------------------------------------- */
static XImage *MakeXImage(Display *dpy, int w, int h);
int XRotDrawString( Display *dpy, XFontStruct *font, Drawable drawable, GC gc,
int x, int y, float angle, float scalex, float scaley, const char
*text);
static RotatedTextItem *XRotCreateTextItem(Display *dpy, XFontStruct *font,
float angle, const char *text);
static void XRotFreeTextItem(Display *dpy, RotatedTextItem *item);
static XImage *XRotMagnifyImage(Display *dpy, XImage *ximage);
/* ---------------------------------------------------------------------- */
/**************************************************************************/
/* Create an XImage structure and allocate memory for it
*/
/**************************************************************************/
static XImage *MakeXImage(Display *dpy, int w, int h)
{
XImage *I;
char *data;
/* reserve memory for image */
data=(char *)calloc((unsigned)(((w-1)/8+1)*h), 1);
if (data==NULL) return NULL;
/* create the XImage */
I=XCreateImage(dpy, DefaultVisual(dpy, DefaultScreen(dpy)), 1, XYBitmap,
0, data, w, h, 8, 0);
if (I==NULL) {
free(data);
return NULL;
}
I->byte_order=I->bitmap_bit_order=MSBFirst;
return I;
}
/**************************************************************************/
/* paints a rotated string
*/
/**************************************************************************/
int XRotDrawString( Display *dpy, XFontStruct *font,
Drawable drawable, GC gc, int x, int y,
float angle, float scalex, float scaley, const char *text)
{
GC my_gc;
int xp, yp;
float hot_x, hot_y;
float hot_xp, hot_yp;
float sin_angle, cos_angle;
RotatedTextItem *item;
/* return early for NULL/empty strings */
if (text==NULL || strlen(text)==0) return 0;
/* manipulate angle to 0<=angle<360 degrees */
while(angle<0) angle+=360;
while(angle>=360) angle-=360;
angle*=M_PI/180;
style.magx = style.magy = 1.;
if (scalex > 0) style.magx = scalex;
if (scaley > 0) style.magy = scaley;
/* horizontal text made easy */
if (angle==0. && style.magx==1. && style.magy == 1.) {
XDrawString(dpy, drawable, gc, x, y, text, strlen(text));
return 0;
}
/* get a rotated bitmap */
item=XRotCreateTextItem(dpy, font, angle, text);
if (item==NULL) return 1;
/* this gc has similar properties to the user's gc */
my_gc=XCreateGC(dpy, drawable, 0, 0);
XCopyGC(dpy, gc, GCForeground|GCBackground|GCFunction|GCPlaneMask,
my_gc);
/* which point (hot_x, hot_y) relative to bitmap centre
coincides with user's specified point? */
hot_y=-((float)(item->rows_in/2.)-(float)font->descent)*style.magy;
hot_x=-(float)(item->cols_in/2.)*style.magx;
/* pre-calculate sin and cos */
sin_angle=sin(angle);
cos_angle=cos(angle);
/* rotate hot_x and hot_y around bitmap centre */
hot_xp= hot_x*cos_angle - hot_y*sin_angle;
hot_yp= hot_x*sin_angle + hot_y*cos_angle;
/* where should top left corner of bitmap go ? */
xp=(float)x-((float)item->cols_out/2. +hot_xp);
yp=(float)y-((float)item->rows_out/2. -hot_yp);
/* paint text using stipple technique */
XSetFillStyle(dpy, my_gc, FillStippled);
XSetStipple(dpy, my_gc, item->bitmap);
XSetTSOrigin(dpy, my_gc, xp, yp);
XFillRectangle(dpy, drawable, my_gc, xp, yp,
item->cols_out, item->rows_out);
/* free our resources */
XFreeGC(dpy, my_gc);
/* destroy item completely */
XRotFreeTextItem(dpy,item);
/* we got to the end OK! */
return 0;
}
/**************************************************************************/
/* Create a rotated text item
*/
/**************************************************************************/
static RotatedTextItem *XRotCreateTextItem(Display *dpy, XFontStruct *font,
float angle, const char *text)
{
RotatedTextItem *item=NULL;
Pixmap canvas;
GC font_gc;
XImage *I_in, *ximage;
register int i, j;
int height;
int byte_w_in, byte_w_out;
int xp, yp;
float sin_angle, cos_angle, tan_angle;
int it, jt;
float di, dj;
float xl, xr, xinc;
int byte_out;
int dir, asc, desc;
XCharStruct overall;
int old_cols_in=0, old_rows_in=0;
/* allocate memory */
item=(RotatedTextItem *)malloc((unsigned)sizeof(RotatedTextItem));
if (!item) return NULL;
item->bitmap = (Pixmap)NULL;
XTextExtents(font, text, strlen(text), &dir, &asc, &desc,
&overall);
/* overall font height */
/* dimensions horizontal text will have */
item->cols_in=overall.rbearing;
item->rows_in=height=font->ascent+font->descent;
/* bitmap for drawing on */
canvas=XCreatePixmap(dpy, DefaultRootWindow(dpy),
item->cols_in, item->rows_in, 1);
/* create a GC for the bitmap */
font_gc=XCreateGC(dpy, canvas, 0, 0);
XSetBackground(dpy, font_gc, 0);
XSetFont(dpy, font_gc, font->fid);
/* make sure the bitmap is blank */
XSetForeground(dpy, font_gc, 0);
XFillRectangle(dpy, canvas, font_gc, 0, 0,
item->cols_in+1, item->rows_in+1);
XSetForeground(dpy, font_gc, 1);
/* pre-calculate sin and cos */
sin_angle=sin(angle);
cos_angle=cos(angle);
/* draw text horizontally */
/* where to draw section */
yp=font->ascent;
xp=0;
/* draw string onto bitmap */
XDrawString(dpy, canvas, font_gc, xp, yp, text, strlen(text));
/* create image to hold horizontal text */
I_in=MakeXImage(dpy, item->cols_in, item->rows_in);
if (I_in==NULL) {
XFreeGC(dpy, font_gc);
XFreePixmap(dpy, canvas);
return NULL;
}
/* extract horizontal text */
XGetSubImage(dpy, canvas, 0, 0, item->cols_in, item->rows_in,
1, XYPixmap, I_in, 0, 0);
I_in->format=XYBitmap;
/* magnify horizontal text */
if (style.magx != 1. || style.magy != 1.) {
I_in=XRotMagnifyImage(dpy, I_in);
old_cols_in=item->cols_in;
old_rows_in=item->rows_in;
item->cols_in=(float)item->cols_in*style.magx;
item->rows_in=(float)item->rows_in*style.magy;
}
item->cols_out=overall.rbearing;
item->rows_out=height=font->ascent+font->descent;
/* how big will rotated text be ? */
item->cols_out=fabs((float)item->rows_in*sin_angle) +
fabs((float)item->cols_in*cos_angle) +0.99999+2;
item->rows_out=fabs((float)item->rows_in*cos_angle) +
fabs((float)item->cols_in*sin_angle) +0.99999+2;
if (item->cols_out%2==0) item->cols_out++;
if (item->rows_out%2==0) item->rows_out++;
/* create image to hold rotated text */
ximage=MakeXImage(dpy, item->cols_out, item->rows_out);
if (ximage==NULL) {
XDestroyImage(I_in);
XFreeGC(dpy, font_gc);
XFreePixmap(dpy, canvas);
return NULL;
}
byte_w_in=(item->cols_in-1)/8+1;
byte_w_out=(item->cols_out-1)/8+1;
/* we try to make this bit as fast as possible - which is why it looks
a bit over-the-top */
/* vertical distance from centre */
dj=0.5-(float)item->rows_out/2;
/* where abouts does text actually lie in rotated image? */
if (angle==0 || angle==M_PI/2 ||
angle==M_PI || angle==3*M_PI/2) {
xl=0;
xr=(float)item->cols_out;
xinc=0;
} else if (angle<M_PI) {
tan_angle = sin_angle/cos_angle;
xl=(float)item->cols_out/2+
(dj-(float)item->rows_in/(2*cos_angle))/
tan_angle-2;
xr=(float)item->cols_out/2+
(dj+(float)item->rows_in/(2*cos_angle))/
tan_angle+2;
xinc=1./tan_angle;
} else {
tan_angle = sin_angle/cos_angle;
xl=(float)item->cols_out/2+
(dj+(float)item->rows_in/(2*cos_angle))/
tan_angle-2;
xr=(float)item->cols_out/2+
(dj-(float)item->rows_in/(2*cos_angle))/
tan_angle+2;
xinc=1./tan_angle;
}
/* loop through all relevent bits in rotated image */
for(j=0; j<item->rows_out; j++) {
/* no point re-calculating these every pass */
di=(float)((xl<0)?0:(int)xl)+0.5-(float)item->cols_out/2;
byte_out=(item->rows_out-j-1)*byte_w_out;
/* loop through meaningful columns */
for(i=((xl<0)?0:(int)xl);
i<((xr>=item->cols_out)?item->cols_out:(int)xr); i++) {
/* rotate coordinates */
it=(float)item->cols_in/2 + ( di*cos_angle +
dj*sin_angle);
jt=(float)item->rows_in/2 - (-di*sin_angle +
dj*cos_angle);
/* set pixel if required */
if (it>=0 && it<item->cols_in && jt>=0 &&
jt<item->rows_in)
if ((I_in->data[jt*byte_w_in+it/8] &
128>>(it%8))>0)
ximage->data[byte_out+i/8]|=128>>i%8;
di+=1;
}
dj+=1;
xl+=xinc;
xr+=xinc;
}
XDestroyImage(I_in);
if ((style.magx != 1.) || style.magy != 1.) {
item->cols_in=old_cols_in;
item->rows_in=old_rows_in;
}
/* create a bitmap to hold rotated text */
item->bitmap=XCreatePixmap(dpy, DefaultRootWindow(dpy),
item->cols_out, item->rows_out, 1);
/* make the text bitmap from XImage */
XPutImage(dpy, item->bitmap, font_gc, ximage, 0, 0, 0, 0,
item->cols_out, item->rows_out);
XDestroyImage(ximage);
XFreeGC(dpy, font_gc);
XFreePixmap(dpy, canvas);
return item;
}
/* ---------------------------------------------------------------------- */
/**************************************************************************/
/* Free the resources used by a text item
*/
/**************************************************************************/
static void XRotFreeTextItem(Display *dpy, RotatedTextItem *item)
{
if (item->bitmap) XFreePixmap(dpy, item->bitmap);
free((char *)item);
}
/* ---------------------------------------------------------------------- */
/**************************************************************************/
/* Magnify an XImage using bilinear interpolation
*/
/**************************************************************************/
static XImage *XRotMagnifyImage(Display *dpy, XImage *ximage)
{
int i, j;
float x, y;
float u,t;
XImage *I_out;
int cols_in, rows_in;
int cols_out, rows_out;
register int i2, j2;
float z1, z2, z3, z4;
int byte_width_in, byte_width_out;
float magx_inv, magy_inv;
/* size of input image */
cols_in=ximage->width;
rows_in=ximage->height;
/* size of final image */
cols_out=(float)cols_in*style.magx;
rows_out=(float)rows_in*style.magy;
/* this will hold final image */
I_out=MakeXImage(dpy, cols_out, rows_out);
if (I_out==NULL) return NULL;
/* width in bytes of input, output images */
byte_width_in=(cols_in-1)/8+1;
byte_width_out=(cols_out-1)/8+1;
/* for speed */
magx_inv=1./style.magx;
magy_inv = 1./style.magy;
y=0.;
/* loop over magnified image */
for(j2=0; j2<rows_out; j2++) {
x=0;
j=y;
for(i2=0; i2<cols_out; i2++) {
i=x;
/* bilinear interpolation - where are we on bitmap ? */
/* right edge */
if (i==cols_in-1 && j!=rows_in-1) {
t=0;
u=y-(float)j;
z1=(ximage->data[j*byte_width_in+i/8] &
128>>(i%8))>0;
z2=z1;
z3=(ximage->data[(j+1)*byte_width_in+i/8] &
128>>(i%8))>0;
z4=z3;
}
/* top edge */
else if (i!=cols_in-1 && j==rows_in-1) {
t=x-(float)i;
u=0;
z1=(ximage->data[j*byte_width_in+i/8] &
128>>(i%8))>0;
z2=(ximage->data[j*byte_width_in+(i+1)/8] &
128>>((i+1)%8))>0;
z3=z2;
z4=z1;
}
/* top right corner */
else if (i==cols_in-1 && j==rows_in-1) {
u=0;
t=0;
z1=(ximage->data[j*byte_width_in+i/8] &
128>>(i%8))>0;
z2=z1;
z3=z1;
z4=z1;
}
/* somewhere `safe' */
else {
t=x-(float)i;
u=y-(float)j;
z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0;
z2=(ximage->data[j*byte_width_in+(i+1)/8] &
128>>((i+1)%8))>0;
z3=(ximage->data[(j+1)*byte_width_in+(i+1)/8] &
128>>((i+1)%8))>0;
z4=(ximage->data[(j+1)*byte_width_in+i/8] &
128>>(i%8))>0;
}
/* if interpolated value is greater than 0.5, set bit */
if (((1-t)*(1-u)*z1 + t*(1-u)*z2 + t*u*z3 +
(1-t)*u*z4)>0.5)
I_out->data[j2*byte_width_out+i2/8]|=128>>i2%8;
x+=magx_inv;
}
y+=magy_inv;
}
/* destroy original */
XDestroyImage(ximage);
/* return big image */
return I_out;
}
#undef M_PI
/* ************************************************************************ */
/* Header file for the `xvertext 5.0' routines.
Copyright (c) 1993 Alan Richardson (mppa3@uk.ac.sussex.syma) */
/* ************************************************************************ */
#ifndef _XVERTEXT_INCLUDED_
#define _XVERTEXT_INCLUDED_
/* ---------------------------------------------------------------------- */
int XRotDrawString(Display*, XFontStruct*, Drawable, GC,
int, int,
float, float, float,
const char*);
/* ---------------------------------------------------------------------- */
#endif /* _XVERTEXT_INCLUDED_ */
- patch for text scaling and rotation,
S. V. Ramanan <=