From: "Saved by Windows Internet Explorer 7" Subject: PHP to PDF conversion with TCPDF Date: Thu, 31 Jul 2008 13:13:50 +0100 MIME-Version: 1.0 Content-Type: text/html; charset="utf-8" Content-Transfer-Encoding: quoted-printable Content-Location: http://66.102.9.104/search?q=cache:http://www.akamarketing.com/blog/109-php-to-pdf-conversion-with-tcpdf.html&hl=en&rlz=1T4GGLJ_enIE267IE267&strip=1 X-MimeOLE: Produced By Microsoft MimeOLE V6.0.6000.16545 =EF=BB=BF PHP to PDF conversion with TCPDF This=20 is Google's cache of http://www.akamarketing.com/blog/109-php-to-pdf-conversion-wit= h-tcpdf.html.=20 It is a snapshot of the page as it appeared on 25 Jul 2008 20:41:27 GMT. = The current=20 page could have changed in the meantime. Lea= rn more=20 =C2=BB

Full=20 version
 
Blogged=20 thoughts, is our web blog. Expect views, opinion, rants and tirades = about=20 everything and anything 
=C2=AB Home /=  Services / Forums <= /A>=C2=BB        =20 Organic Search Engine Optimization (SEO) Solutions. Call now on=20 +00-353-879807629

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

Blogged thoughts

| by = the=20 www.akamarketing.com team=20

=C2=AB Off=20 to sunny Algarve on an extended working holiday


PHP to PDF conversion with TCPDF

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

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

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

I have to say I found it quite a slow & tedious process to create = the=20 more complex dynamic PDFs with this library, however this is because of = what I=20 was trying to do in the overall sense and was not the libraries = =E2=80=98fault=E2=80=99, after=20 all creating PDFs dynamically is quite different than creating = webpages=20 dynamically. I found having to work out all the =E2=80=98maths=E2=80=99 = for positioning=20 elements and the fact you can=E2=80=99t just press refresh to see = if your latest=20 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=E2=80=99ll go=20 through how I actually created the PDF report which my client wanted by=20 providing a striped down version of the code. The two = interesting=20 things about the report was that it had to have a table with = all the=20 data and the page the table was on had to be presented in landscape = style=20 (because the table was wide). The table I output is related to Golf and = is very=20 simple, but hopefully it will be a good TCPDF starting block for=20 you. 

Creating a table with TCPDF
Within the TCPDF class there are a couple of useful methods = which enable=20 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=20 does not support putting HTML into the cell data. Although I could have=20 outputted a standard HTML coded table using writeHTML() I went with = MultiCell()=20 in the end. The code below is similar to what I used, it produces this = PDF (please right click and save as=E2=80=A6 = otherwise your=20 browser might crash). Be sure to change the line that says =E2=80=98FIX = THIS LINE=E2=80=99=E2=80=A6 I=20 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=20 it
 require_once(=E2=80=99../tcpdf/tcpdf.php=E2=80=99);

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

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

 // add a page - landscape = style
 $pdf->AddPage(=E2=80=9DL=E2=80=9D);

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

 //styling for normal non header=20 cells
 $pdf->SetTextColor(0);=20 //black
 $pdf->SetFont('=E2=80=99,'=E2=80=99);

 //the data - normally would come from DB, web service=20 etc.
 $rank =3D = array(=E2=80=991=E2=80=B2,=E2=80=992=E2=80=B2,=E2=80=993=E2=80=B2);
