As classes do projeto são distribuídas em 5 pacotes:
Esta classe deve ser a encarregada de ler o arquivo de uma página WhatsApp salva e produzir uma cópia desse arquivo onde os emojis inseridos pelo usuário apareçam renderizados.
Converte um emoji codificado como String UTF-8 no nome do arquivo PNG que contém a figura deste emoji.
A linha 107 obtém a string de codepoints para este emoji. Enquanto a linha 109 acrescenta a esta String o caminho relativo e a extensão produzindo o nome do arquivo.
Isto é, o nome do arquivo tem caminho relativo ao diretório onde estão os arquivos HTML processados pelo programa.
A linha 112 cria um objeto File com o caminho absoluto para representar este arquivo e a linha 114 testa se o arquivo existe. (Aqui precisamos do caminho absoluto para o programa verificar se existe um arquivo no disco com este nome que foi obtido. Já o caminho relativo será utilizado no documento HTML para que este possa renderizar o emoji com este arquivo PNG.)
Mas caso não exista o arquivo, o método então verifica se existe um arquivo com a figura do emoji raiz deste emoji. E se existir retorna este nome de arquivo para que o programa possa pelo menos renderizar uma figura que se aproxime do emoji correto. No entanto a informação de que se trata de um arquivo com uma figura apenas semelhante é passada acrescentando uma exclamação (!) antes do nome do arquivo retornado.
Mas se não existir nem mesmo um arquivo com a figura do emoji raiz o método retorna null.
Em suma: este método faz a associação entre a tag no arquivo HTML original que insere a figura do emoji, com o nome de um arquivo PNG na pasta emoji-images contendo justamente uma figura para o emoji especificado na tag.
O método recebe uma tag que insere emoji no arquivo original e retorna uma nova tag que deve substitui-la no arquivo cópia.
O dado que define qual emoji deve ser renderizado é o valor do atributo alt na tag do arquivo original.
Portanto na linha 158 um objeto Matcher é criado para localizar o atributo alt na tag.
A String com o valor do atributo alt é atribuído ao objeto utf8Emoji na linha 164. E o nome do arquivo que contém a figura deste emoji é obtido na linha 169.
A nova tag que este método vai retornar dependerá do nome atribuído a utf8Emoji.
Constrói um HashMap associando cada tag que insere emojis no arquivo original à tag que irá substitui-la no arquivo destino.
getMap() varre o conteúdo do arquivo original procurando por tags que inserem emojis. Para cada nova tag localizada o método cria uma entrada na estrutura HashMap que tem esta tag como chave. E como o valor para esta chave, a tag pela qual será substituída no arquivo destino (cópia do original mas com tags deste tipo substituídas).
Numa próxima etapa, o método createNewFile() irá varrer o arquivo original para cada chave (tag original) neste HashMap, substituindo-a no arquivo destino pelo seu respetivo valor (tag gerada pelo programa) neste HashMap.
Cria o arquivo HTML capaz de renderizar os emojis.
Na linha 221, tagMap recebe um HashMap mapeando todas as tags que inserem emojis no arquivo original, em tags que irão substitui-las no arquivo destino.
O loop na linha 223 obtém cada uma das chaves neste mapa (as tags originais) e varre o conteúdo do arquivo original substituindo as ocorrências desta tag. As novas tags irão renderizar o emoji com os arquivos PNG baixados pela aplicação GetPngs.jar deste projeto.
A linha 226 grava este conteúdo editado no arquivo destino.
O método agora se ocupa de gravar um arquivo de relatório listando todos os emojis que a página tentava inserir, informando juntamente seus respectivos codepoints e a informação se o emoji foi renderizado corretamente, se o programa teve que usar o arquivo com a figura deste emoji raiz, ou se, na falta de um arquivo PNG para este emoji e até para seu raiz, este foi inserido na página simplesmente como um caractere UNICODE por meio de uma tag span.
A estrutura de dados com esta informação é também um HashMap cujas entradas foram inseridas nas execuções do método utf8EmojiToFilename(). Para cada String UTF-8 que utf8EmojiToFilename() converteu para nome de arquivo, o método verificou se este respectivo arquivo existia, se o que existia era apenas o arquivo com a imagem do emoji raiz, ou se nenhum arquivo PNG disponível poderia ser adequado para a renderização do emoji. E esse dado foi então inserido como uma entrada no HashMap emojisReport.
Esta classe usa um arquivo com o código fonte da URL https://emojipedia.org/whatsapp/ para localizar e baixar os arquivos PNG com figuras de emojis estilo WhatsApp.
A classe declara dois campos privados:
O método recebe um objeto Matcher que empacota uma regex juntamente com o texto do arquivo HTML e localiza todas as ocorrências que casem com a regex neste texto. A regex deve localizar URLs que serão baixadas para o diretório TARGET_DIR.
No loop da linha 42, o método find() localiza uma URL que case com a regex e retorna true. Esta URL é recuperada pelo método group() do objeto m. A linha 46 pega essa String a partir de "https:" até o final. (Portanto a regex não deve localizar as aspas no final de um link, caso contrário daria erro ao tentar baixar o arquivo).
Na linha 48 o método estático da classe FileTools é chamado para baixar o arquivo da URL para o diretório TARGET_DIR.
Na linha 50 uma saída formatada na janela de progresso da interface informa a URL que foi baixada.
Este método recebe o arquivo que é o código fonte da página https://emojipedia.org/whatsapp e baixa todos os arquivos PNG com imagens de emojis que estiverem referenciados nesta página. (O código fonte desta página foi obtido com a opção "Exibir código fonte" do Chrome, seguido de Copy/Paste em um editor de textos).
A linha 71 cria o diretório TARGET_DIR para onde serão baixados os arquivos se este diretório não existir. Se não houver este diretório e o método falhar ao criar um, o programa é abortado.
A linha 80 copia todo o conteúdo do código fonte da página https://emojipedia.org/whatsapp para o objeto String contentFile.
A linha 84 abre na tela a janela que irá exibir o progresso na execução do método.
Nas linhas 89 a 94, todas as URLs de arquivos PNG que forem o valor de um atributo srcset serão baixadas. (Note que a regex na linha 89 começa com um espaço em branco para evitar que URLs de um atributo como, por exemplo, data-srcset sejam indevidamente baixadas).
Nas linhas 99 a 104, todas as URLs de arquivos PNG que forem o valor de um atributo data-src serão baixadas.
A linha 106 apaga o título da janela de progresso do método. A linha 108 informa que todos as URLs localizadas foram baixadas e quantas foram baixadas. A linha 110 emite um sinal sonoro de aviso de término.
Faz o trabalho de normalizar os nomes dos arquivos baixados pela aplicação GetPngs.jar
A execução do método normalize() desta classe gera um arquivo de log em HTML que tabela todos os emojis catalogados. Os campos estáticos HEAD e FOOTER são respectivamente a parte inicial e final desse arquivo.
A linha 78 inicializa a janela que exibe o progresso da execução do método.
A linha 81 cria um array de arquivos que deve conter todos os arquivos PNG com imagens de emojis que foram baixados da Emojipedia. O objeto da classe EmojiFileFilter passado ao método listFiles() garante que apenas estes tipos de arquivos serão inseridos no array.
A linha 85 verifica se pelo menos algum arquivo foi encontrado no diretório indicado e caso contrário aborta a execução do método.
A linha 97 inicializa a barra de progresso passando o número de arquivos que serão normalizados.
O código entre as linhas 103 e 107 cria um novo diretório dentro do diretório onde estão os arquivos PNG. Arquivos com nomes normalizados serão movidos para este diretório de nome emoji-images.
Note-se que para criar este diretório a linha 103 obtém o caminho absoluto (caminho completo desde a raiz) do diretório onde estão os arquivos PNG baixados. Isso porque o diretório corrente pode ser diferente deste no momento da execução do programa.
A linha 113 cria um TreeMap onde cada entrada contém - como chave - o nome do arquivo antes de ser normalizado associado ao valor que é o nome que ele recebe depois de normalizado. Mostrando a alteração realizada no nome de cada arquivo baixado. As entradas deste TreeMap é que serão gravadas no arquivo HTML de log e por isso a escolha de uma estrutura TreeMap. Para que a listagem seja exibida ordenada alfabeticamente pelos nomes originais dos arquivos.
O loop da linha 119 até 150 renomeia e move todos os arquivos.
Por fim o método cria um arquivo HTML com a listagem dos arquivos renomeados. Onde para cada arquivo na lista é exibida a figura do seu emoji. A este arquivo é atribuído nome de _emoji-list.html
Gera cópias de páginas salvas onde os emojis são renderizados.
Classe que normaliza os nomes dos arquivos PNG baixados da Emojipedia.
O executável que obtém os arquivos PNGs no servidor da Emojipedia.
Métodos e campos com acesso por todas as classes do projeto.
Janela de interface que mostra o progresso da execução dos programas.
Metodos estáticos para leitura, gravação e download de arquivos.
Recebe um objeto File indicando um arquivo texto e lê todo o conteúdo deste arquivo para dentro de um objeto String que é retornado pelo método.
É importante ressaltar que o método espera que o arquivo esteja codificado com o padrão UTF-8
Recebe o nome de um arquivo texto e lê todo o conteúdo deste arquivo para dentro de um objeto String que é retornado pelo método.
É importante ressaltar que o método espera que o arquivo esteja codificado com o padrão UTF-8
Recebe um objeto File e uma String e grava esta String no arquivo. Se o arquivo não existir será criado; se já existir seu conteúdo atual será substituído.
O método espera que a String passada como parâmetro esteja codificada em UTF-8.
Recebe o nome de um arquivo e uma String e grava esta String no arquivo. Se o arquivo não existir será criado; se já existir seu conteúdo atual será substituído.
O método espera que a String passada como parâmetro esteja codificada em UTF-8.
Recebe a URL de um arquivo a ser baixado e o caminho do diretório onde baixar este arquivo. O caminho pode ser relativo ao diretório corrente ou absoluto e não deve terminar com o caractere /. O método baixa o arquivo para o diretório indicado mantendo seu nome original.
Deve-se notar que nomes de arquivos inválidos no sistema em que este programa estiver rodando não permitirão baixar o arquivo e uma exceção IOException será lançada.
Como um exemplo, tomemos o emoji 🇧🇷 que é codificado pelos seguintes UNICODES: U+1F1E7 U+1F1F7. Para renderizar este emoji uma página do WhatsApp Web o faria por intermédio de uma tag como esta abaixo:
<img src="d5fceb6532643d0d84ffe09c40c481ecdf59e15a.gif" alt="🇧🇷" draggable="false" style="background-position: -60px -40px;" class="b92 emoji wa _3Whw5">
Mas como este código não funciona offline, a ideia é gerar um novo arquivo - cópia do original - onde esta tag seria trocada por:
<img src="1f1e7-1f1f7.png" alt="🇧🇷" width="20px" height="20px">
Assim esta última tag renderizará o emoji desde que o arquivo 1f1e7-1f1f7.png exista e contenha a figura do emoji da bandeira do Brasil.
O programa teria que fazer esse tipo de conversão para qualquer tag como esta exemplificada acima.
Portanto é necessário que o programa seja capaz de converter 🇧🇷 na string 1f1e7-1f1f7. Converter qualquer emoji codificado em UTF-8 em seus respectivos codepoints escritos em hexadecimal e separados por um tracinho (-).
Mas também é preciso que possa converter o nome do arquivo flag-brazil_1f1e7-1f1f7.png em 1f1e7-1f1f7.png. E fazer o mesmo com qualquer nome de arquivo PNG baixado da Emojipedia: extrair os codepoints que aparecem como sufixos nestes nomes de arquivos e normalizar para o mesmo padrão usado na conversão de emojis UTF-8 para sequências de codepoints em hexa.
Ou seja, o algoritmo que vai converter UTF-8 emojis em strings de codepoints deve produzir exatamente o mesmo resultado que o algoritmo que vai normalizar os nomes dos arquivos obtidos na Emojipedia.
Para tanto é necessário observar em detalhe que padrão é utilizado para codificar emojis em UTF-8. E também observar cuidadosamente o padrão utilizado pela Emojipedia para nomear os arquivos com figuras de emojis.
No caso dos emojis codificados como caracteres há duas particularidades que precisam ser levadas em consideração:
A consequência do item 1 para os nossos propósitos neste projeto é que LOW SURROGATE BYTES nunca constam nas strings de codepoints que são os sufixos dos nomes dos arquivos que serão baixados da Emojipedia.
Portanto o algoritmo de conversão de string UTF-8 para string codepoint deve simplesmente desprezar qualquer LOW SURROGATE BYTE.
Já a consequência do item 2 é que para um determinado emoji, o caractere U+FE0F pode estar presente na string UTF-8 mas não no nome do arquivo. Ou pode estar presente no nome do arquivo mas não na string UTF-8. Ou pode estar ausente em ambos ou presente em ambos. E isto é imprevisível.
Portanto os algoritmos de normalização do programa irão eliminar códigos U+FE0F sempre que ocorrerem. Seja em strings UTF-8, seja como parte de nomes de arquivos.
Também há uma particularidade em como o Emojipedia nomeia estes arquivos... A parte do sufixo com os codepoints inicia sempre com um underscore e os diferentes codepoints são separados entre si por um tracinho. No entanto, por algum motivo, às vezes um codepoint está repetido nesta string. Mas quando esta repetição ocorre ele é separado do anterior não por um tracinho, mas por um underscore.
Este padrão também deve ser detectado pelo algoritmo para poder eliminar estes codepoints supérfluos.
E esta é fundamentalmente a ideia do processo de normalização aplicada nos dois métodos da classe Normalizer do pacote util.