Results 1 to 7 of 7

Thread: GetPixel() replacement - read from a BITMAP buffer instead

  1. #1

    Thread Starter
    Junior Member
    Join Date
    Aug 2016
    Posts
    19

    GetPixel() replacement - read from a BITMAP buffer instead

    Currently I access the pixel color using the GetPixel() API, but it's awfully slow. To access 1000 pixels it takes ~31 secs!

    Code:
    Dim lngDC As Long, lngScreen As Long, lngColor As Long
    
    lngDC = GetDesktopWindow() ' the entire screen
    lngScreen = GetWindowDC(lngDC)
    lngColor = GetPixel(lngScreen, posX, posY) ' return COLORREF containing the RGB values
    ReleaseDC lngDC, lngScreen
    I want a replacement for GetPixel(), let's call it GetPixelB(), with "B" standing for Byte. I know it's possible to use GetDesktopWindow() and GDI+ to capture the entire screen to a BITMAP buffer in the memory, and then we can read the pixel color from this buffer, which is extremely efficient compared to the standard API. A replacement looks like this (pseudo-code):

    Code:
    Dim lngDC As Long, lngScreen  As Long, lngColor As Long
    
    lngDC = GetDesktopWindow() ' the entire screen
    lngScreen = GetWindowDC(lngDC)
    buffer = ScreenToBuffer(lngScreen) ' this is the sauce, so to speak
    ReleaseDC lngDC, lngScreen ' release it, reason: we already have the buffer to work with
    lngColor = GetPixelB(buffer, posX, posY)
    Two useful posts:
    https://www.vbforums.com/showthread....ll=1#post21100
    https://www.vbforums.com/showthread....=1#post5076067

    Can someone help me with this? I've been searching but I just can't put it together.

    PS: the lngColor of both GetPixel() and GetPixelB() must be equal when accessing the same pixel, after all, the new function is a replacement so compatibility in so far as result is concerned is a must.

  2. #2
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    6,514

    Re: GetPixel() replacement - read from a BITMAP buffer instead

    I know exactly how to do what you ask. Can't do it in a couple minutes though. I have to hunt down a bunch of constants, API declarations and structures to do it. The pains of VB6

    I'll check back on this thread later and if no one has given you a satisfactory solution, I'll go through my old VB6 projects and put together something for you. It's very easy to do in principle. It just requires a tonne of boiler plate code to do it.

    EDIT:

    The first link seems to have all the necessary boiler plate to do it but I like to test things myself. Don't have the time at this very moment but like I said, I'll try to help you a little later. Hopefully one of the VB6 regulars here already has something like this put together and can just post it for you before I get back.
    Last edited by Niya; Sep 15th, 2021 at 08:43 PM.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  3. #3

    Thread Starter
    Junior Member
    Join Date
    Aug 2016
    Posts
    19

    Re: GetPixel() replacement - read from a BITMAP buffer instead

    Thank you Niya. I reckon the links I provided are useful because I know more or less what is required, having done this with modern C++ in the past.

    Two things that are worth mentionting:

    .biCompression must be BI_RGB, which is uncompressed RGB.
    .biBitCount must be 32. In practice it can be 24, but would require padding. I think it's faster to use 32 which is the default color depth of the OS since Windows 8, although in the end only 24 is truly used, 8 for each of R, G, B. The alpha is left unused.

    Hope you or someone can help me out

    My app's routine speed will improve by, I guess, at least 20%. Currently it uses the GetPixel() API to read pixels from the screen, which is often static, so working with buffer is a huge improvement in this scenario where you don't need to update the buffer on every GetPixelB() call. When needed, I can simply update the buffer with ScreenToBuffer(), which is fast - less than 50ms with my screen resolution.

    I mention an improvement of at least 20% in my app's routine speed, but if we were to compare the two functions alone - the GetPixel() API vs this custom GetPixelB() function - then the latter is >1000x faster (!!!) but only if you are making hundreds or thousands of calls using the same buffer. I make hundreds before the buffer needs to be updated.
    Last edited by veloz; Sep 16th, 2021 at 01:10 AM.

  4. #4
    PowerPoster
    Join Date
    Jun 2013
    Posts
    5,625

    Re: GetPixel() replacement - read from a BITMAP buffer instead

    Quote Originally Posted by veloz View Post
    ...done this with modern C++ in the past.

    ...I can simply update the buffer with ScreenToBuffer(), which is fast - less than 50ms with my screen resolution.

    ...GetPixel() API vs this custom GetPixelB() function - then the latter is >1000x faster (!!!)
    Since you've done this in the past, and now report concrete performance-numbers,
    everything seems to be working fine already.

    So, if there's anything you need further help with, what is it exactly?

    Olaf

  5. #5
    PowerPoster
    Join Date
    Feb 2006
    Posts
    22,842

    Re: GetPixel() replacement - read from a BITMAP buffer instead

    Everything about this seems so scatterbrained. "From the screen?" Is this a Goggle Translate issue?

    Why wouldn't you just use GetDIBits() against the bitmap of the DC you want to pixel-peek?

    You ask for 32 bits/pixel so why would you name this thing GetPixelB()? GetPixelL() for "Long" might make a lot more sense.

    Or just return a 2D Long array from GetDIBits() and be all done.

  6. #6

    Thread Starter
    Junior Member
    Join Date
    Aug 2016
    Posts
    19

    Re: GetPixel() replacement - read from a BITMAP buffer instead

    @Schmidt

    That was for a modern C++ project, months ago. I was able to put it together with examples from the internet. I have been so far unable to do the same for my old VB6 project which I'm upgrading. I'm not a programmer and it's a high bar to port one language to another.

    @dilettante

    Sorry, English is not my native language. What you describe is what I think is the way to go. Using GetDIBits() against the bitmap of the DC. But how can I do it, and read the pixels with the custom GetPixelB() function as I would with GetPixel() API? It seems like a relatively straightforward process for people with experience, but I'm breaking my head over it.

  7. #7
    PowerPoster
    Join Date
    Feb 2006
    Posts
    22,842

    Re: GetPixel() replacement - read from a BITMAP buffer instead

    If you are starting with just the hDC you will probably have to fetch its selected hBitmap.


    So first create a junk hBitmap with CreateBitmap(), 1x1 pixel is probably good enough.

    Then use SelectObject() to make this the selected bitmap, getting back the hBitmap that the DC had originally.

    At that point you can call GetObject() on the de-selected hBitmap returned by SelectObject(), in order to get a BITMAP structure to get the dimensions from.

    Then you could ReDim a Pixels() As Long array with the width and height.

    Then you can call GetDIBits() to fill the Pixels() array.

    Finally call SelectObject to put the hBitmap back, and destroy the returned temporary hBitmap by calling DeleteObject() on it.


    That should be close, if not exactly the steps needed.


    As long as you used ReDim Pixels(.bmWidth , .bmHeight) you can use Pixels(X, Y) to get a pixel's color value.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width