Use steganography to hide one picture inside another in C#


The example Use steganography to hide messages in an image in C# hides message bits in the least-significant color bits of randomly selected pixels within an image. The idea is that small changes to the least significant bits of a color won’t be noticeable. For example, if a pixel’s red color component is 254 instead of 255, no one will notice.

In fact, you can make a whole lot more changes without seriously altering an image.

To understand why, note that the most significant bit in an 8-bit binary value contributes fully half of the total value. If you change that bit, you change the value by 128, half of the possible number of values 256.

The next most significant bit accounts for half of the value that you can create with the remaining 7 bits. Changing that bit alters the value by 64, half of the number of possible values with 7 bits 128.

Together the two most significant bits account for 3/4 of the total value.

If you continue this line of reasoning, the 3 most significant bits account for roughly 7/8 of the total, the 4 most significant bits account for 15/16 of the total, and so forth. Even if you take away the 4 least significant bits of a pixel’s 8 bits of red, green, and blue color information, the resulting color is pretty close to the original color. Instead of storing only 1 bit of information in pixels scattered around the image as in the previous example, you can store several bits in every red, green, and blue color value throughout the image.

This example does just that. It takes away the least significant pixels from one image and uses them to store the most significant pixels of a second hidden image. The hidden image’s values are stored in the result image’s least significant bits so they don’t add greatly to the resulting combined image.

For example, suppose you want to use 3 bits to hide one image inside another and consider the red component of a particular pixel. Suppose the visible image’s red component for that pixel in binary is 10110101 and the hidden image’s red component for that pixel is 01010011. To use 3 bits to hide the second value inside the first, we remove the 3 least significant bits of the first value and replace them with the most significant bits of the second value. In this example, 10110101 + 01010011 = 10110010.

To see that the change is small, note that the original pixel’s value was 10110101 = 181 and the final value is 10110010 = 178. We stored 3 bits from the hidden value but only changed the original value by a small amount.

To recover the hidden image, you extract the combined image’s 3 least significant bits and use them for the hidden image’s most significant bits. In this example, 10110010 gives the original image’s value as 10110000 and the hidden image’s value is 01000000. These values are slightly different from the original values, but they’re close enough to be useful.

The following code shows how the example program hides one image inside another.

