Чтение и запись непосредственно в неуправляемую память Unlocked Bitmap (Scan0)
Можно ли писать и читать напрямую из неуправляемой памяти с разблокированным растровым изображением?
Могу ли я продолжать использовать BitmapData после разблокировки битов битовой карты? Я сделал тестовое приложение, в котором я могу прочитать пиксель растрового изображения PictureBox в позиции мыши, в то время как другой поток записывает пиксели в то же растровое изображение.
РЕДАКТИРОВАТЬ 1: КакBoing
указал в своем ответе: «Scan0 не указывает на фактические данные пикселей объекта Bitmap; скорее, он указывает на временный буфер, который представляет часть данных пикселей в объекте Bitmap». изMSDN.
Но как только я получу Scan0, я смогу читать / записывать на растровое изображение без необходимости использовать Lockbit или UnlockBits! Я делаю это много раз в потоке. В соответствии с MSDN, это не должно происходить, потому что Scan0 указывает на КОПИЮ битовых данных! Ну, в C # весь тест показывает, что это не копия. В C ++ я не знаю, работает ли он так, как должен.
РЕДАКТИРОВАТЬ 2: Использование метода поворота иногда приводит к тому, что ОС освобождает копию данных растрового изображения. Заключение,it is not safe to read/write an unlocked Bitmap Scan0
, Спасибо Boing за ваш ответ и комментарии!
Ниже описано, как получить BitmapData, прочитать и записать значение пикселя.
/// <summary>
/// Locks and unlocks the Bitmap to get the BitmapData.
/// </summary>
/// <param name="bmp">Bitmap</param>
/// <returns>BitmapData</returns>
public static BitmapData GetBitmapData(Bitmap bmp)
{
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);
bmp.UnlockBits(bmpData);
return bmpData;
}
/// <summary>
/// Get pixel directly from unamanged pixel data based on the Scan0 pointer.
/// </summary>
/// <param name="bmpData">BitmapData of the Bitmap to get the pixel</param>
/// <param name="p">Pixel position</param>
/// <param name="channel">Channel</param>
/// <returns>Pixel value</returns>
public static byte GetPixel(BitmapData bmpData, Point p, int channel)
{
if ((p.X > bmpData.Width - 1) || (p.Y > bmpData.Height - 1))
throw new ArgumentException("GetPixel Point p is outside image bounds!");
int bitsPerPixel = ((int)bmpData.PixelFormat >> 8) & 0xFF;
int bpp = bitsPerPixel / 8;
byte data;
int id = p.Y * bmpData.Stride + p.X * bpp;
unsafe
{
byte* pData = (byte*)bmpData.Scan0;
data = pData[id + channel];
}
return data;
}
//Non UI Thread
private void DrawtoBitmapLoop()
{
while (_drawBitmap)
{
_drawPoint = new Point(_drawPoint.X + 10, _drawPoint.Y + 10);
if (_drawPoint.X > _backImageData.Width - 20)
_drawPoint.X = 0;
if (_drawPoint.Y > _backImageData.Height - 20)
_drawPoint.Y = 0;
DrawToScan0(_backImageData, _drawPoint, 1);
Thread.Sleep(10);
}
}
private static void DrawToScan0(BitmapData bmpData, Point start, int channel = 0)
{
int x = start.X;
int y = start.Y;
int bitsPerPixel = ((int)bmpData.PixelFormat >> 8) & 0xFF;
int bpp = bitsPerPixel / 8;
for (int i = 0; i < 10; i++)
{
unsafe
{
byte* p = (byte*)bmpData.Scan0;
int id = bmpData.Stride * y + channel + (x + i) * bpp;
p[id] = 255;
}
}
}