Getting blank image when trying to XOR two images

tarunlalwani

Member
Joined
Oct 14, 2007
Messages
7
Programming Experience
Beginner
I am trying to XOR two images to find there differences using BtiBlt. But the image i get is a blank one.

I am not sure why is this happening. Can anyone provide some insight on this?
VB.NET:
Private Sub XORImages(ByVal Src1 As String, ByVal Src2 As String)
        Dim oImage1 As Bitmap = Bitmap.FromFile(Src1)
        Dim oImage2 As Bitmap = Bitmap.FromFile(Src2)

        Dim oGfxImage1 As Graphics = Graphics.FromImage(oImage1)
        Dim oGfxImage2 As Graphics = Graphics.FromImage(oImage2)

        Dim oMixedImage As Bitmap = New Bitmap(oImage1.Width, oImage1.Height, oGfxImage1)

        Dim oGfxMixedImage As Graphics = Graphics.FromImage(oMixedImage)

        Dim hdcDest As IntPtr = oGfxMixedImage.GetHdc
        Dim hdcSrc1 As IntPtr = oGfxImage1.GetHdc
        Dim hdcSrc2 As IntPtr = oGfxImage2.GetHdc

        BitBlt(hdcDest, 0, 0, oMixedImage.Width, oMixedImage.Height, hdcSrc1, 0, 0, SRCCOPY)
        BitBlt(hdcDest, 0, 0, oMixedImage.Width, oMixedImage.Height, hdcSrc2, 0, 0, SRCINVERT)


        oGfxImage1.ReleaseHdc()
        oGfxImage2.ReleaseHdc()
        oGfxMixedImage.ReleaseHdc()

        oGfxMixedImage.Flush()

        oGfxMixedImage.Dispose()
        oGfxMixedImage = Nothing

        oGfxImage1.Dispose()
        oGfxImage1 = Nothing

        oGfxImage2.Dispose()
        oGfxImage2 = Nothing

        oMixedImage.Save("C:\mixed.jpg")
        oMixedImage.Dispose()
        oMixedImage = Nothing
    End Sub
 
The way you are doing it needs a bit of tweaking. Firstly you should be creating a ComapitbleDC and a CompaitibleBitmap (A HBitmap). Select the newly created HBitmap into the DC you have created. Then get the HBitmaps of the images you have using the GetHBitmap Method. Then you can BitBlt the images onto your new DC and finally BitBlt it to somewhere you'll be able to see it.
 
I tried tweaking the code to add those APIs but i get an exception
A call to PInvoke function 'ScreenCapture!ScreenCapture.Win32API::CreateCompatibleBitmap' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.

Dim hdcSrc1 As IntPtr = oGfxImage1.GetHdc
Dim hdcSrc2 As IntPtr = oGfxImage2.GetHdc

Dim hDCMem As Long, hBmp As Long

hDCMem = CreateCompatibleDC(hdcSrc1)
hBmp = CreateCompatibleBitmap(hdcDest, Width, Height)
SelectObject(hdcDest, hBmp)
BitBlt(hDCMem, 0, 0, Width, Height, hdcSrc1, 0, 0, SRCCOPY)
'BitBlt(hDCMem, 0, 0, oImage1.Width, oImage1.Height, hdcSrc2, 0, 0, SRCINVERT)

DeleteDC(hdcmem)

'Dim oMixedImage As Image = Image.FromHbitmap(hBmp)
oGfxImage1.ReleaseHdc()
oGfxImage2.ReleaseHdc()
oGfxMixedImage.ReleaseHdc()

I am not able to understand the issue? Is it becuase the HDC of the source is not from an Actual device?
 
Nope, it's becuase you shouldn't be using the Long datatype, in vb.net use int32 or integer. That's why the code you are using is unbalancing the stack.
 
Where Did We End Up With This BitBlt?

Ok, I guess I am just lost, or the solution never really presented itself. I am new to this whole BitBlt subject area, and I ran into a few other examples that I got the same result on. However, I will continue with this example. I do not get an error, but the saved file is just a blank image. Any ideas? VB 2005

