Hợp nhất các tệp PDF với PHP [đã đóng]


83

Khái niệm của tôi là - có 10 tệp pdf trong một trang web. Người dùng có thể chọn một số tệp pdf và sau đó chọn hợp nhất để tạo một tệp pdf duy nhất chứa các trang đã chọn. Làm thế nào tôi có thể làm điều này với php?


Câu hỏi liên quan (trả lời btw): stackoverflow.com/questions/2713701/...
Fran Verona

3
@Webnet thực sự, 64% là ok. Tôi muốn nói 0-25% = thất bại, nhưng tôi đoán rằng, nơi nó được chủ quan
Sean Patrick Floyd

Bạn có thể sử dụng một công cụ dòng lệnh?
Pekka

Bạn có thể sử dụng Zend Framework không? stackoverflow.com/questions/4254218/…
Pekka

Tôi có thể tìm tệp "pdftk-112-1i386.rpm" ở đâu và cách cài đặt tệp đó vào máy chủ?
Imrul.H

Câu trả lời:


28

Tôi đã làm điều này trước đây. Tôi đã có một bản pdf mà tôi đã tạo bằng fpdf và tôi cần thêm một lượng PDF khác nhau vào đó.

Vì vậy, tôi đã thiết lập một đối tượng và trang fpdf (http://www.fpdf.org/) Và tôi đã sử dụng fpdi để nhập các tệp (http://www.setasign.de/products/pdf-php-solutions/ fpdi /) FDPI được thêm vào bằng cách mở rộng lớp 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); 
    }

Về cơ bản, điều này làm cho mỗi pdf thành một hình ảnh để đưa vào pdf khác của bạn. Nó hoạt động tốt một cách đáng kinh ngạc cho những gì tôi cần nó.


Tôi không thể hiểu mã của bạn. bạn có thể vui lòng giải thích một số chi tiết hơn? Tôi cũng không tìm thấy chức năng "setSourceFile" và "importPage" trong hướng dẫn sử dụng fpdf.
Imrul.H

Tôi quay lại và xem xét giải pháp của mình chi tiết hơn một chút. Tôi hy vọng điều này sẽ hữu ích hơn. Tôi đã hoàn toàn quên mất phần fdpi vào sáng nay khi viết bài này, một phần nhỏ của trình tạo PDF khá phức tạp mà tôi đã viết.
Christa

6
@Christa Lưu ý rằng FPDI sẽ chỉ phân tích cú pháp các tệp PDF nhất định. Tôi đang chạy vào một vấn đề mà FPDI sẽ không tập tin PDF phân tích ở trên v 1.4 và FPDI được làm cho tôi mua phân tích cú pháp của họ để xử lý> v1.4 ... Yar ....
n0nag0n

Bạn có nghĩ rằng tốt hơn là làm $ i = 0 và $ i <= $ pagecount. Nó làm cho nó tốt hơn để đọc tôi nghĩ. Great ví dụ btw, thực sự giúp tôi
Nebulosar

123

Dưới đây là lệnh trộn PDF php.

$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);

Tôi quên liên kết từ nơi tôi tìm thấy nó, nhưng nó hoạt động tốt.

Lưu ý: Bạn nên cài đặt gs (trên linux và có thể là Mac) hoặc Ghostscript (trên windows) để tính năng này hoạt động.


4
Nó hoạt động với tôi mà không gặp sự cố và không cần cài đặt các thư viện bên ngoài như FPDI hoặc các thư viện khác.
Memochipan

4
Giải pháp này làm việc tốt nhất cho tôi. Rất dễ dàng để cài đặt Ghostscript trên máy chủ của tôi. Nó chỉ là "yum install ghostcript". Và kịch bản của bạn làm việc một cách hoàn hảo
Theo Kouzelis

