0

Would like your opinion and support on an issue i am trying to overcome. This will be the last piece of puzzle for completion of a small project i am building. Its based on OCR. I am reading text from a live screen ( using below python script ) and able to get the results logged into a file. However, the output is only getting logged once i make the python console window ( in which the script prints the output ) is active/focused by keyboad using alt+tab.

But doing this halts the software from where i am reading the text, breaking the whole process. Toggling the window to the front of the software is a failure to the scripts purpose.

So, i added code after searching from other users about keeping the python console window on top always no matter what the software is doing. I am not able to keep this python console window on top of this sw screen. The SW uses all screen for its purpose of work.

Is there an alternative to this? How can i make the python console become on top of any other window no matter what is on the screen? If not this, please suggest an alternative.

import numpy as nm
from datetime import datetime
import pytesseract
import cv2
import PIL
from PIL import ImageGrab
import win32gui, win32process, win32con
import os

hwnd = win32gui.GetForegroundWindow()
win32gui.SetWindowPos(hwnd,win32con.HWND_TOPMOST,0,0,100,300,0) 

#Define function for OCR to enable on multiple screens. 
def imToString(): 

    # Path of tesseract executable
    pytesseract.pytesseract.tesseract_cmd ='C:\\Tesseract-OCR\\tesseract.exe'
    while(True):


        # ImageGrab-To capture the screen image in a loop.
        # Bbox used to capture a specific area.

        #screen base
        cap1 = PIL.ImageGrab.grab(bbox =(0, 917, 1913, 1065), include_layered_windows=False, all_screens=True)
        date = datetime.now().strftime("%Y-%m-%d %I:%M:%S")    
        #str config - OCR Engine settings for ONLY text based capture.
        config1 = ('-l eng --oem 2 --psm 6')


        #configuring tesseract engine for OCR 
        tess1 = pytesseract.image_to_string(
                cv2.cvtColor(nm.array(cap1), cv2.COLOR_BGR2GRAY),
                config=config1)
    

        #Defining log pattern to generate
        a = [ date, " State: ", tess1 ]


        #writing logging output to file
        file1 = open("C:\\Users\\User\\Desktop\\rev2.log", "a", encoding='UTF8')
        file1.writelines(a)
        file1.writelines("\n")
        file1.close()                                       

        #OUTPUT on colse for Logging verification
        print (date, "State: ", tess1)  
                                



 # Calling the function
imToString()

By requirement, i am not allowed to use a keyboad while operating the screen. I am fairly new to python and have been seeing similar solutions and adding it to the script to make a proper solution.

Please advise.

MattDMo
  • 100,794
  • 21
  • 241
  • 231
Number13
  • 3
  • 4
  • the only thing I can imagine in case it is not possible with console is to use `tkinter` and `subprocess`, start a new process with this file and stream data to tkitner window (using .after()) and set the tkinter to "-topmost", True and even then it may not work if the other program is fullscreen, tho at least could try (not that much code) – Matiiss Aug 13 '21 at 11:56
  • yes, the other SW running is full screen by default once it launches. Could you think of any workaround for this? My last resort is to keep this console in a small resized window, somewhere on the bottom of the screen where there's some space which isn't noticeable. But still, that would require to be ALWAYS ON TOP no matter what. – Number13 Aug 13 '21 at 12:54
  • I can try writing the tkinter code (it will be simple for you to run it (just specify filename and place the tkinter code in the same directory)) but I can't guarantee that it will always stay on top (it certainly will stay on top of windowed apps, otherwise hard to tell) – Matiiss Aug 13 '21 at 13:05
  • yes please, i wanna give it a shot. – Number13 Aug 13 '21 at 13:32

1 Answers1

0

Here is the tkinter method:

from tkinter import Tk, Text
import subprocess
import threading
from queue import Queue, Empty


filename = 'test.py'


def stream_from(queue):
    command = f'python {filename}'
    with subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as process:
        for out in process.stdout:
            queue.put(out.decode())


def update_text(queue):
    try:
        data = queue.get(block=False)
    except Empty:
        pass
    else:
        text.config(state='normal')
        text.insert('end', data.strip() + '\n')
        text.config(state='disabled')
    finally:
        root.after(100, update_text, queue)


def loop():
    root.attributes('-topmost', True)
    root.after(1, loop)


root = Tk()


text = Text(root, state='disabled')
text.pack()

data_queue = Queue()
threading.Thread(target=stream_from, args=(data_queue, ), daemon=True).start()
update_text(data_queue)

loop()

root.mainloop()

Just change the filename to the name of the file you are running and place this script in the same directory
Change delay_in_ms (delay in milliseconds so each 1000 units is one second) and see if that helps (could also leave the 10 seconds and see if it works now, if not there is still another thing to try)

If you are using print to output then this should work (tho I maybe didn't exactly get what you want), if you use logging then there is a slightly different solution

Matiiss
  • 5,970
  • 2
  • 12
  • 29
  • Gives me the same results. About your question on the exactly what i want, this python console should be on top of the SW to read the screen. Currently, it is shifting to background once the SW opens to screen. – Number13 Aug 13 '21 at 15:06
  • [this says something very sad](https://stackoverflow.com/questions/17131857/python-windows-keep-program-on-top-of-another-full-screen-application) – Number13 Aug 13 '21 at 15:08
  • @Number13 ok, I read it and it said that the window that last asks to be topmost will be topmost so you can add a delay as to when the root window is topmost so that it becomes that after the other window becomes fullscreen (at least try) – Matiiss Aug 13 '21 at 15:53
  • @Number13 I edited the answer, try running it now (a minor change really, but maybe helps) if this doesn't work then also could try using loops. (also currently it is gonna be set topmost after 10 seconds so during that period it will not be topmost (can change delay if this worked otherwise will try loops)) – Matiiss Aug 13 '21 at 16:01
  • Same result again. I am thinking of taking a different approach to this. How about using the hwnd. Like can we tell the script to make this window with this title to always be on top of whatever currently is? I tried using hwnd = "C:\WINDOWS\py.exe" but it keeps on giving me error. Also, while testing, i am running the script from cmd, that means the hwnd will change again to get the title. IS this something doable? – Number13 Aug 13 '21 at 16:30
  • @Number13 I have no idea about `hwnd` (I don't even know what it is) but I edited code to include the final attempt from tkinter to try making this possible, if this doesn't work then I am currently out of ideas (because my only ideas were these related to `tkinter`) – Matiiss Aug 13 '21 at 16:33
  • Sorry to say, this didn't work. But i found something strange, sleep(30) hwnd = win32gui.GetForegroundWindow() win32gui.SetWindowPos(hwnd,win32con.HWND_TOP,0,0,500,500,0) when i add sleep(30) like this to the code as above, the script is starting after 30s and taking the SW Fullscreen and making it it ON TOP with 500x500 dimensions. – Number13 Aug 13 '21 at 16:42
  • @Number13 ok, tho I can't really say anything about it because as I already mentioned I have no knowledge about that module (except I can read what the function is called so I can guess what it does but so far I understand that you have partially succeeded) – Matiiss Aug 13 '21 at 16:55
  • Thanks but will need to post another question to borrow some knowledge on that subject. I upvoted your answer but unfortunately, I am new to forum and not yet eligible to make it. Appreciated your support on this. – Number13 Aug 13 '21 at 17:02