From d67500fe1a63b1c0acbe92543eb89f80cc875787 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 8 Jun 2010 18:49:20 +0000 Subject: [PATCH] Mostly working TCPDF conversion for both labels and reports --- admin/reports.inc.php | 96 +++++++++++----- admin/reports_editor.php | 139 +++++----------------- tcpdf.inc.php | 242 ++++++++++++++++++++++++++++++++++++--- 3 files changed, 323 insertions(+), 154 deletions(-) diff --git a/admin/reports.inc.php b/admin/reports.inc.php index 3d87fdb..470235e 100644 --- a/admin/reports.inc.php +++ b/admin/reports.inc.php @@ -49,7 +49,7 @@ $report_options = array(); $report_options['type'] = array('desc' => 'Report Format', - 'values' => array('pdf'=>'PDF', 'csv'=>'CSV', 'label'=>'Label', 'tcpdf_label'=>'TCPDF Label (experimental)') + 'values' => array('tcpdf' => 'PDF', 'tcpdf_label'=>'Label', 'csv'=>'CSV (for Excel)', 'text'=>'Text (Plain text in columns)', 'pdf'=>'PDF (PDFlib deprecated)', 'label'=>'Label (PDFlib deprecated)', ) ); $report_options['group_new_page'] = array('desc' => 'Start each new grouping on a new page', 'values' => array('no'=>'No', 'yes'=>'Yes') @@ -443,14 +443,20 @@ foreach($report_stock as $n=>$v) { (i.e. nothign has changed, only adding on */ if($val['lines'] == 0) $val['lines'] = 1; + + /* Old format, where align and valign are stored in 'align', + * separte them. */ $opts = explode(" ", $val['align']); $align_opts = array ('left', 'right', 'center'); $valign_opts = array ('vtop', 'vbottom', 'vcenter'); - $style_opts = array ('bold'); foreach($opts as $o) { if(in_array($o, $align_opts)) $val['align'] = $o; if(in_array($o, $valign_opts)) $val['valign'] = $o; - if(in_array($o, $valign_opts)) $val['face'] = $o; + } + /* Turn the old 'face' into the fontstyle array */ + $style_opts = array ('bold'); + if(in_array($val['face'], $style_opts)) { + $val['fontstyle'] = array($val['face']); } $report[$t][$a['ord']] = $val; @@ -559,9 +565,7 @@ foreach($report_stock as $n=>$v) { $fieldname = array(); $thead = array(); - $table['header']=array(); - $table['widths']=array(); - $table['dataalign']=array(); + $table['col']=array(); $table['option']=array(); $table['total']=0; @@ -578,8 +582,8 @@ foreach($report_stock as $n=>$v) { $rep=new lcsv(i18n($report['name'])); $gen_mode = 'table'; break; +/* case 'label': - /* Label */ $label_stock = $report_stock[$report['option']['stock']]; $rep=new lpdf( i18n($config['fairname']), i18n($report['name']), @@ -591,8 +595,7 @@ foreach($report_stock as $n=>$v) { $label_stock['x_spacing'], $label_stock['y_spacing'],11,$label_stock['y_padding']); $gen_mode = 'label'; break; - case 'pdf': case '': - /* FIXME: handle landscape pages in here */ + case 'old_pdf': $label_stock = $report_stock[$report['option']['stock']]; $rep=new lpdf( i18n($config['fairname']), i18n($report['name']), @@ -611,7 +614,9 @@ foreach($report_stock as $n=>$v) { if($report['option']['allow_multiline'] == 'yes') $table['option']['allow_multiline'] = true; break; - case 'tcpdf_label': +*/ + case 'label': + case 'tcpdf_label': $label_stock = $report_stock[$report['option']['stock']]; $show_box = ($report['option']['label_box'] == 'yes') ? true : false; $show_fair = ($report['option']['label_fairname'] == 'yes') ? true : false; @@ -625,6 +630,27 @@ foreach($report_stock as $n=>$v) { $gen_mode = 'tcpdf_label'; break; + case 'pdf': case '': + $label_stock = $report_stock[$report['option']['stock']]; + if($report['option']['allow_multiline'] == 'yes') + $on_overflow = 'nothing'; + else + $on_overflow = '...'; + + $rep=new pdf($report['name'], $label_stock['page_format'], $label_stock['page_orientation']); + $rep->setup_for_tables($show_box, $show_fair, $show_logo, + $label_stock['label_width'] * 25.4, $label_stock['label_height'] * 25.4, + $label_stock['x_spacing'] * 25.4, $label_stock['y_spacing'] * 25.4, + $label_stock['rows'], $label_stock['cols']); + $gen_mode = 'table'; + break; + + + + case 'text': + echo "Not implemented [{$report['option']['type']}]"; + exit; + default: echo "Invalid type [{$report['option']['type']}]"; exit; @@ -643,30 +669,47 @@ foreach($report_stock as $n=>$v) { * ones are scalable, just in case */ foreach($report['col'] as $o=>$d) { $f = $d['field']; - $total_width += $fields[$f]['width']; - if($fields[$f]['scalable'] == true) - $scale_width += $fields[$f]['width']; + if($d['w'] != 0) { + /* Always 0 on old reports, so we never get in here */ + $total_width += $d['w']; + /* For the rest of the computation, this field is + * not scalable */ + /* FIXME! */ + } else { + $total_width += $fields[$f]['width']; + if($fields[$f]['scalable'] == true) + $scale_width += $fields[$f]['width']; + } } /* Determine the scale factor (use the label width so * we can enforce margins) */ if($report['option']['fit_columns'] == 'yes') { // && $total_width > $label_stock['label_width']) { $static_width = $total_width - $scale_width; - if($scale_width) - $scale_factor = ($label_stock['label_width'] - $static_width) / $scale_width; - else - $scale_factor = 1.0; + if($scale_width) + $scale_factor = ($label_stock['label_width'] - $static_width) / $scale_width; + else + $scale_factor = 1.0; } else { $scale_factor = 1.0; } + /* Select columns to display */ foreach($report['col'] as $o=>$d) { $f = $d['field']; - $table['header'][] = i18n($fields[$f]['header']); - $sf = ($fields[$f]['scalable'] == true) ? $scale_factor : 1.0; - $table['widths'][] = $fields[$f]['width'] * $sf; - $table['dataalign'][] = 'left'; + + /* If width is specificed, use that, else compute based on default field width */ + if($d['w'] == 0) + $width = $fields[$f]['width'] * (($fields[$f]['scalable'] == true) ? $scale_factor : 1.0); + else + $width = $d['w']; + $col = array( 'header' => i18n($fields[$f]['header']), + 'width' => $width, + 'align' => 'left', + 'on_overflow' => $on_overflow); + $table['col'][] = $col; + $sel[] = "{$fields[$f]['table']} AS C$x"; $fieldname[$f] = "C$x"; /* We want to add these to group by, but AFTER all the other group bys */ @@ -688,7 +731,7 @@ foreach($report_stock as $n=>$v) { $fieldname[$f] = "G$o"; } - if(isset($fields[$f]['table_sort'])) + if(isset($fields[$f]['able_sort'])) $order[] = $fields[$f]['table_sort']; else $order[] = $fieldname[$f]; @@ -810,25 +853,22 @@ foreach($report_stock as $n=>$v) { /* Dump the last table */ if(count($table['data'])) { // print_r($table); - $rep->addTable($table); - $rep->nextLine(); + $rep->add_table($table); $table['data'] = array(); $table['total'] = 0; /* Start a new page AFTER a table is * dumped, so the first page doesn't * end up blank */ if($report['option']['group_new_page'] == 'yes') { - $rep->newPage(); + $rep->addpage(); } else { $rep->hr(); - $rep->vspace(-0.1); } } /* Construct a new header */ $h = implode(" -- ", $last_group_data); $rep->heading($h); - $rep->nextLine(); } } @@ -904,7 +944,7 @@ foreach($report_stock as $n=>$v) { if(count($data)) $table['data'][] = $data; } if(count($table['data'])) { - $rep->addTable($table); + $rep->add_table($table); } diff --git a/admin/reports_editor.php b/admin/reports_editor.php index 980e127..374cc9f 100644 --- a/admin/reports_editor.php +++ b/admin/reports_editor.php @@ -39,7 +39,7 @@ require_once('../tcpdf.inc.php'); $fields = array(); - $locs = array('X' => 'x', 'Y' => 'y', 'W' => 'w', 'H' => 'h', 'Lines' => 'lines'); + $locs = array('X' => 'x', 'Y' => 'y', 'W' => 'w', 'H' => 'h'); function field_selector($name, $id, $selected) { @@ -203,53 +203,7 @@ function initCanvas(w,h,lw,lh) { labelHeight=lh; } -function createData(x,y,w,h,l,face,align,valign,value) { - var canvas=document.getElementById('layoutcanvas'); - var newdiv=document.createElement('div'); - if(valign=="vcenter") verticalAlign="middle"; - else if(valign=="vtop") verticalAlign="top"; - else if(valign=="vbottom") verticalAlign="bottom"; - else verticalAlign="top"; -// alert(verticalAlign); - - //convert x,y,w,h from % to absolute - - var dx=Math.round(x*canvasWidth/100); - var dy=Math.round(y*canvasHeight/100); - var dw=Math.round(w*canvasWidth/100); - var dh=Math.round(h*canvasHeight/100); -// alert(dx+','+dy+','+dw+','+dh); - - var fontheight=Math.round(dh/l); - - newdiv.setAttribute('id','o_'+canvasObjectIndex); - newdiv.style.display="table-cell"; - newdiv.style.position="absolute"; - newdiv.style.width=dw+"px"; - newdiv.style.height=dh+"px"; - newdiv.style.left=dx+"px"; - newdiv.style.top=dy+"px"; - newdiv.style.textAlign=align; - newdiv.style.verticalAlign=verticalAlign; - newdiv.style.padding="0 0 0 0"; - newdiv.style.margin="0 0 0 0"; -// newdiv.style.vertical-align=valign; - newdiv.style.border="1px solid blue"; - newdiv.style.fontSize=fontheight+"px"; - newdiv.style.lineHeight=fontheight+"px"; - newdiv.style.fontFamily="Verdana"; - newdiv.style.fontSizeAdjust=0.65; - - var maxlength=Math.floor(dw/(fontheight*0.7))*l; - if(value.length>maxlength) value=value.substring(0,maxlength); - newdiv.innerHTML=value; //"Maple Test xxxx"; //value; - - canvas.appendChild(newdiv); - - canvasObjectIndex++; -} - -function createDataTCPDF(x,y,w,h,align,valign,fontname,fontstyle,fontsize,value) { +function createData(x,y,w,h,align,valign,fontname,fontstyle,fontsize,value) { var canvas=document.getElementById('layoutcanvas'); var newdiv=document.createElement('div'); @@ -451,27 +405,15 @@ function createDataTCPDF(x,y,w,h,align,valign,fontname,fontstyle,fontsize,value) echo "\n"; $doCanvasSample = false; -$doCanvasSampletcpdf = false; $l_w=$report_stock[$report['option']['stock']]['label_width']; $l_h=$report_stock[$report['option']['stock']]['label_height']; - if($l_w && $l_h && $report['option']['type']=="label") { + + if($l_w && $l_h && $report['option']['type']=='label') { echo "

Label Data Locations

"; - $doCanvasSample=true; - $ratio=$l_h/$l_w; - $canvaswidth=600; - $canvasheight=round($canvaswidth*$ratio); - echo "
"; - echo "
\n"; - echo "\n"; - } - - if($l_w && $l_h && $report['option']['type']=="tcpdf_label") { - echo "

Label Data Locations - TCPDF

"; - $l_w *= 25.4; $l_h *= 25.4; - $doCanvasSampletcpdf=true; + $doCanvasSample=true; $ratio=$l_h/$l_w; $canvaswidth=600; $canvasheight=round($canvaswidth*$ratio); @@ -485,7 +427,7 @@ $doCanvasSampletcpdf = false; $x=0; - if($report['option']['type'] == 'label' || $report['option']['type'] == 'tcpdf_label') { + if($report['option']['type'] == 'label') { $fontlist = array('' => 'Default'); $fl = PDF::getFontList(); foreach($fl as $f) $fontlist[$f] = $f; @@ -497,34 +439,24 @@ $doCanvasSampletcpdf = false; echo ""; $script=""; foreach($locs as $k=>$v) { - if($k=='Lines' && $report['option']['type'] != 'label') continue; - echo "$k="; + echo "$k="; $script.="{$d[$v]},"; } - if($report['option']['type'] == 'label') { - echo 'Face='; - selector("col[$x][face]", array('' => '', 'bold' => 'Bold'), $d['face']); - } echo 'Align'; selector("col[$x][align]", array('center' => 'Center', 'left' => 'Left', 'right' => 'Right'), $d['align']); echo 'vAlign'; - if($report['option']['type'] == 'label') { - selector("col[$x][valign]", array('vcenter' => 'Center', 'vtop' => 'Top', 'vbottom' => 'Bottom'), - $d['valign']); - } else { - selector("col[$x][valign]", array('middle' => 'Middle', 'top' => 'Top', 'bottom' => 'Bottom'), - $d['valign']); - - echo 'Font='; - selector("col[$x][fontname]", $fontlist, $d['fontname']); - selector("col[$x][fontstyle]", array('' => '', 'bold' => 'Bold'), $d['fontstyle']); - echo ""; - echo 'pt '; - echo 'OnOverflow='; - selector("col[$x][on_overflow]", array('tuncate'=>'Truncate','...'=>'Add ...', 'scale'=>'Scale'), $d['on_overflow']); - } + selector("col[$x][valign]", array('middle' => 'Middle', 'top' => 'Top', 'bottom' => 'Bottom'), + $d['valign']); + echo '
'; + echo 'Font='; + selector("col[$x][fontname]", $fontlist, $d['fontname']); + selector("col[$x][fontstyle]", array('' => '', 'bold' => 'Bold'), $d['fontstyle']); + echo ""; + echo 'pt '; + echo 'OnOverflow='; + selector("col[$x][on_overflow]", array('nothing'=>'Nothing (overflow the box)', 'truncate'=>'Truncate','...'=>'Truncate and add ellipses (...)', 'scale'=>'Scale'), $d['on_overflow']); if($f == 'static_text') { echo "
Text="; @@ -532,44 +464,35 @@ $doCanvasSampletcpdf = false; echo ""; } if($doCanvasSample) - echo "\n"; - if($doCanvasSampletcpdf) - echo "\n"; + echo "\n"; $x++; + echo '

'; } for(;$x<$n_columns;$x++) { echo "Loc ".($x+1).": "; echo ""; foreach($locs as $k=>$v) { - if($k=='Lines' && $report['option']['type'] != 'label') continue; - echo "$k="; - } - if($report['option']['type'] == 'label') { - echo 'Face='; - selector("col[$x][face]", array('' => '', 'bold' => 'Bold'), ''); + echo "$k="; } echo 'Align'; selector("col[$x][align]", array('center' => 'Center', 'left' => 'Left', 'right' => 'Right'), 'center'); echo 'vAlign'; - if($report['option']['type'] == 'label') { - selector("col[$x][valign]", array('vcenter' => 'Center', 'vtop' => 'Top', 'vbottom' => 'Bottom'), - 'top'); - } else { - selector("col[$x][valign]", array('middle' => 'Middle', 'top' => 'Top', 'bottom' => 'Bottom'), 'middle'); + selector("col[$x][valign]", array('middle' => 'Middle', 'top' => 'Top', 'bottom' => 'Bottom'), 'middle'); - echo 'Font='; - selector("col[$x][fontname]", $fontlist, ''); - selector("col[$x][fontstyle]", array('' => '', 'bold' => 'Bold'), ''); - echo ""; - echo 'pt '; - echo 'OnOverflow='; - selector("col[$x][on_overflow]", array('Truncate'=>'truncate','Add ...'=>'...', 'Scale'=>'scale'),''); - } + echo '
'; + echo 'Font='; + selector("col[$x][fontname]", $fontlist, ''); + selector("col[$x][fontstyle]", array('' => '', 'bold' => 'Bold'), ''); + echo ""; + echo 'pt '; + echo 'OnOverflow='; + selector("col[$x][on_overflow]", array('nothing'=>'Nothing (overflow the box)', 'truncate'=>'Truncate','...'=>'Truncate and add ellipses (...)', 'scale'=>'Scale'),'truncate'); + echo ""; - echo ""; + echo "

"; } } echo "\n"; diff --git a/tcpdf.inc.php b/tcpdf.inc.php index 0d30a25..0d64c96 100644 --- a/tcpdf.inc.php +++ b/tcpdf.inc.php @@ -93,13 +93,20 @@ class pdf extends TCPDF { } - function _fitcell_lines($w,$h,$txt,$fontsize) + /* Given a cell of width $w, format $txt so it fits into that + * width, using as many lines as necessary, with + * font ($fontname, $fontstyle, $fontsize). + * - fontsize is in points + * Returns an array of lines that fit in the width. + * Compute the final height with: + * count($lines) * ($this->cMargin * 2 + $fontsize_not_in_pts) */ + function _cell_lines($w,$txt,$fontname, $fontstyle, $fontsize) { $index = 0; $lines = array(); /* Get an array of widths */ - $width = $this->getStringWidth($txt,'','',$fontsize,true); + $width = $this->getStringWidth($txt,$fontname, $fontstyle,$fontsize,true); $chars = $this->UTF8StringToArray($txt); $count = count($width); // strlen(utf8_decode($txt)); @@ -173,12 +180,14 @@ class pdf extends TCPDF { $fontsize = $orig_fs; while(1) { - $lines = $this->_fitcell_lines($w, $h, $txt, $fontsize); + $lines = $this->_cell_lines($w, $txt, '', '', $fontsize); + /* this->FontSize is always correct, we change $fontisze + * below, but then use that to set the internal fontsize */ $cell_height = $this->cMargin * 2 + $this->FontSize; - $label_h = $cell_height * count($lines); + $total_height = $cell_height * count($lines); - if($label_h <= $h) { + if($total_height <= $h) { /* It fits! */ break; } @@ -208,10 +217,10 @@ class pdf extends TCPDF { /* SetX, find Y based on alignment */ switch($valign) { case 'M': /* Middle */ - $this->SetXY($x, $y + ($h - $label_h) / 2); + $this->SetXY($x, $y + ($h - $total_height) / 2); break; case 'B': /* Bottom */ - $this->SetXY($x, $y + ($h - $label_h)); + $this->SetXY($x, $y + ($h - $total_height)); break; case 'T': default: /* Top */ $this->SetXY($x, $y); @@ -238,9 +247,11 @@ class pdf extends TCPDF { /* Restore original fontsize */ $this->setFontSize($orig_fs); - /* Deal with the border and ln, leaving x,y wherever $ln - * tells us to */ + /* Print a Cell to print the border (if we're supposed to), and + * to leave x,y wherever $ln tells us to */ $this->Cell($w, $h, '', $border, $ln, 'R'); + + return $total_height; } function GetFontList() @@ -339,15 +350,6 @@ class pdf extends TCPDF { } - function output($filename='', $dest='I') - { - if($filename == '') { - $filename=strtolower($this->subject); - $filename=ereg_replace("[^a-z0-9]","_",$filename).'.pdf'; - } - parent::Output($filename, $dest); - } - /* align = left, center, right valign = top, middle, bottom, fontname, @@ -355,6 +357,7 @@ class pdf extends TCPDF { fontsize, border = true/false on_overflow = truncate, ..., scale */ + function label_text($x,$y,$w,$h,$text,$border,$align,$valign,$fontname,$fontstyle,$fontsize, $on_overflow) { @@ -398,4 +401,207 @@ class pdf extends TCPDF { { $this->Rect($this->lMargin + $x, $this->tMargin + $y, $w, $h); } + +/**************************************************************************** + * Table handling */ + function hr() + { + $this->Cell(0, 1, '', 'B', 1, ''); + $this->Cell(0, 1, '', '', 1, ''); + } + + function vspace($space) + { + $this->SetY($this->GetY() + $space); + } + + function setup_for_tables($show_box, $show_fair, $show_logo, $width, $height, $xspacer, $yspacer, $rows, $cols) + { + $this->SetFont('times', '', 10); + + /* Need to start with a page if autopagebreak is on */ + $this->addPage(); + } + + function heading($text) + { + /* TCPDF will spill this cell over to the next page if the height + * doesn't fit, so we don't have to do any height calculations, just + * create an oversized cell with nothing in it to force a spillover if + * at least the first table row won't fit with the header */ + /* header font size + 5mm + curr font size (2st table rows)*/ + $h = ($this->FontSize * 1.5) + 5 + ($this->FontSize * 2); + $this->Cell(0, $h, '', 0, 2, '', 0, 0, 0, false); + $this->SetY($this->GetY() - $h); + + /* Now print it in a normal sized cell with a bit of bottom padding + * before the table starts */ + $h = ($this->FontSize * 1.5) + 5; + $orig = $this->getFontSizePt(); + $this->setFont('', 'B', $orig * 1.5); + $this->Cell(0, $h, $text, 0, 2, '', 0, 0, 0, false); + $this->setFont('', '', $orig); + } + + /* Generates the HTML for a table */ + function get_table_html($table) + { +// echo "Add Table\n
";
+//		print_r($table);
+		/* Compute the lines in height of each row for pagination */
+
+		$html = '';
+		foreach($table['col'] as $c=>$col) {
+			$html .= "";
+		}
+		$html .= '';
+
+//		echo "
";
+
+		/* Width of "..." */
+		$e_width = $this->getStringWidth('...', '', '', '', false);
+
+		foreach($table['data'] as $row) {
+			$html .= '
'; + foreach($row as $c => $d) { + /* unfortunately, HTML doesn't do overflow the + * way we want, so compute the width of each cell + * and truncate the text if needed */ + if($table['col'][$c]['on_overflow'] == '...') { +// echo "check for overflow... $d"; + /* See if $d fits in the allowed width */ + $width = $this->getStringWidth($d, '', '', '', true); + $target_w = $table['col'][$c]['width']; + /* FIXME, this doesn't work all the time + * there must be some cellpadding that HTML is doing */ + $target_w -= 1.4111111111; /* 2 points * 2*/ + $target_w -= 0.7055555556; /* 2 points */ + + $cw = 0; +// echo "target=$target_w, w="; +// print_r($width); + for($x=0; $x $target_w) { + /* Overflow */ + while($x >= 0) { + $x--; + $cw -= $width[$x]; + if($cw + $e_width < $target_w) break; + } + $d = substr($d, 0, $x).'...'; + break; + } + $cw += $w; + } + } + + $html .= ""; + } + $html .= ''; + } + $html .= '
{$col['header']}
$d
'; + return $html; + } +//echo "
";
+//echo $html;					
+
+			
+/*			
+$html = <<
+
+ 
+  A
+  XXXX
+  XXXX
+   XXXX
+  XXXX
+  XXXX
+ 
+ 
+  B
+  XXXX
+  XXXX
+   XXXX
+  XXXX
+  XXXX
+ 
+
+ 
+  1.
+  XXXX
XXXX
XXXX
XXXX
XXXX
XXXX
XXXX
XXXX + XXXX
XXXX + XXXX
XXXX + XXXX + XXXX
XXXX + + + 2. + XXXX
XXXX + XXXX
XXXX + XXXX
XXXX + XXXX
XXXX + + + XXXX
XXXX
XXXX
XXXX + XXXX
XXXX + XXXX
XXXX + + + RRRRRR
XXXX
XXXX
XXXX
XXXX
XXXX
XXXX
XXXX + XXXX
XXXX + XXXX
XXXX + + + 3. + XXXX1
XXXX + XXXX
XXXX + XXXX
XXXX + + + 4. + XXXX
XXXX + XXXX
XXXX + XXXX
XXXX + XXXX
XXXX + + +EOD; +*/ + function add_table($table) + { + $orig_lmargin = $this->lMargin; + $orig_tmargin = $this->tMargin; + + $html = $this->get_table_html($table); + $total_width = 0; + foreach($table['col'] as $c=>$col) + $total_width += $col['width']; + + $lpad = (($this->getPageWidth() - $this->lMargin - $this->rMargin) - $total_width)/2; + + $this->SetLeftMargin($orig_lmargin + $lpad); + $this->writeHTML($html, false, false, false, false, ''); + $this->SetLeftMargin($orig_lmargin); + + if($table['total'] != 0) { + $this->Cell($total_width, 0, "(Total: {$table['total']})", 0, 1, 'R'); + } else { + $t = count($table['data']); + $this->Cell($total_width, 0, "(Rows: $t)", 0, 1, 'R'); + } + } + + function output($filename='', $dest='I') + { + if($filename == '') { + $filename=strtolower($this->subject); + $filename=ereg_replace("[^a-z0-9]","_",$filename).'.pdf'; + } + parent::Output($filename, $dest); + } + + }