问题
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 yourCatch 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