我有两个位图,一个包含“普通”图像,另一个包含灰度图像。
我的目标只是将灰度图像放在第一个位图的alpha通道中,以便像面具一样使用灰度图像。
我已经看到了一些使用SetPixel来做到这一点的解决方案,但由于内存分配错误,它很慢并且在最终图像上创建了一些奇怪的工件。
所以也许这样做的方法是浏览原始位图中的所有像素,并从alpha通道中的灰度位图中分配相应的像素。也许使用LockBits像素阵列?
所以我的问题是如何做到这一点?我特别难以找到如何在alpha通道中分配像素以及如何在灰度位图中获取相应的像素。
答案 0 :(得分:3)
这还没有使用LockBits,但它足够好看看它是否会让你想要你想要的东西:
public Bitmap getGrayOverlay(Bitmap bmpColor, Bitmap bmpGray)
{
Size s1 = bmpColor.Size;
Size s2 = bmpGray.Size;
if (s1 != s2) return null;
Bitmap bmpResult= new Bitmap(s1.Width, s1.Height);
for (int y = 0; y < s1.Height; y++)
for (int x = 0; x < s1.Width; x++)
{
Color c1 = bmpColor.GetPixel(x, y);
Color c2 = bmpGray.GetPixel(x, y);
bmpResult.SetPixel(x, y, Color.FromArgb((int)(255 * c2.GetBrightness()), c1 ) );
}
return bmpResult;
}
完成后使用所有三个位图!
这是LockBit版本,稍长一点,但基本相同。大约快10倍.. 我假设输入文件是24bppRGB或32bppARGB,否则它们返回null ..:
public Bitmap getGrayOverlayLBA(Bitmap bmp1, Bitmap bmp2)
{
Size s1 = bmp1.Size;
Size s2 = bmp2.Size;
if (s1 != s2) return null;
PixelFormat fmt1 = bmp1.PixelFormat;
PixelFormat fmt2 = bmp2.PixelFormat;
PixelFormat fmt = new PixelFormat();
fmt = PixelFormat.Format32bppArgb;
Bitmap bmp3 = new Bitmap(s1.Width, s1.Height, fmt);
Rectangle rect = new Rectangle(0, 0, s1.Width, s1.Height);
BitmapData bmp1Data = bmp1.LockBits(rect, ImageLockMode.ReadOnly, fmt1);
BitmapData bmp2Data = bmp2.LockBits(rect, ImageLockMode.ReadOnly, fmt2);
BitmapData bmp3Data = bmp3.LockBits(rect, ImageLockMode.ReadWrite, fmt);
byte bpp1 = 4;
byte bpp2 = 4;
byte bpp3 = 4;
if (fmt1 == PixelFormat.Format24bppRgb) bpp1 = 3;
else if (fmt1 == PixelFormat.Format32bppArgb) bpp1 = 4; else return null;
if (fmt2 == PixelFormat.Format24bppRgb) bpp2 = 3;
else if (fmt2 == PixelFormat.Format32bppArgb) bpp2 = 4; else return null;
int size1 = bmp1Data.Stride * bmp1Data.Height;
int size2 = bmp2Data.Stride * bmp2Data.Height;
int size3 = bmp3Data.Stride * bmp3Data.Height;
byte[] data1 = new byte[size1];
byte[] data2 = new byte[size2];
byte[] data3 = new byte[size3];
System.Runtime.InteropServices.Marshal.Copy(bmp1Data.Scan0, data1, 0, size1);
System.Runtime.InteropServices.Marshal.Copy(bmp2Data.Scan0, data2, 0, size2);
System.Runtime.InteropServices.Marshal.Copy(bmp3Data.Scan0, data3, 0, size3);
for (int y = 0; y < s1.Height; y++)
{
for (int x = 0; x < s1.Width; x++)
{
int index1 = y * bmp1Data.Stride + x * bpp1;
int index2 = y * bmp2Data.Stride + x * bpp2;
int index3 = y * bmp3Data.Stride + x * bpp3;
Color c1, c2;
if (bpp1 == 4)
c1 = Color.FromArgb(data1[index1 + 3], data1[index1 + 2], data1[index1 + 1], data1[index1 + 0]);
else c1 = Color.FromArgb(255, data1[index1 + 2], data1[index1 + 1], data1[index1 + 0]);
if (bpp2 == 4)
c2 = Color.FromArgb(data2[index2 + 3], data2[index2 + 2], data2[index2 + 1], data2[index2 + 0]);
else c2 = Color.FromArgb(255, data2[index2 + 2], data2[index2 + 1], data2[index2 + 0]);
byte A = (byte)(255 * c2.GetBrightness());
data3[index3 + 0] = c1.B;
data3[index3 + 1] = c1.G;
data3[index3 + 2] = c1.R;
data3[index3 + 3] = A;
}
}
System.Runtime.InteropServices.Marshal.Copy(data3, 0, bmp3Data.Scan0, data3.Length);
bmp1.UnlockBits(bmp1Data);
bmp2.UnlockBits(bmp2Data);
bmp3.UnlockBits(bmp3Data);
return bmp3;
}
编辑:我修改了代码以允许24bpp图像作为来源。