Steps we are going to take are the following. We are going to take an image that we want to store in our database. Then the image will be converted into an array of bytes. Now here's the most important step. Before storing it into database, we are going to compute a hash code/digest using a cryptographic hash function already built into .NET (this ensures us that no image will give the same hash code when encrypted with this sort of algorithm). Same principal is also used for storing passwords in database since it is "impossible" to decode this hash digest. When the hash code is computed, we are going to compare it to hash codes stored in database. If we find that this hash code already exists in our database we know this same image has been also previously stored in database.
As database provider I used PostgreSQL database, but you can use any other. In my database I created a table named "images" with three columns as follows:
ID [bigserial NOT NULL]
HASH [character varying(255)]
IMAGE [bytea] //data type that can store an array of bytes
First, create a Windows Forms Application and add a button named btnSaveImage. Navigate to your form's code designer and before the Form's constructor add these global variables:
private NpgsqlConnection conn = null; //PostgreSQL connection object private ImageConverter converter = null; //Image converter object private SHA256Managed shaEncryptor = null; //Sha algorithm encryptor object
Do not forget to code using statement for System.Security.Cryptography at the top of Form1.cs file.
Then I created a private method InitCustomComponents which is used to initialize our globally declared variables. This method is called in form's constructor just after InitializeComponent method.
private void InitCustomComponents()
{
shaEncryptor = new SHA256Managed(); //initialize encryptor
converter = new ImageConverter(); //initialize image converter
conn = new NpgsqlConnection //initialize connection string
(@"Server=127.0.0.1;Port=5432;Database=imagesdb;User Id=YourUserId;Password=YourPassword;");
}
Then I created the InsertRecord method that accepts image's bytes array and a hash string argument.
private void InsertRecord(byte[] imgBytes, string hash)
{
NpgsqlCommand cmd = new NpgsqlCommand();
cmd.Connection = conn;
cmd.CommandText = "INSERT INTO images (image, hash) VALUES(@image, @hash)";
cmd.Parameters.Add("image", imgBytes);
cmd.Parameters.Add("hash", hash);
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
The next method we need is ComputeHashCode method that computes an array of bytes of image into a short hash string representation. Computed hash code is also an array of bytes, that's why I converted it into a string before returning this value to the caller.
private string ComputeHashCode(byte[] imgBytes)
{
//Compute hash bytes
byte[] hash = shaEncryptor.ComputeHash(imgBytes);
//Convert hash bytes to string representation
return Convert.ToBase64String(hash);
}
Another method we need is HashExists method. This method accepts a hash string argument and is used to query the database whether this has exists or not.
private bool HashExists(string hash)
{
NpgsqlCommand cmd = new NpgsqlCommand();
cmd.Connection = conn;
cmd.CommandText = "SELECT hash from images where hash = @hash";
cmd.Parameters.Add("hash", hash);
conn.Open();
//Execute scalar returns the first column of the first row in the result set
string hashString = (string)cmd.ExecuteScalar();
conn.Close();
return (hashString != null);
}
The last method is the button's click event that is used to trigger the comparing and saving process.
private void btnSaveImage_Click(object sender, EventArgs e)
{
//get some image from file system to store it in DB
Bitmap image = new Bitmap(@"C:\Temp\progress.gif");
//initialize byte array variable
byte[] imgBytes = new byte[0];
//convert image to byte array
imgBytes = (byte[])converter.ConvertTo(image, imgBytes.GetType());
//compute SHA hash string from image bytes
string hash = ComputeHashCode(imgBytes);
//if computed hash already exists in DB, do nothing
if (HashExists(hash)) return;
//Guess this has doesn't exist in DB - lets store this image to DB
InsertRecord(imgBytes, hash);
}
I added another function just to show you how to retrieve an image that was stored as binary data and convert it back to an image:
private void GetImage(int recordIdx)
{
NpgsqlCommand cmd = new NpgsqlCommand();
cmd.Connection = conn;
cmd.CommandText = "SELECT image FROM images WHERE id = @id";
cmd.Parameters.Add("id", recordIdx);
conn.Open();
byte[] imgBytes = (byte[])cmd.ExecuteScalar();
conn.Close();
Bitmap image = new Bitmap(new System.IO.MemoryStream(imgBytes));
pbMyPictureBox.Image = image;
}
The complete code looks like this:
using System;
using System.Drawing;
using System.Security.Cryptography;
using System.Windows.Forms;
using Npgsql;
namespace ImageHash
{
public partial class Form1 : Form
{
private NpgsqlConnection conn = null; //PostgreSQL connection object
private ImageConverter converter = null; //Image converter object
private SHA256Managed shaEncryptor = null; //Sha algorithm encryptor object
public Form1()
{
InitializeComponent();
InitCustomComponents();
}
private void InitCustomComponents()
{
shaEncryptor = new SHA256Managed(); //initialize encryptor
converter = new ImageConverter(); //initialize image converter
conn = new NpgsqlConnection //initialize connection string
(@"Server=127.0.0.1;Port=5432;Database=imagesdb;User Id=YourUserId;Password=YourPassword;");
}
private void btnSaveImage_Click(object sender, EventArgs e)
{
//get some image from file system to store it in DB
Bitmap image = new Bitmap(@"C:\Temp\progress.gif");
//initialize byte array variable
byte[] imgBytes = new byte[0];
//convert image to byte array
imgBytes = (byte[])converter.ConvertTo(image, imgBytes.GetType());
//compute SHA hash string from image bytes
string hash = ComputeHashCode(imgBytes);
//if computed hash already exists in DB, do nothing
if (HashExists(hash)) return;
//Guess this has doesn't exist in DB - lets store this image to DB
InsertRecord(imgBytes, hash);
}
private void InsertRecord(byte[] imgBytes, string hash)
{
NpgsqlCommand cmd = new NpgsqlCommand();
cmd.Connection = conn;
cmd.CommandText = "INSERT INTO images (image, hash) VALUES(@image, @hash)";
cmd.Parameters.Add("image", imgBytes);
cmd.Parameters.Add("hash", hash);
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
private string ComputeHashCode(byte[] imgBytes)
{
//Compute hash bytes
byte[] hash = shaEncryptor.ComputeHash(imgBytes);
//Convert hash bytes to string representation
return Convert.ToBase64String(hash);
}
private bool HashExists(string hash)
{
NpgsqlCommand cmd = new NpgsqlCommand();
cmd.Connection = conn;
cmd.CommandText = "SELECT hash from images where hash = @hash";
cmd.Parameters.Add("hash", hash);
conn.Open();
//Execute scalar returns the first column of the first row in the result set
string hashString = (string)cmd.ExecuteScalar();
conn.Close();
return (hashString != null);
}
private void GetImage(int recordIdx)
{
NpgsqlCommand cmd = new NpgsqlCommand();
cmd.Connection = conn;
cmd.CommandText = "SELECT image FROM images WHERE id = @id";
cmd.Parameters.Add("id", recordIdx);
conn.Open();
byte[] imgBytes = (byte[])cmd.ExecuteScalar();
conn.Close();
Bitmap image = new Bitmap(new System.IO.MemoryStream(imgBytes));
pbMyPictureBox.Image = image;
}
}
}
I hope you liked the tutorial, feel free to ask if anything unclear or if any additional information needed.




MultiQuote


|