1(818)262-8552
Or Email
contact@invertedsoftware.com

Embedding data in images


By Gal Ratner, with pointers from Nick Wilson

Disclaimer: The purpose of this article is to explore the .NET framework. It is not my intention to encourage any actions that may be considered illegal.

Embedding data in images in most cases is a part of the image format; it is a very effective way to save copyrights, watermarks, metadata, company information and anything else you may want to pass on.
In this article we will explore two different ways of saving information in images.
This article also includes a small .NET windows application available to download and test for free.
See the link at the bottom of this page.

Let's start by introducing a few quick concepts:
Image header - This is a small metadata structure which holds data such as image creator name or company information. This structure is then compressed into an array of bytes and embedded into the image
Color - Every color is composed from the three base colors Red, Blue and Green. By mixing them, we create all of the known colors. We mix them in a range of 0-255 so for example 0,0,0 will be the color black and 255,255,255 will be the color white.
Pixel - The basic unit of color which composes an image. If we look closely at our computer monitor, we can see the dots that are composing the image. Each dot is a pixel and its size depends on your monitor.
Pixel Format - The number of bits in memory used to hold one pixel. For example: Format32bppRgb specifies 32 bits per pixel; 8 bits each are used for the red, green, and blue components.
The remaining 8 bits are not used and can be used for anything else.

Embedding data in image headers

We will be working with the namespace System.Drawing and System.Drawing.Imaging.
The first step will be to define and fill an System.Drawing.Image object. We will call it imageData.

ImageData = System.Drawing.Image.FromFile(pathToImage);

After we did that, we can move on and read all of its headers

PropertyItem[] propItems = imageData.PropertyItems;

foreach (PropertyItem propItem in propItems)
{
   Response.Write(propItem.Id + " " + propItem.Type);
}


Lets write some of our own data to the image:

We will pick a PropertyItem ID and enter a value into it. The value will be in bytes

byte[] dataToHold = Encoding.UTF8.GetBytes("Hi, This image has text");
PropertyItem propItem = imageData.PropertyItems[0];
propItem.Id = anIntegerWePick;
propItem.Type = 1; //Array of bytes
propItem.Len = dataToHold.Length;
propItem.Value = dataToHold;
imageData.SetPropertyItem(propItem);


Simple, isnt it?
Now we can email the picture to anyone and ask them to read the data in the header ID we picked.
The example encryptes the data using theRijndael Encryption algorithm.
When reading it, we will have to know how to decrypt it.

Embedding data in image pixels

Remember the definition of color from the top of this page? Let see how it is being composed:

Color.FromArgb(red (0-255), green (0-255), blue (0-255));

Since the three base colors are stored in bytes, we can use some color manipulation to replace one of the bytes, usualy the weekest one with our byte.
Even thow our byte will contain a number from 0-255, it wont be a color at all.
It will be a small part of the data we are loading into the image.

Color.FromArgb(255, (byte)ourData, 255);

Embedding in a pixel pattern

There are many algorithms to embed in a pattern; we are going to use a simple density one.
We are going to manipulate every 10th pixel.

byte[] dataArray = new System.Text.ASCIIEncoding().GetBytes(dataText);
LongOperationMax = imageData.Size.Height * imageData.Size.Width; // Total pixels in the image
LongOperationCurrent = 0;
int maxPixels = Convert.ToInt32(LongOperationMax / Utils.DATA_PIXEL_DENSITY); // Pixels we can use for data
int currentDataIndex = 0;
for (int x = 0; x < imageData.Width; x++)
{
   for (int y = 0; y < imageData.Height; y++)
   {
      // Embed new data
      if (LongOperationCurrent % 10 == 0 && currentDataIndex < dataArray.Length)
      {
         Color pixelColor = imageData.GetPixel(x, y);
         imageData.SetPixel(x, y, HideByteInPixel(dataArray[currentDataIndex], pixelColor));
         currentDataIndex++;
      }
      LongOperationCurrent++;
   }
}

public Color HideByteInPixel(byte dataToHide, Color pixelColor)
{
   // We are replacing green with our own "Green"
   return Color.FromArgb(pixelColor.R, Convert.ToInt32(dataToHide), pixelColor.B);
}


Finaly we are going to store the size of the data we just embedded in a random pixel in the image.

SetDataSizeInImage(currentDataIndex);

public void SetDataSizeInImage(int dataSize)
{
   if (dataSize <= 255)
   {
      imageData.SetPixel(3, 2, Color.FromArgb(dataSize, 0, 0));
   }
   else if (dataSize > 255 && dataSize <= 510)
   {
      imageData.SetPixel(3, 2, Color.FromArgb(255, dataSize - 255, 0));
   }
   else if (dataSize > 510 && dataSize <= 765)
   {
      imageData.SetPixel(3, 2, Color.FromArgb(255, 255, dataSize - 255));
   }
   else
   {
      imageData.SetPixel(3, 2, Color.FromArgb(255, 255, 255));
   }
}


This will allow us to read the correct amount of pixels when we read back our data

Reading back pixel data

We now have to open the image, go to the random pixel we used in order to know how much data we have to extract, Then we loop over the pixels and use the same density algorithm to read every 10th pixel.

int dataSize = imageData.GetPixel(3, 2).B + imageData.GetPixel(3, 2).G + imageData.GetPixel(3, 2).R;

for (int x = 0; x < imageData.Width; x++)
{
   for (int y = 0; y < imageData.Height; y++)
   {
      Color pixColor = imageData.GetPixel(x, y);
   if (LongOperationCurrent % 10 == 0 && currentDataIndex < hiddenData.Length)
   {
      hiddenData[currentDataIndex] = (byte)pixColor.G;// Get our "Green" back
      currentDataIndex++;
   }
   LongOperationCurrent++;
   }
}


In this article we have shown you two common ways to embed data in images. As you can tell, it is quick and easy and can help you whether you are coding any media authoring software or just want to have some fun with your friends by sending them hidden message.

About the authors

Mr. Gal Ratner graduated from the Technion Institute in Israel and has been writing software for over 10 years. He is the founder and CEO of Inverted Software located in southern California, which consults to large organizations.
Mr. Nick Wilson is the CTO of Break Media (Break.com), with 15 million unique visitors a month; it is the largest independent video site on the web.
He has an industry experience of over 20 years and his resume includes companies such as DMX Music (CTO) and Getty Images (CTO).

About the example

The example is a working open source program written for this article.

Image Spy is provided as is and with no warranty. Inverted Software and the writers / distributers of this software are not responsible directly or indirectly for any damages caused by direct or indirect use of this software.
Download and use at your own risk

You can download the source files from here.



Download ImageSpy's Windows Installer Package (MSI)




About Us | Contact Us | Standards of Business Conduct | Employment
© InvertedSoftware.com All rights reserved