Back to index

texmacs  1.0.7.15
printer.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : printer.cpp
00004 * DESCRIPTION: Renderer for printing post-script graphics
00005 * COPYRIGHT  : (C) 1999  Joris van der Hoeven
00006 *******************************************************************************
00007 * This software falls under the GNU general public license version 3 or later.
00008 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00009 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00010 ******************************************************************************/
00011 
00012 #include "printer.hpp"
00013 #include "Metafont/tex_files.hpp"
00014 #include "Freetype/tt_file.hpp"
00015 #include "file.hpp"
00016 #include "image_files.hpp"
00017 #include "analyze.hpp"
00018 #include "iterator.hpp"
00019 #include "merge_sort.hpp"
00020 #include "scheme.hpp"
00021 #include "image_files.hpp"
00022 
00023 string PS_CLIP_PUSH ("gsave");
00024 string PS_CLIP_POP ("grestore");
00025 string PS_CLIP ("cl");
00026 string PS_LINE ("ln");
00027 string PS_FILL ("fl");
00028 string PS_ARC ("ac");
00029 string PS_FILL_ARC ("fac");
00030 string PS_STROKE ("st");
00031 string PS_POL_START ("sp");
00032 string PS_POL_NEXT ("np");
00033 string PS_POL_END ("ep");
00034 string PS1 ("u");
00035 string PS2 ("z");
00036 
00037 /******************************************************************************
00038 * constructors and destructors
00039 ******************************************************************************/
00040 
00041 printer_rep::printer_rep (
00042   url ps_file_name2, int dpi2, int nr_pages2,
00043   string page_type2, bool landscape2, double paper_w2, double paper_h2):
00044     ps_file_name (ps_file_name2), dpi (dpi2),
00045     nr_pages (nr_pages2), page_type (page_type2),
00046     landscape (landscape2), paper_w (paper_w2), paper_h (paper_h2),
00047     use_alpha (get_preference ("experimental alpha") == "on"),
00048     linelen (0), fg (-1), bg (-1), ncols (0),
00049     lw (-1), nwidths (0), cfn (""), nfonts (0),
00050     xpos (0), ypos (0), tex_flag (false),
00051     defs ("?"), tex_chars ("?"), tex_width ("?"),
00052     tex_fonts ("?"), tex_font_chars (array<int>(0))    
00053 {
00054   string tex_pro, special_pro, color_pro, texps_pro;
00055   load_string ("$TEXMACS_PATH/misc/convert/tex.pro", tex_pro, true);
00056   load_string ("$TEXMACS_PATH/misc/convert/special.pro", special_pro, true);
00057   load_string ("$TEXMACS_PATH/misc/convert/color.pro", color_pro, true);
00058   load_string ("$TEXMACS_PATH/misc/convert/texps.pro", texps_pro, true);
00059   
00060   prologue   << "%!PS-Adobe-2.0\n"
00061             << "%%Creator: TeXmacs-" TEXMACS_VERSION "\n"
00062             << "%%Title: " << as_string (tail (ps_file_name)) << "\n"
00063             << "%%Pages: " << as_string (nr_pages) << "\n"
00064             << "%%PageOrder: Ascend\n";
00065   if (page_type != "user")
00066     prologue << "%%DocumentPaperSizes: " << page_type << "\n";
00067   if (landscape)
00068     prologue << "%%BoundingBox: 0 0 "
00069             << as_string ((int) (28.36*paper_h+ 0.5)) << " "
00070             << as_string ((int) (28.36*paper_w+ 0.5)) << "\n"
00071             << "%%Orientation: Landscape\n";
00072   else
00073     prologue << "%%BoundingBox: 0 0 "
00074             << as_string ((int) (28.36*paper_w+ 0.5)) << " "
00075             << as_string ((int) (28.36*paper_h+ 0.5)) << "\n";
00076   prologue   << "%%EndComments\n\n"
00077             << tex_pro << "\n"
00078             << special_pro << "\n"
00079             << texps_pro << "\n"
00080             << "TeXDict begin\n"
00081             << as_string ((int) (1864680.0*paper_w+ 0.5)) << " "
00082             << as_string ((int) (1864680.0*paper_h+ 0.5)) << " 1000 "
00083             << as_string (dpi) << " " << as_string (dpi)
00084             << " (TeXmacs) @start\n";
00085 
00086   define (PS_CLIP, string ("/pt4 X /pt3 X /pt2 X /pt1 X\n") *
00087          string ("newpath pt1 pt2 moveto pt3 pt2 lineto ") *
00088          string ("pt3 pt4 lineto pt1 pt4 lineto pt1 pt2 lineto clip"));
00089   define (PS_LINE, string ("/pt4 X /pt3 X /pt2 X /pt1 X\n") *
00090          string ("newpath pt1 pt2 moveto pt3 pt4 lineto stroke"));
00091   define (PS_FILL, string ("/pt4 X /pt3 X /pt2 X /pt1 X\n") *
00092          string ("newpath pt1 pt2 moveto pt3 pt2 lineto ") *
00093          string ("pt3 pt4 lineto pt1 pt4 lineto pt1 pt2 eofill stroke"));
00094   define (PS_ARC, string ("/a2 X /a1 X /r2 X /r1 X /pt2 X /pt1 X\n") *
00095          string ("newpath pt1 pt2 r1 r2 a1 a2 ellipse stroke"));
00096   define (PS_FILL_ARC, string ("/a2 X /a1 X /r2 X /r1 X /pt2 X /pt1 X\n") *
00097          string ("newpath pt1 pt2 r1 r2 a1 a2 ellipse eofill stroke"));
00098   define (PS_STROKE, string ("stroke"));
00099   define (PS_POL_START, string ("/pt2 X /pt1 X\n") *
00100          string ("newpath pt1 pt2 moveto"));
00101   define (PS_POL_NEXT, string ("/pt2 X /pt1 X\n") *
00102          string ("pt1 pt2 lineto"));
00103   define (PS_POL_END, string ("closepath eofill"));
00104   define (PS1, string ("gsave"));
00105   define (PS2, string ("1 -1 scale show grestore"));
00106 
00107   cur_page= 0;
00108   next_page ();
00109 }
00110 
00111 printer_rep::~printer_rep () {
00112   next_page ();
00113   body << "\n%%Trailer\n"
00114        << "end\n"
00115        << "userdict /end-hook known{end-hook} if\n"
00116        << "%%EOF\n";
00117 
00118   generate_tex_fonts ();
00119   prologue << "end\n"
00120 
00121            << "systemdict /pdfmark known{userdict /?pdfmark systemdict /exec get put}{userdict /?pdfmark systemdict /pop get put userdict /pdfmark systemdict /cleartomark get put}ifelse\n"
00122 
00123            << "%%EndProlog\n\n"
00124           << "%%BeginSetup\n"
00125           << "%%Feature: *Resolution " << as_string (dpi) << "dpi\n"
00126           << "TeXDict begin\n";
00127   if (page_type != "user") {
00128     prologue << "%%BeginPaperSize: " << page_type << "\n";
00129     prologue << page_type << "\n";
00130     prologue << "%%EndPaperSize\n";
00131   }
00132   if (landscape)
00133     prologue << "@landscape\n";
00134   prologue << "%%EndSetup\n";
00135 
00136   string ps_text= prologue * "\n" * body;
00137   save_string (ps_file_name, ps_text);
00138 }
00139 
00140 bool
00141 printer_rep::is_printer () {
00142   return true;
00143 }
00144 
00145 void
00146 printer_rep::next_page () {
00147   if (cur_page > 0) print ("eop\n");
00148   if (cur_page >= nr_pages) return;
00149   cur_page++;
00150   body << "\n%%Page: " << as_string (cur_page) << " "
00151        << as_string (cur_page) << "\n"
00152        << as_string (cur_page) << " "
00153        << as_string (cur_page-1) << " bop\n";
00154 
00155   set_clipping (0, (int) (-(dpi*PIXEL*paper_h)/2.54),
00156               (int) ((dpi*PIXEL*paper_w)/2.54), 0);
00157 
00158   fg  = -1;
00159   bg  = -1;
00160   lw  = -1;
00161   cfn = "";
00162   xpos= 0;
00163   ypos= 0;
00164 }
00165 
00166 /******************************************************************************
00167 * subroutines for printing
00168 ******************************************************************************/
00169 
00170 void
00171 printer_rep::define (string s, string defn) {
00172   if (defs->contains (s)) return;
00173   defs (defn)= s;
00174   prologue << "/" << s << " {" << defn << "} N\n";
00175 }
00176 
00177 void
00178 printer_rep::sep () {
00179   if ((N(body) > 0) &&
00180       (body [N(body)-1] != ')') &&
00181       (body [N(body)-1] != '\n')) {
00182     body << " ";
00183     linelen++;
00184     tex_flag= false;
00185   }
00186 }
00187 
00188 void
00189 printer_rep::cr () {
00190   body << "\n";
00191   linelen= 0;
00192   tex_flag= false;
00193 }
00194 
00195 void
00196 printer_rep::print (string s) {
00197   if (N(s)==0) return;
00198   if ((linelen>0) && (linelen+N(s)>79)) {
00199     body << "\n";
00200     linelen= 0;
00201     tex_flag= false;
00202   }
00203   else if (s[0]!='(') sep ();
00204   if (tex_flag && (s[0]=='(')) {
00205     body->resize (N(body)-2);
00206     linelen -= 2;
00207     s= s (1,N(s));
00208   }
00209   body << s;
00210   linelen += N(s);
00211   tex_flag= false;
00212 }
00213 
00214 void
00215 printer_rep::print (SI x, SI y) {
00216   x += ox; y += oy;
00217   if (x>=0) x= x/PIXEL; else x= (x-PIXEL+1)/PIXEL;
00218   if (y>=0) y= y/PIXEL; else y= (y-PIXEL+1)/PIXEL;
00219   print (as_string (x-dpi));
00220   print (as_string (-y-dpi));
00221 }
00222 
00223 void
00224 printer_rep::move_to (SI x, SI y) {
00225   x += ox; y += oy;
00226   if (x>=0) x= x/PIXEL; else x= (x-PIXEL+1)/PIXEL;
00227   if (y>=0) y= y/PIXEL; else y= (y-PIXEL+1)/PIXEL;
00228   if (tex_flag && (xpos==x) && (ypos==y)) return;
00229   if (tex_flag && (ypos==y)) {
00230     body->resize (N(body)-1);
00231     linelen -= 1;
00232     tex_flag= false;
00233 
00234     int diff= x-xpos;
00235     if ((diff>=-4) && (diff<=4)) print (string ((char) ('p'+diff)));
00236     else {
00237       print (as_string (diff));
00238       print ("b");
00239     }
00240     xpos= x;
00241     return;
00242   }
00243   xpos= x; ypos= y;
00244   print (as_string (x-dpi));
00245   print (as_string (-y-dpi));
00246   print ("a");
00247 }
00248 
00249 string
00250 printer_rep::define_alpha (int a) {
00251   string aa= as_string (((double) a) / 255.0);
00252   string s= "[ /ca " * aa * " /CA " * aa * " /SetTransparency pdfmark";
00253   if (!defs->contains (s)) define ("A" * as_string (a), s);
00254   return defs[s];
00255 }
00256 
00257 void
00258 printer_rep::select_color (color c) {
00259   int r, g, b, a;
00260   get_rgb_color (c, r, g, b, a);
00261   r= 10000+ ((r*1000)/255);
00262   g= 10000+ ((g*1000)/255);
00263   b= 10000+ ((b*1000)/255);
00264   string rr= as_string (r); rr= rr(1,2) * "." * rr(2,5);
00265   string gg= as_string (g); gg= gg(1,2) * "." * gg(2,5);
00266   string bb= as_string (b); bb= bb(1,2) * "." * bb(2,5);
00267   string s = rr * " " * gg * " " * bb * " setrgbcolor";
00268   if (use_alpha) s= s * " " * define_alpha (a);
00269   if (!defs->contains (s)) {
00270     define ("C" * as_string (ncols), s);
00271     ncols++;
00272   }
00273   print (defs[s]);
00274 }
00275 
00276 void
00277 printer_rep::select_line_width (SI w) {
00278   w= w/PIXEL; if (w<1) w=1;
00279   string s = as_string (w) * " setlinewidth";
00280   if (!defs->contains (s)) {
00281     define ("W" * as_string (nwidths), s);
00282     nwidths++;
00283   }
00284   print (defs[s]);
00285 }
00286 
00287 /******************************************************************************
00288 * subroutines for fonts
00289 ******************************************************************************/
00290 
00291 static string
00292 prepare_text (string s) {
00293   int i;
00294   string r;
00295   for (i=0; i<N(s); i++) {
00296     int c= ((unsigned char) s[i]);
00297     if ((s[i]=='(') || (s[i]==')') || (s[i]=='\\'))
00298       r << '\\' << s[i];
00299     else if ((c <= 32) || (c >= 128)) {
00300       r << '\\';
00301       r << ('0' + (c >> 6));
00302       r << ('0' + ((c >> 3) & 7));
00303       r << ('0' + (c & 7));
00304     }
00305     else r << s[i];
00306   }
00307   return r;
00308 }
00309 
00310 void
00311 printer_rep::select_tex_font (string name) {
00312   if (cfn==name) return;
00313   cfn= name;
00314   print (tex_fonts [name]);
00315 }
00316 
00317 /******************************************************************************
00318 * make tex characters and fonts
00319 ******************************************************************************/
00320 
00321 static const char* hex_string= "0123456789ABCDEF";
00322 
00323 void
00324 printer_rep::make_tex_char (string name, unsigned char c, glyph gl) {
00325   // cout << "Make char " << (int) c << " of " << name << "\n";
00326   string char_name (name * "-" * as_string ((int) c));
00327   if (tex_chars->contains (char_name)) return;
00328   if (!tex_fonts->contains (name)) {
00329     tex_fonts (name)= "F" * as_string (nfonts);
00330     tex_font_chars (name)= array<int> (0);
00331     nfonts++;
00332   }
00333   tex_font_chars (name) << ((int) c);
00334 
00335   string hex_code;
00336   int i, j, count=0, cur= 0;
00337   for (j=0; j < gl->height; j++)
00338     for (i=0; i < ((gl->width+7) & (-8)); i++) {
00339       cur= cur << 1;
00340       if ((i<gl->width) && (gl->get_x(i,j)>0)) cur++;
00341       count++;
00342       if (count==4) {
00343         hex_code << hex_string[cur];
00344         cur  = 0;
00345         count= 0;
00346       }
00347     }
00348 
00349   int d1= gl->width;
00350   int d2= gl->height;
00351   int d3= 130+ gl->xoff;
00352   int d4= 126+ gl->yoff;
00353   int d5= gl->lwidth;
00354   if ((d1<256) && (d2<256) && (d3<256) && (d4<256) && (d5<256)) {
00355     hex_code << as_hexadecimal (d1, 2) << as_hexadecimal (d2, 2)
00356             << as_hexadecimal (d3, 2) << as_hexadecimal (d4, 2)
00357             << as_hexadecimal (d5, 2);
00358     hex_code= "<" * hex_code * ">";
00359   }
00360   else {
00361     hex_code= "[<" * hex_code * ">";
00362     hex_code << as_string (d1) << " " << as_string (d2) << " "
00363             << as_string (d3) << " " << as_string (d4) << " "
00364             << as_string (d5) << " ";
00365   }
00366 
00367   tex_chars (char_name)= hex_code;
00368   tex_width (char_name)= as_string (d5);
00369 }
00370 
00371 static string
00372 find_ps_font_name (string name, string s) {
00373   int i, n= N(s);
00374   for (i=0; i<n; i++) {
00375     if (test (s, i, "/FontName /")) {
00376       i += 11;
00377       int start= i;
00378       while (i<n && s[i] != ' ') i++;
00379       return s (start, i);
00380     }
00381     while (i<n && s[i] != '\12' && s[i] != '\15') i++;
00382   }
00383   return name;
00384 }
00385 
00386 
00387 #define HEX_PER_LINE 30
00388 
00389 static SI parse_length (string pfb, int& pos) {
00390   QN c4= (QN) pfb[pos++];
00391   QN c3= (QN) pfb[pos++];
00392   QN c2= (QN) pfb[pos++];
00393   QI c1= (QI) pfb[pos++];
00394   return (((((((SI) c1)<<8)+ ((SI) c2))<<8)+ ((SI) c3))<<8)+ c4;
00395 }
00396 
00397 static string pfb_to_pfa (url file) {
00398   //cout << "pfb_to_pfa :" << file << LF;
00399   string pfb, pfa;
00400   QN magic, type = 0;
00401   SI length;
00402   
00403   (void) load_string (file, pfb, true);
00404   int pos = 0, size = N(pfb);
00405   while ((pos < size) && (type != 3)) {
00406     parse (pfb, pos, magic);
00407     //cout << "magic:" << as_hexadecimal(magic,2) << LF ;
00408     if (magic != 128) {
00409       FAILED ("Not a pfb file");
00410     }
00411     parse (pfb, pos, type);
00412     //cout << "type:" << as_hexadecimal(type,2) << LF;
00413     switch (type) {
00414         
00415       case 1 :
00416         // plain text
00417         length = parse_length (pfb, pos);
00418         // parse (pfb, pos, length);
00419         //cout << "plain text of size " << length << LF;
00420         for (int i=0; i <length; i++) {
00421           QI ch;
00422           parse(pfb, pos, ch);
00423           if (ch == '\r') pfa << "\n";
00424           else pfa << ch;
00425         }
00426         break;
00427         
00428       case 2 :
00429         // binary data
00430         length = parse_length (pfb, pos);
00431         //        parse (pfb, pos, length);
00432         //cout << "binary data of size " << length << LF;
00433         for (int i=0; i <length; i++) {
00434           QI ch;
00435           parse(pfb, pos, ch);
00436           pfa << as_hexadecimal (ch, 2);
00437           if ((i+1) % HEX_PER_LINE == 0) pfa << "\n"; 
00438         }
00439         break;
00440         
00441       case 3 :
00442         //cout << "end of file"  << LF;
00443         // end of file
00444         break;
00445         
00446       default : 
00447         FAILED ("Unknown field type while reading PFB file");
00448         break;
00449         
00450     }
00451   }
00452   return pfa;
00453 }
00454 
00455 #undef HEX_PER_LINE
00456 
00457 
00458 
00459 
00460 void
00461 printer_rep::generate_tex_fonts () {
00462   hashset<string> done;
00463   iterator<string> it= iterate (tex_fonts);
00464   while (it->busy ()) {
00465     string fn_name= it->next ();
00466     array<int> a= tex_font_chars [fn_name];
00467     merge_sort (a);
00468 
00469     int i, d, l;
00470     string name = tex_fonts [fn_name], ttf;
00471     int    pos  = search_forwards (".", fn_name);
00472     string root = (pos==-1? fn_name: fn_name (0, pos));
00473 #ifndef OS_WIN32 // we need pfbtopfa
00474     if ((pos!=-1) && ends (fn_name, "tt")) {
00475       int pos2= search_backwards (":", fn_name);
00476       root= fn_name (0, pos2);
00477       url u= tt_font_find (root);
00478       if (suffix (u) == "pfb") {
00479         ttf = pfb_to_pfa (u);
00480       }
00481     }
00482 #endif
00483 
00484     if (ttf != "") {
00485       string ttf_name= find_ps_font_name (root, ttf);
00486       if (!done->contains (root)) {
00487        prologue << "%%BeginFont: " << root << "\n";
00488        prologue << ttf;
00489        prologue << "\n%%EndFont\n";
00490        done->insert (root);
00491       }
00492 
00493       array<string> cum;
00494       cum << "{}" * as_string (N(a));
00495       for (i=0; i<N(a); i++) {
00496         string w= tex_width [fn_name * "-" * as_string (a[i])];
00497         d= (i==0? a[0]: (a[i]-a[i-1]-1));
00498         if (d>0) cum << as_string (d) * "[";
00499         cum << w * " ";
00500       }
00501       d= 255-a[i-1];
00502       if (d>0) cum << as_string (d) * "[";
00503 
00504       int szpos = pos-1;
00505       while ((szpos>0) && is_numeric (fn_name[szpos-1])) szpos--;
00506       double sz = as_double (fn_name (szpos, pos));
00507       double dpi= as_double (fn_name (pos+1, N(fn_name)-2));
00508       string mag= as_string (83.022 * (sz/10.0) * (dpi/600.0));
00509 
00510       string fdef;
00511       for (i=N(cum)-1; i>=0; i--) fdef << cum[i];
00512       fdef= "/" * name * " " * fdef * " " * mag * " /" * ttf_name * " rf";
00513       for (i=0, l=0; i<N(fdef); i++, l++)
00514         if ((l<70) || (fdef[i]!=' ')) prologue << fdef[i];
00515         else { prologue << '\n'; l=-1; }
00516       prologue << "\n";
00517     }
00518     else {
00519       prologue << "/" << tex_fonts [fn_name]
00520               << " " << as_string (N(a))
00521               << " " << as_string (a[N(a)-1]+1) << " df\n";
00522       for (i=0; i<N(a); i++) {
00523         int end;
00524         string hex_code= tex_chars [fn_name * "-" * as_string (a[i])];
00525         for (end=1; end < N(hex_code); end++)
00526           if (hex_code[end-1]=='>') break;
00527         string after= hex_code (end, N(hex_code));
00528         if ((i>0) && (a[i]==(a[i-1]+1))) after << "I";
00529         else after << as_string (a[i]) << " D";
00530         if (i==(N(a)-1)) after << " E";
00531         hex_code= hex_code (0, end);
00532       
00533         int j, l, n= N(hex_code);
00534         for (j=0; j<n; j+=79) {
00535           if (n < (j+79)) prologue << hex_code (j, n);
00536           else prologue << hex_code (j, j+79) << "\n";
00537         }
00538         l= 79-(n%79);
00539         if (l<N(after)) prologue << "\n";
00540         prologue << after << "\n";
00541       }
00542     }
00543   }
00544 }
00545 
00546 /******************************************************************************
00547 * Clipping
00548 ******************************************************************************/
00549 
00550 void
00551 printer_rep::set_clipping (SI x1, SI y1, SI x2, SI y2, bool restore) {
00552   outer_round (x1, y1, x2, y2);
00553   renderer_rep::set_clipping (x1, y1, x2, y2);
00554   if (restore) {
00555     print (PS_CLIP_POP);
00556     cfn= "";
00557   }
00558   else {
00559     print (PS_CLIP_PUSH);
00560     print (x1, y1);
00561     print (x2, y2);
00562     print (PS_CLIP);
00563   }
00564 }
00565   
00566 /******************************************************************************
00567 * graphical routines
00568 ******************************************************************************/
00569 
00570 color
00571 printer_rep::get_color () {
00572   return fg;
00573 }
00574 
00575 color
00576 printer_rep::get_background () {
00577   return bg;
00578 }
00579 
00580 void
00581 printer_rep::set_color (color c) {
00582   if (fg==c) return;
00583   fg= c;
00584   select_color (c);
00585 }
00586 
00587 void
00588 printer_rep::set_background (color c) {
00589   if (bg==c) return;
00590   bg= c;
00591 }
00592 
00593 void
00594 printer_rep::draw (int ch, font_glyphs fn, SI x, SI y) {
00595   glyph gl= fn->get(ch);
00596   if (is_nil (gl)) return;
00597   string name= fn->res_name;
00598   unsigned char c= ch;
00599   if (ch >= 256) {
00600     name= name * "-" * as_string (ch / 256);
00601     c= (unsigned char) (ch & 255);
00602   }
00603   make_tex_char (name, c, gl);
00604   select_tex_font (name);
00605   move_to (x, y);
00606   print ("(" * prepare_text (string ((char) c)) * ")p");
00607   tex_flag= true;
00608   xpos += gl->lwidth;
00609 }
00610 
00611 void
00612 printer_rep::set_line_style (SI w, int type, bool round) {
00613   (void) type;
00614   (void) round;
00615   // if (lw == w) return;
00616   // FIXME: apparently, the line width can be overidden by some of
00617   // the graphical constructs (example file: newimpl.tm, in which
00618   // the second dag was not printed using the right width)
00619   lw= w;
00620   select_line_width (w);
00621 }
00622 
00623 void
00624 printer_rep::line (SI x1, SI y1, SI x2, SI y2) {
00625   print (x1, y1);
00626   print (x2, y2);
00627   print (PS_LINE);
00628 }
00629 
00630 void
00631 printer_rep::lines (array<SI> x, array<SI> y) {
00632   int i, n= N(x);
00633   if ((N(y) != n) || (n<1)) return;
00634   print (x[0], y[0]);
00635   print (PS_POL_START);
00636   for (i=1; i<n; i++) {
00637     print (x[i], y[i]);
00638     print (PS_POL_NEXT);
00639   }
00640   print (PS_STROKE);
00641 }
00642 
00643 void
00644 printer_rep::clear (SI x1, SI y1, SI x2, SI y2) {
00645   select_color (bg);
00646   print (x1, y1);
00647   print (x2, y2);
00648   print (PS_FILL);
00649   select_color (fg);
00650 }
00651 
00652 void
00653 printer_rep::fill (SI x1, SI y1, SI x2, SI y2) {
00654   if ((x1<x2) && (y1<y2)) {
00655     print (x1, y1);
00656     print (x2, y2);
00657     print (PS_FILL);
00658   }
00659 }
00660 
00661 void
00662 printer_rep::arc (SI x1, SI y1, SI x2, SI y2, int alpha, int delta) {
00663   print ((x1+x2)/2, (y1+y2)/2);
00664   print (as_string ((x2-x1)/(2*PIXEL)));
00665   print (as_string ((y1-y2)/(2*PIXEL)));
00666   print (as_string (((double) alpha)/64));
00667   print (as_string (((double) (alpha+delta))/64));
00668   print (PS_ARC);
00669 }
00670 
00671 void
00672 printer_rep::fill_arc (SI x1, SI y1, SI x2, SI y2, int alpha, int delta) {
00673   print ((x1+x2)/2, (y1+y2)/2);
00674   print (as_string ((x2-x1)/(2*PIXEL)));
00675   print (as_string ((y1-y2)/(2*PIXEL)));
00676   print (as_string (((double) alpha)/64));
00677   print (as_string (((double) (alpha+delta))/64));
00678   print (PS_FILL_ARC);
00679 }
00680 
00681 void
00682 printer_rep::polygon (array<SI> x, array<SI> y, bool convex) {
00683   (void) convex;
00684   int i, n= N(x);
00685   if ((N(y) != n) || (n<1)) return;
00686   print (x[0], y[0]);
00687   print (PS_POL_START);
00688   for (i=1; i<n; i++) {
00689     print (x[i], y[i]);
00690     print (PS_POL_NEXT);
00691   }
00692   print (PS_POL_END);
00693 }
00694 
00695 void
00696 printer_rep::xpm (url file_name, SI x, SI y) {
00697   (void) file_name; (void) x; (void) y;
00698   FAILED ("not yet implemented");
00699 }
00700 
00701 /*
00702 string
00703 incorporate_postscript (string s) {
00704   int i;
00705   string r;
00706   for (i=0; i<N(s); )
00707     if (s[i] == '%') {
00708       for (; (i<N(s)) && (s[i]!='\n'); i++);
00709       if (i<N(s)) i++;
00710     }
00711     else {
00712       for (; (i<N(s)) && (s[i]!='\n'); ) r << s[i++];
00713       if (i<N(s)) { r << s[i++]; }
00714     }
00715   return r;
00716 }
00717 */
00718 
00719 void
00720 printer_rep::image (
00721   url u, SI w, SI h, SI x, SI y,
00722   double cx1, double cy1, double cx2, double cy2, int alpha)
00723 {
00724   (void) alpha; // FIXME
00725   int bx1, by1, bx2, by2;
00726   ps_bounding_box (u, bx1, by1, bx2, by2);
00727   int x1= bx1 + (int) (cx1 * (bx2 - bx1) + 0.5);
00728   int y1= by1 + (int) (cy1 * (by2 - by1) + 0.5);
00729   int x2= bx1 + (int) (cx2 * (bx2 - bx1) + 0.5);
00730   int y2= by1 + (int) (cy2 * (by2 - by1) + 0.5);
00731 
00732   double sc_x= (72.0/dpi) * ((double) (w/PIXEL)) / ((double) (x2-x1));
00733   double sc_y= (72.0/dpi) * ((double) (h/PIXEL)) / ((double) (y2-y1));
00734   cr ();
00735   cr ();
00736 
00737   print (x, y);
00738   print ("a");
00739   print ("currentpoint");
00740   print ("currentpoint");
00741   print ("translate");
00742   print (as_string (sc_x));
00743   print (as_string (sc_y));
00744   print ("scale");
00745   print ("neg");
00746   print ("exch");
00747   print ("neg");
00748   print ("exch");
00749   print ("translate");
00750   print (x, y);
00751   print ("a");
00752   cr ();
00753   /* Black Black 248 3155 a currentpoint currentpoint translate
00754      0.37114 0.37114 scale neg exch neg exch translate 248 3155 a */
00755 
00756   print ("@beginspecial");
00757   print (as_string (x1));
00758   print ("@llx");
00759   print (as_string (y1));
00760   print ("@lly");
00761   print (as_string (x2));
00762   print ("@urx");
00763   print (as_string (y2));
00764   print ("@ury");
00765   print (as_string (10*(x2-x1)));
00766   print ("@rwi");
00767   print ("@clip");
00768   print ("@setspecial");
00769   cr ();
00770   /* @beginspecial 0 @llx 0 @lly 613.291260 @urx 613.291260 @ury 6110 @rwi
00771      @clip @setspecial */
00772   
00773   string ps_image= ps_load (u);
00774   string imtext= is_ramdisc (u)? "inline image": as_string (u);
00775   body << "%%BeginDocument: " << imtext  << "\n";
00776   body << ps_image; // incorporate_postscript (ps_image);
00777   body << "%%EndDocument";
00778   cr ();
00779 
00780   print ("@endspecial");
00781   print (x, y);
00782   print ("a");
00783   print ("currentpoint");
00784   print ("currentpoint");
00785   print ("translate");
00786   print (as_string (1/sc_x));
00787   print (as_string (1/sc_y));
00788   print ("scale");
00789   print ("neg");
00790   print ("exch");
00791   print ("neg");
00792   print ("exch");
00793   print ("translate");
00794   print (x, y);
00795   print ("a");
00796   cr ();
00797   cr ();
00798   
00799   /* @endspecial 248 3155 a currentpoint currentpoint translate
00800      1 0.37114 div 1 0.37114 div scale neg exch neg exch translate
00801      248 3155 a 660 3073 a ... */
00802 
00803   (void) w; (void) h;
00804 }
00805 
00806 void
00807 printer_rep::fetch (SI x1, SI y1, SI x2, SI y2, renderer ren, SI x, SI y) {
00808   (void) x1; (void) y1; (void) x2; (void) y2;
00809   (void) ren; (void) x; (void) y;
00810 }
00811 
00812 void
00813 printer_rep::new_shadow (renderer& ren) {
00814   (void) ren;
00815 }
00816 
00817 void
00818 printer_rep::delete_shadow (renderer& ren) {
00819   (void) ren;
00820 }
00821 
00822 void
00823 printer_rep::get_shadow (renderer ren, SI x1, SI y1, SI x2, SI y2) {
00824   (void) ren; (void) x1; (void) y1; (void) x2; (void) y2;
00825 }
00826 
00827 void
00828 printer_rep::put_shadow (renderer ren, SI x1, SI y1, SI x2, SI y2) {
00829   (void) ren; (void) x1; (void) y1; (void) x2; (void) y2;
00830 }
00831 
00832 void
00833 printer_rep::apply_shadow (SI x1, SI y1, SI x2, SI y2) {
00834   (void) x1; (void) y1; (void) x2; (void) y2;
00835 }
00836 
00837 void
00838 printer_rep::anchor (string label, SI x, SI y) {
00839   string s = "(";
00840   s = s << prepare_text (label) << ") cvn";
00841   if (linelen>0) cr ();
00842   print ("[ /Dest");
00843   print (s);
00844   print ("/View [/XYZ");
00845   print (x, y);
00846   print ("null] /DEST pdfmark");
00847   cr ();
00848 }
00849 
00850 void
00851 printer_rep::href (string label, SI x1, SI y1, SI x2, SI y2) {
00852   if (linelen>0) cr ();
00853   print ("[");
00854   if (starts (label, "#")) {
00855     print ("/Dest");
00856     print ("(" * prepare_text (label) * ") cvn");
00857   }
00858   else {
00859     print ("/Action");
00860     print ("<< /Subtype /URI /URI (" * prepare_text (label) * ") >>");
00861   }
00862   print ("/Rect [");
00863   print (x1 - 5*PIXEL, y1 - 10*PIXEL);
00864   print (x2 + 5*PIXEL, y2 + 10*PIXEL);
00865   print ("]");
00866   print ("/Border [16 16 1 [3 10]] /Color [0.75 0.5 1.0]");
00867   print ("/Subtype /Link");
00868   print ("/ANN pdfmark");
00869   cr ();
00870 }
00871 
00872 /******************************************************************************
00873 * user interface
00874 ******************************************************************************/
00875 
00876 renderer
00877 printer (url ps_file_name, int dpi, int nr_pages,
00878         string page_type, bool landscape, double paper_w, double paper_h)
00879 {
00880   page_type= as_string (call ("correct-paper-size", object (page_type)));
00881   return tm_new<printer_rep> (ps_file_name, dpi, nr_pages,
00882                               page_type, landscape, paper_w, paper_h);
00883 }