我的概念是 - 网站上有10个pdf文件。用户可以选择一些pdf文件,然后选择合并以创建包含所选页面的单个pdf文件。我怎么能用PHP做到这一点?
我之前做过这个。我有一个用fpdf生成的pdf,我需要为它添加可变数量的PDF。
所以我已经有了一个fpdf对象和页面设置(http://www.fpdf.org/)我用fpdi来导入文件(http://www.setasign.de/products/pdf-php-solutions/ fpdi /)通过扩展PDF类添加FDPI:
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);
}
这基本上使每个pdf成为一个图像,以放入您的其他PDF格式。它非常适合我需要的东西。
myokyawhtun的解决方案最适合我(使用PHP 5.4)
你仍然会收到错误 - 我使用以下内容解决了:
fpdf_tpl.php的第269行 - 将函数参数更改为:
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) {
我也在fpdf.php的第898行做了同样的改动
我在FPDI上创建了一个抽象层(可能适用于其他引擎)。我将它作为Symfony2捆绑包发布,具体取决于库,以及库本身。
用法:
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;
}
下面是php PDF merge命令。
$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);
我忘记了找到它的链接,但它工作正常。
我建议来自github.com的PDFMerger,很容易就像::
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
在PDF5版本中不推荐使用PDFMerger中使用的代码。我分叉并修复了代码以使用PHP 5.您可以抓住我的github帐户https://github.com/myokyawhtun/PDFMerger
$cmd = "gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=".$new." ".implode(" ", $files);
shell_exec($cmd);
Chauhan答案的简化版本
我的软件中遇到过类似的问题。我们想将几个PDF文件合并为一个PDF文件并将其提交给外部服务。我们一直在使用Christina解决方案中所示的FPDI解决方案。
但是,我们一直使用的输入PDF版本可能高于1.7。我们决定评估FPDI商业插件。但事实证明,我们办公室复印机扫描的一些文件的索引格式错误,导致商业FPDI插件崩溃。所以我们决定使用Ghostscript解决方案,如Chauhan的答案。
但后来我们在输出PDF属性中得到了一些奇怪的元数据。
最后,我们决定加入两个解决方案,以便通过Ghostscript合并和降级PDF,但元数据由FPDI设置。我们还不知道如何使用一些高级格式化的pdf,但对于扫描,我们使用它可以正常工作。这是我们的课程摘录:
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;
}
}
该类的用法如下:
$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);
接受的答案甚至FDPI主页似乎都提供了拙劣或不完整的例子。这是我的工作,易于实施。正如预期的那样,它需要fpdf和fpdi库:
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');
我尝试过类似的问题并且工作正常,试试吧。它可以处理PDF之间的不同方向。
// 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');
}
}
这在Windows上适用于我
$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);