我编写了这个函数的一个版本,它将灰度位图作为掩码和源位图,并使用SetPixel
和GetPixel
输出掩码,但是它非常慢,所以相反我尝试使用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
答案 0 :(得分: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 的返回值不准确(不确定)。
答案 1 :(得分:1)
您正在使用mask_data.Stride
两次(copy-n-paste错误)。
为什么在步幅上使用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)))