"Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
I'm experiencing this error in the Marshal.Copy portion of my code. I do believe that my data is not corrupted nor protected.
I was wondering in what case does this occur.
I have a List<> of bitmaps. This only occurs when I process the first index [0].
So here's how I did it :
- First, I used this code [This code gets the pixel data of a bitmap] :
Bitmap tmp_bitmap = BitmapFromFile[0];
Rectangle rect = new Rectangle(0, 0, tmp_bitmap.Width, tmp_bitmap.Height);
System.Drawing.Imaging.BitmapData bmpData =
tmp_bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
PixelFormat.Format24bppRgb);
int length = bmpData.Stride * bmpData.Height;
byte[] bytes = new byte[length];
// Copy bitmap to byte[]
Marshal.Copy(bmpData.Scan0, bytes, 0, length);
tmp_bitmap.UnlockBits(bmpData);
It works fine, no errors occur.
Then, I apply this code [ This will remove the pixel data line scan padding ]:
byte[] bytes = new byte[bmpData.Width * bmpData.Height * 3];
for (int y = 0; y < bmpData.Height; ++y) {
IntPtr mem = (IntPtr)((long)bmpData.Scan0 + y * bmpData.Stride * 3);
Marshal.Copy(mem, bytes, y * bmpData.Width * 3, bmpData.Width * 3); //This is where the exception is pointed.
}
It gives me that error whenever I'm processing the first image -- second to last, no problem at all.
I hope you can help me with this.
Thank you in advance.
You seem to be considering 3 times the stride for every row; your code will only work for the first third of the image; after that you have indeed gone outside of your allowed range. Basically:
bmpData.Scan0 + y * bmpData.Stride * 3
looks really dodgy. The "stride" is the number of bytes (including padding) used by every line. Typically, that would be just:
bmpData.Scan0 + y * bmpData.Stride
Related
The method for editing Bitmap using BitmapData and Lock and UnlockBits taken from the MSDN seems to work very differently on Bitmaps with with different sizes. It only does this on PixelFormat.Format24bppRgb and changing it seems to fix it, but I'd like to know what's going on.
Here's the method for reference:
private void LockUnlockBitsExample(PaintEventArgs e)
{
// Create a new bitmap.
Bitmap bmp = new Bitmap("c:\\fakePhoto.jpg");
// Lock the bitmap's bits.
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
System.Drawing.Imaging.BitmapData bmpData =
bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
bmp.PixelFormat);
// Get the address of the first line.
IntPtr ptr = bmpData.Scan0;
// Declare an array to hold the bytes of the bitmap.
int bytes = Math.Abs(bmpData.Stride) * bmp.Height;
byte[] rgbValues = new byte[bytes];
// Copy the RGB values into the array.
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
// Set every third value to 255. A 24bpp bitmap will look red.
for (int counter = 2; counter < rgbValues.Length; counter += 3)
rgbValues[counter] = 255;
// Copy the RGB values back to the bitmap
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
// Unlock the bits.
bmp.UnlockBits(bmpData);
// Draw the modified image.
e.Graphics.DrawImage(bmp, 0, 150);
}
It works just fine for Bitmap(200, 200) or Bitmap(200,250). But when it's used on Bitmap(50, 50) or most of the other sizes it goes completely crazy...
The rgbValues array has unexpected length of 7600. (The expected length would be Width * Height * Bytes per pixel = 50 * 50 * 3 = 7500)
This causes it to throw IndexOutOfRange Exception in most cases
I tried to change the value added to the counter but none seems to work
for (int counter = 10; counter + 10 < rgbValues.Length; counter += n)
rgbValues[counter] = 255;
//Doesn't work for any number put for n from 2 to 10
//I also limited it from beginning and end just to try
//if it's not changing some crucial value in the bytes
//(I know it's a nonsense but I tried)
If 3 is put for n (referring to the code above) it yields a picture with 1st row red, 2nd blue, 3rd green, repeat
If 1 is put there it actually makes the whole picture white
Can someone please explain why is this happening? And how can this be fixed? (besides changing the format)
Note: I'm not keen on this format but I'd like to know what's actually going on.
I have the following code which takes an array of bytes which i generated and writes them out to this bitmap. If i set the pixel format to Format4bppIndexed, then i get a readable image repeating width wise 4 times, if i set it to Format1bppIndexed(which is the correct setting) then i get one big unreadable image.
The image was a decoded Jbig2 image , i know the bytes are correct i can't seem to figure out how to get it into a 1bpp readable format.
Does anyone have any advice on that matter
Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format1bppIndexed);
//Create a BitmapData and Lock all pixels to be written
BitmapData bmpData = bitmap.LockBits(
new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.WriteOnly, bitmap.PixelFormat);
//Copy the data from the byte array into BitmapData.Scan0
Marshal.Copy(newarray, 0, bmpData.Scan0, newarray.Length);
//Unlock the pixels
bitmap.UnlockBits(bmpData);
The following may work although, if I remember correctly, Stride sometimes has an effect and a simple block-copy won't suffice (line by line must be used instead).
Bitmap bitmap = new Bitmap(
width,
height,
System.Drawing.PixelFormat.Format16bppGrayScale
);
To handle the Stride you'd want:
BitmapData^ data = bitmap->LockBits(oSize,
ImageLockMode::ReadOnly, bitmap->PixelFormat);
try {
unsigned char *pData = (unsigned char *)data->Scan0.ToPointer();
for( int x = 0; x < bmpImage->Width; ++x )
{
for( int y = 0; y < bmpImage->Height; ++y )
{
// Note: Stride is data width of scan line rounded up
// to 4 byte boundary.
// Requires use of Stride, not (width * pixelWidth)
int ps = y*bmpImage->Width*(nBitsPerPixel / 8)
+ x * (nBitsPerPixel / 8);
int p = y * data->Stride + x * (nBitsPerPixel / 8);
Byte lo = newarray[ps + 1];
Byte hi = newarray[ps + 0];
pData[p + 1] = lo;
pData[p + 0] = hi;
}
}
} finally {
bmpImage->UnlockBits(data);
}
Note: This was written in C++/CLI. Let me know if you need C# equivalents for any of the operations here. (Also, I pulled it from a read from bitmap rather than a write to bitmap so it may yet be a bit rough, but should hopefully give you the idea...)
I figured this out Although i'm still not sure why it should matter.
Based on this stackoverflow posting How can I load the raw data of a 48bpp image into a Bitmap?
I used the WPF classes instead of the GDI and wrote the code like this
var bitmap = new WriteableBitmap(width, height, 96, 96, System.Windows.Media.PixelFormats.BlackWhite, null);
bitmap.WritePixels(new System.Windows.Int32Rect(0, 0, width, height), newarray, stride, 0);
MemoryStream stream3 = new MemoryStream();
var encoder = new TiffBitmapEncoder ();
encoder.Frames.Add(BitmapFrame.Create(bitmap));
encoder.Save(stream3);
This correctly creates the image.
If anyone has any insight into why this might be the case please comment below
The port which now mostly works(lots of cleanup code) was based on a java implementation of JPedal Big2 Decoder to .NET. If anyone knows anyone interested send them here
https://github.com/devteamexpress/JBig2Decoder.NET
How do I calculate the required buffer size for the WriteableBitmap.WritePixels method?
I am using the overload taking four parameters, the first is an Int32Rect, the next is a byte array containing the RGBA numbers for the colour, the third is the stride (which is the width of my writeable bitmap multiplied by the bits per pixel divided by 8), and the last is the buffer (referred to as the offset in Intellisense).
I am getting the Buffer size is not sufficient runtime error in the below code:
byte[] colourData = { 0, 0, 0, 0 };
var xCoordinate = 1;
var yCoordinate = 1;
var width = 2;
var height = 2;
var rect = new Int32Rect(xCoordinate, yCoordinate, width, height);
var writeableBitmap = new WriteableBitmap(MyImage.Source as BitmapSource);
var stride = width*writeableBitmap.Format.BitsPerPixel/8;
writeableBitmap.WritePixels(rect, colourData, stride,0);
What is the formula I need to use to calculate the buffer value needed in the above code?
The stride value is calculated as the number of bytes per "pixel line" in the write rectangle:
var stride = (rect.Width * bitmap.Format.BitsPerPixel + 7) / 8;
The required buffer size is the number of bytes per line multiplied by the number of lines:
var bufferSize = rect.Height * stride;
Provided that you have a 2x2 write rectangle and a 32-bits-per-pixel format, e.g. PixelFormats.Pbgra32, you get stride as 8 and bufferSize as 16.
The stride is simply the width in bytes of your input buffer. It is called stride, because sometimes there is extra memory behind each line of an image, which makes it impossible to use the width of the image to read each line of an image.
So in your example, this is 2. You do not need to calculate anything with the bits per pixel of the bitmap, the WritePixels method knows all this information. You need to provide the information about how your input data is structured.
However, as mentioned in the other answer, your example won't work if the bitmap is also 2x2. Then the starting coordinate would be 0,0.
EDIT:
When I look closer at your example, I see the mistake. You say the colourData is the input color. But this is input per pixel. So if you want to change a rect of 2x2, you need the following inputdata:
byte[] colourData = { 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 };
And then the bytes per pixel is equal to that of the bitmap, so that is 4, times the width of each line (2), makes total 8.
Here's Microsoft's reflected code that performs the check within CopyPixels
int num = ((sourceRect.Width * this.Format.BitsPerPixel) + 7) / 8;
if (stride < num)
{
throw new ArgumentOutOfRangeException("stride", MS.Internal.PresentationCore.SR.Get("ParameterCannotBeLessThan", new object[] { num }));
}
int num2 = (stride * (sourceRect.Height - 1)) + num;
if (bufferSize < num2)
{
throw new ArgumentOutOfRangeException("buffer", MS.Internal.PresentationCore.SR.Get("ParameterCannotBeLessThan", new object[] { num2 }));
}
Although user Clemens answered the question concerning the buffer size, the questioner was not aware that he calculated the buffer size already correct and the problem was somewhere else.
While details are given and discussed in comments there is lacking one comprehensive snippet (and complete usage example of .WritePixels (without .CopyPixels) as well).
Here it is (I scanned similar questions, but this has been the best place):
var dpiX = 96;
var writeableBitmap = new WriteableBitmap(width, height, dpiX, dpiX, PixelFormats.Bgra32, null); // Pixelformat of Bgra32 results always in 4 bytes per pixel
int bytesPerPixel = (writeableBitmap.Format.BitsPerPixel + 7) / 8; // general formula
int stride = bytesPerPixel * width; // general formula valid for all PixelFormats
byte[] pixelByteArrayOfColors = new byte[stride * height]; // General calculation of buffer size
// The numbers in the array are indices to the used BitmapPalette,
// since we initialized it with null in the writeableBitmap init, they refer directly to RGBA, but only in this case.
// Choose a light green color for whole bitmap (for not easy to find commented MSDN example with random colors, see https://msdn.microsoft.com/en-us/library/system.windows.media.imaging.writeablebitmap(VS.85).aspx
for (int pixel = 0; pixel < pixelByteArrayOfColors.Length; pixel += bytesPerPixel)
{
pixelByteArrayOfColors[pixel] = 0; // blue (depends normally on BitmapPalette)
pixelByteArrayOfColors[pixel + 1] = 255; // green (depends normally on BitmapPalette)
pixelByteArrayOfColors[pixel + 2] = 0; // red (depends normally on BitmapPalette)
pixelByteArrayOfColors[pixel + 3] = 50; // alpha (depends normally on BitmapPalette)
}
writeableBitmap.WritePixels(new Int32Rect(0, 0, width, height), pixelByteArrayOfColors, stride, 0);
I am work with this.
60z fs
this.playerOpacityMaskImage.WritePixels(
new Int32Rect(0, 0, this.depthWidth, this.depthHeight),
this.greenScreenPixelData,
this.depthWidth * ((this.playerOpacityMaskImage.Format.BitsPerPixel + 7) / 8),
0);
I am not sure but try this works for 24 bit rgb
{
//your code
var stride = width * 3;
WriteableBitmap bmp = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgr24, null);
bmp.WritePixels(new System.Windows.Int32Rect(0, 0, width , height),byte[],stride,0));
}
I have a method to copy the data out of a System.Drawing.Bitmap which looks like this:
var readLock = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
byte[] data = new byte[3 * image.Width * image.Height];
if (data.Length != readLock.Stride * readLock.Height)
throw new InvalidOperationException("Incorrect number of bytes");
Marshal.Copy(readLock.Scan0, data , 0, data.Length);
image.UnlockBits(readLock);
Pretty simple, and it works for most of my images. However for a very small image (14x14) it hits the exception. In the failing case Stride is 44, not 42 (14 * 3) as expected.
The pixel format is Format24bppRgb, so there should be three bytes for every pixel in the image. Where are these extra bytes coming from, and how can I deal with them when processing the image data?
For anyone interested, I'm generating Normal data from a heightmap, so I need to be able to get each pixel and its neighbours accurately).
Every pixel line of Bitmap must be aligned, that's why stride is not always width * bytes-per-pixel. You should ignore any extra bytes. It means that if you are working with byte arrays with unaligned data, you might not always be able to copy all image data in a single Marshal.Copy() call. Every line of pixels starts at readLock.Scan0 + y * readLock.Stride and contains readLock.Width * bytes-per-pixel meaningful bytes.
Solution:
const int BYTES_PER_PIXEL = 3;
var data = new byte[readLock.Width * readLock.Height * BYTES_PER_PIXEL];
if(readLock.Stride == readLock.Width * BYTES_PER_PIXEL)
{
Marshal.Copy(readLock.Scan0, data, 0, data.Length);
}
else
{
for(int y = 0; y < readLock.Height; ++y)
{
IntPtr startOfLine = (IntPtr)((long)readLock.Scan0 + (readLock.Stride * y));
int dataOffset = y * readLock.Width * BYTES_PER_PIXEL;
Marshal.Copy(startOfLine, data, dataOffset, readLock.Width * BYTES_PER_PIXEL);
}
}
I have a doubt in c#. How to read a jpeg or bmp file using c#? and how to store the pixel's RGB values in array? Then how to check whether the value is already exist or not?
James Schek has it, but beware that GetPixel is extremely, incredibly slow.
Here's a complete sample using lockbits:
/*Note unsafe keyword*/
public unsafe Image ThresholdUA(float thresh)
{
Bitmap b = new Bitmap(_image);//note this has several overloads, including a path to an image
BitmapData bData = b.LockBits(new Rectangle(0, 0, _image.Width, _image.Height), ImageLockMode.ReadWrite, b.PixelFormat);
byte bitsPerPixel = GetBitsPerPixel(bData.PixelFormat);
/*This time we convert the IntPtr to a ptr*/
byte* scan0 = (byte*)bData.Scan0.ToPointer();
for (int i = 0; i < bData.Height; ++i)
{
for (int j = 0; j < bData.Width; ++j)
{
byte* data = scan0 + i * bData.Stride + j * bitsPerPixel / 8;
//data is a pointer to the first byte of the 3-byte color data
}
}
b.UnlockBits(bData);
return b;
}
There's another way to do it using marshaling though. Here's the same thing, but with marshaling:
/*No unsafe keyword!*/
public Image ThresholdMA(float thresh)
{
Bitmap b = new Bitmap(_image);
BitmapData bData = b.LockBits(new Rectangle(0, 0, _image.Width, _image.Height), ImageLockMode.ReadWrite, b.PixelFormat);
/* GetBitsPerPixel just does a switch on the PixelFormat and returns the number */
byte bitsPerPixel = GetBitsPerPixel(bData.PixelFormat);
/*the size of the image in bytes */
int size = bData.Stride * bData.Height;
/*Allocate buffer for image*/
byte[] data = new byte[size];
/*This overload copies data of /size/ into /data/ from location specified (/Scan0/)*/
System.Runtime.InteropServices.Marshal.Copy(bData.Scan0, data, 0, size);
for (int i = 0; i < size; i += bitsPerPixel / 8 )
{
double magnitude = 1/3d*(data[i] +data[i + 1] +data[i + 2]);
//data[i] is the first of 3 bytes of color
}
/* This override copies the data back into the location specified */
System.Runtime.InteropServices.Marshal.Copy(data, 0, bData.Scan0, data.Length);
b.UnlockBits(bData);
return b;
}
Read the file using the Bitmap class.
Lock pixels.
Retrieve bytes from array.
Alternatively, you can use GetPixel if you just need one or two.
You can use Image.FromFile (http://msdn.microsoft.com/en-us/library/system.drawing.image.fromfile.aspx) to create an Image object from an image on disk.
As it was already mentioned, the fastest way to retrieve pixels is to use LockBits(), however, there's a way to do it without Marshal.Copy or unsafe code.
First, you'll need to compute Stride of your image:
var stride = ComputeStride(img.Width, format);
it is width*bytesPerPixel value rounded up to be divisible by 4. See formulas here.
Then you'll need to initialize an array of the required size:
var pixels = new byte[img.Height*stride]
Then you'll need to retrieve an unmanaged pointer to the beginning of this array.
You may use Marshal.UnsafeAddrOfPinnedArrayElement(pixels, 0), but it's safer to pin the array in memory:
var handle = GCHandle.Alloc(pixels, GCHandleType.Pinned);
var scan0 = pixels.AddrOfPinnedObject();
You'll need to create BitmapData structure:
var bData = new BitmapData{Width = img.Width, height = img.Height, Stride = stride, Scan0 = scan0};
Then you'll pass it to LockBits method while setting ImageLockMode.UserInputBuffer flag.
img.LockBits(area, ImageLockMode.Readonly | ImageLockMode.UserInputBuffer, format, bData);
Voila! Pixels are stored in pixels array. But you'll need to unpin your buffer:
handle.Free();
This may seem cumbersome, but this is the fastest way, since only one copying of data is required.