VB.NET:
         Declare Auto Function BitBlt Lib "GDI32.DLL" ( _
        ByVal hdcDest As IntPtr, _
        ByVal nXDest As Integer, _
        ByVal nYDest As Integer, _
        ByVal nWidth As Integer, _
        ByVal nHeight As Integer, _
        ByVal hdcSrc As IntPtr, _
        ByVal nXSrc As Integer, _
        ByVal nYSrc As Integer, _
        ByVal dwRop As Int32) As Boolean

    Dim SRCCOPY As Double = &HCC0020
    Dim SRCINVERT As Double = &H5A0049L

    Declare Function CreateCompatibleDC Lib "Gdi32" (ByVal hdc As Long) As Integer

    Declare Function CreateCompatibleBitmap Lib "Gdi32" (ByVal hdc _
    As Long, ByVal nWidth As Long, _
    ByVal nHeight As Long) As Integer

    Declare Function DeleteDC Lib "Gdi32" (ByVal hdc As Long) As Long

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click

Dim oImage1 As Bitmap = Bitmap.FromFile("C:\Screen.jpeg")
        Dim oImage2 As Bitmap = Bitmap.FromFile("C:\Screen2.jpeg")

        Dim oGfxImage1 As Graphics = Graphics.FromImage(oImage1)
        Dim oGfxImage2 As Graphics = Graphics.FromImage(oImage2)

        Dim oMixedImage As Bitmap = New Bitmap(oImage1.Width, oImage1.Height, oGfxImage1)

        Dim oGfxMixedImage As Graphics = Graphics.FromImage(oMixedImage)

        Dim hdcDest As IntPtr = oGfxMixedImage.GetHdc
        Dim hdcSrc1 As IntPtr = oGfxImage1.GetHdc
        Dim hdcSrc2 As IntPtr = oGfxImage2.GetHdc

        Dim hDCMem As Integer
        Dim hBmp As Integer

        hDCMem = CreateCompatibleDC(hdcSrc1)
        hBmp = CreateCompatibleBitmap(hdcDest, Width, Height)
        SelectObject(hdcDest, hBmp)
        BitBlt(hDCMem, 0, 0, Width, Height, hdcSrc1, 0, 0, SRCCOPY)
        BitBlt(hDCMem, 0, 0, oImage1.Width, oImage1.Height, hdcSrc2, 0, 0, SRCINVERT)

        DeleteDC(hDCMem)

        'Dim oMixedImage As Image = Image.FromHbitmap(hBmp)
        oGfxImage1.ReleaseHdc()
        oGfxImage2.ReleaseHdc()
        oGfxMixedImage.ReleaseHdc()

        oMixedImage.Save("C:\mixed.jpeg")
        oMixedImage.Dispose()
        oMixedImage = Nothing

End Sub

Thanks in advance!
 
OK, so now I have changed the code to what I have found on the msdn forums so as to get the bitblt to work for a srccopy. Now I am trying to figure out how to compare the image with a previous image so as to figure out what has changed. I believe this can be done, from what I understand, the next questions is how.

Here is the code to get the simple bltbit to work for a srccopy should anyone be interested, or for newbies in this subject area who are having a little bit of trouble finding bltbit examples.

VB.NET:
Private Declare Function CreateDC Lib "gdi32" Alias "CreateDCA" (ByVal lpDriverName As String, _
      ByVal lpDeviceName As String, _
      ByVal lpOutput As String, _
      ByVal lpInitData As String) As Integer

    Private Declare Function CreateCompatibleDC Lib "GDI32" (ByVal hDC As Integer) As Integer

    Private Declare Function CreateCompatibleBitmap Lib "GDI32" (ByVal hDC As Integer, ByVal nWidth As Integer, ByVal nHeight As Integer) As Integer

    Private Declare Function GetDeviceCaps Lib "gdi32" Alias "GetDeviceCaps" (ByVal hdc As Integer, ByVal nIndex As Integer) As Integer

    Private Declare Function SelectObject Lib "GDI32" (ByVal hDC As Integer, ByVal hObject As Integer) As Integer

    Private Declare Function BitBlt Lib "GDI32" (ByVal srchDC As Integer, _
      ByVal srcX As Integer, _
      ByVal srcY As Integer, _
      ByVal srcW As Integer, _
      ByVal srcH As Integer, _
      ByVal desthDC As Integer, _
      ByVal destX As Integer, _
      ByVal destY As Integer, _
      ByVal op As Integer) As Integer

    Private Declare Function DeleteDC Lib "GDI32" (ByVal hDC As Integer) As Integer

    Private Declare Function DeleteObject Lib "GDI32" (ByVal hObj As Integer) As Integer

    Const SRCCOPY As Integer = &HCC0020


    Public Function CaptureScreen() As Bitmap

        Dim FW, FH As Integer

        Dim hSDC, hMDC As Integer

        Dim hBMP, hBMPOld As Integer

        Dim r As Integer

        hSDC = CreateDC("DISPLAY", "", "", "")

        hMDC = CreateCompatibleDC(hSDC)

        FW = GetDeviceCaps(hSDC, 8)

        FH = GetDeviceCaps(hSDC, 10)

        hBMP = CreateCompatibleBitmap(hSDC, FW, FH)

        hBMPOld = SelectObject(hMDC, hBMP)

        r = BitBlt(hMDC, 0, 0, FW, FH, hSDC, 0, 0, 13369376)
        
        hBMP = SelectObject(hMDC, hBMPOld)

        r = DeleteDC(hSDC)

        r = DeleteDC(hMDC)

        CaptureScreen = Image.FromHbitmap(New IntPtr(hBMP))

        DeleteObject(hBMP)

    End Function


    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim scrn As Bitmap

        Try

            scrn = CaptureScreen()

            scrn.Save("C:\test.jpeg", System.Drawing.Imaging.ImageFormat.Jpeg)

        Catch ex As Exception

            MsgBox(ex.Message)

        End Try
    End Sub

