Kombinieren Sie zwei (oder mehr) PDFs


74

Hintergrund: Ich muss meinen Vertriebsmitarbeitern ein wöchentliches Berichtspaket zur Verfügung stellen. Dieses Paket enthält mehrere (5-10) Kristallberichte.

Problem: Ich möchte einem Benutzer erlauben, alle Berichte auszuführen und auch nur einen einzigen Bericht auszuführen. Ich dachte, ich könnte dies tun, indem ich die Berichte erstelle und dann:

List<ReportClass> reports = new List<ReportClass>();
reports.Add(new WeeklyReport1());
reports.Add(new WeeklyReport2());
reports.Add(new WeeklyReport3());
<snip>

foreach (ReportClass report in reports)
{
    report.ExportToDisk(ExportFormatType.PortableDocFormat, @"c:\reports\" + report.ResourceName + ".pdf");
}

Dies würde mir einen Ordner mit den Berichten zur Verfügung stellen, aber ich möchte jedem ein einzelnes PDF mit allen wöchentlichen Berichten per E-Mail senden. Also muss ich sie kombinieren.

Gibt es eine einfache Möglichkeit, dies zu tun, ohne weitere Steuerelemente von Drittanbietern zu installieren? Ich habe bereits DevExpress & CrystalReports und möchte lieber nicht zu viele hinzufügen.

Wäre es am besten, sie in der foreach-Schleife oder in einer separaten Schleife zu kombinieren? (oder ein anderer Weg)


Es sieht so aus, als würde ich eine Bibliothek von Drittanbietern benötigen, danke für all die Hilfe.
Nathan Koop

Antworten:


114

Ich musste ein ähnliches Problem lösen und am Ende habe ich ein kleines PDF-Dienstprogramm erstellt, das das PDFSharp- Projekt verwendet, das im Wesentlichen MIT-lizenziert ist.

Der Code ist denkbar einfach. Ich brauchte ein Cmdline-Dienstprogramm, damit ich mehr Code zum Parsen der Argumente habe als für das Zusammenführen von PDFs:

using (PdfDocument one = PdfReader.Open("file1.pdf", PdfDocumentOpenMode.Import))
using (PdfDocument two = PdfReader.Open("file2.pdf", PdfDocumentOpenMode.Import))
using (PdfDocument outPdf = new PdfDocument())
{                
    CopyPages(one, outPdf);
    CopyPages(two, outPdf);

    outPdf.Save("file1and2.pdf");
}

void CopyPages(PdfDocument from, PdfDocument to)
{
    for (int i = 0; i < from.PageCount; i++)
    {
        to.AddPage(from.Pages[i]);
    }
}

Ah sieht so aus, als hätte Martin mich geschlagen, ich sage, es war, weil ich mein Codebeispiel ausgegraben habe :)
Andrew Burns

Hallo Andrew, würden Sie bitte einen Blick auf diese werfen .... pls stackoverflow.com/questions/6953471/…
user682417

Hat jemand anderes den Fehler "Eine Objektreferenz ist für das nicht statische Feld, die Methode oder die Eigenschaft erforderlich ..." für CopyPages (one, outDocument) erhalten? CopyPages (zwei, outDocument);
user001

2
Wenn Sie PDFSharp von Nuget installieren, stellen Sie sicher, dass Sie die Vorabversion verwenden. Andernfalls tritt möglicherweise der folgende Fehler auf: stackoverflow.com/questions/36788746/…
mkimmet

35

Hier ist eine einzelne Funktion, mit der X PDF-Dateien mit PDFSharp zusammengeführt werden

using PdfSharp;
using PdfSharp.Pdf;
using PdfSharp.Pdf.IO;

public static void MergePDFs(string targetPath, params string[] pdfs) {
    using(PdfDocument targetDoc = new PdfDocument()){
        foreach (string pdf in pdfs) {
            using (PdfDocument pdfDoc = PdfReader.Open(pdf, PdfDocumentOpenMode.Import)) {
                for (int i = 0; i < pdfDoc.PageCount; i++) {
                    targetDoc.AddPage(pdfDoc.Pages[i]);
                }
            }
        }
        targetDoc.Save(targetPath);
    }
}

