www.pudn.com > ilib > IDrawStr.c


/*
 * IDrawStr.c
 *
 * Image library
 *
 * Description:
 *	Portable routines to manipulate raster images.
 *
 * History:
 *	21-Jan-00	Geovan Rodriguez 
 *			Added IDrawStringRotatedAngle()
 *	23-Aug-99	Craig Knudsen	cknudsen@radix.net
 *			Added support for text styles:
 *			ITEXT_NORMAL, ITEXT_ETCHED_IN, 
 *			ITEXT_ETCHED_OUT, ITEXT_SHADOWED
 *	21-Aug-99	Craig Knudsen	cknudsen@radix.net
 *			Added IDrawStringRotated()
 *			Removed anti-aliasing stuff since it didn't really
 *			work.  Eventually, true type fonts will be used
 *			for this (FreeType lib).
 *	18-May-98	Craig Knudsen	cknudsen@radix.net
 *			Added support for anti-aliasing fonts by using a
 *			font 2X bigger than we need.
 *	20-May-96	Craig Knudsen	cknudsen@radix.net
 *			Created
 *
 ****************************************************************************/

#include 
#include 
#include 
#include 
#include 

#include "Ilib.h"
#include "IlibP.h"
#include "IFontBDF.h"


#define SPACES_PER_TAB		8



static IError draw_string_rotated_90 (
#ifndef _NO_PROTO
  IImage image,
  IGC gc,
  int x,
  int y,
  char *text,
  unsigned int len,
  ITextDirection direction
#endif
);



IError IDrawString ( image, gc, x, y, text, len )
IImage image;
IGC gc;
int x;
int y;
char *text;
unsigned int len;
{
  return IDrawStringRotated ( image, gc, x, y, text, len, ITEXT_LEFT_TO_RIGHT );
}



/* calculate values for topshadow and bottomshadow */
static void make_top_and_bottom_shadow ( incolorp, top, bottom )
IColorP *incolorp;
IColor *top, *bottom;
{
  unsigned int topr, topg, topb, bottomr, bottomg, bottomb;

  if ( incolorp == NULL ) {
    *top = 0;
    *bottom = 1;
  } else {
    topr = incolorp->red > 205 ? 255 : incolorp->red + 50;
    topg = incolorp->green > 205 ? 255 : incolorp->green + 50;
    topb = incolorp->blue > 205 ? 255 : incolorp->blue + 50;
    *top = IAllocColor ( topr, topg, topb );
    bottomr = incolorp->red < 50 ? 0 : incolorp->red - 50;
    bottomg = incolorp->green < 50 ? 0 : incolorp->green - 50;
    bottomb = incolorp->blue < 50 ? 0 : incolorp->blue - 50;
    *bottom = IAllocColor ( bottomr, bottomg, bottomb );
  }
}


/* calculate values for shadows  */
static void make_shadows ( incolorp, shadows, nshadows )
IColorP *incolorp;
IColor *shadows;
int nshadows;
{
  unsigned int rinc, ginc, binc, rstart, gstart, bstart;
  int loop;

  rstart = ( incolorp->red / 2 );
  gstart = ( incolorp->green / 2 );
  bstart = ( incolorp->blue / 2 );

  if ( incolorp != NULL ) {
    rinc = ( incolorp->red - rstart ) / nshadows;
    ginc = ( incolorp->green - gstart ) / nshadows;
    binc = ( incolorp->blue - bstart ) / nshadows;
    for ( loop = 0; loop < nshadows; loop++ )
      shadows[loop] = IAllocColor ( rstart + rinc * loop,
        gstart + ginc * loop, bstart + binc * loop );
  }
}


