iTextSharp Adding Background Color to Watermark Text - vb.net

I am adding watermark text to PDFs in a class library I have created. The code I posted below works fine, however the watermark is sometimes difficult to read because it overlays with content on the PDF. How would I go about adding a white background color around the watermark text? I basically would like the watermark text to be surrounded inside a white rectangle the size of the text. Thanks
Public Function AddWatermarkText(ByVal tempDirectory As String) As String
' Just return the full path of the PDF if we don't need to add a watermark.
If Me.Document.RevRank <> 0 OrElse Me.Document.ReleaseDate Is Nothing Then Return Me.FullPath
Dim reader As iTextSharp.text.pdf.PdfReader = Nothing
Dim stamper As iTextSharp.text.pdf.PdfStamper = Nothing
Dim gstate As New iTextSharp.text.pdf.PdfGState()
Dim overContent As iTextSharp.text.pdf.PdfContentByte = Nothing
Dim rect As iTextSharp.text.Rectangle = Nothing
Dim watermarkFont As iTextSharp.text.pdf.BaseFont = Nothing
Dim folderGuid As Guid = Guid.NewGuid()
Dim outputFile As String = tempDirectory & System.IO.Path.DirectorySeparatorChar & folderGuid.ToString() & System.IO.Path.DirectorySeparatorChar _
& Me.Document.Prefix & Me.Document.BaseNumber & Me.Document.Revision & ".pdf"
' Create the temp directory to place the new PDF in.
If Not My.Computer.FileSystem.DirectoryExists(tempDirectory) Then My.Computer.FileSystem.CreateDirectory(tempDirectory)
My.Computer.FileSystem.CreateDirectory(tempDirectory & System.IO.Path.DirectorySeparatorChar & folderGuid.ToString())
reader = New iTextSharp.text.pdf.PdfReader(Me.FullPath)
rect = reader.GetPageSizeWithRotation(1)
stamper = New iTextSharp.text.pdf.PdfStamper(reader, New System.IO.FileStream(outputFile, IO.FileMode.Create))
watermarkFont = iTextSharp.text.pdf.BaseFont.CreateFont(iTextSharp.text.pdf.BaseFont.HELVETICA_BOLD, _
iTextSharp.text.pdf.BaseFont.CP1252, _
iTextSharp.text.pdf.BaseFont.NOT_EMBEDDED)
gstate.FillOpacity = 0.9F
gstate.StrokeOpacity = 1.0F
' Add the watermark to each page in the document.
For i As Integer = 1 To reader.NumberOfPages()
overContent = stamper.GetOverContent(i)
With overContent
.SaveState()
.SetGState(gstate)
.SetColorFill(iTextSharp.text.BaseColor.BLUE)
.Fill()
.BeginText()
.SetFontAndSize(watermarkFont, 8)
.SetTextMatrix(30, 30)
If Me.Document.RevRank = 0 AndAlso Me.Document.ReleaseDate IsNot Nothing Then
.ShowTextAligned(iTextSharp.text.Element.ALIGN_LEFT, UCase(String.Format("CONTROLLED DOCUMENT – THIS COPY IS THE LATEST REVISION AS OF {0}" _
, Date.Now.ToString("ddMMMyyyy"))), 10, rect.Height - 15, 0)
End If
.Fill()
.EndText()
.RestoreState()
End With
Next
stamper.Close()
reader.Close()
Return outputFile
End Function

