Extract Images with text from PDF and Edit it using iTextSharp - vb.net

I am trying to do following things in Windows Forms
1) Read a PDF in Windows Forms
2) Get the Images with Text in it
3) Color / fill the Image
4) save everything to a new file
I have tried Problem with PdfTextExtractor in itext!
But It didn't help.
Here is the code I've tried:
Public Shared Sub ExtractImagesFromPDF(sourcePdf As String, outputPath As String)
'NOTE: This will only get the first image it finds per page.'
Dim pdf As New PdfReader(sourcePdf)
Dim raf As RandomAccessFileOrArray = New iTextSharp.text.pdf.RandomAccessFileOrArray(sourcePdf)
Try
For pageNumber As Integer = 1 To pdf.NumberOfPages
Dim pg As PdfDictionary = pdf.GetPageN(pageNumber)
' recursively search pages, forms and groups for images.'
Dim obj As PdfObject = FindImageInPDFDictionary(pg)
If obj IsNot Nothing Then
Dim XrefIndex As Integer = Convert.ToInt32(DirectCast(obj, PRIndirectReference).Number.ToString(System.Globalization.CultureInfo.InvariantCulture))
Dim pdfObj As PdfObject = pdf.GetPdfObject(XrefIndex)
Dim pdfStrem As PdfStream = DirectCast(pdfObj, PdfStream)
Dim bytes As Byte() = PdfReader.GetStreamBytesRaw(DirectCast(pdfStrem, PRStream))
If (bytes IsNot Nothing) Then
Using memStream As New System.IO.MemoryStream(bytes)
memStream.Position = 0
Dim img As System.Drawing.Image = System.Drawing.Image.FromStream(memStream)
' must save the file while stream is open.'
If Not Directory.Exists(outputPath) Then
Directory.CreateDirectory(outputPath)
End If
Dim path__1 As String = Path.Combine(outputPath, [String].Format("{0}.jpg", pageNumber))
Dim parms As New System.Drawing.Imaging.EncoderParameters(1)
parms.Param(0) = New System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Compression, 0)
'Dim jpegEncoder As System.Drawing.Imaging.ImageCodecInfo = iTextSharp.text.Utilities.GetImageEncoder("JPEG")'
img.Save(path__1) 'jpegEncoder, parms'
End Using
End If
End If
Next
Catch
Throw
Finally
pdf.Close()
raf.Close()
End Try
End Sub
Now, the actual purpose of this is to get something like this
If this is the actual PDF, I will have to check if there any any items in that bin(by Text in that box)
If there are items then I have to color it like below
Can someone help me with this
The PDF can be retrieved here.

Related

AxWMPlib: How to load playlist from an external file

I am making a media player application using AXWMPlib which has a playlist.
what i successfully able to do was saving the playlist items in a text file.
below is the code for saving:
If SavePlaylist.ShowDialog = Windows.Forms.DialogResult.OK Then
Dim writefile As New System.IO.StreamWriter(SavePlaylist.FileName)
For i = 0 To lstview.Items.Count - 2
writefile.WriteLine(Form1.main.AxWMP1.currentPlaylist.Item(i).sourceURL)
Next
writefile.Write(Form1.main.AxWMP1.currentPlaylist.Item(Form1.main.AxWMP1.currentPlaylist.count - 1).sourceURL)
writefile.Close()
End If
for loading i wrote till here:
If OpenPlaylist.ShowDialog = Windows.Forms.DialogResult.OK Then
Dim readfile As New System.IO.StreamReader(OpenPlaylist.FileName)
Dim ob As String = readfile.ReadToEnd()
Dim content() As String = OpenPlaylist.FileName.Split(Environment.NewLine)
End If
i dont know how to read the lines stored in current() and append them in current playlist.
found a solution:
If Open.ShowDialog = Windows.Forms.DialogResult.OK Then
Dim readfile As New System.IO.StreamReader(Open.FileName)
Dim ob As String = readfile.ReadToEnd()
Dim content() As String = ob.Split(Environment.NewLine)
For Each Line As String In content
Dim item As IWMPMedia = Form1.AxWMP1.newMedia(Line)
Form1.AxWMP1.currentPlaylist.appendItem(item)
Next
End If

