Imágenes duotono o monocromáticas puro CSS: el filtro SVG feColorMatrix y su matriz a fondo 17.9.17
Explicación del filtro SVG feColorMatrix y su matriz para poder crearla con los valores necesarios para así obtener imágenes en la gama de colores deseada.
Demos incluidas para verlo en funcionamiento obteniendo imágenes en duotono o monocromáticas.
Imágenes duotono o monocromáticas puro CSS: el filtro SVG feColorMatrix y su matriz a fondo
Si has seguido los artículos que he dedicado a los filtros, especialmente el dedicado a los filtros equivalentes de SVG con los de Css que usan una palabra clave habrás observado que algunos filtros nativos de SVG usan lo que se conoce como matriz de color.
Son los filtros conocidos como feColorMatrix
por ser el elemento del SVG en el que se declara la matriz de color a usar por el filto.
La potencia y posibilidades que ofrecen los filtros SVG feColorMatrix
basados en una matriz de color son bestiales. Pero obtener el efecto deseado primero hay que conocer el significado de cada valor de la matriz y cómo funciona.
A intentar comprender la matriz de color empleada en los filtros SVG feColorMatrix
va dedicado este artículo. Con un poco de suerte, y gracias a que otros autores han compartido sus conocimientos, al final lo tendremos algo más claro.
AVISO PARA FIREFOX:
Si ocultas el SVG que contiene el filtro con "display: none" Firefox fallará.
Si incluyes el SVG en el mismo documento donde haces uso del filtro es conveniente ocultarlo, el SVG, de alguna manera. Son muchas las formas disponibles.
De un tiempo a esta parte había observado que Firefox fallaba al aplicar el filtro SVG vía css filter: url(#id)
.
Tras unas cuantas vueltas he descubierto que si el SVG es ocultado mediante display: none
deja de funcionar en Firefox. No hay problema con otros navegadores como Chrome.
La matriz de color en el filtro feColorMatrix
Un típico elemento feColorMatrix
con su matriz luce como ves en el siguiente código:
<filter id="miMatriz">
<feColorMatrix in="SourceGraphic"
type="matrix" values="
1 1 1 1 0
0 0 0 0 0
0 0 0 0 0
0 0 0 1 0" />
</filter>
Como ves, la matriz son los 0 y 1 del atributo values
. Es una estructura compuesta de cuatro filas y cinco columnas.
La notación de los colores es RGBa expresados en un rango para cada uno de los canales de 0 a 1.
Cómo funciona la matriz del filtro SVG feColorMatrix
Trabajar con una matriz no deja de ser una operación matemática de multiplicación de 2 matrices: la primera la que declaramos en el atributo values
del elemento feColorMatrix
y la segunda es el valor del color de cada píxel en la imagen original. El resultado de esta operación (y del filtro) es el color final o de salida:
salida matriz del filtro entrada
| R' | | a00 a01 a02 a03 a04 | | R |
| G' | | a10 a11 a12 a13 a14 | | G |
| B' | = | a20 a21 a22 a23 a24 | * | B |
| A' | | 0 0 0 0 1 | | A |
/*R G B A X */
1 1 1 1 0
0 0 0 0 0
0 0 0 0 0
0 0 0 1 0
Cada fila representa el valor de salida para cada uno de los canales RGBa. Cada columna representa el valor de entrada de cada canal y un valor constante (la X).
Si aplicamos la matriz anterior a cualquier imagen el resultado (valor de salida) será R=1, G=0, B=0 sin modificar el canal alfa. Dicho de otra manera, hemos convertido todos los colores de entrada a un único valor de salida: rojo. Como en el siguiente pen:
See the Pen vOKYJy by Kseso (@Kseso) on CodePen.
Pero por lo general este no será el resultado buscado. Normalmente se busca o bien que el negro se mantenga negro o cambiarlo por otro tono y el resto de colores que sea una gama (gradiente) entre él (el negro o su sustituto) y un segundo color.
Matriz para imágenes duotono
Todo lo anterior es teoría. Teoría que podemos obviar a la hora de crear cualquier matriz sabiendo de antemano qué 2 colores deseamos. Para hacer más sencillo esta intro teórica partamos de una imagen imaginaria en escala de grises que queremos pasar a duotono.
Lo primero que tenemos que hacer es elegir el color que reemplazará al negro.
Elegimos un azul, en notación hexadecimal #1A6699
. Pero como hemos visto esta codificación no se puede emplear. Necesitamos pasarlo a un valor RGB con valores para cada canal entre 0 y 1. Para esto cualquier aplicación de gestión de colores nos sirve. Sólo necesitamos pasar la anotación RGB porcentual (en %) 10% 40% 60%
a su equivalente en este rango. Para este azul vemos que su valor RGB de 0 a 1 es 0.1 | 0.4 | 0.6
. Lo llamaremos R1G1B1
Ahora sólo tenemos que tomar este valor y ponerlo en nuestra matriz en la columna de la constante. La columna de la X
:
/*R G B A X */
0 0 0 0 0.1
0 0 0 0 0.4
0 0 0 0 0.6
0 0 0 0 1
Primer paso conseguido. El resultado de esta matriz será un solo color plano: este azul. Así que ahora necesitamos crear el gradiente de color entre este azul y el segundo color o tono elegido.
Para esta explicación elegimos un amarillo #E5FF1A
que pasado a notación RGB en el rango de 0 a 1 es 0.9 | 1 | 0.1
. A este color lo llamaremos R2G2B2 para diferenciarlo del azul anterior.
Para obtener el valor para la matriz que genere el gradiente entre el azul anterior (R1G1B1) y este amarillo (R2G2B2) necesitamos hacer una pequeña operación matemática: restarle por canales al segundo color el primero:
(R2 - R1) | (G2 - G1) | (B2 - B1)
(0.9 - 0.1) | (1 - 0.4) | (0.1 - 0.6) =
0.8 | 0.6 | -0.5
El resultado de esta resta canal a canal 0.8 | 0.6 | -0.5
es el que tenemos que tomar para ingresarlo en la primera columna de nuestra matriz. La indicada con la R.
/*R G B A X */
0.8 0 0 0 0.1
0.6 0 0 0 0.4
-0.5 0 0 0 0.6
0 0 0 1 0
Y con esto ya tenemos nuestra matriz para pasar una imagen a un duotono con ese azul #1A6699 como color principal y el amarillo #E5FF1A como segundo color. El resultado, aplicado de nuevo a la imagen del Diablo de Tasmania es el que puedes ver en el siguiente pen:
See the Pen waWMLw by Kseso (@Kseso) on CodePen.
Imágenes monocromáticas
Un caso particular es el pasar cualquier imagen a un solo tono de color: monocromáticas. O lo que es lo mismo, que se dibuje en un color y su gradiente a blanco.
Como hemos visto, en la columna X de la matriz colocamos el valor del color seleccionado. Por ejemplo, para volver verde a nuestro amigo Taz, vamos con el color #005000
que pasado a la notación RGB es 0 | 0.31 | 0
. Es nuestro R1G1B1
Como no queremos otro tono que no sea mezcla con el blanco 1 | 1 | 1
este será el R2G2B2 al que restarle el verde: 1 | 0.69 | 1
serán los valores de la columna R:
/*R G B A X */
1 0 0 0 0
0.69 0 0 0 0.31
1 0 0 0 0
0 0 0 1 0
See the Pen gpMrJM by Kseso (@Kseso) on CodePen.
Matriz para escala de grises
Y como ya habrás caído, una variante de las imágenes monocromáticas son las mostradas en escala de grises. Su matriz es aún más sencilla. Valores para X todos ceros y en R unos:
<svg class='hide'>
<filter id="miMatriz">
<feColorMatrix in="SourceGraphic"
type="matrix" values="
1 0 0 0 0
1 0 0 0 0
1 0 0 0 0
0 0 0 1 0" />
</filter>
</svg>
Puedes probar a ir bajando el valor de los unos de esta matriz y ver qué ocurre con la luminosidad y brillo y si disminuyes el valor del canal alfa (el uno de la última fila) su efecto en función del color de fondo que haya debajo de la imagen.
Matriz para negativo en blanco y negro
Si deseas obtener un negativo en escala de grises de cualquier imagen la matriz tampoco tiene secretos: el color principal (R1G1B1) es el blanco 1 | 1 | 1
y el segundo será el negro (triple cero) y el valor de su resta todos -1 (en la primera columna):
values="
-1 0 0 0 1
-1 0 0 0 1
-1 0 0 0 1
0 0 0 1 0"
Resumiendo cómo trabajar con la matriz del filtro SVG feColorMatrix
- Elegimos dos colores. El primero como color principal de salida y el segundo para crear el gradiente entre ambos.
- Ambos los convertimos a notación RGB con valores entre 0 y 1 (el valor RGB poncentual en base 1).
- El primer color en esta notación lo escribimos en la columna X o del valor constante de la matriz.
- Restamos (canal por canal) del valor del segundo color el del primero.
- El resultado de esta resta lo colocamos en la primera columna de la matriz (la marcada con la R)
Pasar cualquier imagen a escala de grises y a duotono
La cuestión de aplicar estos filtros a una imagen en color verdadero es que el resultado final puede que quede algo difuminado.
Para resaltarla creo que es mejor (dependiendo muy mucho de cada imagen y su gama de colores) reducir su profundidad de color y hasta quizás jugar con el contraste
Es más, quizás hasta te interese pasarla primero a escala de grises para a continuación obtener la versión en duotono. O monocromática. Que está muy de moda también.
Para lograrlo no necesitas estropear la imagen usando un editor de imágenes. Se puede hacer con Css concatenando filtros:
.miImagen {
filter: contrast(2) grayscale(1) url(#url(#miMatriz);
}
El resultado de los tres filtros anteriores (los dos filtros Css y el filtro SVG) lo puedes ver a continuación. Pasa el puntero sobre la imagen para ver la original:
See the Pen mJEPmN by Kseso (@Kseso) on CodePen.
RECUERDA que el orden en que aparecen los filtos en la declaración sí importa. Primero se aplica el filtro declarado en primer lugar, a su resultado se aplica el segundo y así sucesivamente. Por lo tanto, si pones en el ejemplo anterior el filtro de escala de grises el último el resultado será una imagen en escala de grises.
Artículos relacionados y créditos
A lo largo de estos años son varios los artículos dedicados a los filtros aparecidos en el blog. No sólo los aplicables mediante la propiedad filter
(ya sean con palabras clave de Css o filtros SVG). También tienes información sobre los modos de fusión blend-mode
.
Siguiendo este enlace te aparecerán listados: filtros y modos de fusión.
Y en el artículo Yes, we fun!
un divertimento emulando la estética de ese tipo de carteles con los filtros a partir de cualquier imagen:
Agradecimientos y créditos
- Una ayuda inestimable para la comprensión de las matrices en el filtro SVG feColorMatrix fue la respuesta de AmeliaBR en este hilo de stackoverflow.
- @AmeliasBrain en Twiter
- Amelia en Codepen
- Para ampliar: Con posterioridad a la publicación de este artículo (25/05/2015) Amelia pucblicó en Css-tricks este post.
- La imagen del inicio del post de publicdomainreview.org
Kseso
the obCSServer ᛯ Ramajero Argonauta, Enredique Amanuense de CSS.#impoCSSible inside
Dicen que, en español, EsCss es el mejor blog de CSS. Posíblemente exageren.
@Kseso EsCss Kseso