Libgdx: Emojis are not rendering

Created on 31 Oct 2019  ยท  18Comments  ยท  Source: libgdx/libgdx

English characters render, but emojis don't. I have loaded a font with emojis.

Issue details

https://stackoverflow.com/questions/58635857/how-to-render-an-emoji-with-libgdx

Reproduction steps/code

FileHandle fontFile = Gdx.files.internal("path/to/file.ttf");
FreeTypeFontGenerator g = new FreeTypeFontGenerator(fontFile);
FreeTypeFontGenerator.FreeTypeFontParameter p = new FreeTypeFontGenerator.FreeTypeFontParameter();
// Some config here with p
BitmapFont emojiFont= g.generateFont(p);

public static void renderFont(SpriteBatch sb, BitmapFont font, String msg, float x, float y, Color c) {
  font.setColor(c);
  font.draw(sb, msg, x, y);
}

String str = "emoji โค \uD83D\uDC49 test \uD83D\uDC49 \uD83D\uDC4D test \uD83D\uDE03"
renderFont(sb, emojiFont, str, x, y, new Color(-597249));

Version of LibGDX and/or relevant dependencies

1.9.2

Please select the affected platforms

  • [ x] Windows

Most helpful comment

would be nice add point code support for font and label. when i try add code point (int type) to font i get error
BitmapFontData bitmapFontData = new BitmapFontData(); bitmapFontData.setGlyph(0x1F60B, new Glyph());

java.lang.ArrayIndexOutOfBoundsException: 251
at com.badlogic.gdx.graphics.g2d.BitmapFont$BitmapFontData.setGlyph(BitmapFont.java:744)

and then we can easy to add custom emoji and stickers. for example https://github.com/taluks/libgdx-emodji

All 18 comments

@alexdriedger I believe you need to include these emojis into FreeTypeFontParameter.characters field before generating BitmapFont.
Maybe something like:
p.characters += "\uD83D\uDC49\uD83D\uDC49\uD83D\uDC4D\uD83D\uDE03";

I have over 2000 emojis that are included in the font. Do I have to do that for all 2000 emojis?

For gdx-freetypefont exstention, I think yes, if these characters are not already contained inside FreeTypeFontGenerator.DEFAULT_CHARS variable. But having such big amount of characters may consume a lot of memory.
Probably you need to implement your own solution.

Isn't there a simpler solution for rendering Chinese characters that would be similar to this?

Unfortunately, I do not know...
But if you plan to use only small font sizes like 32x32 pixels, I think it is worth to try just appending to p.characters field all 2000 emojis. Because it will allocate only about 2-3 bitmap pages with 1024x1024 dimensions, which is kind of acceptable.

There's an incremental mode for FreetypeFontGenerator that allows you to add glyphs on demand. I've not used it so I don't know exactly what that looks like, but it might be an option.

+1 for incremental mode. I'm using freetype in my game and so far have had no issue using incremental mode to support asian scripts, even at large text sizes (size scales with device resolution) and 1,000+ characters.

Incremental is great, but it might not help.
Depending on your Java version, some emojis won't be supported due to their multibyte nature.
If you look at what's new in Java releases you'll often see a UTF-8 specification update, based off which spec is used it may or may not recognize your emojis (and that's putting aside skin tones).

I think this does not depend on the Java version but mostly on the codepoints supported by the font. We should handle multichar UTF-16 codepoints correctly (and if we don't the change won't be difficult). The main problem is that some characters are multi-codepoint ("grapheme clusters"), which is non trivial to handle without something like HarfBuzz.

would be nice add point code support for font and label. when i try add code point (int type) to font i get error
BitmapFontData bitmapFontData = new BitmapFontData(); bitmapFontData.setGlyph(0x1F60B, new Glyph());

java.lang.ArrayIndexOutOfBoundsException: 251
at com.badlogic.gdx.graphics.g2d.BitmapFont$BitmapFontData.setGlyph(BitmapFont.java:744)

and then we can easy to add custom emoji and stickers. for example https://github.com/taluks/libgdx-emodji

@taluks That example is amazing.

I noticed all the emojis in the example are a single byte (example: 0x1F603). Should this example also work with a font with emojis that are more than a single byte (example: https://emojipedia.org/man-rowing-boat-type-4/)?

@alexdriedger for TextArea I change code point (0x1F603 - 4 bytes or two UTF-16 symbols) when rendering to one using surrogate key. You can add any Unicode characters by replacing them with UTF-16 character code.

for (short i = 0; i < Emoji.CODES.length; i++) {
    int originalCode = Emoji.CODES[i];
    char replacementCode = (char) ('\uFFFF' - i);
    font.putSurrogateCode(originalCode, replacementCode);
    font.appendEmoji(replacementCode, 
    String.format("emoji/%s.png", Emoji.hexFromCodePoint(originalCode)));
}

\uFFFF is max for char type (UTF-16)

For Label I replace Unicode characters in advance

text = text.codePoints().map(i -> font.surrogateCodeMap.containsKey(i)? font.surrogateCodeMap.get(i): i)
                .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append).toString();

I have been doing some "experiments" on how to add Emojis to libGDX texts (Labels, BitmapFonts, etc) and have created a EmojiSupport class without having to change any file in the gdx core.
https://github.com/DavidPDev/gdx-EmojiSupport
Currently supports adding emojis to any text with very low penalty.
Please if you can check it, it's not 100% perfect but may be the way to supporting emojis natively.

https://github.com/DavidPDev/gdx-EmojiSupport
great example repo. I'm impressed. keep up the good work.

will check it out later.

As mentioned above, FreeTypeFontGenerator has an incremental mode and supports multi byte characters, but doesn't do complex glyph layout. DavidPDev's project looks like a good solution.

I've just started using the repo by @DavidPDev and is great so far!! Thank you so much!

from what i can see, the proposed solution to add emojis is bad for performance, since it doesn't merge the textures, you'll end up with ton of texture switches for no reasons, wich is bad idea, specially for libgdx since its main target are mobile phones

i think this should be re-open until a proper solution is found

Thank you all... I didn't come back to this issue... I forgot I had commented here :)

@RUSshy I don't think there should be a lot of texture switching, just the same as if you have several texture atlas in the same project (it's the normal use case, I think.). Keep in mind that you only have a small penalty in the loading phase. In runtime it's the same performance as mixing different fonts in a scene.
I'm using this solution in a published game (not heavy graphics) and its working great.

In Android I thought of a very clean solution, but somehow complicated when using freetype fonts (runtime created):

  • Before rendering a Label check if there is an emoji inside the text.
  • Then check if that emoji exists in a "Global Emoji Glyph Cache"
  • if it doesn't exists then create the glyph with the freetype generator (just that emoji) using the Android renderer. So the next time you need that emoji it's ready to use.
Was this page helpful?
0 / 5 - 0 ratings