顶部的 iText 标记图像并不总是有效

iText stamp image on top not always working

我正在使用 iTextSharp 在 PDF 的每一页上放置图像和一些文本。这对某些 PDF 非常有效,但对其他 PDF 无效。奇怪的是,它不适用于我使用 Word 2010 的 'Save as pdf' 函数创建的 PDF。我使用 GetOverContent,它应该将所有内容放在最前面。

使用 Acrobat,我可以看到我的图层已添加。所以它一定在某处的文字文字下面。

如何为邮票设置 z-index?

有没有一种方法(工具)可以清楚地看到 PDF 中有哪些对象?我发现 Acrobat 在这方面并不是很有帮助,但也许我需要培训 ;-)

示例无法使用 PDF here。 (link 已更新)

戳这里的代码,PDF来自数据库,存入数据库:

Protected Sub cbTekening_Callback(source As Object, e As DevExpress.Web.CallbackEventArgs) Handles cbTekening.Callback
    Dim document As New iTextSharp.text.Document()
    Dim intTekID As Integer

    Try

        Dim fieldValues As List(Of Object) = gridTekeningen.GetSelectedFieldValues(New String() {"TekeningID"})

        For Each item As Object In fieldValues
            Using ms As MemoryStream = New MemoryStream()
                intTekID = item

                Dim pdfr = New PdfReader(GetPDFFromDatabase(intTekID).ToArray())

                Dim pdfs As New iTextSharp.text.pdf.PdfStamper(pdfr, ms)

                Dim image__1 As iTextSharp.text.Image = iTextSharp.text.Image.GetInstance(New System.Uri(Session("ORG_Website") & Session("ORG_Tekeninglogo")))
                Dim image__2 As iTextSharp.text.Image = iTextSharp.text.Image.GetInstance(New System.Uri(Session("ORG_Website") & "Images/contactid_" & Session("ContactID") & ".png"))
                Dim rect As Rectangle

                Dim PageCount As Integer = pdfr.NumberOfPages
                Dim content As iTextSharp.text.pdf.PdfContentByte
                For x = 1 To PageCount
                    rect = pdfr.GetPageSize(x)
                    content = pdfs.GetOverContent(x)

                    image__1.SetAbsolutePosition(50.0F, 50.0F)
                    image__1.ScalePercent(30.0F, 30.0F)
                    image__2.SetAbsolutePosition(100.0F, 100.0F)
                    image__2.ScalePercent(30.0F, 30.0F)
                    Content.AddImage(image__1)
                    Content.AddImage(image__2)
                    Dim layer As New PdfLayer("Goedkeurlaag" & x.ToString, pdfs.Writer)
                    'Tell the cb that the next commands should be "bound" to this new layer
                    Content.BeginLayer(layer)
                    Content.SetFontAndSize(BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED), 20)

                    Dim strWatermerkText1 As String = Session("ORG_Tekeningtekst")
                    Dim strWatermerkText2 As String = Format(Now, "dd-MM-yyyy")
                    Dim strWatermerkText3 As String = Session("VolNaam")

                    Content.SetColorFill(BaseColor.RED)
                    Content.BeginText()
                    Content.ShowTextAligned(PdfContentByte.ALIGN_LEFT, strWatermerkText3, 60, 160, 0.0F)
                    Content.ShowTextAligned(PdfContentByte.ALIGN_LEFT, strWatermerkText2, 60, 185, 0.0F)
                    Content.ShowTextAligned(PdfContentByte.ALIGN_LEFT, strWatermerkText1, 60, 210, 0.0F)
                    Content.EndText()

                    '// Close the layer
                    Content.EndLayer()                
                Next

                pdfs.Close()
                StoreToDatabase(ms, intTekID)

            End Using
        Next item

        imgPubliceerTekening.ClientVisible = False
        gridTekeningen.DataBind()

    Catch ex As Exception

    End Try
End Sub

使其可运行

我通过删除所有数据库和会话对象访问使您的示例独立且可运行。此外,我将它翻译成 C#,这对我来说更自然。作为图像,我使用了我们各自的 Whosebug 头像,作为文本,您的代码从中导出字符串值的会话对象键或格式字符串:

