Image — Dead Zebra

Duotone and Android

Lucas Urbas
4 min readOct 3, 2016

--

Duotone is a hot design trend in web design. Probably this movement started getting more traction in beginning of 2016 when Spotify applied it to their summary of 2015 year in music.

Basically duotone is a black and white imagery, where the white color is replaced with one color, black with an other, and greyscale is a calculation between this two. You can see the example in header of this post.
The answer to the question if it works well with Material Design and Android guidelines is a personal matter. I wanted to play with it, make some experiments and see if I can come up with something interesting.
Here are some examples of popular screens from Android apps changed to have a little bit of this duotone feeling.

I found it works best when you want the image to blend better with your branding colors, or with the color important for specific section. Consider a background image where instead of adding a scrim for text protection, you can choose text color with hight contrast of image duotone.

Another place where it feels right is a category screen, here the color is more important than a picture, user will feel a connection with it itself, not with images, which can change with time.
I general, it is a counter pattern of applying colors to UI extracted from photography (with use of library like Palette). This one is particularly strong in apps like music players or any portfolio apps.
But anyways, like I said, it’s a personal matter.

If you feel like you want to take a chance on this style, this is where I hope it will start being interesting. Actually, this is what this post is all about. It’s relatively easy to achieve the wanted effect in Photoshop or even Sketch. The main question is, how to do it programmatically on Android?
I’m happy to give an answer — color matrix and color filter.

Building a duotone color filter

Assuming you want to change any image downloaded from internet to a duotone one, you have to do this three steps:

  • Convert image to black and white.
  • Adjust contrast (optional).
  • Switch black and white with customs colors.

Here is a ready method that does exactly these three things and returns ColorFilter you can simply attach to your ImageView.

But if you are interested in color matrixes, stay with me.
To change image rendering on Android, without changing the source bitmap can be done by applying ColorFilters. In this case a child class — ColorMatrixColorFilter created with a result of multiplying three different color matrixes. Color matrix is a transformation of RGBA channels of every pixel’s value when applied.
It has a form of 4x5 matrix and to apply multiple operations on Android use postConcat or preConcat method.

First lets desaturate image, make a black and white version of it. To do it, change all RGB channels to have the same value (R’=G’=B’). Just apply this matrix:

      R    G    B    A O
R' [0.21 0.72 0.07 0 0]
G' [0.21 0.72 0.07 0 0]
B' [0.21 0.72 0.07 0 0]
A' [0 0 0 1 0]

Take a look that to achieve more pleasant feeling I’m not applying an average values of source RGB (which will be 0.33) but I’m applying different weights based on luminance brightness of a color.

Second (optional) — play with contrast. You can find a contrast color matrix everywhere on the internet:

float contrast;
float scale = contrast + 1.0f;
float translate = (-0.5f * scale + 0.5f) * 255.0f;
R G B A O
R' [scale 0 0 0 translate]
G' [0 scale 0 0 translate]
B' [0 0 scale 0 translate]
A' [0 0 0 1 0 ]

Lets start with the last part of transformation. The color to be used instead of white will be called colorWhite, and the RGB channels will be called r1, g1, b1. Following the same pattern, the color which replaces black will be called colorBlack, and RGB channels accordingly r2, g2, b2.

To change black areas, change the offset value to r2, g2, b2. To change white areas, the output of matrix equation (R’, G’, B’) needs to be r1, g1, b1. At this point the image is in grayscale, the input values for all channels are equal. Input value of R=G=B. The calculation can be simplified to use only one input channel, and replace others with zeros. The final result will be to multiply the value of red channel by difference of colorWhite and colorBlack channels.

float r1r2 = (r1 - r2) / 255f;
float g1g2 = (g1 - g2) / 255f;
float b1b2 = (b1 - b2) / 255f;
R G B A O
R' [r1r2 0 0 0 r2]
G' [g1g2 0 0 0 g2]
B' [b1b2 0 0 0 b2]
A' [0 0 0 1 0 ]

Well, that’s it. Hope you will experiment with this, playing with color matrixes is always fun. Again, the whole source code can be found on GitHub.

Read next

If you want to know a little bit more about Material Design tips for developers read my next article.

Case Study. Master/Detail Pattern Revisited

.

--

--

Lucas Urbas

Android developer. UI/UX enthusiast. Nomadic lifestyle