Image Attributes
After looking at the twelve image overloads which require ImageAttributes to work, it's only fitting to
see how ImageAttributes really work.
An ImageAttributes object basically only changes the colors seen in the picture. The shape or size of the
picture does not change. It may seem to be not very important, but just watch and see what the
ImageAttributes object can do.
I'll use this picture - hopefully it will bring out the changes that ImageAttributes makes to it.
First, don't forget to declare the ImageAttributes object and set it to a new instance:
Dim Ia As System.Drawing.Imaging.ImageAttributes = New Imaging.ImageAttributes
'Image Attributes object.
We're going to look at a few of the Setblahblah methods first.
.SetColorKey(CL, CH)
CL and CH are color structures.
First of all, what is a ColorKey? A ColorKey is a pair of colors that determine the transparency in a
picture or a drawing operation. This will allow a range of colors to become transparent. The range of
colors is defined by the two colors that are passed into the method. For example, you can remove all of
the pure greens in a picture (you know, Green Green
Green Green Green
Green Green Green,
R & B are both 0.) by setting the color key to be CL = Color.FromArgb(0, 0, 0), and CH =
Color.FromArgb(0, 255, 0).
The transparent areas show up to match the form's background color.
Notice that black is also removed. If you want to keep black, then you'd use Color.FromArgb(0, 1, 0).
System.Drawing.dll will throw a fit if your lowcolor in the color key is not absolutely lower than the
highcolor, so CL = Color.FromArgb(0, 255, 0) and CH = Color.FromArgb(0, 0, 255), if you wanted to get rid
of green through blue, will throw an error. Also, even something as slight as CL = Color.FromArgb(1, 0, 0)
and CH = Color.FromArgb(0, 255, 0) will throw an error.
On the situation with CL = Color.FromArgb(0, 255, 0) and CH = Color.FromArgb(0, 0, 255): if you wanted to
get rid of Greens/Blues, you'd do: CL = Color.FromArgb(0, 0, 0) and CH = Color.FromArgb(0, 255, 255).

This would mean that anything that contains a hint of red will be visible.
CL = Color.FromArgb(64, 64, 64) and CH = Color.FromArgb(192, 192, 192) gets rid of all colors that have
Red between 64 and 192, Green between 64 and 192, and Blue between 64 and 192... this would be all of the
grays in the picture vanishing.

The overload to this method takes a ColorAdjustType, but you won't see any effects unless you use .Bitmap
(since that's what we're doing - drawing a bitmap) or .Default (where the function determines thaat you
want .Bitmap). So, nothing of interest here. There are other functions and types which take
ImageAttributes objects.
Dim Ia As System.Drawing.Imaging.ImageAttributes = New Imaging.ImageAttributes
Ia.SetColorKey(Color.FromArgb(64, 64, 64), Color.FromArgb(192, 192, 192)) 'Low must actually be lower than High.
GFX.DrawImage(Bmp, New Rectangle(0, 0, 64, 64), 0, 0, 64, 64, GraphicsUnit.Pixel, Ia)
.SetGamma(Gamma)
Gamma is a single value which determines the amount of gamma 'radiation(?)' that the bitmap will go
through. A gamma of 1F causes the bitmap to be unchanged. Values of gamma greater than one cause the
picture to look more 'dead', as in the dark colors become darker. Just like more gamma radiation makes
people look more dead, more gamma makes pictures look more dead. 2.2F, the maximum in the
function's typical usage range, does turn a few of the colors into blackness.
Specifically, dark red, dark green, dark blue, gray, and dark gray have
all turned into black. If you have a keen eye, you'll see that light gray has turned to a dark grayish
color. A heavy gamma bombardment, such as 50F does little to this picture, but does a pretty horrific
operation to more photographic pictures, turning most of the colors to darkness.
On the flipside, setting gamma to a value less than 1F gives some life to the picture, turning all of the
dark colors into brighter colors.
You can see the orange is slightly brighter than in the original picture, along
with the other in-between colors (the green-yellow, red-violet, green-blue, light-blue, etc.). Of course,
setting gamma to 0F or less causes System.drawing.dll to get upset... possibly a deep-seated division by zero
error, but 0.1F practically maxes out all of the R, G, and B values in the pictures (dark red turned to red).
The second overload to SetGamma takes a ColorAdjustType as well, and the same things apply here as in
SetColorKey.
Dim Ia As System.Drawing.Imaging.ImageAttributes = New Imaging.ImageAttributes
Ia.SetGamma(0.1F) 'Gamma must be greater than 0.
'Greater than 1 zombifies the picture, and less than 1 aurafies the picture.
GFX.DrawImage(Bmp, New Rectangle(0, 0, 64, 64), 0, 0, 64, 64, GraphicsUnit.Pixel, Ia)
.SetOutputChannel(channel)
This sub has a choice of five flags to pick from as its argument. When you pass it a channel, the drawn
picture becomes like a color detector. If you pass Imaging.ColorChannelFlag.ColorChannelM, the picture
becomes like a infrared camera (in reverse), showing white for places where there is no Magenta, and black
in places where there is a lot of Magenta, and gray for medium Magenta levels.

