Sunday, May 14, 2017

An even more clever workaround for saving photos to SharePoint from PowerApps – using Microsoft Flow

At the time of writing there is a gap using PowerApps with SharePoint which won’t let you save a captured image from PowerApps directly to SharePoint. There are numerous posts out there about this, and Paul Culmsee wrote a post with a clever work around using Azure functions to get the image over to SharePoint.

Paul posted about this in Facebook, and cheeky me replied:
 
image

Note the (not really) at the end there, so I blame Paul entirely for making me write this post, which I think introduce an even more clever way of doing this – doable for any power user out there :D

I’ll skip all the fancy parts which Paul has to get nice random file names etc, so head over to his post for that piece of the pie.

A small note to Paul, and every one else – this will not work for the Windows desktop version of PowerApps – as it stores the captured image different compared to other devices. Instead of using the data uri notation with the full image base64 encoded, it only has a blob reference.

I’ve tested it with great success on:
  • Web
  • Windows Phone – Win10
  • iPad – iOS 10.3.1
So how do you do this? (I strongly urge you to read his post first, as it explains it all in very detail, where as I jump to the gist of things.)

First off, create a new PowerApp and add a camera control to the canvas. For the OnSelect command for the camera add the following command:

ClearCollect(PictureColl,Camera1.Photo)

When you click the image box it will grab the photo, and store it in a collection named PicureColl. As I’m using ClearCollect, the collection will always be cleared first, having one image only in the collection.

image

Next, I added a button which will send the image to SharePoint via Microsoft Flow. So let’s head over to Flow and see what the Flow looks like?

First add a collect from PowerApps actions. Then add a Create file in SharePoint action. For the file name and content, click “Ask in PowerApps”. This will generate two input variables, which we will use to pass in information from the PowerApp to the Flow.

image

Next, add a Compose step between the PowerApps action and the create file in SharePoint action. This is where we will strip away the base64 header, and convert the data to binary. You can type formulas directly into the SharePoint step as well, but I find it easier to manage this way.

The formula in the compose step is:

"@base64ToBinary(replace(triggerBody()['Createfile_FileContent'],'data:image/jpeg;base64,',''))"

"@dataUriToBinary(triggerBody()['Createfile_FileContent'])"

NOTE: It’s important to add the quotes "" before and after the expression, even though they don’t show on edit.

Next change the File Content box to retrieve the Output from the compose step instead of the collect from PowerApps as seen below.

image

And that’s it for the Flow, and head back to the PowerApp. Using PowerApps studio add a Flow to your app.

image

For the OnSelect command for the button add the following:

Saveimage.Run("test.jpg",First(PictureColl).Url)

Saveimage is the name of the Flow, which takes two parameters. The first being the filename, the second being the base64 encoded image from the Url parameter of the image. (All this is in Paul's great post.)

Fire up the app, click once on the image, and once on the button, and you should see a nice picture stored in your SharePoint library.

image

You can very well combine the OnSelect statements into either the image or button control if you want, but that’s all in how you want to have your UI. Having two controls made the demo simpler :)

