e576bb2002-10-11Martin Nilsson /* || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. */
1b10db2002-10-08Martin Nilsson 
fec6251998-03-25Fredrik Hübinette (Hubbe) #include "global.h"
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
7abac31997-09-01Per Hedbor #define SPACE_CHAR 'i'
2062bd2003-02-20Henrik Grubbström (Grubba) extern const unsigned char image_default_font[];
bbdf8c2013-02-03Henrik Grubbström (Grubba) #define IMAGE_DEFAULT_FONT_SIZE 30560
0e756f1999-05-24Mirar (Pontus Hagland) 
e3cb4b1997-04-03Mirar (Pontus Hagland) 
ab5e032001-11-18Martin Nilsson /*! @module Image
15dfec1997-05-28Mirar (Pontus Hagland)  */
ab5e032001-11-18Martin Nilsson /*! @class Font *! *! Short technical documentation on a font file: *! This object adds the text-drawing and -creation
cf98cf2002-11-29Johan Sundström  *! capabilities of the @[Image] module.
ab5e032001-11-18Martin Nilsson  *! *! For simple usage, see @[write] and @[load]. *! *! @note *! @pre{
cf98cf2002-11-29Johan Sundström  *! struct file_head
ab5e032001-11-18Martin Nilsson  *! {
cf98cf2002-11-29Johan Sundström  *! unsigned INT32 cookie; - 0x464f4e54 *! unsigned INT32 version; - 1
ab5e032001-11-18Martin Nilsson  *! 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; *! *! version 2: *! *! *! On-disk syntax (everything in N.B.O), int is 4 bytes, a byte is 8 bits:
13670c2015-05-25Martin Nilsson  *!
ab5e032001-11-18Martin Nilsson  *! 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
13670c2015-05-25Martin Nilsson  *!
ab5e032001-11-18Martin Nilsson  *! 24 int offsets[numchars]; pointers into the data, realative to &cookie. *! [colortable] *! [kerningtable]
13670c2015-05-25Martin Nilsson  *!
ab5e032001-11-18Martin Nilsson  *! At each offset:
13670c2015-05-25Martin Nilsson  *! *!
ab5e032001-11-18Martin Nilsson  *! 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.
13670c2015-05-25Martin Nilsson  *!
ab5e032001-11-18Martin Nilsson  *! 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
13670c2015-05-25Martin Nilsson  *!
ab5e032001-11-18Martin Nilsson  *! 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)
13670c2015-05-25Martin Nilsson  *!
ab5e032001-11-18Martin Nilsson  *! 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) *! @} *! *! @seealso *! @[Image], @[Image.Image] */
15dfec1997-05-28Mirar (Pontus Hagland) 
da46841999-09-14Mirar (Pontus Hagland) #include "image_machine.h"
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  #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
4fcf442003-04-30Henrik Grubbström (Grubba) #ifdef HAVE_WINSOCK2_H #include <winsock2.h> #elif defined(HAVE_WINSOCK_H)
32434a1998-02-10Fredrik Hübinette (Hubbe) #include <winsock.h>
75920f1997-12-28Fredrik Hübinette (Hubbe) #endif
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #include <errno.h> #include "stralloc.h" #include "object.h" #include "interpret.h" #include "svalue.h" #include "threads.h"
9c6f7d1997-04-15Fredrik Hübinette (Hubbe) #include "builtin_functions.h"
7d60af2004-05-19Martin Nilsson #include "module_support.h"
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  #include "image.h"
94734d2015-10-18Martin Nilsson 
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #ifdef HAVE_MMAP #include <sys/mman.h> #endif
da46841999-09-14Mirar (Pontus Hagland) #include "fdlib.h"
50c6fa2000-08-14Henrik Grubbström (Grubba) #include "bignum.h"
6dc2772000-07-28Fredrik Hübinette (Hubbe) 
6ad2372002-05-11Martin Nilsson #define sp Pike_sp
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) 
13670c2015-05-25Martin Nilsson struct font
ab6aec1997-02-11Fredrik Hübinette (Hubbe) { 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 */
0af1852000-08-11Henrik Grubbström (Grubba)  double xspacing_scale; /* Fraction of spacing to use */ double yspacing_scale; /* Fraction of spacing to use */
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  enum { J_LEFT, J_RIGHT, J_CENTER } justification;
13670c2015-05-25Martin Nilsson  struct _char
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  { 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 *********************************/
01b9212016-01-12Per 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
092c7c2005-11-03Henrik Grubbström (Grubba)  if (font->mmaped_size) { munmap(font->mem,font->mmaped_size); } else
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #else
092c7c2005-11-03Henrik Grubbström (Grubba)  free(font->mem);
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #endif
092c7c2005-11-03Henrik Grubbström (Grubba)  font->mem = NULL;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  } free(font); } }
74dfe82012-12-30Jonas Walldén static void init_font_struct(struct object *UNUSED(o))
ab6aec1997-02-11Fredrik Hübinette (Hubbe) { THIS=NULL; }
74dfe82012-12-30Jonas Walldén static void exit_font_struct(struct object *UNUSED(obj))
ab6aec1997-02-11Fredrik Hübinette (Hubbe) { free_font_struct(THIS); THIS=NULL; } /***************** internals ***********************************/
01b9212016-01-12Per Hedbor static inline int char_space(struct font *this, INT32 c)
d4f2441997-09-06Per Hedbor { if(c==0x20)
04a97d2016-02-12Martin Nilsson  return (int)((double)(this->height*this->xspacing_scale)/4.5);
d4f2441997-09-06Per Hedbor  else if(c==0x20+128)
04a97d2016-02-12Martin Nilsson  return (int)((this->height*this->xspacing_scale)/18); return (int)(this->charinfo[c].spacing*this->xspacing_scale);
d4f2441997-09-06Per Hedbor }
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
01b9212016-01-12Per Hedbor 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;
13670c2015-05-25Martin Nilsson }
d4f2441997-09-06Per Hedbor 
01b9212016-01-12Per Hedbor static inline ptrdiff_t my_read(int fd, void *t, size_t towrite)
ab6aec1997-02-11Fredrik Hübinette (Hubbe) {
bea2ad2000-08-14Henrik Grubbström (Grubba)  ptrdiff_t res;
092c7c2005-11-03Henrik Grubbström (Grubba)  while((res = fd_read(fd, t, towrite)) < 0)
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  { switch(errno) { case EAGAIN: case EINTR: continue; default: res = 0; return 0; } } return res; }
01b9212016-01-12Per Hedbor static inline off_t file_size(int fd)
ab6aec1997-02-11Fredrik Hübinette (Hubbe) {
40962a2003-03-27Martin Stjernholm  PIKE_STAT_T 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; }
01b9212016-01-12Per 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;
0af1852000-08-11Henrik Grubbström (Grubba)  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;
0af1852000-08-11Henrik Grubbström (Grubba)  }
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  pos++; p++; } pos=nl; } } /***************** methods *************************************/
ab5e032001-11-18Martin Nilsson /*! @decl Image.Font|int load(string filename) *! Loads a font file to this font object. *! @returns *! Returns zero upon failure and a font object upon success. *! @param filename *! The path to the font file. *! @seealso *! @[write] */
092c7c2005-11-03Henrik Grubbström (Grubba) #ifndef MAP_FAILED #define MAP_FAILED ((void *)-1) #endif
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  void font_load(INT32 args) {
13670c2015-05-25Martin Nilsson  struct file_head
092c7c2005-11-03Henrik Grubbström (Grubba)  { unsigned INT32 cookie; unsigned INT32 version; unsigned INT32 chars; unsigned INT32 height; unsigned INT32 baseline; unsigned INT32 o[1]; } *fh = NULL; #ifdef HAVE_MMAP size_t mmaped_size = 0; #endif
b7f5e72015-04-18Martin Nilsson  int size = 0;
ddc1a32010-07-27Martin Stjernholm  char *filename = NULL;
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
69c0aa2014-08-25Martin Nilsson  get_all_args("load", args, ".%s", &filename);
0e756f1999-05-24Mirar (Pontus Hagland) 
ddc1a32010-07-27Martin Stjernholm  if (!filename)
092c7c2005-11-03Henrik Grubbström (Grubba)  { fh = (struct file_head *)image_default_font; size = IMAGE_DEFAULT_FONT_SIZE; } else { int fd = -1;
0e756f1999-05-24Mirar (Pontus Hagland) 
092c7c2005-11-03Henrik Grubbström (Grubba)  do {
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #ifdef FONT_DEBUG
092c7c2005-11-03Henrik Grubbström (Grubba)  fprintf(stderr,"FONT open '%s'\n",sp[-args].u.string->str);
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #endif
62522d2005-11-13Martin Nilsson  fd = fd_open(filename,fd_RDONLY,0);
092c7c2005-11-03Henrik Grubbström (Grubba)  if (errno == EINTR) check_threads_etc(); } while(fd < 0 && errno == EINTR);
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
092c7c2005-11-03Henrik Grubbström (Grubba)  if (fd >= 0) {
b7f5e72015-04-18Martin Nilsson  size = file_size(fd);
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  if (size > 0) {
092c7c2005-11-03Henrik Grubbström (Grubba)  THREADS_ALLOW();
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #ifdef HAVE_MMAP
092c7c2005-11-03Henrik Grubbström (Grubba)  fh = (struct file_head *) mmap(0, size, PROT_READ, MAP_SHARED, fd, 0); if (fh != (struct file_head *)MAP_FAILED) mmaped_size = size; else {
c6b2f61999-10-16Mirar (Pontus Hagland) #endif
dc8d022014-04-27Martin Nilsson  fh = xalloc(size);
e42eaf1998-01-02Fredrik Hübinette (Hubbe) #ifdef FONT_DEBUG
092c7c2005-11-03Henrik Grubbström (Grubba)  fprintf(stderr,"FONT Malloced %p (%d)\n", fh, size);
e42eaf1998-01-02Fredrik Hübinette (Hubbe) #endif
13670c2015-05-25Martin Nilsson  if (fh && (!my_read(fd, fh, size)))
092c7c2005-11-03Henrik Grubbström (Grubba)  { free(fh); fh = NULL; } #ifdef HAVE_MMAP }
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #endif
092c7c2005-11-03Henrik Grubbström (Grubba)  THREADS_DISALLOW();
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
092c7c2005-11-03Henrik Grubbström (Grubba)  } /* size failure */ #ifdef FONT_DEBUG else fprintf(stderr,"FONT size failure\n"); #endif fd_close(fd); } /* fd failure */ #ifdef FONT_DEBUG else fprintf(stderr,"FONT fd failure\n"); #endif }
74e4352003-10-07Martin Stjernholm 
092c7c2005-11-03Henrik Grubbström (Grubba)  if (THIS) { free_font_struct(THIS); THIS=NULL; }
0e756f1999-05-24Mirar (Pontus Hagland) 
092c7c2005-11-03Henrik Grubbström (Grubba)  if (fh) { struct char_head { unsigned INT32 width; unsigned INT32 spacing; unsigned char data[1]; } *ch;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  #ifdef FONT_DEBUG
092c7c2005-11-03Henrik Grubbström (Grubba)  fprintf(stderr,"FONT mapped ok\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #endif
092c7c2005-11-03Henrik Grubbström (Grubba)  if (ntohl(fh->cookie)==0x464f4e54) /* "FONT" */ {
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #ifdef FONT_DEBUG
092c7c2005-11-03Henrik Grubbström (Grubba)  fprintf(stderr,"FONT cookie ok\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #endif
092c7c2005-11-03Henrik Grubbström (Grubba)  if (ntohl(fh->version)==1) { struct font *new_font; unsigned long num_chars; unsigned long i;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  #ifdef FONT_DEBUG
092c7c2005-11-03Henrik Grubbström (Grubba)  fprintf(stderr,"FONT version 1\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #endif
092c7c2005-11-03Henrik Grubbström (Grubba)  num_chars = ntohl(fh->chars);
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
092c7c2005-11-03Henrik Grubbström (Grubba)  new_font=malloc(sizeof(struct font)+ sizeof(struct _char)*(num_chars-1)); if(!new_font) {
ddc1a32010-07-27Martin Stjernholm  if (filename) {
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #ifdef HAVE_MMAP
092c7c2005-11-03Henrik Grubbström (Grubba)  if (mmaped_size) munmap((void *)fh, mmaped_size); else
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #endif
092c7c2005-11-03Henrik Grubbström (Grubba)  free(fh); } SIMPLE_OUT_OF_MEMORY_ERROR(0,0); } new_font->mem = (void *)fh; #ifdef HAVE_MMAP new_font->mmaped_size = mmaped_size;
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #endif
092c7c2005-11-03Henrik Grubbström (Grubba)  new_font->chars = num_chars; new_font->xspacing_scale = 1.0; new_font->yspacing_scale = 1.0; new_font->justification = J_LEFT; new_font->height=ntohl(fh->height); new_font->baseline=ntohl(fh->baseline); for (i=0; i<num_chars; i++) {
3c5fe62015-04-20Henrik Grubbström (Grubba)  if ((i*sizeof(INT32) + OFFSETOF(file_head, o))<(size_t)size
b7f5e72015-04-18Martin Nilsson  && ntohl(fh->o[i])<(size_t)size
092c7c2005-11-03Henrik Grubbström (Grubba)  && ! ( ntohl(fh->o[i]) % 4) ) /* must be aligned */ { ch = (struct char_head*) (((char *)(fh)) + ntohl(fh->o[i])); new_font->charinfo[i].width = ntohl(ch->width); new_font->charinfo[i].spacing = ntohl(ch->spacing); new_font->charinfo[i].pixels = ch->data; } else /* illegal <tm> offset or illegal align */ {
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #ifdef FONT_DEBUG
092c7c2005-11-03Henrik Grubbström (Grubba)  fprintf(stderr,"FONT failed on char %02xh %d '%c'\n", i,i,i);
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #endif
092c7c2005-11-03Henrik Grubbström (Grubba)  free_font_struct(new_font); pop_n_elems(args); push_int(0); return; } } pop_n_elems(args); THIS = new_font; ref_push_object(THISOBJ); /* success */
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #ifdef FONT_DEBUG
092c7c2005-11-03Henrik Grubbström (Grubba)  fprintf(stderr,"FONT successfully loaded\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #endif
092c7c2005-11-03Henrik Grubbström (Grubba)  return; } /* wrong version */
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #ifdef FONT_DEBUG
092c7c2005-11-03Henrik Grubbström (Grubba)  else fprintf(stderr,"FONT unknown version\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #endif
092c7c2005-11-03Henrik Grubbström (Grubba)  } /* wrong cookie */
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #ifdef FONT_DEBUG
092c7c2005-11-03Henrik Grubbström (Grubba)  else fprintf(stderr,"FONT wrong cookie\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #endif
ddc1a32010-07-27Martin Stjernholm  if (filename) {
092c7c2005-11-03Henrik Grubbström (Grubba) #ifdef HAVE_MMAP if (mmaped_size) munmap((void *)fh, mmaped_size); else
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #endif
092c7c2005-11-03Henrik Grubbström (Grubba)  free(fh); } } /* mem failure */
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #ifdef FONT_DEBUG
092c7c2005-11-03Henrik Grubbström (Grubba)  else fprintf(stderr,"FONT mem failure\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #endif
092c7c2005-11-03Henrik Grubbström (Grubba)  pop_n_elems(args); push_int(0); return; } /*! @decl void create(string filename) *! Loads a font file to this font object. *! Similar to @[load()]. */
0e756f1999-05-24Mirar (Pontus Hagland) 
092c7c2005-11-03Henrik Grubbström (Grubba) void font_create(INT32 args) { font_load(args);
ab6aec1997-02-11Fredrik Hübinette (Hubbe) }
ab5e032001-11-18Martin Nilsson /*! @decl Image.Image write(string text, string ... more_text_lines) *! Writes some text; thus creating an image object *! that can be used as mask or as a complete picture. *! One or more text lines may be provided. *! *! @seealso *! @[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;
0af1852000-08-11Henrik Grubbström (Grubba)  ptrdiff_t to_write_len;
086cf01998-10-11Marcus Comstedt  INT32 c;
39221e2000-07-07Henrik Grubbström (Grubba)  struct font *this = (*(struct font **)(Pike_fp->current_storage));
7d60af2004-05-19Martin Nilsson  ONERROR err;
7abac31997-09-01Per Hedbor  if (!this)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("font->write: no font loaded\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
8856291998-05-04Mirar (Pontus Hagland)  if (args==0) {
7863d62005-05-06Martin Nilsson  push_empty_string();
7d60af2004-05-19Martin Nilsson  args=1;
8856291998-05-04Mirar (Pontus Hagland)  }
5cb0011998-02-10Mirar (Pontus Hagland)  maxwidth2=1;
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
dc8d022014-04-27Martin Nilsson  width_of=xalloc((args+1)*sizeof(int));
7d60af2004-05-19Martin Nilsson  SET_ONERROR(err, free, width_of);
1f94161997-09-03Per Hedbor 
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  for (j=0; j<args; j++) {
8856291998-05-04Mirar (Pontus Hagland)  int max;
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(sp[j-args]) != T_STRING)
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("write",1,"string");
de22f72014-08-25Martin Nilsson 
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++) {
90748e2012-03-01Henrik Grubbström (Grubba)  if ((unsigned INT32)to_write2[i] < this->chars)
2d6c521998-11-03Per Hedbor  { 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;
8856291998-05-04Mirar (Pontus Hagland)  } width_of[j]=max; if (max>maxwidth2) maxwidth2=max;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  }
13670c2015-05-25Martin Nilsson 
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)
04a97d2016-02-12Martin Nilsson  img->ysize = (int)(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;
20d0552009-04-22Martin Stjernholm  img->img=malloc(img->xsize*img->ysize*sizeof(rgb_group)+RGB_VEC_PAD);
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
7d60af2004-05-19Martin Nilsson  if (!img->img) { free_object(o); SIMPLE_OUT_OF_MEMORY_ERROR("write", img->xsize*img->ysize*sizeof(rgb_group)+1); }
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
21b12a2014-09-03Martin Nilsson  memset(img->img,0,img->xsize*img->ysize*sizeof(rgb_group));
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  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);
74e4352003-10-07Martin Stjernholm  /* THREADS_ALLOW(); */ /* Can't release the thread here; this would point to freed * memory if font_load gets called. We'd have to refcount font * structs to cope with that, but since the released window * typically is short and since this code isn't used much now * when we have Image.FreeType, I bluntly disable it instead. * /mast */
086cf01998-10-11Marcus Comstedt  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)+
04a97d2016-02-12Martin Nilsson  (img->xsize*(int)(j*this->height* this->yspacing_scale)),
086cf01998-10-11Marcus Comstedt  img->xsize, this->height); xsize += char_space(this, c); } }
74e4352003-10-07Martin Stjernholm  /* THREADS_DISALLOW(); */
086cf01998-10-11Marcus Comstedt  break; case 1: to_write1 = STR1(sp[j-args].u.string);
74e4352003-10-07Martin Stjernholm  /* THREADS_ALLOW(); */
086cf01998-10-11Marcus Comstedt  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)+
04a97d2016-02-12Martin Nilsson  (img->xsize*(int)(j*this->height* this->yspacing_scale)),
086cf01998-10-11Marcus Comstedt  img->xsize, this->height); xsize += char_space(this, c); } }
74e4352003-10-07Martin Stjernholm  /* THREADS_DISALLOW(); */
086cf01998-10-11Marcus Comstedt  break; case 2: to_write2 = STR2(sp[j-args].u.string);
74e4352003-10-07Martin Stjernholm  /* THREADS_ALLOW(); */
086cf01998-10-11Marcus Comstedt  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)+
04a97d2016-02-12Martin Nilsson  (img->xsize*(int)(j*this->height* this->yspacing_scale)),
086cf01998-10-11Marcus Comstedt  img->xsize, this->height); xsize += char_space(this, c); } }
74e4352003-10-07Martin Stjernholm  /* THREADS_DISALLOW(); */
086cf01998-10-11Marcus Comstedt  break;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  } }
092c7c2005-11-03Henrik Grubbström (Grubba)  CALL_AND_UNSET_ONERROR(err);
7abac31997-09-01Per Hedbor 
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  pop_n_elems(args); push_object(o); }
ab5e032001-11-18Martin Nilsson /*! @decl int height() *! Returns the font height. *! *! @seealso *! @[baseline], @[text_extents] */
b9284c1997-04-09Mirar (Pontus Hagland) 
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); }
ab5e032001-11-18Martin Nilsson  /*! @decl array(int) text_extents(string text, string ... more_text_lines) *! Calculate extents of a text-image, *! that would be created by calling @[write] *! with the same arguments. One or more lines *! of text may be provided. *! *! @returns *! @array *! @elem int width *! *! @elem int height *! @endarray *! *! @seealso *! @[write], @[height], @[baseline] */
b9284c1997-04-09Mirar (Pontus Hagland) 
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) 
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  if (!THIS) Pike_error("font->text_extents: no font loaded\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  maxwidth2=0;
8856291998-05-04Mirar (Pontus Hagland)  if (args==0) {
7863d62005-05-06Martin Nilsson  push_empty_string();
7d60af2004-05-19Martin Nilsson  args=1;
8856291998-05-04Mirar (Pontus Hagland)  } 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;
0af1852000-08-11Henrik Grubbström (Grubba)  ptrdiff_t to_write_len;
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(sp[j-args]) != T_STRING)
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("text_extents",1,"string");
de22f72014-08-25Martin Nilsson 
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;
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);
cc7cf42015-10-14Martin Nilsson  push_int64((INT64)(args * THIS->height * THIS->yspacing_scale));
b9284c1997-04-09Mirar (Pontus Hagland)  f_aggregate(2);
ab6aec1997-02-11Fredrik Hübinette (Hubbe) }
ab5e032001-11-18Martin Nilsson /*! @decl void set_xspacing_scale(float scale) *! @decl 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. */
b9284c1997-04-09Mirar (Pontus Hagland) 
ab6aec1997-02-11Fredrik Hübinette (Hubbe) void font_set_xspacing_scale(INT32 args) {
7d60af2004-05-19Martin Nilsson  FLOAT_TYPE f; if(!THIS) Pike_error("font->set_xspacing_scale(): No font loaded.\n"); get_all_args("set_xspaxing_scale", args, "%f", &f); if(f < 0.0) f=0.1; THIS->xspacing_scale = (double)f;
ab6aec1997-02-11Fredrik Hübinette (Hubbe) } void font_set_yspacing_scale(INT32 args) {
7d60af2004-05-19Martin Nilsson  FLOAT_TYPE f; if(!THIS) Pike_error("font->set_yspacing_scale(): No font loaded.\n"); get_all_args("set_yspacing_scale", args, "%f", &f); if(f <= 0.0) f=0.1; THIS->yspacing_scale = (double)f;
ab6aec1997-02-11Fredrik Hübinette (Hubbe) }
b9284c1997-04-09Mirar (Pontus Hagland) 
ab5e032001-11-18Martin Nilsson /*! @decl int baseline() *! *! Returns font baseline (pixels from top) *! *! @seealso *! @[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); }
ab5e032001-11-18Martin Nilsson /*! @decl void center() *! *! @fixme *! Document this function. */
96f63c2015-11-25Henrik Grubbström (Grubba) void font_set_center(INT32 UNUSED(args))
ab6aec1997-02-11Fredrik Hübinette (Hubbe) { if(THIS) THIS->justification=J_CENTER; }
ab5e032001-11-18Martin Nilsson /*! @decl void right() *! *! @fixme *! Document this function. */
96f63c2015-11-25Henrik Grubbström (Grubba) void font_set_right(INT32 UNUSED(args))
ab6aec1997-02-11Fredrik Hübinette (Hubbe) { if(THIS) THIS->justification=J_RIGHT; }
ab5e032001-11-18Martin Nilsson /*! @decl void left() *! *! @fixme *! Document this function. */
96f63c2015-11-25Henrik Grubbström (Grubba) void font_set_left(INT32 UNUSED(args))
ab6aec1997-02-11Fredrik Hübinette (Hubbe) { 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 */
ab5e032001-11-18Martin Nilsson /*! @endclass */ /*! @endmodule */
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) 
ab5e032001-11-18Martin Nilsson  /* function(void:int) */
07228a1999-06-19Fredrik Hübinette (Hubbe)  ADD_FUNCTION("height",font_height,tFunc(tNone,tInt),0);
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
ab5e032001-11-18Martin Nilsson  /* function(void:int) */
07228a1999-06-19Fredrik Hübinette (Hubbe)  ADD_FUNCTION("baseline",font_baseline,tFunc(tNone,tInt),0);
13670c2015-05-25Martin Nilsson 
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);
13670c2015-05-25Martin Nilsson 
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);
13670c2015-05-25Martin Nilsson 
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);
ab5e032001-11-18Martin Nilsson 
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(void:void) */
448c201999-04-13Mirar (Pontus Hagland)  ADD_FUNCTION("left", font_set_left,tFunc(tVoid,tVoid), 0);
ab5e032001-11-18Martin Nilsson 
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); }
13670c2015-05-25Martin Nilsson void exit_image_font(void)
ab6aec1997-02-11Fredrik Hübinette (Hubbe) { }