Загрузка данных


using Microsoft.Win32;
using System;
using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace Steganography
{
    public partial class MainWindow : Window
    {
        private BitmapSource originalBitmap;
        private WriteableBitmap workingBitmap;

        public MainWindow()
        {
            InitializeComponent();
        }

        private static BitmapSource ConvertToBgra32(BitmapSource src)
        {
            if (src.Format == PixelFormats.Bgra32)
                return src;

            var formatted = new FormatConvertedBitmap(src, PixelFormats.Bgra32, null, 0);

            formatted.Freeze();

            return formatted;
        }

        public static void EncryptMessage(WriteableBitmap bmp, string message)
        {
            if (bmp == null)
                throw new ArgumentNullException(nameof(bmp));

            if (bmp.Format != PixelFormats.Bgra32)
                throw new ArgumentException("Bitmap должен быть в формате Bgra32.");

            byte[] msgBytes = Encoding.UTF8.GetBytes(message);

            int msgBits = msgBytes.Length * 8;
            int headerBits = 32;
            int totalBits = headerBits + msgBits;

            int pixelCount = bmp.PixelWidth * bmp.PixelHeight;

            if (totalBits > pixelCount)
                throw new InvalidOperationException(
                    $"Недостаточно места: требуется {totalBits} бит, доступно {pixelCount} бит.");

            int stride = bmp.BackBufferStride;

            int bytesCount = stride * bmp.PixelHeight;

            byte[] pixels = new byte[bytesCount];

            bmp.CopyPixels(pixels, stride, 0);

            int msgLengthBytes = msgBytes.Length;

            byte[] lenBytes = BitConverter.GetBytes(msgLengthBytes);

            bool[] bits = new bool[headerBits + msgBits];

            for (int i = 0; i < headerBits; i++)
            {
                int byteIndex = i / 8;
                int bitIndex = i % 8;

                bits[i] = ((lenBytes[byteIndex] >> bitIndex) & 1) == 1;
            }

            for (int i = 0; i < msgBytes.Length; i++)
            {
                for (int b = 0; b < 8; b++)
                {
                    bits[headerBits + i * 8 + b] =
                        ((msgBytes[i] >> b) & 1) == 1;
                }
            }

            for (int bitIndex = 0; bitIndex < bits.Length; bitIndex++)
            {
                int pixelIndex = bitIndex;

                int offset = pixelIndex * 4;

                int row = pixelIndex / bmp.PixelWidth;

                int col = pixelIndex % bmp.PixelWidth;

                offset = row * stride + col * 4;

                byte blue = pixels[offset];

                blue = (byte)((blue & 0xFE) | (bits[bitIndex] ? 1 : 0));

                pixels[offset] = blue;
            }

            var rect = new Int32Rect(0, 0, bmp.PixelWidth, bmp.PixelHeight);

            bmp.WritePixels(rect, pixels, stride, 0);
        }

        public static string DecryptMessage(WriteableBitmap bmp)
        {
            if (bmp == null)
                throw new ArgumentNullException(nameof(bmp));

            if (bmp.Format != PixelFormats.Bgra32)
                throw new ArgumentException("Bitmap должен быть в формате Bgra32.");

            int stride = bmp.BackBufferStride;

            int bytesCount = stride * bmp.PixelHeight;

            byte[] pixels = new byte[bytesCount];

            bmp.CopyPixels(pixels, stride, 0);

            int pixelCount = bmp.PixelWidth * bmp.PixelHeight;

            if (pixelCount < 32)
                throw new InvalidOperationException(
                    "Картинка слишком мала для хранения заголовка.");

            byte[] lenBytes = new byte[4];

            for (int i = 0; i < 32; i++)
            {
                int pixelIndex = i;

                int row = pixelIndex / bmp.PixelWidth;

                int col = pixelIndex % bmp.PixelWidth;

                int offset = row * stride + col * 4;

                byte blue = pixels[offset];

                int bit = blue & 1;

                int byteIndex = i / 8;

                int bitIndex = i % 8;

                lenBytes[byteIndex] |= (byte)(bit << bitIndex);
            }

            int msgLengthBytes = BitConverter.ToInt32(lenBytes, 0);

            if (msgLengthBytes < 0)
                throw new InvalidOperationException(
                    "Неверная длина сообщения (отрицательная).");

            int totalBitsNeeded = 32 + msgLengthBytes * 8;

            if (totalBitsNeeded > pixelCount)
                throw new InvalidOperationException(
                    $"Заявленная длина ({msgLengthBytes} байт) не помещается в изображении.");

            byte[] msgBytes = new byte[msgLengthBytes];

            for (int i = 0; i < msgLengthBytes * 8; i++)
            {
                int bitPos = 32 + i;

                int pixelIndex = bitPos;

                int row = pixelIndex / bmp.PixelWidth;

                int col = pixelIndex % bmp.PixelWidth;

                int offset = row * stride + col * 4;

                byte blue = pixels[offset];

                int bit = blue & 1;

                int byteIndex = i / 8;

                int bitIndex = i % 8;

                msgBytes[byteIndex] |= (byte)(bit << bitIndex);
            }

            string message = Encoding.UTF8.GetString(msgBytes);

            return message;
        }

        private void BtnLoad_Click(object sender, RoutedEventArgs e)
        {
            var dlg = new OpenFileDialog
            {
                Filter = "Images|*.png;*.bmp;*.jpg;*.jpeg|All files|*.*"
            };

            if (dlg.ShowDialog() == true)
            {
                var bmp = new BitmapImage(new Uri(dlg.FileName));

                originalBitmap = ConvertToBgra32(bmp);

                workingBitmap = new WriteableBitmap(originalBitmap);

                ImagePreview.Source = workingBitmap;

                BtnEncrypt.IsEnabled = true;
                BtnDecrypt.IsEnabled = true;
                BtnSave.IsEnabled = true;
            }
        }

        private void BtnSave_Click(object sender, RoutedEventArgs e)
        {
            if (workingBitmap == null)
                return;

            var dlg = new SaveFileDialog
            {
                Filter = "PNG Image|*.png"
            };

            if (dlg.ShowDialog() == true)
            {
                using (var fs = new FileStream(dlg.FileName, FileMode.Create))
                {
                    var encoder = new PngBitmapEncoder();

                    encoder.Frames.Add(BitmapFrame.Create(workingBitmap));

                    encoder.Save(fs);
                }
            }
        }

        private void BtnEncrypt_Click(object sender, RoutedEventArgs e)
        {
            if (workingBitmap == null)
                return;

            var message = TxtMessage.Text ?? "";

            if (string.IsNullOrWhiteSpace(message))
            {
                MessageBox.Show(
                    "Введите сообщение (слово).",
                    "Внимание",
                    MessageBoxButton.OK,
                    MessageBoxImage.Warning);

                return;
            }

            try
            {
                EncryptMessage(workingBitmap, message);

                ImagePreview.Source = workingBitmap;
            }
            catch (Exception ex)
            {
                MessageBox.Show(
                    "Ошибка при шифровании: " + ex.Message,
                    "Ошибка",
                    MessageBoxButton.OK,
                    MessageBoxImage.Error);
            }
        }

        private void BtnDecrypt_Click(object sender, RoutedEventArgs e)
        {
            if (workingBitmap == null)
                return;

            try
            {
                var msg = DecryptMessage(workingBitmap);

                MessageBox.Show(
                    $"Извлечённое сообщение:\n{msg}",
                    "Результат",
                    MessageBoxButton.OK,
                    MessageBoxImage.Information);
            }
            catch (Exception ex)
            {
                MessageBox.Show(
                    "Ошибка при дешифровке: " + ex.Message,
                    "Ошибка",
                    MessageBoxButton.OK,
                    MessageBoxImage.Error);
            }
        }
    }
}