bug-gnustep
[Top][All Lists]
Advanced

[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_ */




reply via email to

[Prev in Thread] Current Thread [Next in Thread]