VB.NET writing comments to jpeg file programmatically - vb.net

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

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

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

Extract Images with text from PDF and Edit it using iTextSharp

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.

Put content of fileStream in dataset

I want to read Stream that i get from XtrapivotGrid of DevExpress. I can save it in the computer but what i want is to save it in one of my table in my dataset called dataset1.
For now i have that code who permit to save it the directory Temp:.
Using FS As New IO.FileStream("D:\Temp\qqc.layout", IO.FileMode.Create)
PivotGridControl1.SaveLayoutToStream(FS)
End Using
Dim read As New System.IO.FileStream("D:\Temp\qqc.layout", IO.FileMode.Open, IO.FileAccess.Read)
DataSet1.LayoutMainRapport.ReadXml(read)
DataSet1.AcceptChanges()
read.Close()
The table LayoutMainRapport have 3 columns:
ID(Int)
Name(nvarchar(50))
Content(xml).
The output from the stream is xml.
thanks in advance!
I believe you should convert your saved layout into string and then save this string to database (and of course you can load this layout back from the database string value):
Private Function SaveLayoutToString(ByVal dxControl As DevExpressControl) As String
Using ms As MemoryStream = New MemoryStream()
dxControl.SaveLayoutToStream(ms)
Return Convert.ToBase64String(ms.ToArray())
End Using
End Function
Private Sub RestoreLayoutFromString(ByVal dxControl As DevExpressControl, ByVal layout As String)
If String.IsNullOrEmpty(layout) Then
Return
End If
Using ms As MemoryStream = New MemoryStream(Convert.FromBase64String(layout))
dxControl.RestoreLayoutFromStream(ms)
End Using
End Sub
Here DevExpressControl dxControl is the DevExpress control which supports saving and loading layout (XtraPivotGrid, XtraGrid, XtraLayoutControl etc.)
I simply had to save a name for the xml and after save it into my dataset.
Dim saveDialog As SaveLayout = New SaveLayout
If saveDialog.ShowDialog() = Windows.Forms.DialogResult.OK Then
Dim read As New IO.MemoryStream
PivotGridControl1.SaveLayoutToStream(read)
read.Position = 0
Dim lecteur As New IO.StreamReader(read)
Dim ligne As DataRow = DataSet1.LayoutMainRapport.NewRow()
ligne("Nom") = saveDialog.txtNom.Text
ligne("Contenu") = lecteur.ReadToEnd()
DataSet1.LayoutMainRapport.Rows.Add(ligne)
LayoutMainRapportTableAdapter.Update(DataSet1)
End If

How to correctly read a random access file in VB.NET