I usually like to have code that you can just plop in but unfortunately you're code is a little too domain-specific to provide a direct answer (lots of Me.* that we have to guess at) but I can still get you there with a little code refactoring.
To do what you want to do you have to measure the string that you are drawing and then draw a rectangle to those dimensions. The PDF spec doesn't have a concept of "background color" for text and any implementation that makes it look like it does is really just drawing rectangles for you. (Yes, you can highlight text but that's an Annotation which is different.)
So first I'm going to pull things out into variables so that we can reuse and adjust them easier:
''//Text to measure and draw
Dim myText As String = UCase(String.Format("CONTROLLED DOCUMENT – THIS COPY IS THE LATEST REVISION AS OF {0}", Date.Now.ToString("ddMMMyyyy")))
''//Font size to measure and draw with
Dim TextFontSize As Integer = 8
''//Original X,Y positions that we were drawing the text at
Dim TextX As Single = 10
Dim TextY As Single = rect.Height - 15
Next we need to calculate the width and height. The former is easy but the latter requires us to first get the Ascent and Descent of the text and then calculate the difference.
''//Calculate the width
Dim TextWidth As Single = watermarkFont.GetWidthPoint(myText, TextFontSize)
''//Calculate the ascent and decent
Dim TextAscent As Single = watermarkFont.GetAscentPoint(myText, TextFontSize)
Dim TextDescent As Single = watermarkFont.GetDescentPoint(myText, TextFontSize)
''//The height is the difference between the two
Dim TextHeight As Single = TextAscent - TextDescent
(NOTE: I'm not sure if GetWidthPoint(), GetAscentPoint() and GetDescentPoint() work as desired with multi-line text.)
Then you probably want to have some padding between the box and text:
''//Amount of padding around the text when drawing the box
Dim TextPadding As Single = 2
Lastly, somewhere before you setup and draw the text you want to first draw the rectangle:
''//Set a background color
.SetColorFill(BaseColor.YELLOW)
''//Create a rectangle
.Rectangle(TextX - TextPadding, TextY - TextPadding, TextWidth + (TextPadding * 2), TextHeight + (TextPadding * 2))
''//Fill it
.Fill()

Related

How can I copy a graphic drawn on a PictureBox to clipboard?

I have a software that builds a 3D text by using grafx.DrawString() and I need to copy this graphic to clipboard. When I try to do so, it throws a NullReferenceException.
How can I copy the graphics drawn on a PictureBox?
This is the code to draw the text:
Dim grafx As Graphics
Private Sub draw_block_text10()
Dim text_size As SizeF
Dim back_brush As Brush = Brushes.Black 'COLOR FOR THE BOARDER TEXT
Dim fore_brush As Brush = Brushes.Blue 'COLOR FOR THE MAIN TEXT
Dim fnt As New Font("Microsoft Sans Serif", NumericUpDown1.Value, FontStyle.Regular)
Dim location_x, location_y As Single 'USED IT FOR THE LOCATION
Dim i As Integer
'CREATE A GRAPHIC OBJECT IN THE PICTUREBOX.
grafx = Me.PictureBox2.CreateGraphics()
'CLEAR THE PICTUREBOX
grafx.Clear(Color.White)
'LOOK THE REQUIRED SIZE TO DRAW THE TEXT
text_size = grafx.MeasureString(Me.TextBox1.Text, fnt)
'ELIMINATE THE REDUNDANT CAlCULATION AFTER GETTING THE LOCATION.
location_x = (Me.PictureBox2.Width - text_size.Width) / 2
location_y = (Me.PictureBox2.Height - text_size.Height) / 2
'FIRST, DRAW THE BLACK BACKGROUND TO GET THE EFFECT,
'AND THE TEXT MUST BE DRAWN REAPETEDLY FROM THE OFFSET RIGHT, UP TO THE MAIN TEXT IS DRAWN.
For i = CInt(nupDepth.Value) To 0 Step -1
grafx.DrawString(TextBox1.Text, fnt, back_brush, _
location_x - i, location_y + i)
Next
Dim mydataandtimeforsave = DateTime.Now.ToString("yyyyMMddHHmmss")
'DRAW THE ROYAL BLUE FOR THE MAIN TEXT OVER THE BLACk TEXT
grafx.DrawString(TextBox1.Text, fnt, fore_brush, location_x, location_y)
Dim bmp As New Bitmap(Me.PictureBox2.Width, Me.PictureBox2.Height)
Dim g As Graphics = Graphics.FromImage(bmp)
g.Clear(Color.Transparent)
''Perform Drawing here
End Sub
This is the code to copy to clipboard:
Clipboard.SetDataObject( _
DirectCast(PictureBox2.Image.Clone, Bitmap), _
True)
Beep()
Using a Graphics object created from a PictureBox control (PictureBox.CreateGraphics()) to draw on doesn't actually set/change the Image property of the PictureBox. You can confirm that by checking for PictureBox2.Image Is Nothing, which will return true if the PictureBox had no image before drawing on it.
Instead, create an Image with the dimensions of the PictureBox, use Graphics.FromImage() to create your Graphics object, draw what you need to draw, and then assign the image to the PictureBox.Image property.
Something like this should work fine:
Dim bmp As New Bitmap(PictureBox2.Width, PictureBox2.Height)
Using g As Graphics = Graphics.FromImage(bmp)
g.Clear(Color.White)
text_size = g.MeasureString(Me.TextBox1.Text, fnt)
location_x = (Me.PictureBox2.Width - text_size.Width) / 2
location_y = (Me.PictureBox2.Height - text_size.Height) / 2
For i = CInt(nupDepth.Value) To 0 Step -1
g.DrawString(TextBox1.Text, fnt, back_brush, location_x - i, location_y + i)
Next
g.DrawString(TextBox1.Text, fnt, fore_brush, location_x, location_y)
End Using
PictureBox2.Image = bmp
Note: Always remember to dispose the created Graphics object when you finish using it either by calling .Dispose() or by wrapping it in a Using statement like what I did above.
Instead of
Clipboard.SetDataObject(DirectCast(PictureBox2.Image.Clone, Bitmap), True)
Use
Clipboard.SetDataObject(PictureBox2.Image, 2)

How to auto align and adjust text in VB.net that getting converted to Image

I was trying with a code that coverts Text to Image using Vb.net and my problem is I need to accept a message from user (Max 160 Characters) by a text box and i need to convert it to a Image. The generated image should be aligned in the middle and the image max resolution should be 800x600.
So the message should be neatly aligned in new lines if needed and perfectly aligned to the middle.
The code I am trying is as follows:
======================================================
Try
Dim Text As String = TextBox3.Text
Dim FontColor As Color = Color.Blue
Dim BackColor As Color = Color.White
Dim FontName As String = "Times New Roman"
Dim FontSize As Integer = 36
Dim Height As Integer = 60
Dim Width As Integer = 200
Dim daten As String
daten = Now.ToString("ddMMyyyyhhmmss")
Dim FileName As String = daten
Dim objBitmap As New Bitmap(Width, Height)
Dim objGraphics As Graphics = Graphics.FromImage(objBitmap)
Dim objColor As Color
objColor = Nothing
Dim objFont As New Font(FontName, FontSize)
'Following PointF object defines where the text will be displayed in the
'specified area of the image
Dim objPoint As New PointF(5.0F, 5.0F)
Dim objBrushForeColor As New SolidBrush(FontColor)
Dim objBrushBackColor As New SolidBrush(BackColor)
objGraphics.FillRectangle(objBrushBackColor, 0, 0, Width, Height)
objGraphics.DrawString(Text, objFont, objBrushForeColor, objPoint)
objBitmap.Save("D:\DNB\" + daten + ".JPG", ImageFormat.Jpeg)
PictureBox1.Image = Image.FromFile("D:\DNB\" + daten + ".JPG")
Catch ex As Exception
End Try
Have you tried the MeasureString function of the Graphics object and it's various overrides? With that you can measure how much space a text in a given size and font needs on the screen. With that knowledge you can calculate the upper left point to use to make the text appear centered.

how to highlight a text or word in a pdf file using iTextsharp?

I need to search a word in a existing pdf file and i want to highlight the text or word
and save the pdf file
I have an idea using PdfAnnotation.CreateMarkup we could find the position of the text and we can add bgcolor to it...but i dont know how to implement it :(
Please help me out
This is one of those "sounds easy but is actually really complicated" things. See Mark's posts here and here. Ultimately you'll probably be pointed to LocationTextExtractionStrategy. Good luck! If you actually find out how to do it post it here, there several people wondering exactly what you are wondering!
I've found how to do this, just in case someone needs to get words or sentences with locations (coordinates) from a PDF document you'll find this example Project
HERE
, I used VB.NET 2010 for this. Remember to add a reference to your iTextSharp DLL in this Project.
I added my own TextExtraction Strategy Class, based on Class LocationTextExtractionStrategy. I focused on TextChunks, because they already have these coordinates.
There are some known limitations like:
No multiple line searches (phrases), just char/s or word's or a one line sentence are allowed.
It Won't work with rotated text.
I didn't test on PDFs with landscape page orientation but i assume some modifications may be required for this.
In case you need to draw this HighLight/rectangles over a watermark you'll need to add/modify some code, but just code in the Form, this is not related to the text/locations extraction proccess.
#Jcis, I actually managed a workaround for handling multiple searches using your example as a starting point. I use your project as a reference in a c# project, and altered what it does. Instead of just highlighting I actually have it drawing a white rectangle around the search term, and then using the rectangle coordinates, place a form field. I also had to swap the contentbyte writing mode to getovercontent so that I block out the searched text entirely. What I actually did was to create a string array of search terms, and then using a for loop, I create as many different text fields as I need.
Test.Form1 formBuilder = new Test.Form1();
string[] fields = new string[] { "%AccountNumber%", "%MeterNumber%", "%EmailFieldHolder%", "%AddressFieldHolder%", "%EmptyFieldHolder%", "%CityStateZipFieldHolder%", "%emptyFieldHolder1%", "%emptyFieldHolder2%", "%emptyFieldHolder3%", "%emptyFieldHolder4%", "%emptyFieldHolder5%", "%emptyFieldHolder6%", "%emptyFieldHolder7%", "%emptyFieldHolder8%", "%SiteNameFieldHolder%", "%SiteNameFieldHolderWithExtraSpace%" };
//int a = 0;
for (int a = 0; a < fields.Length; )
{
string[] fieldNames = fields[a].Split('%');
string[] fieldName = Regex.Split(fieldNames[1], "Field");
formBuilder.PDFTextGetter(fields[a], StringComparison.CurrentCultureIgnoreCase, htmlToPdf, finalhtmlToPdf, fieldName[0]);
File.Delete(htmlToPdf);
System.Array.Clear(fieldNames, 0, 2);
System.Array.Clear(fieldName, 0, 1);
a++;
if (a == fields.Length)
{
break;
}
string[] fieldNames1 = fields[a].Split('%');
string[] fieldName1 = Regex.Split(fieldNames1[1], "Field");
formBuilder.PDFTextGetter(fields[a], StringComparison.CurrentCultureIgnoreCase, finalhtmlToPdf, htmlToPdf, fieldName1[0]);
File.Delete(finalhtmlToPdf);
System.Array.Clear(fieldNames1, 0, 2);
System.Array.Clear(fieldName1, 0, 1);
a++;
}
It bounces the PDFTextGetter function in your example back and forth between two files until I achieve the finished product. It works really well, and it would not have been possible without your initial project, so thank you for that. I also altered your VB to do the text field mapping like so;
For Each rect As iTextSharp.text.Rectangle In MatchesFound
cb.Rectangle(rect.Left, rect.Bottom + 1, rect.Width, rect.Height + 4)
Dim field As New TextField(stamper.Writer, rect, FieldName & Fields)
Dim form = stamper.AcroFields
Dim fieldKeys = form.Fields.Keys
stamper.AddAnnotation(field.GetTextField(), page)
Fields += 1
Next
Just figured I would share what I managed to do with your project as a backbone. It even increments the field names as I need them to. I also had to add a new parameter to your function, but that's not worth listing here. Thank you again for this great head start.
Thanks Jcis!
After a couple of hours of research and thinking, i found your solution, which helped me to solve my Problems.
there were 2 little bugs.
first: the stamper needs to be closed before the reader, otherwise it throws an exception.
Public Sub PDFTextGetter(ByVal pSearch As String, ByVal SC As StringComparison, ByVal SourceFile As String, ByVal DestinationFile As String)
Dim stamper As iTextSharp.text.pdf.PdfStamper = Nothing
Dim cb As iTextSharp.text.pdf.PdfContentByte = Nothing
Me.Cursor = Cursors.WaitCursor
If File.Exists(SourceFile) Then
Dim pReader As New PdfReader(SourceFile)
stamper = New iTextSharp.text.pdf.PdfStamper(pReader, New System.IO.FileStream(DestinationFile, FileMode.Create))
PB.Value = 0 : PB.Maximum = pReader.NumberOfPages
For page As Integer = 1 To pReader.NumberOfPages
Dim strategy As myLocationTextExtractionStrategy = New myLocationTextExtractionStrategy
'cb = stamper.GetUnderContent(page)
cb = stamper.GetOverContent(page)
Dim state As New PdfGState()
state.FillOpacity = 0.3F
cb.SetGState(state)
'Send some data contained in PdfContentByte, looks like the first is always cero for me and the second 100, but i'm not sure if this could change in some cases
strategy.UndercontentCharacterSpacing = cb.CharacterSpacing
strategy.UndercontentHorizontalScaling = cb.HorizontalScaling
'It's not really needed to get the text back, but we have to call this line ALWAYS,
'because it triggers the process that will get all chunks from PDF into our strategy Object
Dim currentText As String = PdfTextExtractor.GetTextFromPage(pReader, page, strategy)
'The real getter process starts in the following line
Dim MatchesFound As List(Of iTextSharp.text.Rectangle) = strategy.GetTextLocations(pSearch, SC)
'Set the fill color of the shapes, I don't use a border because it would make the rect bigger
'but maybe using a thin border could be a solution if you see the currect rect is not big enough to cover all the text it should cover
cb.SetColorFill(BaseColor.PINK)
'MatchesFound contains all text with locations, so do whatever you want with it, this highlights them using PINK color:
For Each rect As iTextSharp.text.Rectangle In MatchesFound
' cb.Rectangle(rect.Left, rect.Bottom, rect.Width, rect.Height)
cb.SaveState()
cb.SetColorFill(BaseColor.YELLOW)
cb.Rectangle(rect.Left, rect.Bottom, rect.Width, rect.Height)
cb.Fill()
cb.RestoreState()
Next
'cb.Fill()
PB.Value = PB.Value + 1
Next
stamper.Close()
pReader.Close()
End If
Me.Cursor = Cursors.Default
End Sub
second: your solution dont work, when the searched text is in the last line of the extraced text.
Public Function GetTextLocations(ByVal pSearchString As String, ByVal pStrComp As System.StringComparison) As List(Of iTextSharp.text.Rectangle)
Dim FoundMatches As New List(Of iTextSharp.text.Rectangle)
Dim sb As New StringBuilder()
Dim ThisLineChunks As List(Of TextChunk) = New List(Of TextChunk)
Dim bStart As Boolean, bEnd As Boolean
Dim FirstChunk As TextChunk = Nothing, LastChunk As TextChunk = Nothing
Dim sTextInUsedChunks As String = vbNullString
' For Each chunk As TextChunk In locationalResult
For j As Integer = 0 To locationalResult.Count - 1
Dim chunk As TextChunk = locationalResult(j)
If chunk.text.Contains(pSearchString) Then
Thread.Sleep(1)
End If
If ThisLineChunks.Count > 0 AndAlso (Not chunk.SameLine(ThisLineChunks.Last) Or j = locationalResult.Count - 1) Then
If sb.ToString.IndexOf(pSearchString, pStrComp) > -1 Then
Dim sLine As String = sb.ToString
'Check how many times the Search String is present in this line:
Dim iCount As Integer = 0
Dim lPos As Integer
lPos = sLine.IndexOf(pSearchString, 0, pStrComp)
Do While lPos > -1
iCount += 1
If lPos + pSearchString.Length > sLine.Length Then Exit Do Else lPos = lPos + pSearchString.Length
lPos = sLine.IndexOf(pSearchString, lPos, pStrComp)
Loop
'Process each match found in this Text line:
Dim curPos As Integer = 0
For i As Integer = 1 To iCount
Dim sCurrentText As String, iFromChar As Integer, iToChar As Integer
iFromChar = sLine.IndexOf(pSearchString, curPos, pStrComp)
curPos = iFromChar
iToChar = iFromChar + pSearchString.Length - 1
sCurrentText = vbNullString
sTextInUsedChunks = vbNullString
FirstChunk = Nothing
LastChunk = Nothing
'Get first and last Chunks corresponding to this match found, from all Chunks in this line
For Each chk As TextChunk In ThisLineChunks
sCurrentText = sCurrentText & chk.text
'Check if we entered the part where we had found a matching String then get this Chunk (First Chunk)
If Not bStart AndAlso sCurrentText.Length - 1 >= iFromChar Then
FirstChunk = chk
bStart = True
End If
'Keep getting Text from Chunks while we are in the part where the matching String had been found
If bStart And Not bEnd Then
sTextInUsedChunks = sTextInUsedChunks & chk.text
End If
'If we get out the matching String part then get this Chunk (last Chunk)
If Not bEnd AndAlso sCurrentText.Length - 1 >= iToChar Then
LastChunk = chk
bEnd = True
End If
'If we already have first and last Chunks enclosing the Text where our String pSearchString has been found
'then it's time to get the rectangle, GetRectangleFromText Function below this Function, there we extract the pSearchString locations
If bStart And bEnd Then
FoundMatches.Add(GetRectangleFromText(FirstChunk, LastChunk, pSearchString, sTextInUsedChunks, iFromChar, iToChar, pStrComp))
curPos = curPos + pSearchString.Length
bStart = False : bEnd = False
Exit For
End If
Next
Next
End If
sb.Clear()
ThisLineChunks.Clear()
End If
ThisLineChunks.Add(chunk)
sb.Append(chunk.text)
Next
Return FoundMatches
End Function

Detect width of text in vb.net

Is there a way to detect the actual width of text in a vb.net web app? It needs to be dependant upon its font-style and size.
In vb6 you could copy the text into a label and make it expand to fit then measure its width, but this won't work in vb.net.
Update: On further inspection, TextRenderer.MeasureText seems a better option:
Dim text1 As String = "Measure this text"
Dim arialBold As New Font("Arial", 12.0F)
Dim textSize As Size = TextRenderer.MeasureText(text1, arialBold)
See Graphics.MeasureString:
Measures the specified string when
drawn with the specified Font.
Dim myFontBold As New Font("Microsoft Sans Serif", 10, FontStyle.Bold)
Dim StringSize As New SizeF
StringSize = e.Graphics.MeasureString("How wide is this string?", myFontBold)
i have just recently done this in one of my projects here is how i did it
Dim textsize As Size = TextRenderer.MeasureText(cbx_Email.Text, cbx_Email.Font)
cbx_Email.Width = textsize.Width + 17
this is in a combobox.SelectedIndex changed sub.
The +17 is for the pixels that the dropdown arrow takes up in a combobox so it doesntcover text.
by using control.font it allows the code to dynamically change no matter what font is being used. Using Control.Text means you can use this on anything and wont have to change the code when changing the text of the control or page.
I wrote this low-end function to do just that without higher-level API's.
It creates a bitmap and graphics object, writes the string to the bitmap, scans backwards for the font edge and then returns the width in pixels
Private Function FontLengthInPixels(inputString As String, FontStyle As Font) As Integer
' Pick a large, arbitrary number for the width (500) in my case
Dim bmap As New Bitmap(500, 100)
Dim g As Graphics = Graphics.FromImage(bmap)
g.FillRectangle(Brushes.Black, bmap.GetBounds(GraphicsUnit.Pixel))
g.DrawString(inputString, FontStyle, Brushes.White, New Point(0, 0))
' Scan backwards to forwards, since we know the first pixel location is 0,0; we need to find the LAST and subtract
' the bitmap width from it to find the width.
For x = -(bmap.Width - 1) To -1
' Scan from the 5th pixel to the 10th, we'll find something within that range!
For y = 5 To 10
Dim col As Color = bmap.GetPixel(Math.Abs(x), y)
' Look for white (ignore alpha)
If col.R = 255 And col.G = 255 And col.B = 255 Then
Return Math.Abs(x) ' We got it!
End If
Next
Next
' Lets do this approx
Return 0
End Function

itextsharp: how do i place an image all the way at the bottom?

i have an image that i just want to place all the way at the bottom of the page. how do i do this?
'Set these as needed
Dim DocumentWidth = 1000
Dim DocumentHeight = 1000
Dim ImagePath = "c:\test.jpg"
Dim ImageWidth As Integer
Dim ImageHeight As Integer
Using Img = System.Drawing.Image.FromFile(ImagePath)
ImageWidth = Img.Width
ImageHeight = Img.Height
End Using
'Create the document
Dim D As New Document()
'Set the page size
D.SetPageSize(New iTextSharp.text.Rectangle(0, 0, DocumentWidth, DocumentHeight))
'Zero the margins
D.SetMargins(0, 0, 0, 0)
'Create and open the PDF writer
Dim W = PdfWriter.GetInstance(D, New System.IO.FileStream("C:\test.pdf", IO.FileMode.Create, IO.FileAccess.Write, IO.FileShare.Read))
D.Open()
'Make a new image object
Dim I As New iTextSharp.text.Jpeg(New Uri("file:///" & ImagePath))
'Lower left is (0,0), upper right is (1000,1000)
I.SetAbsolutePosition(DocumentWidth - ImageWidth, 0)
'Add the image
D.Add(I)
D.Close()
place it at the top of the page upside down, and flip the page.
edit:
sorry, i was half kidding. there's an example here of positioning an image using the Image.setAbsolutePosition method. You should be able to calculate the parameters to supply to this function based on the size of the image and the size of the document you're working with.