CopyPixelOperation.SourceInvert не работает - PullRequest
3 голосов
/ 18 июля 2011
        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 Ответ

2 голосов
/ 19 июля 2011

Означает ли это, что CopyPixelOperation.SourceInvert не работает?

Да;Я запускаю код, который вы предоставили, и обнаружил, что CopyPixelOperation.SourceInvert на самом деле не работает так, как предполагалось.Дальнейшие исследования с использованием Reflector показали, что метод CopyFromScreen является внутренним вызовом метода gdi32.dll BitBlt, возможно, это ошибка в этом методе.

Обновление: После проверки результатавашего кода должно быть альфа-изображение, а не черное изображение.new Bitmap(s.Width, s.Height); равно new Bitmap(s.Width, s.Height, PixelFormat.Format32bppArgb);, поэтому в результате получается черное изображение с альфа-значением, установленным на 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;
}
...