2013-04-10 33 views
17

Come unire più file PDF (generati in fase di esecuzione) tramite ItextSharp quindi stamparli.Come unire più file PDF (generati in fase di esecuzione)?

Ho trovato il seguente link ma quel metodo richiede i nomi pdf considerando che i file pdf sono archiviati e questo non è il mio caso.


ho più rapporti sarò convertirli in pdf files attraverso questo metodo:

private void AddReportToResponse(LocalReport followsReport) 
{ 
    string mimeType; 
    string encoding; 
    string extension; 
    string[] streams = new string[100]; 
    Warning[] warnings = new Warning[100]; 
    byte[] pdfStream = followsReport.Render("PDF", "", out mimeType, out encoding, out extension, out streams, out warnings); 
    //Response.Clear(); 
    //Response.ContentType = mimeType; 
    //Response.AddHeader("content-disposition", "attachment; filename=Application." + extension); 
    //Response.BinaryWrite(pdfStream); 
    //Response.End(); 
} 

Ora voglio unire tutti i file generati (Bytes) in un unico file pdf stamparlo

+1

Penso che la domanda sia simile a questa: http://stackoverflow.com/questions/3961804/itextsharp-creation-of-a-pdf-from-a-list-of-byte-arrays –

+0

I campioni che hai trovato e il o il r i commentatori ti hanno indicato, usa 'PdfReader' per leggere i documenti di origine. 'PdfReader' ha più costruttori, alcuni prendono un nome file come argomento, alcuni array di byte che contengono il PDF; nel tuo caso usa questi ultimi. Dagli esempi di fusione trovati, tuttavia, non scegliere uno con 'PdfWriter', ma uno con' PdfCopy, PdfSmartCopy, PdfCopyFields, 'o' PdfCopyForms' (la scelta dipende dai vostri esatti requisiti). – mkl

+0

@mkl: Potrebbe U fornire un esempio per risolvere il problema, per favore? –

risposta

45

Se si desidera unire i documenti di origine utilizzando iText (Sharp), ci sono due situazioni fondamentali:

  1. Sei sicuro di voler unire i documenti, acquisendo le pagine in formato originale, trasferendo il maggior numero di il loro contenuto e le loro annotazioni interattive il più possibile. In questo caso, è necessario utilizzare una soluzione basata su un membro della famiglia di classi Pdf*Copy*.

  2. In realtà si desidera integrare le pagine dei documenti di origine in un nuovo documento ma si desidera che il nuovo documento gestisca il formato generale e non si cura delle funzionalità interattive (annotazioni ...) nei documenti originali (o anche voglia di sbarazzarsi di loro). In questo caso è necessario utilizzare una soluzione basata sulla classe PdfWriter.

È possibile trovare i dettagli in chapter 6 (in particolare la sezione 6.4) di iText in Action — 2nd Edition. È possibile accedere al codice di esempio Java here e alle versioni C#.

Un semplice esempio che utilizza PdfCopy è Concatenate.java/Concatenate.cs. Il pezzo centrale del codice è:

byte[] mergedPdf = null; 
using (MemoryStream ms = new MemoryStream()) 
{ 
    using (Document document = new Document()) 
    { 
     using (PdfCopy copy = new PdfCopy(document, ms)) 
     { 
      document.Open(); 

      for (int i = 0; i < pdf.Count; ++i) 
      { 
       PdfReader reader = new PdfReader(pdf[i]); 
       // loop over the pages in that document 
       int n = reader.NumberOfPages; 
       for (int page = 0; page < n;) 
       { 
        copy.AddPage(copy.GetImportedPage(reader, ++page)); 
       } 
      } 
     } 
    } 
    mergedPdf = ms.ToArray(); 
} 

