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