I have this code:
private void FindPoints()
{
try
{
GraphicsPath gp = new GraphicsPath();
int x, y, p, j, wdthHght;
int bytes;
byte[] rgbValuesWithClouds;
byte[] rgbValuesWithoutClouds;
IntPtr ptr;
Rectangle rect;
BitmapData bitmap_Data;
Bitmap bmpWithClouds; //No memory is allocated
Bitmap bmpWithoutClouds; //No memory is allocated
gp.AddEllipse(new RectangleF(73, 72, 367, 367));
using (bmpWithClouds = new Bitmap(mymem))
{
rect = new Rectangle(0, 0, bmpWithClouds.Width, bmpWithClouds.Height);
wdthHght = bmpWithClouds.Width;
bitmap_Data = bmpWithClouds.LockBits(rect, ImageLockMode.ReadWrite, bmpWithClouds.PixelFormat);
ptr = bitmap_Data.Scan0;
bytes = bitmap_Data.Stride * bmpWithClouds.Height;
rgbValuesWithClouds = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValuesWithClouds, 0, bytes);
bmpWithClouds.UnlockBits(bitmap_Data);
}
su = System.IO.Directory.GetCurrentDirectory();
using (bmpWithoutClouds = new Bitmap(su + "\\WithoutClouds.bmp")) //24 bit bitmap
{
rect = new Rectangle(0, 0, bmpWithoutClouds.Width, bmpWithoutClouds.Height);
bitmap_Data = bmpWithoutClouds.LockBits(rect, ImageLockMode.ReadWrite, bmpWithoutClouds.PixelFormat);
ptr = bitmap_Data.Scan0;
bytes = bitmap_Data.Stride * bmpWithoutClouds.Height;
rgbValuesWithoutClouds = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValuesWithoutClouds, 0, bytes);
bmpWithoutClouds.UnlockBits(bitmap_Data);
}
cloudPoints = new List<Point>();
for (y = 0; y < wdthHght; y++)
{
j = 0;
for (x = 0; x < wdthHght; x++)
{
p = y * wdthHght * 3 + j;
if (rgbValuesWithClouds[p] != rgbValuesWithoutClouds[p])
{
cloudPoints.Add(new Point(x, y));
}
j += 3;
}
}
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
The exception is on the line number 393:
if (rgbValuesWithClouds[p] != rgbValuesWithoutClouds[p])
I used try and catch but i can't see what is the values of p and rgbValuesWithClouds and rgbValuesWithoutClouds are.
And also what can make this exception ?
System.IndexOutOfRangeException was caught
HResult=-2146233080
Message=Index was outside the bounds of the array.
Source=My Weather Station
StackTrace:
at mws.ScanningClouds.FindPoints() in d:\C-Sharp\Download File\Downloading-File-Project-Version-012\Downloading File\ScanningClouds.cs:line 393
InnerException:
You already know that you have an IndexOutOfRangeException in the line of
if (rgbValuesWithClouds[p] != rgbValuesWithoutClouds[p])
which means that p is either smaller than 0 or bigger than the length of rgbValuesWithClouds or rgbValuesWithoutClouds.
You might want to check whether p is greater or equal than 0 and smaller than the length of both of your arrays before you make this comparison.
Related
private void FindPoints()
{
GraphicsPath gp = new GraphicsPath();
int x, y, p, j, wdthHght;
int bytes;
byte[] rgbValuesWithClouds;
byte[] rgbValuesWithoutClouds;
IntPtr ptr;
Rectangle rect;
BitmapData bitmap_Data;
Bitmap bmpWithClouds; //No memory is allocated
Bitmap bmpWithoutClouds; //No memory is allocated
gp.AddEllipse(new RectangleF(73, 72, 367, 367));
//using the using statement, bmpWithClouds bitmap is automatically disposed at the end of statement. No memory leaks :)
using (bmpWithClouds = new Bitmap(mymem))
{
rect = new Rectangle(0, 0, bmpWithClouds.Width, bmpWithClouds.Height);
wdthHght = bmpWithClouds.Width;
//Lock bitmap to copy its color information fast
bitmap_Data = bmpWithClouds.LockBits(rect, ImageLockMode.ReadWrite, bmpWithClouds.PixelFormat);
ptr = bitmap_Data.Scan0;
bytes = bitmap_Data.Stride * bmpWithClouds.Height;
rgbValuesWithClouds = new byte[bytes];
//copy color information to rgbValues array
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValuesWithClouds, 0, bytes);
//we are done copying so unlock bitmap. We dont need it anymore
bmpWithClouds.UnlockBits(bitmap_Data);
}
//using the using statement, bmpWithClouds bitmap is automatically disposed at the end of statement. No memory leaks :)
using (bmpWithoutClouds = new Bitmap(#"F:\Drive Backup\Samsung Galaxy S9\Danny Backup\Recovered data 02-10 18_32_36\1 (D) NTFS\C-Sharp\Weather Radar\WithoutClouds.bmp")) //24 bit bitmap
{
rect = new Rectangle(0, 0, bmpWithoutClouds.Width, bmpWithoutClouds.Height);
//Lock bitmap to copy its color information fast
bitmap_Data = bmpWithoutClouds.LockBits(rect, ImageLockMode.ReadWrite, bmpWithoutClouds.PixelFormat);
ptr = bitmap_Data.Scan0;
bytes = bitmap_Data.Stride * bmpWithoutClouds.Height;
rgbValuesWithoutClouds = new byte[bytes];
//copy color information to rgbValues array
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValuesWithoutClouds, 0, bytes);
//we are done copying so unlock bitmap. We dont need it anymore
bmpWithoutClouds.UnlockBits(bitmap_Data);
}
// Each position in these arrays, rgbValuesWithoutClouds and rgbValuesWithClouds, corresponds a color. eg
// First pixel Second pixel Third pixel Forth pixel .... // bitmaps
// B G R B G R B G R B G R .... // rgbValues arrays
bmptest = new Bitmap(512, 512);
cloudPoints = new List<Point>();
for (y = 0; y < wdthHght; y++)
{
j = 0;
for (x = 0; x < wdthHght; x++)
{
p = y * wdthHght * 3 + j;
if (rgbValuesWithClouds[p] != rgbValuesWithoutClouds[p])
{
cloudPoints.Add(new Point(x, y));
if (graphicsPath.IsVisible(x, y))
{
bmptest.SetPixel(x, y, Color.Yellow);
}
}
j += 3;
}
}
bmptest.Save(#"d:\bmptest1.bmp");
}
this method is being called in paint event
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.DrawRectangle(Pens.Green, 0, 0, pictureBox1.Width - 1, pictureBox1.Height - 1);
Pen p = new Pen(Color.Red);
e.Graphics.DrawLine(p, 256, 0, 256, 512);
e.Graphics.DrawLine(p, 0, 256, 512, 256);
FindPoints();
DrawPieOnPicturebox(e.Graphics);
}
i found that if i'm not using or removing the part :
if (graphicsPath.IsVisible(x, y))
it will working fast but then it will color the pixels in yellow at once and i want it to color the pixels in yellow only if the graphicsPath is visible which make the whole application working very slow.
this is where and how i'm using the graphicsPath
public void DrawPieOnPicturebox(Graphics myPieGraphic)
{
Color myPieColors = Color.FromArgb(150, Color.LightGreen);
Size myPieSize = new Size((int)distanceFromCenterPixels, (int)distanceFromCenterPixels);
Point myPieLocation = new Point((pictureBox1.Width - myPieSize.Width) / 2, (pictureBox1.Height - myPieSize.Height) / 2);
DrawMyPie(myPiePercent, myPieColors, myPieGraphic, myPieLocation, myPieSize);
}
public void DrawMyPie(int myPiePerecent, Color myPieColor, Graphics myPieGraphic, Point
myPieLocation, Size myPieSize)
{
using (SolidBrush brush = new SolidBrush(myPieColor))
{
myPieGraphic.FillPie(brush, new Rectangle(myPieLocation, myPieSize), Convert.ToSingle(myPiePerecent * 360 / 100), Convert.ToSingle(15 * 360 / 100));
}
myPieGraphic.DrawImage(bmptest, Point.Empty);
graphicsPath.AddPie(new Rectangle(myPieLocation, myPieSize), Convert.ToSingle(myPiePerecent * 360 / 100), Convert.ToSingle(15 * 360 / 100));
}
in my unity3d project code i have this method : i want to use Bitmap GraphicsPath BitmapData Rectangle and more but they are all missing reference.
I tried to google for it some result suggest to change in the unity editor Project Settings > Player API Compatibility level to .NET 2.1 but it didn't much help. it did add some System.Drawing but not the csharp one.
a bit messed.
private void FindPoints()
{
Bitmap bmptest;
GraphicsPath gp = new GraphicsPath();
int x, y, p, j, wdthHght;
int bytes;
byte[] rgbValuesWithClouds;
byte[] rgbValuesWithoutClouds;
IntPtr ptr;
Rectangle rect;
BitmapData bitmap_Data;
Bitmap bmpWithClouds; //No memory is allocated
Bitmap bmpWithoutClouds; //No memory is allocated
gp.AddEllipse(new RectangleF(73, 72, 367, 367));
//using the using statement, bmpWithClouds bitmap is automatically disposed at the end of statement. No memory leaks :)
using (bmpWithClouds = new Bitmap(mymem))
{
rect = new Rectangle(0, 0, bmpWithClouds.Width, bmpWithClouds.Height);
wdthHght = bmpWithClouds.Width;
//Lock bitmap to copy its color information fast
bitmap_Data = bmpWithClouds.LockBits(rect, ImageLockMode.ReadWrite, bmpWithClouds.PixelFormat);
ptr = bitmap_Data.Scan0;
bytes = bitmap_Data.Stride * bmpWithClouds.Height;
rgbValuesWithClouds = new byte[bytes];
//copy color information to rgbValues array
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValuesWithClouds, 0, bytes);
//we are done copying so unlock bitmap. We dont need it anymore
bmpWithClouds.UnlockBits(bitmap_Data);
}
//using the using statement, bmpWithClouds bitmap is automatically disposed at the end of statement. No memory leaks :)
using (bmpWithoutClouds = new Bitmap(#"F:\Drive Backup\Samsung Galaxy S9\Danny Backup\Recovered data 02-10 18_32_36\1 (D) NTFS\C-Sharp\Weather Radar\WithoutClouds.bmp")) //24 bit bitmap
{
rect = new Rectangle(0, 0, bmpWithoutClouds.Width, bmpWithoutClouds.Height);
//Lock bitmap to copy its color information fast
bitmap_Data = bmpWithoutClouds.LockBits(rect, ImageLockMode.ReadWrite, bmpWithoutClouds.PixelFormat);
ptr = bitmap_Data.Scan0;
bytes = bitmap_Data.Stride * bmpWithoutClouds.Height;
rgbValuesWithoutClouds = new byte[bytes];
//copy color information to rgbValues array
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValuesWithoutClouds, 0, bytes);
//we are done copying so unlock bitmap. We dont need it anymore
bmpWithoutClouds.UnlockBits(bitmap_Data);
}
// Each position in these arrays, rgbValuesWithoutClouds and rgbValuesWithClouds, corresponds a color. eg
// First pixel Second pixel Third pixel Forth pixel .... // bitmaps
// B G R B G R B G R B G R .... // rgbValues arrays
bmptest = new Bitmap(512, 512);
cloudPoints = new List<Point>();
for (y = 0; y < wdthHght; y++)
{
j = 0;
for (x = 0; x < wdthHght; x++)
{
p = y * wdthHght * 3 + j;
if (rgbValuesWithClouds[p] != rgbValuesWithoutClouds[p])
{
cloudPoints.Add(new Point(x, y));
bmptest.SetPixel(x, y, Color.Red);
}
j += 3;
}
}
}
My code calculates average color of each pixel in an image and returns a new image.
Image calculateAverage(Bitmap image1, Bitmap image2)
{
// Locking the image into memory.
BitmapData sourceData = image1.LockBits(new Rectangle(0, 0, image1.Width, image1.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
// All of the pixels will be stored in this array(each 4 numbers represent a pixel).
byte[] sourceBuffer = new byte[sourceData.Stride * sourceData.Height];
// Copying the image pixels into sourceBuffer.
Marshal.Copy(sourceData.Scan0, sourceBuffer, 0, sourceBuffer.Length);
// Don't need the image, unlock memory.
image1.UnlockBits(sourceData);
// --- Same thing for the second image ---
BitmapData blendData = image2.LockBits(new Rectangle(0, 0, image2.Width, image2.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
byte[] blendBuffer = new byte[blendData.Stride * blendData.Height];
Marshal.Copy(blendData.Scan0, blendBuffer, 0, blendBuffer.Length);
image2.UnlockBits(blendData);
//---
// Calculating average of each color in each pixel.
for (int k = 0; (k + 4 < sourceBuffer.Length) && (k + 4 < blendBuffer.Length); k += 4)
{
sourceBuffer[k] = (byte)calcualteAverage(sourceBuffer[k], blendBuffer[k]);
sourceBuffer[k + 1] = (byte)calcualteAverage(sourceBuffer[k + 1], blendBuffer[k + 1]);
sourceBuffer[k + 2] = (byte)calcualteAverage(sourceBuffer[k + 2], blendBuffer[k + 2]);
// Average of Alpha
sourceBuffer[k + 3] = (byte)calcualteAverage(sourceBuffer[k + 3], sourceBuffer[k + 3]);
}
// Saving the result.
Bitmap resultBitmap = new Bitmap(image1.Width, image1.Height);
BitmapData resultData = resultBitmap.LockBits(new Rectangle(0, 0,
resultBitmap.Width, resultBitmap.Height),
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
Marshal.Copy(sourceBuffer, 0, resultData.Scan0, sourceBuffer.Length);
resultBitmap.UnlockBits(resultData);
return resultBitmap;
}
For performance reasons I need to rewrite this method using unsafe code though I'm a noob with pointers; don't know how it can improve performance or what will change in the algorithm?
The function can be replaced by this:
public static Bitmap CalculateAverage(
Bitmap sourceBitmap, Bitmap blendBitmap)
{
// Locking the images into the memory.
BitmapData sourceData = sourceBitmap.LockBits(
new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
BitmapData blendData = blendBitmap.LockBits(
new Rectangle(0, 0, blendBitmap.Width, blendBitmap.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
// Get required variables. This wont work for images with different sizes.
int resultWidth = sourceBitmap.Width;
int resultHeight = sourceBitmap.Height;
int stride = sourceData.Stride;
// result will be stored here.
var resultBitmap = new Bitmap(resultWidth, resultHeight);
BitmapData resultData = resultBitmap.LockBits(
new Rectangle(0, 0, resultWidth, resultHeight),
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
unsafe
{
// Getting address of locked images.
byte* sourceAddress = (byte*)sourceData.Scan0.ToPointer();
byte* blendAddress = (byte*)blendData.Scan0.ToPointer();
byte* resultAddress = (byte*)resultData.Scan0.ToPointer();
// Iterating throgh pixels and storing averages inside the result variable.
for (int y = 0; y < resultHeight; y++)
{
for (int x = 0; x < resultWidth; x++)
{
for (int color = 0; color < 4; color++)
{
int currentByte = (y * stride) + x * 4 + color;
resultAddress[currentByte] = (byte)average(
sourceAddress[currentByte],
blendAddress[currentByte]);
}
}
}
}
// Unlocking the Bits; returning the result bitmap.
sourceBitmap.UnlockBits(sourceData);
blendBitmap.UnlockBits(blendData);
resultBitmap.UnlockBits(resultData);
return resultBitmap;
}
I cannot test it at the moment but this might give a hint in the right direction. If there are any questions please don't hesitate to ask. It's based on this code: How to calculate the average rgb color values of a bitmap.
I have to draw an image from integer values. They are stored in List<int>[].
The list has 5081 arrays with 2048 values each. Each value is between 0-1000 and one int is the color for one pixel, so it's grayscale.
I know how to do it with setpixel but this is too slow.
for (int y = 0; y < channelId.Length; y++) {
for (int x = 0; x < channelId[y].Count; x++) {
int myColor = (channelId[y].ElementAt(x) * 255) / 1000;
if (myColor > 255) {
myColor = 255;
} else if (myColor < 0) {
myColor = 0;
}
bmp.SetPixel(x, y, Color.FromArgb(myColor, myColor, myColor));
}
}
I know that there are similar questions here how to draw bitmaps faster but they already have a bitmap. I have to draw the image from my values.
If you don't want to do it unsafely, you could do this (assumes a 32bppArgb pixelformat):
var rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
var bmpData = bmp.LockBits(rect, ImageLockMode.WriteOnly, bmp.PixelFormat);
IntPtr ptr = bmpData.Scan0;
for (var y = 0; y < channelId.Length; y++)
{
var scanLineSize = channelId[y].Count*4;
var rgb = new byte[scanLineSize];
int idx = 0;
// Convert the whole scanline
foreach (var id in channelId[y])
{
rgb[idx] = rgb[idx+1] = rgb[idx+2] = (byte)(id*255/1000);
rgb[idx+3] = 255;
idx += 4;
}
// And copy it in one pass
System.Runtime.InteropServices.Marshal.Copy(rgb, 0, ptr, scanLineSize);
ptr += bmpData.Stride;
}
bmp.UnlockBits(bmpData);
If it's not fast enough for you, you could do the whole conversion of the bitmap in-memory and copy the whole array in one pass. This would not be very memory-efficient though, and this should be "fast enough" for the amount of data you are moving.
Update
Just for fun, in one pass:
var rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
var bmpData = bmp.LockBits(rect, ImageLockMode.WriteOnly, bmp.PixelFormat);
IntPtr ptr = bmpData.Scan0;
int idx = 0;
var rgb = new byte[channelId[0].Count * 4 * channelId.Length];
foreach (var id in channelId.SelectMany(t => t))
{
rgb[idx] = rgb[idx+1] = rgb[idx+2] = (byte)(id*255/1000);
rgb[idx+3] = 255;
idx += 4;
}
System.Runtime.InteropServices.Marshal.Copy(rgb, 0, ptr, rgb.Length);
bmp.UnlockBits(bmpData);
Apart from the memory-efficiency, you'll need to make sure all List<int> in the array contain the same number of elements and that the Stride of the bitmap is the same as width*4. It should be for 2048 elements, but you never know.
BitmapData bitmapData = bmp.LockBits(
new Rectangle(0, 0, channelId[0].Count, channelId.Length),
ImageLockMode.ReadWrite,
PixelFormat.Format32bppArgb
);
unsafe{
ColorARGB* startingPosition = (ColorARGB*) bitmapData.Scan0;
for (int y = 0; y < channelId.Length; y++) {
for (int x = 0; x < channelId[y].Count; x++) {
int myColor = (channelId[y].ElementAt(x) * 255) / 1000;
if (myColor > 255) {
myColor = 255;
} else if (myColor < 0) {
myColor = 0;
}
ColorARGB* position = startingPosition + j + i * channelId[0].Count;
position->A = 255;
position->R = myColor;
position->G = myColor;
position->B = myColor;
}
}
bmp.UnlockBits(bitmapData);
}
I am trying to generate 16bit grayscale Bitmap in C# from a random data.But it crashed on Marshal.Copy.
Here is my code:
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");
}
The exception is:
An unhandled exception of type 'System.AccessViolationException' occurred in mscorlib.dll
This is not my code.I found it in relation to 32bit Bitmaps and modified.But I guess I have missed something as I am pretty new to C#.
Basically,all I need is to wrap into BitmapData an arrays of shorts.
This works for 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;
}
I have corrected some of your mistakes (mostly wrong sizes). But it will still crash on b16bpp.Save(), because GDI+ does not support saving 16bit grayscale images.
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");
}
Explanation of my changes:
bitmapData.Stride is already IMAGE_WIDTH * BytesPerPixel so you don't need to multiply by 2
as you declared bitmapBytes as short[] it has to have the size of the image in pixels not in bytes
that means you also do not need to multiply i by 2
since you have a grayscale image it does not have a blue, green and red channel, but one single 16bit gray channel
Marshal.Copy takes the length in "array units" not in bytes
All in all you tried to copy an array 8 times to large into the bitmap.