3
Erfordert die Verwendung von PdfSharp; using PdfSharp.Pdf; using PdfSharp.Pdf.IO;
B. Hawkins

Welche Werte übergeben Sie in string [] pdfs? Ist es der Dateipfad?
KMR

@KMR ja, es ist der Dateipfad.
JustMaier

7

Dies ist etwas, das ich herausgefunden habe und mit Ihnen teilen wollte.

Hier können Sie mehrere PDFs in einem zusammenfügen (in der Reihenfolge der Eingabeliste).

    public static byte[] MergePdf(List<byte[]> pdfs)
    {
        List<PdfSharp.Pdf.PdfDocument> lstDocuments = new List<PdfSharp.Pdf.PdfDocument>();
        foreach (var pdf in pdfs)
        {
            lstDocuments.Add(PdfReader.Open(new MemoryStream(pdf), PdfDocumentOpenMode.Import));
        }

        using (PdfSharp.Pdf.PdfDocument outPdf = new PdfSharp.Pdf.PdfDocument())
        { 
            for(int i = 1; i<= lstDocuments.Count; i++)
            {
                foreach(PdfSharp.Pdf.PdfPage page in lstDocuments[i-1].Pages)
                {
                    outPdf.AddPage(page);
                }
            }

            MemoryStream stream = new MemoryStream();
            outPdf.Save(stream, false);
            byte[] bytes = stream.ToArray();

            return bytes;
        }           
    }

3

Ich habe iTextsharp mit c # verwendet, um PDF-Dateien zu kombinieren. Dies ist der Code, den ich verwendet habe.

string[] lstFiles=new string[3];
    lstFiles[0]=@"C:/pdf/1.pdf";
    lstFiles[1]=@"C:/pdf/2.pdf";
    lstFiles[2]=@"C:/pdf/3.pdf";

    PdfReader reader = null;
    Document sourceDocument = null;
    PdfCopy pdfCopyProvider = null;
    PdfImportedPage importedPage;
    string outputPdfPath=@"C:/pdf/new.pdf";


    sourceDocument = new Document();
    pdfCopyProvider = new PdfCopy(sourceDocument, new System.IO.FileStream(outputPdfPath, System.IO.FileMode.Create));

    //Open the output file
    sourceDocument.Open();

    try
    {
        //Loop through the files list
        for (int f = 0; f < lstFiles.Length-1; f++)
        {
            int pages =get_pageCcount(lstFiles[f]);

            reader = new PdfReader(lstFiles[f]);
            //Add pages of current file
            for (int i = 1; i <= pages; i++)
            {
                importedPage = pdfCopyProvider.GetImportedPage(reader, i);
                pdfCopyProvider.AddPage(importedPage);
            }

            reader.Close();
         }
        //At the end save the output file
        sourceDocument.Close();
    }
    catch (Exception ex)
    {
        throw ex;
    }


private int get_pageCcount(string file)
{
    using (StreamReader sr = new StreamReader(File.OpenRead(file)))
    {
        Regex regex = new Regex(@"/Type\s*/Page[^s]");
        MatchCollection matches = regex.Matches(sr.ReadToEnd());

        return matches.Count;
    }
}

3

PDFsharp scheint das Zusammenführen mehrerer PDF-Dokumente zu einem zu ermöglichen.

Dasselbe ist auch mit ITextSharp möglich .


1

Hier gibt es bereits einige gute Antworten, aber ich dachte, ich könnte erwähnen, dass pdftk für diese Aufgabe nützlich sein könnte. Anstatt ein PDF direkt zu erstellen, können Sie jedes benötigte PDF erstellen und dann als Nachbearbeitung mit pdftk kombinieren. Dies kann sogar innerhalb Ihres Programms mit einem system () - oder ShellExecute () -Aufruf erfolgen.


