Automattic/node-canvas

Any emoji support?

kevzettler opened this issue Β· 73 comments

The following code gives me the follwing image output:

    var Canvas = require('canvas');
    var Image = Canvas.Image;
    var canvas = new Canvas(1200, 600);
    var ctx = canvas.getContext('2d');

    ctx.font = '80px HelveticaNeue';
    ctx.fillText('Start Here emoji πŸ”', 50, 100);

    res.setHeader('Content-Type', 'image/png');
    canvas.pngStream().pipe(res);

Not rendering the emoji. Is this possible?

tiltimage

jakeg commented

Sudo apt-get install ttf-ancient-fonts
On 3 May 2016 6:24 p.m., "Kev Zettler" notifications@github.com wrote:

The following code gives me the follwing image output:

var Canvas = require('canvas');
var Image = Canvas.Image;
var canvas = new Canvas(1200, 600);
var ctx = canvas.getContext('2d');

ctx.font = '80px HelveticaNeue';
ctx.fillText('Start Here emoji πŸ”', 50, 100);

res.setHeader('Content-Type', 'image/png');
canvas.pngStream().pipe(res);

Not rendering the emoji is this possible?

[image: tiltimage]
https://cloud.githubusercontent.com/assets/126209/14992066/1bda3db0-1119-11e6-9d8a-032830b641e0.png

β€”
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub
#760

duplicate of #614

is there a solution for OSX?

Trying to use Apple Color Emoji.ttf

getting

Assertion failed: (!scaled_font->cache_frozen), function _cairo_scaled_glyph_page_destroy, file cairo-scaled-font.c, line 459.
var AppleColorEmoji = new Font('Apple Color Emoji', fontFile('Apple Color Emoji.ttf'));
ctx.addFont(AppleColorEmoji);

Still no luck, anyone found way to render emojis on the mac?

I did some digging on this... the code point printed out in the screenshot from @kevzettler is correct, so I think that was just a missing emoji font, not a bug in node-canvas

But I tried to do it on my Mac and I couldn't get emojis to print with or without Pango. I think there might be an encoding issue on OS X, because the code point that prints out for me is definitely wrong. I tried several emoji and they all printed out as D83C

there's definitely a problem with Pango, I tried it in pure C. I submitted a bug with them:

https://bugzilla.gnome.org/show_bug.cgi?id=766091

@chearon I ended up just using phantom to take screenshots of emojis. Good find on the bug! Hopefully someone can pick it up!

@gabrielcsapo it looks like someone already has fixed it in the next Pango version, but it also has to be fixed in Cairo but that patch hasn't made it in yet. We will just have to wait!

@chearon awesome news!

@chearon My apologies for my ignorance, but are those changes available yet? I'm currently still experiencing this issue.

After a quick look at the cairo master I don't think so :/

Kristian Rietveld has been maintaining patches that, for whatever reason, have not been accepted into Cairo. The only option right now is to compile Cairo with the patches yourself.

It could also be part of the canvas-prebuilt build if I can find the time

I spent a few hours trying to compile cairo on OS X with unfortunately no success. That being said, my particular use case doesn't demand emoji rendering -- it's more so a nice to have. Given that Cairo hasn't released since 2015, I think using the branch with the emoji support inside of canvas-prebuilt would be a good option.

Yeah, probably, I was already thinking about bundling at least one Pango patch with prebuilt. Pango suffers from incompleteness on Not Linux platforms as well. It's a real bummer.

And for Cairo compilation... it might help to look at the Homebrew formula. Actually it'd be great if we convinced them to use the patch in the official formula, if not maybe it could be forked.

@chearon Thanks for the tip. I was able to get a custom build of Cairo to succeed by modifying the brew formula to point to this branch. I don't believe that branch had the needed fixes, though, so my rendering still lacked emojis.

