[Nexus S Android Development] nightsky87:
This started out as an idea I had while trying to calibrate the screen color of my Nexus S using a colorimeter. While a lot of users are not particularly picky about colors, I do hope quite a number of people would also be interested in this. To give a clearer understanding for all, I'll put in a not-so-short introduction.

As most of us would know, AMOLED screens, while good in terms of brightness and contrast, tend to distort colors. If you're viewing an image on an AMOLED screen, you'll likely notice areas which appear oversaturated and have blown-out details. The reason behind this is that our AMOLED screens have a much wider gamut (i.e. displays more colors) than how images are encoded. If you look at the image below, the bigger triangle represents the set of colors that the AMOLED screen can display. The smaller triangle is the sRGB reference color which is how Android and most images are encoded.

​

Unfortunately for us, the Android OS isn't aware of this difference. A color with value of #00FF00 (pure green)

should

look like the green at the upper peak of the smaller triangle. But in reality, it is shown to us as the green of the larger triangle. This remapping between the two color spaces causes lighter shades of color to appear darker (or actually more saturated).

So far, the solution to fixing the problem is through the use of voodoo color (cheers to supercurio). Voodoo allows for the modification of gamma which somehow compensates for the saturation levels of the colors. Also, color multipliers allow for the shifting of the white point. White point, you ask? See, the intersection of the dotted lines? That is the white point which is how white would appear on the screen. Some like warm colors (white points to the right) while cool colors are to the left. However, gamma and multipliers only operate on a single color at a time. This means that the larger triangle will

always

remain the same shape regardless of the settings we use. Colors would look better but still not the same as the original intent.

So what can we do about it? Well one way would be by analyzing the way in which colors are mapped to a visually-oriented reference (such as the xyY/XYZ space shown in the above image). A standard sRGB image would be mapped using:

​

While the Nexus S (using the marmite kernel by bedalus with equal multipliers) would map out like:

​

In effect, you can find a map to convert the intended sRGB colors to the values usable by the screen to simulate the original rendering intent of the colors. This is done by using the following relationship:

​

Note that the other non-labelled matrix here is simply a way to shift the white point from 6500K (warm) to 9300K (cool) to display good colors on our devices using chromatic adaptation. The end effect is a means to fix color by simply mixing together red, green, and blue values (after gamma correction to be strictly accurate but this has its tolerances). The mix is just as shown above or in a more non-scientific notation:

R = 0.7043 * R + 0.3440 * B - 0.0028 * B
G = 0.0160 * R + 0.8930 * G + 0.0598 * B
B = 0.0195 * R + 0.0846 * G + 1.1185 * B

As an example, I've uploaded a before-and-after comparison of a test image. On a computer display, the right image (modified) would appear weird compared to the left image but if you load it up (or just view it) on your phone, you can see that the right one actually looks better (no oversaturation). This would be better if you have voodoo color with the multipliers set to more or less equal values.

​

The task then is to implement this on a kernel level (or similar) which I will touch on my next post (maybe tomorrow). Note that I have

not

successfully done the modifications as I lack the development skillz to match. :p In this regard, I would like to solicit the assitance of the dev community with a much wider experience with these things than I do. :D