1

Kombinieren Sie zwei byte[]mit iTextSharp bis Version 5.x:

internal static MemoryStream mergePdfs(byte[] pdf1, byte[] pdf2)
{
    MemoryStream outStream = new MemoryStream();
    using (Document document = new Document())
    using (PdfCopy copy = new PdfCopy(document, outStream))
    {
        document.Open();
        copy.AddDocument(new PdfReader(pdf1));
        copy.AddDocument(new PdfReader(pdf2));
    }
    return outStream;
}

Anstelle der byte[]'s ist es möglich, auch Stream' s zu bestehen


Ich habe die Informationen zu der externen Bibliothek hinzugefügt, die Ihr Code benötigt. Bitte fügen Sie immer alle Informationen hinzu, die erforderlich sind, um Ihre Antworten zu verwenden.
mkl

1

Ich habe die beiden oben kombiniert, weil ich 3 pdfbytes zusammenführen und ein Byte zurückgeben musste

internal static byte[] mergePdfs(byte[] pdf1, byte[] pdf2,byte[] pdf3)
        {
            MemoryStream outStream = new MemoryStream();
            using (Document document = new Document())
            using (PdfCopy copy = new PdfCopy(document, outStream))
            {
                document.Open();
                copy.AddDocument(new PdfReader(pdf1));
                copy.AddDocument(new PdfReader(pdf2));
                copy.AddDocument(new PdfReader(pdf3));
            }
            return outStream.ToArray();
        } 

1

Hier ist ein Beispiel mit iTextSharp

public static void MergePdf(Stream outputPdfStream, IEnumerable<string> pdfFilePaths)
{
    using (var document = new Document())
    using (var pdfCopy = new PdfCopy(document, outputPdfStream))
    {
        pdfCopy.CloseStream = false;
        try
        {
            document.Open();
            foreach (var pdfFilePath in pdfFilePaths)
            {
                using (var pdfReader = new PdfReader(pdfFilePath))
                {
                    pdfCopy.AddDocument(pdfReader);
                    pdfReader.Close();
                }
            }
        }
        finally
        {
            document?.Close();
        }
    }
}

Der PdfReader-Konstruktor weist viele Überladungen auf. Es ist möglich , den Parametertyp ersetzen IEnumerable<string>mit IEnumerable<Stream>und es sollte auch funktionieren. Beachten Sie, dass die Methode den OutputStream nicht schließt, sondern diese Aufgabe an den Stream-Ersteller delegiert.




0

Ich habe das mit PDFBox gemacht. Ich nehme an, es funktioniert ähnlich wie iTextSharp.



0

Ich weiß, dass viele Leute PDF Sharp empfohlen haben, aber es sieht nicht so aus, als ob das Projekt seit Juni 2008 aktualisiert wurde. Außerdem ist die Quelle nicht verfügbar.

Persönlich habe ich mit iTextSharp gespielt, mit dem man ziemlich einfach arbeiten konnte.



0

A bekommt Verfahren folgende Listvon byteArray , das PDF ist byteArray und gibt dann ein byteArray.

using ...;
using PdfSharp.Pdf;
using PdfSharp.Pdf.IO;

public static class PdfHelper
{
    public static byte[] PdfConcat(List<byte[]> lstPdfBytes)
    {
        byte[] res;

        using (var outPdf = new PdfDocument())
        {
            foreach (var pdf in lstPdfBytes)
            {
                using (var pdfStream = new MemoryStream(pdf))
                using (var pdfDoc = PdfReader.Open(pdfStream, PdfDocumentOpenMode.Import))
                    for (var i = 0; i < pdfDoc.PageCount; i++)
                        outPdf.AddPage(pdfDoc.Pages[i]);
            }

            using (var memoryStreamOut = new MemoryStream())
            {
                outPdf.Save(memoryStreamOut, false);

                res = Stream2Bytes(memoryStreamOut);
            }
        }

        return res;
    }