Like I said above, anyone have any idea how to get the comparison and display the differences of a first screenshot in this case, to a second?

Thanks in advance!
 
Last edited:
Ok, So I have found this code enabling me to to see how SRCCOPY and SRCINVERT works.

I am trying to send a screen capture and updates across the network.

Technically there are 3 images.
Image1 - The Original Image
Image2 - The Updated Image
Image3 - The Inverted Image of Image1 & Image2

I want to then send Image3 across the network to another computer.

The other computer will have Image1 from a previous network transfer. It will then do the following:
Take Image1 and Invert it with Image3 to get Image2.

This will enable the ability to compress the inverted image for transferring it across the network.

This is where I may be wrong:
I believe this needs to be done with GetDIBits, but thats where I am clueless. How do I correctly use GETDIBits to get a BYTE array that I can compress and transport it across the network.

The following code is what I was testing out the SRCCOPY and SRCINVERT functions.

VB.NET:
Declare Function GetDIBits Lib "gdi32" (ByVal aHDC As IntPtr, _
 ByVal hBitmap As IntPtr, _
ByVal nStartScan As Integer, _
ByVal nNumScans As Integer, _
ByVal lpBits As IntPtr, _
ByRef lpBI As BITMAPINFO, _
ByVal wUsage As Integer) As Integer
    
