Back to index

texmacs  1.0.7.15
pdf_renderer.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : pdf_renderer.cpp
00004 * DESCRIPTION: Renderer for printing pdf graphics
00005 * COPYRIGHT  : (C) 2010 Massimiliano Gubinelli
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 "pdf_renderer.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 "sys_utils.hpp"
00022 #include "convert.hpp"
00023 
00024 
00025 extern "C" {
00026   
00027 #include "dvipdfmx/pdfdoc.h"
00028 #include "dvipdfmx/pdfdev.h"
00029 #include "dvipdfmx/pdfdraw.h"  
00030 #include "dvipdfmx/pdffont.h"
00031 #include "dvipdfmx/pdfximage.h"
00032 #include "dvipdfmx/tfm.h"
00033   
00034 void error_cleanup (void) ;
00035   
00036 };
00037 
00038 
00039 
00040 
00041 
00042   
00043 void error_cleanup (void) 
00044   {
00045     pdf_close_images();  /* delete temporary files */
00046     pdf_error_cleanup();
00047 #if 0
00048     if (pdf_filename) {
00049       remove(pdf_filename);
00050       fprintf(stderr, "\nOutput file removed.\n");
00051     }
00052 #endif
00053   }
00054   
00055 
00056 
00057 
00058 //static double paper_width  = 595.0;
00059 //static double paper_height = 842.0;
00060 static double annot_grow    = 0.0;
00061 static int    bookmark_open = 0;
00062 static int    font_dpi      = 600;
00063 
00064 static long opt_flags = 0;
00065 
00066 
00067 
00068 #define OPT_TPIC_TRANSPARENT_FILL (1 << 1)
00069 #define OPT_CIDFONT_FIXEDPITCH    (1 << 2)
00070 #define OPT_FONTMAP_FIRST_MATCH   (1 << 3)
00071 #define OPT_PDFDOC_NO_DEST_REMOVE (1 << 4)
00072 
00073 static int do_encryption    = 0;
00074 
00075 
00076 static double dvi2pts = 1.0;
00077 
00078 /*
00079  * Precision is essentially limited to 0.01pt.
00080  * See, dev_set_string() in pdfdev.c.
00081  */
00082 static int pdfdecimaldigits = 2;
00083 static char   ignore_colors = 0;
00084 
00085 
00086 
00087 
00088 double
00089 pdf_renderer_rep::to_x (SI x) {
00090   return p * (ox + x);  
00091 }
00092 
00093 double
00094 pdf_renderer_rep::to_y (SI y) {
00095   return  p * ( oy + y);  
00096 }
00097 
00098 void
00099 pdf_renderer_rep::select_color (color c) {;
00100   int r, g, b, a;
00101   get_rgb_color (c, r, g, b, a);
00102   double dr= ((double) r) / 255;
00103   double dg= ((double) g) / 255;
00104   double db= ((double) b) / 255;
00105   double da= ((double) a) / 255; // FIXME: what to do with alpha?
00106   
00107   
00108   pdf_color color;
00109   pdf_color_rgbcolor(&color, dr, dg, db);
00110   pdf_dev_set_color(&color,0,0); // stroke color;
00111   pdf_dev_set_color(&color,0x20,0); // non-stroking color;
00112   
00113 #if 0
00114   HPDF_Page_SetRGBFill (page, dr, dg, db);
00115   HPDF_Page_SetRGBStroke (page, dr, dg, db);
00116 #endif
00117 }
00118 
00119 void
00120 pdf_renderer_rep::select_line_width (SI w) {
00121   double pw= p * w;
00122   //if (pw < 1) pw= 1;
00123 //  HPDF_Page_SetLineWidth (page, pw);
00124 }
00125 
00126 /******************************************************************************
00127 * constructors and destructors
00128 ******************************************************************************/
00129 
00130 pdf_renderer_rep::pdf_renderer_rep (
00131   url pdf_file_name2, int dpi2, int nr_pages2,
00132   string page_type2, bool landscape2, double paper_w2, double paper_h2):
00133     pdf_file_name (pdf_file_name2), dpi (dpi2),
00134     nr_pages (nr_pages2), page_type (page_type2),
00135     landscape (landscape2), paper_w (paper_w2), paper_h (paper_h2),
00136     fg (-1), bg (-1),
00137     lw (-1),  cfn (""), cfid(0),
00138     tex_fonts (0),
00139     image_resources (0)
00140 {
00141 //  dvi2pts = 1.0;
00142   width= default_dpi * paper_w / 2.54;
00143   height= default_dpi * paper_h / 2.54;
00144   dvi2pts = (double)default_dpi / dpi / PIXEL;
00145   p= (double)default_dpi / dpi / PIXEL;
00146 //  p = 1.0;
00147   if (landscape) {
00148     width= (width > height)? width : height;
00149     height= (width > height)? height : width;
00150   } else {
00151     width= (width > height)? height : width;
00152     height= (width > height)? width : height;
00153   }
00154   
00155   set_origin(0, paper_h*dpi*PIXEL/2.54);
00156   
00157  // mem_debug_init();
00158   pdf_init_fontmaps(); /* This must come before parsing options... */
00159   pdf_font_set_dpi(dpi);
00160   pdf_doc_set_creator("TeXmacs");
00161   pdf_set_version(3);
00162   pdf_files_init();
00163   /* Set default paper size here so that all page's can inherite it.
00164    * annot_grow:    Margin of annotation.
00165    * bookmark_open: Miximal depth of open bookmarks.
00166    */
00167   
00168   {
00169     char* _pdf_file_name;
00170     _pdf_file_name= as_charp (concretize (pdf_file_name));
00171 
00172     pdf_open_document(_pdf_file_name, do_encryption,
00173                     width, height, annot_grow, bookmark_open,
00174                     !(opt_flags & OPT_PDFDOC_NO_DEST_REMOVE));
00175   
00176     tm_delete_array (_pdf_file_name);
00177   }
00178   
00179   /* Ignore_colors placed here since
00180    * they are considered as device's capacity.
00181    */
00182   pdf_init_device(dvi2pts, pdfdecimaldigits, ignore_colors);
00183   
00184   
00185   pdf_rect mediabox;
00186   mediabox.llx = 0.0;
00187   mediabox.lly = 0.0;
00188   mediabox.urx = width;
00189   mediabox.ury = height;
00190   
00191   pdf_doc_set_mediabox(0, &mediabox); /* Root node */
00192   
00193   pdf_doc_begin_page(1.0,0.0,0.0);
00194   
00195 
00196   set_clipping (0, (int) ((-dpi*PIXEL*paper_h)/2.54), (int) ((dpi*PIXEL*paper_w)/2.54), 0);
00197   fg  = -1;
00198   bg  = -1;
00199   lw  = -1;
00200   cfn= "Helvetica";
00201   cfid = pdf_dev_locate_font("Helvetica",10);
00202   tex_fonts (cfn)= cfid+1;
00203 }
00204 
00205 pdf_renderer_rep::~pdf_renderer_rep () {
00206   pdf_doc_end_page();
00207   
00208   pdf_files_close();
00209   
00210   /* Order of close... */
00211   pdf_close_device  ();
00212   /* pdf_close_document flushes XObject (image) and other resources. */
00213   pdf_close_document();
00214   
00215   pdf_close_fontmaps(); /* pdf_font may depend on fontmap. */
00216 }
00217 
00218 bool
00219 pdf_renderer_rep::is_printer () {
00220 //  cerr << "is_printer\n";
00221   return true;
00222 }
00223 
00224 void
00225 pdf_renderer_rep::next_page () {
00226 //  cerr << "next_page\n";
00227   pdf_doc_end_page();
00228   pdf_doc_begin_page(1.0,0.0,0.0);
00229 
00230   set_clipping (0, (int) ((-dpi*PIXEL*paper_h)/2.54), (int) ((dpi*PIXEL*paper_w)/2.54), 0);
00231   fg  = -1;
00232   bg  = -1;
00233   lw  = -1;
00234   cfn= "Helvetica";
00235   cfid = tex_fonts(cfn)-1;
00236 }
00237 
00238 /******************************************************************************
00239 * Clipping
00240 ******************************************************************************/
00241 
00242 void
00243 pdf_renderer_rep::set_clipping (SI x1, SI y1, SI x2, SI y2, bool restore) {
00244 //  cerr << "set_clipping\n";
00245   outer_round (x1, y1, x2, y2);
00246   renderer_rep::set_clipping (x1, y1, x2, y2);
00247 /*  if (restore) {
00248     print (PDF_CLIP_POP);
00249     cfn= "";
00250   }
00251   else {
00252     print (PDF_CLIP_PUSH);
00253     print (x1, y1);
00254     print (x2, y2);
00255     print (PDF_CLIP);
00256   }*/
00257 }
00258   
00259 /******************************************************************************
00260 * graphical routines
00261 ******************************************************************************/
00262 
00263 color
00264 pdf_renderer_rep::get_color () {
00265 //  cerr << "get_color\n";
00266   return fg;
00267 }
00268 
00269 color
00270 pdf_renderer_rep::get_background () {
00271 //  cerr << "get_background\n";
00272   return bg;
00273 }
00274 
00275 void
00276 pdf_renderer_rep::set_color (color c) {
00277 //  cerr << "set_color\n";
00278   if (fg==c) return;
00279   fg= c;
00280   select_color (c);
00281 }
00282 
00283 void
00284 pdf_renderer_rep::set_background (color c) {
00285 //  cerr << "set_background\n";
00286   if (bg==c) return;
00287   bg= c;
00288 }
00289 
00290 static double font_size (string name) {
00291   int pos= search_forwards (".", name);
00292   int szpos= pos-1;
00293   while ((szpos>0) && is_numeric (name[szpos-1])) szpos--;
00294   double size= as_double (name (szpos, pos));
00295   if (size == 0) size= 10;
00296   return size;
00297 }
00298 
00299 void
00300 pdf_renderer_rep::draw (int ch, font_glyphs fn, SI x, SI y) {
00301   //cerr << "draw \"" << (char)ch << "\" " << ch << " " << fn->res_name << "\n";
00302   glyph gl= fn->get(ch);
00303   if (is_nil (gl)) return;
00304   if (cfn != fn->res_name) {
00305     
00306   //  cerr << "CHANGE FONT" << LF;
00307     
00308     if (!tex_fonts [fn->res_name]) {
00309       int pos= search_forwards (":", fn->res_name);
00310       string fname= (pos==-1? fn->res_name: fn->res_name (0, pos));
00311       url u = url_none();
00312       {        
00313         //cerr << " try freetype " << LF;
00314         u = tt_font_find(fname);
00315         //cerr << fname << " " << u << LF;
00316       }
00317       if (is_none (u)) {
00318         //cerr << " try pk " << LF;
00319         u= resolve_tex (fn->res_name);
00320         //cerr << fname << " " << u << LF;
00321       }
00322       if (!is_none (u)) {
00323         int pos= search_forwards (".", fn->res_name);
00324         string rname= (pos==-1? fn->res_name: fn->res_name (0, pos));
00325         double fsize= font_size (fn->res_name);
00326 
00327         url utfm =  resolve_tex(fname * ".tfm") ;
00328    
00329         char *_rname = as_charp(fname);
00330         char* _u= as_charp (concretize (u));
00331         char* _utfm= NULL;
00332         if (!is_none(utfm)) _utfm = as_charp (concretize (utfm));
00333         //cout << "DEVFONT " << _rname << " " << fsize << " " << u << " " << utfm << LF;
00334         int font_id = pdf_dev_physical_font(_rname,fsize*dpi*PIXEL/default_dpi,_u,_utfm); 
00335         tm_delete_array(_rname);
00336         tm_delete_array(_u);
00337         if (_utfm) tm_delete_array(_utfm);
00338         if (font_id >= 0) {
00339           tex_fonts(fn->res_name)= font_id+1;
00340         }  else {
00341           cout << "(pdf_renderer) Problems with font: " << fname << " file " << u << LF;
00342         }
00343       }
00344     }
00345     cfn= fn->res_name;
00346     if (tex_fonts [cfn]) {
00347       cfid = tex_fonts(cfn) -1;
00348     } else cfid = 0;
00349   }
00350 
00351   y += oy;  x += ox;
00352 #if 0
00353   pdf_dev_set_raw_glyph(x, y, ch, cfid);
00354 #else
00355   unsigned char buf[2] = { ch, 0 };
00356   fixword width = pdf_dev_string_width(cfid, buf, 1);
00357   pdf_dev_set_string(x, y, buf, 1, width, cfid, 1);
00358 #endif
00359 //  cerr << "char " << ch << " " << x << " " << y << " font " << cfid << " width " << w << LF;
00360   
00361 }
00362 
00363 void
00364 pdf_renderer_rep::set_line_style (SI w, int type, bool round) {
00365 //  cerr << "set_line_style\n";
00366   if (lw == w) return;
00367   lw= w;
00368   select_line_width (w);
00369 }
00370 
00371 void
00372 pdf_renderer_rep::line (SI x1, SI y1, SI x2, SI y2) {
00373 //  cerr << "line\n";
00374   pdf_dev_moveto(to_x (x1), to_y (y1));
00375   pdf_dev_lineto(to_x (x2), to_y (y2));
00376   pdf_dev_stroke();
00377 }
00378 
00379 void
00380 pdf_renderer_rep::lines (array<SI> x, array<SI> y) {
00381 //  cerr << "lines\n";
00382   int i, n= N(x);
00383   if ((N(y) != n) || (n<1)) return;
00384   pdf_dev_moveto(to_x (x[0]), to_y (y[0]));
00385   for (i=1; i<n; i++) {
00386     pdf_dev_lineto(to_x (x[i]), to_y (y[i]));
00387   }
00388   pdf_dev_stroke();
00389 }
00390 
00391 void
00392 pdf_renderer_rep::clear (SI x1, SI y1, SI x2, SI y2) {
00393 //  cerr << "clear\n";
00394   select_color (bg);
00395   double xx1= to_x (min (x1, x2));
00396   double yy1= to_y (min (y1, y2));
00397   double xx2= to_x (max (x1, x2));
00398   double yy2= to_y (max (y1, y2));
00399   pdf_dev_moveto(xx1, yy1);
00400   pdf_dev_lineto(xx2, yy1);
00401   pdf_dev_lineto(xx2, yy2);
00402   pdf_dev_lineto(xx1, yy2);
00403   pdf_dev_closepath();
00404   pdf_dev_fill();  
00405   select_color (fg);
00406 }
00407 
00408 void
00409 pdf_renderer_rep::fill (SI x1, SI y1, SI x2, SI y2) {
00410 //  cerr << "fill\n";
00411   double xx1= to_x (min (x1, x2));
00412   double yy1= to_y (min (y1, y2));
00413   double xx2= to_x (max (x1, x2));
00414   double yy2= to_y (max (y1, y2));
00415   pdf_dev_moveto(xx1, yy1);
00416   pdf_dev_lineto(xx2, yy1);
00417   pdf_dev_lineto(xx2, yy2);
00418   pdf_dev_lineto(xx1, yy2);
00419   pdf_dev_closepath();
00420   pdf_dev_fill();  
00421 }
00422 
00423 void
00424 pdf_renderer_rep::arc (SI x1, SI y1, SI x2, SI y2, int alpha, int delta) {
00425   cerr << "arc\n";
00426 #if 0
00427   double cx= to_x ((x1+x2)/2);
00428   double cy= to_y ((y1+y2)/2);
00429   double rx= (x2-x1);
00430   double ry= (y2-y1);
00431   double a= -(double)alpha / 64 + 90;
00432   double d= -(double)(alpha + delta) / 64 + 90;
00433   cerr << "arc GSave\n", HPDF_Page_GSave (page);
00434   HPDF_Page_SetRGBFill (page, 1, 0, 0);
00435   cerr << "arc Concat\n", HPDF_Page_Concat (page, p * rx, 0, 0, p * ry, cx, cy);
00436   cerr << "arc Arc\n", HPDF_Page_Arc (page, 0, 0, 1, min (a, d), max (a, d));
00437   cerr << "arc LineTo\n", HPDF_Page_LineTo (page, 0, 0);
00438   cerr << "arc ClosePath\n", HPDF_Page_ClosePath (page);
00439   cerr << "arc Clip\n", HPDF_Page_Clip (page);
00440   cerr << "arc EndPath\n", HPDF_Page_EndPath (page);
00441   cerr << "arc Concat\n", HPDF_Page_Concat (page, 1 / p / rx, 0, 0, 1 / p / ry, 0, 0);
00442   cerr << "arc SetLineWidth\n", HPDF_Page_SetLineWidth (page, p * lw);  
00443   cerr << "arc Ellipse\n", HPDF_Page_Ellipse (page, 0, 0, p * rx / 2, p * ry / 2);
00444   cerr << "arc Stroke\n", HPDF_Page_Stroke (page);
00445   cerr << "arc GRestore\n", HPDF_Page_GRestore (page);
00446 #endif
00447 }
00448 
00449 void
00450 pdf_renderer_rep::fill_arc (SI x1, SI y1, SI x2, SI y2, int alpha, int delta) {
00451   cerr << "fill_arc\n";
00452 #if 0
00453   double cx= to_x ((x1+x2)/2);
00454   double cy= to_y ((y1+y2)/2);
00455   double rx= (x2-x1);
00456   double ry= (y2-y1);
00457   double a= -(double)alpha / 64 + 90;
00458   double d= -(double)(alpha + delta) / 64 + 90;
00459   cerr << "arc GSave\n", HPDF_Page_GSave (page);
00460   HPDF_Page_SetRGBFill (page, 1, 0, 0);
00461   cerr << "arc Concat\n", HPDF_Page_Concat (page, p * (rx / 2), 0, 0, p * (ry / 2), cx, cy);
00462   cerr << "arc Arc\n", HPDF_Page_Arc (page, 0, 0, 1, min (a, d), max (a, d));
00463   cerr << "arc EndPath\n", HPDF_Page_ClosePath (page);
00464   cerr << "arc Stroke\n", HPDF_Page_Fill (page);
00465   cerr << "arc GRestore\n", HPDF_Page_GRestore (page);
00466 #endif
00467 }
00468 
00469 void
00470 pdf_renderer_rep::polygon (array<SI> x, array<SI> y, bool convex) {
00471 //  cerr << "polygon\n";
00472   int i, n= N(x);
00473   if ((N(y) != n) || (n<1)) return;
00474   pdf_dev_moveto(to_x (x[0]), to_y (y[0]));
00475   for (i=1; i<n; i++) {
00476      pdf_dev_lineto (to_x (x[i]), to_y (y[i]));
00477   }
00478   pdf_dev_closepath ();
00479   pdf_dev_fill (); //  HPDF_Page_Eofill (page);
00480 }
00481 
00482 void
00483 pdf_renderer_rep::xpm (url file_name, SI x, SI y) {
00484 //  cerr << "xpm\n";
00485 /*  (void) file_name; (void) x; (void) y;
00486   FAILED ("not yet implemented");*/
00487 }
00488 
00489 
00490 /*
00491  * Compute a transformation matrix
00492  * transformations are applied in the following
00493  * order: scaling, rotate, displacement.
00494  */
00495 static void
00496 make_transmatrix (pdf_tmatrix *M,
00497                   double xoffset, double yoffset,
00498                   double xscale,  double yscale,
00499                   double rotate)
00500 {
00501   double c, s;
00502   
00503   c = cos(rotate);
00504   s = sin(rotate);
00505   
00506   M->a =  xscale * c; M->b = xscale * s;
00507   M->c = -yscale * s; M->d = yscale * c;
00508   M->e = xoffset;     M->f = yoffset;
00509 }
00510 
00511 void
00512 pdf_renderer_rep::image (
00513   url u, SI w, SI h, SI x, SI y,
00514   double cx1, double cy1, double cx2, double cy2,
00515   int alpha)
00516 {
00517   //cerr << "image " << u << LF;
00518   (void) alpha; // FIXME
00519   
00520   int bx1, by1, bx2, by2;
00521   ps_bounding_box (u, bx1, by1, bx2, by2);
00522   int x1= bx1 + (int) (cx1 * (bx2 - bx1) + 0.5);
00523   int y1= by1 + (int) (cy1 * (by2 - by1) + 0.5);
00524   int x2= bx1 + (int) (cx2 * (bx2 - bx1) + 0.5);
00525   int y2= by1 + (int) (cy2 * (by2 - by1) + 0.5);
00526   
00527   double sc_x= (72.0/dpi) * ((double) (w/PIXEL)) / ((double) (x2-x1));
00528   double sc_y= (72.0/dpi) * ((double) (h/PIXEL)) / ((double) (y2-y1));
00529   
00530   transform_info ti;
00531   
00532   transform_info_clear(&ti);
00533   
00534   make_transmatrix(&(ti.matrix), 0, 0, sc_x, sc_y, 0.0);
00535   ti.bbox.llx = x1;
00536   ti.bbox.lly = y1;
00537   ti.bbox.urx = x2;
00538   ti.bbox.ury = y2;
00539   ti.flags = INFO_DO_CLIP  | INFO_HAS_USER_BBOX;
00540   
00541   string filename = concretize(u);
00542 
00543   if (!image_resources->contains(filename)) {
00544     url temp= url_temp (".pdf");
00545     string cmd = "ps2pdf13";
00546     system(cmd, u, temp);
00547     cout << temp << LF;
00548     char *_u = as_charp(concretize(temp));
00549     
00550     int form_id = pdf_ximage_findresource(_u, 1, NULL);
00551     if (form_id < 0) {
00552       cerr <<  "Failed to read image file:" << _u << LF;
00553     } else {
00554       image_resources (filename) = form_id;
00555     }
00556     tm_delete_array(_u);
00557     remove (temp);    
00558   }
00559   
00560   if (image_resources->contains(filename)) {
00561     pdf_dev_put_image(image_resources (filename), &ti, to_x(x), to_y(y));
00562   }
00563   
00564 }
00565 
00566 void
00567 pdf_renderer_rep::fetch (SI x1, SI y1, SI x2, SI y2, renderer ren, SI x, SI y) {
00568 //  cerr << "fetch\n";
00569 /*  (void) x1; (void) y1; (void) x2; (void) y2;
00570   (void) ren; (void) x; (void) y;*/
00571 }
00572 
00573 void
00574 pdf_renderer_rep::new_shadow (renderer& ren) {
00575 //  cerr << "new_shadow\n";
00576 //  (void) ren;
00577 }
00578 
00579 void
00580 pdf_renderer_rep::delete_shadow (renderer& ren) {
00581 //  cerr << "delete_shadow\n";
00582 //  (void) ren;
00583 }
00584 
00585 void
00586 pdf_renderer_rep::get_shadow (renderer ren, SI x1, SI y1, SI x2, SI y2) {
00587 //  cerr << "get_shadow\n";
00588 //  (void) ren; (void) x1; (void) y1; (void) x2; (void) y2;
00589 }
00590 
00591 void
00592 pdf_renderer_rep::put_shadow (renderer ren, SI x1, SI y1, SI x2, SI y2) {
00593 // cerr << "put_shadow\n";
00594 //  (void) ren; (void) x1; (void) y1; (void) x2; (void) y2;
00595 }
00596 
00597 void
00598 pdf_renderer_rep::apply_shadow (SI x1, SI y1, SI x2, SI y2) {
00599 //  cerr << "apply_shadow\n";
00600 //  (void) x1; (void) y1; (void) x2; (void) y2;
00601 }
00602 
00603 /******************************************************************************
00604 * user interface
00605 ******************************************************************************/
00606 
00607 renderer
00608 pdf_renderer (url pdf_file_name, int dpi, int nr_pages,
00609         string page_type, 
00610               bool landscape, 
00611               double paper_w, 
00612               double paper_h)
00613 {
00614   return tm_new<pdf_renderer_rep> (pdf_file_name, dpi, nr_pages,
00615                        page_type, landscape, paper_w, paper_h);
00616 }
00617 
00618