VB.NET writing comments to jpeg file programmatically

I searched stackoverflow and I realized that GetPropertyItem and SetPropertyItem can edit comments in JPEG file
Dim images As Image = System.Drawing.Image.FromFile("C:\\Sample.jpeg")
Dim MSGF As New ArrayList
Dim ID() As String = {"hello ","i am here"}
Dim propItem As PropertyItem = images.GetPropertyItem(40092)
Dim encoderParameters As New EncoderParameters(1)
encoderParameters.Param(0) = New EncoderParameter(Encoder.Quality, 100L)
For i = 0 To ID.Length - 1
Dim TEMP As String = ID(i)
For II = 0 To TEMP.Length - 1
MSGF.Add(Convert.ToInt32(TEMP(II)))
Next
Next
For i = 0 To MSGF.Count - 1
propItem.Value.SetValue(Convert.ToByte(MSGF(i)), i)
Next
images.SetPropertyItem(propItem)
images.Save(TextBox1.Text & "\" & "1" & TextBox2.Text)
What I realized was I can get comments from jpeg file by GetPropertyItem. However, comments is based on the ascii code. Therefore, I was trying to convert comment that I wanted to insert to ascii code.
propItem.Value.SetValue(Convert.ToByte(MSGF(i)), i)
This part was actually changed comments which already existed in the jpeg file.
However, if there is no comments in jpeg file, propItem.value.setValue doesn't work because there is nothing to edit.
Is there anyway to just add comments to jpeg file?
Based on this answer in C#, it could be as simple as this:
Dim jpeg = New JpegMetadataAdapter(pathToJpeg)
jpeg.Metadata.Comment = "Some comments"
jpeg.Metadata.Title = "A title"
jpeg.Save()
' Saves the jpeg in-place
jpeg.SaveAs(someNewPath)
' Saves with a new path
Here is the class:
Public Class JpegMetadataAdapter
Private ReadOnly path As String
Private frame As BitmapFrame
Public ReadOnly Metadata As BitmapMetadata
Public Sub New(path As String)
Me.path = path
frame = getBitmapFrame(path)
Metadata = DirectCast(frame.Metadata.Clone(), BitmapMetadata)
End Sub
Public Sub Save()
SaveAs(path)
End Sub
Public Sub SaveAs(path As String)
Dim encoder As New JpegBitmapEncoder()
encoder.Frames.Add(BitmapFrame.Create(frame, frame.Thumbnail, Metadata, frame.ColorContexts))
Using stream As Stream = File.Open(path, FileMode.Create, FileAccess.ReadWrite)
encoder.Save(stream)
End Using
End Sub
Private Function getBitmapFrame(path As String) As BitmapFrame
Dim decoder As BitmapDecoder = Nothing
Using stream As Stream = File.Open(path, FileMode.Open, FileAccess.ReadWrite, FileShare.None)
decoder = New JpegBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad)
End Using
Return decoder.Frames(0)
End Function
End Class

Embedded base64String for images is to long for large images?