If there was a way to get the URL to the git repo containing the patch changes from the bugzilla patch (which I haven't been able to figure out), I could build it and verify it fixes this issue.

Nice work! I just tried applying Kristian's patch to Cairo@master and it applied cleanly! I've pushed it up here for your convenience - let me know if it works, I haven' tried but I might make an attempt in a bit

Using cairo@HEAD-a212165 and pango@1.40.3, I get a slightly different result than @kevzettler. No emoji, but also no undesirable artifact.

result

Here is my modified formula and node script to generate png (which will be available at http://localhost:8099/). I edited the formula using brew edit cairo and installed using brew install cairo --HEAD.

I get the same result. I noticed there were 2 patches posted and I tried the other one instead (I pushed it to the repo too) but it didn't seem to work either

I just heard back from Andrea Canciani. I was advised to use apply the patch from bugzilla to https://github.com/matthiasclasen/cairo/tree/matthiasc/emoji-5.

Ok, my master is now the emoji-5 branch with the patch applied. I'm trying it now

I love this awesome support! You guys rock!

@gabrielcsapo The new build also did not seem to resolve the issue. :( I've commented on the original bugzilla report, and hopefully though continued discussion with cairo contributors we'll be able to get a working build that people can compile and use with node-canvas (possibly creating a prebuilt version) and, in the long term, a new release of cairo installable through homebrew.

I commented on the one I submitted, too. They were talking about how Mozilla's fork of Cairo resolves the issue, so there is probably working code in their fork here (the emoji patch looks to be here) but it'll be harder to get compiling

Emoji font works with pango master branch and 1.40.2 or later, cairo master branch and 1.14.6 or later applied Kris's patch.

pango depends on cairo, compile and install cairo first. Emoji font is 4 bytes long <----

emoji font seems too big and pango cuts off right and bottom edges of emoji font.

1

@nuixdt
cairo: 1.14.10-1ubuntu1
pango: 1.14.10-1ubuntu1

but not showing colored apple emojies

my code

const { createCanvas, loadImage , registerFont} = require('canvas');
registerFont('applecoloremoji.ttf',{family: "Apple"});
let canvas = createCanvas(512,512);
let c = canvas.getContext('2d');
c.font = '50px "Apple"';
c.fillText("πŸ˜‚πŸ˜πŸ˜ΆπŸ’‹πŸ‘πŸ˜­ ",50,50,50);

On macOS you need to compile Pango yourself with 2 patches to get emoji working. The first one being the one that @petermikitsh and I were trying to get working, and the other being one that was posted early this year. Both here, I haven't tried the second patch yet though.

@chearon
Thank you i will test that
but im using ubuntu 17.10

Is there a good workaround for this currently? I'm reading the thread here, bi]but it's a little hard to follow and figure out what I should do.

Does anyone have steps for supporting emojis on OS X?

Even after updating Pango, I get the following:

emojis

This is what it should look like:

screen shot 2018-04-10 at 2 36 12 pm

Cairo and Pango have to do some coordinating to get emojis working, I would try to compile the latest of both from source. Supposedly it should work but as you can see above we couldn't get it working, and I sunk a lot of time into it πŸ˜•

So, node-canvas still not support emoji, right?πŸ™

Any update on this? Or anything we can do to help?

@chearon is there any update regarding colour emoji support? I've been digging into this a lot since I need proper emojis to show up when using fabric.js but haven't found a solution yet. I'm happy to help out but not sure how.

@chearon I've also installed cairo 1.16 and tried building from source as well and it's still just showing the black-and-white emoji. I'd really appreciate your help in finding a solution to this.

Any update on this? Or anything we can do to help?

@robert-moore did you ever find a solution?

I'm on Debian (Buster) by the way

@lukasondrej have you been able to make any progress on this yourself?

@ushmakapure I've overcome the issue by inserting the blank character instead of all emojis and then by placing emoji pngs (from twemoji) into the gaps. Certainly more involved then it should be.

@lukasondrej how do you figure out where the emoji should be? A bunch of measureTexts?

Thanks @lukasondrej, we've decided to work around the issue entirely & not allow emoji to be entered inline in text. We'll most likely end up adding an emoji picker and insert as images.

@robert-moore I've implemented a subclass of Textbox and overrode the _renderChar method like so:

_renderChar: function(method, ctx, lineIndex, charIndex, _char, left, top) {
  // Render emoji
  if (_char === ' ') {
    // Draw emoji
    const emoji = this.emojis[this.emojiCodes[this.emojisCodeIndex]]
    emoji.set({
      left,
      top: top - this.options.fontSize + 2
    })
    emoji.scaleToWidth(this.options.fontSize)
    emoji.scaleToHeight(this.options.fontSize)
    emoji.drawObject(ctx)

    // Set emoji index of next emoji
    this.emojisCodeIndex++
    if (this.emojisCodeIndex > this.emojiCodes.length - 1) {
      this.emojisCodeIndex = 0
    }
  }
}

In summary, when I get the string of text to display, I extract all emojis by matching their unicode definitions and replace them by the square space character. Then in the _renderChar method, each time there's a square space character, I look up the emoji to put in based on its index and manually draw it. I'm using fabric.js by the way.

Hope that helps :)

@lukasondrej can you please share how do you create this.emojis and this.emojiCodes?

UPD: ok, got it - twemoji. But the second problem - I get full text row in _renderChar method, not singe characters.

maybe this is helpful for someone searching in this thread. i just stumbled upon the actual oposite problem that on Ubuntu 18.04 i'm always getting the colourful emojis. it seems in my installation it's not picking from the specified font, but would always replace the font with the emoji font.

after some research i found it's caused by the configurations in these both files:
/etc/fonts/conf.d/45-generic.conf
/etc/fonts/conf.d/60-generic.conf

now i wanted to change this behaviour only for my application and not systemwide, so i
took a local copy of the /etc/fonts.conf file in my workspace and removed directions that would load the both files (remove the include of all files under /etc/fonts/conf.d/*). then when starting the node.js application have an environment variable FONTCONFIG_FILE set to point to the new config file. be aware that this might have side-effects on other font configurations or font replacement rules...

I wrote a module to draw emoji with Twemoji.
Until the problem is solved, try it out.

https://github.com/cagpie/node-canvas-with-twemoji
https://www.npmjs.com/package/node-canvas-with-twemoji

_renderChar: function(method, ctx, lineIndex, charIndex, _char, left, top) {
  // Render emoji
  if (_char === ' ') {
    // Draw emoji
    const emoji = this.emojis[this.emojiCodes[this.emojisCodeIndex]]
    emoji.set({
      left,
      top: top - this.options.fontSize + 2
    })
    emoji.scaleToWidth(this.options.fontSize)
    emoji.scaleToHeight(this.options.fontSize)
    emoji.drawObject(ctx)

    // Set emoji index of next emoji
    this.emojisCodeIndex++
    if (this.emojisCodeIndex > this.emojiCodes.length - 1) {
      this.emojisCodeIndex = 0
    }
  }
}

I tried but it isn't working for me, Can you please share full code in gist or codepen please.

Thanks a lot in advance!

_renderChar: function(method, ctx, lineIndex, charIndex, _char, left, top) {
  // Render emoji
  if (_char === ' ') {
    // Draw emoji
    const emoji = this.emojis[this.emojiCodes[this.emojisCodeIndex]]
    emoji.set({
      left,
      top: top - this.options.fontSize + 2
    })
    emoji.scaleToWidth(this.options.fontSize)
    emoji.scaleToHeight(this.options.fontSize)
    emoji.drawObject(ctx)

    // Set emoji index of next emoji
    this.emojisCodeIndex++
    if (this.emojisCodeIndex > this.emojiCodes.length - 1) {
      this.emojisCodeIndex = 0
    }
  }
}

I tried but it isn't working for me, Can you please share full code in gist or codepen please.

Thanks a lot in advance!

@lukasondrej

tsafs commented

Edit: I found out that not all typical emojis are supported by twmoji-emojis. I haven't updated the code below, but I am now not painting anything (just skipping the position in the text) if the emoji was not found on the server.

@motyar and others who are using fabric.js: I'm afraid I'm a little late, but the code below is my solution to the problem, similar to @lukasondrej's solution. I also use fabric.js for the canvas and twemoji-emojis for emoji svgs.

The approach is similar, because I do not use ' ' to replace emojis, but a regular emoji πŸ˜€. This is necessary, because using ' ' will result in wrong left and top locations for the characters, i.e. for drawing emoji's SVGs and also for the text. My software has a frontend-canvas accessible through the browser and a backend-canvas on the server-side which generates a PNG-file from what was drawn on the front-end. The text & emoji bounds would be different, using ' ' as a placeholder.

Also, I override _renderChars() to force it to always render each character by itself and not render the whole line at once. I guess that @lukasondrej forgot to mention that, hence why his solution is not working, or not complete.

Use the following Textbox instead of fabric.Textbox and call await myCustomTextbox.extractEmojis() before calling fabricCanvas.renderAll().

One possible problem with this code: I don't know how it behaves if we use a font family that does not support emojis. Is that even possible? I will probably stumble upon this problem in the following days and might update this answer. If not then just leave me a bump if you like.

import { fabric } from "fabric";
import fs from "fs";
import EmojiRegex from "emoji-regex";

const EMOJI_FOLDER = "./node_modules/twemoji-emojis/vendor/svg";
const TOP_CORRECTION = 0.6;
const LEFT_CORRECTION = 0.15;

class Textbox extends fabric.Textbox {
  emojis = {}; // holds fabric svgs for emojis that were identified in text
  emojiCodes = []; // holds emoji codes that were identified in text
  currentEmojiCodeIndex = 0; // current index of emoji that is being rendered
  emojisForLogging = []; // holds emojis for logging

  async extractEmojis() {
    const regex = EmojiRegex();
    let match;
    const distinctEmojiCodes = [];
    const indexes = [];
    let escapedText = this.text + "";
    while ((match = regex.exec(this.text))) {
      const emoji = match[0];
      const hexes = [];
      for (let part of [...emoji]) {
        hexes.push(part.codePointAt(0).toString(16));
      }
      console.log(emoji, match["index"], hexes);
      indexes.push(match["index"]);
      this.emojisForLogging.push(emoji);

      // this is the emoji code in twemoji-format
      const filename = hexes.join("-");

      // create a reference
      this.emojiCodes.push(filename);

      // push to distinct list of emoji codes, from which emojis will be created
      if (!distinctEmojiCodes.includes(filename)) {
        distinctEmojiCodes.push(filename);
      }

      // replace emoji with placeholder emoji
      escapedText = escapedText.replace(emoji, "πŸ˜€");
    }

    // override this.text with escaped text
    this.text = escapedText;
    console.log(escapedText, distinctEmojiCodes, indexes, this.emojiCodes, this.emojisForLogging);

    for (let emojiCode of distinctEmojiCodes) {
      this.emojis[emojiCode] = await this.loadSvg(emojiCode);
    }
  }

  loadSvg(emojiCode) {
    return new Promise((resolve, reject) => {
      fs.readFile(`${EMOJI_FOLDER}/${emojiCode}.svg`, "utf8", (err, data) => {
        if (err) return reject(err);
        fabric.loadSVGFromString(data, (objects, options) => {
          resolve(new fabric.util.groupSVGElements(objects, options));
        });
      });
    });
  }

  _renderChar(method, ctx, lineIndex, charIndex, _char, left, top, lineHeight) {
    if (_char === "πŸ˜€") {
      console.log(this.emojisForLogging[this.currentEmojiCodeIndex], lineIndex, charIndex, left, top, lineHeight);

      const emoji = this.emojis[this.emojiCodes[this.currentEmojiCodeIndex]];
      emoji.set({
        left: left + lineHeight * LEFT_CORRECTION,
        top: top - lineHeight * TOP_CORRECTION,
      });
      emoji.drawObject(ctx);

      // Set emoji index of next emoji
      this.currentEmojiCodeIndex++;
      if (this.currentEmojiCodeIndex > this.emojiCodes.length - 1) {
        this.currentEmojiCodeIndex = 0;
      }
    } else {
      super._renderChar(method, ctx, lineIndex, charIndex, _char, left, top);
    }
  }

  _renderChars(method, ctx, line, left, top, lineIndex) {
    // set proper line offset
    var lineHeight = this.getHeightOfLine(lineIndex),
      actualStyle,
      nextStyle,
      charsToRender = "",
      charBox,
      boxWidth = 0,
      path = this.path;

    ctx.save();
    top -= (lineHeight * this._fontSizeFraction) / this.lineHeight;
    for (var i = 0, len = line.length - 1; i <= len; i++) {
      charsToRender += line[i];
      charBox = this.__charBounds[lineIndex][i];
      if (boxWidth === 0) {
        left += charBox.kernedWidth - charBox.width;
        boxWidth += charBox.width;
      } else {
        boxWidth += charBox.kernedWidth;
      }
      if (path) {
        ctx.save();
        ctx.translate(charBox.renderLeft, charBox.renderTop);
        ctx.rotate(charBox.angle);
        this._renderChar(method, ctx, lineIndex, i, charsToRender, -boxWidth / 2, 0, lineHeight);
        ctx.restore();
      } else {
        this._renderChar(method, ctx, lineIndex, i, charsToRender, left, top, lineHeight);
      }
      charsToRender = "";
      actualStyle = nextStyle;
      left += boxWidth;
      boxWidth = 0;
    }
    ctx.restore();
  }
}

export default Textbox;

almost 4 years no support of emoji... any news here?

I've made recent tests with Noto Color Emoji, Segoe UI and twemoji-color-font, and emoji do work now, but they are always black and white (MacOS, in Docker).

Changelog says that Cairo v1.15.8 supports color emoji with PNGs, but I wasn't able to make it colorful anyway.

Related patch seems to be still unmerged https://gitlab.freedesktop.org/cairo/cairo/-/issues/54

For instance, Segoe UI Emoji which uses Microsoft emoji format is tested here and reported to be working https://gitlab.freedesktop.org/cairo/cairo/-/issues/404

However, in node-canvas it's always rendering as black and white. Maybe something needs to be configure in node-canvas when Cairo is used?

I've made recent tests with Noto Color Emoji, Segoe UI and twemoji-color-font, and emoji do work now, but they are always black and white (MacOS, in Docker).

Those fonts have path glyph emojis. They have always worked as they are not any different from any other character.

On the other hand, Bitmap emojis don't have proper support yet

Having the same issues, I attempted using 'node-canvas-with-twemoji-and-discord-emoji' package to fix this, and seemed to work.
image
image

I still have problems with unicode characters, when I render them on my local workstation they render correctly:
image
but on server side it looks like this
image

skr-canvas has supported emoji fonts: Brooooooklyn/canvas#327

Produced in node:lts-apline docker container, 0 system dependencies and 0 postinstall scripts:

draw-emoji

skr-canvas has supported emoji fonts: Brooooooklyn/canvas#327

Produced in node:lts-apline docker container, 0 system dependencies and 0 postinstall scripts:

draw-emoji

How can we use it with fabricjs? Please provide example code.

Hey guys, any updates here?

we need emoji☝️

This has been driving me absolutely nuts, thought it was my code. I can't believe it's been years with regular browser canvas allowing emoji in text and we still can't do it in node-canvas :(

Cairo patch https://gitlab.freedesktop.org/cairo/cairo/-/issues/54 has been merged. I guess colored bitmap emoji should work now if we update Cairo?

I compiled the latest version of cairo but it does not seem to work at least on Linux. They have specific font management for mac and windows

rklf commented

Any news on it ?

Any news or a solid solution to this?

@mrsegev You have to download the Segoe Emoji ttf from the Internet. Importing the downloaded file will make Windows emojis come on the canvas. Image below has the crown (πŸ‘‘) emoji

image

Thanks @Elitex07 ,
What do you mean by importing the file?

@mrsegev Use registerfont() function to import custom fonts.

registerFont('src/assets/fonts/Segoe/seguiemj.ttf', {family: 'Segoe'})

My "dirty" solution was to use twemoji-parser to get the url of the correponding emoji svg and than draw it as a regular image inside the canvas.

To render emojis with colors on Linux, you need to take into account different aspects:

  1. you should use the "glyph" drawing mode for text: ctx.textDrawingMode = "glyph";. In the default path mode only the outline of the glyph is drawn, so it will always be using one unique color. In glyph mode, the rendering of the glyph is delegated to Pango/Cairo (and Freetype) that know about the glyph colors and can draw it correctly.
  2. you should configure correctly fontconfig. Even if node-canvas provides recent binaries for Pango, Cairo, Freetype and FontConfig, the latter will still read your configuration files from /etc/fonts/conf.d/. In particular, on recent Linux distributions, emojis fonts configurations are grouped into 45-generic.conf and 60-generic.conf files (see below).
  3. all emojis fonts cannot be rendered with colors under Linux. In particular the ones with OpenType-SVG format (like https://github.com/13rac1/twemoji-color-font). The SVG support in Freetype is very recent (version 2.12.0 https://freetype.org/) and has not been implemented in Pango/Cairo yet. You should use CBDT fonts to have colored emojis under Linux.

As far as fontconfig emojis configuration is concerned here are the details you need to enable colored emojis (from: 45-generic.conf and 60-generic.conf files):

        <!-- System emoji -->
        <alias binding="same">
                <family>Noto Color Emoji</family> <!-- Google -->
                <default><family>emoji</family></default>
        </alias>
        <alias binding="same">
                <family>Apple Color Emoji</family> <!-- Apple -->
                <default><family>emoji</family></default>
        </alias>
        <alias binding="same">
                <family>Segoe UI Emoji</family> <!-- Microsoft -->
                <default><family>emoji</family></default>
        </alias>
        <alias binding="same">
                <family>Twitter Color Emoji</family> <!-- Twitter -->
                <default><family>emoji</family></default>
        </alias>
        <alias binding="same">
                <family>EmojiOne Mozilla</family> <!-- Mozilla -->
                <default><family>emoji</family></default>
        </alias>
        <!-- Third-party emoji -->
        <alias binding="same">
                <family>Emoji Two</family>
                <default><family>emoji</family></default>
        </alias>
        <alias binding="same">
                <family>Emoji One</family>
                <default><family>emoji</family></default>
        </alias>
        <!-- B&W -->
        <alias binding="same">
                <family>Noto Emoji</family> <!-- Google -->
                <default><family>emoji</family></default>
        </alias>
        <alias binding="same">
                <family>Android Emoji</family> <!-- Google -->
                <default><family>emoji</family></default>
        </alias>

        <!-- Add language for emoji, to match other emoji fonts. -->
        <match>
                <test name="family">
                        <string>emoji</string>
                </test>
                <edit name="lang" mode="prepend">
                        <string>und-zsye</string>
                </edit>
        </match>

        <match>
                <test name="lang">
                        <string>und-zsye</string>
                </test>
                <test qual="all" name="family" compare="not_eq">
                        <string>emoji</string>
                </test>

                <!-- Add generic family. -->
                <edit name="family" mode="append" binding="strong">
                        <string>emoji</string>
                </edit>
        </match>

and

<!-- Emoji -->

        <!-- Prefer to match color emoji font. -->
        <match>
                <test name="lang">
                        <string>und-zsye</string>
                </test>
                <test qual="all" name="color" compare="not_eq">
                        <bool>true</bool>
                </test>
                <test qual="all" name="color" compare="not_eq">
                        <bool>false</bool>
                </test>
                <edit name="color" mode="append">
                        <bool>true</bool>
                </edit>
        </match>

        <!-- TODO
         ! Match on "color" and alias B&W ones first if no color is requested.
         ! That's "hard" because <alias> doesn't work in match and needs to be
         ! expanded to its non-sugar form.
         !-->
        <alias binding="same">
                <family>emoji</family>
                <prefer>
                        <!-- System fonts -->
                        <family>Noto Color Emoji</family> <!-- Google -->
                        <family>Apple Color Emoji</family> <!-- Apple -->
                        <family>Segoe UI Emoji</family> <!-- Microsoft -->
                        <family>Twitter Color Emoji</family> <!-- Twitter -->
                        <family>EmojiOne Mozilla</family> <!-- Mozilla -->
                        <!-- Third-Party fonts -->
                        <family>Emoji Two</family>
                        <family>Emoji One</family>
                        <!-- Non-color -->
                        <family>Noto Emoji</family> <!-- Google -->
                        <family>Android Emoji</family> <!-- Google -->
                </prefer>
        </alias>

In particular, the list provided after <!-- System fonts --> comment is very important to determine the preferred emojis font when you have more than one installed on your system. If you want to select a particular emojis font, you should change this list order, or install/load only one emoji font. To be more concrete, if Noto Color Emoji font is installed on your system, loading Apple Color Emoji using registerFont() in node-canvas will do nothing as in fontconfig configuration Noto Color Emoji will take precedence over Apple Color Emoji.

@mrsegev Use registerfont() function to import custom fonts.

Not sure if I am using it correctly but it still does not show correct emoji?

registerFont('src/assets/fonts/Segoe/seguiemj.ttf', {family: 'Segoe'})
import { createCanvas, registerFont } from "canvas";

registerFont("../seguiemj.ttf", { family: "Segoe" });
const canvas = createCanvas(100, 100);
const ctx = canvas.getContext("2d");
ctx.font = "20px sans-serif";

const emojis = ["πŸ˜€"];

emojis.forEach((emoji, i) => {
  ctx.fillText(emoji, 8 * (i + 1), 8);
});

console.log(canvas.toDataURL());

@00Prime You need to set the font family correctly.

import { createCanvas, registerFont } from "canvas";

registerFont("../seguiemj.ttf", { family: "Segoe UI Emoji" });
const canvas = createCanvas(100, 100);
const ctx = canvas.getContext("2d");
ctx.textDrawingMode = "glyph"
ctx.font = "20px 'Segoe UI Emoji'";

const emojis = ["πŸ˜€"];

emojis.forEach((emoji, i) => {
  ctx.fillText(emoji, 8 * (i + 1), 50);
});

console.log(canvas.toDataURL());

Works for me.

I don’t know if emoji is already supported😭

How do I display in native color? For example, for apple color emoji.

Depending on the fillStyle, the color of the emoji will change along with the text πŸ˜”.

After a crazy amount of time trying to render emojis with node-canvas, I figured a very unconventional way to render it.

I'm using fontkit to convert the emoji into an image and then render that image with node-canvas.

any update for this?

Anyone stumbling upon this issue, and need fabric js to support apple emoji - follow my setup on the dockerfile as described in this issue.

Make sure the text data doesn't include objectCaching: true.

Made by node-canvas + fabric js:
image

I'm not certain if this will be beneficial for others, but I wanted to share my experience working with fabric.js.
After spending an entire day experimenting with different approaches, I discovered that simply changing the textDrawingMode to glyph resolved the issues I was experiencing:

this.canvas = new fabric.StaticCanvas(null, {
      width,
      height,
      backgroundColor: "#000",
});
this.canvas.getContext().textDrawingMode = "glyph";

image

Before making this alteration, I ensured that the noto-color-emoji font was properly installed.