E-Zine Exclusivo para o Whastapp

Como descobrir se uma cor hexadecimal é escura ou clara

php_e_javascript Como descobrir se uma cor hexadecimal é escura ou clara
foto_ramos Como descobrir se uma cor hexadecimal é escura ou clara

Ramos de Souza Janones

Janones, é um empreendedor brasileiro apaixonado por empreendedorismo e tecnologia. Ao longo dos anos trabalhando com o desenvolvimento de softwares desktop desde a linguagem Clipper, passando pelo Delphi e atualmente com Java.

Optou pela formação de Publicidade e Marketing por sua segunda empresa de tecnologia ter participado do "boom" da internet nos anos 90 e na procura de melhorar seus conhecimentos em negócios.

Em razão da principal formação e profundos conhecimentos em programação e banco de dados, é capaz de realizar o desenvolvimento de aplicativos web, desktop e mobile com maior criatividade e inovação que profissionais de desenvolvimento com uma formação única e mais especifica, dedicada somente ao desenvolvimento de softwares.

Com toda sua experiência com empresas de software, sua formação e paixão por negócios escreveu o livro "Marketing para Empresas e Profissionais de Software", publicado pela editora carioca Ciência Moderna em 2012. Além de outros livros sobre programação.
foto_ramos Como descobrir se uma cor hexadecimal é escura ou clara

Antes de mais nada um pouco de teoria:

Estratégias para o anti-aliasing

O algoritmo de anti-aliasing em geral não é muito complexo, mas ele torna-se complexo quando você entra nos detalhes mais sórdidos e nas otimizações. Para efeitos de comparação vamos começar com um algoritmo simples sem anti-aliasing, que vou denominar de A:

A: Para cada pixel que você analisa para decidir qual é a sua cor, você verifica dentro de qual forma geométrica este pixel está e aplica a cor correspondente.

E agora com anti-aliasing, vamos fazer uma algoritmo B:

B: Para cada pixel que você analisa para decidir qual é a cor, você verifica qual é a fração de sua área que está em cada uma das formas geométricas e então obtém a cor correspondente de cada uma das formas geométricas e aplica a cor correspondente a média ponderada pelas áreas.

O algoritmo basicamente é isso. É óbvio que ele se torna mais complicado quando você começa a aplicar degradês, texturas, transparências e translucências, reflexão, etc. Uma forma simples de se lidar com esta complexidade é usar uma técnica chamada supersampling, criando então o algoritmo C:

C: Subdivida cada pixel em um número suficiente de subpixels e aplique o algoritmo A para cada subpixel. No fim, a cor do pixel resultante será a média das cores dos subpixels.

O resultado deste algoritmo C deverá ser idêntico ou quase idêntico ao do algoritmo B, porém mantendo-se a simplicidade do algoritmo A. O problema é que o desempenho dele é bem pior devido ao grande número de subpixels, mas existe bastante espaço para efetuar-se otimizações e eliminar a necessidade de computar-se subpixels com cores sabidamente idênticas, além de muitas outras possíveis otimizações.

Curso de PHP ERP com NFe.

Além disso, para calcular o número suficiente de subpixels do algoritmo C, normalmente o número de tons diferente que cada componente de cor (vermelho, verde ou azul) pode assumir é um limite superior para tal número. Ou seja, na maioria dos casos, aonde cada componente é representado com um byte variando de 0 a 255, então dividir um pixel em 256 subpixels (16×16) é suficiente, mas talvez este número seja exagerado e você queira subdividir em um número menor de subpixels.

Anti-aliasing em monitores LCD

Também tenho que dizer que o algoritmo usado em monitores e telas LCD é diferente do CRT. No CRT o algoritmo é basicamente o B ou o C. No LCD, se você for fazer anti-aliasing de uma linha diagonal preta em um fundo branco, ou então de letras, e você der um screenshot na imagem resultante (tecla prt scr) e dar um zoom nela, o anti-aliasing apresentará cores bem diferentes das que seriam esperadas sem o anti-aliasing. Eis aqui um screenshot do texto “LCD” de cor preta em fundo branco em zoom de 500%, ao lado da imagem original para provar isso:

