Design PDF with TCPDF
The third way that you can upload a PDF to the server is by designing it with TCPDF. TCPDF is definitely the most complicated of the three upload strategies, but it also gives you the most control of the final design of the PDF that is generated. Additionally, it is created entirely on the server side, so there is no need to adjust the Router.php
or the client side, since it is all a side effect of a php function.
Generate the PDF
The first step in using TCPDF actually generating the PDF. There are several helpful commands here. The full documentation for TCPDF can be found here, but their docs can be hard to navigate, so we will give a general description of the important aspects. Of course, this brief summary cannot cover everything, and so at times it may be necessary to attempt to navigate their docs to find a better answer than the one given here.
Create TCPDF Class
One of the first steps to using TCPDF is using the construct method, and the full description of that method can be found here. There are a few important parameters.
$orientation
The first parameter determines the orientation of the PDF whether vertical (P
orPortrait
), which is the default, or horizontal (L
orLandscape
)$unit
The second parameter tells TCPDF what unit of measure it uses when you give it numbers for length. The options are:pt
(point, which is 1/72 of an inch),mm
(millimeter, default),cm
(centimeter), andin
(inch)$format
The third parameter is format, which allows you to specify the size of the paper, can be set to either one of the string parameters of various paper sizes (it accepts all paper standard paper sizes and more, for a full list of paper sizes TCPDF will accept, click here), or you can specify an array of the dimensions in mm (so long as it resolves to an actual paper size)$unicode
The fourth parameter is a boolean whether the input text is unicode or not (default is true and not really a reason to change the default)$encoding
The final parameter is a string which takes a string encoding method (default isUTF-8
, and again, not really a reason to change the default)
So then, as an example, you would construct this file by having the following line at the top of your file (TCPDF is already imported with PDF Core, so you only need to use it):
use TCPDF;
Then you would construct the class in your code in a similar way to the following:
$pdf = new TCPDF('P', 'mm', 'LETTER');
Set Document Information
Before you can start adding actual content to the PDF that you are generating, you must set up certain metadata. PDF Core has made a nice function to set these things up for you, so that you can do this easily by just passing in an associative array of options. This is the format of the request, where $pdf
is your TCPDF object, and $options
is an object:
PdfUtils::pdfSetup($pdf, $options)
Here is a list of the metadata options that you are able to pass into options
(the see TCPDF docs links you to the function we call on the $pdf
to give you more context):
creator
string. Default isnull
. If defined, this is the creator of the pdf, usually the application which was used to create the PDF. For more information, see TCPDF Docs.author
string. Default isnull
. If defined, this is the documents primary author. For more information, see TCPDF Docs.title
string. Default isnull
. If defined, this is not the same as the file name, but reflects the main topic or purpose of the pdf. For more information, see TCPDF Docs.subject
string. Default isnull
. If defined, this should be a brief description or summary of the document. For more information, see TCPDF Docs.keywords
array[string]. Default is empty. These are terms that users might use when searching for the document. For more information, see TCPDF Docs
While not technically metadata, the following information is also available to setup pdf in options
:
font
array[string,int]. Default iscourier
|10
. You are able to pass in an array with the font family (such astimes
,courier
,helvetica
, etc) and the font size (a number). The font style parameter in ourpdfSetup
is set to regular regardless of what you pass in. For more information, see TCPDF docs.autoPageBreak
boolean. Default istrue
. This is whether or not the page automatically breaks 2 CM above the bottom of the page or not. For more information, see TCPDF docsprintHeader
boolean. Default isfalse
. This is whether or not the PDF will print the header data. For more information, see TCPDF docsprintFooter
boolean. Default isfalse
. This is whether or not the PDF will print the footer data. For more information, see TCPDF docs
Create the Document
With the two functions described above, you have successfully set up the $pdf
object so that you are able to begin generating your PDF file. A tip as you are writing in TCPDF, if you are drawing and not just writing text, you need to constantly keep track of the (x, y) coordinates of where you are, so that you do not write over data that you have already generated. A few of the more important functions would be helpful:
AddPage()
. This function adds a new page with your current page settings (such as header, orientation, format, margins, etc). Some of these can be overwritten with optional parameters of:$orientation
(same as above),$format
(same as above),$keepmargins
(boolean, default false, whether or not to override current margins), and lastly$tocpage
(boolean of whether the page is a Table of Contents or not). Most of the time, this function will be called with no parameters, if it is called at all. It must be called after the TCPDF object is created before you can write anything on the page, then if in yourpdfSetup
, you setautoPageBreak
, it will probably not be called again. If however, you setautoPageBreak
to false (as Tally does), you will need to manually keep track of where you are on the page, and add a new page when it is time (see Tally for an example). For more information, see TCPDF docsWrite()
. This function is just to write the text that you input at the current position (defaults to start at the top left). It requires two parameters and has many other potentially helpful optional parameters:$h
(required float. This is the line height of the text),$txt
(required string which is actually printed),$link
(optional URL string),$fill
(optional boolean for whether the cell background is painted, default false), or$align
(optional string of the alignment of the text whether default left ,L
or empty string; center ,C
; rightR
; or justifyJ
). There are many more fringe parameters that may be used, which are described in the full docs. For more information, see TCPDF docswriteHTML()
. This is perhaps one of the most helpful functions available with TCPDF, it will render simple HTML as HTML rather than a plain string, so at times this can be the fastest way to display certain formatting. For a list of supported tags, see link provided at the end. The only required parameter is the$html
string, which must be wrapped in double quotes. A few helpful optional parameters include:$ln
(boolean whether or not to add a new line after text, default true),$fill
(same as above),$reseth
(boolean to reset height, default false),$cell
(boolean to add current left/right padding to each write, default false), and$align
(same as above). For more information, including the full list of acceptable HTML tags, see TCPDF docswriteHTMLCell()
. This function is used to print a rectangular area (beginning with the upper-left corner, which corresponds to the current position), with optional borders, background color, and html text string. IfautoPageBreak
is true, and the cell will go over the limit, it prints onto the new page. There are several parameters which are important:$w
(required float. Cell width. 0 will go to full available width),$h
(required float. Cell minimum height, though cell will extend automatically if needed),$x
(optional upper-left corner X coordinate - if null, it will default to current position),$y
(optional upper-left corner Y coordinate - if null, it will default to current position),$html
(optional html string to print in cell),$border
(optional can either be 0, meaning no border; 1, meaning frame; or string containing any or all the bordersLTRB
; or it can be a more complicated array, see link for more),$ln
(optional specifies where the current position will be after the cell: 0, to the right/left, which is default; 1, beginning of next line; or 2, below cell). For more information or for the other available parameters, see TCPDF docs.
These functions are important in Tally, but may not be used outside of Tally:
Image()
. This is the function used to insert an image, must give either the file name or an '@' character followed by the data string. There are many other parameters, but as this will likely only be used for Tally, we will simplify the discussion by simply pointing you to the TCPDF docswrite1DBarcode()
. This similarly is the function to make a working one-dimensional, linear barcode. There are many parameters, including a required array of style options, so it is easier merely to point to the TCPDF docs, since it likely won't be used outside of Tally.
There are of course, many, many more different things you are able to do with TCPDF, in fact, it seems that if you can think of it, it can be done (to name a few other things, adding linkable elements within the PDF, making bookmarks, adding a table of contents, drawing lines, create a text field or even adding a signature box). The full list of TCPDF functions can be found at this link, it is certainly worth perusing the full list to see the kinds of things you are able to do.
Full Example
While we have attempted to helpfully describe the various aspects of the PDF generation process, perhaps, seeing an example after having it explained to you is still beneficial. This is the PDF generation code in Tally, which creates the Tally Point pages for print. Certainly in future apps, the TCPDF functions used will be different, just as the PDF generated is different, but seeing how it is used in Tally may help you to be able to get an idea of what you are going to do:
public static function generatePdf($dept, $generatedCards, $options = []) {
$pdf = new TCPDF('P', 'mm', 'LETTER');
$options['autoPageBreak'] = false;
$options = (object) $options;
$numberOfCards = count($generatedCards);
PdfUtils::pdfSetup($pdf, $options);
$x = 20;
$y = 10;
$width = 45;
$height = 61;
$i = 1;
$barcodeStyle = [
'position' => '',
'align' => 'C',
'stretch' => false,
'fitwidth' => true,
'cellfitalign' => '',
'hpadding' => 'auto',
'vpadding' => 'auto',
'fgcolor' => [0,0,0],
'bgcolor' => false,
'text' => true,
'font' => isset($options->font['family']) ? $options->font['family'] : 'courier',
'fontsize' => isset($options->font['size']) ? $options->font['size'] : 10,
'stretchtext' => 0
];
foreach ($generatedCards as $card) {
if ($i === 1) {
$pdf->AddPage();
$x = 20;
$y = 10;
}
$img = self::getRandomImage($dept);
$imgType = $img->get('img_type');
$imgSrc = "data:${imgType};base64," . $img->get('image');
$html = '<br><br><br><br><br><br><br><br><br><br><em>1 Point</em>';
$imageBinary = base64_decode($img->get('image'));
$size = getimagesizefromstring($imageBinary);
if ($size[0] >= $size[1]) {
//width is bigger
$heightOffset = (45 - (35 * $size[1] / $size[0])) / 2;
$widthOffset = 5;
} else {
$widthOffset = (45 - (35 * $size[0] / $size[1])) / 2;
$heightOffset = 4;
}
$pdf->Image('@'.$imageBinary, $x + $widthOffset, $y + $heightOffset, 35, 35, null, null, 'N',
true, 300, null, false, false, 0, true);
$pdf->writeHTMLCell($width, $height, $x, $y, $html, '1', '1', false, true, 'C');
$pdf->Line($x + 4, $y + 44, $x + 42, $y + 44);
$pdf->write1DBarcode($card['cardCode'], 'C39', $x, $y + 43, '', 15, .2, $barcodeStyle);
if ($i % 4 !== 0) {
$x += 45;
} else {
$x = 20;
$y += 61;
}
if ($i < 16) {
$i++;
} else {
$i = 1;
}
}
return $pdf;
}
Uploading the Generated TCPDF Object
Now that you have a finished pdf, hosted in a TCPDF object, now you need to upload it to the server so that it can actually be saved. This part of the process is quite simple, you just need to pass the TCPDF $pdf
variable in as the first parameter, and a string which will be the filename as a second parameter to the PdfUtils::savePdf($pdf, $fileName)
function. As an example, this is what Tally did for:
$pdf = CardGenerator::generatePdf(
$dept,
$cardsGenerated,
[
'creator' => $this->user->get('id'),
'author' => 'Tally Point System',
'title' => 'Point Cards'
]
);
PdfUtils::savePdf($pdf, "{$dept}/cards-" . date(self::$pdfDateString) . '.pdf');
Now the PDF file that has been generated should be saved in your pdfDirectory
as the file name that you selected, and now it is able to be retrieved just like any of the other upload methods.