Относительно вашего вопроса 4: ImageLockMode.UserInputBuffer
может дать вам контроль над процессом выделения того огромного объема памяти, на который можно ссылаться в объекте BitmapData
.
Если вы решите создать себе объект BitmapData
, вы можете избежать Marshall.Copy
. Затем вам придется использовать этот флаг в сочетании с другим ImageLockMode
.
Остерегайтесь, что это сложное дело, особенно в отношении Страйд
и PixelFormat.
Вот пример, в котором за один снимок получит содержимое буфера 24 ббит / с в BitMap, а затем за один снимок прочитает его обратно в другой буфер в 48 ббит / с.
Size size = Image.Size;
Bitmap bitmap = Image;
// myPrewrittenBuff is allocated just like myReadingBuffer below (skipped for space sake)
// But with two differences: the buff would be byte [] (not ushort[]) and the Stride == 3 * size.Width (not 6 * ...) because we build a 24bpp not 48bpp
BitmapData writerBuff= bm.LockBits(new Rectangle(0, 0, size.Width, size.Height), ImageLockMode.UserInputBuffer | ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb, myPrewrittenBuff);
// note here writerBuff and myPrewrittenBuff are the same reference
bitmap.UnlockBits(writerBuff);
// done. bitmap updated , no marshal needed to copy myPrewrittenBuff
// Now lets read back the bitmap into another format...
BitmapData myReadingBuffer = new BitmapData();
ushort[] buff = new ushort[(3 * size.Width) * size.Height]; // ;Marshal.AllocHGlobal() if you want
GCHandle handle= GCHandle.Alloc(buff, GCHandleType.Pinned);
myReadingBuffer.Scan0 = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0);
myReadingBuffer.Height = size.Height;
myReadingBuffer.Width = size.Width;
myReadingBuffer.PixelFormat = PixelFormat.Format48bppRgb;
myReadingBuffer.Stride = 6 * size.Width;
// now read into that buff
BitmapData result = bitmap.LockBits(new Rectangle(0, 0, size.Width, size.Height), ImageLockMode.UserInputBuffer | ImageLockMode.ReadOnly, PixelFormat.Format48bppRgb, myReadingBuffer);
if (object.ReferenceEquals(result, myReadingBuffer)) {
// Note: we pass here
// and buff is filled
}
bitmap.UnlockBits(result);
handle.Free();
// use buff at will...
Если вы используете ILSpy, вы увидите, что этот метод ссылается на GDI + , и эти методы помогают более полно.
Вы можете увеличить производительность, используя собственную схему памяти, но
остерегайтесь того, что Stride, возможно, должен иметь некоторое выравнивание, чтобы получить лучшее
производительность.
Затем вы сможете сойти с ума, например, выделив огромную виртуальную память, отображенную на scan0, и довольно эффективно их скопировать.
Обратите внимание, что закрепление огромного массива (и особенно нескольких) не будет обременительным для GC и позволит вам совершенно безопасно манипулировать байтом / шортом (или небезопасно, если вы стремитесь к скорости)