How to Modify a iTextSharp.text.Rectangle Top left position in VB? - vb.net

I am Using itextsharp dll in VB to generate a PDF. In the PDF, need to increase space between rectangle and text. I tried to setmargin and changed the rectangle coordinates, but the space between top rectangle and text is not creating. Please see the attachment.
Below is the code i am using to generate PDF
Dim reader As PdfReader = New PdfReader(tempFile)
Dim size As Rectangle = reader.GetPageSize(1)
Dim AcroAVDoc As Document = New Document(iTextSharp.text.PageSize.A4.Rotate())
AcroAVDoc.SetMargins(0, 0, 0, 0)
Dim FS As FileStream = New FileStream(newFile, FileMode.Create, FileAccess.Write)
Dim writer As PdfWriter = PdfWriter.GetInstance(AcroAVDoc, FS)
AcroAVDoc.Open()
If (SaveDoc) Then
Dim cb As PdfContentByte = writer.DirectContent
Dim bf As BaseFont = BaseFont.CreateFont(BaseFont.TIMES_ROMAN, BaseFont.CP1252, BaseFont.NOT_EMBEDDED)
cb.SetColorFill(BaseColor.BLACK)
cb.SetFontAndSize(bf, 11)
cb.BeginText()
Dim text As String = "HeaderText " + TableData(HeaderText)
''put the alignment And coordinates here
cb.SetTextMatrix(240, 583)
cb.ShowText(text)
cb.EndText()
''create the New page And add it to the pdf
Dim Page As PdfImportedPage = writer.GetImportedPage(reader, 1)
Dim psize As Rectangle = reader.GetPageSizeWithRotation(1)
cb.AddTemplate(Page, 0, -1.0F, 1.0F, 0, 0, psize.Height)
'AcroAVDoc.Save(1, newFile)
End If
AcroAVDoc.Close()
FS.Close()
writer.Close()
reader.Close()

What your code does (if SaveDoc is true) is
creating a new PDF file in newFile with landscape A4 page size,
drawing the string text on its first page, and
drawing the rotated static contents of the first page of the PDF in tempFile on the same first page.
Thus, to modify the position of the text relative to content copied from the other file, you have to adjust the position where you draw the text and/or the position where you draw the imported content.
You set the position of the text you draw by setting the text matrix (translation coordinates only):
cb.SetTextMatrix(240, 583)
You set the position of the imported page content you draw by setting the transformation matrix (full matrix):
cb.AddTemplate(Page, 0, -1.0F, 1.0F, 0, 0, psize.Height)
The second through fifth parameter (0, -1.0F, 1.0F, 0) define a clockwise rotation by 90° around the bottom left corner and the sixth and seventh parameter (0, psize.Height) define an upwards translation. As the rotation around the bottom left corner rotates the content out of the visible page area, that upwards translation is needed to move it back into view.
To tweak the position of the text in relation to the imported page, simply experiment with changing the 240, 583 for the text and/or the 0, psize.Height for the imported page a bit (e.g. plus or minus 10) until it matches your expectation.

Related

Split an Image into different PictureBoxes

I have a Image with size 187x16 which contain 10 smaller Images in a row.
I want split those Images into 10 different PictureBoxes.
Original Image:
Dim fr_bm As New Bitmap(Image.FromFile(AppDomain.CurrentDomain.BaseDirectory & "/images/u/image.gif"))
Dim to_bm As New Bitmap(16, 16)
Dim unitsimagearray(9) As Image
Dim gr As Graphics = Graphics.FromImage(to_bm)
For i As Integer = 0 To 9
Dim fr_rect As New Rectangle(i * 19, 0, 16, 16) '0,19,38,76
Dim to_rect As New Rectangle(0, 0, 16, 16)
gr.DrawImage(fr_bm, to_rect, fr_rect, GraphicsUnit.Pixel)
unitsimagearray(i) = to_bm
Next
u1.Image = unitsimagearray(0)
But the PictureBox shows all the splitted images.
The main problem with your current code is that the destination image (the image containing a slice of the original), is created once but painted many times.
Since the original image has transparent pixels, the result of the painting will be accumulated.
You can see the transparent sections overlapping.
It can be easily corrected, creating a new Bitmap for each slice of the original. You could also re-paint the same image with a transparent color, but this is faster.
In code, I'm assembling all the PictureBox controls that will receive the slices in one array, so you can assign the Image in the same loop that creates the Bitmaps.
You called the first PictureBox u1, so I'm following the same naming convention.
You will dispose of the Bitmap contained in the unitsimagearray when you don't need them anymore or the application closes.
Original Bitmap (.GIF):
Sliced images (2x). Anti-aliasing and transparency are preserved:
Private unitsimagearray(9) As Bitmap
Dim imagePath As String = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "images/u/image.gif")
Dim picBoxes() As PictureBox = {u1, u2, u3, u4, u5, u6, u7, u8, u9, u10}
Using sourceBitmap As Bitmap = Image.FromStream(New MemoryStream(File.ReadAllBytes(imagePath)))
For idx As Integer = 0 To picBoxes.Length - 1
Dim slice As Bitmap = New Bitmap(16, 16, PixelFormat.Format32bppArgb)
Using g As Graphics = Graphics.FromImage(slice)
Dim sourceRect As New Rectangle(idx * 19, 0, 16, 16)
Dim destinationRect As New Rectangle(0, 0, 16, 16)
g.DrawImage(sourceBitmap, destinationRect, sourceRect, GraphicsUnit.Pixel)
unitsimagearray(idx) = slice
picBoxes(idx).Image = unitsimagearray(idx)
End Using
Next
End Using

