4dfdeb | 1996-12-04 | Per Hedbor | | string cvs_version="$Id: graphic_text.pike,v 1.3 1996/12/04 06:06:34 per Exp $";
|
d47cbf | 1996-12-02 | Per Hedbor | | #include <module.h>
inherit "module";
inherit "roxenlib";
array register_module()
{
return ({ MODULE_LOCATION | MODULE_PARSER,
"Graphics text",
"Makes a few new tags:"
"<gh1> to <gh6>: Headers<br>\n"
"<gh>: Header<br>\n"
"<gtext>: Graphical text<br>\n"
"<anfang>: Make the first character to a graphical one<br>\n"
"\n"
"Common arguments:\n <pre>"
" bg=#rrggbb Use this background, default taken from the\n"
" <body> tag, if any\n"
" fg=#rrggbb Use this foreground, default taken from the\n"
" <body> tag, if any\n"
" font=fnt Use this font. The fonts can be found in the\n"
" directory specified in the configuration\n"
" interface.\n"
" If no font is specified, the one from the\n"
" define 'font' is used, or if there is no\n"
" define, the default font will be used.\n"
" scale=float Scale to this font, mostly useful in the <gtext>\n"
" tag, will not work at all in the <gh[number]>\n"
" tags.\n"
" 2 3 4 5 6 Short for scale=1.0/([number]*0.6)\n"
" notrans Do _not_ make the background color transparent\n"
" split Make each word into a separate gif image\n"
" href=url Link the image to the specified URL\n"
" The 'link' color of the document will be\n"
" used as the default foreground of the text\n"
" quant=cols Use this number of colors\n"
" magic[=message] Modifier to href, more flashy links\n"
" Does <b>not</b> work with 'split'\n"
" fs Use floyd-steinberg dithering\n"
" border=int,#col Draw an border (width is the first argument\n"
" in the specified color\n"
" spacing=int Add this amount of spacing around the text\n"
" bevel=int Draw a bevel box (width is the argument)\n"
" textbox=al,#col Use 'al' as opaque value to draw a box below\n"
" the text with the specified color.\n"
|
4dfdeb | 1996-12-04 | Per Hedbor | | " shadow=int,dist Draw a drop-shadow (variable distance/intensity)\n"
|
d47cbf | 1996-12-02 | Per Hedbor | | " fuzz=#col The 'shine' effect used in the 'magic'\n"
" highlightning\n"
" opaque=0-100% Draw with more or less opaque text (100%\n"
" is default)\n"
" rotate=ang(deg.)Rotate the finished image\n"
" background=file Use the specifed file as a background\n"
" texture=file Use the specified file as text texture\n"
|
4dd97c | 1996-12-04 | Per Hedbor | | "</pre>\n",
0,
1,
|
d47cbf | 1996-12-02 | Per Hedbor | | });
}
array (string) list_fonts()
{
|
4dd97c | 1996-12-04 | Per Hedbor | | array fnts;
catch(fnts = get_dir("fonts/32/") - ({".",".."}));
if(!fnts)
{
report_error("Failed to find any fonts in 'fonts/32/'. No default font.\n");
return ({});
}
return fnts;
|
d47cbf | 1996-12-02 | Per Hedbor | | }
void create()
{
defvar("location", "/gtext/", "Mountpoint", TYPE_LOCATION,
"The URL-prefix for the anfang characters.");
defvar("cols", 16, "Default number of colors per image", TYPE_INT_LIST,
"The default number of colors to use. 16 seems to be enough. "
"The size of the image depends on the number of colors",
({ 1,2,3,4,5,6,7,8,10,16,32,64,128,256 }));
defvar("default_size", 32, "Default font size", TYPE_INT_LIST,
"The default size for the font. This is used for the 'base' size, "
"and can be scaled up or down in the tags.",
({ 16, 32, 64 }));
defvar("default_font", "urw_itc_avant_garde-demi-r", "Default font",
TYPE_STRING_LIST,
"The default font. The 'font dir' will be prepended to the path",
list_fonts());
}
string query_location() { return query("location"); }
mapping (string:object) fonts = ([]);
object(Font) load_font(string name)
{
object fnt = Font();
if(!name) name = QUERY(default_size)+"/"+QUERY(default_font);
else if(sscanf(name, "%*s/%*s") != 2) name=QUERY(default_size)+"/"+name;
name = "fonts/" + name;
if(fnt->load( name )) return fnt;
perror("Failed to load the font "+name+", using the default font.\n");
if(!fnt->load("fonts/"+QUERY(default_size) +"/"+ QUERY(default_font)))
error("Failed to load the default font\n");
return fnt;
}
static private mapping (int:mapping(string:mixed)) cached_args = ([ ]);
#define MAX(a,b) ((a)<(b)?(b):(a))
static private mapping (int:array(array(int))) matrixes = ([]);
array (array(int)) make_matrix(int size)
{
if(matrixes[size]) return matrixes[size];
array res;
int i;
int j;
res = map_array(allocate(size), lambda(int s, int size){
return allocate(size); }, size);
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);
return matrixes[size] = res;
}
object (Image) load_image(string f)
{
object file = File();
string data;
object img = Image();
perror("Loading "+f+"\n");
if(!file->open(f,"r"))
{
perror("Failed to open file ("+f+").\n");
return 0;
}
if(!(data=file->read(0x7fffffff))) return 0;
if(img->frompnm(data)) return img;
if(img->fromgif(data)) return img;
perror("Failed to parse file.\n");
return 0;
}
object (Image) blur(object (Image) img, int amnt)
{
for(int i=0; i<amnt; i++)
img = img->apply_matrix( make_matrix((int)sqrt(img->ysize()+10)));
return img;
}
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 });
object (Image) bevel(object (Image) in, int width)
{
|
4dfdeb | 1996-12-04 | Per Hedbor | | int h=in->ysize();
int w=in->xsize();
|
d47cbf | 1996-12-02 | Per Hedbor | |
|
4dfdeb | 1996-12-04 | Per Hedbor | | in->paste_alpha(Image(width,h-width*2,@white), 160, 0, width);
in->paste_alpha(Image(width,h-width*2,@black), 128, in->xsize()-width, width);
in->paste_alpha(Image(w-width*2,width,@white), 160, 0, 0);
in->paste_alpha(Image(w-width*2,width,@black), 128, width, in->ysize()-width);
|
d47cbf | 1996-12-02 | Per Hedbor | |
|
4dfdeb | 1996-12-04 | Per Hedbor | | object corner = Image(width+1,width+1);
for(int i=-1; i<=width; i++) corner->line(i,width-i,i,-1, 200,200,200);
|
d47cbf | 1996-12-02 | Per Hedbor | | in->paste_alpha(corner, 128, in->xsize()-width,0);
in->paste_alpha(corner, 128, -1, in->ysize()-width);
|
4dfdeb | 1996-12-04 | Per Hedbor | | corner=0;
|
d47cbf | 1996-12-02 | Per Hedbor | | return in;
}
object (Image) make_text_image(mapping args, object font, string text)
{
object (Image) text_alpha=font->write(@(text/"\n"));
int xoffset=0, yoffset=0;
if(int op=((((int)args->opaque)*255)/100))
text_alpha=text_alpha->color(op,op,op);
int txsize=text_alpha->xsize();
int tysize=text_alpha->ysize();
int xsize=txsize;
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;
}
|
4dfdeb | 1996-12-04 | Per Hedbor | | if(args->shadow)
{
xsize+=((int)(args->shadow/",")[-1])+2;
ysize+=((int)(args->shadow/",")[-1])+2;
}
|
d47cbf | 1996-12-02 | Per Hedbor | | if(args->xspacing)
{
xoffset += (int)args->xspacing;
xsize += ((int)args->xspacing)*2;
}
if(args->border)
{
xoffset += (int)args->border;
yoffset += (int)args->border;
xsize += ((int)args->border)*2;
ysize += ((int)args->border)*2;
}
|
4dd97c | 1996-12-04 | Per Hedbor | | array (int) bgcolor = parse_color(args->bg);
array (int) fgcolor = parse_color(args->fg);
|
d47cbf | 1996-12-02 | Per Hedbor | |
object background,foreground;
if(args->texture) foreground = load_image(args->texture);
|
4dfdeb | 1996-12-04 | Per Hedbor | | if(args->background)
{
background = load_image(args->background);
xsize = background->xsize();
ysize = background->ysize();
} else
background = Image(xsize, ysize, @bgcolor);
|
d47cbf | 1996-12-02 | Per Hedbor | |
if(args->bevel) background = bevel(background, (int)args->bevel);
if(args->textbox)
{
|
4dfdeb | 1996-12-04 | Per Hedbor | | int alpha,border;
|
d47cbf | 1996-12-02 | Per Hedbor | | string bg;
sscanf(args->textbox, "%d,%s", alpha, bg);
|
4dfdeb | 1996-12-04 | Per Hedbor | | sscanf(bg,"%s,%d", bg,border);
background->paste_alpha(Image(txsize+border,tysize+border,@parse_color(bg)),
255-(alpha*255/100), xoffset, yoffset);
|
d47cbf | 1996-12-02 | Per Hedbor | | }
|
4dfdeb | 1996-12-04 | Per 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);
background->paste_mask(Image(txsize,tysize),ta,xoffset+sdist, yoffset+sdist);
}
if(!foreground) foreground=Image(xsize, ysize, @fgcolor);
|
d47cbf | 1996-12-02 | Per Hedbor | |
|
4dfdeb | 1996-12-04 | Per Hedbor | | background->paste_mask(foreground, text_alpha, xoffset, yoffset);
|
d47cbf | 1996-12-02 | Per Hedbor | |
foreground = text_alpha = 0;
if(args->scale)
if((float)args->scale <= 2.0)
background = background->scale((float)args->scale);
if(args->rotate)
{
string c;
if(sscanf(args->rotate, "%*d,%s", c))
|
4dd97c | 1996-12-04 | Per Hedbor | | background->setcolor(@parse_color(c));
|
d47cbf | 1996-12-02 | Per Hedbor | | else
background->setcolor(@bgcolor);
background = background->rotate((float)args->rotate);
}
|
4dfdeb | 1996-12-04 | Per Hedbor | | if(args->crop) background = background->autocrop();
|
d47cbf | 1996-12-02 | Per Hedbor | |
return background;
}
array(int)|string write_text(int _args, string text, int size,
object id)
{
object img;
mapping args = cached_args[_args];
if(!args) return 0;
text = replace(text, ({ "<", ">", "&" }), ({ "<", ">", "&" }));
if(!id || (!id->pragma["no-cache"]))
if(mixed data = cache_lookup("font:"+_args, text))
{
if(size) return data[1];
return data[0];
}
data = cache_lookup("fonts:fonts", args->font);
if(!data)
{
data = load_font(args->font);
cache_set("fonts:fonts", args->font, data);
}
img = make_text_image(args,data,text);
if(!img) return 0;
int q = (int)args->quant || (args->background?256:16);
|
4dd97c | 1996-12-04 | Per Hedbor | | img = img->map_closest(img->select_colors(q-1)+({parse_color(args->bg)}));
|
d47cbf | 1996-12-02 | Per Hedbor | | if(args->fs)
|
4dd97c | 1996-12-04 | Per Hedbor | | data=({ img->togif_fs(@(args->notrans?({}):parse_color(args->bg))),
|
d47cbf | 1996-12-02 | Per Hedbor | | ({img->xsize(),img->ysize()})});
else
|
4dd97c | 1996-12-04 | Per Hedbor | | data=({ img->togif(@(args->notrans?({}):parse_color(args->bg))),
|
d47cbf | 1996-12-02 | Per Hedbor | | ({img->xsize(),img->ysize()})});
img=0;
cache_set("font:"+_args, text, data);
if(size) return data[1];
return data[0];
}
mapping find_file(string f, object rid)
{
string id;
sscanf(f,"%d/%s", id, f);
return http_string_answer(write_text((int)id,f,0,rid), "image/gif");
}
string quote(string in)
{
string res="";
for(int i=0; i<strlen(in); i++)
switch(in[i])
{
case 'a'..'z':
case 'A'..'Z':
case '0'..'9':
case '.':
case ',':
case '!':
res += in[i..i];
break;
default:
res += sprintf("%%%02x", in[i]);
}
return res;
}
int number=time(1);
int find_or_insert(mapping find)
{
array a = indices(cached_args);
array b = values(cached_args);
int i;
for(i=0; i<sizeof(a); i++)
if(equal(find, b[i])) return a[i];
cached_args[number]=find;
return number++;
}
string magic_javascript_header(object id)
{
if(!id->supports->javascript || !id->supports->images) return "";
return
("<script>\n"
"<!-- \n"
"version = 1;\n"
"browserName = navigator.appName;\n"
"browserVer = parseInt(navigator.appVersion); \n"
"if(browserName == \"Netscape\" && (browserVer == 3 || browserVer == 4 || browserVer == 5 || browserVer == 6)) \n"
" version = \"3\";\n"
"else\n"
" version= \"1\";\n"
"\n"
"function stat(txt)\n"
"{\n"
" top.window.status = txt;\n"
"}\n"
"\n"
"function img_act(imgName, txt)\n"
"{\n"
" if (version == \"3\") \n"
" {\n"
" imgOn = eval(imgName + \"2.src\");\n"
" document [imgName].src = imgOn;\n"
" }\n"
" setTimeout(\"stat('\"+txt+\"')\", 100);\n"
"}\n"
"\n"
"function img_inact(imgName)\n"
"{\n"
" if (version == \"3\") \n"
" {\n"
" imgOff = eval(imgName + \".src\");\n"
" document [imgName].src = imgOff;\n"
" }\n"
"}\n"
"// -->\n"
"</script>\n");
}
string magic_image(string url, int xs, int ys, string sn,
string image_1, string image_2, string alt,
string mess,object id)
{
if(!id->supports->images) return alt;
if(!id->supports->javascript)
return
("<a href=\""+url+"\"><img src="+image_1+" name="+
sn+" border=0 alt=\""+alt+"\" ></a>\n");
return
("<script>\n"
"<!-- \n"
"if(version == \"3\")\n"
"{\n"
" "+sn+" = new Image("+xs+", "+ys+");\n"
" "+sn+".src = \""+image_1+"\";\n"
" "+sn+"2 = new Image("+xs+", "+ys+");\n"
" "+sn+"2.src = \""+image_2+"\";\n"
"}\n"
"// -->\n"
"</script>\n"
"<a href=\""+url+"\" onMouseover=\"img_act('"+sn+"','"
+(mess||url)+"');return true;\"\n"
"\n"
"onMouseout=\"img_inact('"+sn+"')\"><img \n"
" src="+image_1+" name="+sn+" border=0 alt=\""+alt+"\" ></a>\n");
}
string tag_graphicstext(string t, mapping arg, string contents,
object id, object foo, mapping defines)
{
if(!strlen(contents)) return "";
string pre, post, defalign, gt, rest, magic;
int i, split;
if(!id->supports->images || id->prestate->noimages)
{
if(!arg->split) contents=replace(contents,"\n", "\n<br>\n");
switch(t)
{
case "gtext":
case "anfang":
if(arg->href)
return "<a href=\""+arg->href+"\">"+contents+"</a>";
return contents;
default:
if(sscanf(t, "%s%d", t, i)==2)
rest="<h"+i+">"+contents+"</h"+i+">";
else
rest="<h1>"+contents+"</h1>";
if(arg->href)
return "<a href=\""+arg->href+"\">"+rest+"</a>";
return rest;
}
}
if(arg->magic)
{
magic=arg->magic;
m_delete(arg,"magic");
}
string lp, url;
if(arg->href)
{
url = arg->href;
lp = "<a href=\""+arg->href+"\">";
if(!arg->fg) arg->fg=defines->link||"#0000ff";
m_delete(arg,"href");
}
if(defines->fg && !arg->fg) arg->fg=defines->fg;
if(defines->bg && !arg->bg) arg->bg=defines->bg;
if(defines->font && !arg->font) arg->font=defines->font||QUERY(default_font);
if(!arg->font) arg->font = QUERY(default_font);
if(arg->split)
{
split=1;
m_delete(arg,"split");
}
for(i=2; i<10; i++)
if(arg[(string)i])
{
arg->scale = 1.0 / ((float)i*0.6);
m_delete(arg, (string)i);
}
if(sscanf(t, "%s%d", t, i)==2)
if(i > 1) arg->scale = 1.0 / ((float)i*0.6);
string moreargs="";
if(arg->hspace)
{
moreargs += "hspace="+arg->hspace+" ";
m_delete(arg,"hspace");
}
if(arg->vspace)
{
moreargs += "vspace="+arg->vspace+" ";
m_delete(arg,"vspace");
}
int num = find_or_insert( arg );
gt=contents;
rest="";
if(split)
{
string word;
array res = ({});
string pre = query_location()+num+"/";
if(lp) res+=({ lp });
gt=replace(gt, "\n", " ");
foreach(gt/" "-({""}), word)
{
array size = write_text(num,word,1,0);
res += ({ "<img border=0 alt=\""+replace(word,"\"","'")
+"\" src=\'"+pre+quote(word)+"\' width="+
size[0]+" height="+size[1]+" "+moreargs+">\n"
});
}
if(lp) res+=({ "</a>" });
return res*"";
}
switch(t)
{
case "gh1": case "gh2": case "gh3": case "gh4":
case "gh5": case "gh6": case "gh7":
case "gh": pre="<p>"; post="<br>"; defalign="top"; break;
case "gtext":
pre=""; post=""; defalign="bottom";
break;
case "anfang":
gt=contents[0..0]; rest=contents[1..];
pre="<br clear=left>"; post=""; defalign="left";
break;
}
array size = write_text(num,gt,1,0);
if(magic)
{
string res = "";
arg = mkmapping(indices(arg), values(arg));
arg->fuzz = arg->fg;
arg->fg = defines->alink||"#ff0000";
int num2 = find_or_insert(arg);
array size = write_text(num2,gt,1,0);
if(!defines->magic_java)
res = magic_javascript_header(id);
defines->magic_java="yes";
return res + magic_image(url||"", size[0], size[1],
"i"+(num+""+hash(gt,0x7fffffff))+"g",
query_location()+num+"/"+quote(gt),
query_location()+num2+"/"+quote(gt),
replace(gt, "\"","'"),(magic=="magic"?0:magic),
id);
}
return (pre+(lp?lp:"")+
"<img border=0 alt=\""+replace(gt,"\"","'")+"\" src="+
query_location()+num+"/"+quote(gt)
+" align="+(arg->align?arg->align:defalign)+
" width="+size[0]+" height="+size[1]+">"+rest+(lp?"</a>":"")+post);
}
string tag_body(string t, mapping args, object id, object file,
mapping defines)
{
if(args->bgcolor) defines->bg = args->bgcolor;
if(args->text) defines->fg = args->text;
if(args->link) defines->link = args->link;
if(args->alink) defines->alink = args->alink;
if(args->clink) defines->clink = args->clink;
if(args->vlink) defines->vlink = args->vlink;
}
mapping query_tag_callers()
{
return (["body":tag_body]);
}
mapping query_container_callers()
{
return ([ "anfang":tag_graphicstext,
"gh":tag_graphicstext,
"gh1":tag_graphicstext,
"gh2":tag_graphicstext,
"gh3":tag_graphicstext,
"gh4":tag_graphicstext,
"gh5":tag_graphicstext,
"gh6":tag_graphicstext,
"gtext":tag_graphicstext, ]);
}
|