iText stamp image on top not always working

孤街醉人 提交于 2019-12-13 20:06:04

问题


I am using iTextSharp to place an image and some text on every page of a PDF. This works perfectly for some PDF's but not for others. Strangely enough it does not work for instance on a PDF I created with Word 2010's 'Save as pdf' function. I use GetOverContent, which should everything on top.

With Acrobat I can see that my layer has been added. So it must be under the word text somewhere.

How can I set a z-index for my stamp?

And is there a way (tool) to see clearly what objects are in a PDF? I find Acrobat not really helpfull in that regard, but maybe I need training ;-)

Example not working PDF here. (link updated)

Stamping code here, PDF comes from database and is stored in database:

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

回答1:


Making it runnable

I made your example self-contained and runnable by removing all database and session object access. Additionally I translated it to C# which comes more naturally to me. As images I used our respective stackoverflow avatars and as texts the session object keys or format strings from which your code derives the string values:

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

Running it

Applying this method to your sample file the result looks like this:

i.e. on each page the following stamp is clearly visible:

Thus

As the stamp is clearly visible on your sample document and the translation VB to C# here was fairly faithful, the issue is caused by some factor you did not mention, e.g.

  • some exception occurs (probably during database access or due to some null value returned by the database or session) which you ignore with your

    Catch ex As Exception
    
    End Try
    

    empty catch block.

  • your images are completely transparent and your text is empty.

In general

So it must be under the word text somewhere.

If you add content to pdfs.GetOverContent(x), it is added after the existing content of that page, and as PDF does not know a z axis, any content drawn later covers content drawn earlier. Your new content can only be covered by

  • even newer content added later or
  • annotation content because all annotations by specification are above all regular content.

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

Looking at the new sample document

The OP meanwhile has supplied a different sample document, and applying the code above to it indeed does not result in visible stamps.

But the cause has already hinted at above:

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

The OP's code implicitly assumes that the coordinate system origin is in the lower left of the page. While this is often the case, it does not have to be so!

The OP's code already fetches the media box of the page:

rect = pdfr.GetPageSize(x)

Inspecting this media box for the document at hand, one sees that its lower left corner is (0, -836.64001) and its top right corner is (1207.68005, 0). Thus, the origin is in the top left corner and all the coordinates the OP used are above the visible page.

If one replaces the corresponding lines in the C# code above by:

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

one again gets the desired stamps:



来源:https://stackoverflow.com/questions/33898280/itext-stamp-image-on-top-not-always-working

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!