// Hide bm_hidden inside bm_visible and return the result.
public static Bitmap HideImage(Bitmap bm_visible,
    Bitmap bm_hidden, int hidden_bits)
    int shift = (8 - hidden_bits);
    int visible_mask = 0xFF << hidden_bits;
    int hidden_mask = 0xFF >> shift;
    Bitmap bm_combined = new Bitmap(bm_visible.Width,
    for (int x = 0; x < bm_visible.Width; x++)
        for (int y = 0; y < bm_visible.Height; y++)
            Color clr_visible = bm_visible.GetPixel(x, y);
            Color clr_hidden = bm_hidden.GetPixel(x, y);
            int r = (clr_visible.R & visible_mask) +
                ((clr_hidden.R >> shift) & hidden_mask);
            int g = (clr_visible.G & visible_mask) +
                ((clr_hidden.G >> shift) & hidden_mask);
            int b = (clr_visible.B & visible_mask) +
                ((clr_hidden.B >> shift) & hidden_mask);
            bm_combined.SetPixel(x, y,
                Color.FromArgb(255, r, g, b));
    return bm_combined;

The code first makes bit masks to extract the bits from the visible and hidden images. It creates a new bitmap to store the result and then loops over the images’ pixels. For each pixel, the code gets the color component values for the visible and hidden pixels. It uses the masks to clear the unwanted bits from each value and then combines them, shifting the hidden value’s bits so they move into the least significant bit positions.

The following code shows how the program recovers an image hidden inside another image.

// Recover a hidden image.
public static Bitmap RecoverImage(Bitmap bm_combined,
    int hidden_bits)
    int shift = (8 - hidden_bits);
    int hidden_mask = 0xFF >> shift;
    Bitmap bm_hidden = new Bitmap(bm_combined.Width,
    for (int x = 0; x < bm_combined.Width; x++)
        for (int y = 0; y < bm_combined.Height; y++)
            Color clr_combined = bm_combined.GetPixel(x, y);
            int r = (clr_combined.R & hidden_mask) << shift;
            int g = (clr_combined.G & hidden_mask) << shift;
            int b = (clr_combined.B & hidden_mask) << shift;
            bm_hidden.SetPixel(x, y, Color.FromArgb(255, r, g, b));
    return bm_hidden;

This code loops over the combined image’s pixels. It pulls the least significant bits out of each pixel’s color components and shifts them so they become the most significant bits in the recovered image’s pixels.

The following code shows how the program uses these methods.

// Hide and then recover the image.
private void btnGo_Click(object sender, EventArgs e)
    Cursor = Cursors.WaitCursor;
    int num_bits = (int)nudHiddenBits.Value;

    // Hide the image.
    picCombined.Image = Stego.HideImage(

    // Recover the hidden image.
    picRecovered.Image = Stego.RecoverImage(
        (Bitmap)picCombined.Image, num_bits);
    Cursor = Cursors.Default;

This code gets the number of bits to shift from the user’s selection. It then calls the HideImage method to hide the image in the picHidden PictureBox inside the image displayed by the picVisible PictureBox. It then displays the result.

Next the code calls RecoverImage to extract the hidden image and displays the result.

If you look closely at the picture shown here, you’ll see that the combined image looks very much like the original image and the recovered hidden image looks very much like its original value. By using 4 bits, you get a pretty remarkable result. If you experiment with other numbers of bits such as 1 or 7, you’ll see lots of degradation in one image or the other.

This method works well for the photographs used here. It might not work as well for large geometric shapes of constant colors. For example, if you hid a series of vertical stripes inside an image containing a large rectangle, you might see the stripes showing through.

Download Example   Follow me on Twitter   RSS feed   Donate

This entry was posted in algorithms, cryptography, graphics, image processing, mathematics and tagged , , , , , , , , , , , , , , , , , , . Bookmark the permalink.

22 Responses to Use steganography to hide one picture inside another in C#

  1. Hi,

    I implemented this algorithm in Python, in my version both images have the same sizes and the data of hidden image is stored on only two lowest bits.

    The result (=quality) is a bit worse, it can be checked below, the source code in Python is also available:


  2. Sinan Basalan says:

    This is a good article, I’ll try this. Thankyou.
    I want to ask you that whether you have an article for applying an image and text in a cell together in DataGridView?

  3. Pingback: Use steganography to hide one large picture inside anotherC# Helper

  4. harzyne says:

    Hi Sir, I tried this example and it has done a marvelous contribution to my project.
    But when i try to modify this as saving the combined image to disk and then tried to open it in a seperate window and did the extraction.
    The result was not the same as what i gained in picRecovered pictureBox. Rather i get a noisy image as extracted one.
    Please suggest some ideas to overcome.

    • RodStephens says:

      Be sure you save the image in a loss-less form such as a BMP or PNG. If you save it as a JPG, the pixel values get modified to save space and even a tiny change in the pixels can completely destroy the steganography. This example shows how to save in different formats including PNG:

      • harzyne says:

        Yeah, Thank you !
        By the way is this algorithm is specifically known with a name?

        • RodStephens says:

          I don’t know of a name for it. I sort of thought it up based on ideas that were out there, but I haven’t seen the code before.

          If you want to refer to it, for example in documentation or code, I suggest you include this page’s URL so you can find it again later if you need to look at the details.

          • harzyne says:

            Thank you 🙂
            And one more clarification please,
            Can u help with some code for rather applying the whole image as watermark; i prefer if i could scramble the watermark pixels and embed into the cover image. Hence in image authentication, i need to tell by extracting that scrambled signature is found in particular suspicious tampered image and authenticate my work.
            I would be much obliged if you guide me through this 🙂

  5. Aman Saxena says:

    Sir, i have to hide more than one image behind the cover image so please suggest me something…………………….

    • RodStephens says:

      You have two options. First, you can place the hidden images in different areas inside the main image. Or equivalently you could combine small hidden images into one larger image and then hide that.

      Second, you could use only some of the bits for each image. For example, you could use the high 4 bits for the main image, the next 2 bits for one hidden image, and 2 more bits for another hidden image. You would only have two bits for each of the hidden images so the results won’t be as good, but there’s only so much information you can hide behind a single main image before it’s obvious that the main image is distorted.

      (Actually multiple hidden images will probably be less noticeable because they will tend to randomize each others’ data. As long as you don’t give them too many of the image’s bits.)

  6. Aman Saxena says:

    Thank you sir i’ll be waiting

  7. Pingback: Use steganography to hide multiple images in C# - C# HelperC# Helper

  8. trvs says:

    when i go to the combined image and use a save as image. and use that image and upload to web program some the colour changes

    • RodStephens says:

      You should check the image before you upload it. My guess is it’s probably okay at that point and your web server or upload process is compressing the image. That will change some colors slightly and ruin the data you need for the steganography to work.

      Try using bmp or png files. They shouldn’t change the colors the way a gif or jpg usually will.

  9. fifi says:

    Hi sur ,help me
    I have projection about vide image un image using techniques LSB with language c#and visual studio
    Plz help me

  10. niza says:

    Hi Sir, first of all I’m sorry for out of your topic. do you know what technique/method used by the following encryption image codes?

    for (int i = 0; i < simple.Height; i++)
        for (int j = 0; j < simple.Width; j++)
            pixelMsgImage = secretGreyScale.GetPixel(j, i);
            MsgBits = getBits((byte)pixelMsgImage.R);
            pixelContainerImage = simple.GetPixel(j, i);
            AlphaBits = getBits((byte)pixelContainerImage.A);
            RedBits = getBits((byte)pixelContainerImage.R);
            GreenBits = getBits((byte)pixelContainerImage.G);
            BlueBits = getBits((byte)pixelContainerImage.B);
            AlphaBits[6] = MsgBits[0];
            AlphaBits[7] = MsgBits[1];
            RedBits[6] = MsgBits[2];
            RedBits[7] = MsgBits[3];
            GreenBits[6] = MsgBits[4];
            GreenBits[7] = MsgBits[5];
            BlueBits[6] = MsgBits[6];
            BlueBits[7] = MsgBits[7];
            newAlpha = getByte(AlphaBits);
            newRed = getByte(RedBits);
            newGreen = getByte(GreenBits);
            newBlue = getByte(BlueBits);
            pixelContainerImage = Color.FromArgb(newAlpha, newRed, newGreen, newBlue);
            simple.SetPixel(j, i, pixelContainerImage);
    • RodStephens says:

      It looks like the code is storing message bits in the two least significant bits of the image’s pixels. It’s a lot like the following example except it uses the image’s bits in order instead of in a random order.

      Use steganography to hide messages in an image in C#

      The advantage of the method shown in the linked post is that you cannot easily tell if there is data hidden in the image unless you know where to look for it. The advantage to the method you show is that it’s simpler and can potentially hold more data.

Leave a Reply

Your email address will not be published. Required fields are marked *