39221e2000-07-07Henrik Grubbström (Grubba) /* $Id: font.c,v 1.59 2000/07/07 13:56:45 grubba Exp $ */
fec6251998-03-25Fredrik Hübinette (Hubbe) #include "global.h"
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
7abac31997-09-01Per Hedbor #define SPACE_CHAR 'i'
0e756f1999-05-24Mirar (Pontus Hagland) extern unsigned char * image_default_font; #define IMAGE_DEFAULT_FONT_SIZE 30596
e3cb4b1997-04-03Mirar (Pontus Hagland) /* **! module Image
4ce7411997-05-29Mirar (Pontus Hagland) **! note
39221e2000-07-07Henrik Grubbström (Grubba) **! $Id: font.c,v 1.59 2000/07/07 13:56:45 grubba Exp $
448c201999-04-13Mirar (Pontus Hagland) **! class Font
b9284c1997-04-09Mirar (Pontus Hagland) **!
4ce7411997-05-29Mirar (Pontus Hagland) **! note **! Short technical documentation on a font file:
a827cd1997-04-19Mirar (Pontus Hagland) **! This object adds the text-drawing and -creation **! capabilities of the <ref>Image</ref> module. **! **! For simple usage, see **! <ref>write</ref> and <ref>load</ref>. **! **! other methods: <ref>baseline</ref>, **! <ref>height</ref>, **! <ref>set_xspacing_scale</ref>, **! <ref>set_yspacing_scale</ref>, **! <ref>text_extents</ref> **!
f311411997-04-18Mirar (Pontus Hagland) **! <pre>
b9284c1997-04-09Mirar (Pontus Hagland) **! struct file_head **! { **! unsigned INT32 cookie; - 0x464f4e54 **! unsigned INT32 version; - 1 **! unsigned INT32 chars; - number of chars **! unsigned INT32 height; - height of font **! unsigned INT32 baseline; - font baseline **! unsigned INT32 o[1]; - position of char_head's **! } *fh; **! struct char_head **! { **! unsigned INT32 width; - width of this character **! unsigned INT32 spacing; - spacing to next character **! unsigned char data[1]; - pixmap data (1byte/pixel) **! } *ch;
558db11998-02-24Per Hedbor **! **! version 2: **! **! **! On-disk syntax (everything in N.B.O), int is 4 bytes, a byte is 8 bits: **! **! pos **! 0 int cookie = 'FONT'; or 0x464f4e54 **! 4 int version = 2; 1 was the old version without the last four chars **! 8 int numchars; Always 256 in this version of the dump program **! 12 int height; in (whole) pixels **! 16 int baseline; in (whole) pixels **! 20 char direction; 1==right to left, 0 is left to right **! 21 char format; Font format **! 22 char colortablep; Colortable format **! 23 char kerningtablep; Kerning table format **! **! 24 int offsets[numchars]; pointers into the data, realative to &cookie. **! [colortable] **! [kerningtable] **! **! At each offset: **! **! **! 0 int width; in pixels **! 4 int spacing; in 1/1000:th of a pixels **! 8 char data[]; Enough data to plot width * font->height pixels **! Please note that if width is 0, there is no data. **! **! Font formats: **! id type **! 0 Raw 8bit data **! 1 RLE encoded data, char length, char data, 70% more compact than raw data **! 2 ZLib compressed data 60% more compact than RLE **! **! Colortable types: **! 0 No colortable (the data is an alpha channel) **! 1 24bit RGB with alpha (index->color, 256*4 bytes, rgba) **! 2 8bit Greyscale with alpha (index->color, 256*2 bytes) **! **! Kerningtable types: **! 0 No kerning table **! 1 numchars*numchars entries, each a signed char with the kerning value **! 2 numchar entries, each with a list of kerning pairs, like this: **! int len **! len * (short char, short value) **! **! </pre>
b9284c1997-04-09Mirar (Pontus Hagland) **!
448c201999-04-13Mirar (Pontus Hagland) **! see also: Image, Image.Image
e3cb4b1997-04-03Mirar (Pontus Hagland) */
15dfec1997-05-28Mirar (Pontus Hagland) /* Dump a font into a Roxen Font file (format version 2) On-disk syntax (everything in N.B.O), int is 4 bytes, a byte is 8 bits: pos 0 int cookie = 'FONT'; or 0x464f4e54 4 int version = 2; 1 was the old version without the last four chars 8 int numchars; Always 256 in this version of the dump program 12 int height; in (whole) pixels 16 int baseline; in (whole) pixels 20 char direction; 1==right to left, 0 is left to right 21 char format; Font format 22 char colortablep; Colortable format 23 char kerningtablep; Kerning table format 24 int offsets[numchars]; pointers into the data, realative to &cookie. [colortable] [kerningtable] At each offset: 0 int width; in pixels 4 int spacing; in 1/1000:th of a pixels 8 char data[]; Enough data to plot width * font->height pixels Please note that if width is 0, there is no data. Font formats: id type efficiency with lucida 128 0 Raw 8bit data not really.. :-) 1 RLE encoded data, char length, char data, 70% more compact than raw data 2 ZLib compressed RLE encoded data 60% more compact than RLE Colortable types: 0 No colortable 1 24bit RGB (index->color, 256*3 bytes) 2 24bit Greyscale (index->color, 256*3 bytes) Kerningtable types: 0 No kerning table 1 numchars*numchars entries, each a signed char with the kerning value 2 numchar entries, each with a list of kerning pairs, like this: int len len * (short char, short value) */
da46841999-09-14Mirar (Pontus Hagland) #include "image_machine.h"
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  #include <sys/types.h> #include <sys/stat.h> #ifdef HAVE_FCNTL_H #include <fcntl.h> #endif #ifdef HAVE_SYS_FCNTL_H #include <sys/fcntl.h> #endif
7210191997-12-22Fredrik Hübinette (Hubbe) #ifdef HAVE_NETINET_IN_H
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #include <netinet/in.h>
7210191997-12-22Fredrik Hübinette (Hubbe) #endif
32434a1998-02-10Fredrik Hübinette (Hubbe) #ifdef HAVE_WINSOCK_H #include <winsock.h>
75920f1997-12-28Fredrik Hübinette (Hubbe) #endif
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #include <errno.h> #include "stralloc.h"
bb55f81997-03-16Fredrik Hübinette (Hubbe) #include "pike_macros.h"
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #include "object.h" #include "constants.h" #include "interpret.h" #include "svalue.h" #include "array.h" #include "threads.h"
9c6f7d1997-04-15Fredrik Hübinette (Hubbe) #include "builtin_functions.h"
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  #include "image.h"
c6b2f61999-10-16Mirar (Pontus Hagland) #ifdef HAVE_UNISTD_H #include <unistd.h> #endif
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #ifdef HAVE_MMAP #include <sys/mman.h> #endif
3c0c281998-01-26Fredrik Hübinette (Hubbe) #include "dmalloc.h"
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
da46841999-09-14Mirar (Pontus Hagland) #include "fdlib.h"
15e40e1999-06-03Mirar (Pontus Hagland) extern struct program *font_program;
ab6aec1997-02-11Fredrik Hübinette (Hubbe) extern struct program *image_program;
75920f1997-12-28Fredrik Hübinette (Hubbe) #undef THIS
39221e2000-07-07Henrik Grubbström (Grubba) #define THIS (*(struct font **)(Pike_fp->current_storage)) #define THISOBJ (Pike_fp->current_object)
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  struct font { unsigned long height; /* height of character rectangles */ unsigned long baseline; /* baseline of characters */ #ifdef HAVE_MMAP unsigned long mmaped_size; /* if 0 - not mmaped: just free() mem */ #endif void *mem; /* pointer to mmaped/malloced memory */ unsigned long chars; /* number of characters */ float xspacing_scale; /* Fraction of spacing to use */ float yspacing_scale; /* Fraction of spacing to use */ enum { J_LEFT, J_RIGHT, J_CENTER } justification; struct _char { unsigned long width; /* character rectangle has this width in pixels */ unsigned long spacing; /* pixels to next character */ unsigned char *pixels; /* character rectangle */ } charinfo [1]; /* many!! */ }; /***************** init & exit *********************************/
9037d01998-02-18Per Hedbor static INLINE void free_font_struct(struct font *font)
ab6aec1997-02-11Fredrik Hübinette (Hubbe) { if (font) {
0e756f1999-05-24Mirar (Pontus Hagland)  if (font->mem && font->mem!=image_default_font)
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  { #ifdef HAVE_MMAP munmap(font->mem,font->mmaped_size); #else free(font->mem); #endif } free(font); } } static void init_font_struct(struct object *o) { THIS=NULL; } static void exit_font_struct(struct object *obj) { free_font_struct(THIS); THIS=NULL; } /***************** internals ***********************************/
086cf01998-10-11Marcus Comstedt static INLINE int char_space(struct font *this, INT32 c)
d4f2441997-09-06Per Hedbor { if(c==0x20) return (int)((float)(this->height*this->xspacing_scale)/4.5); else if(c==0x20+128) return (this->height*this->xspacing_scale)/18; return this->charinfo[c].spacing*this->xspacing_scale; }
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
086cf01998-10-11Marcus Comstedt static INLINE int char_width(struct font *this, INT32 c)
d4f2441997-09-06Per Hedbor { if(c==0x20 || c==0x20+128) return 0; return this->charinfo[c].width; }
87b4cb1997-11-11Mirar (Pontus Hagland) #ifndef HAVE_MMAP
e42eaf1998-01-02Fredrik Hübinette (Hubbe) static INLINE int my_read(int from, void *t, int towrite)
ab6aec1997-02-11Fredrik Hübinette (Hubbe) { int res;
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  while((res = fd_read(from, t, towrite)) < 0)
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  { switch(errno) { case EAGAIN: case EINTR: continue; default: res = 0; return 0; } } return res; }
87b4cb1997-11-11Mirar (Pontus Hagland) #endif
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
4d869c1999-04-25Henrik Grubbström (Grubba) static INLINE off_t file_size(int fd)
ab6aec1997-02-11Fredrik Hübinette (Hubbe) { struct stat tmp;
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  if((!fd_fstat(fd, &tmp)) &&
7a5e471999-11-22Fredrik Hübinette (Hubbe)  ( tmp.st_mode & S_IFMT) == S_IFREG)
4d869c1999-04-25Henrik Grubbström (Grubba)  return (off_t)tmp.st_size;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  return -1; }
d4f2441997-09-06Per Hedbor static INLINE void write_char(struct _char *ci,
9c6f7d1997-04-15Fredrik Hübinette (Hubbe)  rgb_group *pos, INT32 xsize, INT32 height)
ab6aec1997-02-11Fredrik Hübinette (Hubbe) { rgb_group *nl; INT32 x,y; unsigned char *p; p=ci->pixels; for (y=height; y>0; y--) { nl=pos+xsize; for (x=(INT32)ci->width; x>0; x--) {
1f94161997-09-03Per Hedbor  int r,c;
b56e5a1998-04-24Mirar (Pontus Hagland)  if((c=255-*p))
1f94161997-09-03Per Hedbor  if ((r=pos->r+c)>255) pos->r=pos->g=pos->b=255; else pos->r=pos->g=pos->b=r;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  pos++; p++; } pos=nl; } } /***************** methods *************************************/
b9284c1997-04-09Mirar (Pontus Hagland) /* **! method object|int load(string filename) **! Loads a font file to this font object. **! returns zero upon failure, font object upon success **! arg string filename **! Font file **! see also: write
8856291998-05-04Mirar (Pontus Hagland) **! **! method void create(string filename) **! Loads a font file to this font object. **! Similar to <ref>load</ref>().
b9284c1997-04-09Mirar (Pontus Hagland) */
7ae3b41998-05-04Mirar (Pontus Hagland) void font_load(INT32 args); void font_create(INT32 args) {
0e756f1999-05-24Mirar (Pontus Hagland)  font_load(args); pop_stack();
7ae3b41998-05-04Mirar (Pontus Hagland) }
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  void font_load(INT32 args) {
f93a6b1999-09-25Henrik Grubbström (Grubba)  int fd = -1;
0e756f1999-05-24Mirar (Pontus Hagland)  size_t size;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  if (THIS) { free_font_struct(THIS); THIS=NULL; }
0e756f1999-05-24Mirar (Pontus Hagland)  if (!args) { THIS=(struct font *)xalloc(sizeof(struct font)); THIS->mem=image_default_font; size=IMAGE_DEFAULT_FONT_SIZE; goto loading_default; } if (sp[-args].type!=T_STRING) error("font->read: illegal or wrong number of arguments\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  do { #ifdef FONT_DEBUG fprintf(stderr,"FONT open '%s'\n",sp[-args].u.string->str); #endif
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  fd = fd_open(sp[-args].u.string->str,fd_RDONLY,0);
f93a6b1999-09-25Henrik Grubbström (Grubba)  /* FIXME: check_threads_etc(); ? */
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  } while(fd < 0 && errno == EINTR); if (fd >= 0) {
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  struct font *new_font;
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
758b141999-04-25Henrik Grubbström (Grubba)  size = (size_t) file_size(fd);
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  if (size > 0) {
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  new_font=THIS=(struct font *)xalloc(sizeof(struct font));
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  THREADS_ALLOW(); #ifdef HAVE_MMAP
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  new_font->mem =
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  mmap(0,size,PROT_READ,MAP_SHARED,fd,0);
c6b2f61999-10-16Mirar (Pontus Hagland) #ifdef MAP_FAILED
26ab0a2000-03-25Fredrik Hübinette (Hubbe)  if ((char *)new_font->mem == (char *)MAP_FAILED)
c6b2f61999-10-16Mirar (Pontus Hagland) #else if (new_font->mem==(void*)-1) #endif { new_font->mem=0; new_font->mmaped_size=0; } else new_font->mmaped_size=size;
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #else
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  new_font->mem = malloc(size); #ifdef FONT_DEBUG fprintf(stderr,"FONT Malloced %p (%d)\n",new_font->mem,size); #endif
b56e5a1998-04-24Mirar (Pontus Hagland)  if ((new_font->mem) && (!my_read(fd,new_font->mem,size))) {
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  free(new_font->mem); new_font->mem = NULL;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  } #endif THREADS_DISALLOW();
0e756f1999-05-24Mirar (Pontus Hagland) loading_default:
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  if (THIS->mem) { struct file_head { unsigned INT32 cookie; unsigned INT32 version; unsigned INT32 chars; unsigned INT32 height; unsigned INT32 baseline; unsigned INT32 o[1]; } *fh; struct char_head { unsigned INT32 width; unsigned INT32 spacing; unsigned char data[1]; } *ch; #ifdef FONT_DEBUG fprintf(stderr,"FONT mapped ok\n"); #endif fh=(struct file_head*)THIS->mem; if (ntohl(fh->cookie)==0x464f4e54) /* "FONT" */ { #ifdef FONT_DEBUG fprintf(stderr,"FONT cookie ok\n"); #endif if (ntohl(fh->version)==1) { unsigned long i; #ifdef FONT_DEBUG fprintf(stderr,"FONT version 1\n"); #endif THIS->chars=ntohl(fh->chars);
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  new_font=malloc(sizeof(struct font)+
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  sizeof(struct _char)*(THIS->chars-1));
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  new_font->mem=THIS->mem;
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #ifdef HAVE_MMAP
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  new_font->mmaped_size=THIS->mmaped_size;
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #endif
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  new_font->chars=THIS->chars; new_font->xspacing_scale = 1.0; new_font->yspacing_scale = 1.0; new_font->justification = J_LEFT;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  free(THIS);
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  THIS=new_font;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  THIS->height=ntohl(fh->height); THIS->baseline=ntohl(fh->baseline); for (i=0; i<THIS->chars; i++) { if (i*sizeof(INT32)<(unsigned long)size && ntohl(fh->o[i])<(unsigned long)size && ! ( ntohl(fh->o[i]) % 4) ) /* must be aligned */ { ch=(struct char_head*) ((char *)(THIS->mem)+ntohl(fh->o[i])); THIS->charinfo[i].width = ntohl(ch->width); THIS->charinfo[i].spacing = ntohl(ch->spacing); THIS->charinfo[i].pixels = ch->data; } else /* illegal <tm> offset or illegal align */ { #ifdef FONT_DEBUG fprintf(stderr,"FONT failed on char %02xh %d '%c'\n", i,i,i); #endif
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  free_font_struct(new_font);
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  THIS=NULL;
f93a6b1999-09-25Henrik Grubbström (Grubba)  if (fd >= 0) { fd_close(fd); }
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  pop_n_elems(args); push_int(0); return; } }
0e756f1999-05-24Mirar (Pontus Hagland)  if (!args) goto done;
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  fd_close(fd);
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  pop_n_elems(args);
d6ac731998-04-20Henrik Grubbström (Grubba)  ref_push_object(THISOBJ); /* success */
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #ifdef FONT_DEBUG fprintf(stderr,"FONT successfully loaded\n"); #endif return; } /* wrong version */ #ifdef FONT_DEBUG else fprintf(stderr,"FONT unknown version\n"); #endif } /* wrong cookie */ #ifdef FONT_DEBUG else fprintf(stderr,"FONT wrong cookie\n"); #endif
0e756f1999-05-24Mirar (Pontus Hagland)  if (!args) goto done; /* just in case */
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  } /* mem failure */ #ifdef FONT_DEBUG else fprintf(stderr,"FONT mem failure\n"); #endif free_font_struct(THIS); THIS=NULL; } /* size failure */ #ifdef FONT_DEBUG else fprintf(stderr,"FONT size failure\n"); #endif
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  fd_close(fd);
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  } /* fd failure */ #ifdef FONT_DEBUG else fprintf(stderr,"FONT fd failure\n"); #endif
0e756f1999-05-24Mirar (Pontus Hagland) done:
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  pop_n_elems(args); push_int(0); return; }
b9284c1997-04-09Mirar (Pontus Hagland) /* **! method object write(string text,...) **! Writes some text; thus creating an image object **! that can be used as mask or as a complete picture.
448c201999-04-13Mirar (Pontus Hagland) **! returns an <ref>Image.Image</ref> object
b9284c1997-04-09Mirar (Pontus Hagland) **! arg string text, ... **! One or more lines of text.
448c201999-04-13Mirar (Pontus Hagland) **! see also: text_extents, load, Image.Image->paste_mask, Image.Image->paste_alpha_color
b9284c1997-04-09Mirar (Pontus Hagland) */
ab6aec1997-02-11Fredrik Hübinette (Hubbe) void font_write(INT32 args) { struct object *o; struct image *img;
d4f2441997-09-06Per Hedbor  INT32 xsize=0,i,maxwidth2,j;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  int *width_of;
086cf01998-10-11Marcus Comstedt  p_wchar0 *to_write0; p_wchar1 *to_write1; p_wchar2 *to_write2;
1f94161997-09-03Per Hedbor  int to_write_len;
086cf01998-10-11Marcus Comstedt  INT32 c;
39221e2000-07-07Henrik Grubbström (Grubba)  struct font *this = (*(struct font **)(Pike_fp->current_storage));
7abac31997-09-01Per Hedbor  if (!this)
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  error("font->write: no font loaded\n");
8856291998-05-04Mirar (Pontus Hagland)  if (args==0) { push_string(make_shared_binary_string("",0)); args++; }
5cb0011998-02-10Mirar (Pontus Hagland)  maxwidth2=1;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  width_of=(int *)malloc((args+1)*sizeof(int));
80f30b1999-06-18Mirar (Pontus Hagland)  if(!width_of) resource_error(NULL,0,0,"memory",0,"Out of memory.\n");
1f94161997-09-03Per Hedbor 
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  for (j=0; j<args; j++) {
8856291998-05-04Mirar (Pontus Hagland)  int max; if (sp[j-args].type!=T_STRING)
80f30b1999-06-18Mirar (Pontus Hagland)  bad_arg_error("font->write",sp-args,args,0,"",sp-args, "Bad arguments to font->write()\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
8856291998-05-04Mirar (Pontus Hagland)  xsize = max = 1; to_write_len = sp[j-args].u.string->len;
086cf01998-10-11Marcus Comstedt  switch(sp[j-args].u.string->size_shift)
8856291998-05-04Mirar (Pontus Hagland)  {
086cf01998-10-11Marcus Comstedt  case 0: to_write0 = STR0(sp[j-args].u.string); for (i = 0; i < to_write_len; i++) {
2d6c521998-11-03Per Hedbor  if (to_write0[i] < (INT32)this->chars) { if (xsize+char_width(this,to_write0[i]) > max) max=xsize+char_width(this,to_write0[i]); xsize += char_space(this,to_write0[i]); if (xsize > max) max=xsize; }
086cf01998-10-11Marcus Comstedt  } break; case 1: to_write1 = STR1(sp[j-args].u.string); for (i = 0; i < to_write_len; i++) {
2d6c521998-11-03Per Hedbor  if (to_write1[i] < (INT32)this->chars) { if (xsize+char_width(this,to_write1[i]) > max) max=xsize+char_width(this,to_write1[i]); xsize += char_space(this,to_write1[i]); if (xsize > max) max=xsize; }
086cf01998-10-11Marcus Comstedt  } break; case 2: to_write2 = STR2(sp[j-args].u.string); for (i = 0; i < to_write_len; i++) {
2d6c521998-11-03Per Hedbor  if (to_write2[i] < (unsigned INT32)this->chars) { if (xsize+char_width(this,to_write2[i]) > max) max=xsize+char_width(this,to_write2[i]); xsize += char_space(this,to_write2[i]); if (xsize > max) max=xsize; }
086cf01998-10-11Marcus Comstedt  } break; default: fatal("Illegal shift size!\n");
8856291998-05-04Mirar (Pontus Hagland)  } width_of[j]=max; if (max>maxwidth2) maxwidth2=max;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  }
e709751997-03-12Fredrik Hübinette (Hubbe)  o = clone_object(image_program,0);
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  img = ((struct image*)o->storage); img->xsize = maxwidth2; if(args>1)
7abac31997-09-01Per Hedbor  img->ysize = this->height+((double)this->height*(double)(args-1)*(double)this->yspacing_scale)+1;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  else
7a65d61998-02-07Mirar (Pontus Hagland)  img->ysize = this->height;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  img->rgb.r=img->rgb.g=img->rgb.b=255;
7a65d61998-02-07Mirar (Pontus Hagland)  img->img=malloc(img->xsize*img->ysize*sizeof(rgb_group)+1);
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
80f30b1999-06-18Mirar (Pontus Hagland)  if (!img) { free_object(o); free(width_of); resource_error(NULL,0,0,"memory",0,"Out of memory.\n"); }
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  MEMSET(img->img,0,img->xsize*img->ysize*sizeof(rgb_group)); for (j=0; j<args; j++) {
1f94161997-09-03Per Hedbor  to_write_len = sp[j-args].u.string->len;
7abac31997-09-01Per Hedbor  switch(this->justification)
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  {
1f94161997-09-03Per Hedbor  case J_LEFT: xsize = 0; break; case J_RIGHT: xsize = img->xsize-width_of[j]-1; break;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  case J_CENTER: xsize = img->xsize/2-width_of[j]/2-1; break; } if(xsize<0) xsize=0;
1f94161997-09-03Per Hedbor 
086cf01998-10-11Marcus Comstedt  switch(sp[j-args].u.string->size_shift)
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  {
086cf01998-10-11Marcus Comstedt  case 0: to_write0 = STR0(sp[j-args].u.string); THREADS_ALLOW(); for (i = 0; i < to_write_len; i++) { c=*(to_write0++); if (c < (INT32)this->chars) { if(char_width(this,c)) write_char(this->charinfo+c, (img->img+xsize)+ (img->xsize*(int)(j*this->height*this->yspacing_scale)), img->xsize, this->height); xsize += char_space(this, c); } } THREADS_DISALLOW(); break; case 1: to_write1 = STR1(sp[j-args].u.string); THREADS_ALLOW(); for (i = 0; i < to_write_len; i++) { c=*(to_write1++); if (c < (INT32)this->chars) { if(char_width(this,c)) write_char(this->charinfo+c, (img->img+xsize)+ (img->xsize*(int)(j*this->height*this->yspacing_scale)), img->xsize, this->height); xsize += char_space(this, c); } } THREADS_DISALLOW(); break; case 2: to_write2 = STR2(sp[j-args].u.string); THREADS_ALLOW(); for (i = 0; i < to_write_len; i++) { c=*(to_write2++); if (c < (INT32)this->chars) { if(char_width(this,c)) write_char(this->charinfo+c, (img->img+xsize)+ (img->xsize*(int)(j*this->height*this->yspacing_scale)), img->xsize, this->height); xsize += char_space(this, c); } } THREADS_DISALLOW(); break; default: fatal("Illegal shift size!\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  } } free(width_of);
7abac31997-09-01Per Hedbor 
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  pop_n_elems(args); push_object(o); }
b9284c1997-04-09Mirar (Pontus Hagland) /* **! method int height() **! returns font height **! see also: baseline, text_extents */
ab6aec1997-02-11Fredrik Hübinette (Hubbe) void font_height(INT32 args) { pop_n_elems(args); if (THIS) push_int(THIS->height); else push_int(0); }
b9284c1997-04-09Mirar (Pontus Hagland) /*
f311411997-04-18Mirar (Pontus Hagland) **! method array(int) text_extents(string text,...)
b9284c1997-04-09Mirar (Pontus Hagland) **! Calculate extents of a text-image, **! that would be created by calling <ref>write</ref> **! with the same arguments. **! returns an array of width and height **! arg string text, ... **! One or more lines of text. **! see also: write, height, baseline */
ab6aec1997-02-11Fredrik Hübinette (Hubbe) void font_text_extents(INT32 args) {
87b4cb1997-11-11Mirar (Pontus Hagland)  INT32 xsize,i,maxwidth2,j;
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
1f94161997-09-03Per Hedbor  if (!THIS) error("font->text_extents: no font loaded\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  maxwidth2=0;
8856291998-05-04Mirar (Pontus Hagland)  if (args==0) { push_string(make_shared_binary_string("",0)); args++; } for (j=0; j<args; j++)
d4f2441997-09-06Per Hedbor  {
8856291998-05-04Mirar (Pontus Hagland)  int max;
086cf01998-10-11Marcus Comstedt  p_wchar0 *to_write0; p_wchar1 *to_write1; p_wchar2 *to_write2;
8856291998-05-04Mirar (Pontus Hagland)  int to_write_len; if (sp[j-args].type!=T_STRING)
80f30b1999-06-18Mirar (Pontus Hagland)  bad_arg_error("font->write",sp-args,args,0,"",sp-args, "Bad arguments to font->write()\n");
8856291998-05-04Mirar (Pontus Hagland)  xsize = max = 1; to_write_len = sp[j-args].u.string->len;
086cf01998-10-11Marcus Comstedt  switch(sp[j-args].u.string->size_shift)
8856291998-05-04Mirar (Pontus Hagland)  {
086cf01998-10-11Marcus Comstedt  case 0: to_write0 = STR0(sp[j-args].u.string); for (i = 0; i < to_write_len; i++) { if (xsize+char_width(THIS,to_write0[i]) > max) max=xsize+char_width(THIS,to_write0[i]); xsize += char_space(THIS,to_write0[i]); if (xsize > max) max=xsize; } break; case 1: to_write1 = STR1(sp[j-args].u.string); for (i = 0; i < to_write_len; i++) { if (xsize+char_width(THIS,to_write1[i]) > max) max=xsize+char_width(THIS,to_write1[i]); xsize += char_space(THIS,to_write1[i]); if (xsize > max) max=xsize; } break; case 2: to_write2 = STR2(sp[j-args].u.string); for (i = 0; i < to_write_len; i++) { if (xsize+char_width(THIS,to_write2[i]) > max) max=xsize+char_width(THIS,to_write2[i]); xsize += char_space(THIS,to_write2[i]); if (xsize > max) max=xsize; } break; default: fatal("Illegal shift size!\n");
8856291998-05-04Mirar (Pontus Hagland)  } if (max>maxwidth2) maxwidth2=max;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  }
8856291998-05-04Mirar (Pontus Hagland) 
b9284c1997-04-09Mirar (Pontus Hagland)  pop_n_elems(args);
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  push_int(maxwidth2); push_int(args * THIS->height * THIS->yspacing_scale);
b9284c1997-04-09Mirar (Pontus Hagland)  f_aggregate(2);
ab6aec1997-02-11Fredrik Hübinette (Hubbe) }
b9284c1997-04-09Mirar (Pontus Hagland)  /* **! method void set_xspacing_scale(float scale) **! method void set_yspacing_scale(float scale) **! Set spacing scale to write characters closer **! or more far away. This does not change scale **! of character, only the space between them. **! arg float scale **! what scale to use */
ab6aec1997-02-11Fredrik Hübinette (Hubbe) void font_set_xspacing_scale(INT32 args) { if(!THIS) error("font->set_xspacing_scale(FLOAT): No font loaded.\n"); if(!args) error("font->set_xspacing_scale(FLOAT): No argument!\n"); if(sp[-args].type!=T_FLOAT) error("font->set_xspacing_scale(FLOAT): Wrong type of argument!\n"); THIS->xspacing_scale = (double)sp[-args].u.float_number; /*fprintf(stderr, "Setting xspacing to %f\n", THIS->xspacing_scale);*/ if(THIS->xspacing_scale < 0.0) THIS->xspacing_scale=0.1; pop_stack(); } void font_set_yspacing_scale(INT32 args) { if(!THIS) error("font->set_yspacing_scale(FLOAT): No font loaded.\n"); if(!args) error("font->set_yspacing_scale(FLOAT): No argument!\n"); if(sp[-args].type!=T_FLOAT) error("font->set_yspacing_scale(FLOAT): Wrong type of argument!\n"); THIS->yspacing_scale = (double)sp[-args].u.float_number; /*fprintf(stderr, "Setting yspacing to %f\n", THIS->yspacing_scale);*/ if(THIS->yspacing_scale <= 0.0) THIS->yspacing_scale=0.1; pop_stack(); }
b9284c1997-04-09Mirar (Pontus Hagland)  /* **! method int baseline() **! returns font baseline (pixels from top) **! see also: height, text_extents */
ab6aec1997-02-11Fredrik Hübinette (Hubbe) void font_baseline(INT32 args) { pop_n_elems(args); if (THIS) push_int(THIS->baseline); else push_int(0); } void font_set_center(INT32 args) { pop_n_elems(args); if(THIS) THIS->justification=J_CENTER; } void font_set_right(INT32 args) { pop_n_elems(args); if(THIS) THIS->justification=J_RIGHT; } void font_set_left(INT32 args) { pop_n_elems(args); if(THIS) THIS->justification=J_LEFT; } /***************** global init etc *****************************/ /* int load(string filename); // load font file, true is success object write(string text); // new image object int height(); // font heigth int baseline(); // font baseline */
8db2c31999-05-23Mirar (Pontus Hagland) void init_image_font(void)
ab6aec1997-02-11Fredrik Hübinette (Hubbe) {
90e9781999-01-31Fredrik Hübinette (Hubbe)  ADD_STORAGE(struct font*);
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(string:object|int) */
448c201999-04-13Mirar (Pontus Hagland)  ADD_FUNCTION("load",font_load,tFunc(tStr,tOr(tObj,tInt)),0);
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(void|string:void) */
448c201999-04-13Mirar (Pontus Hagland)  ADD_FUNCTION("create",font_create,tFunc(tOr(tVoid,tStr),tVoid),0);
8856291998-05-04Mirar (Pontus Hagland) 
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(string:object) */
07228a1999-06-19Fredrik Hübinette (Hubbe)  ADD_FUNCTION("write",font_write,tFuncV(tNone,tStr,tObj),0);
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(:int) */
07228a1999-06-19Fredrik Hübinette (Hubbe)  ADD_FUNCTION("height",font_height,tFunc(tNone,tInt),0);
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(:int) */
07228a1999-06-19Fredrik Hübinette (Hubbe)  ADD_FUNCTION("baseline",font_baseline,tFunc(tNone,tInt),0);
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(string ...:array(int)) */
07228a1999-06-19Fredrik Hübinette (Hubbe)  ADD_FUNCTION("extents",font_text_extents,tFuncV(tNone,tStr,tArr(tInt)),0);
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(string ...:array(int)) */
07228a1999-06-19Fredrik Hübinette (Hubbe)  ADD_FUNCTION("text_extents",font_text_extents,tFuncV(tNone,tStr,tArr(tInt)),0);
1f94161997-09-03Per Hedbor 
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(float:void) */
448c201999-04-13Mirar (Pontus Hagland)  ADD_FUNCTION("set_x_spacing",font_set_xspacing_scale,tFunc(tFlt,tVoid),0);
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(float:void) */
448c201999-04-13Mirar (Pontus Hagland)  ADD_FUNCTION("set_y_spacing",font_set_yspacing_scale,tFunc(tFlt,tVoid),0);
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(void:void) */
448c201999-04-13Mirar (Pontus Hagland)  ADD_FUNCTION("center", font_set_center,tFunc(tVoid,tVoid), 0);
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(void:void) */
448c201999-04-13Mirar (Pontus Hagland)  ADD_FUNCTION("left", font_set_left,tFunc(tVoid,tVoid), 0);
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(void:void) */
448c201999-04-13Mirar (Pontus Hagland)  ADD_FUNCTION("right", font_set_right,tFunc(tVoid,tVoid), 0);
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  set_init_callback(init_font_struct); set_exit_callback(exit_font_struct); }
8db2c31999-05-23Mirar (Pontus Hagland) void exit_image_font(void)
ab6aec1997-02-11Fredrik Hübinette (Hubbe) { }