Article Purpose
The objective of this article is focussed on exploring the concept of applying Colour Shading to Bitmap images. The various Bitmap manipulation operations detailed in this article are all exclusively implemented by processing raw pixel data. No traditional GDI+ drawing operations are required in implementing Bitmap Colour Shading.
![]() |
![]() |
![]() |
![]() |
Sample source code
This article is accompanied by a sample source code Visual Studio project which is available for download here.
![]() |
![]() |
![]() |
![]() |
Using the sample Application
This article has been written from a practical implementation point of view. The concepts detailed throughout this article are all coupled with a corresponding source code implementation. A sample application has been provided with this article. The sample application has been implemented in the architecture of a Windows Forms application, of which a complete source code implementation has also been provided. The sample application facilitates implementing and testing the concepts surrounding Bitmap Colour Shading as discussed in this article.
![]() |
![]() |
![]() |
![]() |
In using the Bitmap Shading sample application users have the ability to select a source/input image from the local file system. The user interface facilitates implementing Bitmap Colour Shading through three trackbar controls, each associated with a colour component. The value range of each trackbar control is defined from 0 to 100 inclusive. A value of 100 equates to no change and a value of 0 equating to the most possible change.
![]() |
![]() |
![]() |
![]() |
Users are able to save to the local file system any modified Bitmap images by clicking the ‘Save Image’ button and providing a file path and file name.
The screenshot below illustrates the Bitmap Shading application in action:
![]() |
![]() |
![]() |
![]() |
The ColorShade Extension method
The ColorShade extension method forms the crux of this article. The ColorShade method has been defined as an extension method targeting the Bitmap class. It is within this method that all raw pixel manipulation occurs. In essence each pixel expressed by the specified Bitmap image will be extracted upon which calculations are performed updating the value of Alpha, Red, Green and Blue colour components.
![]() |
![]() |
![]() |
![]() |
The following code snippet details the implementation of the ColorShade extension method:
public static Bitmap ColorShade(this Bitmap sourceBitmap, float blueShade, float greenShade, float redShade) { BitmapData sourceData = sourceBitmap.LockBits(new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
byte[] pixelBuffer = new byte[sourceData.Stride * sourceData.Height];
Marshal.Copy(sourceData.Scan0, pixelBuffer, 0, pixelBuffer.Length);
sourceBitmap.UnlockBits(sourceData);
float blue = 0; float green = 0; float red = 0;
for (int k = 0; k + 4 < pixelBuffer.Length; k += 4) { blue = pixelBuffer[k] * blueShade; green = pixelBuffer[k + 1] * greenShade; red = pixelBuffer[k + 2] * redShade;
if (blue < 0) { blue = 0; }
if (green < 0) { green = 0; }
if (red < 0) { red = 0; }
pixelBuffer[k] = (byte)blue; pixelBuffer[k + 1] = (byte)green; pixelBuffer[k + 2] = (byte)red; }
Bitmap resultBitmap = new Bitmap(sourceBitmap.Width, sourceBitmap.Height);
BitmapData resultData = resultBitmap.LockBits(new Rectangle(0, 0, resultBitmap.Width, resultBitmap.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
Marshal.Copy(pixelBuffer, 0, resultData.Scan0, pixelBuffer.Length); resultBitmap.UnlockBits(resultData);
return resultBitmap; }
![]() |
![]() |
![]() |
![]() |
In order to manipulate pixel colour component values directly we first need to lock the source Bitmap into memory by invoking the Bitmap.LockBits method. Once the source Bitmap is locked into memory we can copy the underlying pixel buffer using the Marshal.Copy method.
![]() |
![]() |
![]() |
![]() |
The next step involves iterating through the byte buffer of colour components. Notice how each iteration modifies an entire pixel by iterating by 4. The formula being implemented can be expressed as:
R = R1 * RS
G = G1 * GS
B = B1 * BS
In the stated equation R1 G1 and B1 represents the original value of a colour component and RS GS and BS equates to the percentage of shading expressed by each colour component. Take note that in this scenario shading percentages are defined in terms of a fractional value. As an example 45% would result in a shading factor of 0.45.
![]() |
![]() |
![]() |
![]() |
Sample Images
The original image file used in this article was authored by Konstantin Lanzet and is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported license, and can be downloaded from Wikipedia.
The Original Image |
![]() |
Colour Shaded Images |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Related Articles
- C# How to: Image filtering by directly manipulating Pixel ARGB values
- C# How to: Image filtering implemented using a ColorMatrix
- C# How to: Blending Bitmap images using colour filters
- C# How to: Bitmap Colour Substitution implementing thresholds
- C# How to: Generating Icons from Images
- C# How to: Swapping Bitmap ARGB Colour Channels
- C# How to: Bitmap Pixel manipulation using LINQ Queries
- C# How to: Linq to Bitmaps – Partial Colour Inversion
- C# How to: Bitmap Colour Balance
- C# How to: Bi-tonal Bitmaps
- C# How to: Bitmap Colour Tint
- C# How to: Bitmap Colour Shading
- C# How to: Image Solarise
- C# How to: Image Contrast
- C# How to: Bitwise Bitmap Blending
41 Responses to “C# How to: Bitmap Colour Shading”