I am attempting to read a random access file, but I am getting the following error on the first file Error 5 (unable to read beyond end of the stream). I am not sure what I am doing wrong here, how might I fix this issue?
Structure StdSections
'UPGRADE_WARNING: Fixed-length string size must fit in the buffer. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="3C1E4426-0B80-443E-B943-0627CD55D48B"'
<VBFixedString(15), System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst:=15)> Public A() As Char 'BEAM --- complete beam designation 15
'UPGRADE_WARNING: Fixed-length string size must fit in the buffer. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="3C1E4426-0B80-443E-B943-0627CD55D48B"'
<VBFixedString(2), System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst:=2)> Public B() As Char 'DSG --- shape ie "W" or "C" 2
Dim C As Single 'DN --- nominal depth of section 4
Dim d As Single 'WGT --- weight 4
.
.
.
End structure
''Note 'File1'is the existing RAF and holds complete path!
Dim i,ffr,fLength,lastmembNo as integer
sectionFound = False
Dim std As new StdSections
fLength = Len(std)
If fLength = 0 Then fLength = 168 ' 177
ffr = FreeFile()
FileOpen(ffr, File1, OpenMode.Random, OpenAccess.Read, OpenShare.LockRead, fLength)
lastmembNo = CInt(LOF(ffr)) \ fLength
For i = 1 To lastmembNo
FileGet(ffr, std, i)
>>Error 5 (unable to read beyond end of the stream) <<<
If Trim(memberID) = Trim(std.A) Then
sectionFound = True
end if
next i
Wow Freefile! That's a blast from the past!
I haven't really used the old OpenFile etc. file access methods in VB.NET, so I'm just speculating, but in .NET many of the variable types got changed in size. e.g. an Integer is now 32-bits (4 bytes), I think a Boolean is different, though a Single is still 4 bytes.
Also, strings in .NET are by default in Unicode, not ASCII, so you cannot rely on 1 character=1 byte in a .NET String variable. In fact, .NET actualy "JIT compiles" programs on the PC before running, so you can't really lay out structures in memory easily like the old days.
If you want to switch to the new "Stream" based objects, here's some code to get you started:
Dim strFilename As String = "C:\Junk\Junk.txt"
Dim strTest As String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Call My.Computer.FileSystem.WriteAllText(strFilename, strTest, False)
Dim byt(2) As Byte
Using fs As New FileStream(strFilename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)
fs.Seek(16, SeekOrigin.Begin)
fs.Read(byt, 0, 3)
Dim s As String = Chr(byt(0)) & Chr(byt(1)) & Chr(byt(2))
MsgBox(s)
fs.Seek(5, SeekOrigin.Begin)
fs.Write(byt, 0, 3)
End Using
Dim strModded As String = My.Computer.FileSystem.ReadAllText(strFilename)
MsgBox(strModded)
I wouldn't blame you for keeping the old method though: with the new method, you'll need to define a class, and then have a custom routine to convert from Byte() to the properties of the class. More work than simply loading bytes from the file into memory.
OK, I think you should switch to the ".NET way", as follows:
Imports System.IO
Imports System.Xml
Public Class Form1
Public Const gintRecLen_CONST As Integer = 177
Class StdSections2
Private mstrA As String
Public Property A() As String
Get
Return mstrA
End Get
Set(ByVal value As String)
If value.Length <> 15 Then
Throw New Exception("Wrong size")
End If
mstrA = value
End Set
End Property
Private mstrB As String
Public Property B() As String
Get
Return mstrB
End Get
Set(ByVal value As String)
If value.Length <> 2 Then
Throw New Exception("Wrong size")
End If
mstrB = value
End Set
End Property
Public C(39) As Single
Public Shared Function FromBytes(byt() As Byte) As StdSections2
Dim output As New StdSections2
If byt.Length <> gintRecLen_CONST Then
Throw New Exception("Wrong size")
End If
For i As Integer = 0 To 14
output.mstrA &= Chr(byt(i))
Next i
For i As Integer = 15 To 16
output.mstrB &= Chr(byt(i))
Next i
For i As Integer = 0 To 39
Dim bytTemp(3) As Byte
output.C(i) = BitConverter.ToSingle(byt, 17 + 4 * i)
Next i
Return output
End Function
End Class
Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
End Sub
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim strFilename As String = "C:\Junk\Junk.txt"
Dim strMemberID As String = "foo"
Dim intRecCount As Integer = CInt(My.Computer.FileSystem.GetFileInfo(strFilename).Length) \ gintRecLen_CONST
Dim blnSectionFound As Boolean = False
Using fs As New FileStream(strFilename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
For intRec As Integer = 0 To intRecCount - 1
Dim intRecPos As Integer = gintRecLen_CONST * intRec
fs.Seek(intRecPos, SeekOrigin.Begin)
Dim byt(gintRecLen_CONST - 1) As Byte
fs.Read(byt, 0, gintRecLen_CONST)
Dim ss2 As StdSections2 = StdSections2.FromBytes(byt)
'MsgBox(ss2.A & ":" & ss2.C(3)) 'debugging
If strMemberID.Trim = ss2.A.Trim Then
blnSectionFound = True
Exit For
End If
Next intRec
End Using
MsgBox(blnSectionFound.ToString)
End Sub
End Class
We define a class called StdSections2 which uses .NET strings and an array of Singles. We use 0-based arrays everywhere. We load the file using the new FileStream object, and use the Seek() command to find the position we want. We then load raw bytes out of the file, and use Chr() and BitConverter.ToSingle() to convert the raw bytes into strings and singles.
I'm not sure about your example but this one however, works:
Public Class Form1
Const maxLenName = 30
Structure person
<VBFixedString(maxLenName)> Dim name As String
Dim age As Byte
End Structure
Private Sub Form1_Load(sender As [Object], e As EventArgs) Handles MyBase.Load
Dim entryIn As New person
Dim recordLen As Integer = Len(entryIn)
Dim entry As person
If FileIO.FileSystem.FileExists("test.raf") Then Kill("test.raf")
FileOpen(1, "test.raf", OpenMode.Random,,, recordLen)
'write
entry.name = LSet("Bill", maxLenName)
entry.age = 25
FilePut(1, entry, 6) 'write to 6th record
'read
Dim nRecords As Integer = LOF(1) \ recordLen
FileGet(1, entryIn, nRecords)
FileClose(1)
Dim personName As String = RTrim(entryIn.name)
Dim personAge As Byte = entryIn.age
MsgBox(personName & "'s age is " & personAge)
End Sub
End Class