Resize images in blob storage with Azure Webjobs

Despite the fact that I don’t do much C# these days, I’m still digging Microsoft Azure and it’s awesome services. Today, I’m gonna focus on Azure Blob Storage and WebJobs particularly. For my travel blog I want to upload photos to the blob storage and generate sizes that I use on my website. There is lots of ways how to do it, but one of the most efficient and simplest is to use Azure WebJobs.

Azure Webjobs are part of Azure Website and they can do the heavy lifting of background processing and lots of various service interactions. You can run lots of different scripts and languages (powershell, python, shell, php, javascript or even java), but I want to use Azure SDK with C#. But first things first, we need to resize images.

Resize image

There are multiple ways how to resize JPEG image in C# and one of them is to make use of an awesome open-source library ImageProcessor.

Firstly install Azure SDK via Web Platform Installer. After that create a new project Cloud -> Azure Webjob and install ImageProcessor package with Nuget for that project.

private static void Resize(int width, Stream input, Stream output)
{
  using (var factory = new ImageFactory(preserveExifData: true))
    using (var memory = new MemoryStream())
    {
      factory.Load(input)
        .Resize(new Size(width, 0))
        .Format(new JpegFormat { Quality = 75 })
        .Save(memory);

      memory.CopyTo(output);
    }
}

The ImageFactory class serves as a fluent interface and is really straightforward to use. I want my photos to have unified width and using 0 for heigh property in new Size(width, 0) will scale it appropriately.

Note the usage of memory stream instead of the stream passed into the function, it is due to ImageProcessor using SetLength method on stream which is not implemented on network streams that Azure is using. Damn you, liskov principle violation.

Interact with blob storage

Second step is to interact with the blob storage account. The basic idea is to have two containers — one for input files, the other one for output. When the file is uploaded to the input one, it gets picked up by the job, processed and saved to the ouput.

If you mark your method with [BlobTriggerAttribute](input) and [BlobAttribute(output)] the Azure SDK makes sure that the method gets triggered when the new blob is uploaded.

public static void Create640x([BlobTriggerAttribute("barakuba-input/{name}")] Stream input,
                              [BlobAttribute("barakuba/640x/{name}", FileAccess.Write)] Stream output)
{
  Resize(640, input, output);
}

public static void Create240x([BlobTriggerAttribute("barakuba-input/{name}")] Stream input,
                              [BlobAttribute("barakuba/240x/{name}", FileAccess.Write)] Stream output)
{
  Resize(240, input, output);
}

The two methods above are called when a file is uploaded to a container called barakuba-input, they resize the photo to 640px and 240px width and output it in barakuba container under the proper folder.

Both methods get executed so you can keep one transformation per method which makes the code super simple and clear. And that’s all you need from the code perspective.

Configure Azure Website

There is a small gotcha — you need to configure your blob storage connection string in the environment of your website and not in your web.config file. To do so, go to Azure management portal, select your website and click Configure.

Find the section with Connection Strings and add

AzureWebJobsDashboard  DefaultEndpointsProtocol=https;AccountName=<blob storage>;AccountKey=<your key>
AzureWebJobsStorage    DefaultEndpointsProtocol=https;AccountName=<blob storage>;AccountKey=<your key>

Easiest way to get a connection string is inside Server Explorer in Visual Studio and you can use the same blob storage for both of them, the first one stores the logs and the second one is for the actual work.

After that, publish the job from Visual Studio (right-click on project and Publish as Azure Webjob), select the schedule (or make it run continuously) and you are all set.

Also, there is an awesome UI interface based on top of the logs that you can access on the URL that’s provided on the WebJobs tab in your Azure Website.

We implemented a recurring job that has a monitoring dashboard and interacts with blob storage by resizing images. All of that in just couple lines of code.

Comments

Der Vinylizer: Thanks for this article. It took me a long time to find out that the two Create-Functions should not be placed inside the program.cs but inside the Functions class. Maybe worth to mention this.


Would you like to get the most interesting content about C# every Monday?
Sign up to C# Digest and stay up to date!