AKA Marketing.com Logo            VISIT THE BLOG            

Blogged thoughts, is our web blog. Expect views, opinion, rants and tirades about everything and anything 

« Home / Forums »        

 


Subscribe to our SEO / IT related blog by entering your email address below

Blogged thoughts

| by the www.akamarketing.com team



PHP to PDF conversion with TCPDF

Recently I had a development client which as part of a larger system had a requirement of creating a PDF based report from his clients metrics, KPI’s etc. which he could then forward onto them. It was simple numerical data but for presentation purposes it was needed in PDF… you know to look good.

In the past when budget was less of an issue I used PDFLib, a commercial library which these days is available as part of the core PHP package. This project however required me to look for a free alternative. I found TCPDF on Sourceforge. It had almost 80,000 downloads, good documentation, lots of examples and was being used by applications such as Joomla, Drupal, Moodle and phpMyAdmin so I said I’d give it a go.

Installation was easy, basically I just needed to copy the TCPDF folder to my www space and require() the main class file from PHP scripts that needed to create PDFs on the fly.

I have to say I found it quite a slow & tedious process to create the more complex dynamic PDFs with this library, however this is because of what I was trying to do in the overall sense and was not the libraries ‘fault’, after all creating PDFs dynamically is quite different than creating webpages dynamically. I found having to work out all the ‘maths’ for positioning elements and the fact you can’t just press refresh to see if your latest line or two outputted as intended the most frustrating.  

OK to give you a feel for how the TCPDF class library can be used I’ll go through how I actually created the PDF report which my client wanted by providing a striped down version of the code. The two interesting things about the report was that it had to have a table with all the data and the page the table was on had to be presented in landscape style (because the table was wide). The table I output is related to Golf and is very simple, but hopefully it will be a good TCPDF starting block for you. 

Creating a table with TCPDF
Within the TCPDF class there are a couple of useful methods which enable me to output a nice table with DB data embedded in the cells. These are writeHTML(), writeHTMLCell()Cell() & MultiCell(). I had to rule out Cell() for the most part as it does not support putting HTML into the cell data. Although I could have outputted a standard HTML coded table using writeHTML() I went with MultiCell() in the end. The code below is similar to what I used, it produces this PDF (please right click and save as… otherwise your browser might crash). Be sure to change the line that says ‘FIX THIS LINE’… I had to remove the HTML because Wordpress was acting the goat again. The full not-messed-up-by-wordpress version is available too.

