PageRenderTime 58ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/wx.mod/wxpdfdocument.mod/src/pdfdoc.cpp

http://wxmax.googlecode.com/
C++ | 2230 lines | 1903 code | 198 blank | 129 comment | 403 complexity | 212f807030bc617240d1770a41cb021c MD5 | raw file
Possible License(s): Unlicense, GPL-2.0
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Name: pdfdoc.cpp
  3. // Purpose: Implementation of wxPdfDocument (public methods)
  4. // Author: Ulrich Telle
  5. // Modified by:
  6. // Created: 2005-08-04
  7. // Copyright: (c) Ulrich Telle
  8. // Licence: wxWindows licence
  9. ///////////////////////////////////////////////////////////////////////////////
  10. /// \file pdfdoc.cpp Implementation of the wxPdfDoc class
  11. // For compilers that support precompilation, includes <wx/wx.h>.
  12. #include <wx/wxprec.h>
  13. #ifdef __BORLANDC__
  14. #pragma hdrstop
  15. #endif
  16. #ifndef WX_PRECOMP
  17. #include <wx/wx.h>
  18. #endif
  19. #include <wx/image.h>
  20. #include <wx/paper.h>
  21. #include "wx/pdfdoc.h"
  22. #include "wx/pdfform.h"
  23. #include "wx/pdfgraphics.h"
  24. #include "wx/pdftemplate.h"
  25. // ----------------------------------------------------------------------------
  26. // wxPdfDocument: class representing a PDF document
  27. // ----------------------------------------------------------------------------
  28. wxPdfDocument::wxPdfDocument(int orientation, const wxString& unit, wxPaperSize format)
  29. {
  30. // Allocate arrays
  31. m_currentFont = NULL;
  32. m_page = 0;
  33. m_n = 2;
  34. m_offsets = new wxPdfOffsetHashMap();
  35. m_pages = new wxPdfPageHashMap();
  36. m_orientationChanges = new wxPdfBoolHashMap();
  37. m_state = 0;
  38. InitializeCoreFonts();
  39. m_fonts = new wxPdfFontHashMap();
  40. m_images = new wxPdfImageHashMap();
  41. m_pageLinks = new wxPdfPageLinksMap();
  42. m_links = new wxPdfLinkHashMap();
  43. m_namedLinks = new wxPdfNamedLinksMap();
  44. m_diffs = new wxPdfDiffHashMap();
  45. m_extGStates = new wxPdfExtGStateMap();
  46. m_extGSLookup = new wxPdfExtGSLookupMap();
  47. m_currentExtGState = 0;
  48. m_gradients = new wxPdfGradientMap();
  49. m_annotations = new wxPdfAnnotationsMap();
  50. m_formAnnotations = new wxPdfFormAnnotsMap();
  51. m_formFields = new wxPdfFormFieldsMap();
  52. m_radioGroups = new wxPdfRadioGroupMap();
  53. m_templates = new wxPdfTemplatesMap();
  54. m_parsers = new wxPdfParserMap();
  55. m_spotColors = new wxPdfSpotColourMap();
  56. m_outlineRoot = -1;
  57. m_maxOutlineLevel = 0;
  58. m_inFooter = false;
  59. m_lasth = 0;
  60. m_fontFamily = _T("");
  61. m_fontStyle = _T("");
  62. m_fontSizePt = 12;
  63. m_decoration = wxPDF_FONT_NORMAL;
  64. m_fontSubsetting = true;
  65. m_drawColor = wxPdfColour();
  66. m_fillColor = wxPdfColour();
  67. m_textColor = wxPdfColour();
  68. m_colorFlag = false;
  69. m_ws = 0;
  70. // Scale factor
  71. if (unit == _T("pt"))
  72. {
  73. m_k = 1.;
  74. }
  75. else if (unit == _T("in"))
  76. {
  77. m_k = 72.;
  78. }
  79. else if (unit == _T("cm"))
  80. {
  81. m_k = 72. / 2.54;
  82. }
  83. else // if (unit == "mm") or unknown
  84. {
  85. m_k = 72. / 25.4;
  86. }
  87. // Initialize image scale factor
  88. m_imgscale = 1.;
  89. // Page format
  90. wxPrintPaperDatabase* printPaperDatabase = new wxPrintPaperDatabase;
  91. printPaperDatabase->CreateDatabase();
  92. wxPrintPaperType* paperType = printPaperDatabase->FindPaperType(format);
  93. if (paperType == NULL)
  94. {
  95. paperType = printPaperDatabase->FindPaperType(wxPAPER_A4);
  96. }
  97. wxSize paperSize = paperType->GetSize();
  98. m_fwPt = paperSize.GetWidth() / 254. * 72.;
  99. m_fhPt = paperSize.GetHeight() / 254. * 72.;
  100. delete printPaperDatabase;
  101. m_fw = m_fwPt / m_k;
  102. m_fh = m_fhPt / m_k;
  103. // Page orientation
  104. if (orientation == wxLANDSCAPE)
  105. {
  106. m_defOrientation = wxLANDSCAPE;
  107. m_wPt = m_fhPt;
  108. m_hPt = m_fwPt;
  109. }
  110. else // orientation == wxPORTRAIT or unknown
  111. {
  112. m_defOrientation = wxPORTRAIT;
  113. m_wPt = m_fwPt;
  114. m_hPt = m_fhPt;
  115. }
  116. m_curOrientation = m_defOrientation;
  117. m_w = m_wPt / m_k;
  118. m_h = m_hPt / m_k;
  119. m_angle = 0;
  120. m_inTransform = 0;
  121. // Page margins (1 cm)
  122. double margin = 28.35 / m_k;
  123. SetMargins(margin, margin);
  124. // Interior cell margin (1 mm)
  125. m_cMargin = margin / 10;
  126. // Line width (0.2 mm)
  127. m_lineWidth = .567 / m_k;
  128. // Automatic page break
  129. SetAutoPageBreak(true, 2*margin);
  130. // Full width display mode
  131. SetDisplayMode(wxPDF_ZOOM_FULLWIDTH);
  132. m_zoomFactor = 100.;
  133. // Default viewer preferences
  134. m_viewerPrefs = 0;
  135. // Enable compression
  136. SetCompression(true);
  137. // Set default PDF version number
  138. m_PDFVersion = _T("1.3");
  139. m_importVersion = m_PDFVersion;
  140. m_encrypted = false;
  141. m_encryptor = NULL;
  142. m_javascript = wxEmptyString;
  143. m_inTemplate = false;
  144. m_templateId = 0;
  145. m_templatePrefix = _T("/TPL");
  146. m_currentParser = NULL;
  147. m_currentSource = wxEmptyString;
  148. SetFontPath();
  149. SetFont(_T("ZapfDingBats"), _T(""), 9);
  150. m_zapfdingbats = m_currentFont->GetIndex();
  151. }
  152. wxPdfDocument::~wxPdfDocument()
  153. {
  154. delete m_coreFonts;
  155. wxPdfFontHashMap::iterator font = m_fonts->begin();
  156. for (font = m_fonts->begin(); font != m_fonts->end(); font++)
  157. {
  158. if (font->second != NULL)
  159. {
  160. delete font->second;
  161. }
  162. }
  163. delete m_fonts;
  164. wxPdfImageHashMap::iterator image = m_images->begin();
  165. for (image = m_images->begin(); image != m_images->end(); image++)
  166. {
  167. if (image->second != NULL)
  168. {
  169. delete image->second;
  170. }
  171. }
  172. delete m_images;
  173. wxPdfPageHashMap::iterator page = m_pages->begin();
  174. for (page = m_pages->begin(); page != m_pages->end(); page++)
  175. {
  176. if (page->second != NULL)
  177. {
  178. delete page->second;
  179. }
  180. }
  181. delete m_pages;
  182. wxPdfPageLinksMap::iterator pageLinks = m_pageLinks->begin();
  183. for (pageLinks = m_pageLinks->begin(); pageLinks != m_pageLinks->end(); pageLinks++)
  184. {
  185. if (pageLinks->second != NULL)
  186. {
  187. delete pageLinks->second;
  188. }
  189. }
  190. delete m_pageLinks;
  191. wxPdfLinkHashMap::iterator link = m_links->begin();
  192. for (link = m_links->begin(); link != m_links->end(); link++)
  193. {
  194. if (link->second != NULL)
  195. {
  196. delete link->second;
  197. }
  198. }
  199. delete m_links;
  200. delete m_namedLinks;
  201. size_t j;
  202. for (j = 0; j < m_outlines.GetCount(); j++)
  203. {
  204. wxPdfBookmark* bookmark = (wxPdfBookmark*) m_outlines[j];
  205. delete bookmark;
  206. }
  207. wxPdfDiffHashMap::iterator diff = m_diffs->begin();
  208. for (diff = m_diffs->begin(); diff != m_diffs->end(); diff++)
  209. {
  210. if (diff->second != NULL)
  211. {
  212. delete diff->second;
  213. }
  214. }
  215. delete m_diffs;
  216. wxPdfExtGStateMap::iterator extGState = m_extGStates->begin();
  217. for (extGState = m_extGStates->begin(); extGState != m_extGStates->end(); extGState++)
  218. {
  219. if (extGState->second != NULL)
  220. {
  221. delete extGState->second;
  222. }
  223. }
  224. delete m_extGStates;
  225. delete m_extGSLookup;
  226. wxPdfGradientMap::iterator gradient = m_gradients->begin();
  227. for (gradient = m_gradients->begin(); gradient != m_gradients->end(); gradient++)
  228. {
  229. if (gradient->second != NULL)
  230. {
  231. delete gradient->second;
  232. }
  233. }
  234. delete m_gradients;
  235. wxPdfAnnotationsMap::iterator annotation = m_annotations->begin();
  236. for (annotation = m_annotations->begin(); annotation != m_annotations->end(); annotation++)
  237. {
  238. if (annotation->second != NULL)
  239. {
  240. delete annotation->second;
  241. }
  242. }
  243. delete m_annotations;
  244. wxPdfFormAnnotsMap::iterator formAnnotation = m_formAnnotations->begin();
  245. for (formAnnotation = m_formAnnotations->begin(); formAnnotation != m_formAnnotations->end(); formAnnotation++)
  246. {
  247. if (formAnnotation->second != NULL)
  248. {
  249. delete formAnnotation->second;
  250. }
  251. }
  252. delete m_formAnnotations;
  253. wxPdfFormFieldsMap::iterator formField = m_formFields->begin();
  254. for (formField = m_formFields->begin(); formField != m_formFields->end(); formField++)
  255. {
  256. if (formField->second != NULL)
  257. {
  258. delete formField->second;
  259. }
  260. }
  261. delete m_formFields;
  262. wxPdfRadioGroupMap::iterator radioGroup = m_radioGroups->begin();
  263. for (radioGroup = m_radioGroups->begin(); radioGroup != m_radioGroups->end(); radioGroup++)
  264. {
  265. if (radioGroup->second != NULL)
  266. {
  267. delete radioGroup->second;
  268. }
  269. }
  270. delete m_radioGroups;
  271. wxPdfTemplatesMap::iterator templateIter = m_templates->begin();
  272. for (templateIter = m_templates->begin(); templateIter != m_templates->end(); templateIter++)
  273. {
  274. if (templateIter->second != NULL)
  275. {
  276. delete templateIter->second;
  277. }
  278. }
  279. delete m_templates;
  280. wxPdfParserMap::iterator parser = m_parsers->begin();
  281. for (parser = m_parsers->begin(); parser != m_parsers->end(); parser++)
  282. {
  283. if (parser->second != NULL)
  284. {
  285. delete parser->second;
  286. }
  287. }
  288. delete m_parsers;
  289. wxPdfSpotColourMap::iterator spotColor = m_spotColors->begin();
  290. for (spotColor = m_spotColors->begin(); spotColor != m_spotColors->end(); spotColor++)
  291. {
  292. if (spotColor->second != NULL)
  293. {
  294. delete spotColor->second;
  295. }
  296. }
  297. delete m_spotColors;
  298. delete m_orientationChanges;
  299. delete m_offsets;
  300. if (m_encryptor != NULL)
  301. {
  302. delete m_encryptor;
  303. }
  304. }
  305. // --- Public methods
  306. void
  307. wxPdfDocument::SetProtection(int permissions,
  308. const wxString& userPassword,
  309. const wxString& ownerPassword,
  310. wxPdfEncryptionMethod encryptionMethod,
  311. int keyLength)
  312. {
  313. if (m_encryptor == NULL)
  314. {
  315. int revision = (keyLength > 0) ? 3 : 2;
  316. switch (encryptionMethod)
  317. {
  318. case wxPDF_ENCRYPTION_AESV2:
  319. revision = 4;
  320. if (m_PDFVersion < _T("1.6"))
  321. {
  322. m_PDFVersion = _T("1.6");
  323. }
  324. break;
  325. case wxPDF_ENCRYPTION_RC4V2:
  326. revision = 3;
  327. break;
  328. case wxPDF_ENCRYPTION_RC4V1:
  329. default:
  330. revision = 2;
  331. break;
  332. }
  333. m_encryptor = new wxPdfEncrypt(revision, keyLength);
  334. m_encrypted = true;
  335. int allowedFlags = wxPDF_PERMISSION_PRINT | wxPDF_PERMISSION_MODIFY |
  336. wxPDF_PERMISSION_COPY | wxPDF_PERMISSION_ANNOT;
  337. int protection = 192;
  338. protection += (permissions & allowedFlags);
  339. wxString ownerPswd = ownerPassword;
  340. if (ownerPswd.Length() == 0)
  341. {
  342. ownerPswd = wxPdfDocument::GetUniqueId(_T("wxPdfDoc"));
  343. }
  344. m_encryptor->GenerateEncryptionKey(userPassword, ownerPswd, protection);
  345. }
  346. }
  347. void
  348. wxPdfDocument::SetImageScale(double scale)
  349. {
  350. m_imgscale = scale;
  351. }
  352. double
  353. wxPdfDocument::GetImageScale()
  354. {
  355. return m_imgscale;
  356. }
  357. double
  358. wxPdfDocument::GetPageWidth()
  359. {
  360. return m_w;
  361. }
  362. double
  363. wxPdfDocument::GetPageHeight()
  364. {
  365. return m_h;
  366. }
  367. double
  368. wxPdfDocument::GetBreakMargin()
  369. {
  370. return m_bMargin;
  371. }
  372. double
  373. wxPdfDocument::GetScaleFactor()
  374. {
  375. return m_k;
  376. }
  377. void
  378. wxPdfDocument::AliasNbPages(const wxString& alias)
  379. {
  380. // Define an alias for total number of pages
  381. m_aliasNbPages = alias;
  382. }
  383. void
  384. wxPdfDocument::Open()
  385. {
  386. // Begin document
  387. m_state = 1;
  388. }
  389. void
  390. wxPdfDocument::AddPage(int orientation)
  391. {
  392. if (m_inTemplate)
  393. {
  394. wxLogError(_("wxPdfDocument::AddPage: Adding pages in templates is impossible. Current template ID is %d."), m_templateId);
  395. return;
  396. }
  397. // Start a new page
  398. if (m_state == 0)
  399. {
  400. Open();
  401. }
  402. wxString family = m_fontFamily;
  403. wxString style = m_fontStyle;
  404. if (m_decoration & wxPDF_FONT_UNDERLINE)
  405. {
  406. style += wxString(_T("U"));
  407. }
  408. if (m_decoration & wxPDF_FONT_OVERLINE)
  409. {
  410. style += wxString(_T("O"));
  411. }
  412. if (m_decoration & wxPDF_FONT_STRIKEOUT)
  413. {
  414. style += wxString(_T("S"));
  415. }
  416. double size = m_fontSizePt;
  417. double lw = m_lineWidth;
  418. wxPdfColour dc = m_drawColor;
  419. wxPdfColour fc = m_fillColor;
  420. wxPdfColour tc = m_textColor;
  421. bool cf = m_colorFlag;
  422. if (m_page > 0)
  423. {
  424. // Page footer
  425. m_inFooter = true;
  426. Footer();
  427. m_inFooter = false;
  428. // Close page
  429. EndPage();
  430. }
  431. // Start new page
  432. BeginPage(orientation);
  433. // Set line cap style to square
  434. Out("2 J");
  435. // Set line width
  436. m_lineWidth = lw;
  437. OutAscii(Double2String(lw*m_k,2)+wxString(_T(" w")));
  438. // Set font
  439. if (family.Length() > 0)
  440. {
  441. SetFont(family, style, size);
  442. }
  443. // Set colors
  444. m_drawColor = dc;
  445. if (dc != wxPdfColour(0))
  446. {
  447. OutAscii(dc.GetColor(true));
  448. }
  449. m_fillColor = fc;
  450. if (fc != wxPdfColour(0))
  451. {
  452. OutAscii(fc.GetColor(false));
  453. }
  454. m_textColor = tc;
  455. m_colorFlag = cf;
  456. // Page header
  457. Header();
  458. // Restore line width
  459. if (m_lineWidth != lw)
  460. {
  461. m_lineWidth = lw;
  462. OutAscii(Double2String(lw*m_k,2)+wxString(_T(" w")));
  463. }
  464. // Restore font
  465. if(family.Length() > 0)
  466. {
  467. SetFont(family, style, size);
  468. }
  469. // Restore colors
  470. if (m_drawColor != dc)
  471. {
  472. m_drawColor = dc;
  473. OutAscii(dc.GetColor(true));
  474. }
  475. if (m_fillColor != fc)
  476. {
  477. m_fillColor = fc;
  478. OutAscii(fc.GetColor(false));
  479. }
  480. m_textColor = tc;
  481. m_colorFlag = cf;
  482. }
  483. void
  484. wxPdfDocument::SetLineWidth(double width)
  485. {
  486. // Set line width
  487. m_lineWidth = width;
  488. if (m_page > 0)
  489. {
  490. OutAscii(Double2String(width*m_k,2)+ wxString(_T(" w")));
  491. }
  492. }
  493. double
  494. wxPdfDocument::GetLineWidth()
  495. {
  496. return m_lineWidth;
  497. }
  498. void
  499. wxPdfDocument::SetFontPath(const wxString& fontPath)
  500. {
  501. if (fontPath != wxEmptyString)
  502. {
  503. m_fontPath = fontPath;
  504. }
  505. else
  506. {
  507. wxString localFontPath;
  508. if (!wxGetEnv(_T("WXPDF_FONTPATH"), &localFontPath))
  509. {
  510. localFontPath = wxGetCwd();
  511. if (!wxEndsWithPathSeparator(localFontPath))
  512. {
  513. localFontPath += wxFILE_SEP_PATH;
  514. }
  515. localFontPath += _T("fonts");
  516. }
  517. m_fontPath = localFontPath;
  518. }
  519. }
  520. bool
  521. wxPdfDocument::AddFont(const wxString& family, const wxString& style, const wxString& file)
  522. {
  523. if (family.Length() == 0) return false;
  524. // Add a TrueType or Type1 font
  525. wxString lcFamily = family.Lower();
  526. wxString lcStyle = style.Lower();
  527. wxString ucStyle = style.Upper();
  528. wxString fileName = file;
  529. if (fileName.Length() == 0)
  530. {
  531. fileName = lcFamily + lcStyle + wxString(_T(".xml"));
  532. fileName.Replace(_T(" "),_T(""));
  533. }
  534. if (ucStyle == _T("IB"))
  535. {
  536. ucStyle = _T("BI");
  537. }
  538. // check if the font has been already added
  539. wxString fontkey = lcFamily + ucStyle;
  540. wxPdfFontHashMap::iterator font = (*m_fonts).find(fontkey);
  541. if (font != (*m_fonts).end())
  542. {
  543. // Font already loaded
  544. return true;
  545. }
  546. // Open font metrics XML file
  547. wxFileName fontFileName(fileName);
  548. fontFileName.MakeAbsolute(GetFontPath());
  549. wxFileSystem fs;
  550. wxFSFile* xmlFontMetrics = fs.OpenFile(fontFileName.GetFullPath());
  551. if (!xmlFontMetrics)
  552. {
  553. // Font metrics XML file not found
  554. wxLogDebug(_T("wxPdfDocument::AddFont: Font metrics file '%s' not found."), fileName.c_str());
  555. return false;
  556. }
  557. // Load the XML file
  558. wxXmlDocument fontMetrics;
  559. bool loaded = fontMetrics.Load(*xmlFontMetrics->GetStream());
  560. delete xmlFontMetrics;
  561. if (!loaded)
  562. {
  563. // Font metrics file loading failed
  564. wxLogDebug(_T("wxPdfDocument::AddFont: Loading of font metrics file '%s' failed."), fileName.c_str());
  565. return false;
  566. }
  567. if (!fontMetrics.IsOk() || fontMetrics.GetRoot()->GetName() != wxT("wxpdfdoc-font-metrics"))
  568. {
  569. // Not a font metrics file
  570. wxLogDebug(_T("wxPdfDocument::AddFont: Font metrics file '%s' invalid."), fileName.c_str());
  571. return false;
  572. }
  573. wxString fontType;
  574. wxXmlNode* root = fontMetrics.GetRoot();
  575. if (!root->GetPropVal(_T("type"), &fontType))
  576. {
  577. // Font type not specified
  578. wxLogDebug(_T("wxPdfDocument::AddFont: Font type not specified for font '%s'."), family.c_str());
  579. return false;
  580. }
  581. int i = (*m_fonts).size() + 1;
  582. wxPdfFont* addedFont = NULL;
  583. if (fontType == _T("TrueType"))
  584. {
  585. addedFont = new wxPdfFontTrueType(i);
  586. }
  587. else if (fontType == _T("Type1"))
  588. {
  589. addedFont = new wxPdfFontType1(i);
  590. }
  591. #if wxUSE_UNICODE
  592. else if (fontType == _T("TrueTypeUnicode"))
  593. {
  594. addedFont = new wxPdfFontTrueTypeUnicode(i);
  595. }
  596. else if (fontType == _T("OpenTypeUnicode"))
  597. {
  598. addedFont = new wxPdfFontOpenTypeUnicode(i);
  599. if (m_PDFVersion < _T("1.6"))
  600. {
  601. m_PDFVersion = _T("1.6");
  602. }
  603. }
  604. else if (fontType == _T("Type0"))
  605. {
  606. addedFont = new wxPdfFontType0(i);
  607. }
  608. #endif
  609. else
  610. {
  611. // Unknown font type
  612. wxLogDebug(_T("wxPdfDocument::AddFont: Unknown font type '%s'."), fontType.c_str());
  613. return false;
  614. }
  615. if (!addedFont->LoadFontMetrics(root))
  616. {
  617. delete addedFont;
  618. return false;
  619. }
  620. addedFont->SetFilePath(fontFileName.GetPath());
  621. (*m_fonts)[fontkey] = addedFont;
  622. if (addedFont->HasDiffs())
  623. {
  624. // Search existing encodings
  625. int d = 0;
  626. int nb = (*m_diffs).size();
  627. for (i = 1; i <= nb; i++)
  628. {
  629. if (*(*m_diffs)[i] == addedFont->GetDiffs())
  630. {
  631. d = i;
  632. break;
  633. }
  634. }
  635. if (d == 0)
  636. {
  637. d = nb + 1;
  638. (*m_diffs)[d] = new wxString(addedFont->GetDiffs());
  639. }
  640. addedFont->SetDiffIndex(d);
  641. }
  642. return true;
  643. }
  644. #if wxUSE_UNICODE
  645. bool
  646. wxPdfDocument::AddFontCJK(const wxString& family)
  647. {
  648. wxString lcFamily = family.Lower();
  649. wxString fontFile = lcFamily + wxString(_T(".xml"));
  650. wxString fontkey = lcFamily;
  651. wxString fontName;
  652. bool valid;
  653. wxPdfFontHashMap::iterator font = (*m_fonts).find(fontkey);
  654. if (font != (*m_fonts).end())
  655. {
  656. return true;
  657. }
  658. valid = AddFont(family, _T(""), fontFile);
  659. if (valid)
  660. {
  661. // Add all available styles (bold, italic and bold-italic)
  662. // For all styles the same font metric file is used, therefore
  663. // the font name has to be changed afterwards to reflect the
  664. // style.
  665. AddFont(family, _T("B"), fontFile);
  666. fontkey = lcFamily + wxString(_T("B"));
  667. font = (*m_fonts).find(fontkey);
  668. fontName = font->second->GetName();
  669. fontName += wxString(_T(",Bold"));
  670. font->second->SetName(fontName);
  671. AddFont(family, _T("I"), fontFile);
  672. fontkey = lcFamily + wxString(_T("I"));
  673. font = (*m_fonts).find(fontkey);
  674. fontName = font->second->GetName();
  675. fontName += wxString(_T(",Italic"));
  676. font->second->SetName(fontName);
  677. AddFont(family, _T("BI"), fontFile);
  678. fontkey = lcFamily + wxString(_T("BI"));
  679. font = (*m_fonts).find(fontkey);
  680. fontName = font->second->GetName();
  681. fontName += wxString(_T(",BoldItalic"));
  682. font->second->SetName(fontName);
  683. }
  684. return valid;
  685. }
  686. #endif // wxUSE_UNICODE
  687. bool
  688. wxPdfDocument::SetFont(const wxString& family, const wxString& style, double size)
  689. {
  690. return SelectFont(family, style, size, true);
  691. }
  692. void
  693. wxPdfDocument::SetFontSize(double size)
  694. {
  695. // Set font size in points
  696. if (m_fontSizePt == size)
  697. {
  698. return;
  699. }
  700. m_fontSizePt = size;
  701. m_fontSize = size / m_k;
  702. if ( m_page > 0)
  703. {
  704. OutAscii(wxString::Format(_T("BT /F%d "),m_currentFont->GetIndex()) +
  705. Double2String(m_fontSizePt,2) + wxString(_T(" Tf ET")));
  706. }
  707. }
  708. const wxPdfFontDescription&
  709. wxPdfDocument::GetFontDescription() const
  710. {
  711. return m_currentFont->GetDesc();
  712. }
  713. const wxString
  714. wxPdfDocument::GetFontFamily()
  715. {
  716. return m_fontFamily;
  717. }
  718. const wxString
  719. wxPdfDocument::GetFontStyle()
  720. {
  721. wxString style = m_fontStyle;
  722. if (m_decoration & wxPDF_FONT_UNDERLINE)
  723. {
  724. style += wxString(_T("U"));
  725. }
  726. if (m_decoration & wxPDF_FONT_OVERLINE)
  727. {
  728. style += wxString(_T("O"));
  729. }
  730. if (m_decoration & wxPDF_FONT_STRIKEOUT)
  731. {
  732. style += wxString(_T("S"));
  733. }
  734. return style;
  735. }
  736. double
  737. wxPdfDocument::GetFontSize()
  738. {
  739. return m_fontSizePt;
  740. }
  741. double
  742. wxPdfDocument::GetStringWidth(const wxString& s)
  743. {
  744. double w = 0;
  745. if (m_currentFont != 0)
  746. {
  747. w = m_currentFont->GetStringWidth(s) * m_fontSize;
  748. }
  749. return w;
  750. }
  751. void
  752. wxPdfDocument::Text(double x, double y, const wxString& txt)
  753. {
  754. // Output a string
  755. if (m_colorFlag)
  756. {
  757. Out("q ", false);
  758. OutAscii(m_textColor.GetColor(false), false);
  759. Out(" ", false);
  760. }
  761. OutAscii(wxString(_T("BT ")) +
  762. Double2String(x*m_k,2) + wxString(_T(" ")) +
  763. Double2String((m_h-y)*m_k,2) + wxString(_T(" Td (")), false);
  764. TextEscape(txt,false);
  765. Out(") Tj ET", false);
  766. if (m_currentFont != 0)
  767. {
  768. m_currentFont->UpdateUsedChars(txt);
  769. }
  770. if ((m_decoration & wxPDF_FONT_DECORATION) && txt.Length() > 0)
  771. {
  772. Out(" ", false);
  773. OutAscii(DoDecoration(x, y, txt), false);
  774. }
  775. if (m_colorFlag)
  776. {
  777. Out(" Q", false);
  778. }
  779. Out("\n", false);
  780. }
  781. void
  782. wxPdfDocument::RotatedText(double x, double y, const wxString& txt, double angle)
  783. {
  784. // Text rotated around its origin
  785. StartTransform();
  786. Rotate(angle, x, y);
  787. Text(x, y, txt);
  788. StopTransform();
  789. }
  790. bool
  791. wxPdfDocument::AcceptPageBreak()
  792. {
  793. // Accept automatic page break or not
  794. return m_autoPageBreak;
  795. }
  796. void
  797. wxPdfDocument::Cell(double w, double h, const wxString& txt, int border, int ln, int align, int fill, const wxPdfLink& link)
  798. {
  799. // Output a cell
  800. double x, y;
  801. double k = m_k;
  802. if (m_y + h > m_pageBreakTrigger && !m_inFooter && AcceptPageBreak())
  803. {
  804. // Automatic page break
  805. x = m_x;
  806. double ws = m_ws;
  807. if (ws > 0)
  808. {
  809. m_ws = 0;
  810. Out("0 Tw");
  811. }
  812. AddPage(m_curOrientation);
  813. m_x = x;
  814. if (ws > 0)
  815. {
  816. m_ws = ws;
  817. OutAscii(Double2String(ws*k,3)+wxString(_T(" Tw")));
  818. }
  819. }
  820. if ( w == 0)
  821. {
  822. w = m_w - m_rMargin - m_x;
  823. }
  824. wxString s = wxEmptyString;
  825. if (fill == 1 || border == wxPDF_BORDER_FRAME)
  826. {
  827. s = Double2String(m_x*k,2) + wxString(_T(" ")) +
  828. Double2String((m_h-m_y)*k,2) + wxString(_T(" ")) +
  829. Double2String(w*k,2) + wxString(_T(" ")) +
  830. Double2String(-h*k,2);
  831. if (fill == 1)
  832. {
  833. if (border == wxPDF_BORDER_FRAME)
  834. {
  835. s += wxString(_T(" re B "));
  836. }
  837. else
  838. {
  839. s += wxString(_T(" re f "));
  840. }
  841. }
  842. else
  843. {
  844. s += wxString(_T(" re S "));
  845. }
  846. }
  847. if (border != wxPDF_BORDER_NONE && border != wxPDF_BORDER_FRAME)
  848. {
  849. x = m_x;
  850. y = m_y;
  851. if (border & wxPDF_BORDER_LEFT)
  852. {
  853. s += Double2String(x*k,2) + wxString(_T(" ")) +
  854. Double2String((m_h-y)*k,2) + wxString(_T(" m ")) +
  855. Double2String(x*k,2) + wxString(_T(" ")) +
  856. Double2String((m_h-(y+h))*k,2) + wxString(_T(" l S "));
  857. }
  858. if (border & wxPDF_BORDER_TOP)
  859. {
  860. s += Double2String(x*k,2) + wxString(_T(" ")) +
  861. Double2String((m_h-y)*k,2) + wxString(_T(" m ")) +
  862. Double2String((x+w)*k,2) + wxString(_T(" ")) +
  863. Double2String((m_h-y)*k,2) + wxString(_T(" l S "));
  864. }
  865. if (border & wxPDF_BORDER_RIGHT)
  866. {
  867. s += Double2String((x+w)*k,2) + wxString(_T(" ")) +
  868. Double2String((m_h-y)*k,2) + wxString(_T(" m ")) +
  869. Double2String((x+w)*k,2) + wxString(_T(" ")) +
  870. Double2String((m_h-(y+h))*k,2) + wxString(_T(" l S "));
  871. }
  872. if (border & wxPDF_BORDER_BOTTOM)
  873. {
  874. s += Double2String(x*k,2) + wxString(_T(" ")) +
  875. Double2String((m_h-(y+h))*k,2) + wxString(_T(" m ")) +
  876. Double2String((x+w)*k,2) + wxString(_T(" ")) +
  877. Double2String((m_h-(y+h))*k,2) + wxString(_T(" l S "));
  878. }
  879. }
  880. if (s.Length() > 0)
  881. {
  882. bool newline = txt.Length() == 0;
  883. OutAscii(s, newline);
  884. s = _T("");
  885. }
  886. if (txt.Length() > 0)
  887. {
  888. double width = GetStringWidth(txt);
  889. double dx;
  890. if (align == wxPDF_ALIGN_RIGHT)
  891. {
  892. dx = w - m_cMargin - width;
  893. }
  894. else if (align == wxPDF_ALIGN_CENTER)
  895. {
  896. dx = (w - width) / 2;
  897. }
  898. else
  899. {
  900. dx = m_cMargin;
  901. }
  902. if (m_colorFlag)
  903. {
  904. s += wxString(_T("q ")) + m_textColor.GetColor(false) + wxString(_T(" "));
  905. }
  906. s += wxString(_T("BT ")) +
  907. Double2String((m_x+dx)*k,2) + wxString(_T(" ")) +
  908. Double2String((m_h-(m_y+.5*h+.3*m_fontSize))*k,2) + wxString(_T(" Td ("));
  909. OutAscii(s,false);
  910. TextEscape(txt,false);
  911. s = _T(") Tj ET");
  912. if (m_currentFont != 0)
  913. {
  914. m_currentFont->UpdateUsedChars(txt);
  915. }
  916. if (m_decoration & wxPDF_FONT_DECORATION)
  917. {
  918. s += wxString(_T(" ")) + DoDecoration(m_x+dx,m_y+.5*h+.3*m_fontSize,txt);
  919. }
  920. if (m_colorFlag)
  921. {
  922. s += wxString(_T(" Q"));
  923. }
  924. if (link.IsValid())
  925. {
  926. Link(m_x+dx,m_y+.5*h-.5*m_fontSize,width,m_fontSize,link);
  927. }
  928. OutAscii(s);
  929. }
  930. m_lasth = h;
  931. if (ln > 0)
  932. {
  933. // Go to next line
  934. m_y += h;
  935. if ( ln == 1)
  936. {
  937. m_x = m_lMargin;
  938. }
  939. }
  940. else
  941. {
  942. m_x += w;
  943. }
  944. }
  945. int
  946. wxPdfDocument::MultiCell(double w, double h, const wxString& txt, int border, int align, int fill, int maxline)
  947. {
  948. // Output text with automatic or explicit line breaks
  949. if (w == 0)
  950. {
  951. w = m_w - m_rMargin - m_x;
  952. }
  953. double wmax = (w - 2 * m_cMargin);
  954. wxString s = txt;
  955. s.Replace(_T("\r"),_T("")); // remove carriage returns
  956. int nb = s.Length();
  957. if (nb > 0 && s[nb-1] == _T('\n'))
  958. {
  959. nb--;
  960. }
  961. int b = wxPDF_BORDER_NONE;
  962. int b2 = wxPDF_BORDER_NONE;
  963. if (border != wxPDF_BORDER_NONE)
  964. {
  965. if (border == wxPDF_BORDER_FRAME)
  966. {
  967. b = wxPDF_BORDER_LEFT | wxPDF_BORDER_RIGHT | wxPDF_BORDER_TOP;
  968. b2 = wxPDF_BORDER_LEFT | wxPDF_BORDER_RIGHT;
  969. }
  970. else
  971. {
  972. b2 = wxPDF_BORDER_NONE;
  973. if (border & wxPDF_BORDER_LEFT)
  974. {
  975. b2 = b2 | wxPDF_BORDER_LEFT;
  976. }
  977. if (border & wxPDF_BORDER_RIGHT)
  978. {
  979. b2 = b2 | wxPDF_BORDER_RIGHT;
  980. }
  981. b = (border & wxPDF_BORDER_TOP) ? b2 | wxPDF_BORDER_TOP : b2;
  982. }
  983. }
  984. int sep = -1;
  985. int i = 0;
  986. int j = 0;
  987. double len = 0;
  988. double ls = 0;
  989. int ns = 0;
  990. int nl = 1;
  991. wxChar c;
  992. while (i < nb)
  993. {
  994. // Get next character
  995. c = s[i];
  996. if (c == _T('\n'))
  997. {
  998. // Explicit line break
  999. if (m_ws > 0)
  1000. {
  1001. m_ws = 0;
  1002. Out("0 Tw");
  1003. }
  1004. Cell(w,h,s.SubString(j,i-1),b,2,align,fill);
  1005. i++;
  1006. sep = -1;
  1007. j = i;
  1008. len = 0;
  1009. ns = 0;
  1010. nl++;
  1011. if (border != wxPDF_BORDER_NONE && nl == 2)
  1012. {
  1013. b = b2;
  1014. }
  1015. if (maxline > 0 && nl > maxline)
  1016. {
  1017. return j;
  1018. }
  1019. continue;
  1020. }
  1021. if (c == _T(' '))
  1022. {
  1023. sep = i;
  1024. ls = len;
  1025. ns++;
  1026. }
  1027. len = GetStringWidth(s.SubString(j, i));
  1028. if (len > wmax)
  1029. {
  1030. // Automatic line break
  1031. if (sep == -1)
  1032. {
  1033. if (i == j)
  1034. {
  1035. i++;
  1036. }
  1037. if (m_ws > 0)
  1038. {
  1039. m_ws=0;
  1040. Out("0 Tw");
  1041. }
  1042. Cell(w,h,s.SubString(j,i-1),b,2,align,fill);
  1043. }
  1044. else
  1045. {
  1046. if (align == wxPDF_ALIGN_JUSTIFY)
  1047. {
  1048. m_ws = (ns > 1) ? (wmax - ls)/(ns-1) : 0;
  1049. OutAscii(Double2String(m_ws*m_k,3)+wxString(_T(" Tw")));
  1050. }
  1051. Cell(w,h,s.SubString(j,sep-1),b,2,align,fill);
  1052. i = sep + 1;
  1053. }
  1054. sep = -1;
  1055. j = i;
  1056. len = 0;
  1057. ns = 0;
  1058. nl++;
  1059. if (border != wxPDF_BORDER_NONE && nl == 2)
  1060. {
  1061. b = b2;
  1062. }
  1063. if (maxline > 0 && nl > maxline)
  1064. {
  1065. return j;
  1066. }
  1067. }
  1068. else
  1069. {
  1070. i++;
  1071. }
  1072. }
  1073. // Last chunk
  1074. if (m_ws > 0)
  1075. {
  1076. m_ws = 0;
  1077. Out("0 Tw");
  1078. }
  1079. if ((border != wxPDF_BORDER_NONE) && (border & wxPDF_BORDER_BOTTOM))
  1080. {
  1081. b = b | wxPDF_BORDER_BOTTOM;
  1082. }
  1083. Cell(w,h,s.SubString(j,i-1),b,2,align,fill);
  1084. m_x = m_lMargin;
  1085. return i;
  1086. }
  1087. int
  1088. wxPdfDocument::LineCount(double w, const wxString& txt)
  1089. {
  1090. // Output text with automatic or explicit line breaks
  1091. if (w == 0)
  1092. {
  1093. w = m_w - m_rMargin - m_x;
  1094. }
  1095. double wmax = (w - 2 * m_cMargin);
  1096. wxString s = txt;
  1097. s.Replace(_T("\r"),_T("")); // remove carriage returns
  1098. int nb = s.Length();
  1099. if (nb > 0 && s[nb-1] == _T('\n'))
  1100. {
  1101. nb--;
  1102. }
  1103. int sep = -1;
  1104. int i = 0;
  1105. int j = 0;
  1106. double len = 0;
  1107. int nl = 1;
  1108. wxChar c;
  1109. while (i < nb)
  1110. {
  1111. // Get next character
  1112. c = s[i];
  1113. if (c == _T('\n'))
  1114. {
  1115. // Explicit line break
  1116. i++;
  1117. sep = -1;
  1118. j = i;
  1119. len = 0;
  1120. nl++;
  1121. continue;
  1122. }
  1123. if (c == _T(' '))
  1124. {
  1125. sep = i;
  1126. }
  1127. len = GetStringWidth(s.SubString(j, i));
  1128. if (len > wmax)
  1129. {
  1130. // Automatic line break
  1131. if (sep == -1)
  1132. {
  1133. if (i == j)
  1134. {
  1135. i++;
  1136. }
  1137. }
  1138. else
  1139. {
  1140. i = sep + 1;
  1141. }
  1142. sep = -1;
  1143. j = i;
  1144. len = 0;
  1145. nl++;
  1146. }
  1147. else
  1148. {
  1149. i++;
  1150. }
  1151. }
  1152. return nl;
  1153. }
  1154. int
  1155. wxPdfDocument::TextBox(double w, double h, const wxString& txt,
  1156. int halign, int valign, int border, int fill)
  1157. {
  1158. double xi = m_x;
  1159. double yi = m_y;
  1160. double hrow = m_fontSize;
  1161. int textrows = LineCount(w, txt);
  1162. int maxrows = (int) floor(h / hrow);
  1163. int rows = (textrows < maxrows) ? textrows : maxrows;
  1164. double dy = 0;
  1165. if (valign == wxPDF_ALIGN_MIDDLE)
  1166. {
  1167. dy = (h - rows * hrow) / 2;
  1168. }
  1169. else if (valign == wxPDF_ALIGN_BOTTOM)
  1170. {
  1171. dy = h - rows * hrow;
  1172. }
  1173. SetY(yi+dy);
  1174. SetX(xi);
  1175. int trail = MultiCell(w, hrow, txt, 0, halign, fill, rows);
  1176. if (border == wxPDF_BORDER_FRAME)
  1177. {
  1178. Rect(xi, yi, w, h);
  1179. }
  1180. else
  1181. {
  1182. if (border & wxPDF_BORDER_LEFT) Line(xi,yi,xi,yi+h);
  1183. if (border & wxPDF_BORDER_RIGHT) Line(xi+w,yi,xi+w,yi+h);
  1184. if (border & wxPDF_BORDER_TOP) Line(xi,yi,xi+w,yi);
  1185. if (border & wxPDF_BORDER_BOTTOM) Line(xi,yi+h,xi+w,yi+h);
  1186. }
  1187. return trail;
  1188. }
  1189. void
  1190. wxPdfDocument::Write(double h, const wxString& txt, const wxPdfLink& link)
  1191. {
  1192. WriteCell(h, txt, wxPDF_BORDER_NONE, 0, link);
  1193. }
  1194. void
  1195. wxPdfDocument::WriteCell(double h, const wxString& txt, int border, int fill, const wxPdfLink& link)
  1196. {
  1197. // Output text in flowing mode
  1198. wxString s = txt;
  1199. s.Replace(_T("\r"),_T("")); // remove carriage returns
  1200. int nb = s.Length();
  1201. // handle single space character
  1202. if ((nb == 1) && s[0] == _T(' '))
  1203. {
  1204. m_x += GetStringWidth(s);
  1205. return;
  1206. }
  1207. double saveCellMargin = GetCellMargin();
  1208. SetCellMargin(0);
  1209. double w = m_w - m_rMargin - m_x;
  1210. double wmax = (w - 2 * m_cMargin) + wxPDF_EPSILON;
  1211. int sep = -1;
  1212. int i = 0;
  1213. int j = 0;
  1214. double len=0;
  1215. int nl = 1;
  1216. wxChar c;
  1217. while (i < nb)
  1218. {
  1219. // Get next character
  1220. c = s[i];
  1221. if (c == _T('\n'))
  1222. {
  1223. // Explicit line break
  1224. Cell(w, h, s.SubString(j,i-1), border, 2, wxPDF_ALIGN_LEFT, fill, link);
  1225. i++;
  1226. sep = -1;
  1227. j = i;
  1228. len = 0;
  1229. if (nl == 1)
  1230. {
  1231. m_x = m_lMargin;
  1232. w = m_w - m_rMargin - m_x;
  1233. wmax = (w - 2 * m_cMargin);
  1234. }
  1235. nl++;
  1236. continue;
  1237. }
  1238. if (c == _T(' '))
  1239. {
  1240. sep = i;
  1241. }
  1242. len = GetStringWidth(s.SubString(j, i));
  1243. if (len > wmax)
  1244. {
  1245. // Automatic line break
  1246. if (sep == -1)
  1247. {
  1248. if (m_x > m_lMargin)
  1249. {
  1250. // Move to next line
  1251. m_x = m_lMargin;
  1252. m_y += h;
  1253. w = m_w - m_rMargin -m_x;
  1254. wmax = (w - 2 * m_cMargin);
  1255. i++;
  1256. nl++;
  1257. continue;
  1258. }
  1259. if (i == j)
  1260. {
  1261. i++;
  1262. }
  1263. Cell(w, h,s.SubString(j, i-1), border, 2, wxPDF_ALIGN_LEFT, fill, link);
  1264. }
  1265. else
  1266. {
  1267. Cell(w, h, s.SubString(j, sep-1), border, 2, wxPDF_ALIGN_LEFT, fill, link);
  1268. i = sep + 1;
  1269. }
  1270. sep = -1;
  1271. j = i;
  1272. len = 0;
  1273. if (nl == 1)
  1274. {
  1275. m_x = m_lMargin;
  1276. w = m_w - m_rMargin - m_x;
  1277. wmax = (w - 2 * m_cMargin);
  1278. }
  1279. nl++;
  1280. }
  1281. else
  1282. {
  1283. i++;
  1284. }
  1285. }
  1286. // Last chunk
  1287. if (i != j)
  1288. {
  1289. Cell(len, h, s.SubString(j,i-1), border, 0, wxPDF_ALIGN_LEFT, fill, link);
  1290. }
  1291. // Following statement was in PHP code, but seems to be in error.
  1292. // m_x += GetStringWidth(s.SubString(j, i-1));
  1293. SetCellMargin(saveCellMargin);
  1294. }
  1295. bool
  1296. wxPdfDocument::Image(const wxString& file, double x, double y, double w, double h,
  1297. const wxString& type, const wxPdfLink& link, int maskImage)
  1298. {
  1299. wxPdfImage* currentImage = NULL;
  1300. // Put an image on the page
  1301. wxPdfImageHashMap::iterator image = (*m_images).find(file);
  1302. if (image == (*m_images).end())
  1303. {
  1304. // First use of image, get info
  1305. int i = (*m_images).size() + 1;
  1306. currentImage = new wxPdfImage(this, i, file, type);
  1307. if (!currentImage->Parse())
  1308. {
  1309. bool isValid = false;
  1310. delete currentImage;
  1311. if (wxImage::FindHandler(wxBITMAP_TYPE_PNG) == NULL)
  1312. {
  1313. wxImage::AddHandler(new wxPNGHandler());
  1314. }
  1315. wxImage tempImage;
  1316. tempImage.LoadFile(file);
  1317. if (tempImage.Ok())
  1318. {
  1319. isValid = Image(file, tempImage, x, y, w, h, link, maskImage);
  1320. }
  1321. return isValid;
  1322. }
  1323. if (maskImage > 0)
  1324. {
  1325. currentImage->SetMaskImage(maskImage);
  1326. }
  1327. (*m_images)[file] = currentImage;
  1328. }
  1329. else
  1330. {
  1331. currentImage = image->second;
  1332. if (maskImage > 0 && currentImage->GetMaskImage() != maskImage)
  1333. {
  1334. currentImage->SetMaskImage(maskImage);
  1335. }
  1336. }
  1337. OutImage(currentImage, x, y, w, h, link);
  1338. return true;
  1339. }
  1340. bool
  1341. wxPdfDocument::Image(const wxString& name, const wxImage& img, double x, double y, double w, double h,
  1342. const wxPdfLink& link, int maskImage)
  1343. {
  1344. bool isValid = false;
  1345. if (img.Ok())
  1346. {
  1347. wxImage tempImage = img.Copy();
  1348. wxPdfImage* currentImage = NULL;
  1349. // Put an image on the page
  1350. wxPdfImageHashMap::iterator image = (*m_images).find(name);
  1351. if (image == (*m_images).end())
  1352. {
  1353. if (tempImage.HasAlpha())
  1354. {
  1355. if (maskImage <= 0)
  1356. {
  1357. maskImage = ImageMask(name+wxString(_T(".mask")), tempImage);
  1358. }
  1359. if(!tempImage.ConvertAlphaToMask(0))
  1360. {
  1361. return false;
  1362. }
  1363. }
  1364. // First use of image, get info
  1365. tempImage.SetMask(false);
  1366. int i = (*m_images).size() + 1;
  1367. currentImage = new wxPdfImage(this, i, name, tempImage);
  1368. if (!currentImage->Parse())
  1369. {
  1370. delete currentImage;
  1371. return false;
  1372. }
  1373. if (maskImage > 0)
  1374. {
  1375. currentImage->SetMaskImage(maskImage);
  1376. }
  1377. (*m_images)[name] = currentImage;
  1378. }
  1379. else
  1380. {
  1381. currentImage = image->second;
  1382. if (maskImage > 0 && currentImage->GetMaskImage() != maskImage)
  1383. {
  1384. currentImage->SetMaskImage(maskImage);
  1385. }
  1386. }
  1387. OutImage(currentImage, x, y, w, h, link);
  1388. isValid = true;
  1389. }
  1390. return isValid;
  1391. }
  1392. bool
  1393. wxPdfDocument::Image(const wxString& name, wxInputStream& stream,
  1394. const wxString& mimeType,
  1395. double x, double y, double w, double h,
  1396. const wxPdfLink& link, int maskImage)
  1397. {
  1398. bool isValid = false;
  1399. wxPdfImage* currentImage = NULL;
  1400. // Put an image on the page
  1401. wxPdfImageHashMap::iterator image = (*m_images).find(name);
  1402. if (image == (*m_images).end())
  1403. {
  1404. // First use of image, get info
  1405. int i = (*m_images).size() + 1;
  1406. currentImage = new wxPdfImage(this, i, name, stream, mimeType);
  1407. if (!currentImage->Parse())
  1408. {
  1409. delete currentImage;
  1410. if (wxImage::FindHandler(wxBITMAP_TYPE_PNG) == NULL)
  1411. {
  1412. wxImage::AddHandler(new wxPNGHandler());
  1413. }
  1414. wxImage tempImage;
  1415. tempImage.LoadFile(stream, mimeType);
  1416. if (tempImage.Ok())
  1417. {
  1418. isValid = Image(name, tempImage, x, y, w, h, link, maskImage);
  1419. }
  1420. return isValid;
  1421. }
  1422. if (maskImage > 0)
  1423. {
  1424. currentImage->SetMaskImage(maskImage);
  1425. }
  1426. (*m_images)[name] = currentImage;
  1427. }
  1428. else
  1429. {
  1430. currentImage = image->second;
  1431. if (maskImage > 0 && currentImage->GetMaskImage() != maskImage)
  1432. {
  1433. currentImage->SetMaskImage(maskImage);
  1434. }
  1435. }
  1436. OutImage(currentImage, x, y, w, h, link);
  1437. isValid = true;
  1438. return isValid;
  1439. }
  1440. int
  1441. wxPdfDocument::ImageMask(const wxString& file, const wxString& type)
  1442. {
  1443. int n = 0;
  1444. wxPdfImage* currentImage = NULL;
  1445. // Put an image on the page
  1446. wxPdfImageHashMap::iterator image = (*m_images).find(file);
  1447. if (image == (*m_images).end())
  1448. {
  1449. // First use of image, get info
  1450. n = (*m_images).size() + 1;
  1451. currentImage = new wxPdfImage(this, n, file, type);
  1452. if (!currentImage->Parse())
  1453. {
  1454. delete currentImage;
  1455. return 0;
  1456. }
  1457. // Check whether this is a gray scale image (must be)
  1458. if (currentImage->GetColorSpace() != _T("DeviceGray"))
  1459. {
  1460. delete currentImage;
  1461. return 0;
  1462. }
  1463. (*m_images)[file] = currentImage;
  1464. }
  1465. else
  1466. {
  1467. currentImage = image->second;
  1468. n = currentImage->GetIndex();
  1469. }
  1470. if (m_PDFVersion < _T("1.4"))
  1471. {
  1472. m_PDFVersion = _T("1.4");
  1473. }
  1474. return n;
  1475. }
  1476. int
  1477. wxPdfDocument::ImageMask(const wxString& name, const wxImage& img)
  1478. {
  1479. int n = 0;
  1480. if (img.Ok())
  1481. {
  1482. wxPdfImage* currentImage = NULL;
  1483. // Put an image on the page
  1484. wxPdfImageHashMap::iterator image = (*m_images).find(name);
  1485. if (image == (*m_images).end())
  1486. {
  1487. wxImage tempImage;
  1488. if (img.HasAlpha())
  1489. {
  1490. int x, y;
  1491. int w = img.GetWidth();
  1492. int h = img.GetHeight();
  1493. tempImage = wxImage(w, h);
  1494. unsigned char alpha;
  1495. for (x = 0; x < w; x++)
  1496. {
  1497. for (y = 0; y < h; y++)
  1498. {
  1499. alpha = img.GetAlpha(x, y);
  1500. tempImage.SetRGB(x, y, alpha, alpha, alpha);
  1501. }
  1502. }
  1503. tempImage.SetOption(wxIMAGE_OPTION_PNG_FORMAT, wxPNG_TYPE_GREY_RED);
  1504. }
  1505. else
  1506. {
  1507. tempImage = img.Copy();
  1508. tempImage.SetOption(wxIMAGE_OPTION_PNG_FORMAT, wxPNG_TYPE_GREY);
  1509. }
  1510. tempImage.SetMask(false);
  1511. // First use of image, get info
  1512. n = (*m_images).size() + 1;
  1513. currentImage = new wxPdfImage(this, n, name, tempImage);
  1514. if (!currentImage->Parse())
  1515. {
  1516. delete currentImage;
  1517. return 0;
  1518. }
  1519. (*m_images)[name] = currentImage;
  1520. }
  1521. else
  1522. {
  1523. currentImage = image->second;
  1524. n = currentImage->GetIndex();
  1525. }
  1526. if (m_PDFVersion < _T("1.4"))
  1527. {
  1528. m_PDFVersion = _T("1.4");
  1529. }
  1530. }
  1531. return n;
  1532. }
  1533. int
  1534. wxPdfDocument::ImageMask(const wxString& name, wxInputStream& stream, const wxString& mimeType)
  1535. {
  1536. int n = 0;
  1537. wxPdfImage* currentImage = NULL;
  1538. // Put an image on the page
  1539. wxPdfImageHashMap::iterator image = (*m_images).find(name);
  1540. if (image == (*m_images).end())
  1541. {
  1542. // First use of image, get info
  1543. n = (*m_images).size() + 1;
  1544. currentImage = new wxPdfImage(this, n, name, stream, mimeType);
  1545. if (!currentImage->Parse())
  1546. {
  1547. delete currentImage;
  1548. return 0;
  1549. }
  1550. // Check whether this is a gray scale image (must be)
  1551. if (currentImage->GetColorSpace() != _T("DeviceGray"))
  1552. {
  1553. delete currentImage;
  1554. return 0;
  1555. }
  1556. (*m_images)[name] = currentImage;
  1557. }
  1558. else
  1559. {
  1560. currentImage = image->second;
  1561. n = currentImage->GetIndex();
  1562. }
  1563. if (m_PDFVersion < _T("1.4"))
  1564. {
  1565. m_PDFVersion = _T("1.4");
  1566. }
  1567. return n;
  1568. }
  1569. void
  1570. wxPdfDocument::RotatedImage(const wxString& file, double x, double y, double w, double h,
  1571. double angle, const wxString& type, const wxPdfLink& link, int maskImage)
  1572. {
  1573. // Image rotated around its upper-left corner
  1574. StartTransform();
  1575. Rotate(angle, x, y);
  1576. Image(file, x, y, w, h, type, link, maskImage);
  1577. StopTransform();
  1578. }
  1579. void
  1580. wxPdfDocument::Ln(double h)
  1581. {
  1582. // Line feed; default value is last cell height
  1583. m_x = m_lMargin;
  1584. if (h < 0)
  1585. {
  1586. m_y += m_lasth;
  1587. }
  1588. else
  1589. {
  1590. m_y += h;
  1591. }
  1592. }
  1593. void
  1594. wxPdfDocument::SaveAsFile(const wxString& name)
  1595. {
  1596. wxString fileName = name;
  1597. // Finish document if necessary
  1598. if (m_state < 3)
  1599. {
  1600. Close();
  1601. }
  1602. // Normalize parameters
  1603. if(fileName.Length() == 0)
  1604. {
  1605. fileName = _T("doc.pdf");
  1606. }
  1607. // Save to local file
  1608. wxFileOutputStream outfile(fileName);
  1609. wxMemoryInputStream tmp(m_buffer);
  1610. outfile.Write(tmp);
  1611. outfile.Close();
  1612. }
  1613. const wxMemoryOutputStream&
  1614. wxPdfDocument::CloseAndGetBuffer()
  1615. {
  1616. if (m_state < 3)
  1617. {
  1618. Close();
  1619. }
  1620. return m_buffer;
  1621. }
  1622. void
  1623. wxPdfDocument::SetViewerPreferences(int preferences)
  1624. {
  1625. m_viewerPrefs = (preferences > 0) ? preferences : 0;
  1626. if (((m_viewerPrefs & wxPDF_VIEWER_DISPLAYDOCTITLE) != 0) && (m_PDFVersion < _T("1.4")))
  1627. {
  1628. m_PDFVersion = _T("1.4");
  1629. }
  1630. }
  1631. void
  1632. wxPdfDocument::SetTitle(const wxString& title)
  1633. {
  1634. // Title of document
  1635. m_title = title;
  1636. }
  1637. void
  1638. wxPdfDocument::SetSubject(const wxString& subject)
  1639. {
  1640. // Subject of document
  1641. m_subject = subject;
  1642. }
  1643. void
  1644. wxPdfDocument::SetAuthor(const wxString& author)
  1645. {
  1646. // Author of document
  1647. m_author = author;
  1648. }
  1649. void
  1650. wxPdfDocument::SetKeywords(const wxString& keywords)
  1651. {
  1652. // Keywords of document
  1653. m_keywords = keywords;
  1654. }
  1655. void
  1656. wxPdfDocument::SetCreator(const wxString& creator)
  1657. {
  1658. // Creator of document
  1659. m_creator = creator;
  1660. }
  1661. void
  1662. wxPdfDocument::SetMargins(double left, double top, double right)
  1663. {
  1664. // Set left, top and right margins
  1665. m_lMargin = left;
  1666. m_tMargin = top;
  1667. if (right == -1)
  1668. {
  1669. right = left;
  1670. }
  1671. m_rMargin = right;
  1672. }
  1673. void
  1674. wxPdfDocument::SetLeftMargin(double margin)
  1675. {
  1676. // Set left margin
  1677. m_lMargin = margin;
  1678. if (m_page > 0 && m_x < margin)
  1679. {
  1680. m_x = margin;
  1681. }
  1682. }
  1683. double
  1684. wxPdfDocument::GetLeftMargin()
  1685. {
  1686. return m_lMargin;
  1687. }
  1688. void
  1689. wxPdfDocument::SetTopMargin(double margin)
  1690. {
  1691. // Set top margin
  1692. m_tMargin = margin;
  1693. }
  1694. double
  1695. wxPdfDocument::GetTopMargin()
  1696. {
  1697. return m_tMargin;
  1698. }
  1699. void
  1700. wxPdfDocument::SetRightMargin(double margin)
  1701. {
  1702. // Set right margin
  1703. m_rMargin = margin;
  1704. }
  1705. double
  1706. wxPdfDocument::GetRightMargin()
  1707. {
  1708. return m_rMargin;
  1709. }
  1710. void
  1711. wxPdfDocument::SetCellMargin(double margin)
  1712. {
  1713. // Set cell margin
  1714. m_cMargin = margin;
  1715. }
  1716. double
  1717. wxPdfDocument::GetCellMargin()
  1718. {
  1719. return m_cMargin;
  1720. }
  1721. void
  1722. wxPdfDocument::SetLineHeight(double height)
  1723. {
  1724. m_lasth = height;
  1725. }
  1726. double
  1727. wxPdfDocument::GetLineHeight()
  1728. {
  1729. return m_lasth;
  1730. }
  1731. void
  1732. wxPdfDocument::SetAutoPageBreak(bool autoPageBreak, double margin)
  1733. {
  1734. // Set auto page break mode and triggering margin
  1735. m_autoPageBreak = autoPageBreak;
  1736. m_bMargin = margin;
  1737. m_pageBreakTrigger = m_h - margin;
  1738. }
  1739. void
  1740. wxPdfDocument::SetDisplayMode(wxPdfZoom zoom, wxPdfLayout layout, double zoomFactor)
  1741. {
  1742. // Set display mode in viewer
  1743. switch (zoom)
  1744. {
  1745. case wxPDF_ZOOM_FULLPAGE:
  1746. case wxPDF_ZOOM_FULLWIDTH:
  1747. case wxPDF_ZOOM_REAL:
  1748. case wxPDF_ZOOM_DEFAULT:
  1749. m_zoomMode = zoom;
  1750. break;
  1751. case wxPDF_ZOOM_FACTOR:
  1752. m_zoomMode = zoom;
  1753. m_zoomFactor = (zoomFactor > 0) ? zoomFactor : 100.;
  1754. break;
  1755. default:
  1756. m_zoomMode = wxPDF_ZOOM_FULLWIDTH;
  1757. break;
  1758. }
  1759. switch (layout)
  1760. {
  1761. case wxPDF_LAYOUT_SINGLE:
  1762. case wxPDF_LAYOUT_TWO:
  1763. case wxPDF_LAYOUT_DEFAULT:
  1764. case wxPDF_LAYOUT_CONTINUOUS:
  1765. m_layoutMode = layout;
  1766. break;
  1767. default:
  1768. m_layoutMode = wxPDF_LAYOUT_CONTINUOUS;
  1769. break;
  1770. }
  1771. }
  1772. void
  1773. wxPdfDocument::Close()
  1774. {
  1775. // Terminate document
  1776. if (m_state == 3)
  1777. {
  1778. return;
  1779. }
  1780. if (m_page == 0)
  1781. {
  1782. AddPage();
  1783. }
  1784. // Page footer
  1785. m_inFooter = true;
  1786. Footer();
  1787. m_inFooter = false;
  1788. // Close page
  1789. EndPage();
  1790. // Close document
  1791. EndDoc();
  1792. }
  1793. void
  1794. wxPdfDocument::Header()
  1795. {
  1796. // To be implemented in your own inherited class
  1797. }
  1798. void
  1799. wxPdfDocument::Footer()
  1800. {
  1801. // To be implemented in your own inherited class
  1802. }
  1803. bool
  1804. wxPdfDocument::IsInFooter()
  1805. {
  1806. return m_inFooter;
  1807. }
  1808. int
  1809. wxPdfDocument::PageNo()
  1810. {
  1811. // Get current page number
  1812. return m_page;
  1813. }
  1814. double
  1815. wxPdfDocument::GetX()
  1816. {
  1817. // Get x position
  1818. return m_x;
  1819. }
  1820. void
  1821. wxPdfDocument::SetX(double x)
  1822. {
  1823. // Set x position
  1824. if ( x >= 0.0)
  1825. {
  1826. m_x = x;
  1827. }
  1828. else
  1829. {
  1830. m_x = m_w + x;
  1831. }
  1832. }
  1833. double
  1834. wxPdfDocument::GetY()
  1835. {
  1836. // Get y position
  1837. return m_y;
  1838. }
  1839. void
  1840. wxPdfDocument::SetY(double y)
  1841. {
  1842. // Set y position and reset x
  1843. m_x = m_lMargin;
  1844. if ( y >= 0)
  1845. {
  1846. m_y = y;
  1847. }
  1848. else
  1849. {
  1850. m_y = m_h + y;
  1851. }
  1852. }
  1853. void
  1854. wxPdfDocument::SetXY(double x, double y)
  1855. {
  1856. // Set x and y positions
  1857. SetY(y);
  1858. SetX(x);
  1859. }
  1860. void
  1861. wxPdfDocument::SetCompression(bool compress)
  1862. {
  1863. m_compress = compress;
  1864. }
  1865. void
  1866. wxPdfDocument::AppendJavascript(const wxString& javascript)
  1867. {
  1868. m_javascript += javascript;
  1869. }
  1870. // --- Static methods
  1871. wxString
  1872. wxPdfDocument::RGB2String(const wxColour& color)
  1873. {
  1874. double r = color.Red();
  1875. double g = color.Green();
  1876. double b = color.Blue();
  1877. wxString rgb = Double2String(r/255.,3) + _T(" ") +
  1878. Double2String(g/255.,3) + _T(" ") +
  1879. Double2String(b/255.,3);
  1880. return rgb;
  1881. }
  1882. wxString
  1883. wxPdfDocument::Double2String(double value, int precision)
  1884. {
  1885. wxString number;
  1886. if (precision < 0)
  1887. {
  1888. precision = 0;
  1889. }
  1890. else if (precision > 16)
  1891. {
  1892. precision = 16;
  1893. }
  1894. // Use absolute value locally
  1895. double localValue = fabs(value);
  1896. double localFraction = (localValue - floor(localValue)) +(5. * pow(10.0, -precision-1));
  1897. if (localFraction >= 1)
  1898. {
  1899. localValue += 1.0;
  1900. localFraction -= 1.0;
  1901. }
  1902. localFraction *= pow(10.0, precision);
  1903. if (value < 0)
  1904. {
  1905. number += wxString(_T("-"));
  1906. }
  1907. number += wxString::Format(_T("%.0lf"), floor(localValue));
  1908. // generate fraction, padding with zero if necessary.
  1909. if (precision > 0)
  1910. {
  1911. number += wxString(_T("."));
  1912. wxString fraction = wxString::Format(_T("%.0lf"), floor(localFraction));
  1913. if (fraction.Length() < ((size_t) precision))
  1914. {
  1915. number += wxString(_T('0'), precision-fraction.Length());
  1916. }
  1917. number += fraction;
  1918. }
  1919. return number;
  1920. }
  1921. double
  1922. wxPdfDocument::String2Double(const wxString& str)
  1923. {
  1924. wxString value = str.Strip(wxString::both);
  1925. double result = 0;
  1926. double sign = 1;
  1927. int scale = 0;
  1928. int exponent = 0;
  1929. int expsign = 1;
  1930. int j = 0;
  1931. int jMax = value.Length();
  1932. if (jMax > 0)
  1933. {
  1934. if (value[j] == wxT('+'))
  1935. {
  1936. j++;
  1937. }
  1938. else if (value[j] == wxT('-'))
  1939. {
  1940. sign = -1;
  1941. j++;
  1942. }
  1943. while (j < jMax && wxIsdigit(value[j]))
  1944. {
  1945. result = result*10 + (value[j] - wxT('0'));
  1946. j++;
  1947. }
  1948. if (j < jMax && value[j] == wxT('.'))
  1949. {
  1950. j++;
  1951. while (j < jMax && wxIsdigit(value[j]))
  1952. {
  1953. result = result*10 + (value[j] - wxT('0'));
  1954. scale++;
  1955. j++;
  1956. }
  1957. }
  1958. if (j < jMax && (value[j] == wxT('E') || value[j] == wxT('e')))
  1959. {
  1960. j++;
  1961. if (value[j] == wxT('+'))
  1962. {
  1963. j++;
  1964. }
  1965. else if (value[j] == wxT('-'))
  1966. {
  1967. expsign = -1;
  1968. j++;
  1969. }
  1970. while (j < jMax && wxIsdigit(value[j]))
  1971. {
  1972. exponent = exponent*10 + (value[j] - wxT('0'));
  1973. j++;
  1974. }
  1975. exponent *= expsign;
  1976. }
  1977. result = sign * result * pow(10.0, exponent-scale);
  1978. }
  1979. return result;
  1980. }
  1981. wxString
  1982. wxPdfDocument::Convert2Roman(int value)
  1983. {
  1984. wxString result = wxEmptyString;
  1985. if (value > 0 && value < 4000)
  1986. {
  1987. static wxString romans = _T("MDCLXVI");
  1988. int pos = 6; // Point to LAST character in 'romans'
  1989. int currentDigit;
  1990. while (value > 0)
  1991. {
  1992. currentDigit = value % 10;
  1993. if (currentDigit == 4 || currentDigit == 9)
  1994. {
  1995. result.Prepend(romans.Mid(pos - currentDigit / 4, 1));
  1996. result.Prepend(romans.Mid(pos, 1));
  1997. }
  1998. else
  1999. {
  2000. int x = currentDigit % 5;
  2001. while (x-- > 0)
  2002. {
  2003. result.Prepend(romans.Mid(pos, 1));
  2004. }
  2005. if (currentDigit >= 5)
  2006. {
  2007. result.Prepend(romans.Mid(pos - 1, 1));
  2008. }
  2009. }
  2010. value /= 10;
  2011. pos -= 2;
  2012. }
  2013. }
  2014. else
  2015. {
  2016. result = _T("???");
  2017. }
  2018. return result;
  2019. }
  2020. double
  2021. wxPdfDocument::ForceRange(double value, double minValue, double maxValue)
  2022. {
  2023. if (value < minValue)
  2024. {
  2025. value = minValue;
  2026. }
  2027. else if (value > maxValue)
  2028. {
  2029. value = maxValue;
  2030. }
  2031. return value;
  2032. }