Ultimamente, tive um problema com minha instalação do Fedora Linux exibindo emojis na interface do sistema operacional e nos navegadores. Esse problema me levou a investigar um pouco o projeto de configuração de fontes, mas para testar minhas configurações e fontes, precisei produzir emojis de todas as versões Unicode, o que eventualmente me levou a escrever um "script" Golang para imprimir todos os emojis e alguns informações sobre seus internos.
Ao longo desta viagem, mergulhei profundamente nos aspectos internos dos emojis, suas representações binárias e algumas das decisões estranhas/fofas tomadas pelo padrão Unicode em relação aos emojis.
Mas primeiro, vamos dar um passo atrás e resumir algum glossário.
Poderíamos descrever a codificação como o "mapeamento" ou "tradução" entre uma letra de um idioma e a representação binária desta letra. Por exemplo, a codificação ASCII tradicional mapeia a letra a para 0x61 hexadecimal (0b01100001 binário). Exemplos de codificações são as páginas de código de 8 bits da Microsoft (Windows 125x) ou ISO (ISO/IEC 8859).
Nessas páginas de código fixas de 8 bits, a "quantidade" mínima de informações usadas é de 8 bits (1 byte), o que significa que elas podem conter 256 letras/caracteres diferentes. Diferentes páginas de código foram criadas reutilizando os 256 códigos binários para suportar vários idiomas. Portanto, ter um arquivo de texto com esses 3 bytes escritos nele [0xD0, 0xE5, 0xF2] é lido como "Πες" usando o ISO 8859-7 grego, ou "Ðåò" usando o ISO 8859-7 ocidental (mesmos bytes, interpretados de forma diferente com base na página de código).
Em algum momento, ter muitas páginas de código diferentes não foi bem dimensionado à medida que a tecnologia progredia. Portanto, precisávamos de algo que pudesse se adequar a todos os idiomas (e mais) e ser unificado em todos os sistemas.
[ avançando, deixando muita história e padrões de fora, até o presente ]
O padrão Unicode foi projetado para oferecer suporte a todos os sistemas de escrita do mundo que podem ser digitalizados. Assim, usando o exemplo acima, nos padrões Unicode, a letra grega “Π” possui o código 0x03A0 enquanto a letra latina maiúscula eth “Д possui o código 0x00D0 e não colidem mais. O padrão Unicode tem versões e, no momento em que este artigo foi escrito, a versão mais recente era 16.0 (especificações).
Mas espere um minuto, o que é esse "ponto de código"?
No padrão Unicode, cada "letra", caractere de controle, emoji e cada item definido em geral tem um valor binário exclusivo chamado "ponto de código". O padrão define todos os pontos de código e cada ponto de código contém informações puras de código/binário. O formato hexadecimal para cada ponto de código geralmente é escrito com um prefixo U. Por exemplo, o ponto de código grego com letras minúsculas Ômega (ω) é U 03C9.
Então, quem realmente codificamos esses pontos de código?
A primeira parte da codificação de Code Points em bytes é a Encoding Fomrs. De acordo com o padrão:
Os formulários de codificaçãoespecificam como cada número inteiro (ponto de código) para um caractere Unicode deve ser expresso como uma sequência de uma ou mais unidades de código.
Formulários de codificação usam o termo "unidade de código" para se referir à menor unidade de dados usada para representar um ponto de código Unicode dentro de uma codificação específica.
O padrão Unicode define três formas de codificação diferentes:
Isso significa que um único ponto de código ou uma sequência de pontos de código pode ser codificado de forma diferente dependendo da forma de codificação usada.
A camada que cuida da serialização binária real em Unicode é chamada de Esquemas de Codificação e cuida de todos os detalhes de baixo nível (como endianness). Tabela 2-4 das especificações Unicode:
|Encoding Scheme| Endian Order | BOM Allowed? | | ------------- | ----------------------------| ------------ | | UTF-8 | N/A | yes | | UTF-16 | Big-endian or little-endian | yes | | UTF-16BE | Big-endian | no | | UTF-16LE | Little-endian | no | | UTF-32 | Big-endian or little-endian | yes | | UTF-32BE | Big-endian | no | | UTF-32LE | Little-endian | no |
Nota: Quase todas as linguagens de programação, sistemas operacionais e sistemas de arquivos modernos usam Unicode (com um de seus esquemas de codificação) como sua codificação nativa. Java e .NET usam UTF-16, enquanto Golang usa UTF-8 como codificação de string interna (isso significa que quando criamos qualquer string na memória, ela é codificada em Unicode com a forma de codificação mencionada)
O padrão Unicode também define pontos de código para emojis (muitos deles) e (após alguma confusão com o número da versão), a versão do "padrão" Emoji progride em paralelo com o padrão Unicode. No momento em que este artigo foi escrito, temos Emoji "16.0" e Unicode Standard "16.0".
Exemplos:
⛄ Boneco de neve sem neve (U 26C4)
? Rosto sorridente com olhos sorridentes e três corações (U 1F970)
Unicode define modificadores que podem seguir o ponto de código base de um emoji, como variação e tom de pele (não exploraremos a parte de variação).
Temos seis modificadores de tom de pele (seguindo a escala Fitzpatrick) chamados EMOJI MODIFIER FITZPATRICK TYPE-X (onde x é 1 a 6), e eles afetam todos os emojis humanos.
Tom de pele claro (Fitzpatrick Type-1-2) (U 1F3FB)
Tom de pele médio claro (Fitzpatrick tipo 3) (U 1F3FC)
Tom de pele médio (Fitzpatrick tipo 4) (U 1F3FD)
Tom de pele médio-escuro (Fitzpatrick tipo 5) (U 1F3FE)
Tom de pele escuro (Fitzpatrick tipo 6) (U 1F3FF)
Então, por exemplo, como todos os emojis humanos, o emoji de bebê? (U 1F476), quando não seguido por um modificador de pele, aparece em uma cor amarela neutra. Por outro lado, quando um modificador de cor da pele o segue, ele muda de acordo.
? U 1F476
?? U 1F476 U 1F3FF
?? U 1F476 U 1F3FE
?? U 1F476 U 1F3FD
?? U 1F476 U 1F3FC
?? U 1F476 U 1F3FB
A decisão mais estranha, mas fofa do padrão Emoji/Unicode é que alguns emojis foram definidos juntando-se outros usando o Zero Width Joiner sem um ponto de código independente.
Então, por exemplo, quando combinamos:
Bandeira Branca ?️ (U 1F3F3 U FE0F)
Marceneiro de largura zero (U 200D)
Arco-íris ? (U 1F308)
Aparece como Rainbow Flag ?️? (U 1F3F3 U FE0F U 200D U 1F308)
Ou, ?? ? => ???
Ou mesmo, ?? ❤️ ? ?? => ??❤️???
É como apertar emojis e então, puf?, um novo emoji aparece. Quão fofo é isso?
Eu queria criar uma tabela Markdown com todos os emojis, e as tabelas de sequência de emojis Unicode são a fonte da verdade para isso.
https://unicode.org/Public/emoji/16.0/emoji-sequences.txt
https://unicode.org/Public/emoji/16.0/emoji-zwj-sequences.txt
Então criei um analisador Golang (aqui) que busca e analisa esses arquivos de sequência, gera cada emoji quando um intervalo é descrito no arquivo de sequência e imprime uma tabela de markdown com algumas informações internas para cada um (como o partes caso tenha unido, ou o base tom de pele, etc.).
Você pode encontrar a tabela de descontos aqui.
A última coluna desta tabela está neste formato
str := "⌚" len([]rune(str)) // 1 len([]byte(str)) // 3
Como discutimos, a codificação de string interna do Golang é UTF-8, o que significa que, por exemplo, para emoji de relógio ⌚ o comprimento de byte é 3 (porque o UTF-8 produz 3 bytes para "escrever" este ponto de código), e o comprimento do ponto de código é 1.
Runa Golang == Ponto de código Unicode
Mas no caso de emojis unidos -mesmo que "apareça" como um- temos muitos pontos de código (runas) e ainda mais bytes.
str := "??❤️???" len([]rune(str)) // 10 len([]byte(str)) // 35
E a razão é que:
??❤️??? : ?? ZWJ ❤️ ZWJ ? ZWJ ?? ?? : 1F469 1F3FC // ? skin tone modifier [2 code points] ZWJ : 200D // [1 code points] * 3 ❤️ : 2764 FE0F // ❤ VS16 for emoji-style [2 code points] ? : 1F48B // [1 code point] ?? : 1F468 1F3FE // ? skin tone modifier [2 code points]
?
Vale ressaltar que a forma como vemos os emojis depende da fonte do nosso sistema e de quais versões de emoji essa fonte suporta.
Não sei exatamente os detalhes internos da renderização de fontes e como ela pode renderizar as fontes unidas corretamente. Talvez seja um post futuro.
Até então, felicidades?
Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.
Copyright© 2022 湘ICP备2022001581号-3