Emoji: Experiments with Unicode emoji, print() and text()

The (simple) experiment below (updated for Codea version 1.5.1) takes into account the past discussions here
and here.

It illustrates the current (odd) behaviour of the text() function when rendering Unicode emoji at different fontSize(), when the font() is not font("AppleColorEmoji").

--
-- Emoji
--
supportedOrientations(LANDSCAPE_ANY)
function setup()
    parameter.integer("size", 1, 64, 20)
    -- This could be entered directly from an iPad emoji keyboard
    -- but that can not be copy-pasted into the Codea forum
    monkeyFace = unicode2UTF8(0x01F435)
    dogFace    = unicode2UTF8(0x01F436)
    pigFace    = unicode2UTF8(0x01F437)
    frogFace   = unicode2UTF8(0x01F438)
    str = "emoji: "..monkeyFace..dogFace..pigFace..frogFace
    fill(255)
    textMode(CORNER)
    print("Experiments with emoji.")
    print(str)
    w = 50
    h = {
        HEIGHT/2 + 180,
        HEIGHT/2 + 100,
        HEIGHT/2,
        HEIGHT/2 - 80
    }
end

function draw()
    background(0)
    fontSize(20)
    font("Inconsolata")
    text("With font(\"HelveticaNeue\")", w, h[1])
    text("With font (\"AppleColorEmoji\")", w, h[3])
    fontSize(size)
    font("HelveticaNeue")
    text(str, w, h[2]) -- Emoji stop scaling if size > ~20
    font("AppleColorEmoji")
    text(str, w, h[4]) -- Emoji are scaled as expected
end

-- Unicode code point to UTF-8 format string of bytes
--
-- Bit Last point Byte 1   Byte 2   Byte 3   Byte 4   Byte 5   Byte 6
-- 7   U+007F     0xxxxxxx
-- 11  U+07FF     110xxxxx 10xxxxxx
-- 16  U+FFFF     1110xxxx 10xxxxxx 10xxxxxx
-- 21  U+1FFFFF   11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
-- 26  U+3FFFFFF  111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
-- 31  U+7FFFFFFF 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
--
-- However, largest integer in Codea's Lua is 0x7FFFFF (23 bit)
-- With acknowledgement also to Andrew Stacey's UTF-8 library
function unicode2UTF8(u)
    u = math.max(0, math.floor(u)) -- A positive integer
    local UTF8
    if u < 0x80 then          -- less than  8 bits
        UTF8 = string.char(u)
    elseif u < 0x800 then     -- less than 12 bits
        local b2 = u % 0x40 + 0x80
        local b1 = math.floor(u/0x40) + 0xC0
        UTF8 = string.char(b1, b2)
    elseif u < 0x10000 then   -- less than 16 bits
        local b3 = u % 0x40 + 0x80
        local b2 = math.floor(u/0x40) % 0x40 + 0x80
        local b1 = math.floor(u/0x1000) + 0xE0
        UTF8 = string.char(b1, b2, b3)
    elseif u < 0x200000 then  -- less than 22 bits
        local b4 = u % 0x40 + 0x80
        local b3 = math.floor(u/0x40) % 0x40 + 0x80
        local b2 = math.floor(u/0x1000) % 0x40 + 0x80
        local b1 = math.floor(u/0x40000) + 0xF0
        UTF8 = string.char(b1, b2, b3, b4)
    elseif u < 0x800000 then -- less than 24 bits
        local b5 = u % 0x40 + 0x80
        local b4 = math.floor(u/0x40) % 0x40 + 0x80
        local b3 = math.floor(u/0x1000) % 0x40 + 0x80
        local b2 = math.floor(u/0x40000) % 0x40 + 0x80
        local b1 = math.floor(u/0x1000000) + 0xF8
        UTF8 = string.char(b1, b2, b3, b4, b5)
    else
        print("Error: Code point too large for Codea's Lua.")
    end
    return UTF8
end