R9MYR Como descobrir se uma cor hexadecimal é escura ou clara

Isso ocorre porque o algoritmo do LCD tem uma diferença significativa para o algoritmo C delineado anteriormente: ele considera que os subpixels não são iguais aos pixels que podem assumir qualquer cor. No LCD, os subpixels são monocromáticos, sendo que pelo menos no meu caso, os subpixels azuis estão na parte mais a direita do pixel, os vermelhos na parte mais a esquerda e os verdes no centro. Ao conhecer-se a disposição das cores dos subpixels, é possível efetuar-se este tipo de anti-aliasing.

Composição de cores

É importante ter em mente que embora o branco seja o resultado da soma do vermelho, do verde e do azul, isso não significa que cada uma destas três cores representa um terço do branco. Isso não é verdade, e pode ser percebido facilmente de forma empírica ao notar-se que o verde puro é brilhante, enquanto que o vermelho puro é fosco e o azul puro é escuro.

Na verdade, a proporção exata da composição da luz branca depende da disposição das diferentes células receptoras na retina do olho do observador, condições de saúde, cansaço, idade e stress do observador, das condições de iluminação, do brilho e contraste da tela, do ângulo e direção entre o plano da tela e a linha de visada do observador, do tipo da tela (reflexiva ou anti-reflexiva, CRT, LED, plasma, LCD, retroprojetor, kindle, etc), entre muitas outras variáveis, podendo até mesmo variar de um olho para outro em uma mesma pessoa com visão normal e saudável.

Mas, desconsiderando-se estas variáveis que estão fora do controle do programador e pressupondo que o usuário tenha uma visão saudável e esteja usando uma tela de boa qualidade em um ambiente com iluminação adequada, há uma fórmula que vi em um livro uma vez há alguns anos que dava a seguinte proporção:

chart?cht=tx&chf=bg,s,FFFFFF00&chl=%5Ctext%7BBrilho%7D%5C;%3d%5C;0,290%5C;%5Ctimes%5C;%5Ctext%7Bvermelho%7D%5C;%2b%5C;0,599%5C;%5Ctimes%5C;%5Ctext%7Bverde%7D%5C;%2b0,111%5C;%5Ctimes%5C;%5Ctext%7Bazul%7D%5C; Como descobrir se uma cor hexadecimal é escura ou clara

É uma pena que não lembro o título, mas o bfavaretto deu três referências para isso nos comentários: 1, 2 e 3, embora existam pequenas variações nos fatores exatos.

Ter em mente estes fatores da composição do brilho é importante para o caso de você quiser fazer um algoritmo de anti-aliasing que considere que os subpixels têm diferentes cores.

Essa mesma fórmula dada acima para a cor branca, pode ser usada para medir-se o brilho de uma determinada cor a partir de seus componentes vermelho, verde e azul. De acordo com esta página, a fórmula recomendada pela W3C (parecida com essa anterior) é:

chart?cht=tx&chf=bg,s,FFFFFF00&chl=%5Ctext%7BBrilho%7D%5C;%3d%5C;0,299%5C;%5Ctimes%5C;%5Ctext%7Bvermelho%7D%5C;%2b%5C;0,587%5C;%5Ctimes%5C;%5Ctext%7Bverde%7D%5C;%2b0,114%5C;%5Ctimes%5C;%5Ctext%7Bazul%7D%5C; Como descobrir se uma cor hexadecimal é escura ou clara

