如何解决尝试添加水印时,iText7 文档没有页面
我有一个在 SSRS 中在 iText 之外呈现的 pdf。该报告作为单独的 PDF 提供,我使用 iText 来应用一些进一步的功能,例如将pdf合并为一个,添加密码加密等
我正在尝试在 pdf 的每一页上添加水印,如下所示:
public string MergeReports(ConcurrentDictionary<int,string> base64Reports,string password = null,string watermark = null)
{
try
{
var passwordBytes = password != null ? Encoding.ASCII.GetBytes(password) : null;
// Creating new PdfDocument with smart mode on which maintains formatting and styling.
using (var ms = new MemoryStream())
using (var mergedPdf = new PdfDocument(new PdfWriter(ms,new WriterProperties().SetStandardEncryption(passwordBytes,passwordBytes,EncryptionConstants.ALLOW_PRINTING,EncryptionConstants.ENCRYPTION_AES_128 | EncryptionConstants.DO_NOT_ENCRYPT_MetaDATA)).SetSmartMode(true)))
{
foreach (var report in base64Reports.OrderBy(x => x.Key))
{
var (_,base64String) = report;
var bytes = Convert.FromBase64String(base64String);
using (var memoryStream = new MemoryStream(bytes))
{
using (PdfReader reader = new PdfReader(memoryStream))
{
using (var pdfDoc = new PdfDocument(reader))
{
if (watermark != null)
AddWatermark(watermark,pdfDoc);
pdfDoc.copyPagesTo(1,pdfDoc.GetNumberOfPages(),mergedPdf);
pdfDoc.Close();
}
}
}
}
mergedPdf.Close();
return Convert.ToBase64String(ms.ToArray());
}
}
catch (Exception ex)
{
throw new PdfException($"Unable to merge PDF reports: {ex.Message}");
}
}
private void AddWatermark(string watermark,PdfDocument pdfDoc)
{
float watermarkTrimmingRectangleWidth = 300;
float watermarkTrimmingRectangleHeight = 300;
float formWidth = 300;
float formHeight = 300;
float formXOffset = 0;
float formYOffset = 0;
float xTranslation = 50;
float yTranslation = 25;
double rotationInRads = Math.PI / 3;
var fontProgram = FontProgramFactory.CreateFont(_configuration.GetSection("FontFiles")["Calibri"]);
PdfFont font = PdfFontFactory.CreateFont(fontProgram);
float fontSize = 150;
var numberOfPages = pdfDoc.GetNumberOfPages();
pdfpage page = null;
for (var i = 1; i <= numberOfPages; i++)
{
page = pdfDoc.GetPage(i);
Rectangle ps = page.GetPageSize();
//Center the annotation
float bottomLeftX = ps.GetWidth() / 2 - watermarkTrimmingRectangleWidth / 2;
float bottomLeftY = ps.GetHeight() / 2 - watermarkTrimmingRectangleHeight / 2;
Rectangle watermarkTrimmingRectangle = new Rectangle(bottomLeftX,bottomLeftY,watermarkTrimmingRectangleWidth,watermarkTrimmingRectangleHeight);
PdfWatermarkAnnotation pdfWatermark = new PdfWatermarkAnnotation(watermarkTrimmingRectangle);
//Apply linear algebra rotation math
//Create identity matrix
AffineTransform transform = new AffineTransform();//No-args constructor creates the identity transform
//Apply translation
transform.Translate(xTranslation,yTranslation);
//Apply rotation
transform.Rotate(rotationInRads);
PdfFixedPrint fixedPrint = new PdfFixedPrint();
pdfWatermark.SetFixedPrint(fixedPrint);
//Create appearance
Rectangle formRectangle = new Rectangle(formXOffset,formYOffset,formWidth,formHeight);
//Observation: font XObject will be resized to fit inside the watermark rectangle
PdfFormXObject form = new PdfFormXObject(formRectangle);
PdfExtGState gs1 = new PdfExtGState().SetFillOpacity(0.6f);
PdfCanvas canvas = new PdfCanvas(form,pdfDoc);
float[] transformValues = new float[6];
transform.GetMatrix(transformValues);
canvas.SaveState()
.BeginText().SetColor(ColorConstants.GRAY,true).SetExtGState(gs1)
.SetTextMatrix(transformValues[0],transformValues[1],transformValues[2],transformValues[3],transformValues[4],transformValues[5])
.SetFontAndSize(font,fontSize)
.showtext(watermark)
.EndText()
.RestoreState();
canvas.Release();
pdfWatermark.SetAppearance(PdfName.N,new PdfAnnotationAppearance(form.GetPdfObject()));
pdfWatermark.SetFlags(PdfAnnotation.PRINT);
page.AddAnnotation(pdfWatermark);
}
page?.Flush();
}
我从这个 stackoverflow answer 中找到了水印代码,并且不得不对其进行一些修改以匹配我的实现。
调试时,单步执行好像在canvas.SaveState(..)
上抛出异常
我得到的例外是
((iText.Kernel.PdfException)ex).消息:文档没有页面。
堆栈跟踪
在 iText.Kernel.Pdf.pdfpagesTree.GenerateTree() 在 iText.Kernel.Pdf.PdfDocument.Close() 在 iText.Kernel.Pdf.PdfDocument.System.Idisposable.dispose() 在 RenderService.Services.PDFMerger.MergeReports(ConcurrentDictionary`2 base64Reports,String password,String watermark) 在 D:_src\render-service\Solutions\Render Service\Source\RenderService\Services\PDFMerger.cs:line 66
添加这个是因为它可能是相关的,但我在尝试创建字体时遇到了 iText7 库的问题。错误
System,NullReferenceException 未将对象引用设置为对象异常的实例
在这一行:
PdfFont font = PdfFontFactory.CreateFont(fontProgram);
我仍然遇到此错误,但在从 itext.io.dll 抛出时忽略了此异常,如对问题线程的评论中所述。
解决方法
您的问题存在多个问题,但要解决添加水印的问题,您必须创建另一个 PdfWriter
,因为您正在编辑 pdf:
using (var destMemoryStream = new MemoryStream())
{
using (var memoryStream = new MemoryStream(bytes))
{
using (PdfReader reader = new PdfReader(memoryStream))
{
using (PdfWriter pdfWriter = new PdfWriter(destMemoryStream))
{
using (var pdfDoc = new PdfDocument(reader,pdfWriter))
{
if (watermark != null)
AddWatermark(watermark,pdfDoc);
pdfDoc.CopyPagesTo(1,pdfDoc.GetNumberOfPages(),mergedPdf);
pdfDoc.Close();
}
}
}
}
}
我不确定是否有必要在您的 page?.Flush()
中调用 AddWatermark
以及合并是否有效。您正在尝试将 pdf 页面复制到空的 pdf 文档。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。