HOME  → POSTS  → 2019

Converting iMessage Stickers, Animoji, and Memoji to Slackmoji (Slack Emoji)

Tech Life1176 words6 minutes to read

With the impending shutdown of HipChat (February 2019), my team has been working hard on migrating everything over to Slack. Why not have some fun while we're at it?

Emoji

Slackmoji

Firstly, what is Slackmoji? Slackmoji (the word) refers to Slack + emoji — namely, the custom emoji you can add to your Slack account. It adds a bit of color and personality to the default Slack experience. Since I work in technology and the web, my set of Slackmoji tends to be Mac/Web/Browser-centric.

:browser-chrome: :browser-edge: :browser-firefox-developer-edition: :browser-firefox: :browser-internetexplorer: :browser-opera: :browser-safari: :browser-safari-technology-preview:
:activity: :activity-arrow-up: :activity-circular-arrow: :activity-double-arrow: :activity-red-arrow: :activity-pingpong: :activity-finger-number1: :activity-circle-321: :activity-crown: :activity-diamond: :activity-trophy:
:icon-1password: :icon-alfredapp: :icon-casper: :icon-hipchat: :icon-keybase: :icon-msexcel: :icon-msword: :icon-sublime: :icon-things-app: :icon-virtualbox: :icon-vmware-fusion:
:lang-swift: :lang-typescript: :lang-python: :kubernetes: :docker2: :datadog: :zeldabotw-heart-container:

There are a few things I’ve learned as I’ve been creating my own slackmoji recently.

  1. 128 pixels is a pretty solid target for the size of the image — especially animated GIFs. Anything smaller and you end up with some nasty dithering around the edges of the animation.

  2. Similar to emoji in iMessage (iOS), emoji-only lines will be at one size (32 points), while emoji+text lines are smaller (24 points).

  3. When converting an Animoji recording into an animated GIF, expect you’ll need to edit each PNG frame to remove as much whitespace (and get as much character on-screen) as possible.

Before We Begin…

While it’s possible that you can adapt these instructions to another platform, this tutorial is written assuming that:

  • You have a modern iOS device (like an iPhone or iPad), that is running at least iOS 11, and is signed into your iCloud account.

  • You have a modern Mac that is logged into the same iCloud account as your iOS device. In other words, you can receive your iMessages on your Mac.

  • You are not afraid of the Terminal, and you have Homebrew already installed.

Animated iMessage Stickers

Send yourself a sticker

Start out by sending yourself an iMessage sticker from one of your favorite iMessage apps. In my case, I’m going to use the Heart Container sticker from Zelda: Breath of the Wild. You can use whatever (animated) sticker you’d like.

Receive the sticker and save it

Once the message has come through in Messages on your Mac, you can drag the image into a folder in Finder. I would recommend renaming it to something more memorable.


Process the images into something usable

In Terminal, install FFMPEG and Imagemagick using Homebrew.

brew install ffmpeg imagemagick

How to make GIFs with FFMPEG and Imagemagick animated GIF layers showing through transparency were helpful in figuring this out.

#! /usr/bin/env bash
set -exo pipefail;

find . -maxdepth 1 -type f -name '*.png' \
    | xargs -P $(nproc) -I {} bash -c '
        ff=$(basename -- "${1%.png}");
        if [ ! -f "${ff}.gif" ]; then
            mkdir -p "/tmp/${ff}" && \
            ffmpeg \
                -i "$1" \
                -filter_complex "[0:v] fps=12,scale=w=128:h=-1,split [a][b];[a] palettegen=stats_mode=single [p];[b][p] paletteuse=new=1" \
                -y "/tmp/${ff}/%05d.png" && \
            convert -dispose 2 "/tmp/${ff}/*.png" "${ff}.gif" && \
            rm -Rf "/tmp/${ff}";
        fi;
    ' _ {} \;

