VB.NET Draw независимое от устройства растровое изображение в picturebox

Я зашел в тупик со своей программой. У меня в памяти есть простой массив, состоящий из значений RGB растрового изображения DIB (без BITMAPFILEHEADER). Этот массив создается на C++, но я пытаюсь отобразить его в VB.NET. Я не хочу использовать GDI+, потому что мне нужна чистая скорость.

Это мой код (изображение в файле не имеет заголовка, ширина: 1920 и высота: 100,24 бит, общий размер 6220804):

Dim bData As Byte()
Dim br As BinaryReader = New BinaryReader(File.OpenRead("img1.bmp"))
bData = br.ReadBytes(br.BaseStream.Length) 'no headers just raw data


Dim g As Graphics = Me.CreateGraphics() 'System.Drawing.Graphics.FromImage(bmp) 'or PictureBox1.CreateGraphics()
Dim hdc As IntPtr = g.GetHdc()

Dim bmi As New BITMAPINFO
bmi.bmiheader = New BITMAPINFOHEADER

'Now we fill up the bmi (Bitmap information variable) with all the necessary data
bmi.bmiheader.biSize = 40 'Size, in bytes, of the header (always 40)
bmi.bmiheader.biPlanes = 1 'Number of planes (always one)
bmi.bmiheader.biBitCount = 24 'Bits per pixel (always 24 for image processing)
bmi.bmiheader.biCompression = 0 'Compression: none or RLE (always zero)
bmi.bmiheader.biWidth = 1920
bmi.bmiheader.biHeight = 100
bmi.bmiheader.biSizeImage = 6220804

Dim memHDC As IntPtr = CreateCompatibleDC(hdc)

StretchDIBits(memHDC, 0, 0, 1920, 100, 0, 0, 1920, 100, bData, bmi, 0, 13369376)   ' Copy RGB values on an intermediary HDC
BitBlt(hdc, 0, 0, 1920, 100, memHDC, 0, 0, 13369376)    'Print directly from the memHDC

Вот мои структуры:

<StructLayout(LayoutKind.Sequential)>
Structure RGBQUAD
    Public rgbBlue As Byte
    Public rgbGreen As Byte
    Public rgbRed As Byte
    Public rgbReserved As Byte
End Structure

<StructLayout(LayoutKind.Sequential)>
Private Class BITMAPINFOHEADER
    Public biSize As Int32
    Public biWidth As Int32
    Public biHeight As Int32
    Public biPlanes As Int16
    Public biBitCount As Int16
    Public biCompression As Int32
    Public biSizeImage As Int32
    Public biXPelsPerMeter As Int32
    Public biYPelsPerMeter As Int32
    Public biClrUsed As Int32
    Public biClrImportant As Int32
End Class

<StructLayout(LayoutKind.Sequential)>
Private Structure BITMAPINFO
    Dim bmiheader As BITMAPINFOHEADER
    Dim bmiColors As RGBQUAD
End Structure

Я протестировал почти все возможные комбинации переменных, HDC и графики. Ничего не работает! Где я терплю неудачу?

ПРИМЕЧАНИЕ: кажется, что StretchDIBits и BitBlt выполнены успешно.

Куда вы присваиваете данные bmp?

Brian M Stafford 04.04.2019 17:35

Я не использую bmp. Это juat для teata. Я пытался подключить к нему hdc, затем использовать битблт на этом hdc, а затем использовать bmp в picturebox1.

sergiu reznicencu 04.04.2019 17:50

Просто нет права на ошибку

sergiu reznicencu 04.04.2019 18:17

У вас есть много жестко закодированных свойств изображения (ширина, высота и т. д.). Вы уверены, что эти значения верны для массива данных? Вы также уверены, что массив байтов не начинается с заголовка DIB? Кажется странным, что вы извлекаете такие данные без какого-либо способа определить, что они представляют. Если вы уверены в данных, пробовали ли вы использовать метод типа Lockbits (или в худшем случае Bitmap.SetPixel) для записи данных в растровое изображение, чтобы определить, можете ли вы создать допустимое растровое изображение? Как только у вас будет работать известный метод, попробуйте StretchDIBits и BitBlt.

TnTinMn 04.04.2019 21:37

Это всего лишь тестовый сценарий. Позже я включу BITMAPINFOHEADER внутрь файла или массива. Я не хочу использовать SetPixel, потому что он очень медленный. Сейчас я повторно проверяю данные, чтобы убедиться, что они не повреждены. Также при создании этого массива я использовал положительное значение высоты в структуре. Я не знаю, влияет ли это на код vb.net.

sergiu reznicencu 04.04.2019 21:50

Но помимо массива логика моего кода верна? Это должно было сработать?

sergiu reznicencu 04.04.2019 21:51

И даже если массив был поврежден, разве этот код не должен был показывать хотя бы черный прямоугольник?

sergiu reznicencu 04.04.2019 22:13
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
7
369
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я нашел решение. Я думаю, проблема возникает из-за того, что CreateCompatibleDC создает сетку один пиксель за одним пикселем. Из-за этого ограничения я просто использовал StretchDIBits на HDC окна изображения:

Dim bData As Byte()
Dim br As BinaryReader = New BinaryReader(File.OpenRead("img1_arr.bmp"))
bData = br.ReadBytes(br.BaseStream.Length)

Dim g As Graphics = PictureBox1.CreateGraphics() 'or Me.CreateGraphics()
Dim dsthdc As IntPtr = g.GetHdc()

Dim bmi As New BITMAPINFO
bmi.bmiheader = New BITMAPINFOHEADER

'Now we fill up the bmi (Bitmap information variable) with all the necessary data
bmi.bmiheader.biSize = 40 'Size, in bytes, of the header (always 40)
bmi.bmiheader.biPlanes = 1 'Number of planes (always one)
bmi.bmiheader.biBitCount = 24 'Bits per pixel (always 24 for image processing)
bmi.bmiheader.biCompression = 0 'Compression: none or RLE (always zero)
bmi.bmiheader.biWidth = 1920
bmi.bmiheader.biHeight = 1080
bmi.bmiheader.biSizeImage = 6220804


StretchDIBits(dsthdc, 0, 0, 1920, 1080, 0, 0, 1920, 1080, bData, bmi, 0, SRCCOPY)

Конечно, в примере используются фиксированные значения только для целей тестирования. Он работает безупречно.

Вам просто нужен System.Runtime.InteropServices.GCHandle для выделения массива байтов: Dim gcHandle = GCHandle.Alloc(bData, GCHandleType.Pinned). Затем наведите указатель на scan0: Dim pointer = New IntPtr(CLng(gcHandle.AddrOfPinnedObject())). Теперь вы можете создать новый Bitmap, используя параметры, которые у вас есть: Dim bitmap = New Bitmap(1920, 100, 1920 * 4, PixelFormat.Format32bppArgb, pointer)). Конечно gcHandle.Free()после.

Jimi 05.04.2019 02:01

Я не хочу использовать GDI+. После того, как я нарисую на HDC, я планирую соединить несколько изображений вместе, а затем отобразить результат. Если я использую класс Bitmap, мне нужно работать на уровне GDI+, который для меня слишком медленный. Я мог бы также создать простой BITMAPFILEHEADER и просто использовать трюк с потоком памяти для создания растрового изображения. Но спасибо за информацию.

sergiu reznicencu 05.04.2019 14:31

В .Net методы GDI+ работают как BitBlt и StretchBlt. Если вам нужна скорость, вам нужна внешняя dll C++, которая выполняет все задачи. Или ДиректХ. Если вы не хотите использовать DIB в VB.Net, вы вернетесь к GDI+. Плюс необходимые преобразования.

Jimi 05.04.2019 14:36

Я попробовал сшивание с помощью GDI+: g.DrawImage. Это худшая функция, с которой я когда-либо сталкивался с точки зрения скорости.

sergiu reznicencu 05.04.2019 14:37

Это зависит от того, как вы его используете. Я видел много вредных привычек. SharpDX был бы хорошим выбором (ну, C#, но...).

Jimi 05.04.2019 14:40

Другие вопросы по теме