微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

尝试添加水印时,iText7 文档没有页面

如何解决尝试添加水印时,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 抛出时忽略了此异常,如对问题线程的评论中所述。

link to above issue

解决方法

您的问题存在多个问题,但要解决添加水印的问题,您必须创建另一个 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 举报,一经查实,本站将立刻删除。