2011-01-13 267 views
1

有一些代碼:爲什麼我不斷收到異常?

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; 
} 

這是我的測試運行:

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; 
} 

輸出:

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

爲什麼我得到w % 4 ==1或​​異常?

編輯:
我知道什麼是例外。它是'指數越界',它發生在
get { return data[(rowStarts[y] + x) * 3 + color]; }
不幸的是我不知道如何避免這種情況,爲什麼只發生在w % 4 ==1或​​。這就是我發佈我的問題的原因。我不需要識別異常或處理它的幫助。我只需要修復BitmapDataAccessor和/或Bitmap2Byte以使其工作。

編輯2: 感謝max的回答Bitmap2Byte不會拋出異常。但是,這使我的其他功能Byte2Bitmap拋出異常:

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; 
    } 

而且我的輸出,以顯示其寬度有例外:在線路發生

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 

例外:
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
及其文本方式:There was try to read or write to/from protected memory...
我認爲這是因爲bytes計算不正確。我該如何做到這一點? 我不知道如何獲得英文的異常信息。對於那個很抱歉。

+8

也許如果你真的打印出異常而不是吞嚥它並將其設置爲false,你會發現。異常消息通常非常有用,你知道... – 2011-01-13 13:34:57

+0

必須說,我更喜歡`sfdsgdfs.asd`文件命名約定,我自己。 – 2011-01-13 13:38:00

+0

`lalala.txt`很好玩的名字:P – 2011-01-13 14:02:39

回答

3

嘗試計算填充作爲

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

(至少它更可讀的)

並修復爲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; } 
} 

大約第二問題備註:

類似問題在這裏 - 你計算填充像素,而不是字節。

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; 
} 
3

它會更有用,而不是簡單地收集'ok'或'not ok',以實際檢查拋出的異常,這會給你更多關於什麼是不正確的信息。

嘗試增加

Console.WriteLine(ex.ToString()); 

catch塊。

1

填充不是數字或像素。它是字節數。
但是,我仍然不知道如何修復你的代碼。也許別人可以做到這一點?

相關問題