Private Declare Function CreateCompatibleBitmap Lib "GDI32" (ByVal hDC As IntPtr, _
ByVal nWidth As Integer, _
ByVal nHeight As Integer) As IntPtr

    Dim count As Integer = 0

    Public Structure BITMAPINFO
        Public bmiHeader As BITMAPINFOHEADER
        Public bmColors() As RGBTRIPLE
    End Structure

    Public Structure RGBTRIPLE
        Public rgbBlue As Byte
        Public rgbGreen As Byte
        Public rgbRed As Byte
    End Structure

    Public Structure BITMAPINFOHEADER
        Public biSize As Integer
        Public biWidth As Integer
        Public biHeight As Integer
        Public biPlanes As Integer
        Public biBitCount As Integer
        Public biCompression As Integer
        Public biSizeImage As Integer
        Public biXPelsPerMeter As Integer
        Public biYPelsPerMeter As Integer
        Public biClrUsed As Integer
        Public biClrImportant As Integer
    End Structure


    Private Const DIB_RGB_COLORS As Long = &H0 ' Colour table in RGBs

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'Dim bmp1 As New Bitmap(100, 50)
        'Dim bmp2 As New Bitmap(100, 50)
        'Dim g As Graphics = Graphics.FromImage(bmp1)
        'g.FillRectangle(Brushes.DeepSkyBlue, New RectangleF(0, 0, 100, 50))
        'g.Dispose()
        'g = Graphics.FromImage(bmp2)
        'g.FillRectangle(Brushes.DeepSkyBlue, New RectangleF(0, 0, 100, 50))
        'g.DrawString("Notbono wuz here", New Font("Arial", 8), Brushes.White, 2, 4)
        'g.Dispose()
        Dim bmp1 As Image = Image.FromFile("C:\RemoteHandImages\Screen.jpeg")
        Dim bmp2 As Image = Image.FromFile("C:\RemoteHandImages\Screen2.jpeg")
        PictureBox1.Image = bmp1
        PictureBox2.Image = bmp2

    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        'slow way, but fully .net
        Dim bmp1 As Bitmap = CType(PictureBox1.Image, Bitmap)
        Dim bmp2 As Bitmap = CType(PictureBox2.Image, Bitmap)

        Dim bmp3 As Bitmap = New Bitmap(bmp1.Width, bmp1.Height)


        Dim bmpData1 As Imaging.BitmapData = bmp1.LockBits( _
New Rectangle(0, 0, bmp1.Width, bmp1.Height), _
Imaging.ImageLockMode.ReadWrite, _
Imaging.PixelFormat.Format24bppRgb)
        Dim bmpData2 As Imaging.BitmapData = bmp2.LockBits( _
New Rectangle(0, 0, bmp2.Width, bmp2.Height), _
Imaging.ImageLockMode.ReadWrite, _
Imaging.PixelFormat.Format24bppRgb)
        Dim bmpData3 As Imaging.BitmapData = bmp3.LockBits( _
New Rectangle(0, 0, bmp3.Width, bmp1.Height), _
Imaging.ImageLockMode.ReadWrite, _
Imaging.PixelFormat.Format24bppRgb)
        Dim bytes As Integer = bmpData1.Stride * bmp1.Height

        Dim buffer1(bytes - 1), buffer2(bytes - 1), buffer3(bytes - 1) As Byte

        System.Runtime.InteropServices.Marshal.Copy(bmpData1.Scan0, buffer1, 0, bytes)
        System.Runtime.InteropServices.Marshal.Copy(bmpData2.Scan0, buffer2, 0, bytes)

        For i As Integer = 0 To buffer1.GetUpperBound(0)
            buffer3(i) = buffer1(i) Xor buffer2(i)
        Next

        System.Runtime.InteropServices.Marshal.Copy(buffer3, 0, bmpData3.Scan0, bytes)

        bmp1.UnlockBits(bmpData1)
        bmp2.UnlockBits(bmpData2)
        bmp3.UnlockBits(bmpData3)

        PictureBox3.Image = bmp3


    End Sub


    'Faster (?) API way
    Private Declare Auto Function BitBlt Lib "gdi32.dll" (ByVal _
        hdcDest As IntPtr, ByVal nXDest As Integer, ByVal _
        nYDest As Integer, ByVal nWidth As Integer, ByVal _
        nHeight As Integer, ByVal hdcSrc As IntPtr, ByVal nXSrc _
        As Integer, ByVal nYSrc As Integer, ByVal dwRop As _
        RasterOp) As Boolean

    Public Enum RasterOp
        SRCCOPY = &HCC0020
        PATINVERT = &H5A0049
        SRCINVERT = &H660046
    End Enum

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        CopyImage(PictureBox1, PictureBox3, RasterOp.SRCCOPY)
        CopyImage(PictureBox2, PictureBox3, RasterOp.SRCINVERT)
        
        'CopyImage(PictureBox1, PictureBox4, RasterOp.SRCCOPY)
        'CopyImage(PictureBox3, PictureBox4, RasterOp.SRCINVERT)

    End Sub

    Sub CopyImage(ByVal src As PictureBox, ByVal des As PictureBox, ByVal RasterOP As RasterOp)

        ' Get device context of source and destination picture boxes
        Dim srcHDC As IntPtr = src.CreateGraphics.GetHdc
        Dim desHDC As IntPtr = des.CreateGraphics.GetHdc


        ' Use api function
        BitBlt(desHDC, 0, 0, src.Width, _
        src.Height, srcHDC, 0, 0, RasterOP)


      
    End Sub

Thanks In Advance!
 
So I have been flipping through websites all day trying to figure out how to do this, and no luck yet. Now I am wondering if I want to getDIBits or CreateDIBSection. I'll check back in the morning to see if anyone has any input! Goodnight :confused:
 
Tarunlalwani,

Thanks for the input!!! I will check this out when I wake up in 7 hours. I was able to accomplish just about everything but was failing on SetDIBits. I am going to look at SetDIBits again in the morning, but may I have spent enough time with the seperate API's. I may just go with this nice looking API you have come up with for sending the differences of screen shots across a network connection. I will check it out in further detail in the morning.

Read your bio on the link you posted. LOL same year and zodiac sign here as well. So I don't give up as easily.

Thanks again, and goodnight for now!
 
Back
Top