&n= bsp;$player =3D array(=E2=80=99Tiger=20 Woods,  USA=E2=80=99,'Phil Mickelson,  USA = =E2=80=98,=E2=80=99Padraig Harrington,  Irl=20 =E2=80=98);
 $playerWWW =3D=20 array(=E2=80=99http://tigerwoods.com/=E2=80=99,'http://philmickelson.com/= =E2=80=99,'http://padraigharrington.com/=E2=80=99);
 $avgPts=20 =3D = array(=E2=80=9910=E2=80=B2,=E2=80=999=E2=80=B2,=E2=80=998=E2=80=B2);
&= nbsp;$totPts =3D = array(=E2=80=99100=E2=80=B2,=E2=80=9990=E2=80=B2,=E2=80=9980=E2=80=B2);

 //create & populate table cells
 for($i =3D 0; $i = <=20 count($rank); $i++)
 {
       = if($i =3D=3D=20 "2")//highlight Harrington because he=20 Irish... 
     =20 {            =    =20 //in reality you might highlight profits/losses=20 etc.
         =20 $pdf->SetFillColor(89, 239, 152); = //green
     =20 }
      = else
     =20 {
       =20  $pdf->SetFillColor(255); = //white
     =20 }
      
    &nbs= p; =20 //link the players name to his website
      = $playerANDlink =3D =E2=80=9Ca = href=3D\=E2=80=9D$playerWWW[$i]\=E2=80=9D>$player[$i]/a=E2=80=9D; = //FIX THIS=20 LINE
  
     //int MultiCell( float = $w,=20 float $h, string $txt, [mixed $border =3D 0], [string $align =3D=20 =E2=80=98J=E2=80=99],
     //[int $fill =3D 0], = [int $ln =3D 1], [int $x =3D=20 =E2=80=98=E2=80=99], [int $y =3D =E2=80=98=E2=80=99], [boolean $reseth = =3D true],
     //[int=20 $stretch =3D 0], [boolean $ishtml =3D = false])
    =20 $pdf->MultiCell($width[0],7,$rank[$i],1,=E2=80=99C',1,0,'=E2=80=99,'=E2= =80=99,1,0,1); 
    =20 $pdf->MultiCell($width[1],7,$playerANDlink,1,=E2=80=99C',1,0,'=E2=80=99= ,'=E2=80=99,1,0,1); 
    =20 $pdf->MultiCell($width[2],7,$avgPts[$i],1,=E2=80=99C',1,0,'=E2=80=99,'= =E2=80=99,1,0,1);
    =20 $pdf->MultiCell($width[3],7,$totPts[$i],1,=E2=80=99C',1,0,'=E2=80=99,'= =E2=80=99,1,0,1);
  
    =20 $pdf->Ln(); //new row
 }

 //output the PDF to the=20 browser
 $pdf->Output(=E2=80=9D./pdfs/example.pdf=E2=80=9D, = =E2=80=9CF=E2=80=9D); //F for saving=20 output to file 

PDF creation and setup
OK I=E2=80=99ll briefly go through this = code then. The=20 first couple of lines really just sets up the PDF document or pages = within the=20 document, please refer to the TCPDF class documentation for more = information. The=20 only real item of note here is the method for creating a landspaced PDF = page.=20 The default AddPage() method takes no parameters and with this a page is = created=20 with the default page style (as per the overall TCPDF config file) which = is=20 usually portrait style, so pass in an =E2=80=98L=E2=80=99 for landscape = pages. It is possible to=20 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=20 style of elements. The styles set will correspond to the next = cell/element=20 drawn. Most of them are obvious. SetFillColor() sets the background = color of a=20 cell when that cell is set to be painted or filled. The fun begins = though when=20 you actually start outputting cells (retangles). The header is just = plain text=20 so I used cell(). Cell() is well documented on the TCPDF site and it is = easy to=20 use. Parameters in order from left to right are, width, height, cell = text,=20 border true or false, where next cell should go, cell alignment, fill in = cell=20 true or false, optional link and stretch options.

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

$pdf->Cell(20,7,=E2=80=9DRank=E2=80=9D,1,0,=E2=80=99C',1);

which means create a cell of width 20 and height 7 with its value set = to=20 =E2=80=9CRank=E2=80=9D. It should have a border, have its value centered = and should have its=20 background filled in.

Table Body
The main body of the table is very similar, but uses = the method=20 MultiCell() as we want the ability to output HTML as the cells=E2=80=99 = value. A couple=20 of arrays of data are created and populated. These will slot into the = cells we=20 are about to create. In reality the values of the cell will likely come = straight=20 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=20 using cell() above so I won=E2=80=99t mention them again. It also = introduces a couple of=20 new parameters including, X and Y for setting the positional=20 coordinates of a cell, Reseth which resets the height of the = last cell=20 (without setting this to true your likely to get crazy looking = tables=E2=80=A6 leave it=20 to true and forget about it) and ishtml which determines if the = cell value=20 can hold HTML or not. MultiCell()=E2=80=99s full definition is=20 below.  

int MultiCell( float $w, float $h, string $txt, [mixed $border =3D = 0], [string=20 $align =3D =E2=80=98J=E2=80=99], [int $fill =3D 0], [int $ln =3D = 1], [int $x =3D =E2=80=98=E2=80=99], [int $y =3D=20 =E2=80=98=E2=80=99], [boolean $reseth =3D true], [int $stretch =3D = 0], [boolean $ishtml =3D=20 false])

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

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

$pdf->MultiCell($width[2],7,$avgPts[$i],1,=E2=80=99C',1,0,'=E2=80=99= ,'=E2=80=99,1,0,1);
$pdf->MultiCell($width[3],7,$totPts[$i],1,=E2=80= =99C',1,0,'=E2=80=99,'=E2=80=99,1,0,1);
  
$pdf->Ln();= =20 //new row

to this:

$pdf->MultiCell($width[2],7,$avgPts[$i],1,=E2=80=99C',1,0,'=E2=80=99= ,'=E2=80=99,1,0,1);
$pdf->MultiCell($width[3],7,$totPts[$i],1,=E2=80= =99C',1,1,'=E2=80=99,'=E2=80=99,1,0,1);

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

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

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

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

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

$pdf->Output(=E2=80=9D./pdfs/example.pdf=E2=80=9D, = =E2=80=9CF=E2=80=9D);

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

A little tip when your developing locally (as opposed to directly on = your=20 webhost) and using =E2=80=98F=E2=80=99 for the destination parameter is = to create your=20 PDFs with a random filename so you can simply press refresh on your = script=20 that does the PDF creation logic. If you have a static filename as I do = in this=20 example (called example.pdf) and you have the last generated PDF file = (also=20 example.pdf) open TCPDF will not be able to write the PDF (as it is = aleady=20 open, so a sharing violation error will occur internally). What I often = use for=20 random filenames during development is sha1(microtime()), this means to = check=20 changes I just need to press refresh on my PHP script and then visit my = PDFs=20 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=20 first saving it to disk somewhere.

Both I and D allow you to access the PDF quickly via the = browser. A note=20 about these two lads is this=E2=80=A6 Internet Explorer often looks at = the extension of=20 the file, (which will be .php) and assumes that the output will be HTML = and thus=20 will not present you a PDF, it will likely present a load of = binary=20 data in the webpage itself which obviously is not what you want. Firefox = handles=20 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=20 users might have the same problem too. It might be an idea to save to = disk=20 first, provide a link to the pdf and then periodically purge your temp = PDFs=20 folder.

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

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

Share and Enjoy: These icons link to social = bookmarking=20 sites where readers can share and discover new web pages.=20
One Comment on =E2=80=9CPHP to PDF conversion with = TCPDF=E2=80=9D
1| David = Callan said,=20 25th July @ 19:25 

I=E2=80=99m also going to give dompdf a look, anyone used this = lad instead of=20 TCPDF, PDFLib etc?

Leave a Comment
Name: (Required)
Email: (Will not be displayed)(Required)
Website:
   =20             Notify me of followup = comments=20 via email
HOME | ABOUT = US | CONTACT US |=20 RESOURCES | SITEMAP | GOOGLE SITE SEARCH | TOP=20