Have you ever loved something so much that you might never get enough of it? Party Parrots are something like that for me. There hasn't been a single time when these quirky parrots weren't successful in making me smile.
Since the time the world slipped into a pause. It only made more and more sense to why not build a Party Parrot GIF generator called PartyStarter for my love of the parrots. As crazy as the idea sounds, I wanted to go a step ahead fit the use-case to be a serverless deployment, and hence this blog for taking you through my build process and how you can do stuff with serverless. GIF's looked absolutely gorgeous, I tweeted some out.
Vipul Gupta 🐣Love Party Parrots?
Wanna create your own Party Parrots like GIFs?
PartyStarter coming soon on a browser near you! 🐣12:41 PM - 12 Jun 2020
Cutting straight to the chase, I planned to keep my build as straightforward as possible. Focusing just on the application logic rather than worrying about deployment, scaling, or even setting up the server as serverless will take care of it all.
Azure Functions are nothing but small fragments of code that can be run without worrying about the underlying infrastructure, scaling, security, and 100 other things that come up when deploying code to production. Hence, this containerized style deployments of Azure functions seemed like the right fit for PartyStarter going serverless.
Through John Hobbs's help, the maintainer for "Cult of the Party Parrot" website. I was able to find accurate colors of the OG Party Parrot GIF. With that piece of information, a little Python, and a cup of coffee. I sat down to build the v1 of PartyStarter.
The first hurdle I had to jump through, was transforming the right pixels on an image that contains a color and not alter the ones in the background. Hence, a necessary requirement ofPartyStarter are to be transparent image. This also makes sense because GIFs look considerably better with a transparent background & work better with my use-case. Let's try to understand this better in Python (Azure Functions is available for several popular languages & stacks)
So, each image you see is made of pixels. Lots and lots of pixels. If we have a
200x200 image. That means we will be parsing through 40k data points pixel by pixel, change color of said pixels, and save the image. It's a resource-intensive task which is another great reason behind going with Serverless. No matter how big the picture a user uploads, our server can handle it like a boss.
In programming terms, each image is basically a 2-dimensional array that can be traversed with an
Y coordinate telling us what pixel is at which position in the image. Let's open a random image and load it using
Image.load() method of Python Pillow library.
>>> Image.open('~/partystarter/input/twitter.png') <PIL.PngImagePlugin.PngImageFile image mode=RGBA size=400x400 at 0x7F86416BFCF8> >>> im.load() <PixelAccess at 0x7f864285b170>
The next requirement, is images need to be RGBA mode. In next iterations, we can work towards converting them into RGBA and maintain transparency. We check what color is the pixel at [223, 123] in the image and find it to be(29, 161, 242, 255) according to RGBA color model (Red, Blue, Green, Alpha) where Alpha is transparency. These are the pixels we want to alter into a different color.
>>> pixels = im.load() >>> pixels[223,123] (29, 161, 242, 255)
Similarly, for a pixel located in a transparent area for which we get the output as (0,0,0,0) are ones that we don't want to alter. And, that's about it. Simple right?
>>> pixels[0,0] (0, 0, 0, 0)
With Python, I traverse through only color pixels of the original image, changed their colors to what and how we want them. Later, repeat this about a total of 18 times to basically create 18 different frames. And voila! Generate a GIFs from that runs at 18 FPS. Here's how the color altering
party_changer() method looks like.
While the party is being changed, there needs to be someone willing to step in and save the party as well. Hence, here's how I save the party GIF with the
The FPS or Frames per second matters a lot when creating great GIF's. Low FPS means your GIF will stutter and won't look smooth. While keeping a higher FPS GIF would mean folks seeing it might have a chance to contract a seizure. Let me demonstrate.
As you can see the difference, the GIF on the left is showing 18 frames at 150 milliseconds (ms) and the on the right is showing just 6 frames in 180 ms. The GIF on the right is stuck at one color for some ms to keep in sync with the other GIF in the collage. Here's how the entire code looks when it comes together.
Till this point, I have created my application, the code works on my machine and it looks great to be honest. PartyStarter is ready to party and get deployed. To deploy the Azure Function, I used VScode to build a new Azure function locally for testing and later tweaked my code to deploy it over Azure. If a practical approach is not your thing, why not read a story that I wrote about serverless in The what, why, and how of Serverless the easiest way possible.
- If users grow, serverless helps to auto-scale dynamically as per traffic using only what's needed leading to higher efficiency and greater savings on your subscription.
- If users upload HD photos and PartyStarter needs more resources to process then serverless manages performance like a pro without supervision
- and other 100 things that I won't sell you on rather you can read here. Let's build Devs!
Like functions we code in Python or any language, they need to be called somewhere in the code to make them run when needed. Similar is the case for Azure Functions where they are "called" by triggers that lead to event-driven execution of functions. These triggers can execute our code with as simple events as making an HTTP call on an endpoint or processing files when they get uploaded onto Blob storage or even timer triggers that run at predefined schedules much like cron jobs. You can check them all of them out on Azure Docs.
What I envisioned PartyStarter in a serverless use-case was for users to upload images on to containers which triggers a Function to basically run my code to create a GIF of that image. Therefore, I will be going with the BlobTrigger for my use-case, where we can process new and modified Azure Storage blobs. Blobs are nothing but files that we can upload on containers hosted on Azure Storage account. Check out the diagram below to get a better idea of the same. We will be managing our blobs with Python SDK for Blob Storage.
Source: Microsoft Azure Documentation
Much like that awesome tutorial, I always tend to find 15-20 examples, guides, tutorials detailing every use-case and feature right in the Azure docs whenever I was looking for an idea to build something. That way I didn't have to consult any other sources for getting started with Python Azure Functions. The best part and NECROMANCY ALERT that I saw. Everything just ... works right from the get-go. VScode integration of setting up the entire project locally with the right stack, virtual environment, settings, authorization keys, .gitignore gives the control back to the user to build, customize, and test. It gives you ready to test the function template and code in nearly seconds. I went wrong with a couple of steps, but once I got the hang of it. I was flying off from screen to screen like a ninja. What a rush!
Here are my details of setting up a new local Azure Functions projects + the configuration for the Azure Blob Storage Trigger. When you have tested them locally, then be sure to connect them to a subscription for them to run without interruptions.
Uploading the Azure Function that I just created and testing it out through the Code+Test playground on Azure was a breeze and exactly what I hoped for. Making a few tweaks to my PartyStarter code. It was ready for the party!
With the PartyStarter now a serverless app. I can use it however I like. I could build a web or native app around it, integrate with a command-line interface, use it to generate a bunch of emoji packs for folks to use in their organizations. The possibilities for PartyStarter feel truly endless. The best part the code is open-source at GitHub and go ahead take a crack at it.
Well, that's about it. Starting these many parties has been tiring. I have to fix a lot of bugs that come up in the code as well. I hope this build blog helps you get some motivation to build your next idea, project, or work stuff with serverless!