    public static void DownloadAsPdfFile(string fileName, byte[] content)
    {
        var ms = new MemoryStream(content);

        HttpContext.Current.Response.Clear();
        HttpContext.Current.Response.ContentType = "application/pdf";
        HttpContext.Current.Response.AddHeader("content-disposition", $"attachment;filename={fileName}.pdf");
        HttpContext.Current.Response.Buffer = true;
        ms.WriteTo(HttpContext.Current.Response.OutputStream);
        HttpContext.Current.Response.End();
    }

    private static byte[] Stream2Bytes(Stream input)
    {
        var buffer = new byte[input.Length];
        using (var ms = new MemoryStream())
        {
            int read;
            while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
                ms.Write(buffer, 0, read);

            return ms.ToArray();
        }
    }
}

Das Ergebnis der PdfHelper.PdfConcatMethode wird also an die PdfHelper.DownloadAsPdfFileMethode übergeben.

PS: Ein NuGetPaket mit dem Namen [PdfSharp][1]muss installiert werden. Also im Package Manage ConsoleFenstertyp:

Installationspaket PdfSharp


0

Die folgende Methode führt zwei PDFs (f1 und f2) mit iTextSharp zusammen. Das zweite PDF wird nach einem bestimmten Index von f1 angehängt.

 string f1 = "D:\\a.pdf";
 string f2 = "D:\\Iso.pdf";
 string outfile = "D:\\c.pdf";
 appendPagesFromPdf(f1, f2, outfile, 3);




  public static void appendPagesFromPdf(String f1,string f2, String destinationFile, int startingindex)
        {
            PdfReader p1 = new PdfReader(f1);
            PdfReader p2 = new PdfReader(f2);
            int l1 = p1.NumberOfPages, l2 = p2.NumberOfPages;


            //Create our destination file
            using (FileStream fs = new FileStream(destinationFile, FileMode.Create, FileAccess.Write, FileShare.None))
            {
                Document doc = new Document();

                PdfWriter w = PdfWriter.GetInstance(doc, fs);
                doc.Open();
                for (int page = 1; page <= startingindex; page++)
                {
                    doc.NewPage();
                    w.DirectContent.AddTemplate(w.GetImportedPage(p1, page), 0, 0);
                    //Used to pull individual pages from our source

                }//  copied pages from first pdf till startingIndex
                for (int i = 1; i <= l2;i++)
                {
                    doc.NewPage();
                    w.DirectContent.AddTemplate(w.GetImportedPage(p2, i), 0, 0);
                }// merges second pdf after startingIndex
                for (int i = startingindex+1; i <= l1;i++)
                {
                    doc.NewPage();
                    w.DirectContent.AddTemplate(w.GetImportedPage(p1, i), 0, 0);
                }// continuing from where we left in pdf1 

                doc.Close();
                p1.Close();
                p2.Close();

            }
        }

1
Dies ist eine sehr verlustbehaftete Methode (alle Anmerkungen gehen verloren) und es treten Probleme beim Zusammenführen von Seiten mit der Seitenrotation auf. Schauen Sie sich die Antwort von hmadrigal an, um einen besseren Ansatz zu finden.
mkl

Danke, ich werde es überprüfen.
Viraj Singh

0

Um ein ähnliches Problem zu lösen, habe ich iTextSharp wie folgt verwendet:

//Create the document which will contain the combined PDF's
Document document = new Document();

//Create a writer for de document
PdfCopy writer = new PdfCopy(document, new FileStream(OutPutFilePath, FileMode.Create));
if (writer == null)
{
     return;
}

//Open the document
document.Open();

//Get the files you want to combine
string[] filePaths = Directory.GetFiles(DirectoryPathWhereYouHaveYourFiles);
foreach (string filePath in filePaths)
{
     //Read the PDF file
     using (PdfReader reader = new PdfReader(vls_FilePath))
     {
         //Add the file to the combined one
         writer.AddDocument(reader);
     }
}

//Finally close the document and writer
writer.Close();
document.Close();
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.