Converter RGB888 para RGB565

Para quem utiliza um display RGB como o ILI9341 certamente quererá em algum momento manipular cores. Acontece que existem diferentes profundidades de cores, e nesses displays o RGB é diferente do RGB de monitores de computador. No computador o RGB tem 24 bits (RGB24 ou RGB888), e nos displays como o ILI9341 a profundidade de cores é de 16 bits (RGB16 ou RGB565). Nesse artigo vamos ver brevemente como converter RGB888 para RGB565 e vice-versa.

Já mostrei como fazê-lo através das bibliotecas TFT_eSPI e também através da biblioteca LVGL. A questão é que eu criei uma biblioteca para manipulação de cores CMYK, HSL e HSV para RGB (e vice-versa de novo). Isso porque estou migrando o Misturador de cores CMYK da biblioteca TFT_eSPI para a LVGL, e como estou utilizando widgets para controle das cores, preferi escrever uma biblioteca que todos pudessem aproveitar. Quando estiver disponível no repositório do Arduino para ser instalado pelo gerenciador de bibliotecas, escrevo outro artigo.

“Raio X” do RGB 16 e 24

A maioria dos makers sabe que o RGB é composto por 3 Bytes – ou 24 bits. Cada Byte tem 8 bits, sendo 1 Byte pra cada cor, totalizando os 24 bits. Dois à vigésima quarta potência nos dá uma faixa de 16.777.216 cores possíveis. O R em máxima resulta em 255 (porque 1 Byte vai de 0 à 255), representado por 0xFF em hexadecimal e 0b11111111. É nesse valor binário que eu queria chegar.

Os valores dos bits são contados da direita para a esquerda, começando na potência de 0 (que resulta em 1, porque qualquer número elevado a zero é 1). No último bit temos o valor 128, que somado a todos os bits anteriores resulta em 255. O RGB565 é um RGB de 16 bits, somando os dois 5’s e o 6, sendo que o G tem 1 bit a mais. Com 16 bits deslocados para a direita, teríamos uma profundidade de cores máxima de 65.536  valores possíveis. É pífio em relação aos 24 bits. E isso afetaria na resolução final visualmente, pois diversas tonalidades não poderiam ser exibidas, afetando nossa referência visual. Ainda em relação à variação por cor, contra os 256 valores possíveis de cada cor do RGB888, teríamos apenas 32 cores no vermelho64 cores no verde e, novamente, 32 cores no azul.  Por isso tenha em mente que o que é feito é o descarte dos 3 bits menos significativos de cada cor.

Como converter RGB888 para RGB565 ?

Se você não leu e adotou as práticas de bitwise que indiquei em diversos artigos, descrito em “Dominando PCF8574 com Arduino“, hora de se lamentar. Ou ler agora para entender melhor.

O resultado (mesclando bitwise com um teste visual que fiz para conferir o deslocamento) fica desse jeito:

uint16_t rgb888_rgb565(uint8_t r, uint8_t g, uint8_t b){
  uint8_t blue  = (uint16_t)((b >> 3) & 0x1FU); //8 - 3 = 5
  uint8_t green = (uint16_t)((g >> 2) & 0x3FU); //8 - 2 = 6
  uint8_t red   = (uint16_t)((r >> 3) & 0x1FU); //8 - 3 = 5
  return (red << (16-5)) | (green << (16-(5+6))) | blue << (16-(5+6+5));
}

O retorno desloca para a esquerda, mas obviamente os bits que foram deslocados para a direita, se diferentes de 0, não voltarão a existir.

rgb rgb565_rgb888(uint16_t RGB16)
{
    rgb out;
    out.r = (RGB16 & 0b1111100000000000) >> 8;
    out.g = (RGB16 & 0b11111100000) >> 3;
    out.b = (RGB16 & 0b11111) << 3;
    return out; 
}

Aqui também representei de outro modo, mas a funcionalidade é a mesma.

O tipo rgb de retorno é uma definição de tipo que fiz para armazenar os valores e não precisar passar um monte de variáveis como parâmetro de função. Ela foi criada assim:

typedef struct {
    uint8_t r;
    uint8_t g;
    uint8_t b;
} rgb;

Para usar, é só seguir o exemplo anterior. Se nunca usou structs, para acessar é só fazer como no exemplo anterior também. Por exemplo, se quiser imprimir o valor de R da struct out:

Serial.println(out.r);

Com a biblioteca é muito mais fácil fazer essa manipulação. Não só ela como os demais tipos descrito no início, aguarde!

TODAS as fórmulas estão disponíveis no site Rapid Tables, se quiser fazer suas próprias implementações. Quando a biblioteca for lançada, farei um vídeo.

 

Revisão: Ricardo Amaral de Andrade