38569c1999-12-07Martin Nilsson constant cvs_version="$Id: graphic_text.pike,v 1.194 1999/12/07 13:58:08 nilsson Exp $";
85e8321997-08-31Peter Bortas constant thread_safe=1;
ebf60d1997-03-08Henrik Grubbström (Grubba) 
0595091999-03-12Martin Stjernholm #include <config.h>
d47cbf1996-12-02Per Hedbor #include <module.h>
e5bad21998-02-10Per Hedbor #include <stat.h>
d47cbf1996-12-02Per Hedbor inherit "module"; inherit "roxenlib";
a3dfd41999-11-28Martin Nilsson  // ------------------- Module registration ---------------------
654fca1999-10-04Martin Bähr 
d47cbf1996-12-02Per Hedbor array register_module() {
9374e61999-05-18Per Hedbor  return ({ MODULE_PARSER,
5670551998-06-09Peter Bortas  "Graphics text",
a3dfd41999-11-28Martin Nilsson  "Generates graphical texts.",
5670551998-06-09Peter Bortas  0, 1
a5c21b1999-05-18Peter Bortas  });
0a76aa1998-03-27David Hedbor }
d47cbf1996-12-02Per Hedbor void create() {
39af1a1998-08-26Per Hedbor  defvar("colorparse", 1, "Parse tags for document colors", TYPE_FLAG, "If set, parse the specified tags for document colors.");
a3dfd41999-11-28Martin Nilsson 
c97c421998-08-20Per Hedbor  defvar("colorparsing", ({"body", "td", "layer", "ilayer", "table"}),
a3dfd41999-11-28Martin Nilsson  "Tags to parse for color",
c97c421998-08-20Per Hedbor  TYPE_STRING_LIST, "Which tags should be parsed for document colors? " "This will affect documents without gtext as well as documents " "with it, the parsing time is relative to the number of parsed " "tags in a document. You have to reload this module or restart "
39af1a1998-08-26Per Hedbor  "roxen for changes of this variable to take effect.", 0, lambda(){return !query("colorparse");});
c97c421998-08-20Per Hedbor  defvar("colormode", 1, "Normalize colors in parsed tags", TYPE_FLAG, "If set, replace 'roxen' colors (@c,m,y,k etc) with "
39af1a1998-08-26Per Hedbor  "'netscape' colors (#rrggbb). Setting this to off will lessen the "
c97c421998-08-20Per Hedbor  "performance impact of the 'Tags to parse for color' option quite"
39af1a1998-08-26Per Hedbor  " dramatically. You can try this out with the &lt;gauge&gt; tag.", 0, lambda(){return !query("colorparse");});
a3dfd41999-11-28Martin Nilsson 
9b9f701997-08-12Per Hedbor  defvar("deflen", 300, "Default maximum text-length", TYPE_INT|VAR_MORE,
bfc7071997-01-13Per Hedbor  "The module will, per default, not try to render texts " "longer than this. This is a safeguard for things like " "&lt;gh1&gt;&lt;/gh&gt;, which would otherwise parse the" " whole document. This can be overrided with maxlen=... in the " "tag.");
a3dfd41999-11-28Martin Nilsson  defvar("ext", 0, "Append .fmt (gif, jpeg etc) to all images",
8b6ee51999-07-10Peter Bortas  TYPE_FLAG|VAR_MORE,
9374e61999-05-18Per Hedbor  "Append .gif, .png, .gif etc to all images made by gtext. " "Normally this will only waste bandwidth");
d47cbf1996-12-02Per Hedbor }
a3dfd41999-11-28Martin Nilsson  // ------------------- The actual graphics routines ----------------------
a5c21b1999-05-18Peter Bortas 
0a76aa1998-03-27David Hedbor #define MAX(a,b) ((a)<(b)?(b):(a))
a3dfd41999-11-28Martin Nilsson #define MIN(a,b) ((a)<(b)?(a):(b))
0a76aa1998-03-27David Hedbor 
a5c21b1999-05-18Peter Bortas static private mapping (int:array(array(int))) matrixes = ([]);
0a76aa1998-03-27David Hedbor array (array(int)) make_matrix(int size) {
a5c21b1999-05-18Peter Bortas  if(matrixes[size]) return matrixes[size];
0a76aa1998-03-27David Hedbor  array res; int i; int j;
075da61999-09-05Henrik Grubbström (Grubba)  res = allocate(size, allocate)(size);
0a76aa1998-03-27David Hedbor  for(i=0; i<size; i++) for(j=0; j<size; j++) res[i][j] = (int)MAX((float)size/2.0-sqrt((size/2-i)*(size/2-i) + (size/2-j)*(size/2-j)),0);
a5c21b1999-05-18Peter Bortas  return matrixes[size] = res;
0a76aa1998-03-27David Hedbor }
a3dfd41999-11-28Martin Nilsson object blur(object img, int amnt)
0a76aa1998-03-27David Hedbor { img->setcolor(0,0,0); img = img->autocrop(amnt, 0,0,0,0, 0,0,0);
a3dfd41999-11-28Martin Nilsson  for(int i=0; i<amnt; i++)
a5c21b1999-05-18Peter Bortas  img = img->apply_matrix( make_matrix((int)sqrt(img->ysize()+20)));
0a76aa1998-03-27David Hedbor  return img; }
a3dfd41999-11-28Martin Nilsson object outline(object on, object with,
a5c21b1999-05-18Peter Bortas  array (int) color, int radie, int x, int y)
0a76aa1998-03-27David Hedbor { int steps=10; for(int j=0; j<=steps; j++) on->paste_alpha_color(with, @color, (int)(0.5+x-(sin((float)j/steps*3.145*2)*radie)), (int)(0.5+y-(cos((float)j/steps*3.145*2)*radie))); return on; }
9374e61999-05-18Per Hedbor constant white = ({ 255,255,255 }); constant lgrey = ({ 200,200,200 }); constant grey = ({ 128,128,128 }); constant black = ({ 0,0,0 }); constant wwwb = ({ lgrey,lgrey,grey,black });
0a76aa1998-03-27David Hedbor 
a3dfd41999-11-28Martin Nilsson object bevel(object in, int width, int|void invert)
0a76aa1998-03-27David Hedbor { int h=in->ysize(); int w=in->xsize();
0ee5ab1999-09-05Per Hedbor  object corner = Image.Image(width+1,width+1); object corner2 = Image.Image(width+1,width+1); object pix = Image.Image(1,1);
0a76aa1998-03-27David Hedbor  for(int i=-1; i<=width; i++) { corner->line(i,width-i,i,-1, @white); corner2->setpixel(width-i, width-i, @white); in->paste_alpha(pix, 185, w - width + i+1, h - width + i+1); } if(!invert) {
0ee5ab1999-09-05Per Hedbor  in->paste_alpha(Image.Image(width,h-width*2,@white), 160, 0, width); in->paste_alpha(Image.Image(width,h-width*2,@black), 128, in->xsize()-width, width); in->paste_alpha(Image.Image(w-width,width,@white), 160, 0, 0); in->paste_alpha(Image.Image(w-width,width,@black), 128, width, in->ysize()-width);
0a76aa1998-03-27David Hedbor  } else { corner=corner->invert(); corner2=corner2->invert();
0ee5ab1999-09-05Per Hedbor  in->paste_alpha(Image.Image(width,h-width*2,@black), 160, 0, width); in->paste_alpha(Image.Image(width,h-width*2,@white), 128, in->xsize()-width, width); in->paste_alpha(Image.Image(w-width,width,@black), 160, 0, 0); in->paste_alpha(Image.Image(w-width,width,@white), 128, width, in->ysize()-width);
0a76aa1998-03-27David Hedbor  } in->paste_mask(corner, corner->color(95,95,95), in->xsize()-width,-1); in->paste_mask(corner, corner->invert()->color(128,128,128), in->xsize()-width,-1); in->paste_mask(corner, corner->color(95,95,95), -1, in->ysize()-width); in->paste_mask(corner, corner->invert()->color(128,128,128), -1, in->ysize()-width); corner=0; in->paste_mask(corner2, corner2->color(70,70,70), -1, -1); corner2 = pix = 0; return in; }
a3dfd41999-11-28Martin Nilsson object make_text_image(mapping args, object font, string text, RequestID id)
0a76aa1998-03-27David Hedbor {
0ee5ab1999-09-05Per Hedbor  if( args->encoding ) text = roxen.decode_charset(args->encoding,text); object text_alpha=font->write(@(text/"\n"));
0a76aa1998-03-27David Hedbor  int xoffset=0, yoffset=0; if(!text_alpha->xsize() || !text_alpha->ysize())
0ee5ab1999-09-05Per Hedbor  text_alpha = Image.Image(10,10, 0,0,0);
0a76aa1998-03-27David Hedbor  if(int op=((((int)args->opaque)*255)/100)) // Transparent text... text_alpha=text_alpha->color(op,op,op); int txsize=text_alpha->xsize();
a3dfd41999-11-28Martin Nilsson  int tysize=text_alpha->ysize(); // Size of the text, in pixels.
0a76aa1998-03-27David Hedbor  int xsize=txsize; // image size, in pixels int ysize=tysize; if(args->bevel) { xoffset += (int)args->bevel; yoffset += (int)args->bevel; xsize += ((int)args->bevel)*2; ysize += ((int)args->bevel)*2; } if(args->spacing) { xoffset += (int)args->spacing; yoffset += (int)args->spacing; xsize += ((int)args->spacing)*2; ysize += ((int)args->spacing)*2; } if(args->yspacing) { yoffset += (int)args->yspacing; ysize += ((int)args->yspacing)*2; } if(args->shadow) { xsize+=((int)(args->shadow/",")[-1])+2; ysize+=((int)(args->shadow/",")[-1])+2; } if(args->bshadow) { xsize+=(int)args->bshadow+3; ysize+=(int)args->bshadow+3; } if(args->fadein) { xsize+=6; ysize+=6; xoffset+=3; yoffset+=3; } if(args->move) { int dx,dy; sscanf(args->move, "%d,%d", dx, dy); xoffset += dx; yoffset += dy; } if(args->ghost) { int howmuch=(int)args->ghost; xsize+=howmuch*2+10; xoffset += 3; ysize+=howmuch*2+10; }
a5c21b1999-05-18Peter Bortas  if(args->xspacing) { xoffset += (int)args->xspacing; xsize += ((int)args->xspacing)*2; }
0a76aa1998-03-27David Hedbor  if(args->border) { xoffset += (int)args->border; yoffset += (int)args->border; xsize += ((int)args->border)*2; ysize += ((int)args->border)*2; }
b89ccb1999-11-28Martin Nilsson  array (int) bgcolor = parse_color(args->bgcolor); array (int) fgcolor = parse_color(args->fgcolor);
0a76aa1998-03-27David Hedbor  object background,foreground;
a5c21b1999-05-18Peter Bortas  if(args->texture) { object t = roxen.load_image(args->texture,id); if( t )
0a76aa1998-03-27David Hedbor  {
a5c21b1999-05-18Peter Bortas  foreground = t; if(args->tile)
0a76aa1998-03-27David Hedbor  {
0ee5ab1999-09-05Per Hedbor  object b2 = Image.Image(xsize,ysize);
a5c21b1999-05-18Peter Bortas  for(int x=0; x<xsize; x+=foreground->xsize()) for(int y=0; y<ysize; y+=foreground->ysize())
0a76aa1998-03-27David Hedbor  b2->paste(foreground, x, y);
a5c21b1999-05-18Peter Bortas  foreground = b2; } else if(args->mirrortile) {
0ee5ab1999-09-05Per Hedbor  object b2 = Image.Image(xsize,ysize); object b3 = Image.Image(foreground->xsize()*2,foreground->ysize()*2);
a5c21b1999-05-18Peter Bortas  b3->paste(foreground,0,0); b3->paste(foreground->mirrorx(),foreground->xsize(),0); b3->paste(foreground->mirrory(),0,foreground->ysize()); b3->paste(foreground->mirrorx()->mirrory(),foreground->xsize(), foreground->ysize()); foreground = b3; for(int x=0; x<xsize; x+=foreground->xsize()) { for(int y=0; y<ysize; y+=foreground->ysize()) if(y%2) b2->paste(foreground->mirrory(), x, y); else b2->paste(foreground, x, y); foreground = foreground->mirrorx(); } foreground = b2;
0a76aa1998-03-27David Hedbor  }
a5c21b1999-05-18Peter Bortas  } else werror("Failed to load image for "+args->texture+"\n");
0a76aa1998-03-27David Hedbor  }
7b15a61998-08-10Johan Schön  int background_is_color; if(args->background &&
a22f6f1999-05-12Per Hedbor  ((background = roxen.load_image(args->background, id)) ||
a5c21b1999-05-18Peter Bortas  (sizeof(args->background)>1 &&
0ee5ab1999-09-05Per Hedbor  (background=Image.Image(xsize,ysize, @(parse_color(args->background[1..]))))
7b15a61998-08-10Johan Schön  && (background_is_color=1)))) { object alpha;
a22f6f1999-05-12Per Hedbor  if(args->alpha && (alpha = roxen.load_image(args->alpha,id)) && background_is_color)
7b15a61998-08-10Johan Schön  { xsize=MAX(xsize,alpha->xsize()); ysize=MAX(ysize,alpha->ysize());
a5c21b1999-05-18Peter Bortas  if((float)args->scale)
17bb761998-08-28Marcus Wellhardh  alpha=alpha->scale(1/(float)args->scale);
0ee5ab1999-09-05Per Hedbor  background=Image.Image(xsize,ysize, @(parse_color(args->background[1..])));
7b15a61998-08-10Johan Schön  }
a3dfd41999-11-28Martin Nilsson 
a5c21b1999-05-18Peter Bortas  if((float)args->scale >= 0.1 && !alpha)
0a76aa1998-03-27David Hedbor  background = background->scale(1.0/(float)args->scale);
a3dfd41999-11-28Martin Nilsson 
0a76aa1998-03-27David Hedbor  if(args->tile) {
0ee5ab1999-09-05Per Hedbor  object b2 = Image.Image(xsize,ysize);
0a76aa1998-03-27David Hedbor  for(int x=0; x<xsize; x+=background->xsize()) for(int y=0; y<ysize; y+=background->ysize()) b2->paste(background, x, y); background = b2; } else if(args->mirrortile) {
0ee5ab1999-09-05Per Hedbor  object b2 = Image.Image(xsize,ysize); object b3 = Image.Image(background->xsize()*2,background->ysize()*2);
0a76aa1998-03-27David Hedbor  b3->paste(background,0,0); b3->paste(background->mirrorx(),background->xsize(),0); b3->paste(background->mirrory(),0,background->ysize()); b3->paste(background->mirrorx()->mirrory(),background->xsize(), background->ysize()); background = b3; for(int x=0; x<xsize; x+=background->xsize()) { for(int y=0; y<ysize; y+=background->ysize()) if(y%2) b2->paste(background->mirrory(), x, y); else b2->paste(background, x, y); background = background->mirrorx(); } background = b2; }
7b15a61998-08-10Johan Schön  xsize = MAX(xsize,background->xsize()); ysize = MAX(ysize,background->ysize());
a3dfd41999-11-28Martin Nilsson 
7b15a61998-08-10Johan Schön  if(alpha)
a5c21b1999-05-18Peter Bortas  background->paste_alpha_color(alpha->invert(),@bgcolor);
0a76aa1998-03-27David Hedbor  switch(lower_case(args->talign||"left")) { case "center": xoffset = (xsize/2 - txsize/2); yoffset = (ysize/2 - tysize/2); break; case "right": xoffset = (xsize - txsize); break; case "left": } } else
0ee5ab1999-09-05Per Hedbor  background = Image.Image(xsize, ysize, @bgcolor);
0a76aa1998-03-27David Hedbor  if(args->border) { int b = (int)args->border; background->setcolor(@parse_color((args->border/",")[-1])); for(--b;b>=0;b--) { // upper left -- upper right background->line(b,b, xsize-b-1, b); // lower left -- lower right background->line(b,ysize-b-1, xsize-b-1, ysize-b-1); // upper left -- lower left background->line(b,b, b, ysize-b-1); // upper right -- lower right background->line(xsize-b-1,b, xsize-b-1, ysize-b-1); } }
a3dfd41999-11-28Martin Nilsson 
0a76aa1998-03-27David Hedbor  background->setcolor(@bgcolor);
5863ae1999-05-25Per Hedbor  int xs=background->xsize(), ys=background->ysize(); if( args->rescale ) { xs = txsize; ys = tysize; } if(args->size) { xs=(int)args->size; ys=(int)(args->size/",")[-1]; }
a3dfd41999-11-28Martin Nilsson  if(args->xsize) xs=(int)args->xsize;
5863ae1999-05-25Per Hedbor  if(args->ysize) ys=(int)args->ysize;
9ee0041999-05-31Per Hedbor  if( xs != background->xsize() ||
5863ae1999-05-25Per Hedbor  ys != background->ysize() )
0a76aa1998-03-27David Hedbor  {
0fa8b21998-07-04Peter Bortas  if(!args->rescale) background = background->copy(0,0,xs-1,ys-1); else background = background->scale(xs, ys);
0a76aa1998-03-27David Hedbor  } if(args->turbulence) { array (float|array(int)) arg=({}); foreach((args->turbulence/";"), string s) { array q= s/","; if(sizeof(q)<2) args+=({ ((float)s)||0.2, ({ 255,255,255 }) }); arg+=({ ((float)q[0])||0.2, parse_color(q[1]) }); } background=background->turbulence(arg); } if(args->bevel) background = bevel(background,(int)args->bevel,!!args->pressed); if(args->textbox) // Draw a text-box on the background. { int alpha,border; string bg;
53a5ca1999-05-25Per Hedbor  alpha = (int)args->textbox; sscanf(args->textbox, "%*[^,],%s", bg);
0a76aa1998-03-27David Hedbor  sscanf(bg,"%s,%d", bg,border);
0ee5ab1999-09-05Per Hedbor  background->paste_alpha(Image.Image(txsize+border*2,tysize+border*2,
0a76aa1998-03-27David Hedbor  @parse_color(bg)), 255-(alpha*255/100),xoffset-border,yoffset-border); } if(args->ghost) { // Francesco..
0eb6a61999-01-25Henrik Grubbström (Grubba)  array(string) a = (args->ghost/","); if (sizeof(a) < 2) { // Bad argument. } else { int sdist = (int)(a[0]); int bl=(int)(a[1]); array(int)clr=parse_color(a[-1]); int j; object ta = text_alpha->copy(); for (j=0;j<bl;j++) ta=ta->apply_matrix(({ ({6,7,7,7,6}),({7,8,8,8,7}),({7,8,8,8,7}),({7,8,8,8,7}),({6,7,7,7,6}) })); background->paste_alpha_color(ta,@clr,xoffset+sdist,yoffset+sdist); fgcolor=bgcolor; }
0a76aa1998-03-27David Hedbor  } if(args->shadow) { int sd = ((int)args->shadow+10)*2; int sdist = ((int)(args->shadow/",")[-1])+2; object ta = text_alpha->copy(); ta = ta->color(256-sd,256-sd,256-sd); array sc = parse_color(args->scolor||"black"); background->paste_alpha_color(ta,sc[0],sc[1],sc[2], xoffset+sdist,yoffset+sdist); } if(args->bshadow) { int sdist = (int)(args->bshadow)+1; int xs,ys; xs = text_alpha->xsize()+sdist*2+4; ys = text_alpha->ysize()+sdist*2+4;
0ee5ab1999-09-05Per Hedbor  object ta = Image.Image(xs+sdist*2,ys+sdist*2);
0a76aa1998-03-27David Hedbor  array sc = parse_color(args->scolor||"black"); ta->paste_alpha_color(text_alpha,255,255,255,sdist,sdist);
a5c21b1999-05-18Peter Bortas  ta = blur(ta, MIN((sdist/2),1))->color(256,256,256);
0a76aa1998-03-27David Hedbor  background->paste_alpha_color(ta,sc[0],sc[1],sc[2], xoffset+sdist,yoffset+sdist); } if(args->glow) { int amnt = (int)(args->glow/",")[-1]+2; array (int) blurc = parse_color((args->glow/",")[0]); background->paste_alpha_color(blur(text_alpha, amnt),@blurc, xoffset-amnt, yoffset-amnt); }
a3dfd41999-11-28Martin Nilsson 
0a76aa1998-03-27David Hedbor  if(args->chisel) foreground=text_alpha->apply_matrix(({ ({8,1,0}), ({1,0,-1}), ({0,-1,-8}) }), 128,128,128, 15 ) ->color(@fgcolor);
0ee5ab1999-09-05Per Hedbor  if(!foreground) foreground=Image.Image(txsize, tysize, @fgcolor);
0a76aa1998-03-27David Hedbor  if(args->textscale) { string c1="black",c2="black",c3="black",c4="black"; sscanf(args->textscale, "%s,%s,%s,%s", c1, c2, c3, c4); foreground->tuned_box(0,0, txsize,tysize, ({parse_color(c1),parse_color(c2),parse_color(c3), parse_color(c4)})); } if(args->outline) outline(background, text_alpha, parse_color((args->outline/",")[0]), ((int)(args->outline/",")[-1])+1, xoffset, yoffset);
0fa8b21998-07-04Peter Bortas  if(args->textbelow) { array color = parse_color(args->textbelow);
a3dfd41999-11-28Martin Nilsson 
0fa8b21998-07-04Peter Bortas  background->setcolor( @color ); int oby = background->ysize();
a3dfd41999-11-28Martin Nilsson  background = background->copy(0,0,
0fa8b21998-07-04Peter Bortas  max(background->xsize()-1, foreground->xsize()-1), background->ysize()-1 +foreground->ysize()); background->paste_mask( foreground, text_alpha, (background->xsize()-foreground->xsize())/2, oby ); } else background->paste_mask(foreground, text_alpha, xoffset, yoffset);
0a76aa1998-03-27David Hedbor  foreground = text_alpha = 0; if(args->rotate) { string c; if(sscanf(args->rotate, "%*d,%s", c)==2) background->setcolor(@parse_color(c)); else background->setcolor(@bgcolor); background = background->rotate((float)args->rotate); } if(args->crop) background = background->autocrop(); return background; }
a3dfd41999-11-28Martin Nilsson  // -------------------- Image cache functions --------------------
9374e61999-05-18Per Hedbor roxen.ImageCache image_cache;
e5bad21998-02-10Per Hedbor 
38569c1999-12-07Martin Nilsson void start()
2468b21997-07-06Henrik Grubbström (Grubba) {
9374e61999-05-18Per Hedbor  image_cache = roxen.ImageCache( "gtext", draw_callback );
2468b21997-07-06Henrik Grubbström (Grubba) }
c3655b1997-01-27Per Hedbor 
b1ab8d1997-12-23Per Hedbor constant nbsp = iso88591["&nbsp;"];
db46c81999-06-10Jonas Wallden constant replace_from = indices( iso88591 )+ ({"&ss;","&lt;","&gt;","&amp;",});
a3dfd41999-11-28Martin Nilsson constant replace_to = values( iso88591 ) + ({ nbsp, "<", ">", "&", });
b1ab8d1997-12-23Per Hedbor  #define simplify_text( from ) replace(from,replace_from,replace_to)
06583f1997-09-03Per Hedbor 
a3dfd41999-11-28Martin Nilsson mixed draw_callback(mapping args, string text, RequestID id)
20ca2b1998-01-26Per Hedbor {
38569c1999-12-07Martin Nilsson  object|array data; Image.Image img;
9374e61999-05-18Per Hedbor  int elapsed;
6a9b9d1999-06-25Per Hedbor  if( objectp( text ) ) { if( !args->text ) error("Failed miserably to find a text to draw. That's not"
8b6ee51999-07-10Peter Bortas  " good.\n");
6a9b9d1999-06-25Per Hedbor  id = (object)text; text = args->text; }
9374e61999-05-18Per Hedbor  if(!args->verbatim) // typographically correct...
ba73a21996-12-10Per Hedbor  {
9374e61999-05-18Per Hedbor  text = replace(text, nbsp, " "); text = simplify_text( text ); string res="",nspace="",cspace=""; foreach(text/"\n", string line)
a5c21b1999-05-18Peter Bortas  {
38569c1999-12-07Martin Nilsson  cspace=""; nspace="";
9374e61999-05-18Per Hedbor  foreach(line/" ", string word)
e8c29c1997-09-12Johan Schön  {
9374e61999-05-18Per Hedbor  string nonum; if(strlen(word) && (nonum = replace(word, ({"1","2","3","4","5","6","7","8","9","0","."}), ({"","","","","","","","","","",""}))) == "") { cspace=nbsp+nbsp; if((strlen(word)-strlen(nonum)<strlen(word)/2) &&
38569c1999-12-07Martin Nilsson  (upper_case(word) == word))
9374e61999-05-18Per Hedbor  word=((word/"")*nbsp); }
38569c1999-12-07Martin Nilsson  else if(cspace!="") cspace=" ";
9374e61999-05-18Per Hedbor  res+=(nspace==cspace?nspace:" ")+word;
38569c1999-12-07Martin Nilsson  if(cspace!="") nspace=cspace; else nspace=" ";
1cd5eb1998-03-20Per Hedbor  }
9374e61999-05-18Per Hedbor  res+="\n";
1cd5eb1998-03-20Per Hedbor  }
9374e61999-05-18Per Hedbor  text=replace(res[..strlen(res)-2], ({"!","?",": "}),({ nbsp+"!",nbsp+"?",nbsp+": "}));
a3dfd41999-11-28Martin Nilsson  text=replace(replace(replace(text,({". ",". "+nbsp}),
9374e61999-05-18Per Hedbor  ({"\000","\001"})),".","."+nbsp+nbsp), ({"\000","\001"}),({". ","."+nbsp})); }
e8c29c1997-09-12Johan Schön 
9374e61999-05-18Per Hedbor  if( args->afont ) data = resolve_font(args->afont+" "+(args->font_size||32)); else
a5c21b1999-05-18Peter Bortas  {
9374e61999-05-18Per Hedbor  if(!args->nfont) args->nfont = args->font;
38569c1999-12-07Martin Nilsson  int bold=0, italic=0;
9374e61999-05-18Per Hedbor  if(args->bold) bold=1; if(args->light) bold=-1; if(args->black) bold=2; if(args->italic) italic=1; data = get_font(args->nfont||"default", (int)args->font_size||32,bold,italic, lower_case(args->talign||"left"), (float)(int)args->xpad, (float)(int)args->ypad);
a5c21b1999-05-18Peter Bortas  }
974b2a1997-10-02Peter Bortas 
a3dfd41999-11-28Martin Nilsson  if (!data)
9374e61999-05-18Per Hedbor  error("gtext: No font!\n");
1a67581997-09-26Henrik Grubbström (Grubba) 
9374e61999-05-18Per Hedbor  // Fonts and such are now initialized. img = make_text_image(args,data,text,id);
9558e31998-07-04Per Hedbor 
9374e61999-05-18Per Hedbor  // Now we have the image in 'img', or nothing.
a5c21b1999-05-18Peter Bortas 
9374e61999-05-18Per Hedbor  if( !args->scroll && !args->fadein ) { if(!args->notrans)
a5c21b1999-05-18Peter Bortas  {
b89ccb1999-11-28Martin Nilsson  array (int) bgcolor = parse_color(args->bgcolor);
9374e61999-05-18Per Hedbor  object alpha; alpha = img->distancesq( @bgcolor ); alpha->gamma( 8 ); return ([ "img":img, "alpha":alpha ]);
a5c21b1999-05-18Peter Bortas  }
9374e61999-05-18Per Hedbor  return img; }
a5c21b1999-05-18Peter Bortas 
9374e61999-05-18Per Hedbor  if(args->fadein)
a5c21b1999-05-18Peter Bortas  {
9374e61999-05-18Per Hedbor  int amount=2, steps=10, delay=10, initialdelay=0, ox; string res = img->gif_begin(); sscanf(args->fadein,"%d,%d,%d,%d", amount, steps, delay, initialdelay); if(initialdelay)
a5c21b1999-05-18Peter Bortas  {
b89ccb1999-11-28Martin Nilsson  object foo=Image.Image(img->xsize(),img->ysize(),@parse_color(args->bgcolor));
9374e61999-05-18Per Hedbor  res += foo->gif_add(0,0,initialdelay);
a5c21b1999-05-18Peter Bortas  }
9374e61999-05-18Per Hedbor  for(int i = 0; i<(steps-1); i++) { object foo=img->clone(); foo = foo->apply_matrix(make_matrix(( (int)((steps-i)*amount)))); res += foo->gif_add(0,0,delay);
a5c21b1999-05-18Peter Bortas  }
9374e61999-05-18Per Hedbor  res+= img->gif_add(0,0,delay); res += img->gif_end(); data = ({ res, ({ img->xsize(), img->ysize() }) });
a5c21b1999-05-18Peter Bortas  }
a3dfd41999-11-28Martin Nilsson  else
a5c21b1999-05-18Peter Bortas  {
9374e61999-05-18Per Hedbor  int len=100, steps=30, delay=5, ox; string res = img->gif_begin() + img->gif_netscape_loop(); sscanf(args->scroll, "%d,%d,%d", len, steps, delay); img=img->copy(0,0,(ox=img->xsize())+len-1,img->ysize()-1); img->paste(img, ox, 0); for(int i = 0; i<steps; i++) { int xp = i*ox/steps; res += img->copy(xp, 0, xp+len, img->ysize(),
b89ccb1999-11-28Martin Nilsson  @parse_color(args->bgcolor))->gif_add(0,0,delay);
9374e61999-05-18Per Hedbor  } res += img->gif_end(); data = ({ res, ({ len, img->ysize() }) });
a5c21b1999-05-18Peter Bortas  }
a3dfd41999-11-28Martin Nilsson  return ([ "data":data[0],
df8c031999-05-25Per Hedbor  "meta":
9374e61999-05-18Per Hedbor  ([ "xsize":data[1][0], "ysize":data[1][1],
a3dfd41999-11-28Martin Nilsson  "type":(args->format?id->conf->type_from_filename("x."+args->format):"image/gif"),
9374e61999-05-18Per Hedbor  ]) ]);
68e0301997-08-19Per Hedbor }
9374e61999-05-18Per Hedbor mapping find_internal(string f, object rid)
a5c21b1999-05-18Peter Bortas {
a3dfd41999-11-28Martin Nilsson  if( strlen(f)>4 && query("ext") && f[-4]=='.') // Remove .ext
9374e61999-05-18Per Hedbor  f = f[..strlen(f)-5];
0ee5ab1999-09-05Per Hedbor  if( strlen(f) && f[0]=='$' )
8b6ee51999-07-10Peter Bortas  { array id_text = f/"/"; if( sizeof(id_text)==2 ) { // It's a gtext-id
0ee5ab1999-09-05Per Hedbor  string second_key = roxen->argcache->store( (["":id_text[1]]) );
8b6ee51999-07-10Peter Bortas  return image_cache->http_file_answer( id_text[0][1..] +"$"+ second_key, rid ); } }
9374e61999-05-18Per Hedbor  return image_cache->http_file_answer( f, rid );
a5c21b1999-05-18Peter Bortas }
d47cbf1996-12-02Per Hedbor 
a3dfd41999-11-28Martin Nilsson // -------------- helpfunctions to gtext tags and containers -----------------
b89ccb1999-11-28Martin Nilsson constant filearg=({"background","texture","alpha","magic-texture","magic-background","magic-alpha"});
a3dfd41999-11-28Martin Nilsson constant textarg=({"afont", "alpha", "bevel",
b89ccb1999-11-28Martin Nilsson  "bgcolor",
a3dfd41999-11-28Martin Nilsson  "black", "bold", "bshadow", "chisel", "crop", "encoding", "fadein",
b89ccb1999-11-28Martin Nilsson  "fgcolor",
a3dfd41999-11-28Martin Nilsson  "fs", "font", "font_size", "format", "ghost", "glow", "italic", "light", "mirrortile",
c3aacd1999-12-06Peter Bortas  "move",
a3dfd41999-11-28Martin Nilsson  "narrow", "nfont", "notrans", "opaque", "outline", "pressed", "quant", "rescale", "rotate", "scale", "scolor", "scroll", "shadow", "size", "spacing", "talign", "tile", "textbox", "textbelow", "textscale", "turbulence", "verbatim", "xpad", "xsize", "xspacing", "ypad", "ysize", "yspacing" }); mapping mk_gtext_arg(mapping arg, RequestID id) { mapping defines=id->misc->defines; mapping p=([]); //Picture rendering arguments. foreach(filearg, string tmp) if(arg[tmp]) { p[tmp]=fix_relative(arg[tmp],id); m_delete(arg,tmp); }
d47cbf1996-12-02Per Hedbor 
b89ccb1999-11-28Martin Nilsson  if(arg->border && search(arg->border,",")) { p->border=arg->border; m_delete(arg,"border"); }
a3dfd41999-11-28Martin Nilsson  foreach(textarg, string tmp) if(arg[tmp]) { p[tmp]=arg[tmp],id; m_delete(arg,tmp); }
d47cbf1996-12-02Per Hedbor 
b89ccb1999-11-28Martin Nilsson  if(defines->fgcolor && !p->fgcolor) p->fgcolor=defines->fgcolor; if(defines->bgcolor && !p->bgcolor) p->bgcolor=defines->bgcolor;
a3dfd41999-11-28Martin Nilsson  if(defines->nfont && !p->nfont) p->nfont=defines->nfont; if(defines->afont && !p->afont) p->afont=defines->afont; if(defines->font && !p->font) p->font=defines->font; if(defines->bold && !p->bold) p->bold=defines->bold; if(defines->italic && !p->italic) p->italic=defines->italic; if(defines->black && !p->black) p->black=defines->black; if(defines->narrow && !p->narrow) p->narrow=defines->narrow; return p;
d47cbf1996-12-02Per Hedbor }
a3dfd41999-11-28Martin Nilsson string fix_text(string c, mapping m, RequestID id) {
b91fd51996-12-10Per Hedbor 
a3dfd41999-11-28Martin Nilsson  if(m->nowhitespace)
b91fd51996-12-10Per Hedbor  {
a3dfd41999-11-28Martin Nilsson  sscanf(c,"%*[ \n\r\t]%s",c); sscanf(reverse(c),"%*[ \n\r\t]%s",c); c=reverse(c); m_delete(m, "nowhitespace"); } if(!m->noparse && !m->preparse) c = parse_rxml(c, id); else { m_delete(m, "noparse"); m_delete(m, "preparse");
b91fd51996-12-10Per Hedbor  }
a3dfd41999-11-28Martin Nilsson  c = c[..(((int)m->maxlen||QUERY(deflen))-1)]; m_delete(m, "maxlen"); return c;
b91fd51996-12-10Per Hedbor }
a3dfd41999-11-28Martin Nilsson  // ----------------- gtext tags and containers ------------------- string tag_gtext_url(string t, mapping arg, string c, RequestID id) { c=fix_text(c,arg,id); mapping p=mk_gtext_arg(arg,id);
b89ccb1999-11-28Martin Nilsson  if(arg->href && !p->fgcolor) p->fgcolor=id->misc->defines->link||"#0000ff";
a3dfd41999-11-28Martin Nilsson  string ext=""; if(query("ext")) ext="."+(p->format || "gif"); if(!arg->short) return query_internal_location()+image_cache->store( ({p,c}), id )+ext;
07969c1997-02-25Per Hedbor  else
a3dfd41999-11-28Martin Nilsson  return "+"+image_cache->store( ({p,c}), id )+ext;
8b6ee51999-07-10Peter Bortas }
a3dfd41999-11-28Martin Nilsson string tag_gtext_id(string t, mapping arg, RequestID id) { mapping p=mk_gtext_arg(arg,id);
b89ccb1999-11-28Martin Nilsson  if(arg->href && !p->fgcolor) p->fgcolor=id->misc->defines->link||"#0000ff";
a3dfd41999-11-28Martin Nilsson  if(!arg->short) return query_internal_location()+"$"+image_cache->store(p, id)+"/";
8b6ee51999-07-10Peter Bortas  else
a3dfd41999-11-28Martin Nilsson  return "+"+image_cache->store(p, id )+"/";
07969c1997-02-25Per Hedbor }
a3dfd41999-11-28Martin Nilsson string tag_graphicstext(string t, mapping arg, string c, RequestID id)
62d8c41997-10-16Per Hedbor {
a3dfd41999-11-28Martin Nilsson  mapping defines=id->misc->defines; if((c-" ")=="")
0d19e01998-07-06Peter Bortas  return "";
033c7e1997-02-27Per Hedbor 
a3dfd41999-11-28Martin Nilsson  c=fix_text(c,arg,id); mapping p=mk_gtext_arg(arg,id);
d47cbf1996-12-02Per Hedbor 
a3dfd41999-11-28Martin Nilsson  string ext=""; if(query("ext")) ext="."+(p->format || "gif");
bfc7071997-01-13Per Hedbor 
a3dfd41999-11-28Martin Nilsson  string lp="%s", url="", ea="";
38dca81996-12-10Per Hedbor  int input; if(arg->submit) { input=1; m_delete(arg,"submit"); }
bfc7071997-01-13Per Hedbor 
a3dfd41999-11-28Martin Nilsson  if(!arg->noxml) { arg["/"]="/"; m_delete(arg, "noxml"); } if(!arg->border) arg->border=arg->border||"0";
bfc7071997-01-13Per Hedbor 
d47cbf1996-12-02Per Hedbor  if(arg->href) { url = arg->href;
b89ccb1999-11-28Martin Nilsson  lp = replace(make_tag("a",arg),"%","%%")+"%s</a>"; if(!p->fgcolor) p->fgcolor=defines->link||"#0000ff";
0943711997-02-25Per Hedbor  m_delete(arg, "href");
d47cbf1996-12-02Per Hedbor  } if(arg->split) {
a3dfd41999-11-28Martin Nilsson  string res="",split=arg->split; if(lower_case(split)=="split") split=" ";
d47cbf1996-12-02Per Hedbor  m_delete(arg,"split");
a3dfd41999-11-28Martin Nilsson  c=replace(c, "\n", " "); int setalt=!arg->alt; foreach(c/split-({""}), string word)
d47cbf1996-12-02Per Hedbor  {
a3dfd41999-11-28Martin Nilsson  string fn = image_cache->store( ({ p, word }),id );
9374e61999-05-18Per Hedbor  mapping size = image_cache->metadata( fn, id, 1 );
a3dfd41999-11-28Martin Nilsson  if(setalt) arg->alt=word; arg->src=query_internal_location()+fn+ext;
9374e61999-05-18Per Hedbor  if( size ) {
a3dfd41999-11-28Martin Nilsson  arg->width = (string)size->xsize; arg->height = (string)size->ysize;
1bd5c91997-09-26Henrik Grubbström (Grubba)  }
a3dfd41999-11-28Martin Nilsson  res+=make_tag( "img", arg )+" ";
d47cbf1996-12-02Per Hedbor  }
a3dfd41999-11-28Martin Nilsson  return sprintf(lp,res);
d47cbf1996-12-02Per Hedbor  }
a3dfd41999-11-28Martin Nilsson  string num = image_cache->store( ({ p, c }), id );
6a9b9d1999-06-25Per Hedbor  mapping size = image_cache->metadata( num, id, 1 );
a3dfd41999-11-28Martin Nilsson  if(!arg->alt) arg->alt=replace(c,"\"","'");
f1be801998-02-22Per Hedbor 
a3dfd41999-11-28Martin Nilsson  arg->src=query_internal_location()+num+ext; if(size) { arg->width=size->xsize; arg->height=size->ysize; } if(arg->magic)
d47cbf1996-12-02Per Hedbor  {
a3dfd41999-11-28Martin Nilsson  string magic=replace(arg->magic,"'","`"); m_delete(arg,"magic");
b89ccb1999-11-28Martin Nilsson  if(!arg->fgcolor) p->fgcolor=defines->alink||"#ff0000";
a3dfd41999-11-28Martin Nilsson  if(p->bevel) p->pressed=1; foreach(glob("magic-*", indices(arg)), string q)
20ca2b1998-01-26Per Hedbor  {
a3dfd41999-11-28Martin Nilsson  p[q[6..]]=arg[q];
20ca2b1998-01-26Per Hedbor  m_delete(arg, q); }
a3dfd41999-11-28Martin Nilsson  string num2 = image_cache->store( ({ p, c }),id );
6a9b9d1999-06-25Per Hedbor  size = image_cache->metadata( num2, id );
a3dfd41999-11-28Martin Nilsson  if(size) { arg->width=MAX(arg->xsize,size->xsize); arg->height=MAX(arg->ysize,size->ysize); } if(!id->supports->images) return sprintf(lp,arg->alt);
0943711997-02-25Per Hedbor 
a3dfd41999-11-28Martin Nilsson  string sn="i"+defines->mi++; if(!id->supports->netscape_javascript) { return (!input)? ("<a "+ea+"href=\""+url+"\">"+make_tag("img",arg+(["name":sn]))+"</a>"): make_tag("input",arg+(["type":"image"])); } arg->name=sn; string res="<script>\n"; if(!defines->magic_java) res += "function i(ri,hi,txt)\n" "{\n" " document.images[ri].src = hi.src;\n" " setTimeout(\"top.window.status = '\"+txt+\"'\", 100);\n" "}\n";
d47cbf1996-12-02Per Hedbor  defines->magic_java="yes";
a3dfd41999-11-28Martin Nilsson  return res+ " "+sn+"l = new Image("+arg->width+", "+arg->height+");"+sn+"l.src = \""+arg->src+"\";\n" " "+sn+"h = new Image("+arg->width+", "+arg->height+");"+sn+"h.src = \""+query_internal_location()+num2+ext+"\";\n" "</script>"+ "<a "+ea+"href=\""+url+"\" "+ (input?"onClick='document.forms[0].submit();' ":"") +"onMouseover=\"i('"+sn+"',"+sn+"h,'"+(magic=="magic"?url:magic)+"'); return true;\"\n" "onMouseout=\"top.window.status='';document.images['"+sn+"'].src = "+sn+"l.src;\">" +make_tag("img",arg)+"</a>";
d47cbf1996-12-02Per Hedbor  }
a3dfd41999-11-28Martin Nilsson 
ca0f081997-02-22Per Hedbor  if(input)
a3dfd41999-11-28Martin Nilsson  return make_tag("input",arg+(["type":"image"])); return sprintf(lp,make_tag("img",arg));
d47cbf1996-12-02Per Hedbor }
a3dfd41999-11-28Martin Nilsson array(string) tag_gh(string t, mapping m, string c, RequestID id) { int i; if(sscanf(t, "%s%d", t, i)==2 && i>1) m->scale = (string)(1.0 / ((float)i*0.6)); if(!m->valign) m->valign="top"; return ({ "<p>"+tag_graphicstext("",m,c,id)+"<br>" }); } array(string) tag_anfang(string t, mapping m, string c, RequestID id) { if(!m->align) m->align="left"; return ({ "<br clear=\"left\">"+tag_graphicstext("",m,c[0..0],id)+c[1..] }); } // ------------ Wiretap code to find HTML-colours ---------------------
bfc7071997-01-13Per Hedbor inline string ns_color(array (int) col) { if(!arrayp(col)||sizeof(col)!=3) return "#000000"; return sprintf("#%02x%02x%02x", col[0],col[1],col[2]); }
38569c1999-12-07Martin Nilsson int|array (string) tag_body(string t, mapping args, RequestID id, object file,
fc57521998-03-06Per Hedbor  mapping defines)
d47cbf1996-12-02Per Hedbor {
38569c1999-12-07Martin Nilsson  int changed=0; int cols=(args->bgcolor||args->text||args->link||args->alink||args->vlink);
bfc7071997-01-13Per Hedbor 
38569c1999-12-07Martin Nilsson #define FIX(Y,Z,X) do{if(!args->Y || args->Y==""){defines->X=Z;if(cols){args->Y=Z;changed=1;}}else{defines->X=args->Y;if(QUERY(colormode)&&args->Y[0]!='#'){args->Y=ns_color(parse_color(args->Y));changed=1;}}}while(0)
bfc7071997-01-13Per Hedbor 
2ce3701998-03-29Henrik Grubbström (Grubba)  if(!search((id->client||({}))*"","Mosaic"))
0ee0851997-02-08Per Hedbor  {
b89ccb1999-11-28Martin Nilsson  FIX(bgcolor,"#bfbfbf",bgcolor); FIX(text, "#000000",fgcolor);
0ee0851997-02-08Per Hedbor  FIX(link, "#0000b0",link); FIX(alink, "#3f0f7b",alink); FIX(vlink, "#ff0000",vlink); } else {
b89ccb1999-11-28Martin Nilsson  FIX(bgcolor,"#c0c0c0",bgcolor); FIX(text, "#000000",fgcolor);
0ee0851997-02-08Per Hedbor  FIX(link, "#0000ee",link); FIX(alink, "#ff0000",alink); FIX(vlink, "#551a8b",vlink); }
c97c421998-08-20Per Hedbor  if(changed && QUERY(colormode)) return ({make_tag("body", args) });
38569c1999-12-07Martin Nilsson  return 0;
d47cbf1996-12-02Per Hedbor }
a3dfd41999-11-28Martin Nilsson string|array(string) tag_fix_color(string tagname, mapping args, RequestID id,
fc57521998-03-06Per Hedbor  object file, mapping defines)
bfc7071997-01-13Per Hedbor { int changed;
196dac1997-02-22Per Hedbor  if(!id->misc->colors)
b89ccb1999-11-28Martin Nilsson  id->misc->colors = ({ ({ defines->fgcolor, defines->bgcolor, tagname }) });
196dac1997-02-22Per Hedbor  else
b89ccb1999-11-28Martin Nilsson  id->misc->colors += ({ ({ defines->fgcolor, defines->bgcolor, tagname }) });
f7d9811997-09-12Per Hedbor #undef FIX
c97c421998-08-20Per Hedbor #define FIX(X,Y) if(args->X && args->X!=""){defines->Y=args->X;if(QUERY(colormode) && args->X[0]!='#'){args->X=ns_color(parse_color(args->X));changed = 1;}}
bfc7071997-01-13Per Hedbor 
b89ccb1999-11-28Martin Nilsson  FIX(bgcolor,bgcolor); FIX(color,fgcolor); FIX(text,fgcolor);
c97c421998-08-20Per Hedbor #undef FIX
22846b1998-05-15Per Hedbor 
c97c421998-08-20Per Hedbor  if(changed && QUERY(colormode)) return ({ make_tag(tagname, args) });
bfc7071997-01-13Per Hedbor  return 0; }
d47cbf1996-12-02Per Hedbor 
a3dfd41999-11-28Martin Nilsson string|void pop_color(string tagname,mapping args,RequestID id,object file,
a5c21b1999-05-18Peter Bortas  mapping defines)
196dac1997-02-22Per Hedbor {
c97c421998-08-20Per Hedbor  array c = id->misc->colors;
a3dfd41999-11-28Martin Nilsson  if(!c ||!sizeof(c))
0a76aa1998-03-27David Hedbor  return;
df8d711998-02-27Per Hedbor  int i; tagname = tagname[1..]; for(i=0;i<sizeof(c);i++) if(c[-i-1][2]==tagname)
5f0d911997-02-27Per Hedbor  {
b89ccb1999-11-28Martin Nilsson  defines->fgcolor = c[-i-1][0]; defines->bgcolor = c[-i-1][1];
5f0d911997-02-27Per Hedbor  break; }
a5c21b1999-05-18Peter Bortas  c = c[..sizeof(c)-i-2]; id->misc->colors = c;
196dac1997-02-22Per Hedbor }
a3dfd41999-11-28Martin Nilsson  // --------------- tag and container registration ----------------------
bfc7071997-01-13Per Hedbor mapping query_tag_callers()
d47cbf1996-12-02Per Hedbor {
8b6ee51999-07-10Peter Bortas  mapping tags = ([ "gtext-id":tag_gtext_id ]);
39af1a1998-08-26Per Hedbor  if(query("colorparse")) foreach(query("colorparsing"), string t)
c97c421998-08-20Per Hedbor  {
39af1a1998-08-26Per Hedbor  switch(t) { case "body": tags[t] = tag_body; break; default: tags[t] = tag_fix_color; tags["/"+t]=pop_color; }
c97c421998-08-20Per Hedbor  } return tags;
d47cbf1996-12-02Per Hedbor } mapping query_container_callers() {
a3dfd41999-11-28Martin Nilsson  return ([ "anfang":tag_anfang, "gtext-url":tag_gtext_url, "gh":tag_gh, "gh1":tag_gh, "gh2":tag_gh, "gh3":tag_gh, "gh4":tag_gh, "gh5":tag_gh, "gh6":tag_gh, "gtext":tag_graphicstext ]);
d47cbf1996-12-02Per Hedbor }