I am embedding a base64String into Tinymce to display images:
<img src="blob:https://path/871bf236-3bae-472c-9f02-0bd3be19a435" alt="Desert.jpg" width="300" height="75" />
It works for small images but when it comes to large images it doesn't work and I am guessing its because the URL containing the base64String for large images hits the limit for URL browser length which I believe is around 2000 characters. Wanted to see if there was a way to shorten my base64String?
'File path of the attachment
DIM filePath = C:\path\solutions\Attachments\1\1726014c-7a2d-41b8-a79e-2acec1e8c7e0
'Converted base64String path
DIM base64URLPath = ToBase64String( ConvertToUrl(filePath)).toString
'Converts the path to a base64String
Public Function ToBase64String(filePath As String) As String
Dim aImage = New Bitmap(filePath)
Using stream = New IO.MemoryStream
Using img As Image = Image.FromFile(filePath)
If img.RawFormat.Equals(Imaging.ImageFormat.Jpeg) Then
aImage.Save(stream, Imaging.ImageFormat.Jpeg)
ElseIf img.RawFormat.Equals(Imaging.ImageFormat.Png) Then
aImage.Save(stream, Imaging.ImageFormat.Png)
ElseIf img.RawFormat.Equals(Imaging.ImageFormat.Icon) Then
aImage.Save(stream, Imaging.ImageFormat.Icon)
End If
End Using
Return Convert.ToBase64String(stream.ToArray)
End Using
End Function
'Gets the full file path
Public Function ConvertToUrl(filePath As String) As String
Dim uri = New Uri(filePath).LocalPath
Dim converted = uri
Return converted.ToString()
End Function
Based on this post I fixed the issue: Resize and Compress image to byte array without saving the new image. The ToBase64String was the only function changed and now it looks like:
'Converts the path to a base64String
Public Function ToBase64String(filePath As String) As String
Dim aImage = New Bitmap(filePath)
Dim aspectRatio As Double = aImage.Height / aImage.Width
Dim imgThumb = New Bitmap(aImage, 200, CInt(Math.Round(200 * aspectRatio)))
Using stream = New IO.MemoryStream
Using img As Image = Image.FromFile(filePath)
If img.RawFormat.Equals(Imaging.ImageFormat.Jpeg) Then
imgThumb.Save(stream, Imaging.ImageFormat.Jpeg)
ElseIf img.RawFormat.Equals(Imaging.ImageFormat.Png) Then
imgThumb.Save(stream, Imaging.ImageFormat.Png)
ElseIf img.RawFormat.Equals(Imaging.ImageFormat.Icon) Then
imgThumb.Save(stream, Imaging.ImageFormat.Icon)
End If
End Using
Return Convert.ToBase64String(stream.ToArray)
End Using
End Function

VB.NET Return Form Object using Form Name

I'm basically writing a custom Error Logging Form for one of my applications because users cannot be trusted to report the errors to me.
I am obtaining the Form Name using the 'MethodBase' Object and then getting the DeclaringType Name.
Dim st As StackTrace = New StackTrace()
Dim sf As StackFrame = st.GetFrame(1)
Dim mb As MethodBase = sf.GetMethod()
Dim dt As String = mb.DeclaringType.Name
How can I then use this to obtain the Form Object so I can pass this to my 'screenshot method' that screenshots the particular form referenced.
Public Sub SaveAsImage(frm As Form)
'Dim fileName As String = "sth.png"
'define fileName
Dim format As ImageFormat = ImageFormat.Png
Dim image = New Bitmap(frm.Width, frm.Height)
Using g As Graphics = Graphics.FromImage(image)
g.CopyFromScreen(frm.Location, New Point(0, 0), frm.Size)
End Using
image.Save(_LogPath & Date.Now.ToString("ddMMyyyy") & ".png", format)
End Sub
I posted the same solution to a similar question. Try this:
Dim frm = Application.OpenForms.Item(dt)

Loading Picture Stored in Access Database into Program VB.NET