void AddStamps(string OrigFile, string ResultFile)
{
    Document document = new Document();

    using (MemoryStream ms = new MemoryStream())
    {
        PdfReader pdfr = new PdfReader(OrigFile);
        PdfStamper pdfs = new PdfStamper(pdfr, ms);

        Image image__1 = Image.GetInstance(new System.Uri("https://www.gravatar.com/avatar/6bc6e4a08a5683b6f4ef8a8eb5117114?s=48&d=identicon&r=PG"));
        Image image__2 = Image.GetInstance(new System.Uri("https://www.gravatar.com/avatar/53d3aae5c986ca57f01016f5e0be82de?s=32&d=identicon&r=PG&f=1"));
        Rectangle rect;

        int PageCount = pdfr.NumberOfPages;
        PdfContentByte content;
        for (int x = 1; x <= PageCount; x++)
        {
            rect = pdfr.GetPageSize(x);
            content = pdfs.GetOverContent(x);

            image__1.SetAbsolutePosition(50.0F, 50.0F);
            image__1.ScalePercent(30.0F, 30.0F);
            image__2.SetAbsolutePosition(100.0F, 100.0F);
            image__2.ScalePercent(30.0F, 30.0F);
            content.AddImage(image__1);
            content.AddImage(image__2);
            PdfLayer layer = new PdfLayer("Goedkeurlaag", pdfs.Writer);
            content.BeginLayer(layer);
            content.SetFontAndSize(BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED), 20);

            String strWatermerkText1 = "ORG_Tekeningtekst";
            String strWatermerkText2 = "dd-MM-yyyy";
            String strWatermerkText3 = "VolNaam";

            content.SetColorFill(BaseColor.RED);
            content.BeginText();
            content.ShowTextAligned(PdfContentByte.ALIGN_LEFT, strWatermerkText3, 60, 160, 0.0F);
            content.ShowTextAligned(PdfContentByte.ALIGN_LEFT, strWatermerkText2, 60, 185, 0.0F);
            content.ShowTextAligned(PdfContentByte.ALIGN_LEFT, strWatermerkText1, 60, 210, 0.0F);
            content.EndText();

            content.EndLayer();
        }

        pdfs.Close();
        File.WriteAllBytes(ResultFile, ms.ToArray());
    }
}

运行它

将此方法应用于您的 sample file 结果如下所示:

即在每一页上都清晰可见以下标记:

因此

由于您的示例文档上的图章清晰可见,并且此处 VB 到 C# 的翻译相当忠实,因此问题是由您未提及的某些因素引起的,例如

  • 发生一些异常(可能是在数据库访问期间或由于数据库或会话返回的某些 null 值),您使用

    忽略了这些异常
    Catch ex As Exception
    
    End Try
    

    空捕获块。

  • 你的图片是完全透明的,你的文字是空的。

一般

So it must be under the word text somewhere.

如果您向 pdfs.GetOverContent(x) 添加内容,它会添加到该页面的现有内容之后,并且由于 PDF 不知道 z 轴,因此以后绘制的任何内容都会覆盖之前绘制的内容。您的新内容只能被

覆盖
  • 稍后添加更新的内容或
  • 注释内容,因为按规范的所有注释都在所有常规内容之上。

(当然也可以离屏...)

查看新示例文档

同时,OP 提供了一个不同的示例文档,并且将上面的代码应用于它确实不会产生可见的标记。

但是原因上面已经提示了:

Or, of course, it can be off-screen...

OP 的代码隐含地假定坐标系原点位于页面的左下角。虽然这种情况经常发生,但并非必须如此!

OP 的代码已经获取了页面的媒体框:

rect = pdfr.GetPageSize(x)

检查手头文件的媒体框,左下角是(0, -836.64001),右上角是(1207.68005, 0)。因此,原点位于左上角,OP 使用的所有坐标都在可见页面上方 .

如果将上面 C# 代码中的相应行替换为:

image__1.SetAbsolutePosition(rect.Left + 50.0F, rect.Bottom + 50.0F);
...
image__2.SetAbsolutePosition(rect.Left + 100.0F, rect.Bottom + 100.0F);
...
content.ShowTextAligned(PdfContentByte.ALIGN_LEFT, strWatermerkText3, rect.Left + 60, rect.Bottom + 160, 0.0F);
content.ShowTextAligned(PdfContentByte.ALIGN_LEFT, strWatermerkText2, rect.Left + 60, rect.Bottom + 185, 0.0F);
content.ShowTextAligned(PdfContentByte.ALIGN_LEFT, strWatermerkText1, rect.Left + 60, rect.Bottom + 210, 0.0F);

再次获得想要的邮票: