Page 1 of 1

Read pixels from another program.

Posted: Sun Aug 25, 2024 5:29 pm
by matalog
How can I read pixels from whatever program that is displaying screen data on whatever part of the screen I instruct the program to look at?

For this project, reading a single pixel from a few sceeen coordinates will be fine.

I will eventually want an overlay to float above the pixels being read at the time.

Any ideas or similar projects?

Re: Read pixels from another program.

Posted: Sun Aug 25, 2024 5:54 pm
by Fig

Re: Read pixels from another program.

Posted: Sun Aug 25, 2024 7:05 pm
by matalog
Thanks, I was hoping for something that could read 9 individual pixels, in less than 1 millisecond. To be honest I only want to check if it is black or white (or close to either).

I saw the use of GetPixel_() in that thread, tried that out, and it takes around 18 milliseconds to get one single pixel's colour. I won't be able to use that.

I also see BitBlt being used, and said to be faster, but I don't really understand how it is used yet. Is it possible to quickly read one single pixels colour with BitBlt?

Re: Read pixels from another program.

Posted: Sun Aug 25, 2024 7:19 pm
by matalog
Would it be easier to do If I only wanted to read from a single window of another running program?

Re: Read pixels from another program.

Posted: Sun Aug 25, 2024 7:44 pm
by Fred
Just wondering, why do you need to read other programs pixels ?

Re: Read pixels from another program.

Posted: Sun Aug 25, 2024 8:25 pm
by matalog
Fred wrote: Sun Aug 25, 2024 7:44 pm Just wondering, why do you need to read other programs pixels ?
I'm planning a little visual communication setup - I have written the encoder program, which will make 8 boxes black or white depending if the bit of data is set, now I want to write a decoder, and I want the 2 to be seperate for various reasons.

I also plan to get a program to read the score or other data from a retro computer emulator during gameplay.

Re: Read pixels from another program.

Posted: Sun Aug 25, 2024 9:18 pm
by Fred
Looks cool 👍

Re: Read pixels from another program.