1
Tôi đang nhận được một trang pdf trống :(
itsazzad

2
Bạn cần cài đặt Ghostscript, nếu không nó sẽ không hoạt động.
Pascal Klein

2
Bạn nên giải thích những gì nó thực sự làm. Nó thực sự không thực sự là một cách php để thực hiện nhiệm vụ, trong php bạn chỉ chuẩn bị dữ liệu và sau đó bạn thực thi một tập lệnh shell, thực hiện nhiệm vụ thực tế. Ngoài ra, bạn nên bao gồm trong câu trả lời của mình, rằng gs (trên linux và có thể là Mac), hoặc Ghostscript (trên windows) nên được cài đặt để điều này hoạt động .. Tôi vẫn khá thích giải pháp này, vì gs được bao gồm trong Ubuntu theo mặc định , tôi không phải cài đặt nó.
Vulgo Alias

39

tôi đề xuất PDFMerger từ github.com , rất dễ dàng như ::

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

3
Về cơ bản, đây là cách ai đó triển khai câu trả lời của @ Christa (FPDF + FDPI), thật tuyệt :) Cảm ơn!
Nahuel

5
Nó cũng không hoạt động với một số kiểu nén trên một số tệp PDF.
Theo Kouzelis

3
Sử dụng điều này với DOMPDF và nó hoạt động rất hiệu quả, cảm ơn bạn!
Ma-thi-ơ

1
Tôi nhận được "Lỗi FPDF: Không thể tìm thấy bảng xref." bất kỳ giải pháp cho điều đó?
Sameeraa4ever

1
Nó hoạt động nhưng đôi khi hiển thị lỗi bên dưới ... Lỗi FPDF: Tài liệu này (samplepdfs / four.pdf) có thể sử dụng kỹ thuật nén không được hỗ trợ bởi trình phân tích cú pháp miễn phí đi kèm với FPDI.
Nikhil,

11
$cmd = "gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=".$new." ".implode(" ", $files);
shell_exec($cmd);

Một phiên bản đơn giản của câu trả lời của Chauhan


Đây tốt làm việc cho tôi trên centos hostgator dành riêng máy chủ để GhostScript phải đã được cài đặt
Mike Volmar

9

Cả câu trả lời được chấp nhận và thậm chí cả trang chủ FDPI dường như đều đưa ra các ví dụ sai lệch hoặc không đầy đủ. Đây là của tôi hoạt động và dễ thực hiện. Như mong đợi, nó yêu cầu thư viện fpdf và 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');

Xin chào @billynoah Tôi thích điều này nhưng nó không hoạt động theo chiều ngang và dường như chỉ hợp nhất các trang đầu tiên.
Geraldo Isaaks 22/09/2016

2
@GeraldoIsaaks - Sau đó, tôi đã thêm hỗ trợ cho các tài liệu nhiều trang trong ứng dụng của riêng mình. Tôi đã cập nhật câu trả lời. Không chắc chắn về các vấn đề cảnh quan - tôi chưa gặp phải vấn đề đó.
billynoah

Có gì trên kỳ thi này đã có từ những ngày đầu của FPDI?
Jan Slabon

@Setasign - Tôi chưa bao giờ thấy điều đó nhưng cảm ơn vì đã chia sẻ.
billynoah

@billynoah Cảm ơn vì ví dụ mã đơn giản rõ ràng và được cập nhật ở đây trong SO. Tôi đã bắt đầu. Tôi đã kết thúc bằng cách sử dụng nhiều mã hơn từ ví dụ setasign ( setasign.com/products/fpdi/demos/concatenate-fake , liên kết rất dễ bị bỏ sót trong nhận xét ở trên). Logic của họ bên trong lệnh gọi addPage đã làm cho các trang nối cụ thể của tôi trông đẹp hơn. Có lẽ cũng xử lý chân dung / phong cảnh tốt hơn mặc dù tôi đã không kiểm tra điều đó. Nhưng tôi đã không tìm thấy ví dụ với các tìm kiếm và không biết tôi quan tâm cho đến khi tôi thấy câu trả lời của bạn.
Anne Gunn

5

Tôi đã gặp vấn đề tương tự trong phần mềm của mình. Chúng tôi muốn hợp nhất nhiều tệp PDF thành một tệp PDF và gửi nó đến một dịch vụ bên ngoài. Chúng tôi đã sử dụng giải pháp FPDI như trong giải pháp của Christa .

