I'm working on a UI for an app, and I'm attempting to use grayscale icons, and allow the user to change the theme to a color of their choosing. To do this, I'm trying to just apply a ColorFilter of some sort to overlay a color on top of the drawable. I've tried using PorterDuff.Mode.MULTIPLY, and it works almost exactly as I need, except that whites get overlayed with the color as well. What I'm ideally looking for is something like the "Color" blending mode in Photoshop, where the graphic retains its transparency and luminosity, and only modifies the color of the image. For example:
becomes
After doing some research, it appears that the ColorMatrixColorFilter class may do what I need, but I can't seem to find any resources pointing to how the matrix is used. It's a 4x5 matrix, but what I need to know is how I go about designing the matrix. Any ideas?
EDIT: So okay, what I've found so far on this is as follows:
1 0 0 0 0 //red
0 1 0 0 0 //green
0 0 1 0 0 //blue
0 0 0 1 0 //alpha
Where this matrix is the identity matrix (when applied, makes no changes), and the numbers range from 0 to 1 (floats). This matrix will be multiplied with each pixel to convert to the new color. So this is where it starts to get fuzzy for me. So I would think each pixel would be a 1 x 4 vector containing the argb values (e.g. 0.2, 0.5, 0.8, 1
) that would be dotted with the transformation matrix. So to double the red intensity of an image, you would use a matrix such as:
2 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
which would give you a vector (color) of 0.4, 0.5, 0.8, 1
. From limited testing, this seems to be the case, and works properly, but I actually still end up with the same problem (i.e. whites gain coloring). Further reading tells me that this is because it's doing the conversion on RGB values, whereas for hue shifting, the values should first be converted to HSL values. So possibly I could write a class that would read the image and convert the colors, and redraw the image with the new colors. This creates ANOTHER problem with StateListDrawables, as I'm not sure how I would go about getting each of these in code and modifying all of them, and how slow a process it would be. :/
Hmm, okay, so I suppose another question I would have is whether a matrix can be used to convert RGB to another color space with luminosity information, such as Lab or HSL? If so, I could just multiply the matrix for that converstion, then make the hue adjustment to THAT matrix, then apply that matrix as the ColorFilter.
Like the rest of the answers I used a color matrix to implement this behavior, but you can pass in a regular Android color resource. The matrix, maps the color into a range between the image value and white.
For anyone who is interested in how to use the ColorMatrixColorFilter. The sample I used here, converted every pixel into red when I draw the bitmap on the canvas.
The comment in the class is from: http://developer.android.com/reference/android/graphics/ColorMatrix.html this gives you some insights on how this is working
I think this method will give you what you want:
http://android.okhelp.cz/hue-color-colored-filter-bitmap-image-android-example/
The below class is an improvement on the answers that have already been posted. This makes it easier to read and create a
ColorFilter
from aBitmap
.Example usage:
This is what I use for my game. This is the compilation of various part found on various articles on websites. Credits goes to the original author from the @see links. Note that a lot more can be done with color matrices. Including inverting, etc...
To complete this I should add an example:
here is the complete code if you want to adjust the bright, contrast, saturation and hue. Enjoy! Thanks a lot to @RichardLalancette