Gabe's Code

Stuff I've learned along the way

Web Development

more...

profile for Gabriel Luci at Stack Overflow, Q&A for professional and enthusiast programmers

Web Development: Recreating Skype for Business Emojis

I was part of the team that wrote the front-end of the chat interface for our end users to chat with our help desk. Our help desk uses Computer Talk’s ice Contact Center platform to queue and receive both phone calls and chats. The agent receives the chat through Skype for Business (previously called Lync - they never should have changed the name).

Our help desk is almost exclusively for internal employees only. Everyone in our organization has Skype for Business (SfB), so they are all used to it. Since everyone is already used to SfB, and the help desk agents will actually be using SfB, I wanted to support all the same emojis (aka “emoticons”) that SfB supports in the front end.

I want to support all the emojis
I want to support all the emojis

Trouble Begins

I thought it would be easy to find a list of all emojis that SfB supports. But no, it simply doesn’t exist. I even tried looking in the exe and dll files looking for strings like :) and :p, figuring that even if I can find all string values that it converts to something, that would be a good start. But I didn’t find anything like that.

I did find a couple of websites that did help though. The first was a blog post from 2003 that claimed to be a “Full List of Emoticons”, but it had a few problems:

The second helpful page was the full list of emoticons for Skype (the consumer version of Skype). While SfB does not come close to supporting the amount of emojis that the consumer Skype does, it was a good reference for finding the shortcodes for some of them that weren’t documented anywhere else.

“Best Effort”

Most people would have stopped here. Or maybe just decided to support a short list of emojis and call it a day. And that’s what many people consider “best effort” support: you make an effort, but if it’s clear that it will become difficult, and no one really expects you to do it, then you call it quits.

But my “best effort” is different. If I know that I can get it done, or even see a clue that I haven’t followed yet, I honestly have a really hard time not taking it further.

The Plan

So my plan was:

  1. Build my own table mapping shortcodes to the actual emojis.
  2. Use the consumer Skype emojis for the actual images.

To build the mapping table, I used both those websites I mentioned above, but the authority was really just actually testing each one. As you can guess, that took a while. At least it felt like a while. It did realisitcally go quick once I got on a roll. I’ll share the table I came up with below.

The consumer Skype emojis are actually different than the SfB ones, but I figured that shouldn’t matter, right?

The plan foiled

It turns out that the consumer Skype emojis don’t have transparant backgrounds. And our chat design uses a dark-coloured background for one side of the chat. That looked something like this:

I am so unamused right now Unamused emoji

Looks stupid, right? But SfB has a coloured background for one side of the conversation, so clearly SfB is using transparent images.

Skype for Business is doing it right. Why can't I?
Skype for Business is doing it right. Why can't I?

Stealing Borrowing SfB’s Images

I started hunting for where SfB stores the images. There weren’t any actual image files that I could see, so clearly it wasn’t going to be easy.

I finally found the images in a DLL file:
C:\Program Files (x86)\Microsoft Office\root\Office16\LyncDesktopSmartBitmapResources.dll

But they aren’t just stored as GIF files that I can export and be done. No, of course not. Each frame of the animation is stacked on top of each other in one big PNG image. But there are also multiple resolutions (20x20, 25x25, 30x30 and 40x40).

Not only that, but you might have noticed that when you use an emoji in SfB, the animation stops after a while and becomes static. But that static image isn’t just the first or last frame of the animation. It’s a totally separate image. That image is also used in the pop-up box that shows you all the emojis. That image is also in the DLL file in all 4 resolutions too.

I decided I’m only going to deal with one resolution (20x20). But still, with 110 emojis, and an animation and static image for each, that’s not something I want to do by hand. There must be a way to automate some of this.

Extracting the images

To extract all the images from the DLL, I used ResourceExtract, a free program. I just needed to extract the “Other Binary Resources”:

ResourceExtract
ResourceExtract

All the images we want end up with a file extension of .bin, even though they are PNG’s. So I renamed them all in the command line:

ren *.bin *.png

Exploring the files, I found that the emojis start at resource #430, and end at 1405. So I deleted all the other files. But there are still 4 resolutions, and I just want one. In Windows Explorer, when using the “detailed” view, you can right-click the headings and click “More” to add whatever property as a heading. So I added “Width” and “Height”. Then I sorted by width and deleted everything that did not have a width of 20. There were still several files I didn’t want, but it was manageable. (the “smoking” emoji is actually there, but there is no character combination I could find that uses that)

All the files before I deleted the larger resolutions
All the files before I deleted the larger resolutions

At this point I went through all 220 files and renamed them to the name of the emojis. This was boring, but it had to be done at some point.

Making the animations

I separated the animations into a new folder by sorting the files by height, and moving all files with a height more than 20.

My original thought was to make them all into animated GIFs. But that plan was foiled too. It turns out that each frame of the animations are PNG because they use alpha transparency around the edges. Unfortunately, animated GIFs don’t support alpha transparency - pixels are either 100% opaque or 100% transparent. I originally tried to make them GIFs, but then it still only looked good on white backgrounds. So I had to go with animated PNGs.

I used ImageMagick to split the frames of the animation out of the single files. Unfortunately, ImageMagick doesn’t support animated PNGs. But this was a start:

FOR %f IN (*.png) DO (
    mkdir "%~nf"
    magick "%f" -crop x40 +repage ".\%~nf\%~nf.png"
)

That went through every file, created a new folder for that file (with the same name) and created one PNG file for each frame.

To create the animated PNG files, I used another free program: APNG Assembler. This is the command I used, which I ran from the parent folder of all the image folders created by ImageMagick:

FOR /D %d IN (*) DO (
    apngasm64 "..\%d.png" "%d\%d-*.png"
)

That went through every folder and assembled the frames into a single animated PNG in the root folder. Animations complete!

Using the animations

Our organization still IE11 and Chrome, so the first hurdle was getting IE11 to use the animations, since it doesn’t support animated PNGs. I found a wonderful library called apng-canvas that will help me do that. Using that library, you can just call APNG.animateImage(imgElement) for any image element with an animated PNG.

I found some code online that I can run on page load to test for APNG support, so I’m not running this code unnecessarily on real browsers. This is the code I used:

var apngTest = new Image(),
    ctx = document.createElement("canvas").getContext("2d");
apngTest.onload = function () {
    ctx.drawImage(apngTest, 0, 0);
    window.APNGSupport = ( ctx.getImageData(0, 0, 1, 1).data[3] === 0 );
};
apngTest.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACGFjVEwAAAABAAAAAcMq2TYAAAANSURBVAiZY2BgYPgPAAEEAQB9ssjfAAAAGmZjVEwAAAAAAAAAAQAAAAEAAAAAAAAAAAD6A+gBAbNU+2sAAAARZmRBVAAAAAEImWNgYGBgAAAABQAB6MzFdgAAAABJRU5ErkJggg==";

After that, I can just check APNGSupport to see if we’re using a real browser.

Stopping the animations

As discussed earlier, SfB will stop the animation after a little while. I like this feature since having a bunch of animations constantly moving on screen can get annoying. SfB loops the animation a specific number of times before stopping, but since I can’t count the number of loops in a browser, I decided to just use a hard time limit of 30 seconds.

But to complicate things, the apng-canvas library changes the img tag to a canvas. So I had to figure out how to follow that change. This is the code I came up with when replacing specific characters (like :p) with an emoji, where emojis is my array of emoji objects (as defined at the end of this article):

emojis.forEach(function(e) {
    if (APNGSupport) {
        text = text.replace(e.characters, "<img class='chat-emoji' alt='" + e.characters + "' aria-label='" + e.name.replace("\'", "&#39;") + " emoji' title='" + e.name.replace("\'", "&#39;") + "' src='" + chatSvcRoot + "/images/emoji/" + e.fileName + "_animated.png' onload='var _this = this; setTimeout(function() { _this.src = \"" + chatSvcRoot + "/images/emoji/" + e.fileName + ".png\"; }, 30000);' />");
    } else {
        var className = e.fileName + new Date().valueOf();
        text = text.replace(e.characters, "<img class='chat-emoji " + className + "' alt='" + e.characters + "' aria-label='" + e.name.replace("\'", "&#39;") + " emoji' title='" + e.name.replace("\'", "&#39;") + "' src='" + chatSvcRoot + "/images/emoji/" + e.fileName + "_animated.png' onload=\"APNG.animateImage(this); setTimeout(function() { var elements = document.getElementsByClassName('" + className + "'); for (var i=0; i < elements.length; i++) { var canvas = elements[i]; var newImg = document.createElement('img'); newImg.classList.add('chat-emoji'); newImg.alt='" + e.name.replace("\'", "") + " emoji'; newImg.src='" + chatSvcRoot + "/images/emoji/" + e.fileName + ".png'; canvas.parentNode.replaceChild(newImg, canvas); }}, 30000);\" />");
    }
});

That replaces the characters with an image, but also has an onload event that will start a timer. When the timer elapses, it replaces the animation with the still image. You’ll see the code for IE11 is more complicated, since we need to replace the canvas element, not the original img element we first created. I created a unique class name to find it (the apng-canvas library will copy the class name to the new canvas element).

The Data

After telling you all this, I’m not going to make you do this yourself (although I’m not entirely sure how many people would really want this). But here are all the images I extracted and used:

Download Skype for Business Emojis

That’s only the 20x20 images, so if you want any higher resolution, you’ll have to do it yourself. Sorry not sorry.

Below is the table I painstakingly compiled of all the possible character combinations that SfB turns into emojis (that I could find), and which emojis they turn into, in JSON format. The order of these is important, since you have to look for the longer character sets before the shorter ones. For example, you have to search and replace :o3 (dog) before you look for :o (surprised) otherwise no one will be able to use the dog emoji.

These are the properties I include here:

 

2 comments

Violina Guetzova on

Hi Gabe, I know this is an old post but would you be interested in turning these intoa Telegram sticker pack?

Leave a comment

Your email address is used to display your Gravatar, if applicable, and subscribe you to replies using the Mailgun web service, which you are free to unsubscribe from when you get any emails. Your email address will not be displayed publicly or shared with anyone else.
Comments are moderated. Your comment will be reviewed by a human before being posted to this page. Any comment made for the purpose of advertising will not be approved.