Qui pdf possibile definire come List<byte[]> contiene direttamente i documenti di origine (appropriate per il caso d'uso di unione di documenti intermedi in memoria) o come List<String> contenente i nomi di file di documento sorgente (appropriato se si uniscono documenti dal disco).

Una panoramica alla fine del capitolo fa riferimento riassume l'uso delle classi citate:

  • PdfCopy: copia le pagine da uno o più documenti PDF già esistenti. Aspetti negativi importanti: PdfCopy non rileva il contenuto ridondante e fallisce quando si concatenano i moduli.

  • PdfCopyFields: inserisce i campi delle diverse forme in un'unica forma. Può essere utilizzato per evitare i problemi riscontrati con i campi modulo quando si concatenano i moduli utilizzando PdfCopy. L'utilizzo della memoria può essere un problema.

  • PdfSmartCopy: copia pagine da uno o più documenti PDF esistenti. PdfSmartCopy è in grado di rilevare contenuti ridondanti, ma richiede più memoria e CPU rispetto allo PdfCopy.

  • PdfWriter: genera documenti PDF da zero. Può importare pagine da altri documenti PDF. Lo svantaggio principale è che tutte le funzionalità interattive della pagina importata (annotazioni, segnalibri, campi e così via) vengono perse nel processo.

+0

È davvero interessante vedere che qualcuno ha downvoted questa risposta senza lasciare un commento che spieghi le carenze ... Detto questo, iText si è sviluppato nel frattempo e gran parte degli elementi specifici di 'PdfCopyFields 'è stato trovato in' PdfCopy'. – mkl

+0

Le fusioni sono molto lente (ho fatto un aumento di btw.) –

+1

@BonusKun * Le fusioni sono molto lente * - se è eccezionalmente lento, potresti voler creare una domanda a sé stante che fornisca documenti di esempio per riprodurre il problema ... * (Ho upvoted btw.) * - grazie! – mkl

4

Ecco un codice che ho estratto da un vecchio progetto che avevo. Era un'applicazione web, ma stavo usando iTextSharp per unire file PDF e poi stamparli.

public static class PdfMerger 
    { 
     /// <summary> 
     /// Merge pdf files. 
     /// </summary> 
     /// <param name="sourceFiles">PDF files being merged.</param> 
     /// <returns></returns> 
     public static byte[] MergeFiles(List<Stream> sourceFiles) 
     { 
      Document document = new Document(); 
      MemoryStream output = new MemoryStream(); 

      try 
      { 
       // Initialize pdf writer 
       PdfWriter writer = PdfWriter.GetInstance(document, output); 
       writer.PageEvent = new PdfPageEvents(); 

       // Open document to write 
       document.Open(); 
       PdfContentByte content = writer.DirectContent; 

       // Iterate through all pdf documents 
       for (int fileCounter = 0; fileCounter < sourceFiles.Count; fileCounter++) 
       { 
        // Create pdf reader 
        PdfReader reader = new PdfReader(sourceFiles[fileCounter]); 
        int numberOfPages = reader.NumberOfPages; 

        // Iterate through all pages 
        for (int currentPageIndex = 1; currentPageIndex <= 
             numberOfPages; currentPageIndex++) 
        { 
         // Determine page size for the current page 
         document.SetPageSize(
          reader.GetPageSizeWithRotation(currentPageIndex)); 

         // Create page 
         document.NewPage(); 
         PdfImportedPage importedPage = 
          writer.GetImportedPage(reader, currentPageIndex); 


         // Determine page orientation 
         int pageOrientation = reader.GetPageRotation(currentPageIndex); 
         if ((pageOrientation == 90) || (pageOrientation == 270)) 
         { 
          content.AddTemplate(importedPage, 0, -1f, 1f, 0, 0, 
           reader.GetPageSizeWithRotation(currentPageIndex).Height); 
         } 
         else 
         { 
          content.AddTemplate(importedPage, 1f, 0, 0, 1f, 0, 0); 
         } 
        } 
       } 
      } 
      catch (Exception exception) 
      { 
       throw new Exception("There has an unexpected exception" + 
         " occured during the pdf merging process.", exception); 
      } 
      finally 
      { 
       document.Close(); 
      } 
      return output.GetBuffer(); 
     } 
    } 



    /// <summary> 
    /// Implements custom page events. 
    /// </summary> 
    internal class PdfPageEvents : IPdfPageEvent 
    { 
     #region members 
     private BaseFont _baseFont = null; 
     private PdfContentByte _content; 
     #endregion 

     #region IPdfPageEvent Members 
     public void OnOpenDocument(PdfWriter writer, Document document) 
     { 
      _baseFont = BaseFont.CreateFont(BaseFont.HELVETICA, 
           BaseFont.CP1252, BaseFont.NOT_EMBEDDED); 
      _content = writer.DirectContent; 
     } 

     public void OnStartPage(PdfWriter writer, Document document) 
     { } 

     public void OnEndPage(PdfWriter writer, Document document) 
     { } 

     public void OnCloseDocument(PdfWriter writer, Document document) 
     { } 

     public void OnParagraph(PdfWriter writer, 
        Document document, float paragraphPosition) 
     { } 

     public void OnParagraphEnd(PdfWriter writer, 
        Document document, float paragraphPosition) 
     { } 

     public void OnChapter(PdfWriter writer, Document document, 
           float paragraphPosition, Paragraph title) 
     { } 

     public void OnChapterEnd(PdfWriter writer, 
        Document document, float paragraphPosition) 
     { } 

     public void OnSection(PdfWriter writer, Document document, 
        float paragraphPosition, int depth, Paragraph title) 
     { } 

     public void OnSectionEnd(PdfWriter writer, 
        Document document, float paragraphPosition) 
     { } 

     public void OnGenericTag(PdfWriter writer, Document document, 
            Rectangle rect, string text) 
     { } 
     #endregion 

     private float GetCenterTextPosition(string text, PdfWriter writer) 
     { 
      return writer.PageSize.Width/2 - _baseFont.GetWidthPoint(text, 8)/2; 
     } 
    } 

Non l'ho scritto, ma ho apportato alcune modifiche. Non riesco a ricordare dove l'ho trovato. Dopo aver unito i PDF, chiamerei questo metodo per inserire javascript per aprire la finestra di dialogo di stampa quando viene aperto il PDF. Se si cambia bSilent su true, si dovrebbe stampare in modo silenzioso sulla stampante predefinita.

public Stream addPrintJStoPDF(Stream thePDF) 
{ 
    MemoryStream outPutStream = null; 
    PRStream finalStream = null; 
    PdfDictionary page = null; 
    string content = null; 

    //Open the stream with iTextSharp 
    var reader = new PdfReader(thePDF); 

    outPutStream = new MemoryStream(finalStream.GetBytes()); 
    var stamper = new PdfStamper(reader, (MemoryStream)outPutStream); 
    var jsText = "var res = app.setTimeOut('this.print({bUI: true, bSilent: false, bShrinkToFit: false});', 200);"; 
    //Add the javascript to the PDF 
    stamper.JavaScript = jsText; 

    stamper.FormFlattening = true; 
    stamper.Writer.CloseStream = false; 
    stamper.Close(); 

    //Set the stream to the beginning 
    outPutStream.Position = 0; 

    return outPutStream; 
} 

Non so quanto bene il codice di cui sopra è scritto da quando ho tirato da qualche altra parte e non ho lavorato in profondità a tutti con iTextSharp ma so che ha fatto il lavoro a file PDF fusione che stavo generando in fase di esecuzione.

+2

Si prega di astenersi dall'utilizzare questo tipo di routine di unione, a meno che non si abbiano requisiti molto specifici che ti obbligano a farlo. Quando si utilizza 'PdfWriter' per unire PDF di origine, le funzionalità interattive (moduli e altre annotazioni) vengono perse. Inoltre, il PDF risultante contiene internamente un involucro non necessario attorno alle informazioni della pagina che, se ripetuto più volte, può causare il fallimento dei visualizzatori di PDF quando si tenta di visualizzare il PDF. – mkl

+0

Come ho detto, l'ho estratto dal vecchio codice che era in produzione, ma i PDF sono stati generati da html creato da un editor wysiwyg, quindi non avevamo funzionalità interattive.Anche le nostre iterazioni di solito erano solo circa 10 alla volta e non abbiamo mai avuto problemi con il pdf che non si apriva. Ho postato questo come esempio di come era in esecuzione in produzione e so che stava lavorando per unire pdf senza problemi segnalati. – DSlagle

+0

Non intendevo offendere; tali soluzioni di fusione come la vostra basate su 'PdfWriter', infatti, possono essere trovate più spesso di quelle che usano le classi più adatte quando fanno ricerche su google, e fanno * lavoro * dopo una moda, quindi non hanno completamente torto. Le soluzioni basate su 'Pdf * Copy *', tuttavia, sono generalmente più facili da usare (non è necessario adattare le dimensioni e la rotazione della pagina del documento di destinazione più e più volte), più complete (relative alle funzionalità interattive) e producono output più puliti (rispetto al struttura PDF interna). – mkl

7

Ho utilizzato iTextsharp con C# per combinare i file PDF. Questo è il codice che ho usato.

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

    PdfReader reader = null; 
    Document sourceDocument = null; 
    PdfCopy pdfCopyProvider = null; 
    PdfImportedPage importedPage; 
    string [email protected]"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; 
    } 
} 
1

