CopyPixelOperation.SourceInvert不起作用

时间:2011-07-17 21:49:36

标签: .net graphics gdi+

        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不起作用?

1 个答案:

答案 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.Format32bppArgbPixelFormat.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;
}