Generate an image thumbnail using Azure Functions
Dimitar Iliev ??
Azure AI Solutions Architect ● B. Sc. Computer Science and Engineering ● 7 x Microsoft Certified ● 23 x Microsoft Applied Skills ● Speaker ● Generative AI ● Scrum Master Certified ● 1 x GitHub Certified
What is Azure Blob Storage?
According to the official?MS Docs?(Introduction to Blob (object) storage - Azure Storage | Microsoft Docs)?Blob storage is Microsoft’s cloud storage which can be used to store large volumes of unstructured data like images, audio, video and others.
What are Azure Functions?
According to the official?MS Docs?(Azure Functions Overview | Microsoft Docs)?an Azure Function is a serverless solution that allows you to write less code, maintain less infrastructure, and save on costs.??
Some of the benefits of using Azure Functions are:?
? If you want to find out more about Azure Functions, I cover other information and usage for them in my other article:
and
Setting up the Storage Account and Containers
I have already created a storage account named 'ilievsa'.
In it, I created two containers. The first container named 'profileimages' will store the profile images for the users, while the second one named 'thumbnailimages' will store the thumbnail images generated from the profile images.
Now let’s create and implement the two Azure Functions we will use.
Project structure
Implementing the Azure Functions
First, we will create an Azure Function which will use an HTTP trigger. It will receive a single file from an HTTP POST request and upload that file to the 'profileimages' container.?
Let’s take a look at the code implementation for the function:
领英推荐
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Storage.Blob;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
namespace ImageUploader
{
? ? public static class ImageUploader
? ? {
? ? ? ? [FunctionName("upload")]
? ? ? ? public static async Task<IActionResult> Run(
? ? ? ? ? ? [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req,
? ? ? ? ? ? [Blob("profileimages", Connection = "BlobStorageConnection")] CloudBlobContainer outputContainer)
? ? ? ? {
? ? ? ? ? ? byte[] imageBytes;
? ? ? ? ? ? var file = req.Form.Files[0];
? ? ? ? ? ? using (var ms = new MemoryStream())
? ? ? ? ? ? {
? ? ? ? ? ? ? ? file.CopyTo(ms);
? ? ? ? ? ? ? ? imageBytes = ms.ToArray();
? ? ? ? ? ? }
? ? ? ? ? ? var cloudBlockBlob = outputContainer.GetBlockBlobReference(file.FileName);
? ? ? ? ? ? using (MemoryStream stream = new MemoryStream(imageBytes, 0, imageBytes.Length))
? ? ? ? ? ? {
? ? ? ? ? ? ? ? await cloudBlockBlob.UploadFromStreamAsync(stream);
? ? ? ? ? ? }
? ? ? ? ? ? return new OkResult();
? ? ? ? }
? ? }
}
Next, let’s create the Azure Function which will use the Blob Storage trigger and make the thumbnail image. This function will take the image we just uploaded, create a thumbnail from it and upload that new thumbnail image to the 'thumbnailimages' container.
For resizing of the image, we will use the following NuGet package: System.Drawing.Common.
Let’s take a look at the code implementation for the function:
using System.Drawing;
using System.IO;
using Microsoft.Azure.WebJobs;
namespace ThumbnailImageGenerator
{
? ? public class ThumbnailGenerator
? ? {
? ? ? ? [FunctionName("generate")]
? ? ? ? public static void Run([BlobTrigger("profileimages/{name}", Connection = "BlobStorageConnection")] Stream image, [Blob("thumbnailimages/thumbnail-{name}", FileAccess.Write, Connection = "BlobStorageConnection")] Stream thumbnail)
? ? ? ? {
? ? ? ? ? ? byte[] imageBytes;
? ? ? ? ? ? byte[] buffer = new byte[16 * 1024];
? ? ? ? ? ? using (MemoryStream stream = new MemoryStream())
? ? ? ? ? ? {
? ? ? ? ? ? ? ? int read;
? ? ? ? ? ? ? ? while ((read = image.Read(buffer, 0, buffer.Length)) > 0)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? stream.Write(buffer, 0, read);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? imageBytes = stream.ToArray();
? ? ? ? ? ? }
? ? ? ? ? ? using (MemoryStream stream = new MemoryStream(imageBytes, 0, imageBytes.Length))
? ? ? ? ? ? {
? ? ? ? ? ? ? ? using (Image imageFromStream = Image.FromStream(stream))
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? int height = 100;
? ? ? ? ? ? ? ? ? ? int width = 100;
? ? ? ? ? ? ? ? ? ? using (Bitmap bitmap = new Bitmap(imageFromStream, new Size(width, height)))
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? bitmap.Save(thumbnail, System.Drawing.Imaging.ImageFormat.Jpeg);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? }
}
Let's test our implementation. Start both of the Azure Function projects.
Using Postman let’s make an HTTP POST request with a file added to the first Azure Function.
Observe that the first Azure Function completes successfully.
Then, after a short time, we can see that the second Azure Function was triggered as well, which also executed successfully.
Let’s take a look at what we have in our containers now.
In the 'profileimages' container we can see that our profile image was uploaded as expected.
Next, open the 'thumbnailimage' container. Inside we will see our newly generated thumbnail image.
If we download, open and compare both of the images, we can see the difference in sizes.
Perfect. We have successfully uploaded a profile image using an Azure Function with an HTTP trigger to a container. Then, it triggered an Azure Function with a blob storage trigger to generate a thumbnail image and upload it to another container.
Thanks for sticking to the end of another article from?"Iliev Talks Tech".?#ilievtalkstech
The full, more detailed implementation of this example can be found on my GitHub repository on the following link: