Поворот изображения на 90 градусов в C#

    Эта публикация является продолжением более ранней публикации о преобразовании цветной картинки в чёрно-белую, в которой показан пример хитро-мудрого, но зато очень быстрого, преобразования изображения.
    Здесь я приведу функцию поворота изображения на 90 градусов, но не отображения pictureBox под определённым углом, а именно трансформации изображения при котором на входе имеем одно изображение а на выходе абсолютно другое идентичное первому — но повёрнутое на 90 градусов.
    В функции используется тот же принцип что и в предыдущей публикации (изменяем область памяти где содержится картинка). За счёт этого скорость работы этой функции довольно высокая.

Итак, пример функции:
//Трансформация изображения (поворотом на 90 градусов).
        public static Bitmap MakeTurn(Bitmap bmp)
        {
            //Создаём пустую картинку - с шириной как высота исходной
            //и высотой как ширина исходной
            Bitmap bmp90 = new Bitmap(bmp.Height,bmp.Width);
            // Задаём формат Пикселя.
            PixelFormat pxf = PixelFormat.Format24bppRgb;

            //Для удобства ширину и высоту вынес в переменные.
            int X = bmp.Width;
            int Y = bmp.Height;

            // Получаем данные картинки.
            Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
            //Аналогично поступаем с пустой картинкой.
            Rectangle rect1 = new Rectangle(0, 0, bmp90.Width, bmp90.Height);
            //Блокируем набор данных изображения в памяти (для обеих картинок)
            BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, pxf);
            BitmapData bmpData1 = bmp90.LockBits(rect1, ImageLockMode.ReadWrite, pxf);

            // Получаем адрес первой линии (для обеих картинок).
            IntPtr ptr = bmpData.Scan0;
            IntPtr ptr1 = bmpData1.Scan0;

            // Задаём массив из Byte и помещаем в него набор данных.
            // int numBytes = bmp.Width * bmp.Height * 3; 
            //На 3 умножаем - поскольку RGB цвет кодируется 3-мя байтами
            //Либо используем вместо Width - Stride
            int numBytes = bmpData.Stride * bmp.Height;
            int widthBytes = bmpData.Stride;
            byte[] rgbValues = new byte[numBytes];

            //Аналогично для пустой (пока пустой) картинки.
            int numBytes1 = bmpData1.Stride * bmp90.Height;
            int widthBytes1 = bmpData1.Stride;
            byte[] rgbValues1 = new byte[numBytes1];

            // Копируем значения в массив (для обеих картинок).
            Marshal.Copy(ptr, rgbValues, 0, numBytes);
            Marshal.Copy(ptr1, rgbValues1, 0, numBytes1);

            // Перебираем исходное изображение по линиям и перестраиваем его в пустое
            for (int counter = 0; counter < Y; counter += 1)
            {
                for (int counter1 = 0; counter1 < X; counter1 += 1)
                {
                    //Абсолютная позиция точки в иходнике.
                    int position = ((counter) * X + counter1) * 3;

                    //Абсолютная позиция точки в приёмнике.
                    int position1 = ((X - counter1 - 1) * Y + counter) * 3;


                    //Копируем 3 байта цвета точки.
                    rgbValues1[position1] = rgbValues[position];
                    rgbValues1[position1 + 1] = rgbValues[position+1];
                    rgbValues1[position1 + 2] = rgbValues[position+2];
                }
            }
            // Копируем набор данных обратно в изображения
            Marshal.Copy(rgbValues, 0, ptr, numBytes);
            Marshal.Copy(rgbValues1, 0, ptr1, numBytes1);

            // Разблокируем набор данных изображений в памяти.
            bmp.UnlockBits(bmpData);
            bmp90.UnlockBits(bmpData1);

            //Возвращаем готовую картинку.
            return bmp90;
        }

Разумеется для работы процедуры необходимо подключить:
System.Drawing.Imaging;
System.Runtime.InteropServices;

Вот и всё.
P.S. Для понимания, очень рекомендуется к ознакомлению предыдущая публикация на эту тему.

2 комментария

avatar
Здравствуйте! Подскажите пожалуйста, что именно обозначает строчка «int numBytes = bmpData.Stride * bmp.Height;»?
avatar
В данном случае получает размер массива байт исходного изображения.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.