【发布时间】:2011-01-23 05:50:17
【问题描述】:
我正在尝试使用 itextsharp(Java 的 itext 的 C# 端口)以编程方式在每个页面上创建许多带有水印的 PDF 文档。
我可以在使用 PdfStamper 创建文档后执行此操作。然而,这似乎涉及重新打开阅读它的文档,然后在每页上创建一个带有水印的新文档。
在文档创建期间有没有办法做到这一点?
【问题讨论】:
我正在尝试使用 itextsharp(Java 的 itext 的 C# 端口)以编程方式在每个页面上创建许多带有水印的 PDF 文档。
我可以在使用 PdfStamper 创建文档后执行此操作。然而,这似乎涉及重新打开阅读它的文档,然后在每页上创建一个带有水印的新文档。
在文档创建期间有没有办法做到这一点?
【问题讨论】:
在深入研究之后,我发现最好的方法是在每个页面创建时添加水印。为此,我创建了一个新类并实现了 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;
【讨论】:
under.SetColorFill(iTextSharp.text.pdf.CMYKColor.LIGHT_GRAY);
虽然 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 时不需要这样做。)
它似乎适用于横向和纵向,它可能适用于具有混合方向的文档。
干杯! :)
【讨论】:
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);
【讨论】:
我使用了第一个解决方案。一开始我很难让它工作。我在所有公共空白下都得到了绿色下划线,表示它将隐藏一些继承成员。
基本上我意识到我已经添加了一个 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);
}
}
}
【讨论】:
你不能在制作完之后在每一页上打上水印吗?
【讨论】:
是的,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();
【讨论】:
在 iTextSharp 中,您应该能够以编程方式添加水印,例如
Watermark watermark = new Watermark(Image.getInstance("watermark.jpg"), 200, 420);
document.Add(watermark);
【讨论】: