home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / pstoedit.zip / source.zip / pstoedit.2.50 / src / drvpdf.cpp < prev    next >
C/C++ Source or Header  |  1996-11-08  |  20KB  |  668 lines

  1. /* 
  2.    drvPDF.cpp : This file is part of pstoedit
  3.    Backend for PDF(TM) format
  4.  
  5.    Copyright (C) 1993,1994,1995,1996 Wolfgang Glunz, Wolfgang.Glunz@zfe.siemens.de
  6.  
  7.     This program is free software; you can redistribute it and/or modify
  8.     it under the terms of the GNU General Public License as published by
  9.     the Free Software Foundation; either version 2 of the License, or
  10.     (at your option) any later version.
  11.  
  12.     This program is distributed in the hope that it will be useful,
  13.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.     GNU General Public License for more details.
  16.  
  17.     You should have received a copy of the GNU General Public License
  18.     along with this program; if not, write to the Free Software
  19.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  
  21. */
  22. /*
  23.    The PDF format and the corresponding operators are copyrighted
  24.    by Adobe Systems, Inc.
  25. */
  26.  
  27. #include "drvpdf.h"
  28. #include <iostream.h>
  29. #include <iomanip.h>
  30. #include <fstream.h>
  31. #include <string.h>
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34.  
  35. #include <time.h>
  36.  
  37. // for sin and cos
  38. #include <math.h>
  39.  
  40. static float rnd(const float f,const float roundnumber)
  41. {
  42.     return ((long int) ( (f * roundnumber) + 0.5 )) / roundnumber;
  43. }
  44.  
  45. static inline float RND3(const float f) { return rnd(f,1000.0f);}
  46.  
  47. static const char *PDFFonts[] = { // predefined Fonts (see page 64 PDF Ref. Manual )
  48.     "Courier", 
  49.     "Courier-Bold",
  50.     "Courier-Oblique", 
  51.     "Courier-BoldOblique", 
  52.     "Helvetica", 
  53.     "Helvetica-Bold",
  54.     "Helvetica-Oblique", 
  55.     "Helvetica-BoldOblique", 
  56.     "Symbol",
  57.     "Times-Roman", 
  58.     "Times-Bold",
  59.     "Times-Italic", 
  60.     "Times-BoldItalic", 
  61.     "ZapfDingbats",
  62.     0
  63.     };
  64.  
  65. const  unsigned int numberOfFonts = sizeof(PDFFonts)/(sizeof(char *)) - 1;
  66.  
  67. const char * const *    drvPDF::knownFontNames() const 
  68. {
  69.     return PDFFonts;
  70. }
  71.  
  72. unsigned int drvPDF::newobject()
  73. {
  74.     currentobject++;
  75.     if (currentobject >= maxobjects) {
  76.         errf << "Sorry, too many objects in this file" << endl;
  77.         exit(1);
  78.     }
  79.     startPosition[currentobject] = outf.tellp() ;
  80.     outf << currentobject  << " 0 obj" << endl;
  81.     return currentobject;
  82. }
  83.  
  84. void drvPDF::endobject()
  85. {
  86.     outf << "endobj" << endl;
  87. }
  88.  
  89. template <class T>
  90. inline T Max(T a,T b)
  91. {
  92.     return (a>b ? a : b);
  93. }
  94.  
  95. template <class T>
  96. inline T Min(T a,T b)
  97. {
  98.     return (a<b ? a : b);
  99. }
  100. void drvPDF::adjustbbox(float x, float y)
  101. {
  102.     bb_llx=Min((int)x,bb_llx);
  103.     bb_lly=Min((int)y,bb_lly);
  104.     bb_urx=Max((int)x,bb_urx);
  105.     bb_ury=Max((int)y,bb_ury);
  106. }
  107.  
  108. // the following two functions avoid unneccessary ET BT sequences
  109. void drvPDF::starttext()
  110. {
  111.     if (!inTextMode) {
  112.         buffer << "BT" << endl;
  113.     inTextMode=true;
  114.     }
  115. }
  116. void drvPDF::endtext()
  117. {
  118.     if (inTextMode) {
  119.         buffer << "ET" << endl;
  120.     inTextMode=false;
  121.     }
  122. }
  123.  
  124.  
  125. static streampos newlinebytes = 1; // how many bytes are a newline (1 or 2)
  126.  
  127. static const char * const stdEncoding = "Standard";
  128.  
  129. const int largeint = 32000;
  130. drvPDF::drvPDF(const char * driveroptions_p,ostream & theoutStream,ostream & theerrStream):
  131.     drvbase(driveroptions_p,theoutStream,theerrStream,1,1,0),
  132.     currentobject(0),
  133.     pagenr(0),
  134.     inTextMode(false),
  135.     encodingName(stdEncoding),
  136.         buffer(tempFile.asOutput()),
  137.     bb_llx(largeint),
  138.     bb_lly(largeint),
  139.     bb_urx(-largeint),
  140.     bb_ury(-largeint)
  141. {
  142.         const char * const header = "%PDF-1.1";
  143.         outf << header << endl;
  144.         newlinebytes = outf.tellp() - strlen(header);
  145.  
  146.          if (verbose) outf << "% Driver options:" << endl;
  147.     for (unsigned int i = 0; i < d_argc ; i++ ) {
  148.         if (verbose) outf << "% " << d_argv[i] << endl; 
  149.         if (strcmp(d_argv[i],"-e") == 0) {
  150.             encodingName = d_argv[i+1];
  151.         }
  152.     }
  153.  
  154. }
  155.  
  156. drvPDF::~drvPDF()
  157. {
  158.     // print trailer
  159.  
  160.     endtext(); // close text if open
  161.  
  162.     unsigned int outlines = newobject();
  163.     outf << "<<" << endl;
  164.     outf << "/Type /Outlines" << endl;
  165.     outf << "/Count 0" << endl;
  166.     outf << ">>" << endl;
  167.     endobject();
  168.  
  169.     unsigned int encoding = newobject();
  170.     // write the diffs between pdf-encoding and WinAnsiEncoding
  171.     outf << "<<" << endl;
  172.     outf << "/Type /Encoding" << endl;
  173.  
  174. #if basedonwinansi
  175. // For some reasons this does not work.
  176. // I haven't seen a working example using the /BaseEncoding feature
  177.     outf << "/BaseEncoding /WinAnsiEncoding" << endl;
  178.     outf << "%/Differences [" << endl;
  179.     outf << "% 24 /breve/caron/circumflex/dotaccent/hungarumlaut/ogonek/ring/tilde" << endl;
  180.     outf << "%127 /.notdef 129 /dagger/daggerdbl/ellipsis/emdash/endash/florin/fraction" << endl;
  181.     outf << "%/guilsinglleft/guilsinglright/minus/perthousand/quotedblbase/quotedblleft" << endl;
  182.     outf << "%/quotedblright/quoteleft/quoteright/quotesinglbase/trademark/fi/fl/Lslash" << endl;
  183.     outf << "%/OE/Scaron/Ydieresis/Zcaron/dotlessi/lslash/scaron/zcaron/.notdef/.notdef/.notdef" << endl;
  184.     outf << "%]" << endl;
  185. #endif
  186.  
  187. // The following part (diffs between standard encoding and pdf encoding)
  188. // was generated by a small PostScript program run through gs
  189. outf << "/Differences [" << endl;
  190. outf << "24 /breve" << endl;
  191. outf << "25 /caron" << endl;
  192. outf << "26 /circumflex" << endl;
  193. outf << "27 /dotaccent" << endl;
  194. outf << "28 /hungarumlaut" << endl;
  195. outf << "29 /ogonek" << endl;
  196. outf << "30 /ring" << endl;
  197. outf << "31 /tilde" << endl;
  198. outf << "39 /quotesingle" << endl;
  199. outf << "45 /minus" << endl;
  200. outf << "96 /grave" << endl;
  201. outf << "128 /bullet" << endl;
  202. outf << "129 /dagger" << endl;
  203. outf << "130 /daggerdbl" << endl;
  204. outf << "131 /ellipsis" << endl;
  205. outf << "132 /emdash" << endl;
  206. outf << "133 /endash" << endl;
  207. outf << "134 /florin" << endl;
  208. outf << "135 /fraction" << endl;
  209. outf << "136 /guilsinglleft" << endl;
  210. outf << "137 /guilsinglright" << endl;
  211. outf << "138 /minus" << endl;
  212. outf << "139 /perthousand" << endl;
  213. outf << "140 /quotedblbase" << endl;
  214. outf << "141 /quotedblleft" << endl;
  215. outf << "142 /quotedblright" << endl;
  216. outf << "143 /quoteleft" << endl;
  217. outf << "144 /quoteright" << endl;
  218. outf << "145 /quotesinglbase" << endl;
  219. outf << "146 /trademark" << endl;
  220. outf << "147 /fi" << endl;
  221. outf << "148 /fl" << endl;
  222. outf << "149 /Lslash" << endl;
  223. outf << "150 /OE" << endl;
  224. outf << "151 /Scaron" << endl;
  225. outf << "152 /Ydieresis" << endl;
  226. outf << "153 /Zcaron" << endl;
  227. outf << "154 /dotlessi" << endl;
  228. outf << "155 /lslash" << endl;
  229. outf << "156 /oe" << endl;
  230. outf << "157 /scaron" << endl;
  231. outf << "158 /zcaron" << endl;
  232. outf << "164 /currency" << endl;
  233. outf << "166 /brokenbar" << endl;
  234. outf << "168 /dieresis" << endl;
  235. outf << "169 /copyright" << endl;
  236. outf << "170 /ordfeminine" << endl;
  237. outf << "172 /logicalnot" << endl;
  238. outf << "174 /registered" << endl;
  239. outf << "175 /macron" << endl;
  240. outf << "176 /degree" << endl;
  241. outf << "177 /plusminus" << endl;
  242. outf << "178 /twosuperior" << endl;
  243. outf << "179 /threesuperior" << endl;
  244. outf << "180 /acute" << endl;
  245. outf << "181 /mu" << endl;
  246. outf << "183 /periodcentered" << endl;
  247. outf << "184 /cedilla" << endl;
  248. outf << "185 /onesuperior" << endl;
  249. outf << "186 /ordmasculine" << endl;
  250. outf << "188 /onequarter" << endl;
  251. outf << "189 /onehalf" << endl;
  252. outf << "190 /threequarters" << endl;
  253. outf << "192 /Agrave" << endl;
  254. outf << "193 /Aacute" << endl;
  255. outf << "194 /Acircumflex" << endl;
  256. outf << "195 /Atilde" << endl;
  257. outf << "196 /Adieresis" << endl;
  258. outf << "197 /Aring" << endl;
  259. outf << "198 /AE" << endl;
  260. outf << "199 /Ccedilla" << endl;
  261. outf << "200 /Egrave" << endl;
  262. outf << "201 /Eacute" << endl;
  263. outf << "202 /Ecircumflex" << endl;
  264. outf << "203 /Edieresis" << endl;
  265. outf << "204 /Igrave" << endl;
  266. outf << "205 /Iacute" << endl;
  267. outf << "206 /Icircumflex" << endl;
  268. outf << "207 /Idieresis" << endl;
  269. outf << "208 /Eth" << endl;
  270. outf << "209 /Ntilde" << endl;
  271. outf << "210 /Ograve" << endl;
  272. outf << "211 /Oacute" << endl;
  273. outf << "212 /Ocircumflex" << endl;
  274. outf << "213 /Otilde" << endl;
  275. outf << "214 /Odieresis" << endl;
  276. outf << "215 /multiply" << endl;
  277. outf << "216 /Oslash" << endl;
  278. outf << "217 /Ugrave" << endl;
  279. outf << "218 /Uacute" << endl;
  280. outf << "219 /Ucircumflex" << endl;
  281. outf << "220 /Udieresis" << endl;
  282. outf << "221 /Yacute" << endl;
  283. outf << "222 /Thorn" << endl;
  284. outf << "223 /germandbls" << endl;
  285. outf << "224 /agrave" << endl;
  286. outf << "225 /aacute" << endl;
  287. outf << "226 /acircumflex" << endl;
  288. outf << "227 /atilde" << endl;
  289. outf << "228 /adieresis" << endl;
  290. outf << "229 /aring" << endl;
  291. outf << "230 /ae" << endl;
  292. outf << "231 /ccedilla" << endl;
  293. outf << "232 /egrave" << endl;
  294. outf << "233 /eacute" << endl;
  295. outf << "234 /ecircumflex" << endl;
  296. outf << "235 /edieresis" << endl;
  297. outf << "236 /igrave" << endl;
  298. outf << "237 /iacute" << endl;
  299. outf << "238 /icircumflex" << endl;
  300. outf << "239 /idieresis" << endl;
  301. outf << "240 /eth" << endl;
  302. outf << "241 /ntilde" << endl;
  303. outf << "242 /ograve" << endl;
  304. outf << "243 /oacute" << endl;
  305. outf << "244 /ocircumflex" << endl;
  306. outf << "245 /otilde" << endl;
  307. outf << "246 /odieresis" << endl;
  308. outf << "247 /divide" << endl;
  309. outf << "248 /oslash" << endl;
  310. outf << "249 /ugrave" << endl;
  311. outf << "250 /uacute" << endl;
  312. outf << "251 /ucircumflex" << endl;
  313. outf << "252 /udieresis" << endl;
  314. outf << "253 /yacute" << endl;
  315. outf << "254 /thorn" << endl;
  316. outf << "255 /ydieresis" << endl;
  317.     outf << "]" << endl;
  318.     outf << ">>" << endl;
  319.     endobject();
  320.  
  321.  
  322.     unsigned int firstFontObject = currentobject + 1;
  323.     // Now define all the 14 standard fonts
  324.     for (unsigned int f = 0 ; f < numberOfFonts ; f++ ) {
  325.         unsigned int font  = newobject();
  326.     unused(&font);
  327.         outf << "<<" << endl;
  328.     outf << "/Type /Font" << endl;
  329.     outf << "/Subtype /Type1" << endl;
  330.     outf << "/Name /F" << f << endl;
  331.     outf << "/BaseFont /" << PDFFonts[f] << endl;
  332.     if ( (f == 8) || (f == 13) ) {
  333.         // the special fonts symbol and ZapfDingbats
  334.  
  335.         // commented out based on a suggestion from Derek Noonburg
  336.         // outf << "/Encoding /" << encodingName << "Encoding" << endl;
  337.     } else {
  338.         outf << "/Encoding " << encoding  << " 0 R" << endl;
  339.     }
  340.     outf << ">>" << endl;
  341.     endobject();
  342.     }
  343.  
  344.     unsigned int catalog = newobject();
  345.     unsigned int pages = currentobject + 2; // will be next after resources;
  346.     outf << "<<" << endl;
  347.     outf << "/Type /Catalog" << endl;
  348.     outf << "/Pages " << pages << " 0 R" << endl;
  349.     outf << "/Outlines " << outlines << " 0 R" << endl;
  350.     outf << ">>" << endl;
  351.     endobject();
  352.  
  353.     unsigned int nrOfPages = pagenr;
  354.  
  355.     const unsigned int resources = newobject();
  356.     outf << "<<" << endl;
  357.     outf <<     "/ProcSet [ /PDF /Text ]" << endl;
  358.     outf <<     "/Font <<" << endl;
  359.         for (unsigned int f2 = 0 ; f2 < numberOfFonts; f2++ ) {
  360.         outf << "/F" << f2 << " " << f2 + firstFontObject << " 0 R" << endl;
  361.         }
  362.     outf <<     ">>" << endl; // closing /Font
  363.     outf << ">>" << endl; // closing /Resources dictionary
  364.     endobject();
  365.  
  366.     pages = newobject();
  367.     outf << "<<" << endl;
  368.     outf << "/Type /Pages" << endl;
  369.     outf << "/Count " << nrOfPages << endl;
  370.     outf << "/Kids [ "; 
  371.     for (unsigned int i = 1 ; i <= nrOfPages; i++ ) {
  372.     outf << i + pages  << " 0 R " ;
  373.     }
  374.     outf << " ] " << endl;
  375.     outf << "/MediaBox [0 0 " << (int) (currentDeviceWidth+0.5) << ' ' << (int) (currentDeviceHeight +0.5) << "]" << endl;
  376. #if 0
  377.     const int width  = bb_urx - bb_llx;
  378.     const int height = bb_ury - bb_lly;
  379.     // heuristically increase shown area by 20% in each direction
  380.     outf << "/MediaBox [" 
  381.      << bb_llx - 0.2 * width  << ' '
  382.      << bb_lly - 0.2 * height << ' '
  383.      << bb_urx + 0.2 * width  << ' '
  384.      << bb_ury + 0.2 * height 
  385.          << " ]" << endl;
  386. #endif
  387.     outf << "/Resources " ;
  388.     outf << resources << " 0 R"<< endl;
  389.     outf << ">>" << endl;
  390.     endobject();
  391.  
  392.  
  393.     // Now write the Page parts for each page
  394.     for (unsigned int j = 1 ; j <= nrOfPages; j++ ) {
  395.         unsigned int pageobject = newobject();
  396.     unused(&pageobject);
  397.     outf << "<<" << endl;
  398.     outf << "/Type /Page" << endl;
  399.     outf << "/Parent " << pages << " 0 R" << endl;
  400.     outf << "/Contents " << j << " 0 R" << endl;
  401.         outf << "/Resources " << resources << " 0 R"<< endl;
  402.     outf << ">>" << endl;
  403.     endobject();
  404.     }
  405.  
  406.     unsigned int infoobject = newobject();
  407.     outf << "<<" << endl;
  408.     time_t t = time(0);
  409.     struct tm *localt = localtime(&t);
  410.     outf << "/CreationDate (D:" 
  411.         << setw(4) << localt->tm_year + 1900 
  412.         << setw(2) << setfill('0') << localt->tm_mon + 1
  413.         << setw(2) << setfill('0') << localt->tm_mday 
  414.         << setw(2) << setfill('0') << localt->tm_hour
  415.         << setw(2) << setfill('0') << localt->tm_min
  416.         << setw(2) << setfill('0') << localt->tm_sec
  417.         << ")" << endl;
  418.     outf << "/Producer (pstoedit by Wolfgang.Glunz@zfe.siemens.de)" << endl;
  419.     outf << ">>" << endl;
  420.     endobject();
  421.  
  422.     streampos xrefbegin = outf.tellp() ;
  423.     outf << "xref" << endl;
  424.     outf << "0 " << currentobject+1 << endl;
  425.     outf << "0000000000 65535 f" ;
  426.     if (newlinebytes == 1) {
  427.         outf << " ";
  428.     }
  429.     outf << endl;
  430.  
  431.     for (unsigned int x = 1; x <= currentobject ; x++ ) {
  432.         outf.width(10);
  433.         outf.fill('0');
  434.         outf << startPosition[x] << " 00000 n";
  435.         if (newlinebytes == 1) {
  436.               outf << " ";
  437.         }
  438.     outf << endl;
  439.     }
  440.     outf << "trailer" << endl;
  441.     outf << "<<" << endl;
  442.     outf << "/Size " << currentobject+1 << endl;
  443.     outf << "/Info " << infoobject << " 0 R" << endl;
  444.     outf << "/Root " << catalog << " 0 R" << endl;
  445.     outf << ">>" << endl;
  446.     outf << "startxref" << endl;
  447.     outf << xrefbegin << endl;
  448.     outf << "%%EOF" << endl;
  449. }
  450.  
  451. void drvPDF::print_coords()
  452. {
  453. //    buffer.precision(3);
  454. //    buffer.setf(ios::fixed);
  455. //    buffer.width(0); // to force minimal width
  456. //    buffer.unsetf(ios::showpoint);
  457.  
  458.     for (unsigned int n = 0; n < numberOfElementsInPath(); n++) {
  459.     const basedrawingelement & elem = pathElement(n);
  460.     switch (elem.getType()) {
  461.         case moveto: {
  462.             const Point & p = elem.getPoint(0);
  463.             adjustbbox(p.x_ + x_offset, p.y_ + y_offset);
  464.                 buffer  << RND3(p.x_ + x_offset) << " " 
  465.                      << RND3(p.y_ + y_offset) << " " ;
  466.             buffer << "m " << endl;
  467.             }
  468.             break;
  469.         case lineto: {
  470.             const Point & p = elem.getPoint(0);
  471.             adjustbbox(p.x_ + x_offset, p.y_ + y_offset);
  472.                 buffer  << RND3(p.x_ + x_offset) << " " 
  473.                      << RND3(p.y_ + y_offset) << " " ;
  474.             buffer << "l " << endl;
  475.             }
  476.             break;
  477.         case closepath: 
  478.             buffer << "h " << endl;
  479.             break;
  480.         case curveto:{
  481.             for (unsigned int cp = 0 ; cp < 3; cp++ ) {
  482.                 const Point & p = elem.getPoint(cp);
  483.                 adjustbbox(p.x_ + x_offset, p.y_ + y_offset);
  484.                     buffer  << RND3(p.x_ + x_offset) << " " 
  485.                          << RND3(p.y_ + y_offset) << " " ;
  486.             }
  487.             buffer << "c " << endl;
  488.             }
  489.             break;
  490.         default:
  491.             errf << "Fatal: unexpected case in drvpdf " << endl;
  492.             abort();
  493.             break;
  494.     }
  495.     }
  496. }
  497.  
  498.  
  499. void drvPDF::open_page()
  500. {
  501.         endtext(); // close text if open
  502.     unsigned int currentpage = newobject();
  503.         unused(¤tpage);
  504.     pagenr++;
  505.     // provide a temp stream
  506.     tempFile.asOutput();
  507. }
  508.  
  509. void drvPDF::close_page()
  510. {
  511.         endtext(); // close text if open
  512.  
  513.     streampos endpos = buffer.tellp();
  514.     outf << "<<" << endl;
  515.     outf << "/Length " << endpos << endl;
  516.     outf << ">>" << endl;
  517.     outf << "stream" << endl;
  518.     ifstream & instream = tempFile.asInput();
  519.     copy_file(instream,outf);
  520. //    int ret = 0;
  521. //    while ( (ret = instream.get()) != EOF ) {
  522. //        outf << (char) ret ;
  523. //    }
  524.     outf << "endstream" << endl;
  525.  
  526.         endobject();
  527. }
  528.  
  529. static int getFontNumber(const char * const fontname) {
  530.     const unsigned int fntlength = strlen(fontname);
  531.     for (unsigned int i=0; i < numberOfFonts; i++) {
  532.         const unsigned int pdfFntLengh = strlen(PDFFonts[i]);
  533.     if (fntlength == pdfFntLengh ) { 
  534.         if (strncmp(fontname,PDFFonts[i],fntlength) == 0) {
  535.         return i;
  536.         }
  537.     }
  538.     }
  539.     return -1;
  540. }
  541.  
  542. static int getSubStringFontNumber(const char * const fontname) {
  543.     // searches for a font name which is the longest substring of the current font name
  544.     int index = -1;
  545.     int longest = -1;
  546.     int fntlength = strlen(fontname);
  547.     for (unsigned int i=0; i < numberOfFonts; i++) {
  548.         int pdfFntLength = strlen(PDFFonts[i]);
  549.     if (fntlength >= pdfFntLength ) { 
  550.         if (strncmp(fontname,PDFFonts[i],pdfFntLength) == 0) {
  551.         if (pdfFntLength > longest) {
  552.             longest = pdfFntLength;
  553.             index = i;
  554.         }
  555.         }
  556.     }
  557.     }
  558.     return index;
  559. }
  560.  
  561. void drvPDF::show_text(const TextInfo & textinfo)
  562. {
  563.     const float toRadians = 3.14159265359f / 180.0f;
  564.     const float angleInRadians = textinfo.currentFontAngle * toRadians;
  565.     int PDFFontNum = getFontNumber(textinfo.currentFontName.value());
  566.     if (PDFFontNum == -1) {
  567.     PDFFontNum = getSubStringFontNumber(textinfo.currentFontName.value());
  568.         if (PDFFontNum == -1) {
  569.         errf << "Warning, unsupported font " << textinfo.currentFontName.value() << ", using Courier instead" << endl;
  570.         PDFFontNum = 0; // Courier
  571.     } else {
  572.         errf << "Warning, unsupported font " << textinfo.currentFontName.value() << ", using " << PDFFonts[PDFFontNum] << " instead" << endl;
  573.     }
  574.     } 
  575.     starttext();
  576.     // previously we used currentFontSize for SX and SY
  577.     // and fontsize 1 in Tm, now we use the fontsize in tm and set
  578.     // sx and sy to 1
  579.     const float Sx = 1.0f; // textinfo.currentFontSize;
  580.     const float Sy = 1.0f; // textinfo.currentFontSize;
  581.     buffer << "/F" << PDFFontNum << ' ' << textinfo.currentFontSize << " Tf" << endl; // use size 1 and scale via Tm
  582.     const float cosphi = (float) cos(angleInRadians);
  583.     const float sinphi = (float) sin(angleInRadians);
  584.     // OK, we could get the real transformation matrix from the interpreter,
  585.     // but this approximation should do it in most cases.
  586. //    buffer.precision(3);
  587. //    buffer.setf(ios::fixed);
  588. //    buffer.width(0); // to force minimal width
  589. //    buffer.unsetf(ios::showpoint);
  590.  
  591.     adjustbbox(textinfo.x + x_offset, textinfo.y + y_offset);
  592.     buffer << RND3(Sx * cosphi)  << " "
  593.        << RND3(Sx * sinphi)  << " "
  594.        << RND3(-Sy * sinphi) << " "
  595.        << RND3(Sy * cosphi)  << " "
  596.        << RND3(textinfo.x + x_offset) << " "
  597.        << RND3(textinfo.y + y_offset) << " Tm" << endl;
  598.     buffer << RND3(textinfo.currentR) << " " << RND3(textinfo.currentG) << " " << RND3(textinfo.currentB) << " rg" << endl;
  599.     buffer << RND3(textinfo.cx) << ' ' << RND3(textinfo.ax) << ' ';
  600.     buffer << "(" ;
  601.     const char * start_of_text = textinfo.thetext;
  602.     while (*start_of_text) {
  603.         if ((*start_of_text == '(') || 
  604.             (*start_of_text == ')') ||
  605.             (*start_of_text == '\\')) {
  606.         buffer << '\\';
  607.         }
  608.         buffer << *start_of_text;
  609.         start_of_text++;
  610.     }
  611.     buffer << ") \""  << endl;
  612. //    buffer << ") Tj"  << endl;
  613.     // endtext(); // not done here to avoid ET BT, done on demand 
  614. }
  615. void drvPDF::show_path()
  616. {
  617.     // add_to_page(); // is done in drvbase !! 
  618.     endtext(); // close text if open
  619.     char * setrgbcolor;
  620.     char * drawingop;
  621.     switch (currentShowType() ) {
  622.     case drvbase::stroke : 
  623.       // it's a stroke
  624.       drawingop  = "S";
  625.       setrgbcolor = "RG";
  626.       break;
  627.     case drvbase::fill :
  628.       drawingop  = "f";
  629.       setrgbcolor = "rg";
  630.       break;
  631.     case drvbase::eofill :
  632.       drawingop  = "f*";
  633.       setrgbcolor = "rg";
  634.       break;
  635.     default: 
  636.     // cannot happen
  637.       errf << "unexpected ShowType " << (int) currentShowType() << endl;
  638.       exit(1);
  639.       break;
  640.     }
  641. //    buffer.precision(3);
  642. //    buffer.setf(ios::fixed);
  643. //    buffer.width(0); // to force minimal width
  644. //    buffer.unsetf(ios::showpoint);
  645.  
  646.     if (verbose) {
  647.         buffer << "% path " << pathnumber << endl;
  648.     }
  649.     buffer << RND3(currentR()) << " " << RND3(currentG()) << " " << RND3(currentB()) << " " << setrgbcolor << endl;
  650.     buffer << currentLineWidth() << " w" << endl;
  651.     buffer << currentLineCap()   << " J" << endl;
  652.     buffer << dashPattern()      << " d" << endl;
  653.     print_coords();
  654.     buffer << drawingop << endl;
  655. }
  656.  
  657. void drvPDF::show_rectangle(
  658.                 const float llx, const float lly, const float urx, const float ury)
  659. {
  660.  // just do show_polyline for a first guess
  661.   unused(&llx);
  662.   unused(&lly);
  663.   unused(&urx);
  664.   unused(&ury);
  665.     endtext(); // close text if open
  666.  show_path();
  667. }
  668.