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!