Page 1 of 1

Sample pixel value under a transparent window?

Posted: Tue Apr 05, 2022 1:06 pm
by Cruster
Hi all.

I'm struggling with this and am hoping some kind soul might be able to point me in the correct direction.

I'd like to sample pixel values under a transparent window, code below. I think what's happening is I'm instead sampling the value of the transparent window itself, though that may not be the case!

Anyone have any ideas where I'm going wrong and how best I should go about this?

Many thanks in advance.

Code: Select all

;// ----------------------------------------------------------------------------------------------
;             Create a small transparent window and get the pixel value(s) under it 
;// ----------------------------------------------------------------------------------------------

Enumeration
#TransWin
#img
EndEnumeration

;// ----------------------------------------------------------------------------------------------
Procedure TransWin()
;// source: https://www.purebasic.fr/english/viewtopic.php?f=5&t=45362&hilit=+transparent
If OpenWindow(#TransWin, 0, 0, 144, 10, "Grab Window",#PB_Window_SystemMenu | #PB_Window_TitleBar | #PB_Window_ScreenCentered)

              SetWindowColor(#TransWin,#Blue)
              SetWindowLong_(WindowID(#TransWin), #GWL_EXSTYLE, #WS_EX_LAYERED | #WS_EX_TOPMOST)
              SetLayeredWindowAttributes_(WindowID(#TransWin),#Blue,0,#LWA_COLORKEY)

EndIf
EndProcedure                            
;// ----------------------------------------------------------------------------------------------              
              
              TransWin()                                            ;// Draw the transparent window
              CreateImage(#img, 144, 10, 32, #PB_Image_Transparent)
              StartDrawing(WindowOutput(#TransWin))
              
                    While (#True)                                   ;// just loop for now
                    Event = WindowEvent()                           ;// Non blocking wait for window event                     
                      If Event = #PB_Event_CloseWindow              ;// window closed ? if yes then exit program
                        Goto exit
                      EndIf
                        Debug  Point(1, 6)                          ;// sample pixel under transparent window at coord 1,6
                                                                    ;// draw a white line in middle of transparent window -
                                                                    ;// - to aid "lining up"
                        For i = 0 To 143 : Plot(i,5,RGB(255,255,255)) : Next      
                    Wend    

              StopDrawing()
                        
;// ----------------------------------------------------------------------------------------------
exit:
              StopDrawing()
              End
              
;// ----------------------------------------------------------------------------------------------

Re: Sample pixel value under a transparent window?

Posted: Tue Apr 05, 2022 1:49 pm
by infratec

Code: Select all

Procedure HBitmapFromScreen(X, Y, W, H)
  Protected HDC = GetDC_(0)
  Protected HBM = CreateCompatibleBitmap_(HDC, W, H)
  Protected PDC = CreateCompatibleDC_(HDC)
  SelectObject_(PDC, HBM)
  BitBlt_(PDC, 0, 0, W, H, HDC, X, Y, #SRCCOPY)
  DeleteDC_(PDC)
  ReleaseDC_(0, HDC)
  ProcedureReturn HBM
EndProcedure



OpenWindow(0, 0, 0, 400, 200, "Select your area", #PB_Window_SystemMenu|#PB_Window_SizeGadget|#PB_Window_ScreenCentered|#PB_Window_Tool)
SetWindowColor(0, #Blue)
SetWindowLong_(WindowID(0), #GWL_EXSTYLE, #WS_EX_LAYERED|#WS_EX_TOPMOST)
SetLayeredWindowAttributes_(WindowID(0), #Blue, 0, #LWA_COLORKEY)

Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow

x = WindowX(0, #PB_Window_InnerCoordinate)
y = WindowY(0, #PB_Window_InnerCoordinate)
w = WindowWidth(0)
h = WindowHeight(0)

ImageID = HBitmapFromScreen(x, y, w, h)
CloseWindow(0)

OpenWindow(0, 0, 0, w, h, "Selection was ...", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
CanvasGadget(0, 0, 0, w, h)
If StartDrawing(CanvasOutput(0))
  DrawImage(ImageID, 0, 0)
  StopDrawing()
EndIf


Repeat 
  Event = WaitWindowEvent()
  
  Select Event
    Case #PB_Event_Gadget
      Select EventGadget()
        Case 0
          If EventType() = #PB_EventType_LeftClick
            If StartDrawing(CanvasOutput(0))
              Debug RSet(Hex(Point(GetGadgetAttribute(0, #PB_Canvas_MouseX), GetGadgetAttribute(0, #PB_Canvas_MouseY))), 6, "0")
              StopDrawing()
            EndIf
          EndIf
     EndSelect
  EndSelect
Until Event = #PB_Event_CloseWindow

Re: Sample pixel value under a transparent window?

Posted: Tue Apr 05, 2022 2:16 pm
by infratec
Or more like that:

Code: Select all

Procedure HBitmapFromScreen(X, Y, W, H)
  Protected HDC = GetDC_(0)
  Protected HBM = CreateCompatibleBitmap_(HDC, W, H)
  Protected PDC = CreateCompatibleDC_(HDC)
  SelectObject_(PDC, HBM)
  BitBlt_(PDC, 0, 0, W, H, HDC, X, Y, #SRCCOPY)
  DeleteDC_(PDC)
  ReleaseDC_(0, HDC)
  ProcedureReturn HBM
EndProcedure



OpenWindow(0, 0, 0, 400, 200, "Select your area", #PB_Window_SystemMenu|#PB_Window_SizeGadget|#PB_Window_ScreenCentered|#PB_Window_Tool)
SetWindowColor(0, #Blue)
SetWindowLong_(WindowID(0), #GWL_EXSTYLE, #WS_EX_LAYERED|#WS_EX_TOPMOST)
SetLayeredWindowAttributes_(WindowID(0), #Blue, 0, #LWA_COLORKEY)

CanvasGadget(0, 0, 0, w, h)
HideGadget(0, #True)

PostEvent(#PB_Event_MoveWindow)

Repeat 
  Event = WaitWindowEvent()
  
  Select Event
    Case #WM_LBUTTONDOWN
      If StartDrawing(CanvasOutput(0))
        Debug RSet(Hex(Point(WindowMouseX(0), WindowMouseY(0))), 6, "0")
        StopDrawing()
      EndIf
      
    Case #PB_Event_MoveWindow, #PB_Event_SizeWindow
      x = WindowX(0, #PB_Window_InnerCoordinate)
      y = WindowY(0, #PB_Window_InnerCoordinate)
      w = WindowWidth(0)
      h = WindowHeight(0)
      ImageID = HBitmapFromScreen(x, y, w, h)
      ResizeGadget(0, 0, 0, w, h)
      If StartDrawing(CanvasOutput(0))
        DrawImage(ImageID, 0, 0)
        StopDrawing()
      EndIf
  EndSelect
Until Event = #PB_Event_CloseWindow
But I think it is easier to directly access the pixel via windows API commands.
Then no Gadget and drawing is needed.

Re: Sample pixel value under a transparent window?

Posted: Tue Apr 05, 2022 2:26 pm
by infratec

Code: Select all

OpenWindow(0, 0, 0, 400, 200, "Select your area", #PB_Window_SystemMenu|#PB_Window_SizeGadget|#PB_Window_ScreenCentered|#PB_Window_Tool)
SetWindowColor(0, #Blue)
SetWindowLong_(WindowID(0), #GWL_EXSTYLE, #WS_EX_LAYERED|#WS_EX_TOPMOST)
SetLayeredWindowAttributes_(WindowID(0), #Blue, 0, #LWA_COLORKEY)

Repeat 
  Event = WaitWindowEvent()
  
  Select Event
    Case #WM_LBUTTONDOWN
      HDC = GetDC_(0)
      Debug RSet(Hex(GetPixel_(HDC, WindowX(0, #PB_Window_InnerCoordinate) + WindowMouseX(0), WindowY(0, #PB_Window_InnerCoordinate) + WindowMouseY(0))), 6, "0")
      ReleaseDC_(0, HDC)
      
  EndSelect
  
Until Event = #PB_Event_CloseWindow

Re: Sample pixel value under a transparent window?

Posted: Tue Apr 05, 2022 3:49 pm
by Cruster
Infratec, thank you so much! :D

This -

Code: Select all

OpenWindow(0, 0, 0, 400, 200, "Select your area", #PB_Window_SystemMenu|#PB_Window_SizeGadget|#PB_Window_ScreenCentered|#PB_Window_Tool)
SetWindowColor(0, #Blue)
SetWindowLong_(WindowID(0), #GWL_EXSTYLE, #WS_EX_LAYERED|#WS_EX_TOPMOST)
SetLayeredWindowAttributes_(WindowID(0), #Blue, 0, #LWA_COLORKEY)


PostEvent(#PB_Event_MoveWindow)

Repeat 
  Event = WaitWindowEvent()
  
  Select Event
    Case #WM_LBUTTONDOWN
      HDC = GetDC_(0)
      Debug RSet(Hex(GetPixel_(HDC, WindowX(0, #PB_Window_InnerCoordinate) + WindowMouseX(0), WindowY(0, #PB_Window_InnerCoordinate) + WindowMouseY(0))), 6, "0")
      ReleaseDC_(0, HDC)
      
  EndSelect
  
Until Event = #PB_Event_CloseWindow
Is very much what I was after. I won't pretend to understand exactly how it works but it's doing what I was struggling with. It's given me the start I needed to get on with the rest of the code. Thank you! I'm making a screen recorder which will save RGB values along a line (144 pixels long) so that I can then display the recorded patterns on a string of WS2812B LEDs with an Arduino.