AccessViolation when using LockBits

I would like to compare similar images faster using the LockBits method as follows

using System; using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; public class CompareImages { public static void Main ( String[] args ) { Bitmap bm1 = new Bitmap ( "PB270029.JPG" ); Console.WriteLine ( bm1.PixelFormat.ToString() ); int width = bm1.Width; int height = bm1.Height; Console.WriteLine ( "width = " + width + " height = " + height ); Rectangle rect1 = new Rectangle ( 0, 0, width, height ); BitmapData bm1Data = bm1.LockBits ( rect1, ImageLockMode.ReadOnly, bm1.PixelFormat ); Console.WriteLine ( "stride = " + bm1Data.Stride ); IntPtr bm1Ptr = bm1Data.Scan0; int bytes = Math.Abs(bm1Data.Stride) * height; Console.WriteLine ( "bytes = " + bytes ); byte[] rgbValues1 = new byte [ bytes ]; Marshal.Copy ( bm1Ptr, rgbValues1, 0, bytes ); Console.WriteLine ( "After 1st Marshal.Copy ..." ); Bitmap bm2 = new Bitmap ( "PA050164.JPG" ); Rectangle rect2 = new Rectangle ( 0, 0, bm2.Width, bm2.Height ); BitmapData bm2Data = bm2.LockBits ( rect2, ImageLockMode.ReadOnly, bm2.PixelFormat ); IntPtr bm2Ptr = bm2Data.Scan0; byte[] rgbValues2 = new byte [ Math.Abs(bm2Data.Stride) * bm2.Height ]; Marshal.Copy ( bm2Ptr, rgbValues2, 0, rgbValues2.Length ); } } 

but during the second marshal. Copy an AccessViolationException event occurred:

 C:\CompareImages>csc CompareImages.cs Microsoft (R) Visual C# 2010 Compiler version 4.0.30319.1 Copyright (C) Microsoft Corporation. All rights reserved. C:\CompareImages>CompareImages.exe Format24bppRgb width = 3648 height = 2736 stride = 10944 bytes = 29942784 After 1st Marshal.Copy ... Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. at System.Runtime.InteropServices.Marshal.CopyToManaged(IntPtr source, Object destination, Int32 startIndex, Int32 length) at CompareImages.Main(String[] args) 

What is wrong with my program?

Thanks.

+3
source share
3 answers

I have been studying a similar problem for several hours, and I think I have found what might be your problem. I assume that your bitmaps can be stored in slightly different formats. Bitmap images can be saved either forward or backward. Stride will be negative when saving back. However, Scan0 always points to the first scan line, that is, the first pixel is NOT the first byte in the array.

Therefore, in the reverse scan bitmap, Scan0 + Abs (Stride) - 1 is the last byte in the array. Scan0 + Stride will always be the beginning of the second line, so if the step is negative, it works in the opposite direction, and positive will work forward.

If you do Marshal.Copy (bm2Ptr, rgbValues2, 0, rgbValues2.Length) with a negative step, this will copy the last scan line before entering the access violation territory. The following code converts any bitmap images into reverse scan bytes [] (just because of what I was working with). I assume that you have already fixed / worked on your problems, but hopefully this helps others.

  private byte[] BitmapToByteArray2(Bitmap bmp) { // Lock the bitmap bits. Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, bmp.PixelFormat); int absStride = Math.Abs(bmpData.Stride); int bytes = absStride * bmp.Height; // Declare an array to hold the bytes of the bitmap. byte[] rgbValues = new byte[bytes]; for (int i = 0; i < bmp.Height; i++) { IntPtr pointer = new IntPtr(bmpData.Scan0.ToInt32() + (bmpData.Stride * i)); System.Runtime.InteropServices.Marshal.Copy(pointer, rgbValues, absStride * (bmp.Height - i - 1), absStride); } // Unlock the bits. bmp.UnlockBits(bmpData); return rgbValues; } 
+8
source

I tested the code and it works for me ...

At first I used some random shots, and then a large full white picture with your image size. Perhaps you can provide more information about these two pictures, are they the same size or pixel format?

The only possible error that I see is that you are not calling UnlockBits after copying.

This site explains LockBit quite well.

0
source

This works for me. I tried to invalidate the image file, but this throws another exception. This requires some cleaning.

 using (Bitmap bm1 = new Bitmap("PB270029.JPG")) { Console.WriteLine(bm1.PixelFormat.ToString()); int width = bm1.Width; int height = bm1.Height; Console.WriteLine("width = " + width + " height = " + height); Rectangle rect1 = new Rectangle(0, 0, width, height); BitmapData bm1Data = bm1.LockBits(rect1, ImageLockMode.ReadOnly, bm1.PixelFormat); try { Console.WriteLine("stride = " + bm1Data.Stride); IntPtr bm1Ptr = bm1Data.Scan0; int bytes = Math.Abs(bm1Data.Stride) * height; Console.WriteLine("bytes = " + bytes); byte[] rgbValues1 = new byte[bytes]; Marshal.Copy(bm1Ptr, rgbValues1, 0, bytes); Console.WriteLine("After 1st Marshal.Copy ..."); } finally { bm1.UnlockBits(bm1Data); } } using (Bitmap bm2 = new Bitmap("PA050164.JPG")) { Rectangle rect2 = new Rectangle(0, 0, bm2.Width, bm2.Height); BitmapData bm2Data = bm2.LockBits(rect2, ImageLockMode.ReadOnly, bm2.PixelFormat); try { IntPtr bm2Ptr = bm2Data.Scan0; byte[] rgbValues2 = new byte[Math.Abs(bm2Data.Stride) * bm2.Height]; Marshal.Copy(bm2Ptr, rgbValues2, 0, rgbValues2.Length); } finally { bm2.UnlockBits(bm2Data); } } 
0
source

All Articles