Introduction
I love photos. I love taking photos, even though I am by no means a professional or even an amateur. I love taking pictures spontaneously, especially about my wife and daughter. Funny thing is: I hate being in a photograph!
I also love PhotoShop with all its features to improve the quality of pictures. I love the effect of a black and white photo! This got me thinking, wouldn’t it be nice to make a small tool for my personal use, to make my pictures tinted or gray scaled. This is what we’ll do today. It is not too complicated, so we can take it easy ( for a change ).
Design
Our design is quite simple. All you will need on your form is the following objects:
- 6 Buttons
- Red
- Green
- Blue
- Choose A Color
- Gray
- Save
- 2 PictureBoxes
- Source PictureBox
- Destination PictureBox
- 1 SaveFileDialog
- 1 ColorDialog
You could name all the objects anything you like.
Coding
In all honesty, I was pleasantly surprised about the small amount of code that was needed in this project. I think it comes down to using the right tools for the job. In this case: the ColorMatrix object
As usual, let us start with the Namespaces:
VB.NET
Imports System.Drawing.Imaging ' Advanced Image Functionalities
Imports System.IO 'File Operations
C#
using System.Drawing.Imaging; //Advanced Image Functionalities
using System.IO; //File Operations
Add our Tint function:
VB.NET
Private Function Tint(ByVal bmpSource As Bitmap, ByVal clrScaleColor As Color, ByVal sngScaleDepth As Single) As Bitmap
Dim bmpTemp As New Bitmap(bmpSource.Width, bmpSource.Height) 'Create Temporary Bitmap To Work With
Dim iaImageProps As New ImageAttributes 'Contains information about how bitmap and metafile colors are manipulated during rendering.
Dim cmNewColors As ColorMatrix 'Defines a 5 x 5 matrix that contains the coordinates for the RGBAW space
cmNewColors = New ColorMatrix(New Single()() _
{New Single() {1, 0, 0, 0, 0}, _
New Single() {0, 1, 0, 0, 0}, _
New Single() {0, 0, 1, 0, 0}, _
New Single() {0, 0, 0, 1, 0}, _
New Single() {clrScaleColor.R / 255 * sngScaleDepth, clrScaleColor.G / 255 * sngScaleDepth, clrScaleColor.B / 255 * sngScaleDepth, 0, 1}})
iaImageProps.SetColorMatrix(cmNewColors) 'Apply Matrix
Dim grpGraphics As Graphics = Graphics.FromImage(bmpTemp) 'Create Graphics Object and Draw Bitmap Onto Graphics Object
grpGraphics.DrawImage(bmpSource, New Rectangle(0, 0, bmpSource.Width, bmpSource.Height), 0, 0, bmpSource.Width, bmpSource.Height, GraphicsUnit.Pixel, iaImageProps)
Return bmpTemp
End Function
C#
private Bitmap Tint(Bitmap bmpSource, Color clrScaleColor, float sngScaleDepth)
{
Bitmap bmpTemp = new Bitmap(bmpSource.Width, bmpSource.Height); //Create Temporary Bitmap To Work With
ImageAttributes iaImageProps = new ImageAttributes(); //Contains information about how bitmap and metafile colors are manipulated during rendering.
ColorMatrix cmNewColors = default(ColorMatrix); //Defines a 5 x 5 matrix that contains the coordinates for the RGBAW space
cmNewColors = new ColorMatrix(new float[][] {
new float[] {
1,
0,
0,
0,
0
},
new float[] {
0,
1,
0,
0,
0
},
new float[] {
0,
0,
1,
0,
0
},
new float[] {
0,
0,
0,
1,
0
},
new float[] {
clrScaleColor.R / 255 * sngScaleDepth,
clrScaleColor.G / 255 * sngScaleDepth,
clrScaleColor.B / 255 * sngScaleDepth,
0,
1
}
});
iaImageProps.SetColorMatrix(cmNewColors); //Apply Matrix
Graphics grpGraphics = Graphics.FromImage(bmpTemp); //Create Graphics Object and Draw Bitmap Onto Graphics Object
grpGraphics.DrawImage(bmpSource, new Rectangle(0, 0, bmpSource.Width, bmpSource.Height), 0, 0, bmpSource.Width, bmpSource.Height, GraphicsUnit.Pixel, iaImageProps);
return bmpTemp;
}
This function makes use of the ColorMatrix class to calculate how the colors in the picture should change. We get all the associated RGB ( Red, Green, Blue ) values from the picture, divide it by 255 ( there are only 256 shades of red or green or blue in the RGB Color model. Then, we multiply it with the depth that we want. Any value between .25 and .75 will give you the best results.
Create a Bitmap Variable and add the following line into your Form_Load event:
VB.NET
Dim bmpNewPic As Bitmap 'Source Bitmap
Private Sub frmTint_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
bmpNewPic = New Bitmap(picSource.Image) ' Source Picture To Work With
End Sub
C#
Bitmap bmpNewPic; //Source Bitmap
private void frmTint_Load(object sender, EventArgs e)
{
bmpNewPic = new Bitmap(picSource.Image); //Source Picture To Work With
}
This creates a bitmap object to apply the tint to.
Add the following for the Red, Green and Blue buttons:
VB.NET
Private Sub btnRed_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRed.Click
picDest.Image = Tint(bmpNewPic, Color.Red, 0.3) 'Red
End Sub
Private Sub btnGreen_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGreen.Click
picDest.Image = Tint(bmpNewPic, Color.Green, 0.3) 'Green
End Sub
Private Sub btnBlue_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnBlue.Click
picDest.Image = Tint(bmpNewPic, Color.Blue, 0.3) 'Blue
End Sub
C#
private void btnRed_Click(System.Object sender, System.EventArgs e)
{
picDest.Image = Tint(bmpNewPic, Color.Red, 0.3f); //Red
}
private void btnGreen_Click(System.Object sender, System.EventArgs e)
{
picDest.Image = Tint(bmpNewPic, Color.Green, 0.3f); //Green
}
private void btnBlue_Click(System.Object sender, System.EventArgs e)
{
picDest.Image = Tint(bmpNewPic, Color.Blue, 0.3f); //Blue
}
We call the Tint function for each of the associated colors.
Add the following code for the Choose Color button:
VB.NET
Private Sub btnChoose_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnChoose.Click
If cdTint.ShowDialog = DialogResult.OK Then 'Show Color Dialog
Dim clrSel As Color
clrSel = cdTint.Color 'Store Selected Color
picDest.Image = Tint(bmpNewPic, clrSel, 0.3) 'Apply Tint
End If
End Sub
C#
private void btnChoose_Click(object sender, EventArgs e)
{
DialogResult drColors = cdTint.ShowDialog(); //Show Color Dialog
if (drColors == DialogResult.OK)
{
Color clrSel = cdTint.Color; //Store Selected Color
picDest.Image = Tint(bmpNewPic, clrSel, 0.3f); //Apply Tint
}
}
Same logic, we just allow the user to select a tint color.
Add the following code for the Gray Scale button:
VB.NET
Private Sub btnGray_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGray.Click
Dim intX As Integer 'X Counter
Dim intY As Integer 'Y Counter
Dim clrOld As Integer 'Previous Color
For intX = 0 To bmpNewPic.Width - 1 'Loop Horizontally
For intY = 0 To bmpNewPic.Height - 1 'Loop Vertically
'Get Existing Color At Each Pixel Location and Divide By Scale Depth
'Any Range Between .25 and .75 Will Give optimal Results
clrOld = (CInt(bmpNewPic.GetPixel(intX, intY).R) + _
bmpNewPic.GetPixel(intX, intY).G + _
bmpNewPic.GetPixel(intX, intY).B) 3
bmpNewPic.SetPixel(intX, intY, Color.FromArgb(clrOld, clrOld, clrOld)) 'Apply Tint
Next intY
Next intX
picDest.Image = bmpNewPic 'Set New Picture
End Sub
C#
private void btnGray_Click(System.Object sender, System.EventArgs e)
{
int intX = 0; //X Counter
int intY = 0; //Y Counter
int clrOld = 0; //Previous Color
for (intX = 0; intX <= bmpNewPic.Width - 1; intX++) //Loop Horizontally
{
for (intY = 0; intY <= bmpNewPic.Height - 1; intY++) //Loop Vertically
{
//Get Existing Color At Each Pixel Location and Divide By Scale Depth
//Any Range Between .25 and .75 Will Give optimal Results
clrOld = (Convert.ToInt32(bmpNewPic.GetPixel(intX, intY).R) + bmpNewPic.GetPixel(intX, intY).G + bmpNewPic.GetPixel(intX, intY).B) / 3;
bmpNewPic.SetPixel(intX, intY, Color.FromArgb(clrOld, clrOld, clrOld)); //Apply Tint
}
}
picDest.Image = bmpNewPic; //Set New Picture
}
A more complicated way of tinting. We get each pixel’s color and replace it. This is more time consuming and processor intensive.
All that is left is to save our tinted picture:
VB.NET
Private Sub btnSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSave.Click
If sfdTint.ShowDialog = DialogResult.OK Then
picDest.Image.Save(sfdTint.FileName) 'Save
End If
End Sub
C#
private void btnSave_Click(object sender, EventArgs e)
{
DialogResult drSave = sfdTint.ShowDialog();
if(drSave == DialogResult.OK)
{
picDest.Image.Save(sfdTint.FileName); //Save
}
}
Conclusion
This wasn’t so complicated now, was it? I am attaching the working projects with this article. Thanks for reading! Until next time, cheers!