2010-03-03 4 views
26

Próbuję programowo utworzyć pewną liczbę dokumentów PDF ze znakiem wodnym na każdej stronie, używając itextsharp (port C# dla itext Javy).C# itextsharp Tworzenie plików PDF ze znakiem wodnym na każdej stronie

Jestem w stanie to zrobić po utworzeniu dokumentu za pomocą PdfStamper. Wydaje się to jednak obejmować ponowne otwarcie dokumentu, który go czyta, a następnie utworzenie nowego dokumentu ze znakiem wodnym na każdej stronie.

Czy można to zrobić podczas tworzenia dokumentu?

Pozdrowienia,

Tim.

Odpowiedz

38

Po wkopaniu się w to znalazłem najlepszy sposób na dodanie znaku wodnego do każdej strony, jaka została utworzona. Aby to zrobić, I stworzył nową klasę i wdrożony interfejs IPdfPageEvent następująco:

class PdfWriterEvents : IPdfPageEvent 
    { 
     string watermarkText = string.Empty; 

     public PdfWriterEvents(string watermark) 
     { 
      watermarkText = watermark; 
     } 

     public void OnOpenDocument(PdfWriter writer, Document document) { } 
     public void OnCloseDocument(PdfWriter writer, Document document) { } 
     public void OnStartPage(PdfWriter writer, Document document) { 
      float fontSize = 80; 
      float xPosition = 300; 
      float yPosition = 400; 
      float angle = 45; 
      try 
      { 
       PdfContentByte under = writer.DirectContentUnder; 
       BaseFont baseFont = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.EMBEDDED); 
       under.BeginText(); 
       under.SetColorFill(BaseColor.LIGHT_GRAY); 
       under.SetFontAndSize(baseFont, fontSize); 
       under.ShowTextAligned(PdfContentByte.ALIGN_CENTER, watermarkText, xPosition, yPosition, angle); 
       under.EndText(); 
      } 
      catch (Exception ex) 
      { 
       Console.Error.WriteLine(ex.Message); 
      } 
     } 
     public void OnEndPage(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) { } 

    } 
} 

Cel ten został zarejestrowany do obsługi zdarzeń w następujący sposób:

PdfWriter docWriter = PdfWriter.GetInstance(document, new FileStream(outputLocation, FileMode.Create)); 
PdfWriterEvents writerEvent = new PdfWriterEvents(watermark); 
docWriter.PageEvent = writerEvent; 
+1

Przepraszamy, ale nie dostałem znaku wodnego na utworzonym pliku PDF. Czy mógłbyś dać mi znać, jaki był problem. Użyłem dokładnego kodu podanego powyżej. – suryakiran

+0

Co ze stronami krajobrazowymi? Próbowałem stron page.Didth/2 i page.Height/2, ale strony krajobrazowe są traktowane jak normalne strony -> wyrównany tekst nie znajduje się w centrum strony. –

+0

Dzięki za odpowiedź na to pytanie, działa idealnie. – AndyMcKenna

3

Nie możesz po prostu złożyć znaku wodnego na każdej stronie po jej wykonaniu?

0

W iTextSharp powinno być możliwe programowe dodanie znaku wodnego np.

Watermark watermark = new Watermark(Image.getInstance("watermark.jpg"), 200, 420); 
document.Add(watermark); 
+2