```

The code below (updated for Codea version 1.5.1) provides a viewer for the various emoji.

--
-- Emoji Viewer
--
supportedOrientations(LANDSCAPE_ANY)
function setup()
    parameter.integer("Page", 1, 5)
    fill(255)
    textMode(CENTER)
    isZoomed = false
    pickedCharUnicode = nil
    pickedChar = nil
    page = Page
    print("Use the slider to choose a page of emoji.")
    print("Tap emoji to zoom in")
    print("Tap again to zoom out.")
    print()
    print("A white box means no emoji defined for that code.")
end

function draw()
    background(0)
    if Page ~= page then
        page = Page
        isZoomed = false
    end
    if isZoomed then
        font("AppleColorEmoji")
        fontSize(512)
        text(pickedChar, WIDTH/2, HEIGHT/2)
        fontSize(64)
        text(pickedChar, WIDTH/2, 150)
        font("Inconsolata")
        fontSize(64)
        local title = string.format("U+%4X", pickedCharUnicode)..
            " (= "..pickedCharUnicode..")"
        text(title, WIDTH/2, 50)
    else
        font("AppleColorEmoji")
        fontSize(40)
        local base = base(Page)
        for j = 0, 15 do
            for i = 0, 15 do
                local u = base + i * 0x10 + j
                local char = unicode2UTF8(u)
                local x = WIDTH/16 * (i + 1/2)
                local y = HEIGHT/16 * (15 - j + 1/2)
                text(char, x, y)
            end
        end
    end 
end

function base(page)
    if page < 4 then
        return 0x1F300 + (page - 1) * 0x100
    elseif page < 5 then
        return 0x1F600
    end
    return 0x2600
end    

function touched(touch)
    if touch.state == BEGAN then
        if isZoomed then
            isZoomed = false
        else
            isZoomed = true
            local base = base(Page)
            local i = math.floor(touch.x/WIDTH * 16)
            local j = 15 - math.floor(touch.y/HEIGHT * 16)
            pickedCharUnicode = base + i * 0x10 + j
            pickedChar = unicode2UTF8(pickedCharUnicode)
        end
    end
end            

-- Unicode code point to UTF-8 format string of bytes
--
-- Bit Last point Byte 1   Byte 2   Byte 3   Byte 4   Byte 5   Byte 6
-- 7   U+007F     0xxxxxxx
-- 11  U+07FF     110xxxxx 10xxxxxx
-- 16  U+FFFF     1110xxxx 10xxxxxx 10xxxxxx
-- 21  U+1FFFFF   11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
-- 26  U+3FFFFFF  111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
-- 31  U+7FFFFFFF 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
--
-- However, largest integer in Codea's Lua is 0x7FFFFF (23 bit)
-- With acknowledgement also to Andrew Stacey's UTF-8 library
function unicode2UTF8(u)
    u = math.max(0, math.floor(u)) -- A positive integer
    local UTF8
    if u < 0x80 then          -- less than  8 bits
        UTF8 = string.char(u)
    elseif u < 0x800 then     -- less than 12 bits
        local b2 = u % 0x40 + 0x80
        local b1 = math.floor(u/0x40) + 0xC0
        UTF8 = string.char(b1, b2)
    elseif u < 0x10000 then   -- less than 16 bits
        local b3 = u % 0x40 + 0x80
        local b2 = math.floor(u/0x40) % 0x40 + 0x80
        local b1 = math.floor(u/0x1000) + 0xE0
        UTF8 = string.char(b1, b2, b3)
    elseif u < 0x200000 then  -- less than 22 bits
        local b4 = u % 0x40 + 0x80
        local b3 = math.floor(u/0x40) % 0x40 + 0x80
        local b2 = math.floor(u/0x1000) % 0x40 + 0x80
        local b1 = math.floor(u/0x40000) + 0xF0
        UTF8 = string.char(b1, b2, b3, b4)
    elseif u < 0x800000 then -- less than 24 bits
        local b5 = u % 0x40 + 0x80
        local b4 = math.floor(u/0x40) % 0x40 + 0x80
        local b3 = math.floor(u/0x1000) % 0x40 + 0x80
        local b2 = math.floor(u/0x40000) % 0x40 + 0x80
        local b1 = math.floor(u/0x1000000) + 0xF8
        UTF8 = string.char(b1, b2, b3, b4, b5)
    else
        print("Error: Code point too large for Codea's Lua.")
    end
    return UTF8
end

```

Very interesting - some very unusual images in there

Used this in one of my games today a recreation of “9 mens Morris”. Used it to make the
player pieces more attractive. Thanks for posting this!

Weird… Some emojis are missing and are replaced with a square. Any ideas on why this is?