用 PHP 合并 PDF 文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4794435/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Merge PDF files with PHP
提问by Imrul.H
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?
我的概念是 - 网站中有 10 个 pdf 文件。用户可以选择一些 pdf 文件,然后选择合并以创建包含所选页面的单个 pdf 文件。我怎样才能用 php 做到这一点?
采纳答案by Christa
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.
我以前做过这个。我有一个用 fpdf 生成的 pdf,我需要向其中添加可变数量的 PDF。
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:
所以我已经有一个 fpdf 对象和页面设置 (http://www.fpdf.org/) 我用 fpdi 导入文件 (http://www.setasign.de/products/pdf-php-solutions/ fpdi/) FDPI 是通过扩展 PDF 类添加的:
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.
这基本上使每个pdf变成一个图像以放入您的另一个pdf。它非常适合我需要它的用途。
回答by Sanjeev Chauhan
Below is the php PDF merge command.
下面是 php PDF 合并命令。
$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.
注意:您应该安装 gs(在 Linux 上,可能在 Mac 上)或 Ghostscript(在 Windows 上)才能正常工作。
回答by AgelessEssence
i suggest PDFMergerfrom github.com, so easy like ::
我建议PDFMerger从github.com,所以容易像::
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
回答by Svetoslav Genov
$cmd = "gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=".$new." ".implode(" ", $files);
shell_exec($cmd);
A simplified version of Chauhan's answer
Chauhan 答案的简化版
回答by billynoah
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:
接受的答案甚至 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');
回答by Artur Karczmarczyk
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.
我的软件也有类似的问题。我们希望将多个 PDF 文件合并为一个 PDF 文件并将其提交给外部服务。我们一直在使用 FPDI 解决方案,如Christa的解决方案所示。
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 Ghostscriptsolution as in Chauhan's answer.
但是,我们一直使用的输入 PDF 版本可能高于 1.7。我们决定评估 FPDI 商业附加组件。然而,事实证明,我们办公室复印机扫描的一些文档的索引格式不正确,这导致商业 FPDI 插件崩溃。所以我们决定像Chauhan的回答一样使用Ghostscript解决方案。
But then we got some strange metadata in the output PDF properties.
但是随后我们在输出 PDF 属性中得到了一些奇怪的元数据。
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:
最后我们决定加入两个解决方案,让 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;
}
}
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);
回答by Kevin Chui
I have tried similar issue and works fine, try it. It can handle different orientations between PDFs.
我已经尝试过类似的问题并且工作正常,试试吧。它可以处理 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');
}
}
回答by juanmf
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.
我在 FPDI 上创建了一个抽象层(可能适用于其他引擎)。我根据库将它发布为 Symfony2 包,并作为库本身发布。
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;
}
回答by Stewart Kirkpatrick
This worked for me on Windows
这在 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);
- 从https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/免费下载 PDFtk
- 将文件夹 (PDFtk) 放到 c 的根目录中:
将以下内容添加到您的 php 代码中,其中 $file1 是第一个 PDF 文件的位置和名称,$file2 是第二个 PDF 文件的位置和名称,$newfile 是目标文件的位置和名称
$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);
回答by Scott
myokyawhtun's solution worked best for me (using PHP 5.4)
myokyawhtun 的解决方案最适合我(使用 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:
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) {
I also made this same change on line 898 of fpdf.php
我也在 fpdf.php 的第 898 行做了同样的更改