Make a PDF from Image files
- Patrick Cooley
- May 2
- 7 min read
Ever felt the frustration of trying to convert various image types into a PDF without shelling out for a "Premium" action in Power Automate? You're not alone! But guess what? We've cracked the code. Dive into our innovative technique that leverages an HtmlText control to generate HTML, enabling Power Automate to seamlessly create PDF documents. And the best part? This method effortlessly incorporates images from a SharePoint list image column. Ready to revolutionize your workflow? Let's get started!
SharePoint list with image columns
First, you’ll need a SharePoint list with some image columns. We can insert some images into the list, either JPEG or PNG. Then we connect this list as a data source for our app.

Screen with HtmlText and Image controls
Next create a blank app with Power Apps. Add some Image controls to the screen (corresponding with the number of images you want to use) and an HtmlText control. We’re going to add some code (that refers to the image controls) that runs OnVisible property of the screen. The image controls are tied to the SharePoint list images, either through a variable or a LookUp based on the ID or another “key” column (our example is the ParentID column).
How we harness JSON and extract base64
The first thing we do is get the JSON string of the image via the JSON function, then we determine the image format (PNG or JPEG), then we set a formatting variable for string manipulation to extract the base64 string from the JSON string, finally we assign the base64 string to a variable that we can use in our HTML. That’s the key this technique!
Screen OnVisible code
Let’s break down the code in the screen OnVisible, line-by-line. Then we’ll put it all together once we’ve explained it. In this section, our examples show the code as though we’re pulling two images into the HtmlText control, but the steps below just show you how to do it for a single image. (You can repeat this technique for multiple images in your HtmlText control.)
First, we use a With function pointing towards an Image control. You could simply insert the JSON formula into your variable calculation for varImage1, but you’d have to do it 2x. The With function is more performant, as it’s similar to defining a context variable.
With({jsonImage1: JSON(Image1.Image, JSONFormat.IncludeBinaryData)},
Next we use a series of Context variables. Why? Simply because we don’t have to reset them (since they don’t reside in memory beyond the active screen). Since the calculation of subsequent variables depends on the previous variable calculations, we need to use the UpdateContext formula several times, in a sequence.
Our first Context variable is for the image format. It looks for “.png” and “.jp” in the image text string within the JSON data. How can you view this text? Just insert a Text or Label control onto your screen, and make your Image1.Image the Text property, and you can see the complete text string.

Within that text string, you’ll be able to see the image file suffix, but you must search for it.
So, in the formula, we use the Find formula to look for the image format. The Find formula will either return blank or an integer, so we use a greater than operator to see if the value is greater than 0 to determine what type of image it is (PNG, JPEG or “unknown”). Then we use this value in the next context variable. Additionally, this variable also goes into the HtmlText control in the HTML text string. This is our “Format” variable:
UpdateContext({varImage1Format: If(Find(".png", Step1Image.Image) > 0,"png", If(Find(".jp", Step1Image.Image) > 0,"jpeg","unknown"))})
Our next variable helps us modify our text string to extract the base64. PNG files have base64 code beginning with “iVBOR” whereas JPEG base64 code begins with “/9j/”, so we need to feed different values into our Mid function when we’re extracting the base64 code from the JSON string of the image control. We could have used a single If function, but we wanted to have a way to confirm that the item is a JPEG. We use this variable as input into our next variable that extracts base64. This is our “String manipulation” variable.
UpdateContext({varImage1Code: If(varImage1Format = "png", 24, If(varImage1Format = "jpeg", 25, 24))}),
In our next variable, we slice off everything we don’t need to create the base64 code that our HtmlText control can recognize as an image. This is our “base64” variable.
UpdateContext({varImage1: Mid(jsonImage1, varImage1Code, Max(Len(jsonImage1) - varImage1Code, 0))})
That’s it for the OnVisible coding, here’s the complete block of code (including some remarks):
With({jsonImage1: JSON(Image1.Image, JSONFormat.IncludeBinaryData)},
//Image1Format looks for .png or .jp(eg) in the text string to determine the format for the HTML
UpdateContext({varImage1Format: If(Find(".png", Step1Image.Image) > 0,"png", If(Find(".jp", Step1Image.Image) > 0,"jpeg","unknown"))}),
//Image1Code bases the position for the Mid function to check: 24 for png and 25 for jpeg
UpdateContext({varImage1Code: If(varImage1Format = "png", 24, If(varImage1Format = "jpeg", 25, 24))}),
UpdateContext({varImage1: Mid(jsonImage1, varImage1Code, Max(Len(jsonImage1) - varImage1Code, 0))})

Code for the HtmlText control
We inserted an HtmlText control on our screen. Since we’re just using the text from this control in our Power Automate flow, it’s not necessary to make it visible, but we did, just so we could ensure that the images render properly before initiating the flow to turn it into a PDF. To make the image format dynamic, we used our varImage1Format variable. The base64 text string from the image is in varImage1.
This is how we added the code inside of an HtmlText control to display the image:
"<img src='data:image/"&varImage1Format&";base64," & varImage1&"' >"

In our example above, the image on the left with the cat is a JPEG and the image on the right with the tank is a PNG. Both render properly in the HtmlText control.
(Your HTML can include text, tables, and dynamic content other than your images, but this post focuses on the image piece.) Now you have HTML text that you can submit to Power Automate to build your PDF. Let’s look at how to build your PDF flow.
Create the PDF flow
When you build the flow, if you’re not already in a solution, you should initialize the flow from Power Apps to link it to the app. Else, if you create it straight from Power Automate, you’ll need to add both app and flow into a solution so that you can add the flow to your app. Once you’ve created the flow and it’s tied to your app, you can then enter the flow from Power Automate to continue editing. Let’s go through the flow.
The trigger is “When Power Apps calls a flow (V2)”. Your input must include the text input including the HtmlText from your HtmlText control.

Then use a OneDrive (for business) “Create file” action. This action will create a temporary HTML file in OneDrive that you can use for the next action. For the “File Name” you can use something like test.HTML. For the “File Content” use the dynamic content for the HTML text input from Power Apps.

Next, we use a OneDrive (for business) “Convert file” action. The “File” input is the Id dynamic output from the “Create file” action. Ensure you select PDF (default) as the “Target type”. This step does not create the file; it merely reformats the HTML into PDF. You must save the code next.

To save the PDF code, use a “Create file” SharePoint action. This action adds your new PDF to a document library so you can refer to it from your app. You can use dynamic content for the File Name or simply create a name with a suffix of “.pdf”. If you don’t have a unique file name, each subsequent time your flow runs it will fail, because the SharePoint “Create file” action must patch a unique File Name.
In the formula below, using the concat function, utcNow() provides a unique prefix, and then we add ‘.pdf’ to it to correctly identify the file:
concat(utcNow(),’.pdf’)
Optionally, you can include a “Respond to a Power App or flow” step that includes a link to your new document. You can title a text output as “Link” and add a formula using a concat function, similar to this:
concat(‘[your SharePoint document library]’, outputs(‘Create_file’)?[‘body/Path])
This formula adds your document library “https” address such as:
https://shanescows.sharepoint.com/sites/DoeHillDrive
…to the dynamic content Path from your “Create file” action. You'll simply replace the part of the formula ([your SharePoint document library]) with your own document library.

This PdfLink value will be output to Power Apps during the flow run.
You can save (and publish if it’s in a solution) and close your flow.
Finish the app
Return to your app, select the (…) button from the left side rail, and then Power Automate. Make sure that the flow is in your app. Note the schema name under the title, because that’s what you’ll use to call the flow:

Next, we add two button controls to our screen, one for initiating the flow, and the other for using the link that returns from the flow. We’ll name one PDF and the other Link.
Because we used the Respond to a Power App or flow action in Power Automate, we can harvest that link data by adding a Set function to the button calling the flow in the OnSelect property of the PDF button. Here’s an example:
Set( varPdfLink,CreatePDFfromHtmlText.Run(HtmlText1.HtmlText).pdflink);

With the link saved to the global variable called varPdfLink, you can now use that with a Launch function in Power Apps that opens the new PDF document in another browser tab. You can add this code to the OnSelect property of your Link button.
Launch(varPdfLink)
If you run your app, you will be able to use any JPEG and PNG images in your PDF document. You can continue to add HTML code to your HtmlText control to add data to your PDF, but now you understand how to add different image types to the PDF.
Here’s how ours looks:

Please let us know what you think!
For more on this topic, don't forget to check out Shane's video on creating a PDF: Create a PDF from SharePoint Data using Power Apps and Power Automate flow for free
Comments