Beispiel #1
0
        /// <summary>
        /// Stenographically hide a file in an image.
        /// </summary>
        /// <param name="image">The image to hide stuff in.</param>
        /// <param name="file">The file to hide in the image.</param>
        /// <param name="quality">The number of bits per byte to encode data into. (1-8)</param>
        /// <exception cref="OutOfMemoryException"></exception>
        /// <example>
        ///  // Format the image for encoding
        ///  Image originalImage = Bitmap.FromFile("image.bmp");
        ///  Bitmap image = new Bitmap(originalImage.Width, originalImage.Height);
        ///  Graphics g = Graphics.FromImage(image);
        ///  g.DrawImage(originalImage, 0, 0, originalImage.Width, originalImage.Height);
        ///  TP_Stenography.EncodeImage(image, new TP_File("secret.txt", "password"), 1);
        ///  image.Save("output.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
        /// </example>
        static public void EncodeImage(Bitmap image, TP_File file, int quality)
        {
            // Prepare the image for direct access
            BitmapData bmData  = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            int        stride  = bmData.Stride;
            IntPtr     Scan0   = bmData.Scan0;
            int        nOffset = stride - image.Width * 3;

            int data;                   // Represents 3 bytes of input data

            byte[] bits = new byte[24]; // Represents 24 bits from the 3 bytes of input data

            byte r, g, b;               // Pixel color values (in RGB)
            int  xloc = 0;              // The X location of the working pixel in the image
            int  yloc = 0;              // The Y location of the working pixel in the image
            int  bit  = 0;              // The bit location we are encoding data into
            byte mask = 0x01;           // The bit mask for where we are encoding data into

            // Make sure the file to encode into the image is padded to groups of 3 bytes
            file.PadFileBytes();

            // Make sure the image is large enough to hold the data file
            if (GetImageCapacity(image) * quality < file.Contents.Length)
            {
                throw new FileTooLargeForImageException();
            }

            unsafe // :)
            {
                // The pointer to the Bitmap pixel data of the image
                byte *p = (byte *)(void *)Scan0;

                for (int i = 0; i < file.Contents.Length; i += 3)
                {
                    // Read in 3 bytes of data from the file to be hidden as an int
                    data  = file.Contents[i] << 16;
                    data |= file.Contents[i + 1] << 8;
                    data |= file.Contents[i + 2];

                    // Isolate 24 bits (from the 3 bytes) into an array
                    for (int j = 0; j < 24; j++)
                    {
                        bits[j] = (byte)((data >> (24 - j - 1)) & 1);
                    }

                    // Loop through the pixels and change the color's low order bit to a data bit
                    for (int location = 0; location < 8 * 3; location += 3)
                    {
                        // Get the RGB parts of the next pixel (It's actually stored as BGR, thus the indices)
                        r = p[2];
                        g = p[1];
                        b = p[0];

                        // Clear bit we are going to write to
                        r &= (byte)(0xFF - mask);
                        g &= (byte)(0xFF - mask);
                        b &= (byte)(0xFF - mask);

                        // Set bits to a piece of data
                        r |= (byte)(bits[location] << bit);
                        g |= (byte)(bits[location + 1] << bit);
                        b |= (byte)(bits[location + 2] << bit);

                        // Save the pixel back to the image
                        p[2] = r;
                        p[1] = g;
                        p[0] = b;

                        // Increment the location of the pixels we are writing to (3 bytes)
                        p += 3;

                        // If we reach the end of a row, adjust the pointer further
                        xloc++;
                        if (xloc >= image.Width)
                        {
                            p   += nOffset;
                            xloc = 0;

                            yloc++;
                            if (yloc >= image.Height)
                            {
                                // Start at the beginning of the image again
                                p    = (byte *)(void *)Scan0;
                                xloc = 0;
                                yloc = 0;

                                // Use the next up bit in each pixel
                                bit++;
                                mask *= 2;
                            }
                        }
                    }
                }
            }

            image.UnlockBits(bmData);

            return;
        }
        /// <summary>
        /// Stenographically hide a file in an image.
        /// </summary>
        /// <param name="image">The image to hide stuff in.</param>
        /// <param name="file">The file to hide in the image.</param>
        /// <param name="quality">The number of bits per byte to encode data into. (1-8)</param>
        /// <exception cref="OutOfMemoryException"></exception>
        /// <example>
        ///  // Format the image for encoding
        ///  Image originalImage = Bitmap.FromFile("image.bmp");
        ///  Bitmap image = new Bitmap(originalImage.Width, originalImage.Height);
        ///  Graphics g = Graphics.FromImage(image);
        ///  g.DrawImage(originalImage, 0, 0, originalImage.Width, originalImage.Height);
        ///  TP_Stenography.EncodeImage(image, new TP_File("secret.txt", "password"), 1);
        ///  image.Save("output.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
        /// </example>
        public static void EncodeImage(Bitmap image, TP_File file, int quality)
        {
            // Prepare the image for direct access
            BitmapData bmData = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            int stride = bmData.Stride;
            IntPtr Scan0 = bmData.Scan0;
            int nOffset = stride - image.Width * 3;

            int data;                   // Represents 3 bytes of input data
            byte[] bits = new byte[24]; // Represents 24 bits from the 3 bytes of input data

            byte r, g, b;               // Pixel color values (in RGB)
            int xloc = 0;               // The X location of the working pixel in the image
            int yloc = 0;               // The Y location of the working pixel in the image
            int bit = 0;                // The bit location we are encoding data into
            byte mask = 0x01;           // The bit mask for where we are encoding data into

            // Make sure the file to encode into the image is padded to groups of 3 bytes
            file.PadFileBytes();

            // Make sure the image is large enough to hold the data file
            if (GetImageCapacity(image) * quality < file.Contents.Length)
                throw new FileTooLargeForImageException();

            unsafe // :)
            {
                // The pointer to the Bitmap pixel data of the image
                byte* p = (byte*)(void*)Scan0;

                for (int i = 0; i < file.Contents.Length; i += 3)
                {
                    // Read in 3 bytes of data from the file to be hidden as an int
                    data = file.Contents[i] << 16;
                    data |= file.Contents[i + 1] << 8;
                    data |= file.Contents[i + 2];

                    // Isolate 24 bits (from the 3 bytes) into an array
                    for (int j = 0; j < 24; j++)
                        bits[j] = (byte)((data >> (24 - j - 1)) & 1);

                    // Loop through the pixels and change the color's low order bit to a data bit
                    for (int location = 0; location < 8 * 3; location+=3)
                    {
                        // Get the RGB parts of the next pixel (It's actually stored as BGR, thus the indices)
                        r = p[2];
                        g = p[1];
                        b = p[0];

                        // Clear bit we are going to write to
                        r &= (byte)(0xFF - mask);
                        g &= (byte)(0xFF - mask);
                        b &= (byte)(0xFF - mask);

                        // Set bits to a piece of data
                        r |= (byte)(bits[location] << bit);
                        g |= (byte)(bits[location + 1] << bit);
                        b |= (byte)(bits[location + 2] << bit);

                        // Save the pixel back to the image
                        p[2] = r;
                        p[1] = g;
                        p[0] = b;

                        // Increment the location of the pixels we are writing to (3 bytes)
                        p += 3;

                        // If we reach the end of a row, adjust the pointer further
                        xloc++;
                        if (xloc >= image.Width)
                        {
                            p += nOffset;
                            xloc = 0;

                            yloc++;
                            if (yloc >= image.Height)
                            {
                                // Start at the beginning of the image again
                                p = (byte*)(void*)Scan0;
                                xloc = 0;
                                yloc = 0;

                                // Use the next up bit in each pixel
                                bit++;
                                mask *= 2;
                            }
                        }
                    }
                }
            }

            image.UnlockBits(bmData);

            return;
        }