Arint System.Drawing.Graphics suppose to write/modify the image its attached to?

As you use a graphics object shouldn't the changes occur on the bitmap (source image) at some point? Running the code below I get 5 images that are all identical to the source. 1.bmp, 2.bmp, 3.bmp, 4.bmp, and 5.bmp are identical to "scaleCharacter" except 4 & 5 have higher compression (smaller file size)
Private Function DrawCharacterMenu() As Boolean
Try
'Background
Dim rect As Rectangle = New Rectangle(100, 100, 128, 128)
Graphics.FromImage(Render).FillRectangle(Brushes.Black, rect)
'Scale up sprite
Dim scaleCharacter As Bitmap = ActiveCharacter.img.Clone
Using grDest = Graphics.FromImage(scaleCharacter)
scaleCharacter.Save("1.bmp")
grDest.ScaleTransform(4.0F, 4.0F)
scaleCharacter.Save("2.bmp")
grDest.InterpolationMode = Drawing2D.InterpolationMode.NearestNeighbor
scaleCharacter.Save("3.bmp")
grDest.DrawImage(scaleCharacter, 0, 0)
scaleCharacter.Save("4.bmp")
End Using
scaleCharacter.Save("5.bmp")
'Draw scaled up sprite to rendering
Graphics.FromImage(Render).DrawImage(scaleCharacter, 100, 100)
Catch ex As Exception
addDebugMessage("Error: Mainmenu.DrawCharacterMenu: " & ex.Message)
Return False
End Try
Return True
End Function
I would Expect 1 to be the same as 'scaleCharacter'
2 and beyond to be 4 times larger (32x32 to 128x128)
3 and beyond to have less interpolation (not looked stretched)
The finished 'scaleCharacter' drawn onto the rendering also is identical to the original image...
All your images are the same because technically you never change them.
Graphics.ScaleTransform() changes only the internal "world" matrix used when drawing primitives. ScaleTransform(4.0F, 4.0F) makes the drawing grid 4x wider and 4x taller, but it doesn't change the image itself until you draw something on it. For instance, if you were to draw a 20 x 10 rectangle on your image now it would result in a rectangle 80 x 40 in size.
To resize the actual image you have to create a new bitmap with the scaled size, then draw the old image scaled onto it.
Changing Graphics.InterpolationMode affects only newly drawn objects. Again it doesn't change your image until you draw something on it.
Finally, while grDest.DrawImage(scaleCharacter, 0, 0) does change your image, it draws the same image in the top-left corner (0, 0) of itself, so there is no visible change.
Here's how you can make it work:
Scaling your image:
'Scale factor.
Dim scaleFactor As Single = 4.0F
'Create a new bitmap of the scaled size.
Using scaledBmp As New Bitmap(scaleCharacter.Width * scaleFactor, scaleCharacter.Height * scaleFactor)
Using g As Graphics = Graphics.FromImage(scaledBmp)
'Draw the old image, scaled, onto the new one.
'srcRect: The rectangle specifying which portion of the source image (scaleCharacter) to draw.
' We want the full image so we specify (0, 0, source width, source height).
'destRect: The rectangle specifying where on the destination image (scaledBmp) to draw the source image.
' Since we want to scale it we specify the full destination image (0, 0, dest width, dest height).
Dim srcRect As New Rectangle(0, 0, scaleCharacter.Width, scaleCharacter.Height)
Dim destRect As New Rectangle(0, 0, scaledBmp.Width, scaledBmp.Height)
g.DrawImage(scaleCharacter, destRect, srcRect, GraphicsUnit.Pixel)
'Save the image.
scaledBmp.Save("2.bmp")
End Using
End Using
Scaling your image using Nearest Neighbour interpolation:
'Create a new bitmap of the scaled size.
Using scaledBmp As New Bitmap(scaleCharacter.Width * scaleFactor, scaleCharacter.Height * scaleFactor)
Using g As Graphics = Graphics.FromImage(scaledBmp)
'Set the interpolation mode before drawing.
g.InterpolationMode = Drawing2D.InterpolationMode.NearestNeighbor
'Draw the old image, scaled, onto the new one.
'srcRect: The rectangle specifying which portion of the source image (scaleCharacter) to draw.
' We want the full image so we specify (0, 0, source width, source height).
'destRect: The rectangle specifying where on the destination image (scaledBmp) to draw the source image.
' Since we want to scale it we specify the full destination image (0, 0, dest width, dest height).
Dim srcRect As New Rectangle(0, 0, scaleCharacter.Width, scaleCharacter.Height)
Dim destRect As New Rectangle(0, 0, scaledBmp.Width, scaledBmp.Height)
g.DrawImage(scaleCharacter, destRect, srcRect, GraphicsUnit.Pixel)
'Save the image.
scaledBmp.Save("3.bmp")
End Using
End Using