IError IDrawStringRotated ( image, gc, x, y, text, len, direction )
IImage image;
IGC gc;
int x;
int y;
char *text;
unsigned int len;
ITextDirection direction;
{
  IGCP *gcp = (IGCP *)gc;
  IError ret = INoError;
  IColor shadows[20], top, bottom;
  IColorP *fgsave;
  int loop, nshadows;
  unsigned int font_height;

  if ( ! gcp )
    return ( IInvalidGC );

  fgsave = gcp->foreground;

  switch ( gcp->text_style ) {
    case ITEXT_NORMAL:
      ret = draw_string_rotated_90 ( image, gc, x, y, text, len, direction );
      break;
    case ITEXT_ETCHED_IN:
    case ITEXT_ETCHED_OUT:
      if ( gcp->background != NULL ) {
        if ( gcp->text_style == ITEXT_ETCHED_OUT )
          make_top_and_bottom_shadow ( gcp->background, &top, &bottom );
        else
          make_top_and_bottom_shadow ( gcp->background, &bottom, &top );
        ISetForeground ( gc, top );
        ret = draw_string_rotated_90 ( image, gc, x - 1, y - 1,
          text, len, direction );
        if ( ! ret ) {
          ISetForeground ( gc, bottom );
          ret = draw_string_rotated_90 ( image, gc, x + 1, y + 1,
            text, len, direction );
        }
      }
      if ( ! ret ) {
        gcp->foreground = gcp->background;
        ret = draw_string_rotated_90 ( image, gc, x, y,
          text, len, direction );
      }
      break;
    case ITEXT_SHADOWED:
      if ( gcp->background != NULL ) {
        IFontSize ( (IFont)gcp->font, &font_height );
        nshadows = font_height / 5;
        make_shadows ( gcp->background, shadows, nshadows );
        gcp->foreground = fgsave;
        for ( loop = nshadows; loop > 0; loop-- ) {
          ISetForeground ( gc, shadows[loop-1] );
          ret = draw_string_rotated_90 ( image, gc, x + loop, y + loop,
            text, len, direction );
        }
        gcp->foreground = fgsave;
      }
      if ( ! ret )
        ret = draw_string_rotated_90 ( image, gc, x, y, text, len, direction );
      break;
  }

  gcp->foreground = fgsave;

  return ( ret );
}


static IError draw_string_rotated_90 ( image, gc, x, y, text, len, direction )
IImage image;
IGC gc;
int x;
int y;
char *text;
unsigned int len;
ITextDirection direction;
{
  IGCP *gcp = (IGCP *)gc;
  IImageP *imagep = (IImageP *)image;
  unsigned int *bitdata;
  unsigned int height, width, actual_width, size, font_height;
  int xoffset, yoffset, charx, chary;
  char ch[256], *ptr;
  int loop, loop2, loop3;
  IError ret;
  int myx, myy;
  int char_num = 0;

  if ( ! gcp )
    return ( IInvalidGC );
  if ( gcp->magic != IMAGIC_GC )
    return ( IInvalidGC );

  if ( ! imagep )
    return ( IInvalidImage );
  if ( imagep->magic != IMAGIC_IMAGE )
    return ( IInvalidImage );

  if ( ! gcp->font )
    return ( INoFontSet );

  charx = x;
  chary = y;

  IFontSize ( (IFont)gcp->font, &font_height );

  for ( ptr = text, loop = 0; loop < len; loop++, ptr++ ) {
    if ( *ptr == '\012' ) {
      switch ( direction ) {
        case ITEXT_LEFT_TO_RIGHT:
          charx = x;
          chary += font_height;
          break;
        case ITEXT_TOP_TO_BOTTOM:
          chary = y;
          charx -= font_height;
          break;
        case ITEXT_BOTTOM_TO_TOP:
          chary = y;
          charx += font_height;
          break;
      }
      char_num = 0;
      continue;
    }
    else if ( *ptr == '\t' ) {
      ret = IFontBDFGetChar ( gcp->font->name, ch, &bitdata, &width, &height,
        &actual_width, &size, &xoffset, &yoffset );
      switch ( direction ) {
        case ITEXT_LEFT_TO_RIGHT:
          charx += ( 8 - ( char_num % 8 ) ) * actual_width;
          break;
        case ITEXT_TOP_TO_BOTTOM:
          chary -= ( 8 - ( char_num % 8 ) ) * actual_width;
          break;
        case ITEXT_BOTTOM_TO_TOP:
          chary += ( 8 - ( char_num % 8 ) ) * actual_width;
          break;
      }
      continue;
    }
    else if ( *ptr != '\033' ) {
      ch[0] = *ptr;
      ch[1] = '\0';
    }
    else {
      loop2 = 0;
      ptr++;
      while ( *ptr != ';' && loop < len && loop2 < 256 ) {
        ch[loop2] = *ptr;
        ptr++;
        loop++;
        loop2++;
      }
      ch[loop2] = '\0';
      if ( *ptr != ';' ) {
        return ( IInvalidEscapeSequence );
      }
    }
    ret = IFontBDFGetChar ( gcp->font->name, ch, &bitdata, &width, &height,
      &actual_width, &size, &xoffset, &yoffset );
    if ( ! ret ) {
      for ( loop3 = 0; loop3 < height; loop3++ ) {
        switch ( direction ) {
          case ITEXT_LEFT_TO_RIGHT:
            myy = chary - ( height + yoffset ) + loop3;
            for ( loop2 = 0; loop2 < width; loop2++ ) {
              if ( bitdata[loop3 * width + loop2] ) {
                myx = charx + xoffset + loop2;
                _ISetPoint ( imagep, gcp, myx, myy );
              }
            }
            break;
          case ITEXT_TOP_TO_BOTTOM:
            myx = charx + ( height + yoffset ) - loop3;
            for ( loop2 = 0; loop2 < width; loop2++ ) {
              if ( bitdata[loop3 * width + loop2] ) {
                myy = chary + xoffset + loop2;
                _ISetPoint ( imagep, gcp, myx, myy );
              }
            }
            break;
          case ITEXT_BOTTOM_TO_TOP:
            myx = charx - ( height + yoffset ) + loop3;
            for ( loop2 = 0; loop2 < width; loop2++ ) {
              if ( bitdata[loop3 * width + loop2] ) {
                myy = chary - xoffset - loop2;
                _ISetPoint ( imagep, gcp, myx, myy );
              }
            }
            break;
        }
      }
      switch ( direction ) {
        case ITEXT_LEFT_TO_RIGHT:
          charx += actual_width;
          break;
        case ITEXT_TOP_TO_BOTTOM:
          chary += actual_width;
          break;
        case ITEXT_BOTTOM_TO_TOP:
          chary -= actual_width;
          break;
      }
      char_num++;
    }
  }

  return ( INoError );
}