Entretanto, essa mesma página diz que essa fórmula pode falhar ainda. Por exemplo, a cor (240, 0, 30) é um pouco mais brilhante que (80, 80, 80), sendo que por essa fórmula da W3C, a primeira teria um brilho de 75,18 enquanto que a segunda teria 80 (Sn58i Como descobrir se uma cor hexadecimal é escura ou clara). O motivo disso é que o brilho é na verdade a distância que uma cor tem em relação ao preto, e não apenas a soma ponderada dos valores das suas tonalidades.

Se considerarmos todas as cores dispostas como diferentes pontos internos em um paralelepípedo onde um dos vértices é o preto, o vértice oposto é o branco, os vértices adjacentes ao preto são o vermelho, o verde e o azul e os vértices opostos a esses são o ciano, o magenta e o amarelo (nesta ordem), teríamos que uma das dimensões corresponde ao valor do componente vermelho, a outra do componente verde e a outra do componente azul. Se definirmos o tamanho de cada uma das dimensões desse paralelepípedo como a intensidade do componente da cor correspondente, então poderíamos usar a distância euclideana do ponto ocupado por uma cor qualquer dentro desse paralelepípedo até o vértice da cor preta como uma medida do brilho. Assim, para calcular a intensidade de uma cor, basta usar o teorema de Pitágoras. Se usarmos os valores da W3C, chegaríamos a esta fórmula:

chart?cht=tx&chf=bg,s,FFFFFF00&chl=%5Ctext%7BBrilho%7D%5C;%3d%5C;%5Csqrt%7B0,299%5C;%5Ctimes%5C;%28%5Ctext%7Bvermelho%7D%29%5E2%5C;%2b%5C;0,587%5C;%5Ctimes%5C;%28%5Ctext%7Bverde%7D%29%5E2%5C;%2b0,114%5C;%5Ctimes%5C;%28%5Ctext%7Bazul%7D%29%5E2%7D%5C; Como descobrir se uma cor hexadecimal é escura ou clara

Nesta fórmula, os brilhos das cores acima seriam 131,62 e 80.

Que tal um pouco de prática?

Calculando luminosidade

A solução já vem do próprio W3:

https://www.w3.org/TR/AERT#color-contrast

Mais especificamente com esta fórmula:

( R * 299 + G * 587 + B * 114) / 1000

Ela retorna a luminosidade na faixa de a 255.

Como o ser humano tem em média uma percepção diferente de cada cor, a fórmula compensa para isto (o azul precisa ser muito mais forte para que tenhamos a “sensação” de que ele brilha tanto quanto um determinado vermelho).

Isto é uma média que não se aplica para os daltônicos. Daltônicos são pessoas que justamente tem problemas com algum desses “canais” de cor, muitas vezes deixando de ver parcialmente ou totalmente alguma das três cores.

Tratando o hexadecimal

Uma cor no formato #add555 nada mais é do que a combinação dos valores RGB em hexadecimal. No caso, temos estes valores:

 

 

 

O cálculo do hexa é bem simples. Não vou entrar em detalhes, pois tanto JS quanto PHP tem funções próprias para isto, quem quiser mais detalhes pode ler a postagem acima.
Vamos direto aos exemplos em código:

PHP

 

 

Veja funcionando no IDEONE.

JS

 

 

Veja funcionando no CODEPEN.

Formato “curto” e desconsiderando o #

Importante saber que as cores no formato “curto”, como #fc0 são simplesmente uma maneira mais curta de escrever #ffcc00.

Para converter uma cor do “formato” curto basta isso:

 

  • P: Mas de onde veio esse 17?
  • R: No formato curto, 0xF equivale a 0xFF, 0x1 equivale a 0x11. Em outras palavras, uma variação de a 15 em decimal no formato curto equivale a uma variação real de a 255.Simplificando: 255 / 15 = 17🙂

Em PHP pode ser usado desta forma:

 

E em JS:

Vai além do que foi perguntado, mas se precisar de um código mais “universal”, que reconheça cores em muitos formatos, tem um parser bem completo pronto aqui:

http://www.phpied.com/rgb-color-parser-in-javascript/

Top
%d blogueiros gostam disto: