QR Code em AdvPL – Parte 02 | Tudo em AdvPL
InícioQR Code em AdvPL – Parte 02
18/05/2019 18/05/2019 Júlio Wittwer ADVPL, BLOG, QR CodeImagens, Programação
O post anterior foi apenas para abrir o apetite. Agora nós vamos entrar no passo a passo da classe ZQRCODE.
Classe ZQRCODE
A implementação mais simples para a utilização do usuário normalmente é a mais complexa de ser implementada. Simplificar uma ponta normalmente significa puxar a dificuldade e ter mais etapas e processos na outra. Na Internet existem várias implementações de sites gratuitos com geradores online de QR Code.
Boa parte delas permite gerar um QR Code solicitando ao usuário apenas um link, um email, um texto livre. Outras já são mais sofisticadas, permitem ao usuário informar o nível de correção de erro da imagem — quanto maior o nível, mais módulos (os quadradinhos) são usados para desenhar a imagem.
Criando o Objeto ZQRCODE
O método NEW(), construtor da classe, não recebe parâmetros, apenas cria um objeto vazio para a confecção de um QR Code. Por default, a correção de erro utilizada é "L" (Low) — a menor e mais leve. Por hora basta saber que existem 4 níveis de correção, e que isso pode ser alterado por um método na instância do objeto.
Setando a correção de erro
Através do método SETEC(), podemos alterar o nível da correção de erros da imagem a ser gerada. São 4 níveis, L (Low) , M (Medium), Q (Quartile) e H (High). Cada um dos níveis permite um índice de recuperação aproximado — variando de 7% (L) a 30% (H) — na prática, isto indica o percentual aproximando de "o quanto uma imagem pode estar danificada mas ainda assim ser lida". Este recurso permite por exemplo a criação de QR Codes "artísticos", por exemplo com uma outra imagem ou logotipo sobrescrevendo uma parte do código, e mesmo assim ele é lido com sucesso.
Informando os dados
Através do método SETDATA() podemos definir qual a informação que será colocada dentro da área de dados do QR Code. Embora exista suporte específico para dados numéricos, a implementação em AdvPL recebe sempre uma string. Como o QR Code possui 4 modos de codificação de dados (numérico, alfanumérico restrito, bytes e Kanji), você pode opcionalmente informar um número de 1 a 4 no modo desejado, ou não informar este parâmetro — a classe decide o melhor método baseado nas informações fornecidas. E, apenas para informação, Kanji não foi implementado 😀
Montando o QR Code
O método BUILDDATA() é onde começa realmente a implementação. Baseado nas escolhas anteriores e nos dados fornecidos, este método concentra chamadas para vários métodos e funções auxiliares. Uma das primeiras é a decisão de qual modo serão codificados os dados — numérico, alfanumérico ou bytes.
Como o modo alfanumérico contempla apenas letras maiúsculas, números e os caracteres " " (espaço em branco), "$" (cifrão) , "%" (percentual), "*" (asterisco), "+" (soma), "-" (subtração), "." (ponto), "/" (barra direita) e ":" (dois pontos), ele é suficiente para um endereço de um Web Site, ou mesmo um e-mail — mesmo não tendo o caractere "@" ( arroba) neste alfabeto, nada impede de usar uma escape sequence de URL "%40" no lugar deste caractere — onde a interpretação depende do leitor — ou codificar em bytes UTF8 ( onde o "@" 'é o caractere ASCII 64 ).
Escolhido o alfabeto, e assumindo um nível de correção de erro, podemos estimar qual é a versão de QR Code necessária para que o dado informado "caiba" dentro. A classe possui uma lista predefinida de capacidade por nível de correção de erro e alfabetos, logo uma busca ordenada nesta lista é suficiente para encontrar a versão de QR Code adequada.
Determinada a versão — e consequentemente o tamanho — do QR Code, a propriedade ::aGrid é inicializada com um array bidimensional de números, onde cada posição equivale a um módulo (quadradinho) do QR Code. Todas as posições do array são inicializadas com o valor -1 — que indica que esta posição está livre para uso — e posteriormente as áreas reservadas e de dados serão preenchidas com 0 (módulo vazio) ou 1 (módulo usado).
Um QR Code é lido por um scanner óptico, de uma forma diferente de um código de barras tradicional. Para ser possível a leitura dos dados na ordem correta, e permitir ao leitor determinar a localização e alinhamento dos dados. O padrão de módulos chamado de "localizador" é uma imagem composta por uma matriz 7×7 formando um quadrado com 26 módulos, e na área interna 9 módulos no centro formando outro quadrado.
Um QR Code utiliza três localizadores, distribuídos nos cantos superior esquerdo, superior direito e inferior esquerdo. A partir da versão 2, é necessário utilizar uma imagem adicional, chamada de "alinhamento". Ele é formado por uma matriz 5×5 formando um quadrado de 18 módulos, com um módulo central. Quanto maior a versão do QR Code, e consequentemente seu tamanho, mais imagens de alinhamento são necessárias.
Veja abaixo o padrão localizador e o padrão de alinhamento, respectivamente:
Em volta de cada localizador, deve ser deixada em branco uma margem de um módulo. O localizador é 7×7, mas ele reserva uma área de 8×8 módulos, onde a linha e coluna de margem de módulos não setados está na parte de dentro do QR Code.
Os três localizadores são ligados entre si por uma sequência alternada de módulos ligados e desligados, formando uma espécie de "linha pontilhada". Os módulos que compreendem estas linhas também são reservados. Estas linhas pontilhadas são chamadas de "Timing Patterns". E, existe mais um ponto reservado do lado do localizador inferior, chamado "Dark Module", deve ser setado na nona coluna da esquerda para a direita do localizador inferior, imediatamente a direita da primeira linha do localizador inferior. Veja abaixo um QR Code versão 1 com os localizadores e as "Timing Lines" e o "Dark Module" desenhados.
Ainda faz parte das áreas reservadas 30 módulos, em volta do localizador superior esquerdo, na lateral direita do localizador inferior esquerdo, e na primeira linha abaixo do localizador superior direito. Estes módulos são reservados para representar a formatação e correção de erro, que usam 15 módulos. São reservados 30 módulos, para a informação ser colocada duas vezes na imagem. Estes espaços estão destacados em azul. Posteriormente vamos ver como estas áreas são preenchidas.
Uma vez com a definição do alfabeto a ser usado, os dados fornecidos são codificados em uma sequência de bits. Caso a sequencia de bits seja menor do que a área de dados (quantidade de módulos não reservados disponíveis), são usados dois bytes predefinidos para preencher a sequência até o final. Após a codificação binária, cada conjunto de 8 bits (1 byte) é convertido para um valor inteiro de 0 a 255, que na prática compõe a sequencia de dados da mensagem.
Porém esta sequência não é desenhada diretamente no QR Code. De acordo com a versão e do nível de correção de erro utilizado, um determinado número de bytes de correção de erro devem ser gerados usando a sequencia de dados da mensagem e um polinômio (equação) gerada sob medida para a quantidade de bytes de correção de erro. Neste ponto do processamento, chamamos cada um destes "bytes" ou números de "Code Words".
Geração da correção de erro
Esta é uma das etapas mais complexas do processo. No tutorial mais completo que eu encontrei, as equações e as etapas — multiplicação e divisão de polinômios — era explicada em detalhes, até mesmo como funciona a geração do polinômio de acordo com o número de Code Words necessárias para correção de erro.
A primeira grande sacada foi aproveitar um recurso de montagem dinâmica das equações para cada número de bytes de correção de erro necessários, e guardar as equações em uma lista, assim eu já tenho no programa as equações prontas.
A segunda grande sacada foi aproveitar uma lista pronta de conversão de dados do polinômio em uma notação de potência de dois — ou notação Alpha — também já calculada. Como existe a necessidade durante o processamento de transformar uma equação com os valores numéricos dos elementos entre notações, foram montadas duas funções de conversão com a lista (Alpha para Numérico e vice-versa).
A terceira grande sacada foi, após entender como os cálculos funcionam, que era possível representar os polinômios com arrays bidimensionais, e que as operações poderiam ser feitas apenas com os valores e as potências armazenados nestes arrays. Uma vez que eu entendi a regra, aí sim foi possível escrever o resto da rotina.
Depois de multiplicações e divisões e conversões, o método BUIDERRDATA() retorna um array contendo os números (bytes ou Code Words) que completam a sequência de Code Words dos dados.
Disposição dos dados na matriz
Chegando na penúltima etapa, após montar as sequencias de dados e de correção de erro, a próxima etapa é gerar um (ou mais) grupos de bits com todos estes números e distribuir de forma ordenada na matriz do QR Code, sem passar por cima das áreas reservadas. Esta etapa não é muito complexa, porém pode exigir a separação e intercalação de dados, de acordo com o tamanho (versão) do QR Code a ser gerado.
Na forma mais simples, com QR Code que usam apenas um grupo de informações, a sequência final de CodeWords é gerada apenas acrescentando a correção de erro no final da sequência de dados, gerando uma string binária (apenas com "0" e "1") e distribuindo pares de bits da direita para a esquerda, iniciando no canto inferior direito, de baixo para cima, e invertendo a direção e pulando duas colunas para a esquerda a cada vez que o limite superior ou inferior são atingidos. É praticamente um ziguezague de ziguezagues. E ainda não acabou.
Dependendo da sequência de bits que compõe a mensagem, e da forma que eles foram distribuídos dentro do QR Code, pode acontecer agrupamentos de muitos módulos preenchidos, junto com áreas em branco, ou ainda áreas de dados que podem ficar parecidas com as áreas reservadas e "confundirem" o scanner.
Para evitar este tipo de ocorrência, existem 8 fórmulas de "mascaramento de dados", criadas para serem aplicadas após a disposição dos dados, para verificar como ficou a versão final do QR Code. Existe uma técnica que envolve algumas regras analisar as sequencias e áreas de dados do QR Code, para determinar um fator de "penalidade".
A etapa de mascaramento de dados consiste em guardar a versão original dos dados distribuídos no QR Code, gerar todas as 8 possibilidades de aplicação de mascaramento de dados, e avaliar o índice de penalidade de cada uma. O mascaramento que retornar o menor índice é a melhor opção de uso para facilitar a leitura pelo scanner. Este trabalho é feito pelo método MaskDataGrid()
Informações de versão e formato
Após escolher o mascaramento a ser usado, e já ter as áreas de dados e reservadas plotadas, é possível determinar aquela sequência de formato de 15 módulos que eu mencionei anteriormente, para finalmente colocá-la no grid do QR Code. Com isso feito, o resultado final é o array ::aGrid preenchido com zeros e uns, onde cada 0 é um módulo em branco — vazio — e cada 1 é um módulo a ser desenhado. Com este array, é possível criar um objeto ZBITMAP monocromático, e fazer a pintura de blocos de pontos para formar os quadradinhos necessários, lembrando que a imagem final deve reservar 5 módulos de margem (superior, inferior e laterais) em branco.
Nos próximos posts sobre QR Code, vou detalhar cada etapa deste processo, desde a escolha do alfabeto ou modo de codificação, até a geração da imagem final, com o código, claro !!!!
Espero que vocês tenham gostado, e desejo a todos TERABYTES DE SUCESSO !!!
QR Code – Wikipedia contributors. (2019, May 8). QR code. In Wikipedia, The Free Encyclopedia. Retrieved 22:14, May 16, 2019, from https://en.wikipedia.org/w/index.php?title=QR_code&oldid=896105420
← QR Code em AdvPL – Parte 01
Bitmaps em AdvPL – Parte 05 →
Um comentário sobre "QR Code em AdvPL – Parte 02"
QR Code em AdvPL – Parte 03 | Tudo em AdvPL disse:
26/05/2019 às 00:55
[…] post anterior vimos uma breve introdução a classe ZQRCODE. Agora, vamos ver um fonte usando essa classe ! A […]