# Playing with ColorMatrix

### WEBINAR:On-Demand

Application Security Testing: An Integral Part of DevOps

Environment: VC++ 7.0, XP

### Introduction

GDI+, the new Windows graphics API, comes with a ColorMatrix. It's a pity that ColorMatrix is just a simple struct, without any member functions. And it's also a pity that Microsoft's documentation is very, very sketchy. It's a pity, because you can do some really nice things with color matrices. Some of these things are near to impossible with other means. That's why I wrote an extension class, QColorMatrix, to open up the possibilities of color matrices in GDI+.

I also wrote a mini-application, Tinter, to demonstrate some of the things you can do. See the pictures at the end of this article for the effects you can apply to bitmap pictures. Tinter changes the coloring of JPG, GIF, BMP, and TIFF files interactively, can convert the types into one another, and prints. Pretty impressive for an EXE of just over 70 Kb, I think.

### What Is a Color Matrix?

Just as the co-ordinates x, y, and z define a single point in 3D space, the three color components R (red), G (green), and B (blue) define a single point in color space. In 3D geometrics (and in 2D geometrics as well), matrices can be used to transform the position of a point, and, more importantly, the position of a group of points. Change the matrix, apply the matrix to a group of points, and all the points are moved together. If you apply the matrix to all the points in a specific scene, the whole scene is transformed.

A color matrix works the same way in color space. With a color matrix, you can change one specific color, say dark blue into light red, but you can also change all colors together, in a co-ordinated way. Just like a scene in 3D space, you can scale, translate, rotate, and shear the color space, or apply any combination of these basic transformations to it.

For technical reasons, points in 3D space are transformed with 4x4 matrices. A color in RGB color space can also be transformed with a 4x4 matrix. But as GDI+ works with a fourth 'color', A (alpha, or opacity) throughout, ColorMatrix is defined as a 5x5 matrix of REALs:

`typedef struct { REAL m[5][5]; } ColorMatrix;`

#### QColorMatrix

Microsoft leaves it to us to fill in the 25 REALs of ColorMatrix, which is no easy task for even a simple rotation. My class, QColorMatrix, adds some useful member functions to put meaningful values in the matrix. You can scale, translate, rotate, and shear the color space in one step. There are also two member functions for more complex, but very useful operations: one to set the saturation of the color space, and one to rotate the hue, while preserving the luminance. Better than trying to describe what this all means, I'll let you have a look at the pictures (yes, that's me!).

#### Tinter

Tinter is a mini-application, demonstrating what you can do with QColorMatrix. It is even a small tool in its own right, for correcting bitmap pictures—or disforming, if you like. You can change the contrast, brightness, saturation, and hue. You can even change the gamma, although this has nothing to do with color matrices. I just threw it in for free.

Tinter is built in MFC 7.0. Of course, your system must support GDI+, which currently only XP does. However, Windows 98 and later versions can be upgraded.

### More Information

There is not much information on color matrices on the Web. I leant heavily on a rather dense, 1993 article by Paul Haeberli, published by Silicon Graphics. Also, the documentation of SGI's Color Matrix Extension for OpenGL may come in useful.

 Contrast Brightness Saturation Hue Gamma

### Download

Download demo project and source - 63 Kb

## Comments

• #### Matrices

Posted by didula on 10/18/2007 12:44pm

Hi, great interesting article. I have a few questions: Could you tell what matrices you are using for the hue rotation? Is it possible to multiply all of them to get one master matrix which can change the hue? It would be great to see more of the math behind this. I didnt find much about it at the links.

Reply
• #### Rotating Hues with this code

Posted by jimmygyuma on 05/21/2007 08:37pm

Using this code or any of its progeny, which are legion, to rotate hues in an image will give you bogus results. It seems to be doing what you want it to do, but the results are so inaccurate that it is only useful for effects. I translated this code, as well as a VB version, into C#, but my results were so far off I thought I had done something wrong. But, no. I got out Mr. Priester's demo and ran the same test, with the same results. I had an image consisting of red, green, blue, yellow, magenta, and cyan bands. I rotated it 120 degrees. Red should become green, green should become blue, blue red, and so forth. And they did, sort of. Red became a kind of forest green, green became sky blue, and blue became maroon, and so forth. It amazes me that this code has been propagated far and wide, with everyone singing its praises, when it gives these kind of results. It's not even remotely useful for any halfway serious work.

• #### Re: QColorMatrix

Posted by jimmygyuma on 07/15/2007 05:48pm