IError IDrawStringRotatedAngle ( image, gc, x, y, text, len, angle )
IImage image;
IGC gc;
int x;
int y;
char *text;
unsigned int len;
double angle;
{
  IGCP *gcp = (IGCP *)gc;
  IImageP *imagep = (IImageP *)image;
  unsigned int *bitdata;
  unsigned int height, width, actual_width, size, font_height;
  int xoffset, yoffset, charx, chary;
  char ch[256], *ptr;
  int loop, loop2, loop3;
  IError ret;
  int myx, myy;
  int char_num = 0;

  double x1, y1, x2, y2;
  int alpha;
    
  if ( ! gcp )
    return ( IInvalidGC );
  if ( gcp->magic != IMAGIC_GC )
    return ( IInvalidGC );

  if ( ! imagep )
    return ( IInvalidImage );
  if ( imagep->magic != IMAGIC_IMAGE )
    return ( IInvalidImage );

  if ( ! gcp->font )
    return ( INoFontSet );

  charx = x;
  chary = y;

  IFontSize ( (IFont)gcp->font, &font_height );

  for ( ptr = text, loop = 0; loop < len; loop++, ptr++ ) {
    
    if ( *ptr == '\012' ) {
      chary += font_height;
      charx = x;
      char_num = 0;
      continue;
    }
    else if ( *ptr == '\t' ) {
      ret = IFontBDFGetChar ( gcp->font->name, ch, &bitdata, &width, &height,
        &actual_width, &size, &xoffset, &yoffset );
      chary += ( 8 - ( char_num % 8 ) ) * actual_width;
      continue;
    }
    else if ( *ptr != '\033' ) {
      ch[0] = *ptr;
      ch[1] = '\0';
    }
    else {
      loop2 = 0;
      ptr++;
      while ( *ptr != ';' && loop < len && loop2 < 256 ) {
        ch[loop2] = *ptr;
        ptr++;
        loop++;
        loop2++;
      }
      ch[loop2] = '\0';
      
      if ( *ptr != ';' ) {
        return ( IInvalidEscapeSequence );
      }
    }
    
    ret = IFontBDFGetChar ( gcp->font->name, ch, &bitdata, &width, &height,
      &actual_width, &size, &xoffset, &yoffset );

    alpha=angle;
          
    if ( ! ret ) {
      for ( loop3 = 0; loop3 < height; loop3++ ) {
        for ( loop2 = 0; loop2 < width; loop2++ ) {
          if ( bitdata[loop3 * width + loop2] ) {
            x1 = loop2 + xoffset;
            y1 = loop3 + size - height;
            x2 = x1 * cos ( alpha * M_PI / 180 ) +
              y1 * sin ( alpha * M_PI / 180 );
            y2 = -1 * x1 * sin ( alpha * M_PI / 180 ) +
              y1 * cos ( alpha * M_PI / 180 );
            myy = chary - (size + yoffset ) + y2;
            myx = charx + x2;
            _ISetPoint ( imagep, gcp, myx, myy );
          }
        }  
      }
      x1 = actual_width+xoffset;      
      y1 = 0;      
      x2 = x1 * cos ( alpha * M_PI / 180 ) +
        y1 * sin ( alpha * M_PI / 180 );      
      y2 = -1 * x1 * sin ( alpha * M_PI / 180 ) +
        y1 * cos ( alpha * M_PI / 180 );      
      charx += x2;      
      chary += y2;      
      char_num++;
    }
  }

  return ( INoError );
}