2b165b2001-09-26Martin Nilsson // This file is part of Roxen WebServer.
b655bf2004-06-30Martin Stjernholm // Copyright © 2000 - 2004, Roxen IS.
2b165b2001-09-26Martin Nilsson 
38d0972000-09-04Per Hedbor #include <config.h> #include <stat.h>
b655bf2004-06-30Martin Stjernholm constant cvs_version = "$Id: imagedir.pike,v 1.14 2004/06/30 16:58:48 mast Exp $";
38d0972000-09-04Per Hedbor  constant name = "Image directory fonts"; constant doc = ("Handles a directory with images (in almost any format), each "
e892262000-09-04Per Hedbor  "named after the character they will represent. Characters " "with codes larger than 127 or less than 48 are encoded like "
0bd4d92000-09-04Per Hedbor  "0xHEX where HEX is the code in hexadecimal. There must be a " "file named 'fontname' in the directory, the first line of " "that file is used as the name of the font");
38d0972000-09-04Per Hedbor  inherit FontHandler;
e892262000-09-04Per Hedbor #ifdef THREADS Thread.Mutex lock = Thread.Mutex(); #endif
b5aa9c2000-09-04Per Hedbor static mapping nullchar = ([ "image":Image.Image(1,1), "alpha":Image.Image(1,1) ]); static mapping spacechar = ([ "image":Image.Image(10,1), "alpha":Image.Image(10,1) ]); static mapping smallspacechar = ([ "image":Image.Image(2,1), "alpha":Image.Image(2,1) ]);
38d0972000-09-04Per Hedbor class myFont { inherit Font; static string path; static int size, rsize; static array files;
7319b62001-08-29Martin Nilsson  string _sprintf()
38d0972000-09-04Per Hedbor  { return sprintf( "FontDir(%O,%d)", path, height() ); } static string encode_char( string c ) {
e892262000-09-04Per Hedbor  int cc = c[0]; if( (cc < 48) || (cc > 127) ) return sprintf( "0x%x", cc ); return c;
38d0972000-09-04Per Hedbor  } static mapping(string:Image.Image) load_char( string c ) {
b5aa9c2000-09-04Per Hedbor  if( c[0] == 0x120 ) return smallspacechar;
38d0972000-09-04Per Hedbor  if(!files) files = get_dir( path ) - ({ "fontname" });
e892262000-09-04Per Hedbor  array possible = ({ encode_char(c) })+ glob(encode_char( c )+".*", files); sort( map(possible,strlen), possible );
3efbc92000-09-16Per Hedbor  catch { foreach( possible, string pf ) if( mapping r = Image._load( path+pf ) ) return r; };
b5aa9c2000-09-04Per Hedbor  if( c == " " ) return spacechar;
38d0972000-09-04Per Hedbor  return nullchar; } mapping(string:mapping(string:Image.Image)) char_cache = ([]); static mapping(string:Image.Image) write_char( string c ) { if( char_cache[ c ] ) return char_cache[ c ]; return char_cache[ c ] = load_char( c ); } static Image.Image write_row( string text ) { array(mapping(string:Image.Image)) res = map( text/"", write_char );
3c607d2001-01-01Martin Nilsson  Image.Image rr; if(floatp(x_spacing)) rr=Image.Image((int)abs(`+(0,@res->image->xsize())*x_spacing), max(0,@res->image->ysize())); else rr=Image.Image(abs(`+(0,@res->image->xsize())+(sizeof(res)*x_spacing)), max(0,@res->image->ysize()));
38d0972000-09-04Per Hedbor  float start; if( x_spacing < 0 ) start = (float)rr->xsize()-res[0]->image->xsize(); foreach( res, mapping(string:Image.Image) r ) { if( !r->image ) continue; if( r->alpha ) rr->paste_mask(r->image,r->alpha, (int)start,rr->ysize()-r->image->ysize() ); else rr->paste(r->image,(int)start,rr->ysize()-r->image->ysize());
3c607d2001-01-01Martin Nilsson  if(floatp(x_spacing)) start += r->image->xsize()*x_spacing; else start += r->image->xsize()+x_spacing;
38d0972000-09-04Per Hedbor  } return rr; } int height() { return rsize ? rsize : (rsize = text_extents("0WjI|9")[1] ); } Image.Image write( string ... what ) { array(Image.Image) res = map( what, write_row );
3c607d2001-01-01Martin Nilsson  Image.Image rr; if(floatp(y_spacing)) rr = Image.Image( max(0,@res->xsize()), (int)abs(`+(0,@res->ysize())*y_spacing) ); else rr = Image.Image( max(0,@res->xsize()),
530a6a2001-01-02Martin Nilsson  abs(`+(0,@res->ysize())+(sizeof(res)*y_spacing)) );
38d0972000-09-04Per Hedbor  float start; if( y_spacing < 0 ) start = (float)rr->ysize()-res[0]->ysize(); foreach( res, object r ) { if( j_right ) rr->paste(r,rr->xsize()-r->xsize(),(int)start); else if( j_center ) rr->paste(r,(rr->xsize()-r->xsize())/2,(int)start); else rr->paste( r, 0, (int)start );
3c607d2001-01-01Martin Nilsson  if(floatp(y_spacing)) start += r->ysize()*y_spacing; else start += r->ysize()+y_spacing;
38d0972000-09-04Per Hedbor  } return rr; } array text_extents( string what ) { Image.Image o = write( what ); return ({ o->xsize(), o->ysize() }); }
9786ce2001-01-02Martin Nilsson  void set_x_spacing( int|float value ) { if(value!=1.0) ::set_x_spacing(value); } void set_y_spacing( int|float value ) { if(value!=1.0) ::set_y_spacing(value); } void create( string _path, int _size, int xpad, int ypad )
38d0972000-09-04Per Hedbor  { path = _path; size = _size;
9786ce2001-01-02Martin Nilsson  x_spacing = xpad; y_spacing = ypad;
38d0972000-09-04Per Hedbor  } } mapping font_list;
fad0b72000-09-16Martin Nilsson mapping meta_data;
38d0972000-09-04Per Hedbor static string font_name( string what ) {
fad0b72000-09-16Martin Nilsson  if(!meta_data) meta_data=([]); mapping _meta_data=([]); Parser.HTML()-> add_containers( ([ "name":lambda(string t, mapping m, string c) { what=c; return ""; }, "meta":lambda(string t, mapping m, string c) { _meta_data[m->name]=c; },
9786ce2001-01-02Martin Nilsson  "xpad":lambda(string t, mapping m, string c) { _meta_data->xpad = (int)c; }, "ypad":lambda(string t, mapping m, string c) { _meta_data->ypad = (int)c; },
fad0b72000-09-16Martin Nilsson  ]) )->finish(what); what=(lower_case( replace(what," ","_") )/"\n")[0]-"\r"; if(sizeof(_meta_data)) meta_data[what]=_meta_data; return what;
38d0972000-09-04Per Hedbor } void update_font_list() { font_list = ([]); foreach(roxen->query("font_dirs"), string dir) foreach( (get_dir( dir )||({})), string d )
cf92fe2003-09-18Martin Stjernholm  if( Stdio.is_dir( dir+d ) ) {
530a6a2001-01-02Martin Nilsson  if( file_stat( dir+d+"/fontinfo" ) ) font_list[font_name(Stdio.read_bytes(dir+d+"/fontinfo"))]=dir+d+"/"; else if( file_stat( dir+d+"/fontname" ) )
38d0972000-09-04Per Hedbor  font_list[font_name(Stdio.read_bytes(dir+d+"/fontname"))]=dir+d+"/";
530a6a2001-01-02Martin Nilsson  }
38d0972000-09-04Per Hedbor } array available_fonts() {
e892262000-09-04Per Hedbor #ifdef THREADS object key = lock->lock(); #endif
38d0972000-09-04Per Hedbor  array res = ({}); if( !font_list ) update_font_list(); return indices( font_list ); } array(mapping) font_information( string fnt ) {
e892262000-09-04Per Hedbor #ifdef THREADS object key = lock->lock(); #endif
38d0972000-09-04Per Hedbor  if( !font_list ) update_font_list(); if( font_list[ fnt ] )
fad0b72000-09-16Martin Nilsson  return ({ (meta_data[fnt] || ([])) | ([
38d0972000-09-04Per Hedbor  "name":fnt, "family":fnt, "path":font_list[fnt], "format":"imagedir", ]) }); return ({}); } array has_font( string name, int size ) {
e892262000-09-04Per Hedbor #ifdef THREADS object key = lock->lock(); #endif
38d0972000-09-04Per Hedbor  if( !font_list ) update_font_list(); if( font_list[ name ] ) return ({ "nn" }); } Font open( string name, int size, int bold, int italic ) {
e892262000-09-04Per Hedbor #ifdef THREADS object key = lock->lock(); #endif
38d0972000-09-04Per Hedbor  if( !font_list ) update_font_list();
4dfb8a2001-01-04Martin Nilsson  int xpad,ypad; if(meta_data && meta_data[name]) { xpad = meta_data[name]->xpad; ypad = meta_data[name]->ypad; }
38d0972000-09-04Per Hedbor  if( font_list[ name ] )
9786ce2001-01-02Martin Nilsson  return myFont( font_list[name], size,
4dfb8a2001-01-04Martin Nilsson  xpad, ypad );
38d0972000-09-04Per Hedbor } void create() { roxen.getvar( "font_dirs" ) ->add_changed_callback( lambda(Variable.Variable v){ font_list = 0; } ); }