Generating QR Code in Mac VBA - vba

I'm trying to crate and display a whole series of QR codes (200+) in an excel sheet running on Mac. The first solution given by Patratacus found on Generating 2D (PDF417 or QR) barcodes using Excel VBA takes a long time to run so many codes and because the QR Codes are made up of multiple shapes the screen refresh becomes really slow with 200+ QR codes on one sheet.
So, I have got the code working on PC using #Luiz solution found at Generating 2D (PDF417 or QR) barcodes using Excel VBA but unfortunately it doesn't seem to work on Mac.
With the code:
sURL = "https://api.qrserver.com/v1/create-qr-code/?" + "size=" + Trim(Str(size)) + "x" + Trim(Str(size)) + "&color=" + color + "&bgcolor=" + bgcolor + "&data=" + data
Debug.Print sURL
Set pic = ActiveSheet.Pictures.Insert(sURL + sParameters)
SURL + sParameters - seems to return the raw data of the image from the API https://api.qrserver.com/v1/create-qr-code/?. So I have been able to get a Mac shell script to return the same raw data I think using:
sResult = execShell(= "curl --get -d """ & "size=" + Trim(Str(size)) + "x" + Trim(Str(size)) + "&color=" + color + "&bgcolor=" + bgcolor + "&data=" + data & """" & " " & "https://api.qrserver.com/v1/create-qr-code/?")
However, if you insert the returned string into:
ActiveSheet.Pictures.Insert()
On mac it doesn't seem to work either. So my guess is that on Mac ActiveSheet.Pictures.Insert() is not able to read raw image data and only a path and file name to a picture file.
So I think our options are:
Find a why to display a picture on an excel sheet using the raw data returned by the API or
Find a way to save the raw data returned by the API as a picture file on Macs file system and then open that file using excels ActiveSheet.Pictures.Insert() code.
Here is a link to the API documentation page: http://goqr.me/api/doc/create-qr-code/
I hope what I wrote above make some sense as I probably don't have all the terminology correct. I'm quite new to working with APIs etc.

Related

VBA to save PDF from URL to local folder

I'm trying to cycle through several url's to download the pdf to a local folder.
An example of the url is https://find-energy-certificate.service.gov.uk/energy-certificate/8309-9619-9729-7796-8423?print=true
This is the vb I've written so far.
Dim sveloc As String
Dim svenme As String
Dim url As String
sveloc = Application.ActiveWorkbook.Path & "\Saved EPCs"
i = 7
Do Until sh01.Cells(i, 27) = "" 'all cells in the list are populated with no gaps
url = sh01.Cells(i, 27)
svenme = sh01.Cells(i, 2)
sveloc = sveloc & "\" & svenme & ".pdf"
ThisWorkbook.FollowHyperlink (url)
'code to open and save the pdf goes here
i = i + 1
Loop
Any help gratefully received as I'm really stumped on this one.
TIA.
Inspired by KJ's answer, without error checking etc. Just wanted to illustrate how you'd use shell to automate the entire process.
sveloc = Application.ActiveWorkbook.Path & "\Saved EPCs"
edgePath = Environ$("PROGRAMFILES(X86)") & "\Microsoft\Edge\Application\msedge.exe"
With CreateObject("WScript.Shell")
i = 7
Do Until Len(sh01.Cells(i, 27)) = 0 'all cells in the list are populated with no gaps
On Error Resume Next
.Run """" & edgePath & """ --profile-directory=Default --headless -print-to-pdf=""" & sveloc & "\" & sh01.Cells(i, 2) & ".pdf" & """ """ & sh01.Cells(i, 27) & """", 1, True
On Error GoTo 0
i = i + 1
Loop
End With
No need for VBA but you can use that to alter the variables so using your example from Windows we can run the build pdf at html runtime via Edge:-
"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" --profile-directory=Default --headless -print-to-pdf=C:\Users\WDAGUtilityAccount\Desktop\8309-9619-9729-7796-8423.pdf "https://find-energy-certificate.service.gov.uk/energy-certificate/8309-9619-9729-7796-8423?print=true"
and as if by magic the file is in less than a second on my desktop
There is no online pdf it is built by the browser. So it is essential to use the browser. You can remove the print header/footer with one extra switch, but cannot change orientation it will be A4 portrait in UK device.
-print-to-pdf-no-header see currently https://source.chromium.org/chromium/chromium/src/+/main:headless/app/headless_shell_switches.cc;l=60
one other switch may be of value if you only want smaller untagged files
-disable-pdf-tagging see https://source.chromium.org/chromium/chromium/src/+/main:headless/app/headless_shell_switches.cc;l=64
If you try to download without browser printing you will just get the raw HTML as needed for web page printing, thus calling browser remote print as above, will generate the desired "designed for the web" graphics copy.
curl -o test.htm https://find-energy-certificate.service.gov.uk/energy-certificate/8309-9619-9729-7796-8423?print=true
In comments the question was raised how to adapt this approach for change of browser and keeping call simple so I suggest use a cmd or bat file to make that part easier. Thus from vba call something like
Batchfile 8309-9619-9729-7796-8423
#echo off
set "browser=C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe"
set "filedir=C:\Users\WDAGUtilityAccount\Desktop"
set "urlpath=https://find-energy-certificate.service.gov.uk/energy-certificate"
"%browser%" --profile-directory=Default --headless --print-to-pdf="%filedir%\%~1.pdf" -print-to-pdf-no-header "%urlpath%/%~1?print=true"
However, beware calling pdf generations too fast, add a small wait between calls, even on multithreaded CPU writing PDF's at same time often leads to disasters, due to graphics resource conflicts.

Using ParseQueryString in Winform

My program is writing URL-encoded strings into a text file like this one.
topic1=1&topic2=2&topic3=3&
However, I'm trying to reverse the process by opening the same file and breaking that file up in a manner that I can retrieve into name/value-like pairs.
' Final Challenge Category
Dim sr As StreamReader = New StreamReader("./Game" + nudGameNo.Value.ToString() + "/Final/category.txt")
strLine = WebUtility.UrlDecode(sr.ReadLine)
The closest function that I can find to help is HttpUtility.ParseQueryString but I can't seem to run it in a WinForms application. (Even if I use Imports System.Web)
I've also tried to do a .Split with & being the separator, however problems start up if a particular value contains an & of it's own.
Is it possible to break this form of string up?

Applying a formula to Get From Web URL with VBA Macro

I'm trying to find a way to apply a formula to a get data from web url.
So the url will look like:
http://www.thisurl.com/formula/restOfTheUrl
I'm new to this, so I tried recording the macro using the Advanced Get From Web function and breaking out the elements of the URL from there and substituting the formula in.
So the section of the code looked like this
Source = Xml.Tables(Web.Contents(""http://www.thisurl.com/"" & text(0.123456,2) & ""/restOfTheUrl""))
Had it worked, the number 2 would have been substituted in place of text(0.123456,2).
Is there another way to do this?
Try,
Source = Xml.Tables(Web.Contents("http://www.thisurl.com/" & mid("0.123456", 4, 1) & "/restOfTheUrl"))
'possibly (your sample contradicts your code)
Source = Xml.Tables(Web.Contents("http://www.thisurl.com/" & mid("0.123456", 4, 1) & "restOfTheUrl"))

VBA - Finding folder inside a directory and returning the path of that folder

I am using excel vba to make an application that acts as a job card. User will fill in relevant fields, press a button to update a running summary of costs, as well as generate a printable pdf of the job card. I have very limited experience in coding (a semester of java 4 years ago) so i am relatively new to this.
Currently, the application automatically updates the summary file and can open a word template file and fill it in with information from the input fields, so it mostly works. I have realised an issue in the way it is finding the summary files, in that as soon as a folder name does not align with the way i am constructing the folder paths in the app, it will return errors.
At the moment I am going into folders like this:
templatePath = "C:\SERVICE\Card Template.doc"
If cbxType.Text = "Plant" Then
savePath = "C:\SERVICE\0.1 PLANT\" & cbxNo.Text & " - " & txtMakeModel.Text & " " & txtRego.Text & "\0.2 SERVICE SHEETS\"
ElseIf cbxType.Text = "Vehicle" Then
savePath = "C:\SERVICE\0.2 VEHICLES\"
End If
The directory is constructed from text and combo boxes which are populated once the user chooses a type (plant, vehicle, etc.) and then ID, which fills in boxes for model name, registration number, hours etc.
I am after a piece of code that can iterate through a given directory, searching the folder names for a string and returning the path of that folder. Each folder begins with the ID number, so I figure I can search folder names for that but I am not sure how to construct the loop. Any help with this, or alternative ideas would be appreciated. If it isn't too much to ask I'd also like a little bit of an explanation on how it works.

Excel VBA - Accessing transit_details array from Google directions API using XML

I am accessing the Google Directions API from Excel using VBA. I would like to be able to access the transit_details array in the Google directions API when retrieving transit directions using XML from VBA so I can get number of stops etc. At the moment I have code that gives me basic directions but I don't get stop numbers etc for transit directions:
The following is the Google Directions API webpage: https://developers.google.com/maps/documentation/directions/
'Get Directions
For Each nodeRoute In .SelectSingleNode("//route/leg").ChildNodes
If nodeRoute.BaseName = "step" Then
strInstructions = strInstructions & nodeRoute.SelectSingleNode("html_instructions").text & " - " & nodeRoute.SelectSingleNode("distance/text").text & vbCrLf
End If
Next
strInstructions = CleanHTML(strInstructions) 'Removes MetaTag information from HTML result to convert to plain text.
Else
strError = .SelectSingleNode("//status").text
GoTo errorHandler
End If
End With
Sounds like you need an XML Parser for VBA so that you can reference the XML with it's native structure. I'm not sure if there's XML parsers for VBA, I'll look when I get home from work (no time now)