【问题标题】:c# itextsharp PDF creation with watermark on each pagec# itextsharp PDF 创建每个页面上都有水印
【发布时间】:2011-01-23 05:50:17
【问题描述】:

我正在尝试使用 itextsharp(Java 的 itext 的 C# 端口)以编程方式在每个页面上创建许多带有水印的 PDF 文档。

我可以在使用 PdfStamper 创建文档后执行此操作。然而,这似乎涉及重新打开阅读它的文档,然后在每页上创建一个带有水印的新文档。

在文档创建期间有没有办法做到这一点?

【问题讨论】:

    标签: c# pdf itext


    【解决方案1】:

    在深入研究之后,我发现最好的方法是在每个页面创建时添加水印。为此,我创建了一个新类并实现了 IPdfPageEvent 接口,如下所示:

        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) { }
    
        }
    }
    

    这个对象被注册来处理如下事件:

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

    【讨论】:

    • 抱歉,我在创建的 PDF 上没有水印。你能告诉我,是什么问题。我已经使用了上面提供的确切代码。
    • 横向页面呢?我试过 page.Width/2 和 page.Height/2 但横向页面被视为普通页面 - >对齐的文本不在页面中心。
    • 使用 RazorPDF,缺少 BaseColor.LIGHT_GRAY。在这种情况下,请转至under.SetColorFill(iTextSharp.text.pdf.CMYKColor.LIGHT_GRAY);
    • 我得到这个错误:他的名字“水印”在当前上下文中不存在。我该如何纠正它?目前,我正在使用两个类,其中一个包含 pdf 的生成和你的类......我如何让两个类相互交谈,以便它知道水印是什么?
    • 如何在首页添加水印?我有一个 3 页的文档,它只出现在第 2 页和第 3 页。非常感谢您的回复:)
    【解决方案2】:

    虽然 Tim 的解决方案看起来很不错,但我已经设法使用以下代码(我相信)做了同样的事情(也许从那时起 iTextSharp 得到了一些改进......):

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

    这将在以字节数组形式提供的 PDF 文档的所有页面上添加水印。

    (您在创建 PDF 时不需要这样做。)

    它似乎适用于横向和纵向,它可能适用于具有混合方向的文档。

    干杯! :)

    【讨论】:

    • 如果您的用例是创建新的 PDF 并添加水印,您可能更喜欢 Tim 提出的一次性变体,因为它使用的资源更少。如果您的用例是获取现有的 PDF 并为其添加水印,那么您的解决方案是合适的。
    • 谢谢。这个解决方案对我很有用。我有一个基于此代码的示例 ASP.NET 核心项目。如果有人有兴趣,请在我的github
    • 此解决方案有效,谢谢,但我使用电子邮件地址作为水印,显然它是可点击的。当我单击它时,它会打开 Outlook 应用程序。关于如何阻止它的任何想法?谢谢。
    • @MariusPopa 不确定这是否可行,这有点小技巧,但也许您可以在电子邮件地址中插入一些软连字符 (Unicode U+00AD)(例如,在 at 符号之前) 这将是不可见的,但它会使电子邮件检测器认为它不是电子邮件。我没有尝试过,但它可能有效。很可能有更好的方法来做到这一点,但我还没有真正尝试过。
    • @NoOne 如何为长字符串设置多行?
    【解决方案3】:
    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);
    

    【讨论】:

      【解决方案4】:

      我使用了第一个解决方案。一开始我很难让它工作。我在所有公共空白下都得到了绿色下划线,表示它将隐藏一些继承成员。

      基本上我意识到我已经添加了一个 PagePageEventHelper,我基本上只是剪掉了 OnStartPage 的代码。还!出于某种原因,我不得不将我所有的公共无效的公共覆盖无效。

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

      【讨论】:

        【解决方案5】:

        你不能在制作完之后在每一页上打上水印吗?

        【讨论】:

          【解决方案6】:

          是的,Watermark 类似乎不再是 - 奇怪了。但是在转换到 iTextSharp 5.3 的过程中,我发现了一种向新文档添加水印的简单方法。

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

          【讨论】:

            【解决方案7】:

            在 iTextSharp 中,您应该能够以编程方式添加水印,例如

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

            【讨论】:

            • 是的,我想过;在线查找有很多包含 Watermark 类的示例代码 - 但我相信这已从库中删除:(
            • 如果他们删除了它,我会感到震惊。也许他们刚刚更改了其名称空间?您是否尝试过使用反射器查看组件?
            猜你喜欢
            • 2012-11-01
            • 2016-06-02
            • 2016-05-28
            • 2011-08-27
            • 2015-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-07-03
            相关资源
            最近更新 更多