In the previous post, I shared how an Azure function can really take load off your Rest API or other mechanisms to do some automated action on a new addition to something like a blob storage.
In the example, we wrote a small Azure function app that, once stitched in, get triggered on a new upload to a blob storage. This Azure function uses Azure Cognitive Service to generate a smart thumbnail and saves it back to another blob storage.
This post is the other part of story and may be considered a prequel/sequel.
We will see how quickly we can write an app that can upload to an Azure Blob Storage!
We created a storage account with two blob storage containers named originals and thumbnails. We will go back to the containers in the portal click on the … and select properties. In the container property window, we will find the URL that is needed to access the blob storage.
In the container settings, you will find the access keys; be sure not to share the access keys!
For the demo purpose, I saved the keys in App.xaml
<Application
x:Class="PicUpload.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:PicUpload"
RequestedTheme="Light">
<Application.Resources>
<x:String x:Key="SubscriptionKey">YOUR_COGNITIVE_SERVICE_KEY</x:String>
<x:String x:Key="BaseURI">https://api.projectoxford.ai/face/v1.0/persongroups</x:String>
<x:String x:Key="StoragePath">https://function073638f08fcd.blob.core.windows.net/</x:String>
<x:String x:Key="StorageAccountName">function073638f08fcd</x:String>
<x:String x:Key="StorageAccountKey">YOUR_STORAGE_ACCOUNT_KEY</x:String>
</Application.Resources>
</Application>
In the program I initialized variables and objects as
private static readonly string StorageAccountName = Application.Current.Resources["StorageAccountName"].ToString();
private static readonly string StorageAccountKey = Application.Current.Resources["StorageAccountKey"].ToString();
private static readonly StorageCredentials cred = new StorageCredentials(StorageAccountName, StorageAccountKey);
public static readonly string storagePath = Application.Current.Resources["StoragePath"].ToString();
public static readonly CloudBlobContainer blobContainer = new CloudBlobContainer(new Uri(storagePath + "originals"), cred);
public static readonly CloudBlobContainer thumbContainer = new CloudBlobContainer(new Uri(storagePath + "thumbnails"), cred);
In the app, I provided two option to pick an image from, either the in-built camera app or the picture gallery
For picture gallery, I used FileOpenPicker in-built control, set its default path to Pictures Library and added the extensions I want to allow. Since the function does not return a file but instead directly uploads to blob, which is an async call, I declared my function as async.
using Windows.Storage.Streams;
using Windows.Storage.Pickers;
private async void btnPickFromFile_Click(object sender, RoutedEventArgs e)
{
FileOpenPicker filePicker = new FileOpenPicker();
filePicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
filePicker.ViewMode = PickerViewMode.Thumbnail;
filePicker.FileTypeFilter.Clear();
filePicker.FileTypeFilter.Add(".jpeg"); filePicker.FileTypeFilter.Add(".jpg");
filePicker.FileTypeFilter.Add(".png"); filePicker.FileTypeFilter.Add(".gif");
StorageFile file = await filePicker.PickSingleFileAsync();
if (null != file)
{
string blobFileName = await updateToBlob(file);
AddFaceToPerson(blobFileName);
}
}
This is even simpler for the camera app. I just called in the CameraCaptureUI
using Windows.Storage.Streams;
using Windows.Media.Capture;
private async void btnPickFromCamera_Click(object sender, RoutedEventArgs e)
{
CameraCaptureUI dialog = new CameraCaptureUI();
StorageFile file = await dialog.CaptureFileAsync(CameraCaptureUIMode.Photo);
string blobFileName = await updateToBlob(file);
AddFaceToPerson(blobFileName);
}
Once, I have the image, I can upload to the blob storage as
using Windows.Storage.Streams;
private async Task<string> updateToBlob(StorageFile file)
{
CloudBlockBlob blob = null;
string filename = null;
BitmapImage bitmapImage = new BitmapImage();
IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.Read);
if (null != fileStream)
{
fileName = System.Guid.NewGuid() + "." + file.Name.Split('.').Last<string>();
bitmapImage.SetSource(fileStream);
// Show image in a image box - CapturedPhoto
CapturedPhoto.Source = bitmapImage;
await blobContainer.CreateIfNotExistsAsync();
blob = blobContainer.GetBlockBlobReference(blobFileName);
await blob.DeleteIfExistsAsync();
await blob.UploadFromFileAsync(file);
}
return filename;
}
I renamed files to guid.ext so I can save all uploads, otherwise DeleteIfExistsAsync() will overwrite any file with same name in the store. I can now go back to the azure portal and verify my images getting uploaded.
Also, the thumbnails are getting generated. (There is no thumbnail for one of the files because in my Azure function I had named the source as original/{name} instead of originals/{name}. Have corrected it in original post as well)
Now I have a thumbnail getting generated for every image file I upload to the blob storage. In the Function log I can see the function getting fired and its results as
I can write another Azure function that triggers on image addition to thumbnail blob and send it through events or notification hub, I can read text in the image or identify object through Azure cognitive service and send through SMS, etc… Possibilities are enormous!
NOTE:
When you create a container from within the program code, it is by-default set to private. This is when you will not be able to access it directly. You need to set permissions explicitly on the container.
await HttpHandler.tempContainer.CreateIfNotExistsAsync();
BlobContainerPermissions permissions = new BlobContainerPermissions();
permissions.PublicAccess = BlobContainerPublicAccessType.Blob;
await HttpHandler.tempContainer.SetPermissionsAsync(permissions);
blob = HttpHandler.tempContainer.GetBlockBlobReference(blobFileName);
await blob.DeleteIfExistsAsync();
await blob.UploadFromFileAsync(file);
Comments
Please log in or sign up to comment.