Tak, myślałem o tym; szukając w Internecie jest dużo przykładowego kodu, który zawiera klasę Watermark - ale uważam, że zostało to usunięte z biblioteki :( –

+1

Byłbym zszokowany, gdyby je usunięto. Może właśnie zmienili przestrzeń nazw? próbowałeś zajrzeć do zespołu za pomocą reflektora? – James

2

Tak, klasa Watermark wydaje się być nie więcej - dziwne. Jednak w procesie konwersji do iTextSharp 5.3 znalazłem prosty sposób dodania znaku wodnego do nowego dokumentu.

MemoryStream mem = new MemoryStream(); 

Document document = new Document(); 

PdfWriter writer = PdfWriter.GetInstance(document, mem); 

PdfContentByte cb = writer.DirectContent; 

document.Open(); 

document.NewPage(); 

Image watermark = Image.GetInstance(WATERMARK_URI); 

watermark.SetAbsolutePosition(80, 200); 

document.Add(watermark); 

BaseFont bf = BaseFont.CreateFont(FONT, BaseFont.CP1252, BaseFont.NOT_EMBEDDED); 

cb.BeginText(); 

... 

cb.EndText(); 

document.Close(); 
+1

Działa to tylko na pierwszej stronie. – spadelives

6
string WatermarkLocation = "D:\\Images\\superseded.png"; 

    Document document = new Document(); 
    PdfReader pdfReader = new PdfReader(FileLocation); 
    PdfStamper stamp = new PdfStamper(pdfReader, new FileStream(FileLocation.Replace(".pdf", "[temp][file].pdf"), FileMode.Create)); 

    iTextSharp.text.Image img = iTextSharp.text.Image.GetInstance(WatermarkLocation); 
    img.SetAbsolutePosition(125, 300); // set the position in the document where you want the watermark to appear (0,0 = bottom left corner of the page) 



    PdfContentByte waterMark; 
    for (int page = 1; page <= pdfReader.NumberOfPages; page++) 
    { 
     waterMark = stamp.GetOverContent(page); 
     waterMark.AddImage(img); 
    } 
    stamp.FormFlattening = true; 
    stamp.Close(); 

    // now delete the original file and rename the temp file to the original file 
    File.Delete(FileLocation); 
    File.Move(FileLocation.Replace(".pdf", "[temp][file].pdf"), FileLocation); 
12

Chociaż rozwiązanie Tima wydaje się bardzo ładne, udało mi się zrobić to samo (wierzę), stosując następujący kod (może iTextSharp poprawiła się nieco od tego czasu ...):

private byte[] AddWatermark(byte[] bytes, BaseFont bf) 
    { 
     using(var ms = new MemoryStream(10 * 1024)) 
     { 
      using(var reader = new PdfReader(bytes)) 
      using(var stamper = new PdfStamper(reader, ms)) 
      { 
       int times = reader.NumberOfPages; 
       for (int i = 1; i <= times; i++) 
       { 
        var dc = stamper.GetOverContent(i); 
        PdfHelper.AddWaterMark(dc, AppName, bf, 48, 35, new BaseColor(70, 70, 255), reader.GetPageSizeWithRotation(i)); 
       } 
       stamper.Close(); 
      } 
      return ms.ToArray(); 
     } 
    } 

    public static void AddWaterMark(PdfContentByte dc, string text, BaseFont font, float fontSize, float angle, BaseColor color, Rectangle realPageSize, Rectangle rect = null) 
    { 
     var gstate = new PdfGState { FillOpacity = 0.1f, StrokeOpacity = 0.3f }; 
     dc.SaveState(); 
     dc.SetGState(gstate); 
     dc.SetColorFill(color); 
     dc.BeginText(); 
     dc.SetFontAndSize(font, fontSize); 
     var ps = rect ?? realPageSize; /*dc.PdfDocument.PageSize is not always correct*/ 
     var x = (ps.Right + ps.Left)/2; 
     var y = (ps.Bottom + ps.Top)/2; 
     dc.ShowTextAligned(Element.ALIGN_CENTER, text, x, y, angle); 
     dc.EndText(); 
     dc.RestoreState(); 
    } 

Spowoduje to dodanie znaku wodnego na wszystkich stronach dokumentu PDF dostarczonego jako tablica bajtów.

(nie trzeba to zrobić podczas tworzenia plików PDF.)

Wydaje pracy zarówno dla krajobrazu i portretu i prawdopodobnie działa dla dokumentów z mieszanymi orientacjach.

Pozdrawiam! :)

+2

Jeśli twoim przypadkiem użycia jest * utworzyć nowy plik PDF i dodać znak wodny *, możesz preferować wariant jednoprzebiegowy przedstawiony przez Tima, ponieważ zużywa on mniej zasobów. Jeśli twoim przypadkiem użycia jest * pobranie istniejącego pliku PDF i znaku wodnego *, twoje rozwiązanie jest odpowiednie. – mkl

+0

thanku tak bardzo !! –

4

Użyłem pierwszego rozwiązania. Na początku miałem problemy z uruchomieniem tego. Dostaję zielone podkreślenia pod wszystkimi moimi publicznymi pustkami, mówiąc, że zamierzam ukryć jakiegoś spadkobiercę.

Zasadniczo zdałem sobie sprawę, że dodałem już stronę PagePageEventHelper i zasadniczo po prostu wycinam kod dla OnStartPage. RÓWNIEŻ! Z jakiegoś powodu musiałem unieważnić całą publiczną pustkę publiczną.

public override void OnStartPage(PdfWriter writer, Document document) 
     { 
      if (condition) 
      { 
       string watermarkText = "-whatever you want your watermark to say-"; 
       float fontSize = 80; 
       float xPosition = 300; 
       float yPosition = 400; 
       float angle = 45; 
       try 
       { 
        PdfContentByte under = writer.DirectContentUnder; 
        BaseFont baseFont = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.EMBEDDED); 
        under.BeginText(); 
        under.SetColorFill(iTextSharp.text.pdf.CMYKColor.LIGHT_GRAY); 
        under.SetFontAndSize(baseFont, fontSize); 
        under.ShowTextAligned(PdfContentByte.ALIGN_CENTER, watermarkText, xPosition, yPosition, angle); 
        under.EndText(); 
       } 
       catch (Exception ex) 
       { 
        Console.Error.WriteLine(ex.Message); 
       } 
      } 
     }