The same applies for the other channels C, Y, and K. K is black. These are color printer channels, where
the colors are subtractive (Red + Green = Black, while Cyan + Magenta = Blue). Speaking of Cyan + Magenta,
you cannot do Imaging.ColorChannelFlag.ColorChannelC Or Imaging.ColorChannelFlag.ColorChannelM to check for
the Blue in the picture. (I'm not sure what they mean in the documentation when they say you can do this.)
Also, ColorChannelLast seems to always raise an error, so I'd avoid it.
Dim Ia As System.Drawing.Imaging.ImageAttributes = New Imaging.ImageAttributes
Ia.SetOutputChannel(Imaging.ColorChannelFlag.ColorChannelC) 'Works for C, M, Y, and K.
'Black represents high levels, White represents low level.
GFX.DrawImage(Bmp, New Rectangle(0, 0, 64, 64), 0, 0, 64, 64, GraphicsUnit.Pixel, Ia)
.SetThreshold(Threshold)
Threshold is a single. This is decently explained under the second overload though. What happens is that
the pixels that will be drawn first have their color channels examined. The amount of color in each
channel (the amount of Red, Green, and Blue) is divided by 255, and then compared against the Threshold...
if the final fraction is less than the threshold, the channel is pushed down to zero, and if the value is
greater than the threshold, the channel is bumped all the way up to 255. So, if the threshold was set to
0.5F, and we looked at the orange in the picture which is (255, 128, 0), the color channels are first
divided by 255 to give (1, 0.502, 0), and then each is compared to the threshold. R and G are both
greater than 0.5, the threshold, so they become 255, but B is less than 0.5, so it is set to 0. The
final result is (255, 255, 0), which is Yellow.
A threshold of 0.6F would turn this orange into Red, because 0.502 is less than 0.6.
Dim Ia As System.Drawing.Imaging.ImageAttributes = New Imaging.ImageAttributes
Ia.SetThreshold(0.5F) 'Also works for values lower than 0 or higher than 1,
'but the same thing happens as if it were on 0 or 1.
GFX.DrawImage(Bmp, New Rectangle(0, 0, 64, 64), 0, 0, 64, 64, GraphicsUnit.Pixel, Ia)
.SetRemapTable(Colormaps)
Colormaps is an array of Imaging.ColorMap objects. This method is also pretty straightforward.
A colormap object, after you set it to a new instance, contains two properties (and the rest are methods
inherited from Object): NewColor and OldColor. All occurences of OldColor in the drawing are replaced
with NewColor. This happens for all of the ColorMap objects that are in the array.
Colormaps = New Imaging.ColorMap() {New Imaging.ColorMap, New Imaging.ColorMap, New Imaging.ColorMap, New Imaging.ColorMap}
Colormaps(0).OldColor = Color.Red : Colormaps(0).NewColor = Color.Blue
Colormaps(1).OldColor = Color.Yellow : Colormaps(1).NewColor = Color.Red
Colormaps(2).OldColor = Color.Green : Colormaps(2).NewColor = Color.Blue
Colormaps(3).OldColor = Color.Blue : Colormaps(3).NewColor = Color.White
Notice in the above colormap array, the first ColorMap changes Red to Blue, and the last changes Blue to
White. This does not change Red to White, as you might expect (or maybe not at all). All of the colors
are mapped at the same time. Also, the colors that are in the colormap have to be exact:
(254, 0, 0) will not match with (255, 0, 0) at all, regardless of how many colors you are running in.
Dim Ia As System.Drawing.Imaging.ImageAttributes = New Imaging.ImageAttributes
Ia.SetRemapTable(Colormaps) 'Pass in a 1D array of ColorMap objects.
GFX.DrawImage(Bmp, New Rectangle(0, 0, 64, 64), 0, 0, 64, 64, GraphicsUnit.Pixel, Ia)
.SetNoOp()
If you didn't know already, you can combine as many of these different calls as you'd like. We can do a
SetRemapTable along with a SetThreshold and a SetOutputChannel... or maybe a SetGamma with a SetColorKey. In
any combination, these can be called. However, SetNoOp annuls all of these calls. So, if you SetColorKey,
SetRemapTable, and SetNoOp, then nothing happens to the picture. It also doesn't matter in which order
they are put in, either.
.SetColorMatrix(ColorMatrix)
ColorMatrix is an Imaging.ColorMatrix. At first, I thought this was going to be similar to the
Drawing2D.Matrix, where you can specify the operations, but you cannot set any of the values directly, but
the ColorMatrix is different. The .SetColorMatrix is explained beautifully on this page.

A picture to explain a little bit about matrix multiplication while you wait for the
page to load. 
Finished? So, of course, with the ColorMatrix, we can now make a picture translucent, something we
cannot do unless we went through the bitmap and, using SetPixel, set the Alpha channel of each pixel.
Transparifier = New Imaging.ColorMatrix(New Single()() { _
New Single() {1.0F, 0.0F, 0.0F, 0.0F, 0.0F}, _
New Single() {0.0F, 1.0F, 0.0F, 0.0F, 0.0F}, _
New Single() {0.0F, 0.0F, 1.0F, 0.0F, 0.0F}, _
New Single() {0.0F, 0.0F, 0.0F, 0.0F, 0.0F}, _
New Single() {0.0F, 0.0F, 0.0F, 0.4F, 1.0F}})
' [ 1 0 0 0 0 ]
' [ 0 1 0 0 0 ]
' [ 0 0 1 0 0 ]
' [ 0 0 0 0 0 ]
' [ 0 0 0 .4 1 ] = [ R , G, B, .4, 1 ] , where .4 corresponds to an alpha channel of A = 102.
This will make a picture translucent. The alpha channel seems to be inverted
before it is run through this matrix operation. Multiplying by 0.4 makes the picture less opaque instead
of less transparent. With the 1 in (3,3), you'd see no change in transparency, which means that alpha
was not 0 to begin with.

For more on color matrices, click here. Now, have fun with your ImageAttributes class.