1

There is some code:

struct BitmapDataAccessor { private readonly byte[] data; private readonly int[] rowStarts; public readonly int Height; public readonly int Width; public readonly int Padding; public BitmapDataAccessor(byte[] data, int width, int height, int padding) { this.data = data; this.Height = height; this.Width = width + (4-padding)%4; this.Padding = padding; rowStarts = new int[Height]; for (int y = 0; y < Height; y++) rowStarts[y] = y * Width; } public byte this[int x, int y, int color] // Maybe use an enum with Red = 0, Green = 1, and Blue = 2 members? { get { return data[(rowStarts[y] + x) * 3 + color]; } set { data[(rowStarts[y] + x) * 3 + color] = value; } } public byte[] Data { get { return data; } } } public static byte[, ,] Bitmap2Byte(Bitmap obraz) { int h = obraz.Height; int w = obraz.Width; byte[, ,] wynik = new byte[w, h, 3]; BitmapData bd = obraz.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); int bytes = Math.Abs(bd.Stride) * h; byte[] rgbValues = new byte[bytes]; IntPtr ptr = bd.Scan0; System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes); int padding = Math.Abs(bd.Stride) - (((w * 24) + 7) / 8); BitmapDataAccessor bda = new BitmapDataAccessor(rgbValues, w, h, padding); for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { wynik[j, i, 0] = bda[j, i, 2]; wynik[j, i, 1] = bda[j, i, 1]; wynik[j, i, 2] = bda[j, i, 0]; } } obraz.UnlockBits(bd); return wynik; } 

And this is test I run:

private void btnLoad_Click(object sender, EventArgs e) { string s = ""; for (int i = 400; i < 409; i++) { Bitmap bmp = new Bitmap(i, i); bool ok = true; try { byte[,,] tab = Grafika.Bitmap2Byte(bmp); } catch { ok = false; } s += i + ": "; if (ok) s += "OK"; else s += "NOT OK"; s += "\n"; } StreamWriter w = StreamWriter(@"C:\lalala.txt"); w.Write(s); w.Close(); return; } 

Output:

400: OK 401: NOT OK 402: NOT OK 403: OK 404: OK 405: NOT OK 406: NOT OK 407: OK 408: OK 

Why do I get exceptions for w % 4 ==1 or w % 4 == 2?

EDIT:
I know what the exception is. It is 'Index out of bounds' and it happens in line
get { return data[(rowStarts[y] + x) * 3 + color]; }.
Unfortunately I don't know how to avoid this and why is it happening only for w % 4 ==1 or w % 4 == 2. That is why I posted my question. I don't need help with identyfying the exception or handling it. I just need to fix BitmapDataAccessor and/or Bitmap2Byte to make it work.

EDIT 2: Thanks to max's answer Bitmap2Byte doesn't throw Exceptions. But this makes my other function Byte2Bitmap Throw them:

 public static Bitmap Byte2Bitmap(byte[, ,] tablica) { if (tablica.GetLength(2) != 3) { throw new NieprawidlowyWymiarTablicyException(); } int w = tablica.GetLength(0); int h = tablica.GetLength(1); int padding = w % 4; int ww=w; if (padding != 0) ww += 4 - padding; int bytes = 3 * ww * h; byte[] rgbValues = new byte[bytes]; int counter = -3; for (int j = 0; j < h; j++) { for (int i = 0; i < w; i++) { counter += 3; rgbValues[counter] = tablica[i, j, 2]; rgbValues[counter + 1] = tablica[i, j, 1]; rgbValues[counter + 2] = tablica[i, j, 0]; } if(padding!=0) counter+= padding; } Bitmap obraz = new Bitmap(w, h, PixelFormat.Format24bppRgb); BitmapData bd = obraz.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb); IntPtr ptr = bd.Scan0; System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes); obraz.UnlockBits(bd); return obraz; } 

And my output to show for which widths there is exception:

