web-dev-qa-db-fra.com

Combinez deux (ou plus) PDF

Contexte: Je dois fournir un package de rapport hebdomadaire pour mon personnel de vente. Ce paquet contient plusieurs (5-10) rapports de cristal.

Problème: Je voudrais autoriser un utilisateur à exécuter tous les rapports et également à exécuter un seul rapport. Je pensais que je pouvais le faire en créant les rapports puis en faisant:

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

Cela me fournirait un dossier complet des rapports, mais je voudrais envoyer à chacun un seul PDF PDF avec tous les rapports hebdomadaires. Je dois donc les combiner.

Existe-t-il un moyen simple de le faire sans installer d'autres contrôles tiers? J'ai déjà DevExpress & CrystalReports et je préfère ne pas en ajouter trop.

Serait-il préférable de les combiner dans la boucle foreach ou dans une boucle séparée? (ou d'une autre manière)

51
Nathan Koop

J'ai dû résoudre un problème similaire et j'ai fini par créer un petit utilitaire pdfmerge qui utilise le projet PDFSharp qui est essentiellement MIT sous licence.

Le code est simple, j'avais besoin d'un utilitaire cmdline donc j'ai plus de code dédié à l'analyse des arguments que je n'en ai pour la fusion PDF:

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]);
    }
}
82
Andrew Burns

Voici une seule fonction qui fusionnera X quantité de PDF à l'aide de PDFSharp

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);
    }
}
27
JustMaier

C'est quelque chose que j'ai compris et que je voulais partager avec vous.

Ici, vous pouvez joindre plusieurs Pdfs en un (en suivant l'ordre de la liste d'entrée)

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

PDFsharp semble permettre la fusion de plusieurs documents PDF en un seul).

Et la même chose est également possible avec ITextSharp .

4
M4N

J'ai utilisé iTextsharp avec c # pour combiner des fichiers pdf. C'est le code que j'ai utilisé.

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

Il y a déjà de bonnes réponses ici, mais j'ai pensé que je pourrais mentionner que pdftk pourrait être utile pour cette tâche. Au lieu d'en produire un PDF directement, vous pouvez produire chacun PDF dont vous avez besoin, puis les combiner en tant que post-processus avec pdftk. Cela pourrait même être fait à partir de votre programme en utilisant un appel system () ou ShellExecute ().

2
Naaff

Voici un exemple utilisant 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();
        }
    }
}

Le constructeur PdfReader a de nombreuses surcharges. Il est possible de remplacer le type de paramètre IEnumerable<string> avec IEnumerable<Stream> et cela devrait aussi fonctionner. Veuillez noter que la méthode ne ferme pas OutputStream, elle délègue cette tâche au créateur du flux.

1
hmadrigal

Je sais que beaucoup de gens ont recommandé PDF Sharp, mais il ne semble pas que ce projet ait été mis à jour depuis juin 2008. De plus, la source n'est pas disponible.

Personnellement, j'ai joué avec iTextSharp qui a été assez facile à travailler.

1
NotMe

J'ai combiné les deux ci-dessus, car je devais fusionner 3 pdfbytes et retourner un octet

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
Marimar

Combiner deux byte[] en utilisant iTextSharp jusqu'à la 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;
}

À la place du byte[] il est possible de passer aussi Stream

1
Emaborsa

Voici un lien vers un exemple utilisant PDFSharp et ConcatenateDocuments

1
northpole

Je l'ai fait avec PDFBox. Je suppose que cela fonctionne de manière similaire à iTextSharp.

0
trendl

Vous pouvez essayer pdf-shufflergtk-apps.org

0
medigeek

La méthode suivante fusionne deux fichiers PDF (f1 et f2) à l'aide d'iTextSharp. Le deuxième pdf est ajouté après un index spécifique de f1.

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

            }
        }
0
Viraj Singh

Pour résoudre un problème similaire, j'ai utilisé iTextSharp comme ceci:

//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();
0
AragornMx

La méthode suivante obtient un tableau List de byte qui est PDF byte tableau, puis renvoie un tableau byte.

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

Ainsi, le résultat de PdfHelper.PdfConcat la méthode est passée à PdfHelper.DownloadAsPdfFile méthode.

PS: un package NuGet nommé [PdfSharp][1] doit être installé. Donc, dans le Package Manage Console type de fenêtre:

Install-Package PdfSharp

0
Siyavash Hamdi

Voici la solution http://www.wacdesigns.com/2008/10/03/merge-pdf-files-using-c Il utilise la bibliothèque iTextSharp open source gratuite http: // sourceforge.net/projects/itextsharp

0
Dmitri Kouminov