Per evitare i problemi di memoria menzionati, ho usato flusso di file, invece di flusso di memoria (di cui al ITextSharp Out of memory exception merging multiple pdf) per unire i file pdf:

 var parentDirectory = Directory.GetParent(SelectedDocuments[0].FilePath); 
     var savePath = parentDirectory + "\\MergedDocument.pdf"; 

     using (var fs = new FileStream(savePath, FileMode.Create)) 
     { 
      using (var document = new Document()) 
      { 
       using (var pdfCopy = new PdfCopy(document, fs)) 
       { 
        document.Open(); 
        for (var i = 0; i < SelectedDocuments.Count; i++) 
        { 
         using (var pdfReader = new PdfReader(SelectedDocuments[i].FilePath)) 
         { 
          for (var page = 0; page < pdfReader.NumberOfPages;) 
          { 
           pdfCopy.AddPage(pdfCopy.GetImportedPage(pdfReader, ++page)); 
          } 
         } 
        } 
       } 
      } 
     } 
2

testati con iTextSharp-LGPL 4.1.6:

public static byte[] ConcatenatePdfs(IEnumerable<byte[]> documents) 
    { 
     using (var ms = new MemoryStream()) 
     { 
      var outputDocument = new Document(); 
      var writer = new PdfCopy(outputDocument, ms); 
      outputDocument.Open(); 

      foreach (var doc in documents) 
      { 
       var reader = new PdfReader(doc); 
       for (var i = 1; i <= reader.NumberOfPages; i++) 
       { 
        writer.AddPage(writer.GetImportedPage(reader, i)); 
       } 
       writer.FreeReader(reader); 
       reader.Close(); 
      } 

      writer.Close(); 
      outputDocument.Close(); 
      var allPagesContent = ms.GetBuffer(); 
      ms.Flush(); 

      return allPagesContent; 
     } 
    } 
Problemi correlati