2011-01-13 103 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

填充不是数字或像素。它是字节数。
但是,我仍然不知道如何修复你的代码。也许别人可以做到这一点?

相关问题