Posted: Sun Aug 25, 2024 10:23 pm
by BarryG
matalog wrote: Sun Aug 25, 2024 7:05 pmI saw the use of GetPixel_() in that thread, tried that out, and it takes around 18 milliseconds to get one single pixel's colour. I won't be able to use that.
Maybe try this non-threaded version (I haven't timed it). You can use Red(), Green() and Blue() on the result if needed; or for your black/white test the result will simply be #Black or #White.

Code: Select all

Procedure PixelColor(x,y)
  c=-1
  hDC=GetDC_(0)
  If hDC
    c=GetPixel_(hDC,x,y)
    ReleaseDC_(0,hDC)
  EndIf
  ProcedureReturn c
EndProcedure

Re: Read pixels from another program.

Posted: Sun Aug 25, 2024 10:34 pm
by Mr.L
I was just about to post a similar approach as BarryG.
Scanning 9 Pixels takes around 5 ms on my outdated Laptop...
(Activate the DPI-Aware switch)

Code: Select all

Define hwnd, hdc, pt.Point,p1.Point, rc.RECT, x, y
Define wid = 3, hig = 3,size = 50
Dim color(wid,hig)

OpenWindow(0,0,0,wid*size,hig*size,"", #PB_Window_Tool|#PB_Window_SystemMenu)
CanvasGadget(0,5,5,WindowWidth(0)-10,WindowHeight(0)-10)
StickyWindow(0, 1)

Repeat
	Define time = ElapsedMilliseconds()
	If pt\x <> DesktopMouseX() Or pt\y <> DesktopMouseY()
		pt\x = DesktopMouseX()
		pt\y = DesktopMouseY()
		
		hwnd = WindowFromPoint_(PeekQ(pt))
		If hwnd
			hdc = GetDC_(hwnd)
			If hdc
				For y = 0 To hig-1
					For x = 0 To wid-1
						p1\x = pt\x + x - wid/2
						p1\y = pt\y + y - hig/2
						If ScreenToClient_(hwnd , p1)
							color(x, y) = GetPixel_(hdc, p1\x, p1\y)
						EndIf
					Next
				Next
				ReleaseDC_(hwnd, hdc)
			EndIf
		EndIf	
		
		SetWindowTitle(0, Str(ElapsedMilliseconds() - time) + " ms")
		StartDrawing(CanvasOutput(0))
		For y = 0 To hig-1
			For x = 0 To wid-1
				Box(OutputWidth()/wid*x,OutputHeight()/hig*y,OutputWidth()/wid,OutputHeight()/hig,color(x,y))
			Next
		Next
		StopDrawing()
	EndIf
	
	While WindowEvent():If Event()=#PB_Event_CloseWindow:End:EndIf:Wend
ForEver

Re: Read pixels from another program.

Posted: Mon Aug 26, 2024 12:40 am
by matalog
Thanks, yes, the way you use GetPixel_() seems to be faster.

The pixel coordinates seem to be different from purebasic, coordinates, is that possible?

Re: Read pixels from another program.

Posted: Mon Aug 26, 2024 6:02 am
by Mr.L
the coordinates used in GetPixel_ are relative to the window (client area) rather than the entire screen. The origin (0, 0) in window coordinates is usually the top-left corner of the window's client area.
Therefore I use ScreenToClient_ to convert the screen coordinates (DesktopMouseX() / DesktopMouseY()) to the windows coordinates.
Also the DPI scaling affects the coordinates, that's why you have to enable the "Enable DPI aware executable" switch in the Compiler Options.

Re: Read pixels from another program.

Posted: Mon Aug 26, 2024 11:45 am
by matalog
Can you see why this is taking a much longer time in my program, I would like it to be a procedure:

Code: Select all

Global lastcol.i=1234,newcol.i=0,tot.i=0

Global Dim pi.i(9)
Procedure PixelColor(x,y)
  Shared pi
  c=-1
  hDC=GetDC_(0)
  If hDC
    For a=1 To 9
    pi(a)=GetPixel_(hDC,a*50-20+50,100)
    ;SetPixel_(hDC,a*50-20+1+50,100+1,255)
    Next
ReleaseDC_(0,hDC)
  EndIf
  ProcedureReturn c
EndProcedure


  
    StartTime.q = ElapsedMilliseconds()    
    PixelColor(0,0)
    newcol=pi(9)
 Debug ElapsedMilliseconds() - StartTime 
It seems to take around 150 ms to read the 9 pixels.

Re: Read pixels from another program.

Posted: Mon Aug 26, 2024 12:51 pm
by matalog
Nevermind, I got that just as fast as yours:

Code: Select all

Global lastcol.i=1234,newcol.i=0,tot.i=0
Define hwnd, hdc, pt.Point,p1.Point, rc.RECT, x, y
Define wid = 3, hig = 3,size = 50
Dim color(wid,hig)

Global Dim pi.i(9)
Procedure PixelColor(x,y)
  Shared pi,pt,pi
  c=-1
  hwnd = WindowFromPoint_(PeekQ(pt))
  hdc = GetDC_(hwnd)
  If hDC
    For a=1 To 9
    pi(a)=GetPixel_(hDC,a*50-20+50,100)
    ;SetPixel_(hDC,a*50-20+1+50,100+1,255)
    Next
ReleaseDC_(0,hDC)
  EndIf
  ProcedureReturn c
EndProcedure


  
    StartTime.q = ElapsedMilliseconds()    
    PixelColor(0,0)
    newcol=pi(9)
 Debug ElapsedMilliseconds() - StartTime 
   

Re: Read pixels from another program.

Posted: Mon Aug 26, 2024 9:45 pm
by matalog
To test if GetPixel_() works for what I want I have 2 programs here that should be run together. Their debugged output's should be the same if GetPixel_() was working as I expected.

What is causing the strangley randomly wrong debugged numbers in the first program?

Run the first program first, then, it will wait for the second program to be run, and both will print to debug windows.

The second program uses its own image and POINT to test the pixels, the first program uses GetPixel_() on the second program's image.

Code: Select all

Global lastcol.i=1234,newcol.i=0,tot.i=0
Define hwnd, hdc, pt.Point,p1.Point, rc.RECT
Define wid = 3, hig = 3,size = 50
Dim color(wid,hig)

Global Dim pi.i(9)
Procedure PixelColor(x,y)
  Shared pi,pt,pi,p1
  c=-1
  hwnd = WindowFromPoint_(PeekQ(pt))
  hdc = GetDC_(hwnd)
  If hDC
    For a=1 To 9
      p1\x=a*50+3+20
      p1\y=100+3
      ScreenToClient_(hwnd,p1)
      pi(a)=GetPixel_(hDC,p1\x,p1\y)
      SetPixel_(hDC,p1\x+1,p1\y+1,255)
      SetPixel_(hDC,p1\x+1,p1\y,255)
      SetPixel_(hDC,p1\x+1,p1\y-1,255)
      SetPixel_(hDC,p1\x,p1\y+1,255)
      SetPixel_(hDC,p1\x,p1\y-1,255)
      SetPixel_(hDC,p1\x-1,p1\y,255)
      SetPixel_(hDC,p1\x-1,p1\y+1,255)
      SetPixel_(hDC,p1\x-1,p1\y-1,255)
    Next
    ReleaseDC_(0,hDC)
  EndIf
  ProcedureReturn c
EndProcedure


Repeat
  
  PixelColor(0,0)
  newcol=pi(9)
  If newcol<>lastcol
    tot=tot+1
    temp=0
    For x=1 To 8
      power.i=1<<((x-1))
      temp=temp+Bool(pi(x)>10000)*power
    Next
    Debug temp
    
    lastcol=newcol
  EndIf
  
  
  
Until tot>60
And the second program.

Code: Select all

Global lastcol.i=1234,newcol.i=0,tot.i=0

#width=500
#height=900

OpenWindow(0,0,0,#width,#height,"Flash Bits")

CreateImage(0,#width,#height)
ImageGadget(0,0,0,#width,#height,ImageID(0))

Global byte.a=0
Global x.i=0
Global flip.a=0
Global temp.a=0

StartDrawing(ImageOutput(0))
Box(0,0,#width,#height,0)
Box(0,0,#width,#height,0)
StopDrawing()
SetGadgetState(0,ImageID(0))

For t=1 To 100
  byte=t
StartDrawing(ImageOutput(0))
For x=1 To 8
      power.i=1<<((x-1))
  Box(x*50,0,50,700,#White*Bool(byte & power))
Next
StopDrawing()
SetGadgetState(0,ImageID(0))
StartDrawing(ImageOutput(0))
Box(9*50,0,40,800,flip*#White)
If flip
  flip=0
Else
  flip=1
EndIf
temp=0

For x=1 To 8
  power.i=Pow(2,x-1)
  temp=temp+Bool(Point(x*50+2,100+2)>10000)*power
Next
s$="Point()= "+Str(temp)
Debug s$
StopDrawing()
SetGadgetState(0,ImageID(0))
  Event =WindowEvent()
  Select Event
    Case #PB_Event_CloseWindow
      End
  EndSelect
Delay(1000)
Next
Repeat
 
  Event =WindowEvent()
  Select Event

    Case #PB_Event_CloseWindow
      End
  EndSelect
  


Until 0
End