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.
Overly JPGed picture 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).
Black, Green and Dark Green are goneThe 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). No black, green, blue, cyan, dark blue, or dark green
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.
no gray
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.
Dark colors are blackSpecifically, 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.
All colors brighter, like on the detergent commercialsYou 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.
magenta scanner
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.
All or nothing
                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)
Darkgreen is blue, yellow is red, Oh dear, I need to rest my head

.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.
The cube is translucent
For more on color matrices, click here. Now, have fun with your ImageAttributes class.