I am creating a pdf document using tcpdf which is going well. The issue I am having is that I want to include an external pdf in the middle of the document and then continue to add my own pages afterwards.
I have read that FPDI is the best way to achieve this but I am stuck with trying to implement a solution. All of the examples I have found seem to revolve around using an external pdf as a background or template to the entire document, not just as an insert into a document.
Any help would be gratefully received.
AddPage() Method generates a blank page. Each call generates only 1 page. You need to call AddPage() before useTemplate(); After that you can still add new context.
$pdf = new FPDI();
$pdf->AddPage();
$pdf->AddFont('courier');
$pdf->Write(10, 'page 1 created by TCPDF');
$pages = $pdf->setSourceFile('middle.pdf');
for($i=0; $i<$pages; $i++)
{
$pdf->AddPage();
$tplIdx = $pdf->importPage($i+1);
$pdf->useTemplate($tplIdx, 10, 10, 200);
}
$pdf->AddPage();
$pdf->Write(10, 'page 2 created by TCPDF');
Related
I've been struggling with this for a while and feel helpless.
Prestashop uses tcpdf to generate invoices and delivery slips from HTML templates filled using Smarty. We are working on updating the invoice design and found tcpdf to be lacking in CSS support. After some research we settled for wkhtmltopdf as the right tool from converting the HTML/CSS templates to PDF.
The problem
The store has a feature for exporting multiple invoices into a single PDF. Using TCPDF I was able to make the batch file ready for double sided printing by inserting a blank page after each invoice that had odd number of pages before the file was generated. But now that we switched to wkhtmltopdf I cannot achieve the same result.
The crucial problem is that while wkhtmltopdf allows for the usage of multiple HTML templates there seems to be no reliable way to determine the number of pages they are each going to have before the file is generated. The header and footer templates can receive the page count that the invoice ends up being but they are separate from the main content and therefore I cannot insert a page break accordingly.
I've also tried to calculate the height of the content / PDF page height but there were various issues with that once I started exporting multiple templates (worked alright with a single template). This approach isn't great either because inserting a blank page into the content itself causes the footer to appear on the new page as well which is not what I want.
My best attempt
The only way I've figured out that could get me around these issues is very inefficient. Each time a template is added to the batch I could pre-generate it using a separate instance of a wrapper for wkhtmltopdf, get the temporary file name, determine how many pages it has using pdfinfo and add a blank HTML template to the main instance accordingly. Here's a draft of a function to get the number of pages of the last template added (from a class that extends the wrapper, based on some other pdfinfo questions I found on SO):
/**
* Return the number of pages in the last invoice template added
* $complete === true => return the length of the entire document
*/
public function getNumPages($complete = false)
{
if (!$complete) {
// Generate PDF of last template added
$tmpPdf = new WKPdf($this->_options);
$tmpPdf->addPage($this->content, Array(
'footer-html' => $this->footer
));
/**
The createPdf method is protected so I need to get
the content as string here to force the wrapper to
call wkhtmltopdf.
*/
$tmpPdf->toString();
$document = $tmpPdf->getPdfFilename();
} else {
// Generate entire batch
$this->createPdf();
$document = $this->getPdfFilename();
}
// Use pdfinfo to get the PDF page count
$cmd = 'pdfinfo';
exec("$cmd \"$document\"", $output);
$pagecount = 0;
foreach($output as $op)
{
// Extract the number
if(preg_match("/Pages:\s*(\d+)/i", $op, $matches) === 1)
{
$pagecount = intval($matches[1]);
break;
}
}
return $pagecount;
}
This is very inefficient - it takes about 80 seconds to generate a batch of 25 invoices because I have to call wkhtmltopdf 25 times to create the temporary PDF files so that I can call pdfinfo 25 times to get their individual lengths and insert blank pages where necessary and then generate the final document.
The advantage of TCPDF is that it can give you the number of pages on the fly and a similar functionality takes about 5 seconds to generate a batch file of 25 invoices.
Anyone has any ideas on how to speed things up? Or a better idea to do this altogether. I've considered various tools for the generation including dompdf but wkhtmltopdf is simply the most powerful. The batch generation is really only used from the back office by the store admins so maybe they could be patient. But still.
Unfortunately wkhtmltopdf is the library, which is written in C language and we can not dynamically add one page on the fly like in PHP libraries.
Citate from your comment: Due to number of items ordered or ammount of customer data each invoice can be anywhere from 1 to 3 pages long.
And because of this we can not precalculate the number of pages and write it to a database.
I think you have only one possibility / solution: you have to write behind each invoice a blank page and after the whole PDF was generated you have to edit it with free PHP library like FPDI. In combination with FPDI it is even possible to edit PDF documents.
By PDF editing you could delete all blank pages which you do not need if they starts with odd page number (like 3, 5, etc.). And in FPDI you have the possibility to detect a page number. It is much faster than the solution which you use now.
And the blank(or empty) pages you could detect on content length with FPFI like follows:
<?php
require('fpdf.php');
require_once('setasign/Fpdi/autoload.php');
class Pdf extends \setasign\Fpdi\Fpdi
{
private $pdfReader;
function Header()
{
if(is_null($this->pdfReader))
{
$readerId = $this->getPdfReaderId('blank-pages.pdf');
$this->pdfReader = $this->getPdfReader($readerId);
}
$page_fpdi = $this->pdfReader->getPage($this->PageNo());
$this->content = $page_fpdi->getContentStream();
$this->Cell(0, 15, 'page content length: '.strlen($this->content));
}
protected function _putimages(){}
}
$pdf = new Pdf();
$pdf->SetFont('Arial', '', 12);
$pdf->AddPage(); //page content length: 70 // page with 'Hello World!' string
$pdf->AddPage(); //page content length: 30 // empty page
$pdf->AddPage(); //page content length: 30 // empty page
$pdf->Output();
?>
My blank-pages.pdf I have generated using FPDF with following code:
<?php
require('fpdf.php');
$pdf = new FPDF();
$pdf->AddPage();
$pdf->SetFont('Arial','B',16);
$pdf->Cell(40,10,'Hello World!');
$pdf->AddPage();
$pdf->AddPage();
$pdf->Output();
?>
I'm able to generate a PDF with PHP using FPDF, but I'm trying to create an on-screen preview of the generated PDF rather than jumping straight to the online PDF viewer.
<?php
use setasign\Fpdi\Fpdi;
use setasign\Fpdi\PdfReader;
require_once('fpdf/fpdf.php');
require_once('fpdi2/src/autoload.php');
$pdf = new Fpdi();
$pageCount = $pdf->setSourceFile('pdf1.pdf');
for ($pageNo = 1; $pageNo <= $pageCount; $pageNo++)
{
$tplIdx = $pdf->importPage($pageNo);
// add a page
$pdf->AddPage();
$pdf->useTemplate($tplIdx, 0, 30);
$src = $target_file;
$pdf->Image($src,170,0, 30, 30);
}
$pdf->Output();
?>
The below code is what I've got at the moment, but i'm stuck on trying to generate it on the same page.
$pdf->Output();
The above segment seems to generate the PDF automatically onto a new page (opens online PDF viewer). I've searched through documentation and forums but can't seem to find anything.
Any help would be greatly appreciated. Thanks!
FPDF creates a PDF file. A PDF file needs a viewer or reader application, which renders the content of the PDF document. You cannot just output it e.g. between some HTML fragments on a website.
So your question is not related to FPDF or FPDI at all but you're asking for a PDF viewer/render which you can use on your website.
The most popular solution for such task would be pdf.js.
For other possible canditates you may try "html5 pdf viewer" on google.
I'm stuck at work.
I'm coding in PHP and I have to generate a PDF. My problem is that I have to create cards (same size of credit card 85.6*54mm), I'm using a template at the right size, but the page is still generated with A4 format. I can see my template on that page at the top left corner but the A4 page is filling the rest of my screen.
Here is my code.
$pdf = new FPDI();
$pdf->setSourceFile('inc/om.pdf');
$tplIdx = $pdf->importPage(2);
$pdf->AddPage('L', array(85.6,54));
$pdf->useTemplate($tplIdx);
Does someone have a idea ?
I slightly modified the code that miken32 sent me, now it's working pretty well !
Thank you mate, that was the right way to do it.
$pdf = new FPDI('L','mm', array(54,85.6));
$pdf->setSourceFile('inc/om.pdf');
$tplIdx = $pdf->importPage(2);
$pdf->AddPage();
$pdf->useTemplate($tplIdx);
I have a doubt about using TCPDF and FPDI together.
I am working on a project where I need to modify existing PDF file and generate new PDF, actually existing PDF are Greeting card template and I have to print certain data at certain pages (such as Image on first page, message on 3rd page, artwork on 4th page) to generate final PDF.
I googled and found with TCPDF, it is not possible to manipulate existing PDF, they suggested using FPDI for opening and manipulating existing PDF.
That's where i am stuck. I need TCPDF (it methods to print images, transparent images, utf text, embed font etc) to do what I want to do, but, I need FPDI to start with. :(.
Please help me: is it possible to use both FPDI and TCPDF together? so that I can use features offered by both APIs ?
Thanks in advance...
http://www.setasign.de/products/pdf-php-solutions/fpdi/about/
"As of version 1.2.1 FPDI can be used with TCPDF - a derivate of FPDF."
libraries_load('tcpdf');
libraries_load('fpdi');
$pdf = new FPDI();
$pdf->setSourceFile("%local_file_path%");
$tplIdx = $pdf->importPage(1);
$pdf->AddPage('L', array(3.5, 2), FALSE);
$pdf->useTemplate($tplIdx, 0, 0, 3.5, 2, false);
I was using Drupal at the time so I used libraries_load but require_once should work.
Background info:
I got a project to produce a customised PDF on the fly from a given PDF file using PHP. All I need it to do is to replace strings, e.g. search in "template.pdf" for "{Address}", replace with "Street Name".
I've seen links to fpdf/pdfi/dompdf etc., but can't find any useful example code that I could use :s.
Any help / pointers would be greatly appreciated.
fpdf is fantastic, you need to use somthing else to import an exisitng PDF though, See below.
http://www.setasign.de/products/pdf-php-solutions/fpdi/
require_once('fpdf.php');
require_once('fpdi.php');
$pdf =& new FPDI();
$pagecount = $pdf->setSourceFile('TestDoc.pdf');
$tplidx = $pdf->importPage(1, '/MediaBox');
$pdf->addPage();
$pdf->useTemplate($tplidx, 10, 10, 90);
$pdf->Output('newpdf.pdf', 'D');
decided to generate html web page (PHP) then use wkhtmltopdf
(http://code.google.com/p/wkhtmltopdf)
to produce the pdf bit of a work around but less hastle
PDFlib (with the additional PDI) from pdflib.com should be able to do this for you. Admittedly it is pretty pricey, so there may be other options, too :)