2013-04-10 24 views
17

Jak scalić wiele plików pdf (wygenerowanych w czasie wykonywania) przez ItextSharp, a następnie je wydrukować.Jak scalać wiele plików pdf (generowanych w czasie wykonywania)?

Znalazłem następujące link, ale ta metoda wymaga nazw pdf, biorąc pod uwagę, że pliki pdf przechowywane i to nie jest moja sprawa.


mam wiele raportów będę konwertować je do pdf files dzięki tej metodzie:

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

Teraz chcę połączyć te wszystkie generowanych plików (Bytes) w jednym pliku pdf na ramę

+1

Myślę, że pytanie jest podobne do tego: http://stackoverflow.com/questions/3961804/itextsharp-creation-of-a-pdf-from-a-list-of-byte-arrays –

+0

Próbki, które znalazłeś i othe r komentatorzy wskazali ci, użyj 'PdfReader', aby przeczytać dokumenty źródłowe. 'PdfReader' ma wiele konstruktorów, niektóre pobierają łańcuch nazw plików jako argument, niektóre tablice bajtów zawierające plik PDF; w twoim przypadku użyj tych ostatnich. Z odnalezionych próbek nie należy jednak wybierać za pomocą 'PdfWriter', ale zamiast tego używać' PdfCopy, PdfSmartCopy, PdfCopyFields, 'lub' PdfCopyForms' (wybór zależy od dokładnych wymagań). – mkl

+0

@mkl: Czy mógłbyś podać próbkę rozwiązania problemu? –

Odpowiedz

45

Jeśli chcesz scalić dokumentów źródłowych przy użyciu iText (ostry), istnieją dwie podstawowe sytuacje:

  1. Naprawdę chcesz scalić dokumentów, nabywanie stron w ich oryginalnym formacie, przekazanie jak najwięcej ich zawartość i ich interaktywne adnotacje, jak to możliwe. W takim przypadku powinieneś użyć rozwiązania opartego na rodzinie klasy Pdf*Copy*.

  2. Rzeczywiście chcesz zintegrować strony z dokumentów źródłowych w nowy dokument, ale chcesz, aby nowy dokument regulował ogólny format i nie obchodziłeś interaktywnych funkcji (adnotacji ...) w oryginalnych dokumentach (lub nawet chcesz się ich pozbyć). W takim przypadku powinieneś użyć rozwiązania opartego na klasie PdfWriter.

można znaleźć szczegóły w chapter 6 (zwłaszcza rozdział 6.4) z iText in Action — 2nd Edition. Kod przykładowy Java można uzyskać pod numerem here i C# 'ified wersje here.

Prosta próbka z użyciem PdfCopy to Concatenate.java/Concatenate.cs. Centralny fragment kodu:

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

Tutaj pdf może albo być zdefiniowana jako List<byte[]> natychmiast zawierający dokumenty źródłowe (odpowiednie dla danego przypadku użycia łączenia pośrednich dokumentów w pamięci) lub jako List<String> zawierająca nazwiska pliki dokumentów źródłowych (odpowiednie w przypadku scalania dokumentów z dysku).

Przegląd pod koniec odwołania rozdziale podsumowano korzystanie z wymienionych klas:

  • PdfCopy: kopiuje strony z jednego lub więcej istniejących dokumentów PDF. Główne wady: PdfCopy nie wykrywa nadmiarowej zawartości i nie powiedzie się podczas łączenia formularzy.

  • : Umieszcza pola różnych formularzy w jednym formularzu. Może być używany w celu uniknięcia problemów napotkanych w polach formularza podczas łączenia formularzy przy użyciu PdfCopy. Używanie pamięci może być problemem.

  • PdfSmartCopy: Kopiuje strony z jednego lub więcej istniejących dokumentów PDF. PdfSmartCopy jest w stanie wykryć nadmiarową zawartość, ale potrzebuje więcej pamięci i procesora niż PdfCopy.

  • : Generuje dokumenty PDF od podstaw. Może importować strony z innych dokumentów PDF. Główną wadą jest to, że wszystkie interaktywne funkcje zaimportowanej strony (adnotacje, zakładki, pola i tak dalej) są w trakcie procesu tracone.