I have an Access Database linked with a VB project through a data source. In the database on one of the tables, I have an OLE Object field. I have saved pictures in .BMP format and .JPG format in this field. The problem I am encountering is loading this image into my application. This is what I would like to be able to do:
ButtonMeal1.BackgroundImage = IPOSDBDataSet.Meals.Rows(0).Item(5)
Where Item(5) is the column of the row where the image is stored.
Is there another way of doing this. Do I have to load the picture into the program by storing it as a variable, and then using that to change the background image of the button. There are no clear answers on the internet regarding my issue. Please help!
EDIT 1:
After doing some more research, I found some code and adjusted it to try fix my problem.
Dim ImageByteArray As Byte() = CType(IPOSDBDataSet.Meals.Rows(0).Item(5), Byte())
Dim ImageMemoryStream As MemoryStream = New IO.MemoryStream(ImageByteArray)
Dim MyImage As Image = Drawing.Image.FromStream(ImageMemoryStream)
PictureBox1.Image = MyImage
However, I receive the error "Parameter is Not Valid" with the 3rd line of the code. Would anyone be able to tell me how I could adjust my code to fix this issue, or tell me if I am doing something completely wrong?
EDIT 2:
I keep on changing the code around, but the error is always "Parameter is not valid.". What parameter is not valid?
EDIT 3:
No matter what I change it to, the error still persists. What is this parameter that is causing all my issues?
Dim ImageByteArray As Byte() = CType(IPOSDBDataSet.Meals.Rows(0).Item(5), Byte())
Dim ImageMemoryStream As MemoryStream = New IO.MemoryStream(ImageByteArray)
Dim ImageStream As Stream = ImageMemoryStream
Dim MyImage As Image = Drawing.Image.FromStream(ImageStream)
PictureBox1.Image = MyImage
EDIT 4:
Can anyone please help? I really need to be able to implement this into my program. Is there any other possible way of storing images in an access database, and importing them into my vb.net program?
Credit goes to TnTinMan from CodeProject for the answer. Hopefully this helps someone else:
Dim ImageByteArray As Byte() = CType(DataSet.Table.Rows(RowNo).Item(ItemNo), Byte())
Dim ImageMemoryStream As MemoryStream = New IO.MemoryStream(GetImageBytesFromOLEField(ImageByteArray))
Dim MyImage As Image = Drawing.Image.FromStream(ImageMemoryStream)
Friend Shared Function GetImageBytesFromOLEField(ByVal oleFieldBytes() As Byte) As Byte()
Dim BITMAP_ID_BLOCK As String = "BM"
Dim JPG_ID_BLOCK As String = ChrW(&HFF).ToString() & ChrW(&HD8).ToString() & ChrW(&HFF).ToString()
Dim PNG_ID_BLOCK As String = ChrW(&H89).ToString() & "PNG" & vbCrLf & ChrW(&H1A).ToString() & vbLf
Dim GIF_ID_BLOCK As String = "GIF8"
Dim TIFF_ID_BLOCK As String = "II*" & ChrW(&H0).ToString()
Dim imageBytes() As Byte
' Get a UTF7 Encoded string version
Dim u7 As System.Text.Encoding = System.Text.Encoding.UTF7
Dim strTemp As String = u7.GetString(oleFieldBytes)
Dim st2 As String = System.Text.Encoding.UTF8.GetString(oleFieldBytes)
' Get the first 300 characters from the string
Dim strVTemp As String = strTemp.Substring(0, 300)
' Search for the block
Dim iPos As Integer = -1
If strVTemp.IndexOf(BITMAP_ID_BLOCK) <> -1 Then
iPos = strVTemp.IndexOf(BITMAP_ID_BLOCK)
ElseIf strVTemp.IndexOf(JPG_ID_BLOCK) <> -1 Then
iPos = strVTemp.IndexOf(JPG_ID_BLOCK)
ElseIf strVTemp.IndexOf(PNG_ID_BLOCK) <> -1 Then
iPos = strVTemp.IndexOf(PNG_ID_BLOCK)
ElseIf strVTemp.IndexOf(GIF_ID_BLOCK) <> -1 Then
iPos = strVTemp.IndexOf(GIF_ID_BLOCK)
ElseIf strVTemp.IndexOf(TIFF_ID_BLOCK) <> -1 Then
iPos = strVTemp.IndexOf(TIFF_ID_BLOCK)
Else
Throw New Exception("Unable to determine header size for the OLE Object")
End If
' From the position above get the new image
If iPos = -1 Then
Throw New Exception("Unable to determine header size for the OLE Object")
End If
imageBytes = New Byte(CInt(oleFieldBytes.LongLength - iPos - 1)) {}
Array.ConstrainedCopy(oleFieldBytes, iPos, imageBytes, 0, oleFieldBytes.Length - iPos)
Return imageBytes
End Function
There isn't really such a thing as an 'image' stored in an Access table, only a binary stream. Therefore, the left hand side of your expression doesn't know that the right hand side is providing an image. You would have to stream the binary stream into a stream in VB.NET, then use System.Graphics methods to make it into a BMP or PNG or whatever. You could assign that object to the button.
still show error: index and length must refer to a location within the string.Parameter name: len