Merging PDFs with Codeigniter - php

I've written the following code for merging PDFs using this answer
function merge_pdfs() {
$pdfs_array = array('1.pdf', '2.pdf');
$pdf = new FPDI_Protection();
for ($i = 0; $i < count($pdfs_array); $i++ ) {
$pagecount = $pdf->setSourceFile($pdfs_array[$i]);
for($j = 0; $j < $pagecount ; $j++) {
$tplidx = $pdf->importPage(($j +1), '/MediaBox');
$pdf->addPage('P','A4');
$pdf->useTemplate($tplidx, 0, 0, 0, 0, TRUE);
}
}
$dt = new DateTime(NULL, new DateTimeZone($data->user->timezone));
$pdf->SetTitle('PDF, created: '.$dt->format(MYHMRS_DATETIME_FRIENDLY));
$pdf->SetSubject('PDF subject !');
$output = $pdf->Output('', 'S');
$name = "PDF".'-'.$dt->format('ymd').'.pdf';
$this->output
->set_header("Content-Disposition: filename=$name;")
->set_content_type('Application/pdf')
->set_output($output);
}
So, after this I'm getting the following error message
This document (1.pdf) probably uses a compression technique which is not supported by the free parser shipped with FPDI. (See https://www.setasign.com/fpdi-pdf-parser for more details)
I've checked the link and it suggests to set another PDF Parser ( If I understand right )
But I'm not sure how to make it working with Codeigniter and my example
Should I create library and try to use it?
Or maybe you know another solution for merging PDFs

The issue was related to PDF versions
Edit
If you don't know, the PDFs has versions. Yeah, I was surprised as well. Please check them here PDF versions
So, the problem was that I was trying to merge PDF 1.5 version with PDF 1.6

An example. It is simple.
<?php
require_once __DIR__ . '/vendor/autoload.php';
$mpdf = new \Mpdf\Mpdf();
$mpdf->WriteHTML('<h1>Hello world!</h1>');
$mpdf->AddPage('P');
$mpdf->WriteHTML('<h1>More</h1>');
$mpdf->Output();
?>

Related

FPDM Only first file output works

Acoording this thread I have a similar problem:
Only first pdf file filled with fpdm can be opened
With FPDM (https://github.com/codeshell/fpdm) even with the latest fix (https://gist.github.com/josh-candybox/173cacc476631720a05879327950da4e) I just can't get multiple pdf files processing. One file only. It is not header related, since the files are being thrown out as files (not as downloads).
See me code. One suggested to do the loop with an ajax call. If this is really the only way, how can I do that? I even try to reset the object/class. It just doesn't care...
Error msg: FPDF-Merge Error: getFilter cannot open stream of object
because filter '' is not supported, sorry.
$j=1;
foreach ($id as $value => $key) {
if ($value == 'adresse') {
echo $value." -> ".nl2br($key)."<br>\n";
$fields = array(
'adresse1' => $key
);
$pdf = NULL;
$pdf = new FPDM(__DIR__.'/fpdm/dmc3fixed.pdf' );
$pdf->Load($fields, true);
$pdf->Merge();
$filename=__DIR__."/fpdm/dmc".$j.".pdf";
$pdf->Output($filename,'F');
$pdf->closeFile();
unset($pdf);
$pdf = NULL;
$j++;
} else { ... }
P.S.: Kind of workaround, but doesn't answer my question:
So, if anyone of you has the same problem, actually I managed to accomplish generating multiple PDFs with dynamic text. In my case I wanted to put addresses to letter templates. So I made a PDF Form with a multi cell. I ended up just printing the address with FPDF and FPDI, so... here you go:
require_once __DIR__ . DIRECTORY_SEPARATOR .'fpdi'.DIRECTORY_SEPARATOR.'autoload.php';
require_once(__DIR__ . DIRECTORY_SEPARATOR .'fpdf'.DIRECTORY_SEPARATOR.'fpdf.php');
require_once(__DIR__ . DIRECTORY_SEPARATOR .'fpdi'.DIRECTORY_SEPARATOR.'fpdi.php');
use setasign\Fpdi\Fpdi;
$pdf = null;
$i = 1;
foreach ($result as $value => $key) {
$pdf = new FPDI();
$pagecount = $pdf->setSourceFile(__DIR__ . DIRECTORY_SEPARATOR.'template.pdf');
for ($n = 1; $n <= $pagecount; $n++) {
$pdf->AddPage();
$tplIdx = $pdf->importPage($n);
$pdf->useTemplate($tplIdx);
$pdf->SetFont('Arial', '', 11);
$pdf->SetXY(25, 60);
$pdf->MultiCell(80, 5, $address);
$pdf->Output(__DIR__ . DIRECTORY_SEPARATOR."output".$i.".PDF", "F");
$pdf = NULL;
$i++;
}
}

Convert PDF to PNG without transparent background

I use the following code to convert PDF to PNG. As you can see, I use code setImageAlphaChannel(Imagick::ALPHACHANNEL_REMOVE ) to remove the background transparency. But in practice it only works for the last page. Do you think there is a problem with the code? Do you have a better solution with a higher speed?
$PDF = 'test.pdf';
$img = new imagick();
$img->readImage($PDF.'[0-9]'); //Convert 10 pages
$img->setImageAlphaChannel(Imagick::ALPHACHANNEL_REMOVE );
$pages = count($img);
$img->writeImages('./images/'.'pdf.png', true);
This looks like an iterator issue. You can try looping with something like this:
<?php
$PDF = 'test.pdf';
$img = new Imagick();
$img->readImage($PDF. '[0-9]'); //Convert 10 pages
$lastIndex = $img->getIteratorIndex();
$img->resetIterator();
for($i = $img->getIteratorIndex(); $i <= $lastIndex; $i++) {
$img->setIteratorIndex($i);
$img->setImageAlphaChannel(Imagick::ALPHACHANNEL_REMOVE);
}
$pages = count($img); // not sure why you need this
$img->writeImages('./images/'.'pdf.png', true);
You could also get the iterating part down to a simple loop, if you like it more, since the Imagick class implements Iterator:
foreach($img as $i)
{
$img->setImageAlphaChannel(Imagick::ALPHACHANNEL_REMOVE);
}

How To Merge 2 PDF in MPDF Using PHP Laravel

I want to Merge 2 pdf stored in my storage folder of Laravel app. i only want to merge using MPDF.
i've a function create pdf. From that Function I created a pdf
Here is the Function to create a PDF.
public function generateProjectPDF(){
$projects = Projects::all();
$file_name = 'Project_Task'.rand(1,1000).'.pdf';
$mpdf = new \Mpdf\Mpdf();
$mpdf->WriteHTML(view('pdf.projectpdf',['projects'=>$projects]));
$mpdf->Output('storage/app/files/'.$file_name,'F');
DB::table('merge_pdf')->insert(
[
'name' => $file_name,
]
);
}
Now I have a function to merge 2 pdf.
Now i don't know how to merge the two pdfs.
public function mergePDF(){
$content1 = Storage::get('files/filename.pdf');
$content1 = Storage::get('files/filename.pdf');
}
Change your mergePDF function accordingly.
public function mergePDF(){
$mpdf = new \Mpdf\Mpdf();
$mpdf->SetImportUse(); //only with mPDF <8.0
$pagecount1 = $mpdf->SetSourceFile('file1.pdf');
$tplId1 = $mpdf->importPage($pagecount1);
$mpdf->useTemplate($tplId1);
$pagecount2 = $mpdf->SetSourceFile('file2.pdf');
$tplId2 = $mpdf->importPage($pagecount2);
$mpdf->useTemplate($tplId2);
$mpdf->Output();
}
For more details , please refer https://mpdf.github.io/reference/mpdf-functions/importpage-v8.html
merge multiple pdf using Mpdf library
merge pdf function
function mergePdf($pdfArr){
$pdf = new Mpdf();
foreach($pdfArr as $currentPdf){
$pagecount = $pdf->SetSourceFile($currentPdf);
for($i = 1; $i <= $pagecount; $i++){
$pdf->AddPage();
$tplId = $pdf->importPage($i);
$pdf->useTemplate($tplId);
}
}
//direct show on browser
$pdf->Output();
//spacefic location save file
$outputpath = 'location/output.pdf';
$pdf->Output($outputpath, 'F');
}
Call this function
mergePdf(['path/pdf1.pdf','path/pdf2.pdf', .....])

Error in mPDF Xref?

I am using the mpdf extension in my yii2 site in which the pdf are created.The pdf files are uploaded as an attachment first & then merged using the mpdf, this is working fine for the pdf files of version less than or equals to 1.4 & if i use a pdf file greater than this it gives me the error.I found the posts regarding this too but there is no actual answer its just asked to use the FPDI which also causes this error & i cannot chang my library to any other my whole work is dependent on this mpdf library.The users cannot save there file firstly in lower version & then upload it so please suggest me something i can do with it.
//merge multiple PDF files
$pdf=new mPDF('', 'Letter', 0, '', 8.5, 11);
$pdf->SetImportUse();
if($body !="")
{
$pdf->WriteHTML($body);
$pdf->WriteHTML('<pagebreak />');
}
$body1='<style>#page {margin: 96px;border:1px solid red;}</style>';
$fileArcount = count($multifileArr);
$z=1;
foreach($multifileArr as $fileAr)
{
if($fileAr !="")
{
$dashboard_pdf_file="../web/uploads/".$fileAr;
}
$pagecount = $pdf->SetSourceFile($dashboard_pdf_file);
for ($i=1; $i<=$pagecount; $i++) {
$import_page = $pdf->ImportPage($i);
$pdf->UseTemplate($import_page);
if ($i < $pagecount)
{
//$pdf->AddPage();
$pdf->AddPage('L',80,80,80);
}
}
if($z < $fileArcount){
$pdf->WriteHTML('<pagebreak />');
}
$z++;
}

Merge PDF files with PHP [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
My concept is - there are 10 pdf files in a website. User can select some pdf files and then select merge to create a single pdf file which contains the selected pages. How can i do this with php?
Below is the php PDF merge command.
$fileArray= array("name1.pdf","name2.pdf","name3.pdf","name4.pdf");
$datadir = "save_path/";
$outputName = $datadir."merged.pdf";
$cmd = "gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=$outputName ";
//Add each pdf file to the end of the command
foreach($fileArray as $file) {
$cmd .= $file." ";
}
$result = shell_exec($cmd);
I forgot the link from where I found it, but it works fine.
Note: You should have gs (on linux and probably Mac), or Ghostscript (on windows) installed for this to work.
i suggest PDFMerger from github.com, so easy like ::
include 'PDFMerger.php';
$pdf = new PDFMerger;
$pdf->addPDF('samplepdfs/one.pdf', '1, 3, 4')
->addPDF('samplepdfs/two.pdf', '1-2')
->addPDF('samplepdfs/three.pdf', 'all')
->merge('file', 'samplepdfs/TEST2.pdf'); // REPLACE 'file' WITH 'browser', 'download', 'string', or 'file' for output options
I've done this before. I had a pdf that I generated with fpdf, and I needed to add on a variable amount of PDFs to it.
So I already had an fpdf object and page set up (http://www.fpdf.org/)
And I used fpdi to import the files (http://www.setasign.de/products/pdf-php-solutions/fpdi/)
FDPI is added by extending the PDF class:
class PDF extends FPDI
{
}
$pdffile = "Filename.pdf";
$pagecount = $pdf->setSourceFile($pdffile);
for($i=0; $i<$pagecount; $i++){
$pdf->AddPage();
$tplidx = $pdf->importPage($i+1, '/MediaBox');
$pdf->useTemplate($tplidx, 10, 10, 200);
}
This basically makes each pdf into an image to put into your other pdf. It worked amazingly well for what I needed it for.
$cmd = "gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=".$new." ".implode(" ", $files);
shell_exec($cmd);
A simplified version of Chauhan's answer
Both the accepted answer and even the FDPI homepage seem to give botched or incomplete examples. Here's mine which works and is easy to implement. As expected it requires fpdf and fpdi libraries:
FPDF: http://www.fpdf.org/en/download.php
FPDI: https://www.setasign.com/products/fpdi/downloads
require('fpdf.php');
require('fpdi.php');
$files = ['doc1.pdf', 'doc2.pdf', 'doc3.pdf'];
$pdf = new FPDI();
// iterate over array of files and merge
foreach ($files as $file) {
$pageCount = $pdf->setSourceFile($file);
for ($i = 0; $i < $pageCount; $i++) {
$tpl = $pdf->importPage($i + 1, '/MediaBox');
$pdf->addPage();
$pdf->useTemplate($tpl);
}
}
// output the pdf as a file (http://www.fpdf.org/en/doc/output.htm)
$pdf->Output('F','merged.pdf');
I've had similar problem in my software. We've wanted to merge several PDF files into one PDF file and submit it to an outer service. We've been using the FPDI solution as shown in Christa's solution.
However, the input PDF's we've been using could be in version higher than 1.7. We've decided to evaluate the FPDI commercial add-on. However, it turned out that some of the documents scanned by our office copier were having malformed indexes, which crashed the commercial FPDI add-on. So we've decided to use Ghostscript solution as in Chauhan's answer.
But then we got some strange metadata in the output PDF properties.
Finally we've decided to join two solutions to get PDF's merged and downgraded by Ghostscript, but the metadata is set by FPDI. We don't know yet how it would work with some advanced formatted pdfs, but for scans we use it works just fine. Here's our class excerpt:
class MergedPDF extends \FPDI
{
private $documentsPaths = array();
public function Render()
{
$outputFileName = tempnam(sys_get_temp_dir(), 'merged');
// merge files and save resulting file as PDF version 1.4 for FPDI compatibility
$cmd = "/usr/bin/gs -q -dNOPAUSE -dBATCH -dCompatibilityLevel=1.4 -sDEVICE=pdfwrite -sOutputFile=$outputFileName";
foreach ($this->getDocumentsPaths() as $pdfpath) {
$cmd .= " $pdfpath ";
}
$result = shell_exec($cmd);
$this->SetCreator('Your Software Name');
$this->setPrintHeader(false);
$numPages = $this->setSourceFile($outputFileName);
for ($i = 1; $i <= $numPages; $i++) {
$tplIdx = $this->importPage($i);
$this->AddPage();
$this->useTemplate($tplIdx);
}
unlink($outputFileName);
$content = $this->Output(null, 'S');
return $content;
}
public function getDocumentsPaths()
{
return $this->documentsPaths;
}
public function setDocumentsPaths($documentsPaths)
{
$this->documentsPaths = $documentsPaths;
}
public function addDocumentPath($documentPath)
{
$this->documentsPaths[] = $documentPath;
}
}
The usage of this class is as follows:
$pdf = new MergedPDF();
$pdf->setTitle($pdfTitle);
$pdf->addDocumentPath($absolutePath1);
$pdf->addDocumentPath($absolutePath2);
$pdf->addDocumentPath($absolutePath3);
$tempFileName = tempnam(sys_get_temp_dir(), 'merged');
$content = $pdf->Render();
file_put_contents($tempFileName, $content);
I have tried similar issue and works fine, try it. It can handle different orientations between PDFs.
// array to hold list of PDF files to be merged
$files = array("a.pdf", "b.pdf", "c.pdf");
$pageCount = 0;
// initiate FPDI
$pdf = new FPDI();
// iterate through the files
foreach ($files AS $file) {
// get the page count
$pageCount = $pdf->setSourceFile($file);
// iterate through all pages
for ($pageNo = 1; $pageNo <= $pageCount; $pageNo++) {
// import a page
$templateId = $pdf->importPage($pageNo);
// get the size of the imported page
$size = $pdf->getTemplateSize($templateId);
// create a page (landscape or portrait depending on the imported page size)
if ($size['w'] > $size['h']) {
$pdf->AddPage('L', array($size['w'], $size['h']));
} else {
$pdf->AddPage('P', array($size['w'], $size['h']));
}
// use the imported page
$pdf->useTemplate($templateId);
$pdf->SetFont('Helvetica');
$pdf->SetXY(5, 5);
$pdf->Write(8, 'Generated by FPDI');
}
}
This worked for me on Windows
download PDFtk free from https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/
drop folder (PDFtk) into the root of c:
add the following to your php code where $file1 is the location and name of the first PDF file, $file2 is the location and name of the second and $newfile is the location and name of the destination file
$file1 = ' c:\\\www\\\folder1\\\folder2\\\file1.pdf';
$file2 = ' c:\\\www\\\folder1\\\folder2\\\file2.pdf';
$file3 = ' c:\\\www\\\folder1\\\folder2\\\file3.pdf';
$command = 'cmd /c C:\\\pdftk\\\bin\\\pdftk.exe '.$file1.$file2.$newfile;
$result = exec($command);
I created an abstraction layer over FPDI (might accommodate other engines).
I published it as a Symfony2 bundle depending on a library, and as the library itself.
The bundle
The Library
usage:
public function handlePdfChanges(Document $document, array $formRawData)
{
$oldPath = $document->getUploadRootDir($this->kernel) . $document->getOldPath();
$newTmpPath = $document->getFile()->getRealPath();
switch ($formRawData['insertOptions']['insertPosition']) {
case PdfInsertType::POSITION_BEGINNING:
// prepend
$newPdf = $this->pdfManager->insert($oldPath, $newTmpPath);
break;
case PdfInsertType::POSITION_END:
// Append
$newPdf = $this->pdfManager->append($oldPath, $newTmpPath);
break;
case PdfInsertType::POSITION_PAGE:
// insert at page n: PdfA={p1; p2; p3}, PdfB={pA; pB; pC}
// insert(PdfA, PdfB, 2) will render {p1; pA; pB; pC; p2; p3}
$newPdf = $this->pdfManager->insert(
$oldPath, $newTmpPath, $formRawData['insertOptions']['pageNumber']
);
break;
case PdfInsertType::POSITION_REPLACE:
// does nothing. overrides old file.
return;
break;
}
$pageCount = $newPdf->getPageCount();
$newPdf->renderFile($mergedPdfPath = "$newTmpPath.merged");
$document->setFile(new File($mergedPdfPath, true));
return $pageCount;
}
myokyawhtun's solution worked best for me (using PHP 5.4)
You will still get an error though - I resolved using the following:
Line 269 of fpdf_tpl.php - changed the function parameters to:
function Image($file, $x=null, $y=null, $w=0, $h=0, $type='', $link='',$align='', $resize=false, $dpi=300, $palign='', $ismask=false, $imgmask=false, $border=0) {
I also made this same change on line 898 of fpdf.php

Categories