+0

Naprawdę interesujące jest to, że ktoś zniżył tę odpowiedź, nie pozostawiając komentarza wyjaśniającego braki ... To powiedziawszy, iText rozwinęło się w międzyczasie i wiele z specyficznych "PdfCopyFields" znalazło się w 'PdfCopy'. – mkl

+0

Fuzja jest naprawdę powolna (przeszedłem z góry). –

+1

@BonusKun * Łączy się bardzo wolno * - jeśli jest wyjątkowo powolny, możesz utworzyć pytanie samodzielnie, dostarczając przykładowe dokumenty w celu odtworzenia problemu ... * (Z góry przegłosowałem.) * - thanx! – mkl

4

Oto kod, który wyciągnąłem ze starego projektu, który miałem. Była to aplikacja internetowa, ale korzystałem z iTextSharp do scalania plików pdf, a następnie ich drukowania.

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

Nie napisałem tego, ale wprowadziłem pewne modyfikacje. Nie pamiętam, gdzie go znalazłem. Po scaleniu plików PDF nazwałbym tę metodę, aby wstawić javascript, aby otworzyć okno dialogowe drukowania po otwarciu pliku PDF. Jeśli zmienisz wartość bSilent na true, powinna ona cicho drukować na domyślnej drukarce.

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

Nie wiem, jak dobrze powyższy kod został napisany od Wyciągnąłem go gdzieś indziej, a ja nie pracuję w głębi w ogóle z iTextSharp, ale wiem, że to nie działa na łączących PDF, że byłem generowania W czasie wykonywania.

+2

Prosimy o powstrzymanie się od używania tego rodzaju procedury scalania, chyba że masz bardzo szczególne wymagania, aby to zrobić. Gdy użyjesz 'PdfWriter' do scalenia źródłowych plików PDF, funkcje interaktywne (formularze i inne adnotacje) zostaną utracone. Ponadto wynikowy plik PDF wewnętrznie zawiera niepotrzebne opakowanie informacji o stronie, które po wielokrotnym iterowaniu może spowodować, że przeglądarki plików PDF przestaną być wyświetlane podczas próby wyświetlenia pliku PDF. – mkl

+0

Jak już powiedziałem, wyciągnąłem to ze starszego kodu, który był w produkcji, ale pliki PDF zostały wygenerowane z html zbudowanego przez edytor WYSIWYG, więc nie mieliśmy żadnych interaktywnych funkcji.Również nasze iteracje były zwykle tylko około 10 na raz i nigdy nie mieliśmy problemów z nieotrzymaniem pdf. Opublikowalem to jako przykład, ponieważ mieliśmy go uruchomionego w produkcji i wiem, że pracował nad łączeniem plików PDF bez zgłaszanych problemów. – DSlagle

+0

Nie zamierzałem obrażać; takie łączące się rozwiązania, takie jak twoje oparte na 'PdfWriter', można znaleźć częściej niż te, które używają lepszych klas podczas przeglądania go, a one * działają * po modnej, więc nie są całkowicie błędne. Jednak rozwiązania oparte na 'Pdf * Copy *' są na ogół łatwiejsze w użyciu (bez potrzeby dostosowywania rozmiaru strony docelowej i rotacji), bardziej kompletne (dotyczące funkcji interaktywnych) i generują czystsze wyniki (w odniesieniu do wewnętrzna struktura PDF). – mkl

7

Użyłem iTextsharp z C# do połączenia plików pdf. To jest kod, którego użyłem.

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

aby uniknąć problemów z pamięcią wspomniano, użyłem pliku strumienia zamiast strumienia pamięci (wspomniane w ITextSharp Out of memory exception merging multiple pdf) do scalania plików 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

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