Emoji to PNG or JPG in Node.js - how to?
Asked Answered
F

1

8

For the project I'm working on I need to generate an image file from emoji (ideally Apple emoji). I thought it should be a fairly simple thing, but with each tool I use, I eventually run into a wall.

I've also considered working with an emoji set, like this one that I could query when needed. Unfortunately, the one I've linked to doesn't have Unicode 9.0 emoji such as avocado (πŸ₯‘) shrimp (🦐) or harambe (🦍). Do you know of such an up-to-date set?

Code-wise, I've tried opentype.js, but it doesn't support .ttc fonts, which is the extension of the emoji font on my mac (Apple Color Emoji.ttc). I've converted the font to .ttf but that didn't work either:

  var opentype = require('opentype.js');
  opentype.load('./build_scripts/apple_color_emoji.ttf', function (err, font) {
      if (err) {
          alert('Could not load font: ' + err);
      } else {
          console.log("loaded the font",font);

          var Canvas = require('canvas')
            , Image = Canvas.Image
            , canvas = new Canvas(200, 200)
            , ctx = canvas.getContext('2d');
          var path = font.getPath('πŸπŸ¦ƒ', 0, 150, 72);
          path.draw(ctx);
          console.log('<img src="' + canvas.toDataURL() + '" />');
      }
  });

The result looks like this:

The result looks like this:

I've tried fontkit, which is supposed to be able to read .ttc files, but it throws an error if I try to use the Apple Color Emoji font.

  var fontkit = require('fontkit');
  var font = fontkit.openSync('./build_scripts/Apple Color Emoji.ttc'); 
  // TypeError: font.layout is not a function

If I try the same with my converted .ttf file I end up with some incorrect svg:

  var fontkit = require('fontkit');
  var font = fontkit.openSync('./build_scripts/apple_color_emoji.ttf');
  var run = font.layout('πŸπŸ¦ƒ');
  var svg = run.glyphs[0].path.toSVG();

  console.log(svg);
  // M-1 0ZM799 800Z

My question is, am I even approaching this the right way? Converting emoji that I already have on my machine to a .png or another format seems like something that should be fairly straightforward but I just can't get it to work.

EDIT:

I've found a list of emoji names by their hex codes in this repo (big shoutouts to rodrigopolo). Now I can simply use this:

var emoji = "😊".codePointAt(0).toString(16); //1f60a
var emojiFile = fs.readFileSync('./my-emoji-folder/' + emoji + '.png');

Still, would be great to know if somebody has a coding solution to this problem!

FURTHER EDIT:

Turns out the first solution I've found only included emoji up to Unicode 8.0, not Unicode 9.0. I've found a ruby gem gemoji that does emoji extraction. If you're not a ruby developer (I'm not), you can simply use the following commands in your shell:

git clone https://github.com/github/gemoji.git
cd gemoji
bundle install
bundle exec gemoji extract some-directory/emoji

You now have Unicode 9.0 emoji in your some-directory/emoji folder!

Female answered 26/4, 2017 at 12:55 Comment(7)
That seems like an extremely esoteric problem (+1). Out of curiosity, why exactly do you need to create an image out of emoji? – Fitting
Haha, yeah, might be why I had such a hard time finding a solution. I'm experimenting with a react project where I can change the look of the website by building it with a different .env file. I've decided the favicon to be an emoji so I needed a way to generate them dynamically depending on the emoji specified in .env. But for a more everyday use, you could use it to display the latest emoji on devices that don't support them yet. – Female
Who said fontkit supported TTC? Because it absolutely does not. Unpack your TTC to actual font files, then use those for image generation instead. Also, if you found a solution don't add that as an "edit", write an answer and then a day later accept it. Questions without answers are just going to get lost to time, instead of google indexed. – Bibulous
It seems so on their docs: github.com/devongovett/fontkit – Female
How does it works with google indexing? I'm not accepting my own answer because I'm still looking for a non-hacky solution – Female
Are you doing this as a one off thing? As in you just need to generate the png(s) once? If so, how about generating them using the canvas API in the browser. You can either write a tiny server to save to or you could run it in electron and save directly. – Jackdaw
@Jackdaw I needed it as a part of a build script, but one-off would do as well. Turns out you can do it in regular node, have a look at the accepted answer. – Female
B
6

I was able to get this to work with fontkit by selecting a font from the font collection. I haven't found a case yet where using either of the TTFs included in the "Apple Color Emoji.ttc" gives different results.

const fs = require('fs');
const fontkit = require('fontkit');
const emoji = require('node-emoji');
const font = fontkit.openSync('./Apple Color Emoji.ttc').fonts[0];

let emo = emoji.get('100');
let run = font.layout(emo);
let glyph = run.glyphs[0].getImageForSize(128)

fs.writeFileSync('100.png', glyph.data);
Baer answered 5/5, 2017 at 15:43 Comment(2)
Exactly what I was looking for! I'd just remove node-emoji dependency for the sake of simplicity: let run = font.layout('πŸ’―');. – Female
Also, one thing to keep in mind the getImageForSize function gets the emoji image in pixels, and it looks like the max size for the Apple Color Emoji is 160. – Baer

© 2022 - 2024 β€” McMap. All rights reserved.