Thursday, March 3, 2011

High Quality Dithering for Windows Phone 7

In my last post I showed how to use a 32bpp backbuffer to prevent banding in XNA games. But as it turns out, the WP7 hardware specifications only specify a 16-bit LCD at minimum - and that there are devices out there which only have a 16-bit LCD. (I've heard, but have not been able to confirm, that the Samsung devices suffer especially from this).

In that case, if a device only has an LCD capable of 16bpp, setting a 32bpp backbuffer isn't going to help. Instead, you need to dither your images, which will reduce the bit-depth to 16bpp but in a way which reduces visible banding.

I stumbled across this blog post "Photoshop Action for Windows Phone Dithering", which provides a photoshop script to dither images. It gets the job done, but I noticed that it produces a fairly low-quality dither - the end result is very grainy to my eyes.

A while back when I worked on Metropolitan Melbourne, I wrote my own little tool to dither images because WM6.5 only supported 16-bit colour graphics and I couldn't find any other simple tools for high-quality dithering. My tool is called ReduceBitDepthCPP, and takes an input 24-bit/32-bit image in .png or .bmp format, and reduces it to 16-bit (R5G6B5) colour using the Floyd-Steinberg algorithm. The Floyd-Steinberg algorithm eliminates banding while minimising quantisation error. Here's a comparison picture:

As expected, the undithered gradient has extreme banding. The "Photoshop" image was produced by using the script mentioned earlier. If you look closely, the Photoshop image does get rid of banding but also introduces a lot of noise - which makes the image very grainy.

On the top right is the Floyd-Steinberg algorithm produced by my tool, ReduceBitDepthCPP. It also eliminates banding but does so in a way that doesn't introduce a lot of noise, and the end result looks very close to the original.

You can download ReduceBitDepthCPP below, with source as well. It's free for any use, and the source code is distributed under the MIT license.


ReduceBitDepthCPP is a command-line tool, which makes it easier to integrate into your build. To use it:
  1. Extract the files somewhere (eg. C:\Temp\ReduceBitDepth\)
  2. Open up a command prompt by pressing [win]+[r] and typing in "cmd"
  3. Navigate to the directory where you extracted the files
  4. Run ReduceBitDepthCPP.exe using the following syntax:
    ReduceBitDepthCPP.exe infile outfile

ReduceBitDepthCPP.exe C:\Temp\meow_orig.png C:\Temp\meow_dithered.png

If you found this useful, don't forget to follow me on Twitter, and check out some of the stuff on my website!

Happy coding!


Nina said...

Thanks a lot for sharing!

My issue with these methods of reducing the banding (yours and the "Photoshop Action for Windows Phone Dithering") is the dramatically increased file size - five or more times. This is a big problem for mobile applications because the performance and the smooth user experience are very important.

Do you have any idea or advice on how to reduce the file size of the produced image without a loss in the quality?

Haqwin said...

The problem on Samsung is even worse. I cant give you any snapshot but the only part that looks OK is actually the Photoshop dither.

The F-S dither is better but still show banding. The problems on Samsung is not only due to the 16-bit colors but also has to do with the PenTile matrix that the SuperAMOLED display uses (with extra sub pixel placements.