Tuy nhiên, tệp PDF đầu vào mà chúng tôi đang sử dụng có thể ở phiên bản cao hơn 1.7. Chúng tôi đã quyết định đánh giá tiện ích bổ sung thương mại FPDI. Tuy nhiên, hóa ra một số tài liệu được quét bởi máy photocopy văn phòng của chúng tôi có chỉ mục không đúng định dạng, điều này đã làm hỏng tiện ích bổ sung FPDI thương mại. Vì vậy, chúng tôi đã quyết định sử dụng giải pháp Ghostscript như trong câu trả lời của Chauhan .

Nhưng sau đó chúng tôi nhận được một số siêu dữ liệu lạ trong các thuộc tính PDF đầu ra.

Cuối cùng, chúng tôi đã quyết định kết hợp hai giải pháp để hợp nhất và hạ cấp PDF bởi Ghostscript, nhưng siêu dữ liệu được đặt bởi FPDI. Chúng tôi vẫn chưa biết nó sẽ hoạt động như thế nào với một số pdf được định dạng nâng cao, nhưng để quét, chúng tôi sử dụng nó hoạt động tốt. Đây là đoạn trích của lớp chúng tôi:

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;
    }
}

Cách sử dụng của lớp này như sau:

$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);

Chỉ cần đề cập, Đó là tôi đã sử dụng cùng một mã trên Windows env. và đừng quên đặt thư mục chương trình vào "chứ không phải các tham số.$cmd = "\"C:\\Program Files\\gs\\gs9.20\\bin\\gswin64c.exe\" -q -dNOPAUSE -dBATCH -dCompatibilityLevel=1.4 -sDEVICE=pdfwrite -sOutputFile=[....your parameters...]" ;
Frédéric Klee

3

Tôi đã thử vấn đề tương tự và hoạt động tốt, hãy thử nó. Nó có thể xử lý các hướng khác nhau giữa các tệp 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');
        }
    }

Điều này mang lạiUndefined index: w
vui vẻ

chắc chắn rằng bạn có FPDF cấu hình đúng
Kevin Chui

các thông số đối với tôi là $ size ['width'] và $ size ['height'] thay vì $ size ['w'] và $ size ['h']
gorillagoat 15/03/19

0

Tôi đã tạo một lớp trừu tượng trên FPDI (có thể phù hợp với các công cụ khác). Tôi đã xuất bản nó dưới dạng gói Symfony2 tùy thuộc vào thư viện và như chính thư viện.

Thư viện

sử dụng:

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;
}

0

Điều này đã làm việc cho tôi trên Windows

  1. tải xuống PDFtk miễn phí từ https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/
  2. thả thư mục (PDFtk) vào thư mục gốc của c:
  3. thêm phần sau vào mã php của bạn, trong đó $ file1 là vị trí và tên của tệp PDF đầu tiên, $ file2 là vị trí và tên của tệp thứ hai và $ newfile là vị trí và tên của tệp đích

    $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);
    

Có một trình bao bọc PHP giúp điều này trở nên gọn gàng hơn nhiều. Xem github.com/mikehaertl/php-pdftk
Sean the Bean

Lưu ý: PdfTK không hoạt động với RHEL 7 hoặc Cent OS 7
Ray

Đối với tôi, nó chỉ hoạt động như thế này: $command = "cmd /c C:\\pdftk\\bin\\pdftk.exe {$file1} {$file2} cat output {$new}";Lưu ý đầu ra mèo bổ sung . Xem ví dụ pdftk
maxpower9000

-1

Giải pháp của myokyawhtun phù hợp nhất với tôi (sử dụng PHP 5.4)

Mặc dù vậy, bạn vẫn sẽ gặp lỗi - Tôi đã giải quyết bằng cách sử dụng cách sau:

Dòng 269 của fpdf_tpl.php - đã thay đổi các tham số hàm thành:

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) { 

Tôi cũng đã thực hiện thay đổi tương tự trên dòng 898 của fpdf.php

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.