生成16位灰度BitmapData并保存到文件

我试图从随机数据中生成C#中的16位灰度位图。但是它在Marshal.Copy上崩溃了。

这是我的代码:

Bitmap b16bpp; private void GenerateDummy16bitImage() { b16bpp = new Bitmap(IMAGE_WIDTH, IMAGE_HEIGHT, System.Drawing.Imaging.PixelFormat.Format16bppGrayScale); var rect = new Rectangle(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT); var bitmapData = b16bpp.LockBits(rect, ImageLockMode.WriteOnly, b16bpp.PixelFormat); // Calculate the number of bytes required and allocate them. var numberOfBytes = bitmapData.Stride * IMAGE_HEIGHT * 2; var bitmapBytes = new short[numberOfBytes]; // Fill the bitmap bytes with random data. var random = new Random(); for (int x = 0; x < IMAGE_WIDTH; x++) { for (int y = 0; y < IMAGE_HEIGHT; y++) { var i = ((y * IMAGE_WIDTH) + x) * 2; // 16bpp // Generate the next random pixel color value. var value = (short)random.Next(5); bitmapBytes[i] = value; // BLUE bitmapBytes[i + 1] = value; // GREEN bitmapBytes[i + 2] = value; // RED // bitmapBytes[i + 3] = 0xFF; // ALPHA } } // Copy the randomized bits to the bitmap pointer. var ptr = bitmapData.Scan0; Marshal.Copy(bitmapBytes, 0, ptr, numberOfBytes);//crashes here // Unlock the bitmap, we're all done. b16bpp.UnlockBits(bitmapData); b16bpp.Save("random.bmp", ImageFormat.Bmp); Debug.WriteLine("saved"); } 

例外是:

mscorlib.dll中发生了未处理的“System.AccessViolationException”类型exception

这不是我的代码。我发现它与32位Bitmaps和修改有关。但我想我错过了一些东西,因为我对C#很新。

基本上,我需要的是将BitmapData包装成一个short数组。

我纠正了你的一些错误(大多是错误的大小)。 但它仍会在b16bpp.Save()上崩溃,因为GDI +不支持保存16位灰度图像 。

 Bitmap b16bpp; private void GenerateDummy16bitImage() { b16bpp = new Bitmap(IMAGE_WIDTH, IMAGE_HEIGHT, System.Drawing.Imaging.PixelFormat.Format16bppGrayScale); var rect = new Rectangle(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT); var bitmapData = b16bpp.LockBits(rect, ImageLockMode.WriteOnly, b16bpp.PixelFormat); // Calculate the number of bytes required and allocate them. var numberOfBytes = bitmapData.Stride * IMAGE_HEIGHT; var bitmapBytes = new short[IMAGE_WIDTH * IMAGE_HEIGHT]; // Fill the bitmap bytes with random data. var random = new Random(); for (int x = 0; x < IMAGE_WIDTH; x++) { for (int y = 0; y < IMAGE_HEIGHT; y++) { var i = ((y * IMAGE_WIDTH) + x); // 16bpp // Generate the next random pixel color value. var value = (short)random.Next(5); bitmapBytes[i] = value; // GRAY } } // Copy the randomized bits to the bitmap pointer. var ptr = bitmapData.Scan0; Marshal.Copy(bitmapBytes, 0, ptr, bitmapBytes.Length); // Unlock the bitmap, we're all done. b16bpp.UnlockBits(bitmapData); b16bpp.Save("random.bmp", ImageFormat.Bmp); Debug.WriteLine("saved"); } 

我的更改说明:

  • bitmapData.Stride已经是IMAGE_WIDTH * BytesPerPixel所以你不需要乘以2
  • 当你将bitmapBytes声明为short[]它必须具有图像的大小,以像素为单位而不是以字节为单位
  • 这意味着你也不需要将i乘以2
  • 因为你有一个灰度图像,它没有蓝色,绿色和红色通道,而是一个16位灰色通道
  • Marshal.Copy以“数组单位”取长度,而不是以字节为单位

总而言之,您尝试将数组8次复制到位图中。

这适用于System.Drawing.Imaging.PixelFormat.Format16bppGrayScale:

  private static void SaveBmp(Bitmap bmp, string path) { Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); BitmapData bitmapData = bmp.LockBits(rect, ImageLockMode.ReadOnly, bmp.PixelFormat); var pixelFormats = ConvertBmpPixelFormat(bmp.PixelFormat); BitmapSource source = BitmapSource.Create(bmp.Width, bmp.Height, bmp.HorizontalResolution, bmp.VerticalResolution, pixelFormats, null, bitmapData.Scan0, bitmapData.Stride * bmp.Height, bitmapData.Stride); bmp.UnlockBits(bitmapData); FileStream stream = new FileStream(path, FileMode.Create); TiffBitmapEncoder encoder = new TiffBitmapEncoder(); encoder.Compression = TiffCompressOption.Zip; encoder.Frames.Add(BitmapFrame.Create(source)); encoder.Save(stream); stream.Close(); } private static System.Windows.Media.PixelFormat ConvertBmpPixelFormat(System.Drawing.Imaging.PixelFormat pixelformat) { System.Windows.Media.PixelFormat pixelFormats = System.Windows.Media.PixelFormats.Default; switch (pixelformat) { case System.Drawing.Imaging.PixelFormat.Format32bppArgb: pixelFormats = PixelFormats.Bgr32; break; case System.Drawing.Imaging.PixelFormat.Format8bppIndexed: pixelFormats = PixelFormats.Gray8; break; case System.Drawing.Imaging.PixelFormat.Format16bppGrayScale: pixelFormats = PixelFormats.Gray16; break; } return pixelFormats; }