380: OK 381: NOT OK: Nastąpiła próba odczytu lub zapisu pamięci chronionej. Często wskazuje to, że inna pamięć jest uszkodzona. 382: OK 383: OK 384: OK 385: NOT OK: Nastąpiła próba odczytu lub zapisu pamięci chronionej. Często wskazuje to, że inna pamięć jest uszkodzona. 386: OK 387: OK 388: OK 389: NOT OK: Nastąpiła próba odczytu lub zapisu pamięci chronionej. Często wskazuje to, że inna pamięć jest uszkodzona. 390: OK 391: OK 392: OK 393: OK 394: NOT OK: Nastąpiła próba odczytu lub zapisu pamięci chronionej. Często wskazuje to, że inna pamięć jest uszkodzona. 395: OK 396: OK 397: NOT OK: Nastąpiła próba odczytu lub zapisu pamięci chronionej. Często wskazuje to, że inna pamięć jest uszkodzona. 398: OK 399: OK 400: OK 401: NOT OK: Nastąpiła próba odczytu lub zapisu pamięci chronionej. Często wskazuje to, że inna pamięć jest uszkodzona. 402: OK 403: OK 404: OK 405: NOT OK: Nastąpiła próba odczytu lub zapisu pamięci chronionej. Często wskazuje to, że inna pamięć jest uszkodzona. 406: NOT OK: Nastąpiła próba odczytu lub zapisu pamięci chronionej. Często wskazuje to, że inna pamięć jest uszkodzona. 407: OK 408: OK 409: NOT OK: Nastąpiła próba odczytu lub zapisu pamięci chronionej. Często wskazuje to, że inna pamięć jest uszkodzona. 410: OK 411: OK 412: OK 413: OK 414: NOT OK: Nastąpiła próba odczytu lub zapisu pamięci chronionej. Często wskazuje to, że inna pamięć jest uszkodzona. 415: OK 416: OK 417: NOT OK: Nastąpiła próba odczytu lub zapisu pamięci chronionej. Często wskazuje to, że inna pamięć jest uszkodzona. 418: OK 419: OK 420: OK 421: NOT OK: Nastąpiła próba odczytu lub zapisu pamięci chronionej. Często wskazuje to, że inna pamięć jest uszkodzona. 422: NOT OK: Nastąpiła próba odczytu lub zapisu pamięci chronionej. Często wskazuje to, że inna pamięć jest uszkodzona. 423: OK 424: OK 425: NOT OK: Nastąpiła próba odczytu lub zapisu pamięci chronionej. Często wskazuje to, że inna pamięć jest uszkodzona. 426: OK 427: OK 428: OK 

Exception occurs in line:
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
and its text means: There was try to read or write to/from protected memory...
I think this is because bytes is not calculated correctly. How can I do this right? I don't know how to get Exception message in English. Sorry about that.

8
  • 8
    Maybe if you actually printed out the exception instead of swallowing it and setting ok to false, you'd find out. Exception messages are often pretty useful, you know... Commented Jan 13, 2011 at 13:34
  • Must say, I prefer the sfdsgdfs.asd file naming convention, myself. Commented Jan 13, 2011 at 13:38
  • 2
    @Miko: It would have been helpful to include that information to start with though... especially as interop is involved. Although you don't need help identifying the exception, it makes it easier for people to help you if you tell them everything you know. (I would also argue against just catching Exception in the first place.) Commented Jan 13, 2011 at 14:23
  • I caught Exception to find out which sizes of Bitmap causes problems. And you are right. I should have told everything. Sorry about that. Commented Jan 13, 2011 at 14:29
  • What is the padding used for? Looks like it's the cause of the problem.. Commented Jan 13, 2011 at 14:52

3 Answers 3

3

It would be more useful instead of simply collecting 'ok' or 'not ok', to actually inspect the exception being thrown which will give you more information about what was actually not ok.

Try adding

Console.WriteLine(ex.ToString()); 

to the catch block.

Sign up to request clarification or add additional context in comments.

Comments

2

Try to calculate padding as

int padding = Math.Abs(bd.Stride) - (w * 3); 

(at least it is more readable)

And fix for BitmapDataAccessor:

public BitmapDataAccessor(byte[] data, int width, int height, int padding) { this.data = data; this.Height = height; // width in bytes, not pixels this.Width = width * 3 + padding; this.Padding = padding; rowStarts = new int[Height]; for(int y = 0; y < Height; y++) rowStarts[y] = y * Width; } public byte this[int x, int y, int color] { // row offsets already in bytes, so don't myltiply them by 3 get { return data[rowStarts[y] + x * 3 + color]; } set { data[rowStarts[y] + x * 3 + color] = value; } } 

Notes about 2nd problem:

Similar problem here - you calculate padding for pixels, not bytes.

int ww = w * 3; int padding = (4 - (ww % 4)) % 4; int bytes = (ww + padding) * h; byte[] rgbValues = new byte[bytes]; int rowOffset = 0; for (int j = 0; j < h; j++) { int pixelOffset = rowOffset; for (int i = 0; i < w; i++) { rgbValues[pixelOffset + 0] = tablica[i, j, 2]; rgbValues[pixelOffset + 1] = tablica[i, j, 1]; rgbValues[pixelOffset + 2] = tablica[i, j, 0]; pixelOffset += 3; } rowOffset += ww + padding; } 

2 Comments

added fix for BitmapDataAccessor also
Thanx. That works :). But a new there is a new proble. I'll write more about it in question.
1

Padding is not numer or pixels. It's number of bytes.
But still, I don't know how to fix your code. Maybe somebody else could do that?

1 Comment

That might be true :). Can anybody help?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.