Let’s break this down:

  1. Find all files in the current directory that end with .png.

    find . -maxdepth 1 -type f -name '*.png'
    
  2. Pipe those results into xargs. Parallelize the processes according to the number of cores you have (nproc). Each process will be a bash process.

    xargs -P $(nproc) -I {} bash -c ' ... ' _ {} \;
    
  3. Figure out the filename of the input, without the file extension. Save this value into the ff variable.

    ff=$(basename -- "${1%.png}");
    
  4. Only process the files if we do not already have a same-named GIF file.

    if [ ! -f "${ff}.gif" ]; then
      ...
    fi;
    
  5. We’ll use the /tmp directory for our processing. Let’s create a working directory with the name of the image.

    mkdir -p "/tmp/${ff}"
    
  6. Here’s the complex part.

    1. We call FFMPEG and specify our input file with -i.

    2. We specify a set of complex rules using -filter_complex, but they key takeaways are that:

      1. Set frames per second to 12.

      2. Set the width to 128px, and the height as auto.

      3. We will pre-process the PNG first to generate a color palette, and the GIF processor will use this to help create better-colored images and cleaner transparency.

    3. We set -y to overwrite any existing files.

    4. We use some bash goodness to create filenames for each frame as a 5-digit value.

    ffmpeg -i "$1" \
        -filter_complex "[0:v] fps=12,scale=w=128:h=-1,split [a][b];[a] palettegen=stats_mode=single [p];[b][p] paletteuse=new=1" \
        -y "/tmp/${ff}/%05d.png"
    
  7. Use the convert command to read all of the PNG files and write a new GIF file.

    convert -dispose 2 "/tmp/${ff}/*.png" "${ff}.gif"
    
  8. Let’s clean up after ourselves by deleting our working directory.

    rm -Rf "/tmp/${ff}";
    

Cleaning up

ImageOptim

Using ImageOptim to squeeze unnecessary data out of your images.

At the end, you will have a new animated GIF image that you can upload into Slack. :zeldabotw-heart-container:

Converting Animoji or Memoji videos

Sending/receiving videos

This is done the same way as stickers. Follow the same process to get a file into Finder.

Process the images into something usable

Overall, this is the exact same process, only we’re going to stop mid-way and edit the frames.

  1. I’ve already explained what most of this does above, but this step is essentially extracting all of the frames in the video into a working folder under the /tmp directory.

    find . -maxdepth 1 -type f -name '*.mov' \
        | xargs -P $(nproc) -I {} bash -c '
            ff=$(basename -- "${1%.mov}");
            if [ ! -f "${ff}.gif" ]; then
                mkdir -p "/tmp/${ff}" && \
                ffmpeg \
                    -i "$1" \
                    -filter_complex "[0:v] fps=12,scale=w=300:h=-1,split [a][b];[a] palettegen=stats_mode=single [p];[b][p] paletteuse=new=1" \
                    -y "/tmp/${ff}/%05d.png"
            fi;
        ' _ {} \;
    
  2. You’ll want to use your favorite image editing tool (e.g., Pixelmator, Photoshop). Crop as closely to the face as possible:

    1. Keep every image an identical size.

    2. Crop in an identical spot. Otherwise the frame location is going to be wrong.

    3. You can use something like QuickLook to preview the frames. Feel free to delete any that don’t make the animation better.

    4. Since you need to squeeze your animation into a maximum of 128kb, you have about 10–15 frames, tops.

    Animating Animoji

  3. Once the frame editing is complete, merge each frame back into a single GIF image.

    convert -dispose 2 "/tmp/${ff}/*.png" "${ff}.gif"
    
  4. Cleanup once you’re done.

    rm -Rf "/tmp/${ff}";
    

At the end, you will have a new animated GIF image that you can upload into Slack. :boom:

Conclusion

With your new custom Slackmoji, you can bring your own style and personality to your Slack account. By borrowing some style from things that you enjoy, you can add a fun bit of flavor to your work conversations. :activity-diamond:

Ryan Parman

is an engineering manager with over 20 years of experience across software development, site reliability engineering, and security. He is the creator of SimplePie and AWS SDK for PHP, patented multifactor-authentication-as-a-service at WePay, defined much of the CI/CD and SRE disciplines at McGraw-Hill Education, and came up with the idea of “serverless, event-driven, responsive functions in the cloud” while at Amazon Web Services in 2010. Ryan's aptly-named blog, , is where he writes about ideas longer than . Ambivert. Curious. Not a coffee drinker.