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