Convert base64 to image - vba

I have the following 2 functions which give me the base64 of an image
Option Compare Database
Option Explicit
Function readBytes(strFile As String) As Variant
Const TypeBinary = 1
Dim inStream As Object
' ADODB stream object used
Set inStream = CreateObject("ADODB.Stream")
' open with no arguments makes the stream an empty container
inStream.Open
inStream.Type = TypeBinary
inStream.LoadFromFile strFile
readBytes = inStream.Read()
End Function
Function encodeBase64(arrBytes As Variant) As String
Dim DM As Object, EL As Object
Set DM = CreateObject("Microsoft.XMLDOM")
' Create temporary node with Base64 data type
Set EL = DM.createElement("tmp")
EL.dataType = "bin.base64"
' Set bytes, get encoded String
EL.nodeTypedValue = arrBytes
encodeBase64 = EL.Text
End Function
Sub test()
TestIt CurrentProject.Path & "\pic.jpg"
End Sub
Function TestIt(strFile As String) As String
Dim arrBytes As Variant, strRet As String
arrBytes = readBytes(strFile)
strRet = encodeBase64(arrBytes)
Dim s As String
Open CurrentProject.Path & "\pic_base64.txt" For Binary As #1
Put #1, 1, strRet
Close #1
End Function
I need to convert the following 2 functions to same VBA format as the functions above and add an additional test function which will take the base64 converted image string from the above function and write it back to the image pic.jpg
private function decodeBase64(base64)
dim DM, EL
Set DM = CreateObject("Microsoft.XMLDOM")
' Create temporary node with Base64 data type
Set EL = DM.createElement("tmp")
EL.DataType = "bin.base64"
' Set encoded String, get bytes
EL.Text = base64
decodeBase64 = EL.NodeTypedValue
end function
private Sub writeBytes(file, bytes)
Dim binaryStream
Set binaryStream = CreateObject("ADODB.Stream")
binaryStream.Type = TypeBinary
'Open the stream and write binary data
binaryStream.Open
binaryStream.Write bytes
'Save binary data to disk
binaryStream.SaveToFile file, ForWriting
End Sub

Related

LibreOffice Writer API - Cursors and text selection / replacement from VB6

