[0004756] Amounts in words on documents were printed in user language instead of...
[fa-stable.git] / reporting / includes / class.pdf.inc
1 <?php
2 /**********************************************************************
3     Copyright (C) FrontAccounting, LLC.
4         Released under the terms of the GNU General Public License, GPL, 
5         as published by the Free Software Foundation, either version 3 
6         of the License, or (at your option) any later version.
7     This program is distributed in the hope that it will be useful,
8     but WITHOUT ANY WARRANTY; without even the implied warranty of
9     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
10     See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
11 ***********************************************************************/
12 /*
13         This class is an extension to the tcpdf class using a syntax that the original reports were written in
14         (the R &OS pdf.php class) - due to easily portation this wrapper class
15         was written to allow the same code base to use the more functional tcpdf.class by Nicola Asuni
16
17 *       Wrapper for use R&OSpdf API with tcpdf.org class
18 *       Joe Hunt <joe.hunt.consulting@gmail.com> and Janusz Dobrowolski <janusz@iron.from.pl>
19 */
20
21 define("K_RE_PATTERN_RTL", "/(
22           \xD6\xBE                                                                                                                                                                                      # R
23         | \xD7[\x80\x83\x86\x90-\xAA\xB0-\xB4]                                                                  # R
24         | \xDF[\x80-\xAA\xB4\xB5\xBA]                                                                                                           # R
25         | \xE2\x80\x8F                                                                                                                                                                  # R
26         | \xEF\xAC[\x9D\x9F\xA0-\xA8\xAA-\xB6\xB8-\xBC\xBE]                     # R
27         | \xEF\xAD[\x80\x81\x83\x84\x86-\x8F]                                                                           # R
28         | \xF0\x90\xA0[\x80-\x85\x88\x8A-\xB5\xB7\xB8\xBC\xBF]  # R
29         | \xF0\x90\xA4[\x80-\x99]                                                                                                                               # R
30         | \xF0\x90\xA8[\x80\x90-\x93\x95-\x97\x99-\xB3]                                 # R
31         | \xF0\x90\xA9[\x80-\x87\x90-\x98]                                                                                      # R
32         | \xE2\x80[\xAB\xAE]                                                                                                                                            # RLE & RLO
33         )/x");
34
35 /*
36  * Pattern to test Arabic strings using regular expressions.
37  * source: http://www.w3.org/International/questions/qa-forms-utf-8
38  */
39 define("K_RE_PATTERN_ARABIC", "/(
40                           \xD8[\x80-\x83\x8B\x8D\x9B\x9E\x9F\xA1-\xBA]  # AL
41                         | \xD9[\x80-\x8A\xAD-\xAF\xB1-\xBF]                                                     # AL
42                         | \xDA[\x80-\xBF]                                                                                                                               # AL
43                         | \xDB[\x80-\x95\x9D\xA5\xA6\xAE\xAF\xBA-\xBF]  # AL
44                         | \xDC[\x80-\x8D\x90\x92-\xAF]                                                                  # AL
45                         | \xDD[\x8D-\xAD]                                                                                                                               # AL
46                         | \xDE[\x80-\xA5\xB1]                                                                                                           # AL
47                         | \xEF\xAD[\x90-\xBF]                                                                                                           # AL
48                         | \xEF\xAE[\x80-\xB1]                                                                                                           # AL
49                         | \xEF\xAF[\x93-\xBF]                                                                                                           # AL
50                         | \xEF[\xB0-\xB3][\x80-\xBF]                                                                            # AL
51                         | \xEF\xB4[\x80-\xBD]                                                                                                           # AL
52                         | \xEF\xB5[\x90-\xBF]                                                                                                           # AL
53                         | \xEF\xB6[\x80-\x8F\x92-\xBF]                                                                  # AL
54                         | \xEF\xB7[\x80-\x87\xB0-\xBC]                                                                  # AL
55                         | \xEF\xB9[\xB0-\xB4\xB6-\xBF]                                                                  # AL
56                         | \xEF\xBA[\x80-\xBF]                                                                                                           # AL
57                         | \xEF\xBB[\x80-\xBC]                                                                                                           # AL
58                         | \xD9[\xA0-\xA9\xAB\xAC]                                                                                               # AN
59                         )/x");
60
61 include_once (dirname(__FILE__).'/tcpdf.php');
62 include_once (dirname(__FILE__).'/fpdi/fpdi.php');
63
64 class Cpdf extends FPDI {
65
66         function __construct($pageSize='A4', $lang=null, $pageOrientation='P')
67         {
68                 parent::__construct($pageOrientation, 'pt', $pageSize);//, $uni, $enc);
69                 $this->SetLang($lang);
70                 $this->setPrintHeader(false);
71                 $this->setPrintFooter(false);
72                 $this->setPDFVersion("1.3");
73                 $this->setAutoPageBreak(0);
74                 $this->SetLineWidth(1);
75                 $this->cMargin = 0;
76         }
77         /*
78                 Set lamguage for next report
79         */
80         function SetLang($code=null) 
81         {
82                 global $installed_languages, $dflt_lang, $path_to_root, $local_path_to_root, $GetText;
83
84                 if (!$code)
85                         $code = $dflt_lang;
86                 else
87                         install_hooks($code);
88
89                 $lang = array_search_value($code, $installed_languages, 'code');
90                 $GetText->set_language($lang['code'], strtoupper($lang['encoding']));
91
92                 // $local_path_to_root is  set inside find_custom_file.
93                 // Select extension domain if po file is provided
94                 // otherwise use global translation.
95                 if (file_exists($local_path_to_root.'/lang/'.$lang['code'].'/LC_MESSAGES/'.$lang['code'].'.po'))
96                         $GetText->add_domain($lang['code'], $local_path_to_root . "/lang");
97                 else
98                         $GetText->add_domain($lang['code'], $path_to_root . "/lang", @$lang['version']);
99                 // re-read translated sys names.
100                 include($path_to_root.'/includes/sysnames.inc');
101
102                 $l = array('a_meta_charset' => strtoupper($lang['encoding']), 
103                         'a_meta_dir' => @$lang['rtl'] ? 'rtl' : 'ltr',
104                         'a_meta_language' => $code, 'w_page' => 'page');
105
106                 if (!isset($l['a_meta_charset']))
107                         $l = array('a_meta_charset' => 'ISO-8859-1', 'a_meta_dir' => 'ltr', 'a_meta_language' => 'en_GB', 'w_page' => 'page');
108                 $enc = $l['a_meta_charset'];
109                 $uni = ($enc == 'UTF-8' || $enc == 'GB2312' ? true : false);
110                 if ($uni)
111                         ini_set("memory_limit", "48M");
112
113                 $this->isunicode = $uni;
114                 $this->setLanguageArray($l);
115                 if ($uni)
116                 {
117                                 global $unicode, $unicode_mirror, $unicode_arlet, $laa_array, $diacritics;
118                                 include_once(dirname(__FILE__)."/unicode_data2.php");
119                 }
120                 $this->encoding = strtoupper($lang['encoding']);
121
122                 $this->FontFamily = 'helvetica';
123                 $this->FontStyle = '';
124                 $this->FontSizePt = 12;
125         }
126
127
128         // $fontname should be a standard PDF font (like 'times', 'helvetica' or 'courier')
129         // or one that's been installed on your system.  An empty string can also be used
130         // which will retain the font currently in use.
131         // $style is either:
132         //   * a special case string:
133         //     * bold
134         //     * italic
135         //   * or a case-insensitive string where each char represents a style choice
136         // and you can use more than one or none at all.  Possible choices:
137         //      * empty string: regular
138     //      * B: bold
139     //      * I: italic
140     //      * U: underline
141     //      * D: line trough (aka "strike through")
142         function selectFont($fontname, $style = '')
143         {
144                 // Parse the style - check for special cases, otherwise leave as-is
145                 if ($style == 'italic')
146                         $style = 'i';
147                 elseif ($style == 'bold')
148                         $style = 'b';
149
150                 // Parse the fontname
151                 if ($fontname != '')
152                         $fontname = basename($fontname);
153                 if ($fontname == '')
154                 {
155                         if ($this->isunicode)
156                         {
157                                 switch ($this->l['a_meta_language'])
158                                 {
159                                         case "ar_EG" :  $fontname = "ae_tholoth";       break;
160                                         case "zh_CN" :  $fontname = "gbsn00lp";         break;
161                                         case "zh_TW" :  $fontname = "chinese_traditional_cid0";         break;
162                                         default :       $fontname = "dejavu";           break;
163                                 }
164                         }
165                         elseif ($this->encoding === "ISO-8859-2")
166                         {
167                                 switch ($this->l['a_meta_language'])
168                                 {
169                                         default :               $fontname = "freesans";         break;
170                                 }
171                         }
172                         elseif ($this->encoding === "ISO-8859-5")
173                         {
174                                 switch ($this->l['a_meta_language'])
175                                 {
176                                         default :               $fontname = "freesans5";        break;
177                                 }
178                         }
179                         elseif ($this->encoding === "ISO-8859-13")
180             {
181                 switch ($this->l['a_meta_language'])
182                 {
183                     default :        $fontname = "freesans13";     break;
184                 }
185             }
186             // else use built-in adobe fonts helvetica.
187                 }
188                 $this->SetFont($fontname, $style);
189         }
190
191         function Header1()
192         {
193         }
194
195         function Footer()
196         {
197         }
198
199         function newPage()
200         {
201                 parent::AddPage();
202         }
203
204         function line($x1,$y1,$x2,$y2, $style = array())
205         {
206                 parent::Line($x1, $this->h-$y1, $x2, $this->h-$y2, $style);
207         }
208
209         function rectangle($x, $y, $w, $h, $style='', $border_style=array(), $fill_color=array())
210         {
211                 parent::Rect($x, $this->h-$y, $w, $h, $style, $border_style, $fill_color);
212         }
213
214
215         function addText($xb,$yb,$size,$txt)//,$angle=0,$wordSpaceAdjust=0)
216         {
217                 if ($this->isunicode && $this->encoding != "UTF-8")
218                         $txt = iconv($this->encoding, "UTF-8", $txt);
219                 $this->SetFontSize($size);
220                 $this->Text($xb, $this->h-$yb, $txt);
221         }
222
223         function addInfo($label,$value)
224         {
225                 if (in_array($label, array( 'Title', 'Subject', 'Author', 'Creator'))) {
226                         $seter = "Set{$label}";
227                         $this->$seter($value);
228                 }
229         }
230
231         function addJpegFromFile($img,$x,$y,$w=0,$h=0)
232         {
233                 $this->Image($img, $x, $this->h-$y-$h, $w, $h);
234         }
235
236         function addPngFromFile($img,$x,$y,$w=0,$h=0)
237         {
238                 $this->Image($img, $x, $this->h-$y-$h, $w, $h);
239         }
240         /*
241         * Next Two functions are adopted from R&OS pdf class
242         */
243
244         /**
245         * draw a part of an ellipse
246         */
247         function partEllipse($x0,$y0,$astart,$afinish,$r1,$r2=0,$angle=0,$nSeg=8)
248         {
249                 $this->ellipse($x0,$y0,$r1,$r2,$angle,$nSeg,$astart,$afinish,0);
250         }
251
252         /**
253         * draw an ellipse
254         * note that the part and filled ellipse are just special cases of this function
255         *
256         * draws an ellipse in the current line style
257         * centered at $x0,$y0, radii $r1,$r2
258         * if $r2 is not set, then a circle is drawn
259         * nSeg is not allowed to be less than 2, as this will simply draw a line (and will even draw a
260         * pretty crappy shape at 2, as we are approximating with bezier curves.
261         */
262         function ellipse($x0,$y0,$r1,$r2=0,$angle=0,$nSeg=8,$astart=0,$afinish=360,$close=1,$fill=0, $dummy=null)
263         {
264                 parent::Ellipse($x0, $y0, $r1, $r2, $angle, $astart. $afinish, ($close?'C':''), "", "", $nSeg);
265         }
266
267         function Stream($fname='')
268         {
269                 parent::Output($fname, 'I');
270         }
271
272         function calcTextWrap($txt, $width, $spacebreak=false)
273         {
274                 $ret = "";
275                 $txt2 = $txt;
276                 $w = $this->GetStringWidth($txt);
277                 if ($w > $width && $w > 0 && $width != 0)
278                 {
279                         $n = strlen($txt);
280                         $k = intval($n * $width / $w);
281                         if ($k > 0 && $k < $n)
282                         {
283                                 $txt2 = substr($txt, 0, $k);
284                                 if ($spacebreak && (($pos = strrpos($txt2, " ")) !== false))
285                                 {
286                                         $txt2 = substr($txt2, 0, $pos);
287                                         $ret = substr($txt, $pos+1);
288                                 }
289                                 else
290                                         $ret = substr($txt, $k);
291                         }
292                 }
293                 return array($txt2, $ret);
294         }
295
296         function addTextWrap($xb, $yb, $w, $h, $txt, $align='left', $border=0, $fill=0, $link = NULL, $stretch = 1, $spacebreak=false)
297         {
298                 $ret = "";
299                 if (!$this->rtl)
300                 {
301                         if ($align == 'right')
302                                 $align = 'R';
303                         elseif ($align == 'left')
304                                 $align = 'L';
305                         elseif ($align == 'center')
306                                 $align = 'C';
307                         elseif ($align == 'justify')
308                                 $align = 'J';
309                 }
310                 else
311                 {
312                         if ($align == 'right')
313                                 $align = 'R';// This may need to be 'L'
314                         elseif ($align == 'left')
315                                 $align = 'R';
316                         elseif ($align == 'center')
317                                 $align = 'C';
318                         elseif ($align == 'justify')
319                                 $align = 'J';
320                 }
321
322                 $txt = parent::unhtmlentities($txt);
323                 // If horizontal scaling was requested, check to see if we're trying to scale
324                 // too much.  If so, cut back string first and then scale it.
325                 $maxScaleFactor = 1.4;
326                 if ($stretch == 1 || $stretch == 2)
327                         $txt = $this->calcTextWrap($txt, $w * $maxScaleFactor, $spacebreak);
328                 // Wrap text if stretching isn't turned on
329                 else
330                         $txt = $this->calcTextWrap($txt, $w, $spacebreak);
331                 $ret = $txt[1];
332                 $txt = $txt[0];
333                 $this->SetXY($xb, $this->h - $yb - $h);
334
335                 if ($this->isunicode && $this->encoding != "UTF-8")
336                         $txt = iconv($this->encoding, "UTF-8", $txt);
337                 $this->Cell($w, $h, $txt, $border, 0, $align, $fill, $link, $stretch);
338                 return $ret;
339         }
340
341         function Text($x, $y, $txt, $stroke=0, $clip=false)
342         {
343                 parent::Text($x,$y, parent::unhtmlentities($txt), $stroke, $clip);
344         }
345
346 } // end of class
347