Bitmap x = new Bitmap(s.Width, s.Height);
Graphics g = Graphics.FromImage(x);
g.CopyFromScreen(0, 0, 0, 0, new Size(s.Width, s.Height), CopyPixelOperation.SourceCopy);
g.Dispose();
x.Save("x_before.png", ImageFormat.Png);
Graphics g1 = Graphics.FromImage(x);
g1.DrawImage(x); // to make sure the image is in g1 context
g1.CopyFromScreen(0, 0, 0, 0, new Size(s.Width, s.Height), CopyPixelOperation.SourceInvert);
g1.Dispose();
x.Save("x_after.png", ImageFormat.Png);
我将屏幕复制到位图中。 然后使用Invert XOR参数将同一个屏幕放入同一个位图。
1 xor 1 = 0
0 xor 0 = 0
0 xor 1 = 1
1 xor 0 = 1
结果应为黑色图像。但事实并非如此。
这是否意味着CopyPixelOperation.SourceInvert不起作用?
答案 0 :(得分:2)
这是否意味着CopyPixelOperation.SourceInvert不起作用?
是;我运行您提供的代码,并且发现CopyPixelOperation.SourceInvert
实际上并不像它所假设的那样工作。使用Reflector的进一步调查发现CopyFromScreen
方法在gdi32.dll
方法BitBlt
内部调用,可能是该方法中的错误。
更新:测试后,代码的结果应该是alpha图像,而不是黑色图像。 new Bitmap(s.Width, s.Height);
等于new Bitmap(s.Width, s.Height, PixelFormat.Format32bppArgb);
,因此结果是黑色图片,其中alpha设置为0,因此透明图像。但如果使用24位像new Bitmap(s.Width, s.Height, PixelFormat.Format24bppRgb);
我制作了替代代码,它正在使用unsafe
并使用PixelFormat.Format32bppArgb
或PixelFormat.Format24bppRgb
工作“如果您必须”
public unsafe static Bitmap ImageXOR(this Bitmap source, Bitmap destination)
{
#region Verification
if (destination == null)
{
throw new ArgumentNullException("newBitmap");
}
if (source.PixelFormat != destination.PixelFormat)
{
throw new ArgumentException("PixelFormat does not match");
}
if (source.Size != destination.Size)
{
throw new ArgumentException("Size does not match");
}
if (source.PixelFormat != PixelFormat.Format24bppRgb && source.PixelFormat != PixelFormat.Format32bppArgb)
{
throw new NotSupportedException(string.Format("Pixel format \"{0}\" not supported", source.PixelFormat));
}
#endregion//Verification
BitmapData sourceBitmapData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height),
ImageLockMode.ReadOnly, source.PixelFormat);
try
{
BitmapData destinationBitmapData = destination.LockBits(
new Rectangle(0, 0, destination.Width, destination.Height), ImageLockMode.ReadWrite, destination.PixelFormat);
try
{
int colorDepth = source.PixelFormat == PixelFormat.Format32bppArgb ? 4 : 3;
byte* sourceFirstPixelPhysicalAddress = (byte*)sourceBitmapData.Scan0.ToPointer();
byte* destinationFirstPixelPhysicalAddres = (byte*)destinationBitmapData.Scan0.ToPointer();
for (int heightIndex = 0; heightIndex < source.Height; heightIndex++)
{
for (int widthIndex = 0; widthIndex < sourceBitmapData.Width; widthIndex++)
{
byte* sourceRowPhysicalAddress = (byte*)sourceFirstPixelPhysicalAddress +
(heightIndex * sourceBitmapData.Stride);
byte* destinationRowPhysicalAddress = (byte*)destinationFirstPixelPhysicalAddres +
(heightIndex * destinationBitmapData.Stride);
int pixelPosition = widthIndex * colorDepth;
int indexOfBlue = 0 + pixelPosition;
int indexOfGreen = 1 + pixelPosition;
int indexOfRed = 2 + pixelPosition;
int indexOfAlpha = 3 + pixelPosition;
//get color values
//get blue
byte blue = (byte)((byte)sourceRowPhysicalAddress[indexOfBlue] ^ (byte)destinationRowPhysicalAddress[indexOfBlue]);
//get green
byte green = (byte)((byte)sourceRowPhysicalAddress[indexOfGreen] ^ (byte)destinationRowPhysicalAddress[indexOfGreen]);
//get red
byte red = (byte)((byte)sourceRowPhysicalAddress[indexOfRed] ^ (byte)destinationRowPhysicalAddress[indexOfRed]);
byte alpha = 0;
if (colorDepth > 3)
{
//get alpha
alpha = (byte)((byte)sourceRowPhysicalAddress[indexOfAlpha] ^ (byte)destinationRowPhysicalAddress[indexOfAlpha]);
}
//set blue
destinationRowPhysicalAddress[indexOfBlue] = blue;
//set green
destinationRowPhysicalAddress[indexOfGreen] = green;
//set red
destinationRowPhysicalAddress[indexOfRed] = red;
if (colorDepth > 3)
{
//set alpha
destinationRowPhysicalAddress[indexOfAlpha] = alpha;
}
}
}
}
finally
{
destination.UnlockBits(destinationBitmapData);
}
}
finally
{
source.UnlockBits(sourceBitmapData);
}
return destination;
}