I have been attempting to replace Office OLE in a vb6 application with LibreOffice.
I have had some success, however, I am falling short trying to search for text, then create a cursor based on the text that was found, then insert an image at that cursors point in the document.
I have been able to piece together working code that will allow me to search for text, replace text and insert an image, however, I cannot seem to figure out how to create a cursor that will allow me to insert an image at the pace where the text is that I have found . In the provided example, the [PICTUREPLACEHOLDER] text in the document.
Has anyone ever done this before and do they have any suggestions how I can create a cursor that will allow me to specify where the image will be inserted.
I have included the code for the VB6 test app so you can see the source code to see how its currently working.
Any suggestions would be very much appreciated.
Please Note - this is experimental code - very rough and ready - not final code by a long shot - just trying to figure out how this works with LibreOffice Writer.
To run this, you will need to create an empty vb6 app with a button.
You also need LibreOffice installed.
Many thanks
Rod.
Sub firstOOoProc()
Dim oSM 'Root object for accessing OpenOffice from VB
Dim oDesk, oDoc As Object 'First objects from the API
Dim arg() 'Ignore it for the moment !
'Instanciate OOo : this line is mandatory with VB for OOo API
Set oSM = CreateObject("com.sun.star.ServiceManager")
'Create the first and most important service
Set oDesk = oSM.createInstance("com.sun.star.frame.Desktop")
Dim oProvider As Object
Set oProvider = oSM.createInstance("com.sun.star.graphic.GraphicProvider")
'Open an existing doc (pay attention to the syntax for first argument)
Set oDoc = oDesk.loadComponentFromURL("file:///c:/dev/ooo/testfile.doc", "_blank", 0, arg())
' now - replace some text in the document
Dim Txt
Txt = oDoc.GetText
Dim TextCursor
TextCursor = Txt.CreateTextCursor
' attempt to replace some text
Dim SearchDescriptor
Dim Replace
Replace = oDoc.createReplaceDescriptor
Replace.SearchString = "[TESTDATA1]"
Replace.ReplaceString = "THIS IS A TEST"
oDoc.replaceAll Replace
Dim searchCrtiteria
SearchDescriptor = oDoc.createReplaceDescriptor
' Now - attempt try to replace some text with an image
SearchDescriptor.setSearchString ("[PICTUREPLACEHOLDER]")
SearchDescriptor.SearchRegularExpression = False
Dim Found
Found = oDoc.findFirst(SearchDescriptor)
' create cursor to know where to insert the image
Dim oCurs As Object
Set thing = oDoc.GetCurrentController
Set oCurs = thing.GetViewCursor
' make hte call to insert an image from a file into the document
InsertImage oDoc, oCurs, "file:///c:/dev/ooo/imagefilename.jpg", oProvider
'Save the doc
Call oDoc.storeToURL("file:///c:/dev/ooo/test2.sxw", arg())
'Close the doc
oDoc.Close (True)
Set oDoc = Nothing
oDesk.Terminate
Set oDesk = Nothing
Set oSM = Nothing
End Sub
Function createStruct(strTypeName)
Set classSize = objCoreReflection.forName(strTypeName)
Dim aStruct
classSize.CreateObject aStruct
Set createStruct = aStruct
End Function
Sub InsertImage(ByRef oDoc As Object, ByRef oCurs As Object, sURL As String, ByRef oProvider As Object)
' Init variables and instance object
Dim oShape As Object
Dim oGraph As Object
Set oShape = oDoc.createInstance("com.sun.star.drawing.GraphicObjectShape")
Set oGraph = oDoc.createInstance("com.sun.star.text.GraphicObject")
'Set oProvider = serviceManager.CreateInstance("com.sun.star.graphic.GraphicProvider")
' Add shape to document
oDoc.getDrawPage.Add oShape
' Set property path of picture
Dim oProps(0) As Object
Set oProps(0) = MakePropertyValue("URL", sURL)
' Get size from picture to load
Dim oSize100thMM
Dim lHeight As Long
Dim lWidth As Long
Set oSize100thMM = RecommendGraphSize(oProvider.queryGraphicDescriptor(oProps))
If Not oSize100thMM Is Nothing Then
lHeight = oSize100thMM.Height
lWidth = oSize100thMM.Width
End If
' Set size and path property to shape
oShape.graphic = oProvider.queryGraphic(oProps)
' Copy shape in graphic object and set anchor type
oGraph.graphic = oShape.graphic
oGraph.AnchorType = 1 'com.sun.star.Text.TextContentAnchorType.AS_CHARACTER
' Remove shape and resize graphix
Dim oText As Object
Set oText = oCurs.GetText
oText.insertTextContent oCurs, oGraph, False
oDoc.getDrawPage.Remove oShape
If lHeight > 0 And lWidth > 0 Then
Dim oSize
oSize = oGraph.Size
oSize.Height = lHeight * 500
oSize.Width = lWidth * 500
oGraph.Size = oSize
End If
End Sub
'
'Converts a Ms Windows local pathname in URL (RFC 1738)
'Todo : UNC pathnames, more character conversions
'
Public Function ConvertToUrl(strFile) As String
strFile = Replace(strFile, "\", "/")
strFile = Replace(strFile, ":", "|")
strFile = Replace(strFile, " ", "%20")
strFile = "file:///" + strFile
ConvertToUrl = strFile
End Function
'
'Creates a sequence of com.sun.star.beans.PropertyValue s
'
Public Function MakePropertyValue(cName, uValue) As Object
Dim oStruct, oServiceManager As Object
Set oServiceManager = CreateObject("com.sun.star.ServiceManager")
Set oStruct = oServiceManager.Bridge_GetStruct("com.sun.star.beans.PropertyValue")
oStruct.Name = cName
oStruct.Value = uValue
Set MakePropertyValue = oStruct
End Function
'
'A simple shortcut to create a service
'
Public Function CreateUnoService(strServiceName) As Object
Dim oServiceManager As Object
Set oServiceManager = CreateObject("com.sun.star.ServiceManager")
Set CreateUnoService = oServiceManager.createInstance(strServiceName)
End Function
Public Function RecommendGraphSize(oGraph)
Dim oSize
Dim lMaxW As Double
Dim lMaxH As Double
lMaxW = 6.75 * 2540
lMaxH = 9.5 & 2540
If IsNull(oGraph) Or IsEmpty(oGraph) Then
Exit Function
End If
oSize = oGraph.Size100thMM
If oSize.Height = 0 Or oSize.Width = 0 Then
oSize.Height = oGraph.SizePixel.Height * 2540# * Screen.TwipsPerPixelY() '/ 1440
oSize.Width = oGraph.SizePixel.Width * 2540# * Screen.TwipsPerPixelX() '/ 1440
End If
If oSize.Height = 0 Or oSize.Width = 0 Then
Exit Function
End If
If oSize.Width > lMaxW Then
oSize.Height = oSizeHeight * lMax / oSize.Width
oSize.Width = lMaxW
End If
If oSize.Height > lMaxH Then
oSize.Width = oSize.Width * lMaxH / oSize.Height
oSize.Height = lMaxH
End If
RecommendGraphSize = oSize
End Function
Private Sub Command1_Click()
firstOOoProc
End Sub
The content of the testFile.Doc file is as shown below:
This is a test File
[TESTDATA1]
[PICTUREPLACEHOLDER]
It looks like you need to move the view cursor to the found location.
Found = oDoc.findFirst(SearchDescriptor)
oVC = oDoc.getCurrentController().getViewCursor()
oVC.gotoRange(Found, False)
oVC.setString("")

SHA512 not working in vba for extended character set

Hashing with SHA512 in vba using .net libraries is not correct if input string contains any characters > chr(127). Output is being compared to PHP SHA512. Any ideas?
I have tried different text encodings.
Public Function SHA512(sIn As String) As String
Dim oT As Object, oSHA512 As Object
Dim TextToHash() As Byte, bytes() As Byte
Set oT = CreateObject("System.Text.UTF8Encoding")
Set oSHA512 = CreateObject("System.Security.Cryptography.SHA512Managed")
TextToHash = oT.GetBytes_4(sIn)
bytes = oSHA512.ComputeHash_2((TextToHash))
SHA512 = ConvToHexString(bytes)
Set oT = Nothing
Set oSHA512 = Nothing
End Function
Private Function ConvToHexString(vIn As Variant) As Variant
On Error Resume Next
Dim oD As Object
Set oD = CreateObject("MSXML2.DOMDocument.6.0")
With oD
.loadXML "<root />"
.documentElement.DataType = "bin.Hex"
.documentElement.nodeTypedValue = vIn
End With
ConvToHexString = Replace(oD.documentElement.Text, vbLf, "")
Set oD = Nothing
End Function
Private Sub Command0_Click()
Dim strg As String
strg = "abc" & Chr(148) & "defg"
MsgBox SHA512(strg)
MsgBox strg
End Sub
<?php
$strg = "abc".chr(148)."defg";
echo hash('sha512', $strg);
echo "</br>".$strg;
?>
I have concluded that the SHA512 routines produce identical results. The problem is in how I am sending the data between vba and PHP.

How to read binary content of an embeded word object

I have an embedded OLE object in word as "InlineShape". I would like to access this object as a data stream / string. at the moment, I can see some ideas for Excel via OLEObject, but it seems that there is no solution for Word that I can see.
The following code achieves what I want:
' from here: https://stackoverflow.com/questions/1356118/vba-ws-toolkit-how-to-get-current-file-as-byte-array
Public Function GetFileBytes(ByVal path As String) As Byte()
Dim lngFileNum As Long
Dim bytRtnVal() As Byte
lngFileNum = FreeFile
If LenB(Dir(path)) Then ''// Does file exist?
Open path For Binary Access Read As lngFileNum
ReDim bytRtnVal(LOF(lngFileNum) - 1&) As Byte
Get lngFileNum, , bytRtnVal
Close lngFileNum
Else
Err.Raise 53
End If
GetFileBytes = bytRtnVal
Erase bytRtnVal
End Function
Sub TestMe()
Dim shapeIndex As Integer: shapeIndex = 1
Dim ns As Object
Dim folderItem
Const namePrefix = "site-visit-v2.5"
Const nameSuffix = ".dat"
Dim fileBytes() As Byte
Dim tempDir As String: tempDir = Environ("TEMP")
' first embedded Item - you may need adjust if you have more shapes
ActiveDocument.InlineShapes.Item(shapeIndex).Range.Copy
' paste it to temp dir
Set ns = CreateObject("Shell.Application").namespace((tempDir))
ns.Self.InvokeVerb ("Paste")
' find the file now
Dim Item As Object
Dim rightItem As Object
Set rightItem = Nothing
' find the file that was pasted
' because when files are pasted and name exists, you could get a name such as "site-visit-v2.5 (10).dat"
' we pick the most recent that matches
For Each Item In ns.Items
If Item.Name Like namePrefix & "*" & nameSuffix Then
If rightItem Is Nothing Then
Set rightItem = Item
Else
If Item.modifyDate > rightItem.modifyDate Then 'a more recent date is found
Set rightItem = Item
End If
End If
End If
Next
fileBytes = GetFileBytes(tempDir & "\" & rightItem.Name)
MsgBox "Read " & UBound(fileBytes) + 1 & " bytes"
End Sub

How to store data from a file in memory for reuse?

I have VBA code which executes on mail's reception.
I want to forward a template to the first address found in the mail. I execute a regex to find the email address in the mail, read a html file (the template) and forward it to the email address.
Outlook shuts down after few minutes. I think it is a performance problem. I want to optimize the code and if I can between two executions not read the template two times. Is it possible to store it into a global variable?
Sub GetEmailAndForward(Item As Outlook.MailItem)
' RegExp
Dim mailRegExp As RegExp
' File
Dim FileTemplate As Integer
Dim FileProperties As Integer
' Properties
Dim splitProperty() As String
' Email
Dim DataLine As String
Dim emails As MatchCollection
Dim email As String
Dim forward As Outlook.MailItem
Dim body As String
Dim forwardText As String
' Path
Dim fileTemplatePath As String
Dim dirPath As String
Dim filePropertyPath As String
dirPath = "C:\OutlookVBA"
Set mailRegExp = New RegExp
With mailRegExp
.Pattern = "[\_]*([a-z0-9]+(\.|\_*)?)+#([a-z][a-z0-9\-]+(\.|\-*\.))+[a-z]{2,6}"
.Global = False
.IgnoreCase = True
End With
' Get the template
fileTemplatePath = dirPath & "\template.html"
' Get the email body to analyse
body = Item.body
' Get the first email found
If mailRegExp.Test(body) Then
Set emails = mailRegExp.Execute(body)
If emails.Count > 0 Then
email = emails.Item(0)
Set forward = Item.forward
FileTemplate = FreeFile()
Open fileTemplatePath For Input As #FileTemplate
While Not EOF(FileTemplate)
Line Input #FileTemplate, DataLine
forwardText = forwardText & DataLine
Wend
forward.BodyFormat = olFormatHTML
forward.HTMLBody = forwardText & forward.HTMLBody
Close #FileTemplate
If Not IsEmpty(email) Then
forward.Recipients.Add email
forward.subject = "RE:" & Item.subject
forward.Send
End If
End If
End If
End Sub
You can use something like this - the function will only read from the file on the first call, and after that will use the text stored in the static variable:
Function GetForWardText(f As String) As String
Static rv As String '<< valuje is maintained between calls
If Len(rv) = 0 Then
rv = CreateObject("scripting.filesystemobject"). _
opentextfile(f, 1).readall()
End If
ForWardText = rv
End Function
In your code, remove this:
FileTemplate = FreeFile()
Open fileTemplatePath For Input As #FileTemplate
While Not EOF(FileTemplate)
Line Input #FileTemplate, DataLine
forwardText = forwardText & DataLine
Wend
and replace with:
forwardText = GetForWardText(fileTemplatePath)

How to get the MD5 hex hash for a file using VBA?

How can I get the MD5 hex hash for a file using VBA?
I need a version that works for a file.
Something as simple as this Python code:
import hashlib
def md5_for_file(fileLocation, block_size=2**20):
f = open(fileLocation)
md5 = hashlib.md5()
while True:
data = f.read(block_size)
if not data:
break
md5.update(data)
f.close()
return md5.hexdigest()
But in VBA.
An older question that could use a better answer. These functions are specifically for hashing files, not for hashing passwords. As a bonus, I'm including a function for SHA1. If you get rid of the type declarations these functions work in VBScript too except that the GetFileBytes function needs to be changed to use FileSystemObject (or possibly ADO Stream) as the Free File doesn't exist in VBScript.
Private Sub TestMD5()
Debug.Print FileToMD5Hex("C:\test.txt")
Debug.Print FileToSHA1Hex("C:\test.txt")
End Sub
Public Function FileToMD5Hex(sFileName As String) As String
Dim enc
Dim bytes
Dim outstr As String
Dim pos As Integer
Set enc = CreateObject("System.Security.Cryptography.MD5CryptoServiceProvider")
'Convert the string to a byte array and hash it
bytes = GetFileBytes(sFileName)
bytes = enc.ComputeHash_2((bytes))
'Convert the byte array to a hex string
For pos = 1 To LenB(bytes)
outstr = outstr & LCase(Right("0" & Hex(AscB(MidB(bytes, pos, 1))), 2))
Next
FileToMD5Hex = outstr
Set enc = Nothing
End Function
Public Function FileToSHA1Hex(sFileName As String) As String
Dim enc
Dim bytes
Dim outstr As String
Dim pos As Integer
Set enc = CreateObject("System.Security.Cryptography.SHA1CryptoServiceProvider")
'Convert the string to a byte array and hash it
bytes = GetFileBytes(sFileName)
bytes = enc.ComputeHash_2((bytes))
'Convert the byte array to a hex string
For pos = 1 To LenB(bytes)
outstr = outstr & LCase(Right("0" & Hex(AscB(MidB(bytes, pos, 1))), 2))
Next
FileToSHA1Hex = outstr 'Returns a 40 byte/character hex string
Set enc = Nothing
End Function
Private Function GetFileBytes(ByVal path As String) As Byte()
Dim lngFileNum As Long
Dim bytRtnVal() As Byte
lngFileNum = FreeFile
If LenB(Dir(path)) Then ''// Does file exist?
Open path For Binary Access Read As lngFileNum
ReDim bytRtnVal(LOF(lngFileNum) - 1&) As Byte
Get lngFileNum, , bytRtnVal
Close lngFileNum
Else
Err.Raise 53
End If
GetFileBytes = bytRtnVal
Erase bytRtnVal
End Function
This should do it:
Dim fileBytes() As Byte = File.ReadAllBytes(path:=fullPath)
Dim Md5 As New MD5CryptoServiceProvider()
Dim byteHash() As Byte = Md5.ComputeHash(fileBytes)
Return Convert.ToBase64String(byteHash)