1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: pdfdocument.cpp
3 // Purpose: Implementation of wxPdfDocument (public methods)
4 // Author: Ulrich Telle
5 // Created: 2005-08-04
6 // Copyright: (c) Ulrich Telle
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
9
10 /// \file pdfdocument.cpp Implementation of the wxPdfDocument class
11
12 // For compilers that support precompilation, includes <wx/wx.h>.
13 #include <wx/wxprec.h>
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #ifndef WX_PRECOMP
20 #include <wx/wx.h>
21 #endif
22
23 #include <wx/image.h>
24 #include <wx/paper.h>
25 #include <wx/wfstream.h>
26
27 #include "wx/pdfbookmark.h"
28 #include "wx/pdfdocument.h"
29 #include "wx/pdffont.h"
30 #include "wx/pdffontdetails.h"
31 #include "wx/pdffontmanager.h"
32 #include "wx/pdfform.h"
33 #include "wx/pdfgradient.h"
34 #include "wx/pdfgraphics.h"
35 #include "wx/pdflayer.h"
36 #include "wx/pdfparser.h"
37 #include "wx/pdfpattern.h"
38 #include "wx/pdfspotcolour.h"
39 #include "wx/pdftemplate.h"
40 #include "wx/pdffontparser.h"
41 #include "wx/pdfutility.h"
42
43 #if WXPDFDOC_INHERIT_WXOBJECT
IMPLEMENT_DYNAMIC_CLASS(wxPdfDocument,wxObject)44 IMPLEMENT_DYNAMIC_CLASS(wxPdfDocument, wxObject)
45 #endif
46
47 // ----------------------------------------------------------------------------
48 // wxPdfDocument: class representing a PDF document
49 // ----------------------------------------------------------------------------
50
51 wxPdfDocument::wxPdfDocument(int orientation, const wxString& unit, wxPaperSize format)
52 #if WXPDFDOC_INHERIT_WXOBJECT
53 : wxObject()
54 #endif
55 {
56 m_creationDateSet = false;
57 m_yAxisOriginTop = true;
58 SetScaleFactor(unit);
59
60 // Page format
61 m_defPageSize = CalculatePageSize(format);
62 Initialize(orientation);
63 }
64
wxPdfDocument(int orientation,double pageWidth,double pageHeight,const wxString & unit)65 wxPdfDocument::wxPdfDocument(int orientation, double pageWidth, double pageHeight, const wxString& unit)
66 #if WXPDFDOC_INHERIT_WXOBJECT
67 : wxObject()
68 #endif
69 {
70 m_creationDateSet = false;
71 m_yAxisOriginTop = true;
72 SetScaleFactor(unit);
73 m_defPageSize = CalculatePageSize(pageWidth, pageHeight);
74 Initialize(orientation);
75 }
76
77 void
SetScaleFactor(const wxString & unit)78 wxPdfDocument::SetScaleFactor(const wxString& unit)
79 {
80 // Scale factor
81 if (unit == wxS("pt"))
82 {
83 m_k = 1.;
84 }
85 else if (unit == wxS("in"))
86 {
87 m_k = 72.;
88 }
89 else if (unit == wxS("cm"))
90 {
91 m_k = 72. / 2.54;
92 }
93 else // if (unit == "mm") or unknown
94 {
95 m_k = 72. / 25.4;
96 }
97 }
98
99 wxSize
CalculatePageSize(wxPaperSize format)100 wxPdfDocument::CalculatePageSize(wxPaperSize format)
101 {
102 bool deletePaperDatabase = false;
103 wxPrintPaperDatabase* printPaperDatabase = wxThePrintPaperDatabase;
104 if (printPaperDatabase == NULL)
105 {
106 printPaperDatabase = new wxPrintPaperDatabase;
107 printPaperDatabase->CreateDatabase();
108 deletePaperDatabase = true;
109 }
110 wxPrintPaperType* paperType = printPaperDatabase->FindPaperType(format);
111 if (paperType == NULL)
112 {
113 paperType = printPaperDatabase->FindPaperType(wxPAPER_A4);
114 }
115 wxSize paperSize = paperType->GetSize();
116 if (deletePaperDatabase)
117 {
118 delete printPaperDatabase;
119 }
120 return paperSize;
121 }
122
123 wxSize
CalculatePageSize(double pageWidth,double pageHeight)124 wxPdfDocument::CalculatePageSize(double pageWidth, double pageHeight)
125 {
126 int width = (int) (pageWidth * (m_k * 254. / 72.));
127 int height = (int) (pageHeight * (m_k * 254. / 72.));
128 return wxSize(width,height);
129 }
130
131 void
Initialize(int orientation)132 wxPdfDocument::Initialize(int orientation)
133 {
134 // Allocate arrays
135 m_currentFont = NULL;
136 m_buffer = new wxMemoryOutputStream();
137
138 m_page = 0;
139 m_n = 2;
140 m_offsets = new wxPdfOffsetHashMap();
141
142 m_pages = new wxPdfPageHashMap();
143 m_pageSizes = new wxPdfPageSizeMap();
144 m_orientationChanges = new wxPdfBoolHashMap();
145
146 m_state = 0;
147 m_fonts = new wxPdfFontHashMap();
148 m_images = new wxPdfImageHashMap();
149 m_pageLinks = new wxPdfPageLinksMap();
150 m_links = new wxPdfLinkHashMap();
151 m_namedLinks = new wxPdfNamedLinksMap();
152 m_diffs = new wxPdfStringHashMap();
153 m_winansi = new wxPdfBoolHashMap();
154 m_extGStates = new wxPdfExtGStateMap();
155 m_extGSLookup = new wxPdfExtGSLookupMap();
156 m_currentExtGState = 0;
157 m_gradients = new wxPdfGradientMap();
158 m_annotations = new wxPdfAnnotationsMap();
159 m_formAnnotations = new wxPdfFormAnnotsMap();
160 m_formFields = new wxPdfFormFieldsMap();
161 m_radioGroups = new wxPdfRadioGroupMap();
162 m_templates = new wxPdfTemplatesMap();
163 m_parsers = new wxPdfParserMap();
164 m_spotColours = new wxPdfSpotColourMap();
165 m_patterns = new wxPdfPatternMap();
166 m_ocgs = new wxPdfOcgMap();
167 m_rgLayers = new wxPdfLayerRGMap();
168 m_lockedLayers = NULL;
169 m_attachments = new wxPdfAttachmentMap();
170
171 m_outlineRoot = -1;
172 m_maxOutlineLevel = 0;
173
174 m_inFooter = false;
175 m_lasth = 0;
176 m_fontFamily = wxEmptyString;
177 m_fontStyle = wxPDF_FONTSTYLE_REGULAR;
178 m_fontSizePt = 12;
179 m_decoration = wxPDF_FONTSTYLE_REGULAR;
180 m_fontSubsetting = true;
181
182 m_drawColour = wxPdfColour();
183 m_fillColour = wxPdfColour();
184 m_textColour = wxPdfColour();
185 m_colourFlag = false;
186 m_wsApply = false;
187 m_ws = 0;
188 m_textRenderMode = wxPDF_TEXT_RENDER_FILL;
189
190 // Initialize image scale factor
191 m_imgscale = 1.;
192
193 // Page format
194 m_curPageSize = m_defPageSize;
195 m_fwPt = m_defPageSize.GetWidth() / 254. * 72.;
196 m_fhPt = m_defPageSize.GetHeight() / 254. * 72.;
197 m_fw = m_fwPt / m_k;
198 m_fh = m_fhPt / m_k;
199
200 // Page orientation
201 if (orientation == wxLANDSCAPE)
202 {
203 m_defOrientation = wxLANDSCAPE;
204 m_wPt = m_fhPt;
205 m_hPt = m_fwPt;
206 }
207 else // orientation == wxPORTRAIT or unknown
208 {
209 m_defOrientation = wxPORTRAIT;
210 m_wPt = m_fwPt;
211 m_hPt = m_fhPt;
212 }
213
214 m_curOrientation = m_defOrientation;
215 m_w = m_wPt / m_k;
216 m_h = m_hPt / m_k;
217 m_angle = 0;
218 m_fillRule = wxWINDING_RULE;
219 m_inTransform = 0;
220
221 // Page margins (1 cm)
222 double margin = (72.0 / 25.4 * 10.0) / m_k;
223 SetMargins(margin, margin);
224
225 // Interior cell margin (1 mm)
226 m_cMargin = margin / 10;
227
228 // Line width (0.2 mm)
229 m_lineWidth = (72.0 / 25.4 * 0.2) / m_k;
230
231 // Automatic page break
232 SetAutoPageBreak(true, 2*margin);
233
234 // Full width display mode
235 SetDisplayMode(wxPDF_ZOOM_FULLWIDTH);
236 m_zoomFactor = 100.;
237
238 // Default viewer preferences
239 m_viewerPrefs = 0;
240
241 // Disable kerning
242 SetKerning(false);
243
244 // Enable compression
245 SetCompression(true);
246
247 // Set default PDF version number
248 m_PDFVersion = wxS("1.3");
249 m_importVersion = m_PDFVersion;
250
251 m_encrypted = false;
252 m_encryptor = NULL;
253
254 m_javascript = wxEmptyString;
255
256 m_inTemplate = false;
257 m_templateId = 0;
258 m_templatePrefix = wxS("/TPL");
259
260 m_currentParser = NULL;
261 m_currentSource = wxEmptyString;
262
263 m_translate = false;
264
265 m_zapfdingbats = 0;
266 }
267
~wxPdfDocument()268 wxPdfDocument::~wxPdfDocument()
269 {
270 wxPdfFontHashMap::iterator font = m_fonts->begin();
271 for (font = m_fonts->begin(); font != m_fonts->end(); font++)
272 {
273 if (font->second != NULL)
274 {
275 delete font->second;
276 }
277 }
278 delete m_fonts;
279
280 wxPdfImageHashMap::iterator image = m_images->begin();
281 for (image = m_images->begin(); image != m_images->end(); image++)
282 {
283 if (image->second != NULL)
284 {
285 delete image->second;
286 }
287 }
288 delete m_images;
289
290 wxPdfPageHashMap::iterator page = m_pages->begin();
291 for (page = m_pages->begin(); page != m_pages->end(); page++)
292 {
293 if (page->second != NULL)
294 {
295 delete page->second;
296 }
297 }
298 delete m_pages;
299
300 wxPdfPageLinksMap::iterator pageLinks = m_pageLinks->begin();
301 for (pageLinks = m_pageLinks->begin(); pageLinks != m_pageLinks->end(); pageLinks++)
302 {
303 if (pageLinks->second != NULL)
304 {
305 delete pageLinks->second;
306 }
307 }
308 delete m_pageLinks;
309
310 wxPdfLinkHashMap::iterator link = m_links->begin();
311 for (link = m_links->begin(); link != m_links->end(); link++)
312 {
313 if (link->second != NULL)
314 {
315 delete link->second;
316 }
317 }
318 delete m_links;
319
320 delete m_namedLinks;
321
322 size_t j;
323 for (j = 0; j < m_outlines.GetCount(); j++)
324 {
325 wxPdfBookmark* bookmark = (wxPdfBookmark*) m_outlines[j];
326 delete bookmark;
327 }
328
329 wxPdfStringHashMap::iterator diff = m_diffs->begin();
330 for (diff = m_diffs->begin(); diff != m_diffs->end(); diff++)
331 {
332 if (diff->second != NULL)
333 {
334 delete diff->second;
335 }
336 }
337 delete m_diffs;
338
339 delete m_winansi;
340
341 wxPdfExtGStateMap::iterator extGState = m_extGStates->begin();
342 for (extGState = m_extGStates->begin(); extGState != m_extGStates->end(); extGState++)
343 {
344 if (extGState->second != NULL)
345 {
346 delete extGState->second;
347 }
348 }
349 delete m_extGStates;
350
351 delete m_extGSLookup;
352
353 wxPdfGradientMap::iterator gradient = m_gradients->begin();
354 for (gradient = m_gradients->begin(); gradient != m_gradients->end(); gradient++)
355 {
356 if (gradient->second != NULL)
357 {
358 delete gradient->second;
359 }
360 }
361 delete m_gradients;
362
363 wxPdfAnnotationsMap::iterator annotation = m_annotations->begin();
364 for (annotation = m_annotations->begin(); annotation != m_annotations->end(); annotation++)
365 {
366 if (annotation->second != NULL)
367 {
368 delete annotation->second;
369 }
370 }
371 delete m_annotations;
372
373 wxPdfFormAnnotsMap::iterator formAnnotation = m_formAnnotations->begin();
374 for (formAnnotation = m_formAnnotations->begin(); formAnnotation != m_formAnnotations->end(); formAnnotation++)
375 {
376 if (formAnnotation->second != NULL)
377 {
378 delete formAnnotation->second;
379 }
380 }
381 delete m_formAnnotations;
382
383 wxPdfFormFieldsMap::iterator formField = m_formFields->begin();
384 for (formField = m_formFields->begin(); formField != m_formFields->end(); formField++)
385 {
386 if (formField->second != NULL)
387 {
388 delete formField->second;
389 }
390 }
391 delete m_formFields;
392
393 wxPdfRadioGroupMap::iterator radioGroup = m_radioGroups->begin();
394 for (radioGroup = m_radioGroups->begin(); radioGroup != m_radioGroups->end(); radioGroup++)
395 {
396 if (radioGroup->second != NULL)
397 {
398 delete radioGroup->second;
399 }
400 }
401 delete m_radioGroups;
402
403 wxPdfTemplatesMap::iterator templateIter = m_templates->begin();
404 for (templateIter = m_templates->begin(); templateIter != m_templates->end(); templateIter++)
405 {
406 if (templateIter->second != NULL)
407 {
408 delete templateIter->second;
409 }
410 }
411 delete m_templates;
412
413 wxPdfParserMap::iterator parser = m_parsers->begin();
414 for (parser = m_parsers->begin(); parser != m_parsers->end(); parser++)
415 {
416 if (parser->second != NULL)
417 {
418 delete parser->second;
419 }
420 }
421 delete m_parsers;
422
423 wxPdfSpotColourMap::iterator spotColour = m_spotColours->begin();
424 for (spotColour = m_spotColours->begin(); spotColour != m_spotColours->end(); spotColour++)
425 {
426 if (spotColour->second != NULL)
427 {
428 delete spotColour->second;
429 }
430 }
431 delete m_spotColours;
432
433 wxPdfPatternMap::iterator pattern = m_patterns->begin();
434 for (pattern = m_patterns->begin(); pattern != m_patterns->end(); pattern++)
435 {
436 if (pattern->second != NULL)
437 {
438 delete pattern->second;
439 }
440 }
441 delete m_patterns;
442
443 wxPdfOcgMap::iterator ocg = m_ocgs->begin();
444 for (ocg = m_ocgs->begin(); ocg != m_ocgs->end(); ++ocg)
445 {
446 if (ocg->second != NULL)
447 {
448 delete ocg->second;
449 }
450 }
451 delete m_ocgs;
452
453 wxPdfLayerRGMap::iterator rg;
454 for (rg = m_rgLayers->begin(); rg != m_rgLayers->end(); ++rg)
455 {
456 if (rg->second != NULL)
457 {
458 delete rg->second;
459 }
460 }
461 delete m_rgLayers;
462
463 if (m_lockedLayers != NULL)
464 {
465 delete m_lockedLayers;
466 }
467
468 wxPdfAttachmentMap::iterator attach;
469 for (attach = m_attachments->begin(); attach != m_attachments->end(); ++attach)
470 {
471 if (attach->second != NULL)
472 {
473 delete attach->second;
474 }
475 }
476 delete m_attachments;
477
478 delete m_orientationChanges;
479 delete m_pageSizes;
480
481 delete m_offsets;
482
483 if (m_encryptor != NULL)
484 {
485 delete m_encryptor;
486 }
487
488 if (m_buffer != NULL)
489 {
490 delete m_buffer;
491 }
492 }
493
494 // --- Public methods
495
496 void
SetProtection(int permissions,const wxString & userPassword,const wxString & ownerPassword,wxPdfEncryptionMethod encryptionMethod,int keyLength)497 wxPdfDocument::SetProtection(int permissions,
498 const wxString& userPassword,
499 const wxString& ownerPassword,
500 wxPdfEncryptionMethod encryptionMethod,
501 int keyLength)
502 {
503 if (m_encryptor == NULL)
504 {
505 int revision = (keyLength > 0) ? 3 : 2;
506 switch (encryptionMethod)
507 {
508 case wxPDF_ENCRYPTION_AESV2:
509 revision = 4;
510 if (m_PDFVersion < wxS("1.6"))
511 {
512 m_PDFVersion = wxS("1.6");
513 }
514 break;
515 case wxPDF_ENCRYPTION_RC4V2:
516 revision = 3;
517 break;
518 case wxPDF_ENCRYPTION_RC4V1:
519 default:
520 revision = 2;
521 break;
522 }
523 m_encryptor = new wxPdfEncrypt(revision, keyLength);
524 m_encrypted = true;
525 int allowedFlags = wxPDF_PERMISSION_PRINT | wxPDF_PERMISSION_MODIFY |
526 wxPDF_PERMISSION_COPY | wxPDF_PERMISSION_ANNOT;
527 int protection = 192;
528 protection += (permissions & allowedFlags);
529 wxString ownerPswd = ownerPassword;
530 if (ownerPswd.Length() == 0)
531 {
532 ownerPswd = wxPdfUtility::GetUniqueId(wxS("wxPdfDoc"));
533 }
534 m_encryptor->GenerateEncryptionKey(userPassword, ownerPswd, protection);
535 }
536 }
537
538 void
SetImageScale(double scale)539 wxPdfDocument::SetImageScale(double scale)
540 {
541 m_imgscale = scale;
542 }
543
544 double
GetImageScale()545 wxPdfDocument::GetImageScale()
546 {
547 return m_imgscale;
548 }
549
550 double
GetPageWidth()551 wxPdfDocument::GetPageWidth()
552 {
553 return m_w;
554 }
555
556 double
GetPageHeight()557 wxPdfDocument::GetPageHeight()
558 {
559 return m_h;
560 }
561
562 double
GetBreakMargin()563 wxPdfDocument::GetBreakMargin()
564 {
565 return m_bMargin;
566 }
567
568 double
GetScaleFactor()569 wxPdfDocument::GetScaleFactor()
570 {
571 return m_k;
572 }
573
574 void
AliasNbPages(const wxString & alias)575 wxPdfDocument::AliasNbPages(const wxString& alias)
576 {
577 // Define an alias for total number of pages
578 m_aliasNbPages = alias;
579 }
580
581 void
Open()582 wxPdfDocument::Open()
583 {
584 // Begin document
585 m_state = 1;
586 }
587
588 void
AddPage(int orientation)589 wxPdfDocument::AddPage(int orientation)
590 {
591 AddPage(orientation, m_defPageSize);
592 }
593
594 void
AddPage(int orientation,wxPaperSize format)595 wxPdfDocument::AddPage(int orientation, wxPaperSize format)
596 {
597 wxSize pageSize = CalculatePageSize(format);
598 AddPage(orientation, pageSize);
599 }
600
601 void
AddPage(int orientation,double pageWidth,double pageHeight)602 wxPdfDocument::AddPage(int orientation, double pageWidth, double pageHeight)
603 {
604 if (pageWidth > 0 && pageHeight > 0)
605 {
606 wxSize pageSize = CalculatePageSize(pageWidth, pageHeight);
607 AddPage(orientation, pageSize);
608 }
609 else
610 {
611 wxLogError(wxString(wxS("wxPdfDocument::AddPage: ")) +
612 wxString::Format(_("Invalid page size (%.1f,%.1f)."), pageWidth, pageHeight));
613 }
614 }
615
616 void
AddPage(int orientation,wxSize pageSize)617 wxPdfDocument::AddPage(int orientation, wxSize pageSize)
618 {
619 if (m_inTemplate)
620 {
621 wxLogError(wxString(wxS("wxPdfDocument::AddPage: ")) +
622 wxString::Format(_("Adding pages in templates is impossible. Current template ID is %d."), m_templateId));
623 return;
624 }
625
626 // Start a new page
627 if (m_state == 0)
628 {
629 Open();
630 }
631 wxPdfFontDetails* currentFont = m_currentFont;
632 wxString family = m_fontFamily;
633 int style = m_fontStyle;
634 if (m_decoration & wxPDF_FONTSTYLE_UNDERLINE)
635 {
636 style |= wxPDF_FONTSTYLE_UNDERLINE;
637 }
638 if (m_decoration & wxPDF_FONTSTYLE_OVERLINE)
639 {
640 style |= wxPDF_FONTSTYLE_OVERLINE;
641 }
642 if (m_decoration & wxPDF_FONTSTYLE_STRIKEOUT)
643 {
644 style |= wxPDF_FONTSTYLE_STRIKEOUT;
645 }
646 double size = m_fontSizePt;
647 double lw = m_lineWidth;
648 wxPdfColour dc = m_drawColour;
649 wxPdfColour fc = m_fillColour;
650 wxPdfColour tc = m_textColour;
651 bool cf = m_colourFlag;
652
653 if (m_page > 0)
654 {
655 // Page footer
656 m_inFooter = true;
657 Footer();
658 m_inFooter = false;
659 // Close page
660 EndPage();
661 }
662
663 // Start new page
664 BeginPage(orientation, pageSize);
665
666 // Set line cap style to square
667 Out("2 J");
668
669 // Set line width
670 m_lineWidth = lw;
671 OutAscii(wxPdfUtility::Double2String(lw*m_k,2)+wxString(wxS(" w")));
672
673 // Set font
674 if (currentFont != NULL)
675 {
676 m_currentFont = currentFont;
677 m_fontStyle = style;
678 m_fontSizePt = size;
679 ForceCurrentFont();
680 }
681
682 // Set colours
683 m_drawColour = dc;
684 if (dc != wxPdfColour(0))
685 {
686 OutAscii(dc.GetColour(true));
687 }
688 m_fillColour = fc;
689 if (fc != wxPdfColour(0))
690 {
691 OutAscii(fc.GetColour(false));
692 }
693 m_textColour = tc;
694 m_colourFlag = cf;
695
696 // Page header
697 Header();
698
699 // Restore line width
700 if (m_lineWidth != lw)
701 {
702 m_lineWidth = lw;
703 OutAscii(wxPdfUtility::Double2String(lw*m_k,2)+wxString(wxS(" w")));
704 }
705
706 // Restore font
707 if(family.Length() > 0)
708 {
709 SetFont(family, style, size);
710 }
711 if (currentFont != NULL)
712 {
713 SetFont(currentFont->GetUserFont(), style, size);
714 }
715
716 // Restore colours
717 if (m_drawColour != dc)
718 {
719 m_drawColour = dc;
720 OutAscii(dc.GetColour(true));
721 }
722 if (m_fillColour != fc)
723 {
724 m_fillColour = fc;
725 OutAscii(fc.GetColour(false));
726 }
727 m_textColour = tc;
728 m_colourFlag = cf;
729 }
730
731 void
SetLineWidth(double width)732 wxPdfDocument::SetLineWidth(double width)
733 {
734 // Set line width
735 m_lineWidth = width;
736 if (m_page > 0)
737 {
738 OutAscii(wxPdfUtility::Double2String(width*m_k,2)+ wxString(wxS(" w")));
739 }
740 }
741
742 double
GetLineWidth()743 wxPdfDocument::GetLineWidth()
744 {
745 return m_lineWidth;
746 }
747
748 bool
AddFont(const wxString & family,const wxString & style,const wxString & file)749 wxPdfDocument::AddFont(const wxString& family, const wxString& style, const wxString& file)
750 {
751 bool ok = !family.IsEmpty();
752 if (ok)
753 {
754 wxPdfFont regFont = wxPdfFontManager::GetFontManager()->GetFont(family, style);
755 if (!regFont.IsValid())
756 {
757 wxString fileName = file;
758 if (fileName.IsEmpty())
759 {
760 fileName = family.Lower() + style.Lower() + wxString(wxS(".xml"));
761 fileName.Replace(wxS(" "),wxS(""));
762 }
763 regFont = wxPdfFontManager::GetFontManager()->RegisterFont(fileName, family);
764 ok = regFont.IsValid();
765 }
766 }
767 return ok;
768 }
769
770 #if wxUSE_UNICODE
771
772 bool
AddFontCJK(const wxString & family)773 wxPdfDocument::AddFontCJK(const wxString& family)
774 {
775 bool ok = !family.IsEmpty();
776 if (ok)
777 {
778 wxPdfFont regFont = wxPdfFontManager::GetFontManager()->GetFont(family);
779 if (!regFont.IsValid())
780 {
781 ok = wxPdfFontManager::GetFontManager()->RegisterFontCJK(family);
782 }
783 }
784 return ok;
785 }
786
787 #endif // wxUSE_UNICODE
788
789 bool
SetFont(const wxString & family,const wxString & style,double size)790 wxPdfDocument::SetFont(const wxString& family, const wxString& style, double size)
791 {
792 return SelectFont(family, style, size);
793 }
794
795 bool
SetFont(const wxString & family,int style,double size)796 wxPdfDocument::SetFont(const wxString& family, int style, double size)
797 {
798 return SelectFont(family, style, size);
799 }
800
801 bool
SetFont(const wxPdfFont & font,int style,double size)802 wxPdfDocument::SetFont(const wxPdfFont& font, int style, double size)
803 {
804 return SelectFont(font, style, size);
805 }
806
807 bool
SetFont(const wxFont & font)808 wxPdfDocument::SetFont(const wxFont& font)
809 {
810 return SelectFont(font);
811 }
812
813 void
SetFontSize(double size)814 wxPdfDocument::SetFontSize(double size)
815 {
816 SetFontSize(size, true);
817 }
818
819 void
SetFontSize(double size,bool setSize)820 wxPdfDocument::SetFontSize(double size, bool setSize)
821 {
822 if (m_currentFont == NULL)
823 {
824 wxLogError(wxString(wxS("wxPdfDocument::SetFontSize: ")) +
825 wxString(_("No font selected.")));
826 return;
827 }
828 // Set font size in points
829 if (m_fontSizePt == size)
830 {
831 return;
832 }
833 m_fontSizePt = size;
834 m_fontSize = size / m_k;
835 if (setSize && m_page > 0)
836 {
837 OutAscii(wxString::Format(wxS("BT /F%d "),m_currentFont->GetIndex()) +
838 wxPdfUtility::Double2String(m_fontSizePt,2) + wxString(wxS(" Tf ET")));
839 }
840 }
841
842 wxPdfFont
GetCurrentFont() const843 wxPdfDocument::GetCurrentFont() const
844 {
845 if (m_currentFont == NULL)
846 {
847 wxLogError(wxString(wxS("wxPdfDocument::GetCurrentFont: ")) +
848 wxString(_("No font selected.")));
849 return wxPdfFont();
850 }
851 return m_currentFont->GetUserFont();
852 }
853
854 const wxPdfFontDescription&
GetFontDescription() const855 wxPdfDocument::GetFontDescription() const
856 {
857 if (m_currentFont == NULL)
858 {
859 wxLogError(wxString(wxS("wxPdfDocument::GetFontDescription: ")) +
860 wxString(_("No font selected.")));
861 static wxPdfFontDescription dummy;
862 return dummy;
863 }
864 return m_currentFont->GetDescription();
865 }
866
867 const wxString
GetFontFamily()868 wxPdfDocument::GetFontFamily()
869 {
870 return m_fontFamily;
871 }
872
873 const wxString
GetFontStyle() const874 wxPdfDocument::GetFontStyle() const
875 {
876 wxString style = wxEmptyString;
877 int styles = GetFontStyles();
878 if (styles & wxPDF_FONTSTYLE_BOLD)
879 {
880 style += wxString(wxS("B"));
881 }
882 if (styles & wxPDF_FONTSTYLE_ITALIC)
883 {
884 style += wxString(wxS("I"));
885 }
886 if (styles & wxPDF_FONTSTYLE_UNDERLINE)
887 {
888 style += wxString(wxS("U"));
889 }
890 if (styles & wxPDF_FONTSTYLE_OVERLINE)
891 {
892 style += wxString(wxS("O"));
893 }
894 if (styles & wxPDF_FONTSTYLE_STRIKEOUT)
895 {
896 style += wxString(wxS("S"));
897 }
898 return style;
899 }
900
901 int
GetFontStyles() const902 wxPdfDocument::GetFontStyles() const
903 {
904 return m_fontStyle | m_decoration;
905 }
906
907 double
GetFontSize() const908 wxPdfDocument::GetFontSize() const
909 {
910 return m_fontSizePt;
911 }
912
913 double
GetStringWidth(const wxString & s)914 wxPdfDocument::GetStringWidth(const wxString& s)
915 {
916 wxString voText = ApplyVisualOrdering(s);
917 return DoGetStringWidth(voText);
918 }
919
920 double
DoGetStringWidth(const wxString & s)921 wxPdfDocument::DoGetStringWidth(const wxString& s)
922 {
923 double w = 0;
924 if (m_currentFont != 0)
925 {
926 w = m_currentFont->GetStringWidth(s, m_kerning) * m_fontSize;
927 }
928 return w;
929 }
930
931 void
Text(double x,double y,const wxString & txt)932 wxPdfDocument::Text(double x, double y, const wxString& txt)
933 {
934 // Output a string
935 wxString voText = ApplyVisualOrdering(txt);
936
937 if (m_colourFlag)
938 {
939 Out("q ", false);
940 OutAscii(m_textColour.GetColour(false), false);
941 Out(" ", false);
942 }
943 if (m_yAxisOriginTop)
944 {
945 OutAscii(wxString(wxS("BT 1 0 0 -1 ")) +
946 wxPdfUtility::Double2String(x*m_k,2) + wxString(wxS(" ")) +
947 wxPdfUtility::Double2String(y*m_k,2) + wxString(wxS(" Tm ")), false);
948 }
949 else
950 {
951 OutAscii(wxString(wxS("BT ")) +
952 wxPdfUtility::Double2String(x*m_k,2) + wxString(wxS(" ")) +
953 wxPdfUtility::Double2String(y*m_k,2) + wxString(wxS(" Td ")), false);
954 }
955 OutAscii(wxString::Format(wxS("%d Tr "), m_textRenderMode), false);
956 ShowText(voText);
957 Out("ET", false);
958
959 if ((m_decoration & wxPDF_FONTSTYLE_DECORATION_MASK) && voText.Length() > 0)
960 {
961 Out(" ", false);
962 OutAscii(DoDecoration(x, y, voText), false);
963 }
964
965 if (m_colourFlag)
966 {
967 Out(" Q", false);
968 }
969 Out("\n", false);
970 }
971
972 void
RotatedText(double x,double y,const wxString & txt,double angle)973 wxPdfDocument::RotatedText(double x, double y, const wxString& txt, double angle)
974 {
975 // Text rotated around its origin
976 if (angle == 0)
977 {
978 Text(x, y, txt);
979 }
980 else
981 {
982 StartTransform();
983 Rotate(angle, x, y);
984 Text(x, y, txt);
985 StopTransform();
986 }
987 }
988
989 void
RotatedText(double textX,double textY,double rotationX,double rotationY,const wxString & txt,double angle)990 wxPdfDocument::RotatedText(double textX, double textY, double rotationX, double rotationY, const wxString& txt, double angle)
991 {
992 // Text rotated around its origin
993 if (angle == 0)
994 {
995 Text(textX, textY, txt);
996 }
997 else
998 {
999 StartTransform();
1000 Rotate(angle, rotationX, rotationY);
1001 Text(textX, textY, txt);
1002 StopTransform();
1003 }
1004 }
1005
1006 bool
AcceptPageBreak()1007 wxPdfDocument::AcceptPageBreak()
1008 {
1009 // Accept automatic page break or not
1010 return m_autoPageBreak;
1011 }
1012
1013 void
Cell(double w,double h,const wxString & txt,int border,int ln,int align,int fill,const wxPdfLink & link)1014 wxPdfDocument::Cell(double w, double h, const wxString& txt, int border, int ln, int align, int fill, const wxPdfLink& link)
1015 {
1016 wxString voText = ApplyVisualOrdering(txt);
1017 DoCell(w, h, voText, border, ln, align, fill, link);
1018 }
1019
1020 void
DoCell(double w,double h,const wxString & txt,int border,int ln,int align,int fill,const wxPdfLink & link)1021 wxPdfDocument::DoCell(double w, double h, const wxString& txt, int border, int ln, int align, int fill, const wxPdfLink& link)
1022 {
1023 // Output a cell
1024 double x, y;
1025 double k = m_k;
1026 bool doPageBreak = (m_yAxisOriginTop) ? (m_y+h > m_pageBreakTrigger) : (m_y-h < m_pageBreakTrigger);
1027 if (doPageBreak && !m_inFooter && AcceptPageBreak())
1028 {
1029 // Automatic page break
1030 x = m_x;
1031 double ws = m_ws;
1032 if (ws > 0)
1033 {
1034 m_ws = 0;
1035 Out("0 Tw");
1036 }
1037 AddPage(m_curOrientation);
1038 m_x = x;
1039 if (ws > 0)
1040 {
1041 m_ws = ws;
1042 if (!m_wsApply)
1043 {
1044 OutAscii(wxPdfUtility::Double2String(ws*k, 3) + wxString(wxS(" Tw")));
1045 }
1046 }
1047 }
1048 if ( w == 0)
1049 {
1050 w = m_w - m_rMargin - m_x;
1051 }
1052 wxString s = wxEmptyString;
1053 if (fill == 1 || border == wxPDF_BORDER_FRAME)
1054 {
1055 s = wxPdfUtility::Double2String(m_x*k,2) + wxString(wxS(" ")) +
1056 wxPdfUtility::Double2String(m_y*k,2) + wxString(wxS(" ")) +
1057 wxPdfUtility::Double2String(w*k,2) + wxString(wxS(" ")) +
1058 wxPdfUtility::Double2String(h*k,2);
1059 if (fill == 1)
1060 {
1061 if (border == wxPDF_BORDER_FRAME)
1062 {
1063 s += wxString(wxS(" re B "));
1064 }
1065 else
1066 {
1067 s += wxString(wxS(" re f "));
1068 }
1069 }
1070 else
1071 {
1072 s += wxString(wxS(" re S "));
1073 }
1074 }
1075 if (border != wxPDF_BORDER_NONE && border != wxPDF_BORDER_FRAME)
1076 {
1077 x = m_x;
1078 y = m_y;
1079 if (border & wxPDF_BORDER_LEFT)
1080 {
1081 s += wxPdfUtility::Double2String(x*k,2) + wxString(wxS(" ")) +
1082 wxPdfUtility::Double2String(y*k,2) + wxString(wxS(" m ")) +
1083 wxPdfUtility::Double2String(x*k,2) + wxString(wxS(" ")) +
1084 wxPdfUtility::Double2String((y+h)*k,2) + wxString(wxS(" l S "));
1085 }
1086 if (border & wxPDF_BORDER_TOP)
1087 {
1088 s += wxPdfUtility::Double2String(x*k,2) + wxString(wxS(" ")) +
1089 wxPdfUtility::Double2String(y*k,2) + wxString(wxS(" m ")) +
1090 wxPdfUtility::Double2String((x+w)*k,2) + wxString(wxS(" ")) +
1091 wxPdfUtility::Double2String(y*k,2) + wxString(wxS(" l S "));
1092 }
1093 if (border & wxPDF_BORDER_RIGHT)
1094 {
1095 s += wxPdfUtility::Double2String((x+w)*k,2) + wxString(wxS(" ")) +
1096 wxPdfUtility::Double2String(y*k,2) + wxString(wxS(" m ")) +
1097 wxPdfUtility::Double2String((x+w)*k,2) + wxString(wxS(" ")) +
1098 wxPdfUtility::Double2String((y+h)*k,2) + wxString(wxS(" l S "));
1099 }
1100 if (border & wxPDF_BORDER_BOTTOM)
1101 {
1102 s += wxPdfUtility::Double2String(x*k,2) + wxString(wxS(" ")) +
1103 wxPdfUtility::Double2String((y+h)*k,2) + wxString(wxS(" m ")) +
1104 wxPdfUtility::Double2String((x+w)*k,2) + wxString(wxS(" ")) +
1105 wxPdfUtility::Double2String((y+h)*k,2) + wxString(wxS(" l S "));
1106 }
1107 }
1108 if (s.Length() > 0)
1109 {
1110 bool newline = txt.Length() == 0;
1111 OutAscii(s, newline);
1112 s = wxS("");
1113 }
1114
1115 if (txt.Length() > 0)
1116 {
1117 double width = DoGetStringWidth(txt);
1118 double dx;
1119 if (align == wxPDF_ALIGN_RIGHT)
1120 {
1121 dx = w - m_cMargin - width;
1122 }
1123 else if (align == wxPDF_ALIGN_CENTER)
1124 {
1125 dx = (w - width) / 2;
1126 }
1127 else
1128 {
1129 dx = m_cMargin;
1130 }
1131 if (m_colourFlag)
1132 {
1133 s += wxString(wxS("q ")) + m_textColour.GetColour(false) + wxString(wxS(" "));
1134 }
1135 if (m_yAxisOriginTop)
1136 {
1137 s += wxString(wxS("BT 1 0 0 -1 ")) +
1138 wxPdfUtility::Double2String((m_x+dx)*k,2) + wxString(wxS(" ")) +
1139 wxPdfUtility::Double2String((m_y+.5*h+.3*m_fontSize)*k,2) + wxString(wxS(" Tm "));
1140 }
1141 else
1142 {
1143 s += wxString(wxS("BT ")) +
1144 wxPdfUtility::Double2String((m_x+dx)*k,2) + wxString(wxS(" ")) +
1145 wxPdfUtility::Double2String((m_y+.5*h+.3*m_fontSize)*k,2) + wxString(wxS(" Td "));
1146 }
1147 OutAscii(s,false);
1148 OutAscii(wxString::Format(wxS("%d Tr "), m_textRenderMode), false);
1149 ShowText(txt);
1150 s = wxS(" ET");
1151
1152 if (m_decoration & wxPDF_FONTSTYLE_DECORATION_MASK)
1153 {
1154 s += wxString(wxS(" ")) + DoDecoration(m_x+dx,m_y+.5*h+.3*m_fontSize,txt);
1155 }
1156 if (m_colourFlag)
1157 {
1158 s += wxString(wxS(" Q"));
1159 }
1160 if (link.IsValid())
1161 {
1162 Link(m_x+dx,m_y+.5*h-.5*m_fontSize,width,m_fontSize,link);
1163 }
1164 OutAscii(s);
1165 }
1166 m_lasth = h;
1167 if (ln > 0)
1168 {
1169 // Go to next line
1170 if (m_yAxisOriginTop)
1171 {
1172 m_y += h;
1173 }
1174 else
1175 {
1176 m_y -= h;
1177 }
1178 if ( ln == 1)
1179 {
1180 m_x = m_lMargin;
1181 }
1182 }
1183 else
1184 {
1185 m_x += w;
1186 }
1187 }
1188
1189 int
MultiCell(double w,double h,const wxString & txt,int border,int align,int fill,int maxline)1190 wxPdfDocument::MultiCell(double w, double h, const wxString& txt, int border, int align, int fill, int maxline)
1191 {
1192 // Output text with automatic or explicit line breaks
1193 if (w == 0)
1194 {
1195 w = m_w - m_rMargin - m_x;
1196 }
1197
1198 // Determine whether to apply manual word spacing
1199 wxString fontType = m_currentFont->GetType();
1200 m_wsApply = (align == wxPDF_ALIGN_JUSTIFY) && ((fontType == wxS("TrueTypeUnicode")) || (fontType == wxS("OpenTypeUnicode")));
1201
1202 double wmax = (w - 2 * m_cMargin);
1203 wxString s = ApplyVisualOrdering(txt);
1204 s.Replace(wxS("\r"),wxS("")); // remove carriage returns
1205 int nb = (int) s.Length();
1206 if (nb > 0 && s[nb-1] == wxS('\n'))
1207 {
1208 nb--;
1209 }
1210
1211 int b = wxPDF_BORDER_NONE;
1212 int b2 = wxPDF_BORDER_NONE;
1213 if (border != wxPDF_BORDER_NONE)
1214 {
1215 if (border == wxPDF_BORDER_FRAME)
1216 {
1217 b = wxPDF_BORDER_LEFT | wxPDF_BORDER_RIGHT | wxPDF_BORDER_TOP;
1218 b2 = wxPDF_BORDER_LEFT | wxPDF_BORDER_RIGHT;
1219 }
1220 else
1221 {
1222 b2 = wxPDF_BORDER_NONE;
1223 if (border & wxPDF_BORDER_LEFT)
1224 {
1225 b2 = b2 | wxPDF_BORDER_LEFT;
1226 }
1227 if (border & wxPDF_BORDER_RIGHT)
1228 {
1229 b2 = b2 | wxPDF_BORDER_RIGHT;
1230 }
1231 b = (border & wxPDF_BORDER_TOP) ? b2 | wxPDF_BORDER_TOP : b2;
1232 }
1233 }
1234 int sep = -1;
1235 int i = 0;
1236 int j = 0;
1237 double len = 0;
1238 double ls = 0;
1239 int ns = 0;
1240 int nl = 1;
1241 wxChar c;
1242 while (i < nb)
1243 {
1244 // Get next character
1245 c = s[i];
1246 if (c == wxS('\n'))
1247 {
1248 // Explicit line break
1249 if (m_ws > 0)
1250 {
1251 m_ws = 0;
1252 Out("0 Tw");
1253 }
1254 DoCell(w,h,s.SubString(j,i-1),b,2,align,fill);
1255 i++;
1256 sep = -1;
1257 j = i;
1258 len = 0;
1259 ns = 0;
1260 nl++;
1261 if (border != wxPDF_BORDER_NONE && nl == 2)
1262 {
1263 b = b2;
1264 }
1265 if (maxline > 0 && nl > maxline)
1266 {
1267 return j;
1268 }
1269 continue;
1270 }
1271 if (c == wxS(' '))
1272 {
1273 sep = i;
1274 ls = len;
1275 ns++;
1276 }
1277 len = DoGetStringWidth(s.SubString(j, i));
1278
1279 if (len > wmax)
1280 {
1281 // Automatic line break
1282 if (sep == -1)
1283 {
1284 if (i == j)
1285 {
1286 i++;
1287 }
1288 if (m_ws > 0)
1289 {
1290 m_ws = 0;
1291 Out("0 Tw");
1292 }
1293 DoCell(w,h,s.SubString(j,i-1),b,2,align,fill);
1294 }
1295 else
1296 {
1297 if (align == wxPDF_ALIGN_JUSTIFY)
1298 {
1299 m_ws = (ns > 1) ? (wmax - ls)/(ns-1) : 0;
1300 if (!m_wsApply)
1301 {
1302 OutAscii(wxPdfUtility::Double2String(m_ws*m_k, 3) + wxString(wxS(" Tw")));
1303 }
1304 }
1305 DoCell(w,h,s.SubString(j,sep-1),b,2,align,fill);
1306 i = sep + 1;
1307 }
1308 sep = -1;
1309 j = i;
1310 len = 0;
1311 ns = 0;
1312 nl++;
1313 if (border != wxPDF_BORDER_NONE && nl == 2)
1314 {
1315 b = b2;
1316 }
1317 if (maxline > 0 && nl > maxline)
1318 {
1319 return j;
1320 }
1321 }
1322 else
1323 {
1324 i++;
1325 }
1326 }
1327 // Last chunk
1328 if (m_ws > 0)
1329 {
1330 m_ws = 0;
1331 Out("0 Tw");
1332 }
1333 if ((border != wxPDF_BORDER_NONE) && (border & wxPDF_BORDER_BOTTOM))
1334 {
1335 b = b | wxPDF_BORDER_BOTTOM;
1336 }
1337 DoCell(w,h,s.SubString(j,i-1),b,2,align,fill);
1338 m_x = m_lMargin;
1339 m_wsApply = false;
1340 return i;
1341 }
1342
1343 int
LineCount(double w,const wxString & txt)1344 wxPdfDocument::LineCount(double w, const wxString& txt)
1345 {
1346 // Output text with automatic or explicit line breaks
1347 if (w == 0)
1348 {
1349 w = m_w - m_rMargin - m_x;
1350 }
1351
1352 double wmax = (w - 2 * m_cMargin);
1353 wxString s = txt;
1354 s.Replace(wxS("\r"),wxS("")); // remove carriage returns
1355 int nb = (int) s.Length();
1356 if (nb > 0 && s[nb-1] == wxS('\n'))
1357 {
1358 nb--;
1359 }
1360
1361 int sep = -1;
1362 int i = 0;
1363 int j = 0;
1364 double len = 0;
1365 int nl = 1;
1366 wxChar c;
1367 while (i < nb)
1368 {
1369 // Get next character
1370 c = s[i];
1371 if (c == wxS('\n'))
1372 {
1373 // Explicit line break
1374 i++;
1375 sep = -1;
1376 j = i;
1377 len = 0;
1378 nl++;
1379 continue;
1380 }
1381 if (c == wxS(' '))
1382 {
1383 sep = i;
1384 }
1385 len = DoGetStringWidth(s.SubString(j, i));
1386
1387 if (len > wmax)
1388 {
1389 // Automatic line break
1390 if (sep == -1)
1391 {
1392 if (i == j)
1393 {
1394 i++;
1395 }
1396 }
1397 else
1398 {
1399 i = sep + 1;
1400 }
1401 sep = -1;
1402 j = i;
1403 len = 0;
1404 nl++;
1405 }
1406 else
1407 {
1408 i++;
1409 }
1410 }
1411 return nl;
1412 }
1413
1414 int
TextBox(double w,double h,const wxString & txt,int halign,int valign,int border,int fill)1415 wxPdfDocument::TextBox(double w, double h, const wxString& txt,
1416 int halign, int valign, int border, int fill)
1417 {
1418 double xi = m_x;
1419 double yi = m_y;
1420
1421 double hrow = m_fontSize;
1422 int textrows = LineCount(w, txt);
1423 int maxrows = (int) floor(h / hrow);
1424 int rows = (textrows < maxrows) ? textrows : maxrows;
1425
1426 double dy = 0;
1427 if (valign == wxPDF_ALIGN_MIDDLE)
1428 {
1429 dy = (h - rows * hrow) / 2;
1430 }
1431 else if (valign == wxPDF_ALIGN_BOTTOM)
1432 {
1433 dy = h - rows * hrow;
1434 }
1435
1436 SetY(yi+dy);
1437 SetX(xi);
1438 int trail = MultiCell(w, hrow, txt, 0, halign, fill, rows);
1439
1440 if (border == wxPDF_BORDER_FRAME)
1441 {
1442 Rect(xi, yi, w, h);
1443 }
1444 else
1445 {
1446 if (border & wxPDF_BORDER_LEFT) Line(xi,yi,xi,yi+h);
1447 if (border & wxPDF_BORDER_RIGHT) Line(xi+w,yi,xi+w,yi+h);
1448 if (border & wxPDF_BORDER_TOP) Line(xi,yi,xi+w,yi);
1449 if (border & wxPDF_BORDER_BOTTOM) Line(xi,yi+h,xi+w,yi+h);
1450 }
1451
1452 return trail;
1453 }
1454
1455 void
Write(double h,const wxString & txt,const wxPdfLink & link)1456 wxPdfDocument::Write(double h, const wxString& txt, const wxPdfLink& link)
1457 {
1458 WriteCell(h, txt, wxPDF_BORDER_NONE, 0, link);
1459 }
1460
1461 void
WriteCell(double h,const wxString & txt,int border,int fill,const wxPdfLink & link)1462 wxPdfDocument::WriteCell(double h, const wxString& txt, int border, int fill, const wxPdfLink& link)
1463 {
1464 // Output text in flowing mode
1465 wxString s = ApplyVisualOrdering(txt);
1466
1467 s.Replace(wxS("\r"),wxS("")); // remove carriage returns
1468 int nb = (int) s.Length();
1469
1470 // handle single space character
1471 if ((nb == 1) && s[0] == wxS(' '))
1472 {
1473 m_x += DoGetStringWidth(s);
1474 return;
1475 }
1476
1477 double saveCellMargin = GetCellMargin();
1478 SetCellMargin(0);
1479
1480 double w = m_w - m_rMargin - m_x;
1481 double wmax = (w - 2 * m_cMargin) + wxPDF_EPSILON;
1482
1483 int sep = -1;
1484 int i = 0;
1485 int j = 0;
1486 double len=0;
1487 int nl = 1;
1488 wxChar c;
1489 while (i < nb)
1490 {
1491 // Get next character
1492 c = s[i];
1493 if (c == wxS('\n'))
1494 {
1495 // Explicit line break
1496 DoCell(w, h, s.SubString(j,i-1), border, 2, wxPDF_ALIGN_LEFT, fill, link);
1497 i++;
1498 sep = -1;
1499 j = i;
1500 len = 0;
1501 if (nl == 1)
1502 {
1503 m_x = m_lMargin;
1504 w = m_w - m_rMargin - m_x;
1505 wmax = (w - 2 * m_cMargin);
1506 }
1507 nl++;
1508 continue;
1509 }
1510 if (c == wxS(' '))
1511 {
1512 sep = i;
1513 }
1514 len = DoGetStringWidth(s.SubString(j, i));
1515 if (len > wmax)
1516 {
1517 // Automatic line break
1518 if (sep == -1)
1519 {
1520 if (m_x > m_lMargin)
1521 {
1522 // Move to next line
1523 m_x = m_lMargin;
1524 if (m_yAxisOriginTop)
1525 {
1526 m_y += h;
1527 }
1528 else
1529 {
1530 m_y -= h;
1531 }
1532 w = m_w - m_rMargin - m_x;
1533 wmax = (w - 2 * m_cMargin);
1534 i++;
1535 nl++;
1536 continue;
1537 }
1538 if (i == j)
1539 {
1540 i++;
1541 }
1542 DoCell(w, h,s.SubString(j, i-1), border, 2, wxPDF_ALIGN_LEFT, fill, link);
1543 }
1544 else
1545 {
1546 DoCell(w, h, s.SubString(j, sep-1), border, 2, wxPDF_ALIGN_LEFT, fill, link);
1547 i = sep + 1;
1548 }
1549 sep = -1;
1550 j = i;
1551 len = 0;
1552 if (nl == 1)
1553 {
1554 m_x = m_lMargin;
1555 w = m_w - m_rMargin - m_x;
1556 wmax = (w - 2 * m_cMargin);
1557 }
1558 nl++;
1559 }
1560 else
1561 {
1562 i++;
1563 }
1564 }
1565 // Last chunk
1566 if (i != j)
1567 {
1568 DoCell(len, h, s.SubString(j,i-1), border, 0, wxPDF_ALIGN_LEFT, fill, link);
1569 }
1570
1571 // Following statement was in PHP code, but seems to be in error.
1572 // m_x += GetStringWidth(s.SubString(j, i-1));
1573 SetCellMargin(saveCellMargin);
1574 }
1575
1576 bool
WriteGlyphArray(wxPdfArrayDouble & x,wxPdfArrayDouble & y,wxPdfArrayUint32 & glyphs)1577 wxPdfDocument::WriteGlyphArray(wxPdfArrayDouble& x, wxPdfArrayDouble& y, wxPdfArrayUint32& glyphs)
1578 {
1579 bool ok = m_currentFont != NULL;
1580 #if wxUSE_UNICODE
1581 if (ok)
1582 {
1583 // Check whether the current font is valid for this method
1584 wxString fontType = m_currentFont->GetType();
1585 if (fontType.IsSameAs(wxS("TrueTypeUnicode")) || fontType.IsSameAs(wxS("OpenTypeUnicode")))
1586 {
1587 // if the arrays have different sizes use only the smallest size
1588 size_t nx = x.GetCount();
1589 size_t ny = y.GetCount();
1590 size_t ng = glyphs.GetCount();
1591 size_t n = (nx > ny) ? ((ny > ng) ? ng : ny) : ((nx > ng) ? ng : nx);
1592 double xp, yp;
1593 size_t j;
1594 for (j = 0; j < n; ++j)
1595 {
1596 xp = m_x + x[j];
1597 yp = m_y + y[j];
1598 if (m_yAxisOriginTop)
1599 {
1600 Out("BT 1 0 0 -1 ", false);
1601 }
1602 else
1603 {
1604 Out("BT ", false);
1605 }
1606 OutAscii(wxPdfUtility::Double2String(xp*m_k,2), false);
1607 Out(" ", false);
1608 OutAscii(wxPdfUtility::Double2String(yp*m_k,2), false);
1609 if (m_yAxisOriginTop)
1610 {
1611 Out(" Tm ", false);
1612 }
1613 else
1614 {
1615 Out(" Td ", false);
1616 }
1617 ShowGlyph(glyphs[j]);
1618 Out(" ET");
1619 }
1620 }
1621 else
1622 {
1623 ok = false;
1624 wxLogError(wxString(wxS("wxPdfDocument::WriteGlyphArray: ")) +
1625 wxString::Format(_("Font type '%s' not supported."), fontType.c_str()));
1626 }
1627 }
1628 else
1629 {
1630 wxLogError(wxString(wxS("wxPdfDocument::WriteGlyphArray: ")) +
1631 wxString(_("No font selected.")));
1632 }
1633 #else
1634 wxUnusedVar(x);
1635 wxUnusedVar(y);
1636 wxUnusedVar(glyphs);
1637 wxLogError(wxString(wxS("wxPdfDocument::WriteGlyphArray: ")) +
1638 wxString(_("Supported in Unicode build only.")));
1639 #endif // wxUSE_UNICODE
1640 return ok;
1641 }
1642
1643 wxSize
GetImageSize(const wxString & file,const wxString & mimeType)1644 wxPdfDocument::GetImageSize(const wxString& file, const wxString& mimeType)
1645 {
1646 wxSize imageSize(0, 0);
1647 wxImage image;
1648 if (mimeType.IsEmpty())
1649 {
1650 // Auto detect image type
1651 image.LoadFile(file);
1652 }
1653 else
1654 {
1655 // Use mimetype as specified
1656 image.LoadFile(file, mimeType);
1657 }
1658 if (image.IsOk())
1659 {
1660 #if wxCHECK_VERSION(2,9,0)
1661 imageSize = image.GetSize();
1662 #else
1663 imageSize.Set(image.GetWidth(), image.GetHeight());
1664 #endif
1665 }
1666 return imageSize;
1667 }
1668
1669 bool
Image(const wxString & file,double x,double y,double w,double h,const wxString & type,const wxPdfLink & link,int maskImage)1670 wxPdfDocument::Image(const wxString& file, double x, double y, double w, double h,
1671 const wxString& type, const wxPdfLink& link, int maskImage)
1672 {
1673 wxPdfImage* currentImage = NULL;
1674 // Put an image on the page
1675 wxPdfImageHashMap::iterator image = (*m_images).find(file);
1676 if (image == (*m_images).end())
1677 {
1678 // First use of image, get info
1679 int i = (int) (*m_images).size() + 1;
1680 currentImage = new wxPdfImage(this, i, file, type);
1681 if (!currentImage->Parse())
1682 {
1683 bool isValid = false;
1684 delete currentImage;
1685
1686 if (wxImage::FindHandler(wxBITMAP_TYPE_PNG) == NULL)
1687 {
1688 wxImage::AddHandler(new wxPNGHandler());
1689 }
1690 wxImage tempImage;
1691 tempImage.LoadFile(file);
1692 if (tempImage.Ok())
1693 {
1694 isValid = Image(file, tempImage, x, y, w, h, link, maskImage);
1695 }
1696 return isValid;
1697 }
1698 if (maskImage > 0)
1699 {
1700 currentImage->SetMaskImage(maskImage);
1701 }
1702 (*m_images)[file] = currentImage;
1703 }
1704 else
1705 {
1706 currentImage = image->second;
1707 if (maskImage > 0 && currentImage->GetMaskImage() != maskImage)
1708 {
1709 currentImage->SetMaskImage(maskImage);
1710 }
1711 }
1712 OutImage(currentImage, x, y, w, h, link);
1713 return true;
1714 }
1715
1716 bool
Image(const wxString & name,const wxImage & img,double x,double y,double w,double h,const wxPdfLink & link,int maskImage,bool jpegFormat,int jpegQuality)1717 wxPdfDocument::Image(const wxString& name, const wxImage& img, double x, double y, double w, double h,
1718 const wxPdfLink& link, int maskImage, bool jpegFormat, int jpegQuality)
1719 {
1720 bool isValid = false;
1721 if (img.Ok())
1722 {
1723 wxImage tempImage = img.Copy();
1724 wxPdfImage* currentImage = NULL;
1725 // Put an image on the page
1726 wxPdfImageHashMap::iterator image = (*m_images).find(name);
1727 if (image == (*m_images).end())
1728 {
1729 if (tempImage.HasAlpha())
1730 {
1731 if (maskImage <= 0)
1732 {
1733 maskImage = ImageMask(name+wxString(wxS(".mask")), tempImage);
1734 }
1735 if(!tempImage.ConvertAlphaToMask(0))
1736 {
1737 return false;
1738 }
1739 }
1740 else if (tempImage.HasMask() && maskImage <= 0)
1741 {
1742 // Extract the mask
1743 wxImage mask = tempImage.ConvertToMono(tempImage.GetMaskRed(), tempImage.GetMaskGreen(), tempImage.GetMaskBlue());
1744 // Invert the mask
1745 mask = mask.ConvertToMono(0, 0, 0);
1746 maskImage = ImageMask(name+wxString(wxS(".mask")), mask);
1747 }
1748 // First use of image, get info
1749 tempImage.SetMask(false);
1750 if (jpegFormat)
1751 {
1752 tempImage.SetOption(wxIMAGE_OPTION_QUALITY, jpegQuality);
1753 }
1754 int i = (int) (*m_images).size() + 1;
1755 currentImage = new wxPdfImage(this, i, name, tempImage, jpegFormat);
1756 if (!currentImage->Parse())
1757 {
1758 delete currentImage;
1759 return false;
1760 }
1761 if (maskImage > 0)
1762 {
1763 currentImage->SetMaskImage(maskImage);
1764 }
1765 (*m_images)[name] = currentImage;
1766 }
1767 else
1768 {
1769 currentImage = image->second;
1770 if (maskImage > 0 && currentImage->GetMaskImage() != maskImage)
1771 {
1772 currentImage->SetMaskImage(maskImage);
1773 }
1774 }
1775 OutImage(currentImage, x, y, w, h, link);
1776 isValid = true;
1777 }
1778 return isValid;
1779 }
1780
1781 bool
Image(const wxString & name,wxInputStream & stream,const wxString & mimeType,double x,double y,double w,double h,const wxPdfLink & link,int maskImage)1782 wxPdfDocument::Image(const wxString& name, wxInputStream& stream,
1783 const wxString& mimeType,
1784 double x, double y, double w, double h,
1785 const wxPdfLink& link, int maskImage)
1786 {
1787 bool isValid = false;
1788 wxPdfImage* currentImage = NULL;
1789 // Put an image on the page
1790 wxPdfImageHashMap::iterator image = (*m_images).find(name);
1791 if (image == (*m_images).end())
1792 {
1793 // First use of image, get info
1794 int i = (int) (*m_images).size() + 1;
1795 currentImage = new wxPdfImage(this, i, name, stream, mimeType);
1796 if (!currentImage->Parse())
1797 {
1798 delete currentImage;
1799 if (wxImage::FindHandler(wxBITMAP_TYPE_PNG) == NULL)
1800 {
1801 wxImage::AddHandler(new wxPNGHandler());
1802 }
1803 wxImage tempImage;
1804 tempImage.LoadFile(stream, mimeType);
1805 if (tempImage.Ok())
1806 {
1807 isValid = Image(name, tempImage, x, y, w, h, link, maskImage);
1808 }
1809 return isValid;
1810
1811 }
1812 if (maskImage > 0)
1813 {
1814 currentImage->SetMaskImage(maskImage);
1815 }
1816 (*m_images)[name] = currentImage;
1817 }
1818 else
1819 {
1820 currentImage = image->second;
1821 if (maskImage > 0 && currentImage->GetMaskImage() != maskImage)
1822 {
1823 currentImage->SetMaskImage(maskImage);
1824 }
1825 }
1826 OutImage(currentImage, x, y, w, h, link);
1827 isValid = true;
1828 return isValid;
1829 }
1830
1831 int
ImageMask(const wxString & file,const wxString & type)1832 wxPdfDocument::ImageMask(const wxString& file, const wxString& type)
1833 {
1834 int n = 0;
1835 wxPdfImage* currentImage = NULL;
1836 // Put an image on the page
1837 wxPdfImageHashMap::iterator image = (*m_images).find(file);
1838 if (image == (*m_images).end())
1839 {
1840 // First use of image, get info
1841 n = (int) (*m_images).size() + 1;
1842 currentImage = new wxPdfImage(this, n, file, type);
1843 if (!currentImage->Parse())
1844 {
1845 delete currentImage;
1846 return 0;
1847 }
1848 // Check whether this is a gray scale image (must be)
1849 if (currentImage->GetColourSpace() != wxS("DeviceGray"))
1850 {
1851 delete currentImage;
1852 return 0;
1853 }
1854 (*m_images)[file] = currentImage;
1855 }
1856 else
1857 {
1858 currentImage = image->second;
1859 n = currentImage->GetIndex();
1860 }
1861 if (m_PDFVersion < wxS("1.4"))
1862 {
1863 m_PDFVersion = wxS("1.4");
1864 }
1865 return n;
1866 }
1867
1868 int
ImageMask(const wxString & name,const wxImage & img)1869 wxPdfDocument::ImageMask(const wxString& name, const wxImage& img)
1870 {
1871 int n = 0;
1872 if (img.Ok())
1873 {
1874 wxPdfImage* currentImage = NULL;
1875 // Put an image on the page
1876 wxPdfImageHashMap::iterator image = (*m_images).find(name);
1877 if (image == (*m_images).end())
1878 {
1879 wxImage tempImage;
1880 if (img.HasAlpha())
1881 {
1882 int x, y;
1883 int w = img.GetWidth();
1884 int h = img.GetHeight();
1885 tempImage = wxImage(w, h);
1886 unsigned char alpha;
1887 for (x = 0; x < w; x++)
1888 {
1889 for (y = 0; y < h; y++)
1890 {
1891 alpha = img.GetAlpha(x, y);
1892 tempImage.SetRGB(x, y, alpha, alpha, alpha);
1893 }
1894 }
1895 tempImage.SetOption(wxIMAGE_OPTION_PNG_FORMAT, wxPNG_TYPE_GREY_RED);
1896 }
1897 else
1898 {
1899 tempImage = img.ConvertToGreyscale();
1900 tempImage.SetOption(wxIMAGE_OPTION_PNG_FORMAT, wxPNG_TYPE_GREY_RED);
1901 }
1902 tempImage.SetMask(false);
1903 // First use of image, get info
1904 n = (int) (*m_images).size() + 1;
1905 currentImage = new wxPdfImage(this, n, name, tempImage);
1906 if (!currentImage->Parse())
1907 {
1908 delete currentImage;
1909 return 0;
1910 }
1911 (*m_images)[name] = currentImage;
1912 }
1913 else
1914 {
1915 currentImage = image->second;
1916 n = currentImage->GetIndex();
1917 }
1918 if (m_PDFVersion < wxS("1.4"))
1919 {
1920 m_PDFVersion = wxS("1.4");
1921 }
1922 }
1923 return n;
1924 }
1925
1926 int
ImageMask(const wxString & name,wxInputStream & stream,const wxString & mimeType)1927 wxPdfDocument::ImageMask(const wxString& name, wxInputStream& stream, const wxString& mimeType)
1928 {
1929 int n = 0;
1930 wxPdfImage* currentImage = NULL;
1931 // Put an image on the page
1932 wxPdfImageHashMap::iterator image = (*m_images).find(name);
1933 if (image == (*m_images).end())
1934 {
1935 // First use of image, get info
1936 n = (int) (*m_images).size() + 1;
1937 currentImage = new wxPdfImage(this, n, name, stream, mimeType);
1938 if (!currentImage->Parse())
1939 {
1940 delete currentImage;
1941 return 0;
1942 }
1943 // Check whether this is a gray scale image (must be)
1944 if (currentImage->GetColourSpace() != wxS("DeviceGray"))
1945 {
1946 delete currentImage;
1947 return 0;
1948 }
1949 (*m_images)[name] = currentImage;
1950 }
1951 else
1952 {
1953 currentImage = image->second;
1954 n = currentImage->GetIndex();
1955 }
1956 if (m_PDFVersion < wxS("1.4"))
1957 {
1958 m_PDFVersion = wxS("1.4");
1959 }
1960 return n;
1961 }
1962
1963 void
RotatedImage(const wxString & file,double x,double y,double w,double h,double angle,const wxString & type,const wxPdfLink & link,int maskImage)1964 wxPdfDocument::RotatedImage(const wxString& file, double x, double y, double w, double h,
1965 double angle, const wxString& type, const wxPdfLink& link, int maskImage)
1966 {
1967 // Image rotated around its upper-left corner
1968 StartTransform();
1969 Rotate(angle, x, y);
1970 Image(file, x, y, w, h, type, link, maskImage);
1971 StopTransform();
1972 }
1973
1974 void
Ln(double h)1975 wxPdfDocument::Ln(double h)
1976 {
1977 // Line feed; default value is last cell height
1978 m_x = m_lMargin;
1979 if (h < 0)
1980 {
1981 if (m_yAxisOriginTop)
1982 {
1983 m_y += m_lasth;
1984 }
1985 else
1986 {
1987 m_y -= m_lasth;
1988 }
1989 }
1990 else
1991 {
1992 if (m_yAxisOriginTop)
1993 {
1994 m_y += h;
1995 }
1996 else
1997 {
1998 m_y -= h;
1999 }
2000 }
2001 }
2002
2003 bool
SaveAsFile(const wxString & name)2004 wxPdfDocument::SaveAsFile(const wxString& name)
2005 {
2006 wxString fileName = name;
2007 // Normalize parameters
2008 if(fileName.Length() == 0)
2009 {
2010 fileName = wxS("doc.pdf");
2011 }
2012
2013 wxLogNull logNull;
2014 wxFileOutputStream outfile(fileName);
2015 bool ok = outfile.IsOk();
2016
2017 if (ok)
2018 {
2019 // Finish document if necessary
2020 if (m_state < 3)
2021 {
2022 if (m_buffer != NULL)
2023 {
2024 delete m_buffer;
2025 }
2026 m_buffer = &outfile;
2027 Close();
2028 m_buffer = NULL;
2029 }
2030 else
2031 {
2032 // Save to local file
2033 wxMemoryInputStream tmp(*((wxMemoryOutputStream*) m_buffer));
2034 outfile.Write(tmp);
2035 }
2036 outfile.Close();
2037 }
2038 return ok;
2039 }
2040
2041 const wxMemoryOutputStream&
CloseAndGetBuffer()2042 wxPdfDocument::CloseAndGetBuffer()
2043 {
2044 if (m_state < 3)
2045 {
2046 Close();
2047 }
2048
2049 return *((wxMemoryOutputStream*) m_buffer);
2050 }
2051
2052 void
SetViewerPreferences(int preferences)2053 wxPdfDocument::SetViewerPreferences(int preferences)
2054 {
2055 m_viewerPrefs = (preferences > 0) ? preferences : 0;
2056 if (((m_viewerPrefs & wxPDF_VIEWER_DISPLAYDOCTITLE) != 0) && (m_PDFVersion < wxS("1.4")))
2057 {
2058 m_PDFVersion = wxS("1.4");
2059 }
2060 }
2061
2062 void
SetTitle(const wxString & title)2063 wxPdfDocument::SetTitle(const wxString& title)
2064 {
2065 // Title of document
2066 m_title = title;
2067 }
2068
2069 void
SetSubject(const wxString & subject)2070 wxPdfDocument::SetSubject(const wxString& subject)
2071 {
2072 // Subject of document
2073 m_subject = subject;
2074 }
2075
2076 void
SetAuthor(const wxString & author)2077 wxPdfDocument::SetAuthor(const wxString& author)
2078 {
2079 // Author of document
2080 m_author = author;
2081 }
2082
2083 void
SetKeywords(const wxString & keywords)2084 wxPdfDocument::SetKeywords(const wxString& keywords)
2085 {
2086 // Keywords of document
2087 m_keywords = keywords;
2088 }
2089
2090 void
SetCreator(const wxString & creator)2091 wxPdfDocument::SetCreator(const wxString& creator)
2092 {
2093 // Creator of document
2094 m_creator = creator;
2095 }
2096
2097 void
SetCreationDate(const wxDateTime & creationDate)2098 wxPdfDocument::SetCreationDate(const wxDateTime& creationDate)
2099 {
2100 if (creationDate.IsValid())
2101 {
2102 m_creationDateSet = true;
2103 m_creationDate = creationDate;
2104 }
2105 }
2106
2107 void
SetMargins(double left,double top,double right)2108 wxPdfDocument::SetMargins(double left, double top, double right)
2109 {
2110 // Set left, top and right margins
2111 m_lMargin = left;
2112 m_tMargin = top;
2113 if (right == -1)
2114 {
2115 right = left;
2116 }
2117 m_rMargin = right;
2118 }
2119
2120 void
SetLeftMargin(double margin)2121 wxPdfDocument::SetLeftMargin(double margin)
2122 {
2123 // Set left margin
2124 m_lMargin = margin;
2125 if (m_page > 0 && m_x < margin)
2126 {
2127 m_x = margin;
2128 }
2129 }
2130
2131 double
GetLeftMargin()2132 wxPdfDocument::GetLeftMargin()
2133 {
2134 return m_lMargin;
2135 }
2136
2137 void
SetTopMargin(double margin)2138 wxPdfDocument::SetTopMargin(double margin)
2139 {
2140 // Set top margin
2141 m_tMargin = margin;
2142 }
2143
2144 double
GetTopMargin()2145 wxPdfDocument::GetTopMargin()
2146 {
2147 return m_tMargin;
2148 }
2149
2150 void
SetRightMargin(double margin)2151 wxPdfDocument::SetRightMargin(double margin)
2152 {
2153 // Set right margin
2154 m_rMargin = margin;
2155 }
2156
2157 double
GetRightMargin()2158 wxPdfDocument::GetRightMargin()
2159 {
2160 return m_rMargin;
2161 }
2162
2163 void
SetCellMargin(double margin)2164 wxPdfDocument::SetCellMargin(double margin)
2165 {
2166 // Set cell margin
2167 m_cMargin = margin;
2168 }
2169
2170 double
GetCellMargin()2171 wxPdfDocument::GetCellMargin()
2172 {
2173 return m_cMargin;
2174 }
2175
2176 void
SetLineHeight(double height)2177 wxPdfDocument::SetLineHeight(double height)
2178 {
2179 m_lasth = height;
2180 }
2181
2182 double
GetLineHeight()2183 wxPdfDocument::GetLineHeight()
2184 {
2185 return m_lasth;
2186 }
2187
2188 void
SetAutoPageBreak(bool autoPageBreak,double margin)2189 wxPdfDocument::SetAutoPageBreak(bool autoPageBreak, double margin)
2190 {
2191 // Set auto page break mode and triggering margin
2192 m_autoPageBreak = autoPageBreak;
2193 m_bMargin = margin;
2194 m_pageBreakTrigger = (m_yAxisOriginTop) ? m_h - margin : margin;
2195 }
2196
2197 void
SetDisplayMode(wxPdfZoom zoom,wxPdfLayout layout,double zoomFactor)2198 wxPdfDocument::SetDisplayMode(wxPdfZoom zoom, wxPdfLayout layout, double zoomFactor)
2199 {
2200 // Set display mode in viewer
2201 switch (zoom)
2202 {
2203 case wxPDF_ZOOM_FULLPAGE:
2204 case wxPDF_ZOOM_FULLWIDTH:
2205 case wxPDF_ZOOM_REAL:
2206 case wxPDF_ZOOM_DEFAULT:
2207 m_zoomMode = zoom;
2208 break;
2209 case wxPDF_ZOOM_FACTOR:
2210 m_zoomMode = zoom;
2211 m_zoomFactor = (zoomFactor > 0) ? zoomFactor : 100.;
2212 break;
2213 default:
2214 m_zoomMode = wxPDF_ZOOM_FULLWIDTH;
2215 break;
2216 }
2217
2218 switch (layout)
2219 {
2220 case wxPDF_LAYOUT_SINGLE:
2221 case wxPDF_LAYOUT_TWO:
2222 case wxPDF_LAYOUT_DEFAULT:
2223 case wxPDF_LAYOUT_CONTINUOUS:
2224 m_layoutMode = layout;
2225 break;
2226 default:
2227 m_layoutMode = wxPDF_LAYOUT_CONTINUOUS;
2228 break;
2229 }
2230 }
2231
2232 void
Close()2233 wxPdfDocument::Close()
2234 {
2235 // Terminate document
2236 if (m_state == 3)
2237 {
2238 return;
2239 }
2240 if (m_page == 0)
2241 {
2242 AddPage();
2243 }
2244
2245 // Page footer
2246 m_inFooter = true;
2247 Footer();
2248 m_inFooter = false;
2249
2250 // Close page
2251 EndPage();
2252
2253 // Close document
2254 EndDoc();
2255 }
2256
2257 void
Header()2258 wxPdfDocument::Header()
2259 {
2260 // To be implemented in your own inherited class
2261 }
2262
2263 void
Footer()2264 wxPdfDocument::Footer()
2265 {
2266 // To be implemented in your own inherited class
2267 }
2268
2269 bool
IsInFooter()2270 wxPdfDocument::IsInFooter()
2271 {
2272 return m_inFooter;
2273 }
2274
2275 int
PageNo()2276 wxPdfDocument::PageNo()
2277 {
2278 // Get current page number
2279 return m_page;
2280 }
2281
2282 double
GetX()2283 wxPdfDocument::GetX()
2284 {
2285 // Get x position
2286 return m_x;
2287 }
2288
2289 void
SetX(double x)2290 wxPdfDocument::SetX(double x)
2291 {
2292 // Set x position
2293 if ( x >= 0.0)
2294 {
2295 m_x = x;
2296 }
2297 else
2298 {
2299 m_x = m_w + x;
2300 }
2301 }
2302
2303 double
GetY()2304 wxPdfDocument::GetY()
2305 {
2306 // Get y position
2307 return m_y;
2308 }
2309
2310 void
SetY(double y)2311 wxPdfDocument::SetY(double y)
2312 {
2313 // Set y position and reset x
2314 m_x = m_lMargin;
2315 if ( y >= 0)
2316 {
2317 m_y = y;
2318 }
2319 else
2320 {
2321 m_y = m_h + y;
2322 }
2323 }
2324
2325 void
SetXY(double x,double y)2326 wxPdfDocument::SetXY(double x, double y)
2327 {
2328 // Set x and y positions
2329 SetY(y);
2330 SetX(x);
2331 }
2332
2333 void
SetKerning(bool kerning)2334 wxPdfDocument::SetKerning(bool kerning)
2335 {
2336 m_kerning = kerning;
2337 }
2338
2339 void
SetCompression(bool compress)2340 wxPdfDocument::SetCompression(bool compress)
2341 {
2342 m_compress = compress;
2343 }
2344
2345 void
AppendJavascript(const wxString & javascript)2346 wxPdfDocument::AppendJavascript(const wxString& javascript)
2347 {
2348 m_javascript += javascript;
2349 }
2350
2351 bool
AttachFile(const wxString & fileName,const wxString & attachName,const wxString & description)2352 wxPdfDocument::AttachFile(const wxString& fileName, const wxString& attachName, const wxString& description)
2353 {
2354 wxFileName attachFile(fileName);
2355 bool ok = attachFile.FileExists();
2356 if (ok)
2357 {
2358 wxArrayString* attachment = new wxArrayString();
2359 attachment->Add(fileName);
2360 if (!attachName.IsEmpty())
2361 {
2362 attachment->Add(attachName);
2363 }
2364 else
2365 {
2366 attachment->Add(attachFile.GetFullName());
2367 }
2368 attachment->Add(description);
2369
2370 int index = (int) (m_attachments->size() + 1);
2371 (*m_attachments)[index] = attachment;
2372 }
2373 else
2374 {
2375 wxLogDebug(wxS("*** Attachment file '%s' does not exist."), fileName.c_str());
2376 }
2377 return ok;
2378 }
2379
2380 // ---
2381
2382 void
AddSpotColour(const wxString & name,double cyan,double magenta,double yellow,double black)2383 wxPdfDocument::AddSpotColour(const wxString& name, double cyan, double magenta, double yellow, double black)
2384 {
2385 wxPdfSpotColourMap::iterator spotColour = (*m_spotColours).find(name);
2386 if (spotColour == (*m_spotColours).end())
2387 {
2388 int i = (int) (*m_spotColours).size() + 1;
2389 (*m_spotColours)[name] = new wxPdfSpotColour(i, cyan, magenta, yellow, black);
2390 }
2391 }
2392
2393 bool
AddPattern(const wxString & patternName,const wxImage & image,double width,double height)2394 wxPdfDocument::AddPattern(const wxString& patternName, const wxImage& image, double width, double height)
2395 {
2396 bool isValid = true;
2397 wxPdfPatternMap::iterator patternIter = m_patterns->find(patternName);
2398 if (patternIter == m_patterns->end())
2399 {
2400 if (image.IsOk() && width > 0 && height > 0)
2401 {
2402 wxString imageName = wxString(wxS("pattern:")) + patternName;
2403 wxPdfImage* currentImage = NULL;
2404 wxPdfImageHashMap::iterator imageIter = (*m_images).find(imageName);
2405 if (imageIter == (*m_images).end())
2406 {
2407 // Prepare new image
2408 int maskImage = 0;
2409 wxImage tempImage = image.Copy();
2410 if (tempImage.HasAlpha())
2411 {
2412 maskImage = ImageMask(imageName+wxString(wxS(".mask")), tempImage);
2413 tempImage.ConvertAlphaToMask(0);
2414 }
2415 tempImage.SetMask(false);
2416 int i = (*m_images).size() + 1;
2417 currentImage = new wxPdfImage(this, i, imageName, tempImage);
2418 currentImage->Parse();
2419 if (maskImage > 0)
2420 {
2421 currentImage->SetMaskImage(maskImage);
2422 }
2423 (*m_images)[imageName] = currentImage;
2424 }
2425 else
2426 {
2427 // Use existing image
2428 currentImage = imageIter->second;
2429 }
2430
2431 // Register new pattern
2432 wxPdfPattern* pattern;
2433 int i = (int) m_patterns->size() + 1;
2434 pattern = new wxPdfPattern(i, width, height);
2435 pattern->SetImage(currentImage);
2436 (*m_patterns)[patternName] = pattern;
2437 }
2438 else
2439 {
2440 isValid = false;
2441 if (!image.IsOk())
2442 {
2443 wxLogError(wxString(wxS("wxPdfDocument::AddPattern: ")) +
2444 wxString(_("Invalid image.")));
2445 }
2446 else
2447 {
2448 wxLogError(wxString(wxS("wxPdfDocument::AddPattern: ")) +
2449 wxString::Format(_("Invalid width (%.1f) and/or height (%.1f)."), width, height));
2450 }
2451 }
2452 }
2453 return isValid;
2454 }
2455
2456 void
SetDrawColour(const wxColour & colour)2457 wxPdfDocument::SetDrawColour(const wxColour& colour)
2458 {
2459 wxPdfColour tempColour(colour);
2460 m_drawColour = tempColour;
2461 if (m_page > 0)
2462 {
2463 OutAscii(m_drawColour.GetColour(true));
2464 }
2465 }
2466
2467 void
SetDrawColour(const unsigned char grayscale)2468 wxPdfDocument::SetDrawColour(const unsigned char grayscale)
2469 {
2470 wxPdfColour tempColour(grayscale);
2471 m_drawColour = tempColour;
2472 if (m_page > 0)
2473 {
2474 OutAscii(m_drawColour.GetColour(true));
2475 }
2476 }
2477
2478 void
SetDrawColour(const unsigned char red,const unsigned char green,const unsigned char blue)2479 wxPdfDocument::SetDrawColour(const unsigned char red, const unsigned char green, const unsigned char blue)
2480 {
2481 SetDrawColour(wxColour(red, green, blue));
2482 }
2483
2484 void
SetDrawColour(double cyan,double magenta,double yellow,double black)2485 wxPdfDocument::SetDrawColour(double cyan, double magenta, double yellow, double black)
2486 {
2487 SetDrawColour(wxPdfColour(cyan, magenta, yellow, black));
2488 }
2489
2490 void
SetDrawColour(const wxPdfColour & colour)2491 wxPdfDocument::SetDrawColour(const wxPdfColour& colour)
2492 {
2493 m_drawColour = colour;
2494 if (m_page > 0)
2495 {
2496 OutAscii(m_drawColour.GetColour(true));
2497 }
2498 }
2499
2500 void
SetDrawColour(const wxString & name,double tint)2501 wxPdfDocument::SetDrawColour(const wxString& name, double tint)
2502 {
2503 wxPdfSpotColourMap::iterator spotColour = (*m_spotColours).find(name);
2504 if (spotColour != (*m_spotColours).end())
2505 {
2506 wxPdfColour tempColour(*(spotColour->second), tint);
2507 m_drawColour = tempColour;
2508 if (m_page > 0)
2509 {
2510 OutAscii(m_drawColour.GetColour(true));
2511 }
2512 }
2513 else
2514 {
2515 wxLogError(wxString(wxS("wxPdfDocument::SetDrawColour: ")) +
2516 wxString::Format(_("Undefined spot colour: '%s'."), name.c_str()));
2517 }
2518 }
2519
2520 void
SetDrawPattern(const wxString & name)2521 wxPdfDocument::SetDrawPattern(const wxString& name)
2522 {
2523 wxPdfPatternMap::iterator pattern = m_patterns->find(name);
2524 if (pattern != m_patterns->end())
2525 {
2526 wxPdfColour tempColour(*(pattern->second));
2527 m_drawColour = tempColour;
2528 if (m_page > 0)
2529 {
2530 OutAscii(m_drawColour.GetColour(true));
2531 }
2532 }
2533 else
2534 {
2535 wxLogError(wxString(wxS("wxPdfDocument::SetDrawPattern: ")) +
2536 wxString::Format(_("Undefined pattern: '%s'."), name.c_str()));
2537 }
2538 }
2539
2540 const wxPdfColour
GetDrawColour()2541 wxPdfDocument::GetDrawColour()
2542 {
2543 return wxPdfColour(m_drawColour);
2544 }
2545
2546 void
SetFillColour(const wxColour & colour)2547 wxPdfDocument::SetFillColour(const wxColour& colour)
2548 {
2549 wxPdfColour tempColour(colour);
2550 m_fillColour = tempColour;
2551 m_colourFlag = (m_fillColour != m_textColour);
2552 if (m_page > 0)
2553 {
2554 OutAscii(m_fillColour.GetColour(false));
2555 }
2556 }
2557
2558 void
SetFillColour(const unsigned char grayscale)2559 wxPdfDocument::SetFillColour(const unsigned char grayscale)
2560 {
2561 wxPdfColour tempColour(grayscale);
2562 m_fillColour = tempColour;
2563 m_colourFlag = (m_fillColour != m_textColour);
2564 if (m_page > 0)
2565 {
2566 OutAscii(m_fillColour.GetColour(false));
2567 }
2568 }
2569
2570 void
SetFillColour(const wxPdfColour & colour)2571 wxPdfDocument::SetFillColour(const wxPdfColour& colour)
2572 {
2573 m_fillColour = colour;
2574 m_colourFlag = (m_fillColour != m_textColour);
2575 if (m_page > 0)
2576 {
2577 OutAscii(m_fillColour.GetColour(false));
2578 }
2579 }
2580
2581 void
SetFillColour(const unsigned char red,const unsigned char green,const unsigned char blue)2582 wxPdfDocument::SetFillColour(const unsigned char red, const unsigned char green, const unsigned char blue)
2583 {
2584 SetFillColour(wxColour(red, green, blue));
2585 }
2586
2587 void
SetFillColour(double cyan,double magenta,double yellow,double black)2588 wxPdfDocument::SetFillColour(double cyan, double magenta, double yellow, double black)
2589 {
2590 SetFillColour(wxPdfColour(cyan, magenta, yellow, black));
2591 }
2592
2593 void
SetFillColour(const wxString & name,double tint)2594 wxPdfDocument::SetFillColour(const wxString& name, double tint)
2595 {
2596 wxPdfSpotColourMap::iterator spotColour = (*m_spotColours).find(name);
2597 if (spotColour != (*m_spotColours).end())
2598 {
2599 wxPdfColour tempColour(*(spotColour->second), tint);
2600 m_fillColour = tempColour;
2601 m_colourFlag = (m_fillColour != m_textColour);
2602 if (m_page > 0)
2603 {
2604 OutAscii(m_fillColour.GetColour(false));
2605 }
2606 }
2607 else
2608 {
2609 wxLogError(wxString(wxS("wxPdfDocument::SetFillColour: ")) +
2610 wxString::Format(_("Undefined spot colour: '%s'."), name.c_str()));
2611 }
2612 }
2613
2614 void
SetFillPattern(const wxString & name)2615 wxPdfDocument::SetFillPattern(const wxString& name)
2616 {
2617 wxPdfPatternMap::iterator pattern = m_patterns->find(name);
2618 if (pattern != m_patterns->end())
2619 {
2620 wxPdfColour tempColour(*(pattern->second));
2621 m_fillColour = tempColour;
2622 m_colourFlag = (m_fillColour != m_textColour);
2623 if (m_page > 0)
2624 {
2625 OutAscii(m_fillColour.GetColour(false));
2626 }
2627 }
2628 else
2629 {
2630 wxLogError(wxString(wxS("wxPdfDocument::SetFillPattern: ")) +
2631 wxString::Format(_("Undefined pattern: '%s'."), name.c_str()));
2632 }
2633 }
2634
2635 const wxPdfColour
GetPatternColour(const wxString & name)2636 wxPdfDocument::GetPatternColour(const wxString& name)
2637 {
2638 wxPdfColour colour(0);
2639 wxPdfPatternMap::iterator pattern = m_patterns->find(name);
2640 if (pattern != m_patterns->end())
2641 {
2642 wxPdfColour tempColour(*(pattern->second));
2643 colour = tempColour;
2644 }
2645 else
2646 {
2647 wxLogError(wxString(wxS("wxPdfDocument::GetPatternColour: ")) +
2648 wxString::Format(_("Undefined pattern: '%s'."), name.c_str()));
2649 }
2650 return colour;
2651 }
2652
2653 const wxPdfColour
GetFillColour()2654 wxPdfDocument::GetFillColour()
2655 {
2656 return wxPdfColour(m_fillColour);
2657 }
2658
2659 void
SetTextColour(const wxColour & colour)2660 wxPdfDocument::SetTextColour(const wxColour& colour)
2661 {
2662 wxPdfColour tempColour(colour);
2663 m_textColour = tempColour;
2664 m_colourFlag = (m_fillColour != m_textColour);
2665 }
2666
2667 void
SetTextColour(const unsigned char grayscale)2668 wxPdfDocument::SetTextColour(const unsigned char grayscale)
2669 {
2670 wxPdfColour tempColour(grayscale);
2671 m_textColour = tempColour;
2672 m_colourFlag = (m_fillColour != m_textColour);
2673 }
2674
2675 void
SetTextColour(const wxPdfColour & colour)2676 wxPdfDocument::SetTextColour(const wxPdfColour& colour)
2677 {
2678 m_textColour = colour;
2679 m_colourFlag = (m_fillColour != m_textColour);
2680 }
2681
2682 void
SetTextColour(const unsigned char red,const unsigned char green,const unsigned char blue)2683 wxPdfDocument::SetTextColour(const unsigned char red, const unsigned char green, const unsigned char blue)
2684 {
2685 SetTextColour(wxColour(red, green, blue));
2686 }
2687
2688 void
SetTextColour(double cyan,double magenta,double yellow,double black)2689 wxPdfDocument::SetTextColour(double cyan, double magenta, double yellow, double black)
2690 {
2691 SetTextColour(wxPdfColour(cyan, magenta, yellow, black));
2692 }
2693
2694 void
SetTextColour(const wxString & name,double tint)2695 wxPdfDocument::SetTextColour(const wxString& name, double tint)
2696 {
2697 wxPdfSpotColourMap::iterator spotColour = (*m_spotColours).find(name);
2698 if (spotColour != (*m_spotColours).end())
2699 {
2700 wxPdfColour tempColour(*(spotColour->second), tint);
2701 m_textColour = tempColour;
2702 m_colourFlag = (m_fillColour != m_textColour);
2703 }
2704 else
2705 {
2706 wxLogError(wxString(wxS("wxPdfDocument::SetTextColour: ")) +
2707 wxString::Format(_("Undefined spot colour: '%s'."), name.c_str()));
2708 }
2709 }
2710
2711 void
SetTextPattern(const wxString & name)2712 wxPdfDocument::SetTextPattern(const wxString& name)
2713 {
2714 wxPdfPatternMap::iterator pattern = m_patterns->find(name);
2715 if (pattern != m_patterns->end())
2716 {
2717 wxPdfColour tempColour(*(pattern->second));
2718 m_textColour = tempColour;
2719 m_colourFlag = (m_fillColour != m_textColour);
2720 }
2721 else
2722 {
2723 wxLogError(wxString(wxS("wxPdfDocument::SetFillPattern: ")) +
2724 wxString::Format(_("Undefined pattern: '%s'."), name.c_str()));
2725 }
2726 }
2727
2728 const wxPdfColour
GetTextColour()2729 wxPdfDocument::GetTextColour()
2730 {
2731 return wxPdfColour(m_textColour);
2732 }
2733
2734 void
SetTextRenderMode(wxPdfTextRenderMode mode)2735 wxPdfDocument::SetTextRenderMode(wxPdfTextRenderMode mode)
2736 {
2737 m_textRenderMode = mode;
2738 }
2739
2740 wxPdfTextRenderMode
GetTextRenderMode() const2741 wxPdfDocument::GetTextRenderMode() const
2742 {
2743 return m_textRenderMode;
2744 }
2745