Monday, May 15, 2017

Saving a collection of images from PowerApps to SharePoint using Microsoft Flow

Download the sample Flow and PowerApp

Yesterday I wrote about how you can save an image from PowerApps to a SharePoint library using Microsoft Flow – after reading about Paul Culmsee’s approach using Azure Functions. Paul challenged me to save a whole collection of images, and not only one image, so here goes!

This solution loops the images in Flow, but you could easily have looped them in PowerApps as well, saving one image at a time upon submit.

I’ll start with the Flow, and this time we’ll use one input only. And this is where it get’s a bit nasty. A Flow can only accept strings as input from PowerApps, not a collection of items. To overcome this, I’m concatenating the data into one string in the PowerApp, and then splitting the data in the Flow.

The data being passed in looks like this:

Monday, May 15, 2017LT.jpg|data:image/jpeg;base64,<data>#
Monday, May 15, 2017AB.jpg|data:image/jpeg;base64,<data>#


First is the filename with a readable date (borrowed code from Paul), next a pipe | to separate the filename from the base64 encoded image. And at the end a hash # to separate each image from each other.

In Microsoft flow create a new Flow named “Save Images”

Add a “PowerApps” step, followed by a “Compose” step.

image

In the input field for the “Compose” step pick “Ask in PowerApps”. Next change the formula to:

"@split(triggerBody()['Compose_Inputs'], '#')"

and rename the compose action to “Split images” for readability. This will split the incoming string on the character #, creating an array with one item per image.

Note: Remember to include the double quotes around the formula.

image

Below the “Split Images” action, add a “Filter array” action. This action is used to remove the empty element we get at the end when creating the data string in PowerApps. Use the Output from the previous action as the “From” field, click “Edit in advanced mode” and use the following formula to remove empty values. item() will yield one item in an array.

@not(equals(item(), ''))

Note: No quotes here :)

image

Below the Filter array action, add a for each item loop, so that we can process each image sent over.

image

Pick the Body output from the Filter array step as the input in the for each.

image

In the for each action, add two compose steps. Rename one to “Filename” and the other to “File content”.

For filename add the expression:
"@split(item(),'|')[0]"

For file content add the expression:
"@base64ToBinary(replace(split(item(),'|')[1],'data:image/jpeg;base64,',''))"
"@dataUriToBinary(split(item(),'|')[1])"

The effect is that for each item, split on the character |, and assign the left side as the filename, and base64 decode the right side of the split.
Note: Remember to include the double quotes around the formulas.
image

The last part is adding an action step to create a file in SharePoint. Pick a site and library, and assign the values from the previous compose steps.

image

Setting up the PowerApp

image

For the purpose of this demo I have four controls on in my app. A camera control, a button to send it all to flow, a clear button and a gallery to see the images taken, and which will be sent over to SharePoint.

To grab an image I have the following formula on the OnSelect property of the camera control:

Collect(PictureColl,Camera1.Photo)

This stores each image in a collection named PictureColl.

The gallery control’s “Items” property it bound to the PictureColl collection.

The “OnSelect” property of the submit button contains the following formula:

ForAll(PictureColl,Collect(SubmitData, { filename: Concatenate(Text( Now(), DateTimeFormat.LongDate ),Mid("0123456789ABCDEFGHIJKLMNOPQRTSTIUVWXYZ", 1 + RoundDown(Rand() * 36, 0), 1),Mid("0123456789ABCDEFGHIJKLMNOPQRTSTIUVWXYZ", 1 + RoundDown(Rand() * 36, 0), 1),".jpg"), filebody: Url }));

SaveImages.Run(Concat(SubmitData, filename & "|" & filebody & "#"))


The formula creates random filenames with dates and assigns the filename and image date to a collection named SubmitData (borrowed from Paul’s post). Then the file data is concatenated using a pipe | between the filename and the file contents, and concatenated using a hash # between each image. This is then passed into the SaveImages flow I have added to the PowerApp.

If you run the PowerApp (except in the Windows desktop version), tap the camera a couple of times to grab images, and then hit the submit data, you should end up with some images in your library.

image

See my previous post about on how to add a Flow to the PowerApp using PowerApps studio.