//reference the class so you can use it
 require_once(’../tcpdf/tcpdf.php’);

 // create new PDF document
 $pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true);

 //do not show header or footer
 $pdf->SetPrintHeader(false); $pdf->SetPrintFooter(false);

 // add a page - landscape style
 $pdf->AddPage(”L”);

 // set font
 $pdf->SetFont(”freeserif”, “”, 11);
 
 /////////////////////////////////////////////
 //  START TABLE HEADER
 /////////////////////////////////////////////
  
 //Colors, line width and bold font for the header
 $pdf->SetFillColor(11, 47, 132); //background color of next Cell
 $pdf->SetTextColor(255); //font color of next cell
 $pdf->SetFont(”,’B'); //b for bold
 $pdf->SetDrawColor(0); //cell borders - similiar to border color
 $pdf->SetLineWidth(.3); //similiar to cellspacing
 
 $cols=array(’Rank’,'Player’,'Pts. Avg.’,'Total Pts.’);//Column titles
 $width=array(20,50,40,30); //amount of elements must correspond with $header array above
 
 for($i = 0; $i < count($cols); $i++)
{
     //void Cell( float $w, [float $h = 0], [string $txt = ''], [mixed $border = 0],
     //[int $ln = 0], [string $align = ''], [int $fill = 0], [mixed $link = ''], [int $stretch = 0]) 
     $pdf->Cell($width[$i],7,$cols[$i],1,0,’C',1);
 }
 
 $pdf->Ln(); //new row
 
 ////////////////////////////////////////////////
 //  START TABLE BODY
 ////////////////////////////////////////////////

 //styling for normal non header cells
 $pdf->SetTextColor(0); //black
 $pdf->SetFont(”,”);

 //the data - normally would come from DB, web service etc.
 $rank = array(’1′,’2′,’3′);
 $player = array(’Tiger Woods,  USA’,'Phil Mickelson,  USA ‘,’Padraig Harrington,  Irl ‘);
 $playerWWW = array(’http://tigerwoods.com/’,'http://philmickelson.com/’,'http://padraigharrington.com/’);
 $avgPts = array(’10′,’9′,’8′);
 $totPts = array(’100′,’90′,’80′);

 //create & populate table cells
 for($i = 0; $i < count($rank); $i++)
 {
       if($i == "2")//highlight Harrington because he Irish... 
      {                //in reality you might highlight profits/losses etc.
          $pdf->SetFillColor(89, 239, 152); //green
      }
      else
      {
         $pdf->SetFillColor(255); //white
      }
      
       //link the players name to his website

      $playerANDlink = “a href=\”$playerWWW[$i]\”>$player[$i]/a”; //FIX THIS LINE
  
     //int MultiCell( float $w, float $h, string $txt, [mixed $border = 0], [string $align = 'J'],
     //[int $fill = 0], [int $ln = 1], [int $x = ''], [int $y = ''], [boolean $reseth = true],
     //[int $stretch = 0], [boolean $ishtml = false])
     $pdf->MultiCell($width[0],7,$rank[$i],1,’C',1,0,”,”,1,0,1); 
     $pdf->MultiCell($width[1],7,$playerANDlink,1,’C',1,0,”,”,1,0,1); 
     $pdf->MultiCell($width[2],7,$avgPts[$i],1,’C',1,0,”,”,1,0,1);
     $pdf->MultiCell($width[3],7,$totPts[$i],1,’C',1,0,”,”,1,0,1);
  
     $pdf->Ln(); //new row
 }

 //output the PDF to the browser
 $pdf->Output(”./pdfs/example.pdf”, “F”); //F for saving output to file
 

PDF creation and setup
OK I’ll briefly go through this code then. The first couple of lines really just sets up the PDF document or pages within the document, please refer to the TCPDF class documentation for more information. The only real item of note here is the method for creating a landspaced PDF page. The default AddPage() method takes no parameters and with this a page is created with the default page style (as per the overall TCPDF config file) which is usually portrait style, so pass in an ‘L’ for landscape pages. It is possible to have some pages landscape and some portrait style in a single PDF document.

Table Header
The TCPDF class has a lot of methods for setting the style of elements. The styles set will correspond to the next cell/element drawn. Most of them are obvious. SetFillColor() sets the background color of a cell when that cell is set to be painted or filled. The fun begins though when you actually start outputting cells (retangles). The header is just plain text so I used cell(). Cell() is well documented on the TCPDF site and it is easy to use. Parameters in order from left to right are, width, height, cell text, border true or false, where next cell should go, cell alignment, fill in cell true or false, optional link and stretch options.

The $ln - where next cell should go parameter, is useful if you want to build your tables vertically rather than horizontally. Leave it at 0 to go to the right and then call Ln() (kind of like what tr does in HTML table) to start a new row is what I suggest. If the fill parameter is set to true the cell background will be the color set by SetFillColor() as mentioned above, if no fill color has yet be set, the background will be grey. My header is built by using a loop to create the four required cells. The first iteration in the loop will be:

$pdf->Cell(20,7,”Rank”,1,0,’C',1);

which means create a cell of width 20 and height 7 with its value set to “Rank”. It should have a border, have its value centered and should have its background filled in.

Table Body
The main body of the table is very similar, but uses the method MultiCell() as we want the ability to output HTML as the cells’ value. A couple of arrays of data are created and populated. These will slot into the cells we are about to create. In reality the values of the cell will likely come straight from a DB or webservice but hardcoded arrays is fine for this sample.

MultiCell() has a lot of the same parameters which we have come across when using cell() above so I won’t mention them again. It also introduces a couple of new parameters including, X and Y for setting the positional coordinates of a cell, Reseth which resets the height of the last cell (without setting this to true your likely to get crazy looking tables… leave it to true and forget about it) and ishtml which determines if the cell value can hold HTML or not. MultiCell()’s full definition is below.  

int MultiCell( float $w, float $h, string $txt, [mixed $border = 0], [string $align = 'J'], [int $fill = 0], [int $ln = 1], [int $x = ''], [int $y = ''], [boolean $reseth = true], [int $stretch = 0], [boolean $ishtml = false])

It’s pretty simple to use. It provides power by allowing you to set the exact X and Y coordinates of a cell, but also ease of use in the sense that if you don’t specify values for X and Y it will just output at the current position (just like cell() does) so you don’t have to do any logic to get suitable X & Y values… in most cases anyhow.

After four calls to MultiCell() which printed one row of cells, we call Ln() to move to a new line. In fact we didn’t even need to do this to be honest, we could have just changed the $ln parameter value from 0 (to the right) to 1 (to the beginning of the next line) on our fourth cell in each row. The code then would change from this:

$pdf->MultiCell($width[2],7,$avgPts[$i],1,’C',1,0,”,”,1,0,1);
$pdf->MultiCell($width[3],7,$totPts[$i],1,’C',1,0,”,”,1,0,1);
  
$pdf->Ln(); //new row

to this:

$pdf->MultiCell($width[2],7,$avgPts[$i],1,’C',1,0,”,”,1,0,1);
$pdf->MultiCell($width[3],7,$totPts[$i],1,’C',1,1,”,”,1,0,1);

Personally I prefer the first way of doing things as it’s more obvious that a new line/row is being outputted. 

Before the call to MultiCell() I changed the fill colour of the cells related to Padraig Harrington (for those that don’t know who he is… he’s a two time Golf Major champion from Dublin), I set them back to white for all other rows. Of course that’s more hardcoding, in a ‘real world’ scenario you might highlight your good figures in green and your bad figures in red.

Outputting the final PDF
When you’ve finished creating all required cells, images, links, text etc. you have to call the Output() method to actually get your hands on your dynamically created PDF. This can take no parameters in which case the PDF is sent to the browser, more commonly though, developers specify the filename and the destination of the generated PDF. The destination can be one of four values, these are:

I: send the file inline to the browser.
D: send to the browser and force a file download with the name given by name.
F: save to a local file with the name given by name.
S: return the document as a string.

You can see my code sets the destination value as F:

$pdf->Output(”./pdfs/example.pdf”, “F”);

this is telling TCPDF to save the dynamically generated PDF document in the pdfs folder with the name example.pdf. On Windows it’s not needed but on Unix based machines you will need to set appropriate permissions on the pdfs (or whatever) folder to allow TCPDF to write the pdfs to it.

A little tip when your developing locally (as opposed to directly on your webhost) and using ‘F’ for the destination parameter is to create your PDFs with a random filename so you can simply press refresh on your script that does the PDF creation logic. If you have a static filename as I do in this example (called example.pdf) and you have the last generated PDF file (also example.pdf) open TCPDF will not be able to write the PDF (as it is aleady open, so a sharing violation error will occur internally). What I often use for random filenames during development is sha1(microtime()), this means to check changes I just need to press refresh on my PHP script and then visit my PDFs folder without having to close previous versions of my PDF.

S is useful if you want to sent the PDF as an attachment in an email without first saving it to disk somewhere.

Both I and D allow you to access the PDF quickly via the browser. A note about these two lads is this… Internet Explorer often looks at the extension of the file, (which will be .php) and assumes that the output will be HTML and thus will not present you a PDF, it will likely present a load of binary data in the webpage itself which obviously is not what you want. Firefox handles both I and D perfectly so I recommend using this during development, you obviously need to keep this in mind when you go into production too as your users might have the same problem too. It might be an idea to save to disk first, provide a link to the pdf and then periodically purge your temp PDFs folder.

Conclusion
I guess you could say that was kind of an introduction to TCPDF, my own introduction to it came from the TCPDF examples page. Thanks to Nicola Asuni for all her hard work on the examples and on TCPDF itself of course.

At this stage I’m really only learning TCPDF myself too so at the moment so I can’t really comment on its real power yet. I’ve come across a couple of issues using it so far but none were without workarounds, I imagine the commercially available libraries will out do it but for a library that’s free and relatively easy to use I offer my closing statement as… so far so good.

26 Comments on “PHP to PDF conversion with TCPDF”
1| David Callan said,

I’m also going to give dompdf a look, anyone used this lad instead of TCPDF, PDFLib etc?

2| Use Wordpress? Check the source code of your Google cache for hidden spam links said,

[...] « PHP to PDF conversion with TCPDF [...]

3| Dori B. said,

I just started using TCPDF yesterday and was having difficulty deciding whether to use writeHTML(), writeHTMLCell(), Cell() & MultiCell(). Thanks for this excellent post that helped solidify the concepts. I’m implementing it as a dynamic invoice PDF generator, tied into my client’s adminsitrative backend, and ended up using writeHTMLCell().

Also, nice tip on creating random filenames when writing the PDF to disk. It’s easy to forget those little details and things like browser cache can really bite. :)

4| ludlow said,

So this is a great example of TCPDF. One suggestion since it’s likely I’m not the only one using VIM (or a regular UNIX editor for that matter).

Can you PLEASE remove the specially-formatted quotes and ticks? While they look nice on the page, they make it a huge pain in the ass to copy and paste the code into an editor as PHP doesn’t recognize the fancy-quotes.

Very informative though :)

5| David Callan said,

Hi folks, thanks for the feedback.

Ludlow, not sure what you mean when you mention quotes and ticks? Perhaps the source itself is easier to copy from rather than the post - http://www.akamarketing.com/pdf.phps

6| Imel said,

Hmm…
I wonder if you can make another example of this. Actually I also use tcpdf to make a pdf report from data in database. But I am stuck, when the data (in string form) is long and displayed in two lines of a cell, it will make other cell looks weird.
In your pdf, I think you’re lucky enough because your data is in small number of characters. Can you try if it is customer id, name, address, phone number, office address, office phone number. The display of the report will look horrible.:(
Can you help me out?
Thanks anyway

7| David Callan said,

Hi Imel,
No time to do another example at this stage on this topic but tell me this what are you using to draw your cells? Have you tried the $stretch parameters and the $reseth parameters?

According to documentation $stretch can be :

0 = disabled
1 = horizontal scaling only if necessary
2 = forced horizontal scaling
3 = character spacing only if necessary
4 = forced character spacing

Aslo ensure you have $reseth to true, when I had it to false before my tables looked crazy.

8| Manoj Kumar said,

I am unable to config the file tcpdf_config, getting so many irrors, please help me.

9| Imel said,

Hi David, thank you for your quick response. I’ve tried your suggestion. It’s just that I have a problem. I want to display data like no, employee id, employee name, birth date, address and phone. I tried to use the reseth, but because data address is longer than data phone, it still follow the last cell, which is data phone. So, finally I decided to join the address and the phone, so it will be the longest data compare to employee id, employee name and birth date. But I can’t configure the border layout. The border for employee id, name and birthdate doesn’t following the width and height of address border. Do you have any suggestion what should I do?
Thank you very much. You light my day.

10| Mohsin Ali said,

I m using TCPDF with CakePHP framework..
While creating pdf, an error is occured..

Error::
file does not start with ‘%PDF-’

11| Mohsin Ali said,

Any idea to change the header and footer…

12| Nem said,

I’ve tried a lot of PDF-classes but TCPDF is the best. It’s able to output CMYK-pdf’s which is really important for us because the online created PDF-files are sent out for printing in newspapers.
Also, this is a nice article!

13| Jchon said,

I’m using TCPDF for an on-the-fly pdf creation from form input… I need to send the created pdf as an attachment in an email, but aren’t getting far - can you give me a sample of the php code needed to send the pdf as an email attachment?

14| Keith said,

[... the fact you can’t just press refresh to see if your latest line or two outputted as intended ...]

Hi, after installing a few weeks ago, I am trying out SrWare IRON on WinXP today for development. It seems to be using the Adobe PDF viewer plugin - I stopped using that program a while ago but I assume the plugin is still on the system. Point is, with iron, I can make a change to the code, switch to iron and hit F5 to see the results. It’s fast too!

15| Lawson said,

Can I create a HTML header using TCPDF.

16| wwww said,

Any idea to change the background…

17| Ankur said,

please more somplify it

18| randoogle said,

I haven’t been able to find this anywhere, but is it possible to have cells within cells, kind of like HTML tables inside tables?

I’m currently using writeHTML() with an HTML table, but there is no way really to set a page break programmatically using html, and the data gets broken up in strange places.

19| MD FAISAL said,

I have a HTML Table (created using tinyMCE) to be written in the pdf. The column width is not displayed properly. Even if the column is small, it spreads itself to the whole page. I have tried assigning the width propety in tag. but of no use.Any help to rectify this.

20| ronald said,

thanks for this nice tutorial, Ive noticed that the pdf file crated for your code is 1.045 MB, i think that is much amount of space, is there a way to decrease that?

21| psank said,

Hello,
I am using TCPDF multicell method to create pdf on the fly. Data is output in table format. but there 72 columns in my table, and so my table spreads across the width of the content area of the pdf. Only 7-8 fields are displayed. Can anyone guide me on this how to adjust this much data into fit into the width of pdf.

thank you.

22| منتديات said,

Hi, after installing a few weeks ago, I am trying out SrWare IRON on WinXP today for development. It seems to be using the Adobe PDF viewer plugin - I stopped using that program a while ago but I assume the plugin is still on the system. Point is, with iron, I can make a change to the code, switch to iron and hit F5 to see the results. It’s fast too!

23| Sovit said,

Hi All,

I am creating a Dynamic PDF(Using DB) with tha help of tcpdf . I have to show 4 image in row .but it is not diplaying .plez helpme
i m posting my code as well

SetCreator(PDF_CREATOR);
$pdf->SetAuthor(’Nicola Asuni’);
$pdf->SetTitle(’TCPDF Example 039′);
$pdf->SetSubject(’TCPDF Tutorial’);
$pdf->SetKeywords(’TCPDF, PDF, example, test, guide’);
// set default header data
$pdf->SetHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE.’ 039′, PDF_HEADER_STRING);
// set header and footer fonts
$pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, ”, PDF_FONT_SIZE_MAIN));
$pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, ”, PDF_FONT_SIZE_DATA));
// set default monospaced font
$pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
//set margins
$pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
$pdf->SetHeaderMargin(PDF_MARGIN_HEADER);
$pdf->SetFooterMargin(PDF_MARGIN_FOOTER);
//set auto page breaks
$pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
//set image scale factor
$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
//set some language-dependent strings
$pdf->setLanguageArray($l);
// ———————————————————
// add a page
$pdf->AddPage();
// set font
$pdf->SetFont(’helvetica’, ‘B’, 20);
$pdf->Write(0, ‘Example of HTML Justification’, ”, 0, ‘C’, true, 0, false, false, 0);
// create some HTML content
$i=0;
$html = ”;
//$i=mysql_num_rows($q_cat);
$html .= ”;
$i=0;
while($row_cat=mysql_fetch_array($q_cat))
{
if(($i%4)==0)
{
$html .= ”;
$html .= ”;
break;

}
$html .= ‘
‘;

}
$html .= ”;
$html .= ”;
// set core font
$pdf->SetFont(’helvetica’, ”, 10);
// output the HTML content
$pdf->writeHTML($html, true, 0, true, true);
$pdf->Ln();
// set UTF-8 Unicode font
//$pdf->SetFont(’dejavusans’, ”, 10);
// output the HTML content
//$pdf->writeHTML($html, true, 0, true, true);

// reset pointer to the last page
$pdf->lastPage();

// ———————————————————

//Close and output PDF document
$pdf->Output(’example_039.pdf’, ‘I’);

//============================================================+
// END OF FILE
//============================================================+
?>

24| Sovit said,

SetCreator(PDF_CREATOR);
$pdf->SetAuthor(’Nicola Asuni’);
$pdf->SetTitle(’TCPDF Example 039′);
$pdf->SetSubject(’TCPDF Tutorial’);
$pdf->SetKeywords(’TCPDF, PDF, example, test, guide’);
// set default header data
$pdf->SetHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE.’ 039′, PDF_HEADER_STRING);
// set header and footer fonts
$pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, ”, PDF_FONT_SIZE_MAIN));
$pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, ”, PDF_FONT_SIZE_DATA));
// set default monospaced font
$pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
//set margins
$pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
$pdf->SetHeaderMargin(PDF_MARGIN_HEADER);
$pdf->SetFooterMargin(PDF_MARGIN_FOOTER);
//set auto page breaks
$pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
//set image scale factor
$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
//set some language-dependent strings
$pdf->setLanguageArray($l);
// ———————————————————
// add a page
$pdf->AddPage();
// set font
$pdf->SetFont(’helvetica’, ‘B’, 20);
$pdf->Write(0, ‘Example of HTML Justification’, ”, 0, ‘C’, true, 0, false, false, 0);
// create some HTML content
$i=0;
$html = ”;
//$i=mysql_num_rows($q_cat);
$html .= ”;
$i=0;
while($row_cat=mysql_fetch_array($q_cat))
{
if(($i%4)==0)
{
$html .= ”;
$html .= ”;
break;

}
$html .= ‘
‘;

}
$html .= ”;
$html .= ”;
// set core font
$pdf->SetFont(’helvetica’, ”, 10);
// output the HTML content
$pdf->writeHTML($html, true, 0, true, true);
$pdf->Ln();
// set UTF-8 Unicode font
//$pdf->SetFont(’dejavusans’, ”, 10);
// output the HTML content
//$pdf->writeHTML($html, true, 0, true, true);

// reset pointer to the last page
$pdf->lastPage();

// ———————————————————

//Close and output PDF document
$pdf->Output(’example_039.pdf’, ‘I’);

//============================================================+
// END OF FILE
//============================================================+
?>

25| Vasya said,

Hello. Help deal with TCPDF, I encountered the following problem:
for example 006 from the developer’s site TCPDF created a page and a variable $ view assigns a value to a variable that stores the html code of constructing a table and then calls perememennuyu $ view to create a pdf document using the function TCPDF writeHTML.
As a result, generates an empty strnaitsa format PDF.

What? Where mistake?

If variable $ view directly assign any HTML table as a string variable (ie, $ view = ‘
Hello World !!! ‘;), all performed with a bang for a few seconds.

Where mistake??

26| Deva Karthik said,

Thanks for a good tutorial

Leave a Comment
Name:
Email:
Website:
 
HOME | ABOUT US | CONTACT US | SITEMAP | GOOGLE SITE SEARCH | TOP
12 Lorcan Crescent, Santry, Dublin 9, Ireland +353 87 9807629