All well and good, but it is still inaccurate. You need to preserve both the luminance and the saturation. The only thing you want to change is the hue. I went back to LockBits, UnlockBits, so that I could convert each pixel to HSL, rotate the Hue, a simple addition, and convert the result back to RGB. The saturation and luminance are never changed. Of course you have to have accurate conversion routines. I have a class JColor, which I have been refining and translating since my Java days, to handle this. I use your saturation and brightness routines, which are fine for subjective work, but, I'm sorry, when I rotate pure yellow 120 degrees and get something other than pure cyan, it doesn't work for me.

Reply
• #### RE: Rotating Hues with this code

Posted by Sjaakp on 05/24/2007 08:41am

```QColorMatrix rotates hues while preserving the luminance. In other words: omly the color information is modified, not the black-and-white levels. If you would remove the color from an image (by setting the saturation to zero), rotating the hue has no effect.

Because the luminance of the brightest red on the computer screen (RGB 255, 0, 0) is way lower than the luminance of the brightest green (RGB 0, 255, 0), the brightest red does not translate into the brightest green, but into a darker green.

It all has to do with the 'luminance weights' which are assigned to the R, G, and B elements of the color (see the const's in the top part of QColorMatrix.cpp). If all three luminance weights were equal (1.0), the brightest red would translate to the brightest green after rotation. However, rotating the hue would also mean modifying the luminance.

See http://www.graficaobscura.com/matrix/ for some more information on hue rotation.

For what it's worth, the Photoshop hue control works similar to QColormatrix in this respect.```

Reply
Reply
• #### Superb ..............................

Posted by Legacy on 10/21/2003 12:00am

Originally posted by: Vishal G

Fantastic code given....................

Reply
• #### Fantastic !!!

Posted by Legacy on 09/12/2003 12:00am

Originally posted by: Oleg Salafonov

VC6 version really works, but I am still getting
the error: LNK2001: unresolved external symbol _GdiplusShutdown@8. I have to comment the line
"Gdiplus::GdiplusShutdown(m_Token);" in the QGdiPlus.
Can anybody help?

• #### I think you got the wrong typdef

Posted by AviadOffer on 05/18/2004 05:48pm

typedef unsigned __int64 ULONG_PTR; should be typedef unsigned __int32 ULONG_PTR;

Reply
Reply
• #### The best article i've read so far ....

Posted by Legacy on 08/23/2003 12:00am

Originally posted by: Vergil Cola

This has to be the best GDI+ article i've read so far.
Thanks. This has been a great help

Reply
• #### What is the best way to learn GDI+ ???

Posted by Legacy on 08/20/2003 12:00am

Originally posted by: SK

Same as Subject.

Reply
• #### Excellent job - the first GDI+ sample I have seen

Posted by Legacy on 08/12/2003 12:00am

Originally posted by: Ajay

That's excellent and works very well without flikering at all. Also the speed the image changes is also not noticeable. And it also allows saving the changed image!

Fine!!

Reply
• #### VC6 version, please

Posted by Legacy on 08/07/2003 12:00am

Originally posted by: kimchi

How can I compile the your sample?
I tried to compile on the VC6 with GDI+ Macro(http://www.codeproject.com/vcpp/gdiplus/vc6gdiplusmacro.asp?target=gdiplus%7Cmacro).
But I met following error:

C:\Program Files\Microsoft SDK\include\GdiplusEnums.h(28) : error C2146: syntax error : missing ';' before identifier 'GraphicsState'
C:\Program Files\Microsoft SDK\include\GdiplusEnums.h(28) : fatal error C1004: unexpected end of file found

Reply
• #### NIce!

Posted by Legacy on 08/01/2003 12:00am

Originally posted by: Andreas

Good Introduction and Demo!

Reply
• #### Good

Posted by Legacy on 07/31/2003 12:00am

Originally posted by: Jeff Zhang

push

Reply
• You must have javascript enabled in order to post comments.

Leave a Comment
• Your email address will not be published. All fields are required.

## Top White Papers and Webcasts

• As all sorts of data becomes available for storage, analysis and retrieval - so called 'Big Data' - there are potentially huge benefits, but equally huge challenges...
• The agile organization needs knowledge to act on, quickly and effectively. Though many organizations are clamouring for "Big Data", not nearly as many know what to do with it...
• Cloud-based integration solutions can be confusing. Adding to the confusion are the multiple ways IT departments can deliver such integration...

## Most Popular Programming Stories

• There have been no articles posted today.

## RSS Feeds

Copyright 2018 QuinStreet Inc. All Rights Reserved.

Thanks for your registration, follow us on our social networks to keep up-to-date
×
We have made updates to our Privacy Policy to reflect the implementation of the General Data Protection Regulation.