61 comments:

  1. Mikael, I have followed you excellent article above to the letter and this did not work for me.

    The image gets created in the "Picture Coll" but nothing uploads to Sharepoint. What formula should I be using in the compose step?

    The code that has a strikethrough, the code below that or all of it?

    Regards

    Ian

    ReplyDelete
    Replies
    1. Do you get the flow to run? Are you seeing any errors in the log for it?

      Delete
    2. And be sure not to use the Windows version of PowerApps, as that doesn't work. Any other version is fine.

      Delete
    3. What do you mean by the Windows version of PowerApps, what other versions are there?

      Delete
    4. The error I get in in the compose section so the Flow does not run, details as follows:

      InvalidTemplate. Unable to process template language expressions in action 'Compose' inputs at line '1' and column '1549': 'The template language function 'dataUriToBinary' expects its parameter to be formatted as a valid data URI. The provided value 'blob:93427F3F-9F71-431F-8D30-2A3A8F0C1490' was not formatted correctly. Please see https://aka.ms/logicexpressions#dataUriToBinary for usage details.'.

      Delete
    5. You are using Windows :) Try using PowerApps in a web browser, on Android, iOS or WinPhone and it works. And noted at the top of the post :)

      Delete
    6. Mikael, sorry I missed the notes at the top of the post. The good news is that I no longer have an error with the compose section of the Flow. Now I am getting a permissions on the Sharepoint Create a file section as detailed below:

      Error Message.

      "status": 403, "message": "Access denied. You do not have permission to perform this action or access this resource.", "source": "https://stonarimages.sharepoint.com/sites/PowerAppDemo/_api/web/GetFolderByServerRelativeUrl('/sites...')",

      "errors": [ "-2147024891", "System.UnauthorizedAccessException"

      I am the only user in my Sharepoint tenant and I have full access to the document library in question and I get this message on every device I use the app on.

      It is driving me mad. Any ideas?

      Delete
    7. Weird... you could try to re-add the SP connection and see if that helps.

      Delete
    8. Already tried that with no success.

      Delete
    9. Can you for example create a .txt file using flow in the same or another site/lib?

      Delete
    10. Mikael, permissions issue seems to have gone on the Create file step but now the flow is giving me the following error and I have no idea what it means:

      InvalidTemplate. Unable to process template language expressions in action 'Create_file' inputs at line '1' and column '1511': 'The template language expression 'json(decodeBase64(triggerOutputs().headers['X-MS-APIM-Tokens']))['$connections']['shared_sharepointonline_1']['connectionId']' cannot be evaluated because property 'shared_sharepointonline_1' doesn't exist, available properties are 'shared_sharepointonline'. Please see https://aka.ms/logicexpressions for usage details.'.

      Delete
    11. Looks like the SP connection is broken of sorts. I would try to re-create the connection and the Flow and see if that works. Something is clearly saved wrong.

      Delete
    12. Mikael, thanks for your support. I think I will start again from scratch and will let you know how I get on.

      Delete
    13. Mikae,

      In the following code is it UriToBinary or UrlToBinary)

      "@dataUriToBinary(triggerBody()['Createfile_FileContent'])"

      Delete
    14. dataUriToBinary as per https://docs.microsoft.com/en-us/azure/logic-apps/logic-apps-workflow-definition-language

      Delete
  2. Hi Mikael, first of all great post on getting this done!
    Wanted to check, I have followed your post and I seem to be having an issue at the last step, adding a flow to the button.

    After adding a flow and inputting the following onselect: Saveimage.Run("test.jpg",First(PictureColl).Url)

    powerapps shows me the following error:
    Invalid number of arguements.
    Anything I am missing on, i actually copied and pasted your string exact except changed the name according to my flow name

    ReplyDelete
    Replies
    1. If your flow takes two params, and you are not using the Windows version of PowerApps it should work. When you start typing Saveimage.Run(, it should tell you what params to expect from your flow.

      Delete
    2. Thanks, Mikael for this article, I get the same issue, I only get One Parameter which is File Name. I didn't see any other input on the flow am I missing something ?

      Delete
    3. Depends on your Flow Def..if you have two 'ask from powerapps' you should get two params .

      Delete
    4. I'm just getting test.jpg Text inside the test.jpg file on SharePoint. I clearly have something goofed up on the input line.. which order should the inputs be in "filename" then Ask PowerApps ?

      Thanks, Dave

      Delete
  3. Mikael, that was awesome! Worked first try! I was able to prove I can save a captured image from the PowerApp to Sharepoint. What I really need to do, is to get it saved to a Item/Record in a Sharepoint List. Is there a way to modify the Flow/PowerApp to do that?

    ReplyDelete
    Replies
    1. You would need a custom azure function to save it as an attachment in a list. There is no native support for list item attachments in Flow yet afaik. And cool you got it working :) That said, native support to save images to SharePoint is underway in PowerApps.

      Delete
  4. Awsome... i'm trying to do the same, but with the pen input control, but isn´t working, I get the error "Unable to process template language expressions in action 'Compose' inputs at line '1' and column '1549': 'The template language function 'dataUriToBinary' expects its parameter to be formatted as a valid data URI. The provided value 'blob:C1B854C3-6B8C-49B0-A3A4-4489A74D2034' was not formatted correctly". Any idea?

    ReplyDelete
    Replies
    1. Yes, you are using Windows PowerApps and not web/mobile. Correct? And I have a disclaimer on that in the post :)

      Delete
    2. Nop...I'm using Web and Mobile (IPhone)

      Delete
    3. Maybe they changed things, and we just have to wait for the proper support to land, which it will :)

      Delete
  5. i did exactly as detailed but the picture saved in SP cannot be viewed ;(

    ReplyDelete
    Replies
    1. You should open the image file in notepad and see what it looks like. But, the product team is working on supporting this natively, so if you are patient, the feature will be there eventually :)

      Delete
  6. Do you know how to make this work with an 'Add Picture' Control?

    ReplyDelete
    Replies
    1. I haven’t tried, but add the value to a collection and inspect what it looks like.

      Delete
    2. the value is stored as a URL of sorts.. looks something like blob:https://create.powerapps.com/79d7f767-4dff-448d-87ec-b3d2f7cdf27d

      Delete
    3. Hmm.. seems hard to get that to work in an easy way.

      Delete
  7. Did Microsoft change the way the controls store the image? When calling my Flows, the data that gets sent is in the format of
    Blob:[guid]
    where [guid] is an actual guid.
    Both the 'Add Picture' and 'Camera' controls store the image in the same format.

    ReplyDelete
    Replies
    1. As noted in the article, it won't work in the Windows application - but works in the web version.

      Delete
    2. I get blob: when using the picture control. My users would be happier if they could use their native camera but its not possible to save images from there I dont think. We have only just embarked down the mobile app route but the more I use powerapps and flow the more constraints I come up against. I think I will speak to the ITdepartment about other solutions because there are far too many constraints in powerapps and flow,

      Delete
    3. On a mobile device use the image control instead and on onselect the user should be able to pick the device camera.

      Delete
  8. I managed to get this one to work and it creates the file but the file does not open. Windows photo viewer says the file appears to be damaged, corrupt or too large (it's about 64kb). Paint tells me it's not a valid bitmap file or unsupported. I am desperate to get this solution working as it will make quite a few of my users very happy! Please help.

    ReplyDelete
    Replies
    1. Open the file in an editor and examine the contents.

      Delete
  9. This one doesn't work either. I have like 5 different methods and apps trying to save an image to SP and NONE, "0" work. I followed your instructions to the 'T'.

    The code: (oh sorry this is supposed to be no-code; the expression): Saveimage.Run("test.jpg",First(PictureColl).Url) gives error of invalid number of arguments. If I back out and just use: Saveimage.Run("test.jpg") the error goes away, click submit and the nice floating dots travel accross the top. Go into SP and voila..... as anticipated, 'no image', no new document, nothing. Excellent.

    Now I'm not a rocket scientist,but, the differences in our two expressions are quite drastic in terms of arguments. Now if it worked for you and apparently others and it doesn't for me, in the least on Jan 4, 2018, it really makes me wonder about my ongoing subscription. I pay for a subscription and expect it to work. Who has time to go through and troubleshoot Microsoft's apparent lack of devotion to us EVERYTIME you attempt something with this tech.

    So. Anyone else have similar difficulties?

    ReplyDelete
    Replies
    1. I had the same issue. The .Run call expected 3 arguments. There was a third argument Compose_Input. I just passed a copy of the second argument.

      Saveimage.Run("test.jpg",First(PictureColl).Url, First(PictureColl).Url)

      Delete
  10. Great solution. Works like a charm!

    ReplyDelete
  11. It seems the Url property is no longer present on the Camera1.Photo object. This approach worked for me without this. I actually uploaded the image as a list item attachment using the same approach and including an ID property in my PictureColl. Do we need to determine format or can we always assume jpg? I'm thinking iPhone 99% of the time.

    ReplyDelete
    Replies
    1. I believe most cameras take .jpg these days. Look at my sample files and you see what props where being used. Not sure if that has changes or not recently.

      Delete
  12. Hi Mikael, in regards to quality output of the file, is base64 limited to low quality images or something can be done? e.g. I take a picture from a 4MP camera, I expect it to get out at 4MP but when I get the base64 and convert it it's Always in low quality.

    Is this a limitation on how the conversion itself works?

    Thanks!

    ReplyDelete
    Replies
    1. Currently yes - if you use an image control and pick your camera when the upload dialog show (on a mobile device) the quality is better. We just have to wait for a better way to get the actual blob in full res so we can treat it as bytes like we want.

      Delete
  13. Do you know how long before Microsoft is releasing a native way with camera upload from powerapps to SP?

    ReplyDelete
    Replies
    1. Provably seven years. The time required to let it fester, people asking questions in these forums for the first five, then the last two during which Microsoft will recommend adding this to their user recommendations list after nit having read the last five years of complaints.

      Just standard business process. Nothing to worry about. During that time, however, you can play with MS Delve or Sway.

      Delete
    2. Not to spread false hopes, but when summer is over at the latest, I think this post might be obsolete :)

      Delete
  14. Hello Mikael,

    Thank you so much for this post. I followed your instructions to save the images on OneDrive, not SP. Everything seems to be working for me except when I try to open the file on OneDrive it says that the file is corrupted.

    ANy ideas as to why this could be happening?

    Thank you.

    ReplyDelete
  15. I almost got it but I'm having an issue with getting rid of the "data:image/jpeg;base64," part of the file content. Am I supposed to use another expression somewhere in the flow?

    ReplyDelete
    Replies
    1. This comment has been removed by the author.

      Delete
    2. I edited the my flow and even though I didn't change anything about the file content, it seems to be working now.

      Delete
  16. I recommend reading my post http://www.techmikael.com/2017/05/saving-collection-of-images-from.html which has sample files for download.

    ReplyDelete
  17. Hi Mikael,

    Thanks for the wonderful post. I was thinking if you can blog on using Computer Vision API provided by Microsoft to capture text from image like Business Cards and load it into Sharepoint or CRM.

    ReplyDelete
    Replies
    1. Nice use case indeed and I'll think about it :)

      Delete