Fix #8052 - fixing pdf
[pear] / XML / SvgToPdf / Text.php
1 <?php
2
3
4 class XML_SvgToPDF_Text  extends XML_SvgToPDF_Base { 
5
6         var $linespacing;
7         var $xx;
8         var $yy;        
9
10     function fromXmlNode($node) {
11         
12         parent::fromXmlNode($node);
13                 $this->parse();
14         }
15         function fromNode($node) {
16         
17         parent::fromNode($node);
18                 $this->parse();
19         }
20         function parse()
21         {
22         // any text ???
23         if (empty($this->children) || empty($this->children[0]->content)) {
24             return;
25         }
26         
27         // modify the alignment of the if this block content of the first child is "=="
28         
29         if (substr($this->children[0]->content,0,2) == '==') {
30             $this->style['text-anchor'] = 'justify';
31             $this->children[0]->content = substr($this->children[0]->content,2);
32         }
33     }
34       
35     function transform() {
36         
37         parent::transform();
38         if (empty($this->transform)) {
39             return; 
40         }
41         if (preg_match('/scale\(([0-9e.-]+),([0-9e.-]+)\)/',$this->transform,$args)) {
42             $xscale = $args[1]; // do we use this??? = what do do about 'e'?
43             $yscale = $args[2];
44             $this->style['font-size'] *= $args[1];
45         }
46     }
47     
48         
49     
50     function writePDF($pdf,$data) {
51         // set up font.. 
52          
53         $font = strtolower($this->style['font-family']);
54         $font = trim($font, "'");
55         
56         static $map = array(
57             'times new roman' => 'times',
58             'courier new' => 'courier',
59             'arial' => 'arial',
60         );
61         if (isset($map[$font])) {
62             $font = $map[$font];
63         } else {
64             $font = 'times';
65         }
66         $ffont = $font;
67         if (preg_match('/big5/i',$this->style['font-family'])) {
68             $font = 'Big5';
69
70                         //$ffont = 'ARIALUNI';
71            // $font = 'arial'; // default if not bigg
72         }
73             
74         
75         
76         $weight =  '';
77         if ($this->style['font-weight'] == 'bold') {
78             $weight .=  'B';
79         }
80         if (@$this->style['font-style'] == 'italic') {
81             $weight .=  'I';
82         }
83         
84         if (@$this->style['text-decoration'] == 'underline') {
85             $weight .=  'U';
86         }
87         // size..
88         $size = $this->style['font-size']  * 0.85;
89         
90         $pdf->setFont($font,$weight,$size);
91      
92         switch(@$this->style['text-anchor']) {
93             case 'end':
94                 $align = 'E';
95                 break;
96             case 'middle':
97                 $align = 'M';
98                 break;
99             case 'justify':
100                 $align = 'J';
101                 $max = 0;
102                 foreach ($this->children as $child) {
103                     if (!@$child->content) {
104                         continue;
105                     }
106                     $l = $pdf->getStringWidth($child->content);
107                     $max = ($l > $max) ? $l : $max;
108                 }
109                 // fudge factor!
110                 $this->justifyLen = $max;
111                 break;
112             default:
113                 $align = 'L';
114             
115         }
116         
117         $f = $this->toColor(@$this->style['fill']);
118         if ($f) {
119             $pdf->setTextColor($f[0],$f[1],$f[2]);
120         }
121      
122      
123      
124         $yoffset = 0;
125         $x =  $this->x   + @$this->xx;
126         $y =  $this->y  + @$this->yy;
127         if (empty($this->children)) {
128             return;
129         }
130         $lineno = 0;
131         foreach($this->children as $i=>$c) {
132         
133             $xx = $c->x !== false ? $c->x + @$this->xx : $x;
134             $yy = $c->y !== false ? $c->y + @$this->yy : $y + ($lineno * $size * 1.3);
135             $lineno++;
136                         if (empty($c->content)) {
137                                 //print_R($c);exit;
138                         }
139             $val = $c->content;
140             //if ($ffont == 'ARIALUNI') { //) && preg_match('/[\x7f-\xff]+/',$val)) {
141              //   $pdf->setFont('ARIALUNI' ,
142              //               $weight,
143              //               $size);
144             //}
145             if (isset($c->args)) {
146                 
147                 $args = array();
148                 foreach($c->args as $v) {
149                     if ($v == 'page') {
150                         $args[] = $pdf->PageNo();
151                         continue;
152                     }
153                     if ($v == 'nb') {
154                         $args[] = '{nb}';
155                         continue;
156                     }
157                     
158                     // echo "GET: $v : '$val'<BR>";
159                     $args[] = trim($this->getValue($data,trim($v))); // removes trailing CRLF...
160                 }
161                 
162                 
163                 $has_template = preg_match('/%s/', $val);
164                      
165                 $val = empty($val) || empty($args) ? $val : trim(vsprintf($val,$args));
166                 
167                 //if ($has_template && ($ffont == 'ARIALUNI') && preg_match('/[\x7f-\xff]+/',$val)) {
168                                 if ($has_template && ($font == 'Big5') && preg_match('/[\x7f-\xff]+/',$val)) {
169                     require_once  'Text/ZhDetect.php';
170                     $detect = new Text_zhDetect;
171                     $type = $detect->guess($val);
172                     if ($v == 'S') {
173                      
174                         $val = @iconv('utf8', 'GB2312//IGNORE', $val);
175                         $pdf->setFont('GB' ,
176                             $weight,
177                             $size);
178                     } else {
179                         $val = @iconv('utf8', 'BIG5//IGNORE', $val);
180                         $pdf->setFont('Big5' ,
181                             $weight,
182                             $size);
183                    }
184                 }  else {
185                     $val = @iconv('utf8','ascii//ignore',$val);
186                 }
187                 
188                 
189                 
190                 
191             }
192             $talign = $align;
193             if ((!@$this->children[$i+1] ||  !strlen(trim(@$this->children[$i+1]->content))) && ($align == 'J')) {
194                 $talign = 'L';
195             }
196             
197             $yoffset += $this->multiLine($pdf, str_replace("\r", "", explode("\n",$val)),
198                     $xx/ 3.543307,
199                     ($yy / 3.543307) + $yoffset,
200                     ($size / 3.543307) + 1,
201                     $talign
202                 );
203             
204              
205         }
206         
207         // now daraw
208     
209     }
210     
211     /**
212     * get a value from the data
213     *
214     * eg. $data = array(
215     *     'fred' => 'somevalue'
216     *
217     *  getValue ($data,'fred') returns 'somevalue' 
218     * 
219     * value can also be a method = eg. getFred()
220     *
221     * @param   object|array $data 
222     * @param   string $v key to get.
223     * 
224     *
225     * @return   string
226     * @access   public
227     */
228   
229     function getValue($data,$v) {
230         
231        // print_R(array("GET VALUE: ", $v));
232         // not a method:
233         
234         if ($v[strlen($v)-1]  != ')') {
235             
236             $data = (array) $data;
237             //echo "<PRE>";print_r(array_keys($data));
238             if (false === strpos($v,'.')) {
239                 if (!isset($data[$v])) {
240                   //  echo "missing $v\n";
241                     return '';
242                 }
243                 if (is_array($data[$v]) || is_object($data[$v])) {
244                   //  echo "array/object $v\n";
245                     return '';
246                 }
247                 //echo "returning $v\n";
248                 return $data[$v];
249             }
250             $dd = (array)$data;
251             foreach(explode('.', $v) as $vv) {
252                 if (!is_array($dd)) {
253                     return '';   
254                 }
255                 if (!isset($dd[$vv])) {
256                     return '';
257                 }
258                 $dd = is_object($dd[$vv]) ? ((array) $dd[$vv]) : $dd[$vv];
259             }
260             //echo "ATTEMPT: $v: got $dd\n";
261             //exit;
262             if (is_array($dd) || is_object($dd)) {
263                 return '';
264             }
265             return $dd;
266         }
267         // method !!!
268         if (!is_object($data)) {
269             return '';
270         }
271         $method = substr($v,0,-2);
272        
273         if (is_object($data) && method_exists($data,$method)) {
274            // echo "call $method<BR>";
275             $ret = $data->$method();
276             // echo "done $method $ret<BR>";
277             if (is_array($ret) || is_object($ret)) {
278                 return '';
279             }
280             return '' . $ret;
281         }
282         
283         //echo 
284         //print_r($data);
285         
286         //exit;
287         return "no method $method in ".get_class($data);
288     
289     
290     }
291     
292     
293     function breakLines($pdf,$str,$x,$y,$h,$align) {
294         // do the estimation...
295         $len = strlen($str);
296  
297         $total = $pdf->getStringWidth($str . '      ');
298          
299         $charsize = $total/$len;
300         
301         $max_chars = floor(($this->maxWidth / 3.543307) / $charsize);
302         //echo "LEN: $len, $total, $charsize, $max_chars";
303         $lines = explode("\n",wordwrap($str,$max_chars));
304          
305         return $this->multiLine($pdf,$lines,$x,$y,$h,$align);
306     }
307     var $maxWidth = false;
308     
309     function multiLine($pdf,$lines,$x,$y,$h,$align) {
310         // now dealing with mm
311         ///XML_SvgToPDF::debug("MULTILINE " .implode("\n",$lines) . " $x, $y, $h");
312         $yoffset  = 0;
313         $line = -1;
314         foreach ($lines as $l=>$v) {
315             $line++;
316             if ($this->maxWidth !== false && ($pdf->getStringWidth($v) > ($this->maxWidth / 3.543307))) {
317                 $yoffset += $this->breakLines($pdf,$v,$x,$y + ($l * $h) + $yoffset, $h,$align);
318                 continue;
319             }
320             XML_SvgToPDF::debug("TEXT: $x,$y, $l * $h + $yoffset,$v");
321             $xoffset = 0;
322             if ($align == 'M') { // center
323                 $xoffset = -1 * ($pdf->getStringWidth($v) / 2);
324             }
325             if ($align == 'E') { // right/end
326                 $xoffset = -1 * $pdf->getStringWidth($v);
327             }
328            
329             if ($align == 'J' ) { // justified (eg. started with ==
330                 $this->justify($pdf, $x , $y + ($l * $h) + $yoffset , $v, $this->justifyLen);
331                 continue;
332             }
333             $pdf->text(
334                 $xoffset + $x ,
335                 $y + ($l * $h) + $yoffset ,
336                 $v);
337                 
338         }
339         return   ($l * $h) + $yoffset;
340         
341     }
342         
343         
344     function justify($pdf,$x,$y,$text,$len) {
345         if (!strlen(trim($text))) {
346             return;
347         }
348         $bits = explode(' ', $text);
349         $textlen = $pdf->getStringWidth(implode('',$bits));
350         $spacesize = ($len - $textlen) / (count($bits) -1);
351         foreach($bits as $word) {
352             $pdf->text($x , $y ,$word );
353             $x += $spacesize + $pdf->getStringWidth($word);
354         }
355     }
356         
357      
358
359 }