shirley yin

How I built cowboyz

June 18, 2019

I love emojis.

My friend Anh inspired/challenged me to build an app that generates cowboy variants of emojis, based on this image that has been floating around social media:

screenshot of emoji keyboard with cowboy hats on each emoji The original source, as far as I can tell — I’ve seen it screenshotted and reposted in several places and it gets hard to track. (As an aside, I’m unfortunately fulfilling the meme of there being only four websites in 2k19, all containing screenshots of each other with compounding jpeg artifacts. The trope is of things on the internet lasting forever, yet any individual social media post feels ephemeral and I feel uncertain linking to it, not knowing if the person I’m linking to will have changed their username or deleted it in a year’s time, breaking the url.)

First attempts at image processing

It sounds pretty simple to overlay a cowboy hat onto emojis. I started out with a hardcoded list of images and wrote a Python script that dropped down to the shell and called ImageMagick to composite two images, with hardcoded coordinates that roughly looked right.

for filename in input_files:
    # increase the canvas size to provide space for cowboy hat
    cmd = 'convert {input} -gravity Center -background transparent -extent 100x100 {output}'\
        .format(input=filename, output=out_filename)
    subprocess.call(cmd, shell=True)

    # overlay cowboy hat
    cmd2 = 'convert {input} cowboy-hat.png -composite {output}'\
        .format(input=out_filename, output=composite_filename)
    subprocess.call(cmd2, shell=True)

As it turns out, you can’t use the same coordinates to position the cowboy hat for all emojis because they’re not all centered at the same midpoint — some are offset by hands, or a tongue, or hats, or devil horns, for example. In addition, some emojis are rotated (upside-down smiling face) or differ in size (skulls).

upside down smiling face wearing a cowboy hat on its chin When you realize you need a rotation parameter

I ended up writing a preprocessing script to generate a json dictionary containing the position, rotation, and size for each emoji. This was by far the most laborious part – I had to try out arbitrary numbers and nudge pixels back and forth until the cowboy hat was positioned correctly (not unlike writing CSS).

{
    ...
    "grinning-face-with-one-large-and-one-small-eye-1f92a": {
        "size": [
            132,
            132
        ],
        "offset": [
            24,
            22
        ],
        "rotation": 15,
        "hat_offset": [
            -10,
            -20
        ]
    },
    ...
}

Some emojis simply don’t work well without more intervention. If you look closely at the original tumblr post above, you’ll notice that the OP has carefully edited around the hat where simply overlaying it on top would look clunky. Some examples are:

emoji face with three hearts wearing a cowboy hat emoji sleeping face wearing a cowboy hat emoji starry-eyed face wearing a cowboy hat emoji cold-sweat face wearing a cowboy hat

I left these as is because I couldn’t think of a way to programmatically do what are essentially Photoshop layers.

In a few cases, I was able to improve the cowboy hat-wearing slightly by positioning the hat differently:

angel halo emoji wearing a cowboy hat cowboy emoji wearing a second cowboy hat

How does a cowboy emoji wear a cowboy hat? 🤔

The web app

I’m mainly familiar with Django but I chose to use Flask (largely on Jolene and Anna’s recommendation) because this is a very simple application and I don’t need most of Django’s useful business features, such as translation support, middleware, etc. I upgraded my shoddy ImageMagick subprocess calls to a simple API that uses PIL to process images in memory. I threw together a quick front-end using Riot.js and had some fun with CSS text effects and animations.

screenshot of cowboyz app yeehaw

Vendor implementations of emoji images are copyrighted, of course. In my case, I used Apple emojis and scraped them from the web. Although I could probably claim fair use, I certainly don’t have the resources to defend myself in court, but commutatively, I am also too inconsequential to be taken down for copyright infringement. 🤠

But why?

I’ve shown this to friends and the predominant reaction is a bewildered “… why?”

Why not? 🤪 I don’t get to do fun throwaway projects at my work work.

Doing side projects is an exercise in mindfully (ick) lowering expectations or being forced to do it by the constraints of reality. I initially wrote my throwaway ImageMagick scripts in December of last year but since I’ve been working on it in sporadic bursts it’s taken a long time to release anything. Cowboyz doesn’t constitute 6 months of active work and I want to release things faster (agile et cetera, hand wavy). There are also some old projects that cause me embarrassment that I want to revisit and improve (looking especially hard at bcfires).

Next steps

I hope to add the “Animals & Nature” category soon because I think those will be a valuable addition to my instant messaging.

I’m temporarily hosting this project on Heroku because I haven’t figured out how to host multiple sites in nginx, nor do I have any semblance of deployment/CI/CD/etc. workflow. DevOps is an area in which I am painfully lacking in knowledge (setting up this static site was the first time I’ve ever configured nginx from scratch by myself), and this will be a good opportunity to learn. This will be the first time I’m configuring Docker from scratch by myself!

In the meantime, feel free to use cowboyz in your everyday communication!

Now, if you’ll excuse me, I need to get back to my Goodreads Reading Challenge.

Resources:

https://unicode.org/emoji/charts/full-emoji-list.html
https://emojipedia.org/apple/