Graphics.RotateTransform() does not rotate my picture

I have problem with Graphics.RotateTransfrom() with the following code :
Dim newimage As Bitmap
newimage = System.Drawing.Image.FromFile("C:\z.jpg")
Dim gr As Graphics = Graphics.FromImage(newimage)
Dim myFontLabels As New Font("Arial", 10)
Dim myBrushLabels As New SolidBrush(Color.Black)
Dim a As String
'# last 2 number are X and Y coords.
gr.DrawString(MaskedTextBox2.Text * 1000 + 250, myFontLabels, myBrushLabels, 1146, 240)
gr.DrawString(MaskedTextBox2.Text * 1000, myFontLabels, myBrushLabels, 1146, 290)
a = Replace(Label26.Text, "[ mm ]", "")
gr.DrawString(a, myFontLabels, myBrushLabels, 620, 1509)
a = Replace(Label5.Text, "[ mm ]", "")
gr.DrawString(a, myFontLabels, myBrushLabels, 624, 548)
gr.RotateTransform(90.0F)
gr.DrawString(a, myFontLabels, myBrushLabels, 0, 0)
PictureBox1.Image = newimage
I dont know why but my image in pictureBox1 is not rotated. Someone known solution ?
The issue at hand is that the RotateTransform method does not apply to the existing image.
Instead, it applies to the transformation matrix of the graphics object. Basically, the transformation matrix modifies the coordinate system used to add new items.
Try the following :
Dim gfx = Graphics.FromImage(PictureBox1.Image)
gfx.DrawString("Test", Me.Font, Brushes.Red, New PointF(10, 10))
gfx.RotateTransform(45)
gfx.DrawString("Rotate", Me.Font, Brushes.Red, New PointF(10, 10))
The first string is drawn normally, while the second is drawn rotated.
So what you need to do is create a new graphics object, apply your rotation, draw your source image onto the graphics (graphics.DrawImage), and then draw all your text :
' Easy way to create a graphisc object
Dim gfx = Graphics.FromImage(PictureBox1.Image)
gfx.Clear(Color.Black)
gfx.RotateTransform(90) ' Rotate by 90°
gfx.DrawImage(Image.FromFile("whatever.jpg"), New PointF(0, 0))
gfx.DrawString("Test", Me.Font, Brushes.Red, New PointF(10, 10))
gfx.DrawString("Rotate", Me.Font, Brushes.Red, New PointF(10, 10))
But beware of rotation, you'll find that you need to change the coordinates at which you draw your image (Or change the RenderingOrigin property of the graphics, setting it to the center of the image makes it easier to handle rotations), otherwise your picture won't be visible (it will be drawn, but off the visible part of the graphics).
Hope that helps

iTextSharp Adding Background Color to Watermark Text

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

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.