blob: 7a3840a8bbb795ffc72a3a7a2686640220bd43bd [file] [log] [blame]
Copybara botbe50d492023-11-30 00:16:42 +01001<?php
2 /*********************************************************************
3 * FPDF easyTable *
4 * *
5 * Version: 2.0 *
6 * Date: 12-10-2017 *
7 * Author: Dan Machado *
8 * Require exFPDF v2.0 *
9 **********************************************************************/
10
11class easyTable{
12 const LP=0.4;
13 const XPadding=1;
14 const YPadding=1;
15 const IMGPadding=0.5;
16 const PBThreshold=30;
17 static private $table_counter=false;
18 static private $style=array('width'=>false, 'border'=>false, 'border-color'=>false,
19 'border-width'=>false, 'line-height'=>false,
20 'align'=>'', 'valign'=>'', 'bgcolor'=>false, 'split-row'=>false, 'l-margin'=>false,
21 'font-family'=>false, 'font-style'=>false,'font-size'=>false, 'font-color'=>false,
22 'paddingX'=>false, 'paddingY'=>false);
23 private $pdf_obj;
24 private $document_style;
25 private $table_style;
26 private $col_num;
27 private $col_width;
28 private $baseX;
29 private $row_style_def;
30 private $row_style;
31 private $row_heights;
32 private $row_data;
33 private $rows;
34 private $total_rowspan;
35 private $col_counter;
36 private $grid;
37 private $blocks;
38 private $overflow;
39 private $header_row;
40 private $new_table;
41
42 private function get_available($colspan, $rowspan){
43 static $k=0;
44 if(count($this->grid)==0){
45 $k=0;
46 }
47 while(isset($this->grid[$k])){
48 $k++;
49 }
50 for($i=0; $i<=$colspan; $i++){
51 for($j=0; $j<=$rowspan; $j++){
52 $this->grid[$k+$i+$j*$this->col_num]=true;
53 }
54 }
55 return $k;
56 }
57
58 private function get_style($str, $c){
59 $result=self::$style;
60 if($c=='C'){
61 $result['colspan']=0;
62 $result['rowspan']=0;
63 $result['img']=false;
64 }
65 if($c=='C' || $c=='R'){
66 unset($result['width']);
67 unset($result['border-width']);
68 unset($result['split-row']);
69 unset($result['l-margin']);
70 }
71 if($c=='R' || $c=='T'){
72 if($c=='R'){
73 $result['c-align']=array_pad(array(), $this->col_num, 'L');
74 }
75 else{
76 $result['c-align']=array();
77 }
78 }
79 if($c=='R'){
80 $result['min-height']=false;
81 }
82 $tmp=explode(';', $str);
83 foreach($tmp as $x){
84 if($x && strpos($x,':')>0){
85 $r=explode(':',$x);
86 $r[0]=trim($r[0]);
87 $r[1]=trim($r[1]);
88 if(isset($result[$r[0]])){
89 $result[$r[0]]=$r[1];
90 }
91 }
92 }
93 return $result;
94 }
95
96 private function inherating(&$sty, $setting, $c){
97 if($c=='C'){
98 $sty[$setting]=$this->row_style[$setting];
99 }
100 elseif($c=='R'){
101 $sty[$setting]=$this->table_style[$setting];
102 }
103 else{
104 $sty[$setting]=$this->document_style[$setting];
105 }
106 }
107
108 private function conv_units($x)
109 {
110 if($this->pdf_obj->get_scale_factor()==72/25.4)
111 {
112 return $x;
113 }
114
115 if($this->pdf_obj->get_scale_factor()==72/2.54)
116 {
117 return $x/10;
118 }
119
120 if($this->pdf_obj->get_scale_factor()==72)
121 {
122 return $x/25.4;
123 }
124
125 return $x/0.3527777778;
126 }
127
128 private function set_style($str, $c, $pos=''){
129 $sty=$this->get_style($str, $c);
130 if($c=='T'){
131 if(is_numeric($sty['width'])){
132 $sty['width']=min(abs($sty['width']),$this->document_style['document_width']);
133 if($sty['width']==0){
134 $sty['width']=$this->document_style['document_width'];
135 }
136 }
137 else{
138 $x=strpos($sty['width'], '%');
139 if($x!=false){
140 $x=min(abs(substr($sty['width'], 0, $x)), 100);
141 if($x){
142 $sty['width']=$x*$this->document_style['document_width']/100.0;
143 }
144 else{
145 $sty['width']=$this->document_style['document_width'];
146 }
147 }
148 else{
149 $sty['width']=$this->document_style['document_width'];
150 }
151 }
152 if(!is_numeric($sty['l-margin'])){
153 $sty['l-margin']=0;
154 }
155 else{
156 $sty['l-margin']=abs($sty['l-margin']);
157 }
158 if(is_numeric($sty['border-width'])){
159 $sty['border-width']=abs($sty['border-width']);
160 }
161 else{
162 $sty['border-width']=false;
163 }
164 if($sty['split-row']=='false'){
165 $sty['split-row']=false;
166 }
167 elseif($sty['split-row']!==false){
168 $sty['split-row']=true;
169 }
170 }
171 if($c=='R'){
172 if(!is_numeric($sty['min-height']) || $sty['min-height']<0){
173 $sty['min-height']=0;
174 }
175 }
176 if(!is_numeric($sty['paddingX'])){
177 if($c=='C' || $c=='R'){
178 $this->inherating($sty, 'paddingX', $c);
179 }
180 else{
181 $sty['paddingX']=$this->conv_units(self::XPadding);
182 }
183 }
184 $sty['paddingX']=abs($sty['paddingX']);
185 if(!is_numeric($sty['paddingY'])){
186 if($c=='C' || $c=='R'){
187 $this->inherating($sty, 'paddingY', $c);
188 }
189 else{
190 $sty['paddingY']=$this->conv_units(self::YPadding);
191 }
192 }
193 $sty['paddingY']=abs($sty['paddingY']);
194 if($sty['border']===false && ($c=='C' || $c=='R')){
195 $this->inherating($sty, 'border', $c);
196 }
197 else{
198 $border=array('T'=>1, 'R'=>1, 'B'=>1, 'L'=>1);
199 if(!(is_numeric($sty['border']) && $sty['border']==1)){
200 foreach($border as $k=>$v){
201 $border[$k]=0;
202 if(strpos($sty['border'], $k)!==false){
203 $border[$k]=1;
204 }
205 }
206 }
207 $sty['border']=$border;
208 }
209 $color_settings=array('bgcolor', 'font-color', 'border-color');
210 foreach($color_settings as $setting){
211 if($sty[$setting]===false || !($this->pdf_obj->is_hex($sty[$setting]) || $this->pdf_obj->is_rgb($sty[$setting]))){
212 if($c=='C' || $c=='R'){
213 $this->inherating($sty, $setting, $c);
214 }
215 elseif($setting=='font-color'){
216 $sty[$setting]=$this->document_style[$setting];
217 }
218 }
219 else{
220 $sty[$setting]=$sty[$setting];
221 }
222 }
223 $font_settings=array('font-family', 'font-style', 'font-size');
224 foreach($font_settings as $setting){
225 if($sty[$setting]===false){
226 $this->inherating($sty, $setting, $c);
227 }
228 }
229 if(is_numeric($sty['line-height'])){
230 $sty['line-height']=$this->conv_units(self::LP)*abs($sty['line-height']);
231 }
232 else{
233 if($c=='C' || $c=='R'){
234 $this->inherating($sty,'line-height', $c);
235 }
236 else{
237 $sty['line-height']=$this->conv_units(self::LP);
238 }
239 }
240 if($c=='C'){
241 if($sty['img']){
242 $tmp=explode(',', $sty['img']);
243 if(file_exists($tmp[0])){
244 $sty['img']=array('path'=>'', 'h'=>0, 'w'=>0);
245 $img=@ getimagesize($tmp[0]);
246 $sty['img']['path']=$tmp[0];
247 for($i=1; $i<3; $i++){
248 if(isset($tmp[$i])){
249 $tmp[$i]=trim(strtolower($tmp[$i]));
250 if($tmp[$i][0]=='w' || $tmp[$i][0]=='h'){
251 $t=substr($tmp[$i],1);
252 if(is_numeric($t)){
253 $sty['img'][$tmp[$i][0]]=abs($t);
254 }
255 }
256 }
257 }
258 $ration=$img[0]/$img[1];
259 if($sty['img']['w']+$sty['img']['h']==0){
260 $sty['img']['w']=$img[0];
261 $sty['img']['h']=$img[1];
262 }
263 elseif($sty['img']['w']==0){
264 $sty['img']['w']=$sty['img']['h']*$ration;
265 }
266 elseif($sty['img']['h']==0){
267 $sty['img']['h']=$sty['img']['w']/$ration;
268 }
269 }
270 else{
271 $sty['img']='failed to open stream: file ' . $tmp[0] .' does not exist';
272 }
273 }
274 if(is_numeric($sty['colspan']) && $sty['colspan']>0){
275 $sty['colspan']--;
276 }
277 else{
278 $sty['colspan']=0;
279 }
280 if(is_numeric($sty['rowspan']) && $sty['rowspan']>0){
281 $sty['rowspan']--;
282 }
283 else{
284 $sty['rowspan']=0;
285 }
286 if($sty['valign']==false && ($sty['rowspan']>0 || $sty['img']!==false)){
287 $sty['valign']='M';
288 }
289 if($sty['align']==false && $sty['img']!==false){
290 $sty['align']='C';
291 }
292 }
293 if($c=='T' || $c=='R'){
294 $tmp=explode('{',$sty['align']);
295 if($c=='T'){
296 $sty['align']=trim($tmp[0]);
297 }
298 if(isset($tmp[1])){
299 $tmp[1]=trim($tmp[1], '}');
300 if(strlen($tmp[1])){
301 for($i=0; $i<strlen($tmp[1]); $i++){
302 if(preg_match("/[LCRJ]/", $tmp[1][$i])!=0){
303 $sty['c-align'][$i]=$tmp[1][$i];
304 }
305 else{
306 $sty['c-align'][$i]='L';
307 }
308 }
309 }
310 if($c=='R'){
311 $sty['align']='L';
312 $sty['c-align']=array_slice($sty['c-align'],0,$this->col_num);
313 }
314 }
315 }
316 if($sty['align']!='L' && $sty['align']!='C' && $sty['align']!='R' && $sty['align']!='J'){
317 if($c=='C'){
318 $sty['align']=$this->row_style['c-align'][$pos];
319 }
320 elseif($c=='R'){
321 $sty['align']='L';
322 $sty['c-align']=$this->table_style['c-align'];
323 }
324 else{
325 $sty['align']='C';
326 }
327 }
328 elseif($c=='T' && $sty['align']=='J'){
329 $sty['align']='C';
330 }
331 if($sty['valign']!='T' && $sty['valign']!='M' && $sty['valign']!='B'){
332 if($c=='C' || $c=='R'){
333 $this->inherating($sty, 'valign', $c);
334 }
335 else{
336 $sty['valign']='T';
337 }
338 }
339 return $sty;
340 }
341
342 private function row_content_loop($counter, $f){
343 $t=0;
344 if($counter>0){
345 $t=$this->rows[$counter-1];
346 }
347 for($index=$t; $index<$this->rows[$counter]; $index++){
348 $f($index);
349 }
350 }
351
352 private function mk_border($i, $y, $split){
353 $w=$this->row_data[$i][2];
354 $h=$this->row_data[$i][5];
355 if($split){
356 $h=$this->pdf_obj->PageBreak()-$y;
357 }
358 if($this->row_data[$i][1]['border-color']!=false){
359 $this->pdf_obj->resetColor($this->row_data[$i][1]['border-color'], 'D');
360 }
361 $a=array(1, 1, 1, 0);
362 $borders=array('L'=>3, 'T'=>0, 'R'=>1, 'B'=>2);
363 foreach($borders as $border=>$j){
364 if($this->row_data[$i][1]['border'][$border]){
365 if($border=='B'){
366 if($split==0){
367 $this->pdf_obj->Line($this->row_data[$i][6]+(1+$a[($j+2)%4])%2*$w, $y+(1+$a[($j+1)%4])%2 * $h, $this->row_data[$i][6]+$a[$j%4]*$w, $y+($a[($j+3)%4])%2 *$h);
368 }
369 }
370 else{
371 $this->pdf_obj->Line($this->row_data[$i][6]+(1+$a[($j+2)%4])%2*$w, $y+(1+$a[($j+1)%4])%2 * $h, $this->row_data[$i][6]+$a[$j%4]*$w, $y+($a[($j+3)%4])%2 *$h);
372 }
373 }
374 }
375
376 if($this->row_data[$i][1]['border-color']!=false){
377 $this->pdf_obj->resetColor($this->document_style['bgcolor'], 'D');
378 }
379 if($split){
380 $this->pdf_obj->row_data[$i][1]['border']['T']=0;
381 }
382 }
383
384 private function print_text($i, $y, $split){
385 $padding=$this->row_data[$i][1]['padding-y'];
386 $k=$padding;
387 if($this->row_data[$i][1]['img']!==false){
388 if($this->row_data[$i][1]['valign']=='B'){
389 $k+=$this->row_data[$i][1]['img']['h']+$this->conv_units(self::IMGPadding);
390 }
391 }
392 $l=0;
393 if(count($this->row_data[$i][0])){
394 $x=$this->row_data[$i][6]+$this->row_data[$i][1]['paddingX'];
395 $xpadding=2*$this->row_data[$i][1]['paddingX'];
396 $l=count($this->row_data[$i][0])* $this->row_data[$i][1]['line-height']*$this->row_data[$i][1]['font-size'];
397 $this->pdf_obj->SetXY($x, $y+$k);
398 $this->pdf_obj->CellBlock($this->row_data[$i][2]-$xpadding, $this->row_data[$i][1]['line-height'], $this->row_data[$i][0], $this->row_data[$i][1]['align']);
399 $this->pdf_obj->resetFont($this->document_style['font-family'], $this->document_style['font-style'], $this->document_style['font-size']);
400 $this->pdf_obj->resetColor($this->document_style['font-color'], 'T');
401 }
402 if($this->row_data[$i][1]['img']!==false ){
403 $x=$this->row_data[$i][6];
404 $k=$padding;
405 if($this->row_data[$i][1]['valign']!='B'){
406 $k+=$l+$this->conv_units(self::IMGPadding);
407 }
408 if($this->imgbreak($i, $y)==0 && $y+$k+$this->row_data[$i][1]['img']['h']<$this->pdf_obj->PageBreak()){
409 $x+=$this->row_data[$i][1]['paddingX'];
410 if($this->row_data[$i][2]>$this->row_data[$i][1]['img']['w']){
411 if($this->row_data[$i][1]['align']=='C'){
412 $x-=$this->row_data[$i][1]['paddingX'];
413 $x+=($this->row_data[$i][2]-$this->row_data[$i][1]['img']['w'])/2;
414 }
415 elseif($this->row_data[$i][1]['align']=='R'){
416 $x+=$this->row_data[$i][2]-$this->row_data[$i][1]['img']['w'];
417 $x-=2*$this->row_data[$i][1]['paddingX'];
418 }
419 }
420 $this->pdf_obj->Image($this->row_data[$i][1]['img']['path'], $x, $y+$k, $this->row_data[$i][1]['img']['w'], $this->row_data[$i][1]['img']['h']);
421 $this->row_data[$i][1]['img']=false;
422 }
423 }
424 }
425
426
427 private function mk_bg($i, $T, $split){
428 $h=$this->row_data[$i][5];
429 if($split){
430 $h=$this->pdf_obj->PageBreak()-$T;
431 }
432 if($this->row_data[$i][1]['bgcolor']!=false){
433 $this->pdf_obj->resetColor($this->row_data[$i][1]['bgcolor']);
434 $this->pdf_obj->Rect($this->row_data[$i][6], $T, $this->row_data[$i][2], $h, 'F');
435 $this->pdf_obj->resetColor($this->document_style['bgcolor']);
436 }
437 }
438
439 private function printing_loop($swap=false){
440 $this->swap_data($swap);
441 $y=$this->pdf_obj->GetY();
442 $tmp=array();
443 $rw=array();
444 $ztmp=array();
445 $total_cells=count($this->row_data);
446 while(count($tmp)!=$total_cells){
447 $a=count($this->rows);
448 $h=0;
449 $y=$this->pdf_obj->GetY();
450 for($j=0; $j<count($this->rows); $j++){
451 $T=$y+$h;
452 if($T<$this->pdf_obj->PageBreak()){
453
454 $this->row_content_loop($j, function($index)use($T, $tmp){
455 if(!isset($tmp[$index])){
456 $split_cell=$this->scan_for_breaks($index,$T, false);
457 $this->mk_bg($index, $T, $split_cell);
458 }
459 });
460 if(!isset($rw[$j])){
461 if($this->pdf_obj->PageBreak()-($T+$this->row_heights[$j])>=0){
462 $h+=$this->row_heights[$j];
463 }
464 else{
465 $a=$j+1;
466 break;
467 }
468 }
469 }
470 else{
471 $a=$j+1;
472 break;
473 }
474 }
475 $h=0;
476 for($j=0; $j<$a; $j++){
477 $T=$y+$h;
478 if($T<$this->pdf_obj->PageBreak()){
479
480 $this->row_content_loop($j, function($index)use($T, &$tmp, &$ztmp){
481 if(!isset($tmp[$index])){
482 $split_cell=$this->scan_for_breaks($index,$T);
483 $this->mk_border($index, $T, $split_cell);
484 $this->print_text($index, $T, $split_cell);
485 if($split_cell==0){
486 $tmp[$index]=$index;
487 }
488 else{
489 $ztmp[]=$index;
490 }
491 }
492 });
493 if(!isset($rw[$j])){
494 $tw=$this->pdf_obj->PageBreak()-($T+$this->row_heights[$j]);
495 if($tw>=0){
496 $h+=$this->row_heights[$j];
497 $rw[$j]=$j;
498 }
499 else{
500 $this->row_heights[$j]=$this->overflow-$tw;
501 }
502 }
503 }
504 }
505 if(count($tmp)!=$total_cells){
506 foreach($ztmp as $index){
507 $this->row_data[$index][5]=$this->row_data[$index][7]+$this->overflow;
508 if(isset($this->row_data[$index][8])){
509 $this->row_data[$index][1]['padding-y']=$this->row_data[$index][8];
510 unset($this->row_data[$index][8]);
511 }
512 }
513 $this->overflow=0;
514 $ztmp=array();
515 $this->pdf_obj->addPage($this->document_style['orientation'], $this->pdf_obj->get_page_size(), $this->pdf_obj->get_rotation());
516 }
517 else{
518 $y+=$h;
519 }
520 }
521 $this->pdf_obj->SetXY($this->baseX, $y);
522 $this->swap_data($swap);
523 }
524
525 private function imgbreak($i, $y){
526 $li=$y+$this->row_data[$i][1]['padding-y'];
527 $ls=$this->row_data[$i][1]['img']['h'];
528 if($this->row_data[$i][1]['valign']=='B'){
529 $ls+=$li;
530 }
531 else{
532 $li+=$this->row_data[$i][3]-$this->row_data[$i][1]['img']['h'];
533 $ls+=$li;
534 }
535 $result=0;
536 if($li<$this->pdf_obj->PageBreak() && $this->pdf_obj->PageBreak()<$ls){
537 $result=$this->pdf_obj->PageBreak()-$li;
538 }
539 return $result;
540 }
541
542 private function scan_for_breaks($index, $H, $l=true){
543 $print_cell=0;
544 $h=($H+$this->row_data[$index][5])-$this->pdf_obj->PageBreak();
545 if($h>0){
546 if($l){
547 $rr=$this->pdf_obj->PageBreak()-($H+$this->row_data[$index][1]['padding-y']);
548 if($rr>0){
549 $mx=0;
550 if(count($this->row_data[$index][0]) && $this->row_data[$index][1]['img']!==false){
551 $mx=$this->imgbreak($index, $H);
552 if($mx==0){
553 if($this->row_data[$index][1]['valign']=='B'){
554 $rr-=$this->row_data[$index][1]['img']['h'];
555 }
556 }
557 }
558 $nh=0;
559 $keys=array_keys($this->row_data[$index][0]);
560 foreach($keys as $i){
561 $nh+=$this->row_data[$index][0][$i]['height'];
562 }
563 $nh*=$this->row_data[$index][1]['line-height'];
564 if($mx==0){
565 if($rr<$nh && $rr>0){
566 $nw=0;
567 foreach($keys as $i){
568 $nw+=$this->row_data[$index][0][$i]['height']*$this->row_data[$index][1]['line-height'];
569 if($nw>$rr){
570 $nw-=$this->row_data[$index][0][$i]['height']*$this->row_data[$index][1]['line-height'];
571 $mx=$rr-$nw;
572 break;
573 }
574 }
575 }
576 else{
577 if($rr< $this->row_data[$index][1]['img']['h']){
578 $mx=$this->row_data[$index][1]['img']['h'];
579 }
580 }
581 }
582 $this->overflow=max($this->overflow, $mx);
583 $this->row_data[$index][8]=1;
584 }
585 else{
586 $this->row_data[$index][8]=-1*$rr;
587 }
588 $this->row_data[$index][7]=$h;
589 }
590 $print_cell=1;
591 }
592 return $print_cell;
593 }
594
595 private function swap_data($swap){
596 if($swap==false){
597 return;
598 }
599 static $data=array();
600 if(count($data)==0){
601 $data=array('header_data'=>$this->header_row['row_data'], 'row_heights'=>&$this->row_heights, 'row_data'=>&$this->row_data, 'rows'=>&$this->rows);
602 unset($this->row_heights, $this->row_data, $this->rows);
603 $this->row_heights=&$this->header_row['row_heights'];
604 $this->row_data=&$this->header_row['row_data'];
605 $this->rows=&$this->header_row['rows'];
606 }
607 else{
608 $this->header_row['row_data']=$data['header_data'];
609 unset($this->row_heights, $this->row_data, $this->rows);
610 $this->row_heights=$data['row_heights'];
611 $this->row_data=$data['row_data'];
612 $this->rows=$data['rows'];
613 $data=array();
614 }
615 }
616 /********************************************************************
617
618 function __construct( FPDF-object $fpdf_obj, Mix $num_cols[, string $style = '' ])
619 -----------------------------------------------------
620 Description:
621 Constructs an easyTable object
622 Parameters:
623 fpdf_obj
624 the current FPDF object (constructed with the FPDF library)
625 that is being used to write the current PDF document
626 num_cols
627 this parameter can be a positive integer (the number of columns)
628 or a string of the following form
629 I) a positive integer, the number of columns for the table. The width
630 of every column will be equal to the width of the table (given by the width property)
631 divided by the number of columns ($num_cols)
632 II) a string of the form '{c1, c2, c3,... cN}'. In this case every
633 element in the curly brackets is a positive numeric value that represent
634 the width of a column. Thus, the n-th numeric value is the width
635 of the n-th colum. If the sum of all the width of the columns is bigger than
636 the width of the table but less than the width of the document, the table
637 will stretch to the sum of the columns width. However, if the sum of the
638 columns is bigger than the width of the document, the width of every column
639 will be reduce proportionally to make the total sum equal to the width of the document.
640 III) a string of the form '%{c1, c2, c3,... cN}'. Similar to the previous case, but
641 this time every element represents a percentage of the width of the table.
642 In this case it the sum of this percentages is bigger than 100, the execution will
643 be terminated.
644 style
645 the global style for the table (see documentation)
646 a semicolon-separated string of attribute values that defines the
647 default layout of the table and all the cells and their contents
648 (see Documentation section in README.md)
649 Examples:
650 $table= new easyTable($fpdf, 3);
651 $table= new easyTable($fpdf, '{35, 45, 55}', 'width:135;');
652 $table= new easyTable($fpdf, '%{35, 45, 55}', 'width:190;');
653 Return value:
654 An easyTable object
655 ***********************************************************************/
656
657 public function __construct($fpdf_obj, $num_cols, $style=''){
658 if(self::$table_counter){
659 error_log('Please use the end_table method to terminate the last table');
660 exit();
661 }
662 self::$table_counter=true;
663 $this->pdf_obj=&$fpdf_obj;
664 $this->document_style['bgcolor']=$this->pdf_obj->get_color('fill');
665 $this->document_style['font-family']=$this->pdf_obj->current_font('family');
666 $this->document_style['font-style']=$this->pdf_obj->current_font('style');
667 $this->document_style['font-size']=$this->pdf_obj->current_font('size');
668 $this->document_style['font-color']=$this->pdf_obj->get_color('text');
669 $this->document_style['document_width']=$this->pdf_obj->GetPageWidth()-$this->pdf_obj->get_margin('l')-$this->pdf_obj->get_margin('r');
670 $this->document_style['orientation']=$this->pdf_obj->get_orientation();
671 $this->document_style['line-width']=$this->pdf_obj->get_linewidth();
672 $this->table_style=$this->set_style($style, 'T');
673 $this->col_num=false;
674 $this->col_width=array();
675 if(is_int($num_cols) && $num_cols!=0){
676 $this->col_num=abs($num_cols);
677 $this->col_width=array_pad(array(), abs($num_cols), $this->table_style['width']/abs($num_cols));
678 }
679 elseif(is_string($num_cols)){
680 $num_cols=trim($num_cols, '}, ');
681 if($num_cols[0]!='{' && $num_cols[0]!='%'){
682 error_log('Bad format for columns in Table constructor');
683 exit();
684 }
685 $tmp=explode('{', $num_cols);
686 $tp=trim($tmp[0]);
687 $num_cols=explode(',', $tmp[1]);
688 $w=0;
689 foreach($num_cols as $c){
690 if(!is_numeric($c)){
691 error_log('Bad parameter format for columns in Table constructor');
692 exit();
693 }
694 if(abs($c)){
695 $w+=abs($c);
696 $this->col_width[]=abs($c);
697 }
698 else{
699 error_log('Column width can not be zero');
700 }
701 }
702 $this->col_num=count($this->col_width);
703 if($tp=='%'){
704 if($w!=100){
705 error_log('The sum of the percentages of the columns is not 100');
706 exit();
707 }
708 foreach($this->col_width as $i=>$c){
709 $this->col_width[$i]=$c*$this->table_style['width']/100;
710 }
711 }
712 elseif($w!=$this->table_style['width'] && $w){
713 if($w<$this->document_style['document_width']){
714 $this->table_style['width']=$w;
715 }
716 else{
717 $this->table_style['width']=$this->document_style['document_width'];
718 $d=$this->table_style['width']/$w;
719 for($i=0; $i<count($num_cols); $i++){
720 $this->col_width[$i]*=$d;
721 }
722 }
723 }
724 }
725 if($this->col_num==false){
726 error_log('Unspecified number of columns in Table constructor');
727 exit();
728 }
729 $this->table_style['c-align']=array_pad($this->table_style['c-align'], $this->col_num, 'L');
730 if($this->table_style['l-margin']){
731 $this->baseX=$this->pdf_obj->get_margin('l')+min($this->table_style['l-margin'],$this->document_style['document_width']-$this->table_style['width']);
732 }
733 else{
734 if($this->table_style['align']=='L'){
735 $this->baseX=$this->pdf_obj->get_margin('l');
736 }
737 elseif($this->table_style['align']=='R'){
738 $this->baseX=$this->pdf_obj->get_margin('l')+$this->document_style['document_width']-$this->table_style['width'];
739 }
740 else{
741 $this->baseX=$this->pdf_obj->get_margin('l')+($this->document_style['document_width']-$this->table_style['width'])/2;
742 }
743 }
744 $this->row_style_def=$this->set_style('', 'R');
745 $this->row_style=$this->row_style_def;
746 $this->row_heights=array();
747 $this->row_data=array();
748 $this->rows=array();
749 $this->total_rowspan=0;
750 $this->col_counter=0;
751 $this->grid=array();
752 $this->blocks=array();
753 $this->overflow=0;
754 if($this->table_style['border-width']!=false){
755 $this->pdf_obj->SetLineWidth($this->table_style['border-width']);
756 }
757 $this->header_row=array();
758 $this->new_table=true;
759 }
760 /***********************************************************************
761
762 function rowStyle( string $style )
763 -------------------------------------------------------------
764 Description:
765 Set or overwrite the style for all the cells in the current row.
766 Parameters:
767 style
768 a semicolon-separated string of attribute values that defines the
769 layout of all the cells and its content in the current row
770 (see Documentation section in README.md)
771 Return values
772 Void
773 Notes:
774
775 This function should be called before the first cell of the current row
776 ***********************************************************************/
777
778 public function rowStyle($style){
779 $this->row_style=$this->set_style($style, 'R');
780 }
781 /***********************************************************************
782
783 function easyCell( string $data [, string $style = '' ])
784 ------------------------------------------------------------------------
785 Description:
786 Makes a cell in the table
787 Parameters:
788 data
789 the content of the respective cell
790 style (optional)
791 a semicolon-separated string of attribute values that defines the
792 layout of the cell and its content (see Documentation section in README.md)
793 Return value
794 void
795 ***********************************************************************/
796
797 public function easyCell($data, $style=''){
798 if($this->col_counter<$this->col_num){
799 $sty=$this->set_style($style, 'C', $this->col_counter);
800 $this->col_counter++;
801 $row_number=count($this->rows);
802 $cell_index=count($this->row_data);
803 $cell_pos=$this->get_available($sty['colspan'], $sty['rowspan']);
804 $colm=$cell_pos %$this->col_num;
805 if($sty['img']!=false && $data!='' && $sty['valign']=='M'){
806 $sty['valign']=$this->row_style['valign'];
807 }
808 if($sty['rowspan']){
809 $this->total_rowspan=max($this->total_rowspan, $sty['rowspan']);
810 $this->blocks[$cell_index]=array($cell_index, $row_number, $sty['rowspan']);
811 }
812 $w=$this->col_width[$colm];
813 $r=0;
814 while($r<$sty['colspan'] && $this->col_counter<$this->col_num){
815 $this->col_counter++;
816 $colm++;
817 $w+=$this->col_width[$colm];
818 $r++;
819 }
820 $w-=2*$sty['paddingX'];
821 if($sty['img']!==false && is_string($sty['img'])){
822 $data=$sty['img'];
823 $sty['img']=false;
824 }
825 $data=& $this->pdf_obj->extMultiCell($sty['font-family'], $sty['font-style'], $sty['font-size'], $sty['font-color'], $w, $data);
826 $h=0;
827 $rn=count($data);
828 for($ri=0; $ri<$rn; $ri++){
829 $h+=$data[$ri]['height']*$sty['line-height'];
830 }
831 if($sty['img']){
832 if($sty['img']['w']>$w){
833 $sty['img']['h']=$w*$sty['img']['h']/$sty['img']['w'];
834 $sty['img']['w']=$w;
835 }
836 if($h){
837 $h+=$this->conv_units(self::IMGPadding);
838 }
839 $h+=$sty['img']['h'];
840 }
841 $w+=2*$sty['paddingX'];
842
843 $posx=$this->baseX;
844 $d=$cell_pos %$this->col_num;
845 for($k=0; $k<$d; $k++){
846 $posx+=$this->col_width[$k];
847 }
848 $this->row_data[$cell_index]=array($data, $sty, $w, $h, $cell_pos, 0, $posx, 0);
849
850 }
851 }
852 /***********************************************************************
853
854 function printRow ( [ bool $setAsHeader = false ] )
855 ------------------------------------------------------------------------
856 Description:
857
858 This function indicates the end of the current row.
859 Parameters:
860 setAsHeader (optional)
861 Optional. When it is set as true, it sets the current row as the header
862 for the table; this means that the current row will be printed as the first
863 row of the table (table header) on every page that the table splits on.
864 Remark: 1. In order to work, the table attribute split-row should set as true.
865 2. Just the first row where this parameter is set as true will be
866 used as header any other will printed as a normal row.
867 Return values
868 Void
869 Note:
870
871 This function will print the current row as far as the following holds:
872 total_rowspan=0
873 where total_rowspan is set as
874 total_rowspan=max(total_rowspan, max(rowspan of cell in the current row))-1;
875 ***********************************************************************/
876
877 public function printRow($setAsHeader=false){
878 $this->col_counter=0;
879 $row_number=count($this->rows);
880 $this->rows[$row_number]=count($this->row_data);
881 $mx=$this->row_style['min-height'];
882
883 $this->row_content_loop($row_number, function($index)use(&$mx){
884 if($this->row_data[$index][1]['rowspan']==0){
885 $mx=max($mx, $this->row_data[$index][3]+2*$this->row_data[$index][1]['paddingY']);
886 }
887 });
888 $this->row_heights[$row_number]=$mx;
889
890 if($this->total_rowspan>0){
891 $this->total_rowspan--;
892 }
893 else{
894 $row_number=count($this->rows);
895 if(count($this->blocks)>0){
896
897 foreach($this->blocks as $bk_id=>$block){
898 $h=0;
899 for($i=$block[1]; $i<=$block[1]+$block[2]; $i++){
900 $h+=$this->row_heights[$i];
901 }
902 $t=$this->row_data[$block[0]][3]+2*$this->row_data[$block[0]][1]['paddingY'];
903 if($h>0 && $h<$t){
904 for($i=$block[1]; $i<=$block[1]+$block[2]; $i++){
905 $this->row_heights[$i]*=$t/$h;
906 }
907 }
908 }
909 foreach($this->blocks as $j=>$block){
910 $h=0;
911 for($i=$block[1]; $i<=$block[1]+$block[2]; $i++){
912 $h+=$this->row_heights[$i];
913 }
914 $this->row_data[$j][5]=$h;
915 }
916 }
917 $block_height=0;
918 for($j=0; $j<$row_number; $j++){
919
920 $this->row_content_loop($j, function($index)use($j, $block_height){
921 if($this->row_data[$index][1]['rowspan']==0){
922 $this->row_data[$index][5]=$this->row_heights[$j];
923 }
924 $this->row_data[$index][1]['padding-y']=$this->row_data[$index][1]['paddingY'];
925 if($this->row_data[$index][1]['valign']=='M' || ($this->row_data[$index][1]['img'] && count($this->row_data[$index][0]))){
926 $this->row_data[$index][1]['padding-y']=($this->row_data[$index][5]-$this->row_data[$index][3])/2;
927 }
928 elseif($this->row_data[$index][1]['valign']=='B'){
929 $this->row_data[$index][1]['padding-y']=$this->row_data[$index][5]-($this->row_data[$index][3]+$this->row_data[$index][1]['paddingY']);
930 }
931 });
932 $block_height+=$this->row_heights[$j];
933 }
934
935 $rowIsHeader=1+(count($this->header_row)>0);
936 if($setAsHeader===true){
937 if(count($this->header_row)==0){
938 $this->header_row['row_heights']=$this->row_heights;
939 $this->header_row['row_data']=$this->row_data;
940 $this->header_row['rows']=$this->rows;
941 }
942 }
943 if($this->table_style['split-row']==false && $this->pdf_obj->PageBreak()<$this->pdf_obj->GetY()+max($block_height,$this->row_heights[0])){
944 $this->pdf_obj->addPage($this->document_style['orientation'], $this->pdf_obj->get_page_size(), $this->pdf_obj->get_rotation());
945 if(count($this->header_row)>0){
946 $this->printing_loop(true);
947 $rowIsHeader--;
948 }
949 }
950
951 if($this->new_table){
952 if(count($this->header_row)>0){
953 $r=$this->pdf_obj->PageBreak()-($this->pdf_obj->GetY()+$block_height);
954 if($r<0 || $r<$this->conv_units(self::PBThreshold)){
955 $this->pdf_obj->addPage($this->document_style['orientation'], $this->pdf_obj->get_page_size(), $this->pdf_obj->get_rotation());
956 }
957 }
958 $this->new_table=false;
959 }
960 if($rowIsHeader>0){
961 $this->printing_loop();
962 }
963 $this->grid=array();
964 $this->row_data=array();
965 $this->rows=array();
966 $this->row_heights=array();
967 $this->blocks=array();
968 $this->overflow=0;
969 $this->new_table=false;
970 }
971 $this->row_style=$this->row_style_def;
972 }
973 /***********************************************************************
974
975 function endTable( [int $bottomMargin=2])
976 ------------------------------------------
977 Description:
978 Unset all the data members of the easyTable object
979 Parameters:
980 bottomMargin (optional)
981 Optional. Specify the number of white lines left after
982 the last row of the table. Default 2.
983 If it is negative, the vertical position will be set before
984 the end of the table.
985 Return values
986 Void
987 ***********************************************************************/
988
989 public function endTable($bottomMargin=2){
990 self::$table_counter=false;
991 if($this->table_style['border-width']!=false){
992 $this->pdf_obj->SetLineWidth($this->document_style['line-width']);
993 }
994 $this->pdf_obj->SetX($this->pdf_obj->get_margin('l'));
995 $this->pdf_obj->Ln($bottomMargin);
996 $this->pdf_obj->resetStaticData();
997 unset($this->pdf_obj);
998 unset($this->document_style);
999 unset($this->table_style);
1000 unset($this->col_num);
1001 unset($this->col_width);
1002 unset($this->baseX);
1003 unset($this->row_style_def);
1004 unset($this->row_style);
1005 unset($this->row_heights);
1006 unset($this->row_data);
1007 unset($this->rows);
1008 unset($this->total_rowspan);
1009 unset($this->col_counter);
1010 unset($this->grid);
1011 unset($this->blocks);
1012 unset($this->overflow);
1013 unset($this->header_row);
1014 }
1015
1016}
1017?>