2012-12-24 19 views
1

我写了一个这个函数的版本,它将灰度位图作为蒙板和源位图,并输出一个位图,其中应用了蒙板SetPixelGetPixel,但速度很慢,所以改为我试图写一个使用BitmapData和指针算术,但我得到一个访问冲突,我不知道为什么。在图像蒙板中使用BitmapData访问冲突

当写入结果位图中的像素时,我得到一个AccessViolationException - 我认为这是由不正确的索引造成的,但我看不到我出错的地方。

public static Bitmap ApplyAlphaMask2(Bitmap source, Bitmap mask) 
{ 
    if (source.Size != mask.Size) 
    { 
     throw new NotImplementedException("Applying a mask of a different size to the source image is not yet implemented"); 
    } 
    Bitmap result = new Bitmap(source.Width, source.Height); 
    unsafe 
    { 
     BitmapData source_data = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); 
     BitmapData mask_data = mask.LockBits(new Rectangle(0, 0, mask.Width, mask.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); 
     BitmapData result_data = result.LockBits(new Rectangle(0, 0, result.Width, result.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); 
     for(int column = 0; column < source.Height; column++) 
     { 
      Int32* source_column_ptr = (Int32*)source_data.Scan0 + (column * Math.Abs(source_data.Stride)); 
      Int32* mask_column_ptr = (Int32*)mask_data.Scan0 + (column * Math.Abs(mask_data.Stride)); 
      Int32* result_column_ptr = (Int32*)result_data.Scan0 + (column * Math.Abs(mask_data.Stride)); 
      for (int row = 0; row < source.Width; row++) 
      { 
       Color source_color = Color.FromArgb(source_column_ptr[row]); 
       Color mask_color = Color.FromArgb(mask_column_ptr[row]); 
       Int32* result_pixel_ptr = &result_column_ptr[row]; 
       Color result_color = Color.FromArgb((int)(255.0f * mask_color.GetBrightness()), source_color); 
       *result_pixel_ptr = result_color.ToArgb(); //Access violation! 
      } 
     } 
     source.UnlockBits(source_data); 
     mask.UnlockBits(mask_data); 
     result.UnlockBits(result_data); 
    } 
    return result; 
} 

任何帮助,将不胜感激。

编辑:这并不总是发生在同一列,但该行始终显示为0

回答

1

您正在使用mask_data.Stride两次(复制粘贴错误)。

你为什么在步伐上使用Math.Abs?大步是否定的?这可能意味着图像是从下到上编码的,而采用abs值会破坏这些信息。


编辑:问题就在这里:

(Int32*)source_data.Scan0 + (column * Math.Abs(source_data.Stride)) 

您添加(column * Math.Abs(source_data.Stride))int*这意味着你得到4倍的偏移量,你需要的。您可能打算:

(Int32*)((byte*)source_data.Scan0 + (column * Math.Abs(source_data.Stride))) 
+0

仅使用Math.Abs​​是因为示例显示它在此msdn页面上使用:http://msdn.microsoft.com/zh-cn/library/system。 drawing.imaging.bitmapdata.aspx另外,从'mask_data.Stride'改为'result_data.Stride'没有帮助:/ – Ell

+0

步幅是否定的?请检查所有3个步骤。尝试没有吸收。该示例仅使用Abs分配空间,而不是“导航”现有缓冲区。 – usr

+0

@所有文档都包含以下语句:“跨度是单行像素(扫描线)的宽度,四舍五入为四字节边界。如果跨度为正,则位图为自上而下。如果步幅是负值,则位图是自下而上的。“所以这似乎是错误 - 位图是自下而上的。 – usr

1

顺便说一句,你的变量名是错误的...需要交换他们!
请尝试下列修改。 未经测试!

public static Bitmap ApplyAlphaMask2(Bitmap source, Bitmap mask) 
    { 
     int x, y; 
     Color mask_color; 

     if (source.Size != mask.Size) 
     { 
      throw new NotImplementedException("Applying a mask of a different size to the source image is not yet implemented"); 
     } 
     Bitmap result = new Bitmap(source.Width, source.Height, PixelFormat.Format32bppArgb); 
     BitmapData source_data = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); 
     BitmapData mask_data = mask.LockBits(new Rectangle(0, 0, mask.Width, mask.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); 
     BitmapData result_data = result.LockBits(new Rectangle(0, 0, result.Width, result.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); 
     unsafe 
     { 
      Int32* source_line_ptr = (Int32*)source_data.Scan0; 
      Int32* mask_line_ptr = (Int32*)mask_data.Scan0; 
      Int32* result_line_ptr = (Int32*)result_data.Scan0; 
      for (y = 0; y < source.Height; y++) 
      { 
       for (x = 0; x < source.Width; x++) 
       { 
        mask_color = Color.FromArgb(mask_line_ptr[x]); 
        result_line_ptr[x] = ((int)(mask_color.GetBrightness() * 255.0f) << 24) | (source_line_ptr[x] & 0xFFFFFF); 
       } 
       source_line_ptr += source_data.Stride; 
       mask_line_ptr += mask_data.Stride; 
       result_line_ptr += result_data.Stride; 
      } 
      source.UnlockBits(source_data); 
      mask.UnlockBits(mask_data); 
      result.UnlockBits(result_data); 
     } 
     return result; 
    } 

我不知道你会得到预期的结果无论如何,因为GDI +与灰度图像的问题(如果我没记错的话,如果你申请LockBits它返回一个灰度图像图像16灰度,而不是256)。
另一件事是如果你想优化你的代码,你不应该在循环内声明局部变量。
最后,我认为返回的值Color.GetBrightness不准确(不确定这一点)。

+0

只有命名不正确。实际的代码在这个问题上是正确的。 – usr

+0

@usr我在谈论什么_columns_和_rows_是混淆。没有什么关于这是一个编程错误,只是一种误解(所以'..._ column_ptr'名字也是错误的)。 – Jigsore

+0

设置结果指针时,仍会导致访问冲突:/ – Ell