Hello.
I like the addon but it has some bugs that cause erratic behavior.
When I try to recognize a file on the desktop two things happen:
1. If this is the first time a file is recognized, it says "file not supported" (tested with PDF and BMP file types). The same file recognized from a folder in Windows explorer works fine.
2. If another file has been recognized before, it process any file even if it is not of a supported type. In any case, supported type or not, it always shows the result of the previous recognition, not the requested file. Even after manually deleting the oc.txt and ocr-xxx.png files from the addon's images folder, it re-processes the previously requested file.
None of the above shows any messages or errors in the log.
On the other hand, recognition from scanner does not work for me. My scanner is HP Scanjet G2410, It may not be supported but the addon does not speak any message about it. The thread that processes this remains active and never terminates. If the script is executed again, another thread is launched that also remains active and so on forever. It is normal for the user, if he does not receive a response, to try to run it again, so you can end up with a lot of active threads.
I have the habit of naming the treads that I use to be able to debug better with threading.enumerate(). I have added the line to __init__.py self._thread.name = "tesseractOCR" before starting the thread to do these tests.
finally, in terms of user experience, I think you need to give more information about what is happening. Sometimes, if the recognition takes time, the user does not know if it is working correctly or not.
Greetings.
Javi Dominguez
|
|
Hola Javi! Comments in midle of your message marked with *... Às 18:47 de 05/06/2022, Javi Domínguez escreveu: When I try to recognize a file on the desktop two things happen:
1. If this is the first time a file is recognized, it says "file not supported" (tested with PDF and BMP file types). The same file recognized from a folder in Windows explorer works fine. * It is a limitation of the routine to get the complete path of the file... If you can help bettering the routine, I will be glad! 2. If another file has been recognized before, it process any file even if it is not of a supported type. In any case, supported type or not, it always shows the result of the previous recognition, not the requested file. Even after manually deleting the oc.txt and ocr-xxx.png files from the addon's images folder, it re-processes the previously requested file.
* It was an error on code... The path of last document was not cleared, so list of ocr-xxx.png file was created again...
On the other hand, recognition from scanner does not work for me. My scanner is HP Scanjet G2410, It may not be supported but the addon does not speak any message about it. The thread that processes this remains active and never terminates. If the script is executed again, another thread is launched that also remains active and so on forever. It is normal for the user, if he does not receive a response, to try to run it again, so you can end up with a lot of active threads.
* The scanner is recognized as WIA compatible? * What Windows version? I have the habit of naming the treads that I use to be able to debug better with threading.enumerate(). I have added the line to __init__.py self._thread.name = "tesseractOCR" before starting the thread to do these tests.
* So, I should name each thread differently... * And, before starting another thread, verify if it is active, right? finally, in terms of user experience, I think you need to give more information about what is happening. Sometimes, if the recognition takes time, the user does not know if it is working correctly or not.
* It is schedulled for next version... Thanks! Rui Fontes
|
|
Hello. * It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad! OK. I'll take a look at that. * The scanner is recognized as WIA compatible? what do you mean with "is recognized as WIA compatible"? Yes, the scanner is WIA compliant, other apps recognize it but the addon I don't know, it just doesn't do anything. * What Windows version? Windows 10 21H2 (x64) build 19044.1706 * So, I should name each thread differently... Yes, it would be convenient. * And, before starting another thread, verify if it is active, right? I think so. I would wait for the current thread to finish before starting another. Note that if you assign the new thread to self._thread, the old thread will continue to run until it finishes but you will no longer have a reference to it. You will only be able to access it via threading.enumerate(). You may need a method to kill threads that are stuck or taking too long. Greetings Javi El 05/06/2022 a las 20:34, Rui Fontes escribió: Hola Javi!
Comments in midle of your message marked with *...
Às 18:47 de 05/06/2022, Javi Domínguez escreveu:
When I try to recognize a file on the desktop two things happen:
1. If this is the first time a file is recognized, it says "file not supported" (tested with PDF and BMP file types). The same file recognized from a folder in Windows explorer works fine. * It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad!
2. If another file has been recognized before, it process any file even if it is not of a supported type. In any case, supported type or not, it always shows the result of the previous recognition, not the requested file. Even after manually deleting the oc.txt and ocr-xxx.png files from the addon's images folder, it re-processes the previously requested file.
* It was an error on code... The path of last document was not cleared, so list of ocr-xxx.png file was created again...
On the other hand, recognition from scanner does not work for me. My scanner is HP Scanjet G2410, It may not be supported but the addon does not speak any message about it. The thread that processes this remains active and never terminates. If the script is executed again, another thread is launched that also remains active and so on forever. It is normal for the user, if he does not receive a response, to try to run it again, so you can end up with a lot of active threads.
* The scanner is recognized as WIA compatible?
* What Windows version?
I have the habit of naming the treads that I use to be able to debug better with threading.enumerate(). I have added the line to __init__.py self._thread.name = "tesseractOCR" before starting the thread to do these tests.
* So, I should name each thread differently...
* And, before starting another thread, verify if it is active, right?
finally, in terms of user experience, I think you need to give more information about what is happening. Sometimes, if the recognition takes time, the user does not know if it is working correctly or not.
* It is schedulled for next version...
Thanks!
Rui Fontes
|
|
Hello again.
I have run wia-cmd-scanner.exe directly from the command line, in the Windows CMD, and it has worked perfectly.
However from the addon it doesn't work. stderr shows:
b'The system cannot find the specified path.\r\n'
I hope this helps. It's late and I can't do any more research. Tomorrow dawns very early.
Good nitht
Javi
toggle quoted messageShow quoted text
El 05/06/2022 a las 22:24, Javi Domínguez via groups.io escribió: Hello.
* It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad! OK. I'll take a look at that.
* The scanner is recognized as WIA compatible? what do you mean with "is recognized as WIA compatible"? Yes, the scanner is WIA compliant, other apps recognize it but the addon I don't know, it just doesn't do anything.
* What Windows version? Windows 10 21H2 (x64) build 19044.1706
* So, I should name each thread differently... Yes, it would be convenient.
* And, before starting another thread, verify if it is active, right? I think so. I would wait for the current thread to finish before starting another.
Note that if you assign the new thread to self._thread, the old thread will continue to run until it finishes but you will no longer have a reference to it. You will only be able to access it via threading.enumerate().
You may need a method to kill threads that are stuck or taking too long.
Greetings
Javi
El 05/06/2022 a las 20:34, Rui Fontes escribió:
Hola Javi!
Comments in midle of your message marked with *...
Às 18:47 de 05/06/2022, Javi Domínguez escreveu:
When I try to recognize a file on the desktop two things happen:
1. If this is the first time a file is recognized, it says "file not supported" (tested with PDF and BMP file types). The same file recognized from a folder in Windows explorer works fine. * It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad!
2. If another file has been recognized before, it process any file even if it is not of a supported type. In any case, supported type or not, it always shows the result of the previous recognition, not the requested file. Even after manually deleting the oc.txt and ocr-xxx.png files from the addon's images folder, it re-processes the previously requested file.
* It was an error on code... The path of last document was not cleared, so list of ocr-xxx.png file was created again...
On the other hand, recognition from scanner does not work for me. My scanner is HP Scanjet G2410, It may not be supported but the addon does not speak any message about it. The thread that processes this remains active and never terminates. If the script is executed again, another thread is launched that also remains active and so on forever. It is normal for the user, if he does not receive a response, to try to run it again, so you can end up with a lot of active threads.
* The scanner is recognized as WIA compatible?
* What Windows version?
I have the habit of naming the treads that I use to be able to debug better with threading.enumerate(). I have added the line to __init__.py self._thread.name = "tesseractOCR" before starting the thread to do these tests.
* So, I should name each thread differently...
* And, before starting another thread, verify if it is active, right?
finally, in terms of user experience, I think you need to give more information about what is happening. Sometimes, if the recognition takes time, the user does not know if it is working correctly or not.
* It is schedulled for next version...
Thanks!
Rui Fontes
|
|
toggle quoted messageShow quoted text
El 05/06/2022 a las 23:01, Javi Domínguez via groups.io escribió: Hello again.
I have run wia-cmd-scanner.exe directly from the command line, in the Windows CMD, and it has worked perfectly.
However from the addon it doesn't work. stderr shows:
b'The system cannot find the specified path.\r\n'
I hope this helps. It's late and I can't do any more research. Tomorrow dawns very early.
Good nitht
Javi
El 05/06/2022 a las 22:24, Javi Domínguez via groups.io escribió:
Hello.
* It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad! OK. I'll take a look at that.
* The scanner is recognized as WIA compatible? what do you mean with "is recognized as WIA compatible"? Yes, the scanner is WIA compliant, other apps recognize it but the addon I don't know, it just doesn't do anything.
* What Windows version? Windows 10 21H2 (x64) build 19044.1706
* So, I should name each thread differently... Yes, it would be convenient.
* And, before starting another thread, verify if it is active, right? I think so. I would wait for the current thread to finish before starting another.
Note that if you assign the new thread to self._thread, the old thread will continue to run until it finishes but you will no longer have a reference to it. You will only be able to access it via threading.enumerate().
You may need a method to kill threads that are stuck or taking too long.
Greetings
Javi
El 05/06/2022 a las 20:34, Rui Fontes escribió:
Hola Javi!
Comments in midle of your message marked with *...
Às 18:47 de 05/06/2022, Javi Domínguez escreveu:
When I try to recognize a file on the desktop two things happen:
1. If this is the first time a file is recognized, it says "file not supported" (tested with PDF and BMP file types). The same file recognized from a folder in Windows explorer works fine. * It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad!
2. If another file has been recognized before, it process any file even if it is not of a supported type. In any case, supported type or not, it always shows the result of the previous recognition, not the requested file. Even after manually deleting the oc.txt and ocr-xxx.png files from the addon's images folder, it re-processes the previously requested file.
* It was an error on code... The path of last document was not cleared, so list of ocr-xxx.png file was created again...
On the other hand, recognition from scanner does not work for me. My scanner is HP Scanjet G2410, It may not be supported but the addon does not speak any message about it. The thread that processes this remains active and never terminates. If the script is executed again, another thread is launched that also remains active and so on forever. It is normal for the user, if he does not receive a response, to try to run it again, so you can end up with a lot of active threads.
* The scanner is recognized as WIA compatible?
* What Windows version?
I have the habit of naming the treads that I use to be able to debug better with threading.enumerate(). I have added the line to __init__.py self._thread.name = "tesseractOCR" before starting the thread to do these tests.
* So, I should name each thread differently...
* And, before starting another thread, verify if it is active, right?
finally, in terms of user experience, I think you need to give more information about what is happening. Sometimes, if the recognition takes time, the user does not know if it is working correctly or not.
* It is schedulled for next version...
Thanks!
Rui Fontes
|
|
Hola Javi! Firstly, thanks by your PR! But, I would like to better it a litle more... The case is: When I have set this new laptop and installed Dropbox, I have selected to backup the desktop folder, and so my desktop full path is: c:\Users\userName\dropbox\ambiente de trabalho "Ambiente de trabalho" is the portuguese expression for "Desktop"... So, I have tried to use shlobj.getKnownFolderId to get the correct desktop path for all cases... In spite of modifying the shlobj.ini and importing it in the add-on, I didn't manage to do it... I have added in shlobj.py, on the class FolderId(str, Enum): the following lines: #Desktop folder # The typical path is "C:\Users\Utilizador\appData\desktop APP_DATA_DESKTOP = "{B2C5E279-7ADD-439F-B28C-C41FE1BBF672}" the string between quotes was found at: https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid"""Someone can help on this? Best regards, Rui Fontes NVDA portuguese team Às 17:59 de 11/06/2022, Javi Domínguez escreveu:
toggle quoted messageShow quoted text
Hello.
You have a pull request that fixes both issues.
https://github.com/ruifontes/tesseractOCR/pull/2
Greetings
Javi Dominguez
El 05/06/2022 a las 23:01, Javi Domínguez via groups.io escribió:
Hello again.
I have run wia-cmd-scanner.exe directly from the command line, in the Windows CMD, and it has worked perfectly.
However from the addon it doesn't work. stderr shows:
b'The system cannot find the specified path.\r\n'
I hope this helps. It's late and I can't do any more research. Tomorrow dawns very early.
Good nitht
Javi
El 05/06/2022 a las 22:24, Javi Domínguez via groups.io escribió:
Hello.
* It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad! OK. I'll take a look at that.
* The scanner is recognized as WIA compatible? what do you mean with "is recognized as WIA compatible"? Yes, the scanner is WIA compliant, other apps recognize it but the addon I don't know, it just doesn't do anything.
* What Windows version? Windows 10 21H2 (x64) build 19044.1706
* So, I should name each thread differently... Yes, it would be convenient.
* And, before starting another thread, verify if it is active, right? I think so. I would wait for the current thread to finish before starting another.
Note that if you assign the new thread to self._thread, the old thread will continue to run until it finishes but you will no longer have a reference to it. You will only be able to access it via threading.enumerate().
You may need a method to kill threads that are stuck or taking too long.
Greetings
Javi
El 05/06/2022 a las 20:34, Rui Fontes escribió:
Hola Javi!
Comments in midle of your message marked with *...
Às 18:47 de 05/06/2022, Javi Domínguez escreveu:
When I try to recognize a file on the desktop two things happen:
1. If this is the first time a file is recognized, it says "file not supported" (tested with PDF and BMP file types). The same file recognized from a folder in Windows explorer works fine. * It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad!
2. If another file has been recognized before, it process any file even if it is not of a supported type. In any case, supported type or not, it always shows the result of the previous recognition, not the requested file. Even after manually deleting the oc.txt and ocr-xxx.png files from the addon's images folder, it re-processes the previously requested file.
* It was an error on code... The path of last document was not cleared, so list of ocr-xxx.png file was created again...
On the other hand, recognition from scanner does not work for me. My scanner is HP Scanjet G2410, It may not be supported but the addon does not speak any message about it. The thread that processes this remains active and never terminates. If the script is executed again, another thread is launched that also remains active and so on forever. It is normal for the user, if he does not receive a response, to try to run it again, so you can end up with a lot of active threads.
* The scanner is recognized as WIA compatible?
* What Windows version?
I have the habit of naming the treads that I use to be able to debug better with threading.enumerate(). I have added the line to __init__.py self._thread.name = "tesseractOCR" before starting the thread to do these tests.
* So, I should name each thread differently...
* And, before starting another thread, verify if it is active, right?
finally, in terms of user experience, I think you need to give more information about what is happening. Sometimes, if the recognition takes time, the user does not know if it is working correctly or not.
* It is schedulled for next version...
Thanks!
Rui Fontes
|
|
hello.
this addon have one very serious problem.
downloading of imported language happens in the main thread which locks up NVDA. If user have bad internet connection, they can stay without speech for several minutes. this should be corrected as soon as possible.
suggestion, tesseract can handle more than two languages, and instead of selecting one more language as second language, i suggest a following ui: one list, which will include all possible tesseract languages, add buttton, second list which will include all added languages from the first list, remove button, and move up/down buttons. on saving list of languages would be written in config and some callback should be called, which would check if some of just saved languages are missing, and download them in the background thread.
toggle quoted messageShow quoted text
On 6/19/22, Rui Fontes <rui.fontes@...> wrote: Hola Javi!
Firstly, thanks by your PR!
But, I would like to better it a litle more...
The case is:
When I have set this new laptop and installed Dropbox, I have selected to backup the desktop folder, and so my desktop full path is:
c:\Users\userName\dropbox\ambiente de trabalho
"Ambiente de trabalho" is the portuguese expression for "Desktop"...
So, I have tried to use shlobj.getKnownFolderId to get the correct desktop path for all cases...
In spite of modifying the shlobj.ini and importing it in the add-on, I didn't manage to do it...
I have added in shlobj.py, on the
class FolderId(str, Enum):
the following lines:
#Desktop folder # The typical path is "C:\Users\Utilizador\appData\desktop APP_DATA_DESKTOP = "{B2C5E279-7ADD-439F-B28C-C41FE1BBF672}"
the string between quotes was found at:
https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid"""
Someone can help on this?
Best regards,
Rui Fontes NVDA portuguese team
Às 17:59 de 11/06/2022, Javi Domínguez escreveu:
Hello.
You have a pull request that fixes both issues.
https://github.com/ruifontes/tesseractOCR/pull/2
Greetings
Javi Dominguez
El 05/06/2022 a las 23:01, Javi Domínguez via groups.io escribió:
Hello again.
I have run wia-cmd-scanner.exe directly from the command line, in the Windows CMD, and it has worked perfectly.
However from the addon it doesn't work. stderr shows:
b'The system cannot find the specified path.\r\n'
I hope this helps. It's late and I can't do any more research. Tomorrow dawns very early.
Good nitht
Javi
El 05/06/2022 a las 22:24, Javi Domínguez via groups.io escribió:
Hello.
* It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad! OK. I'll take a look at that.
* The scanner is recognized as WIA compatible? what do you mean with "is recognized as WIA compatible"? Yes, the scanner is WIA compliant, other apps recognize it but the addon I don't know, it just doesn't do anything.
* What Windows version? Windows 10 21H2 (x64) build 19044.1706
* So, I should name each thread differently... Yes, it would be convenient.
* And, before starting another thread, verify if it is active, right? I think so. I would wait for the current thread to finish before starting another.
Note that if you assign the new thread to self._thread, the old thread will continue to run until it finishes but you will no longer have a reference to it. You will only be able to access it via threading.enumerate().
You may need a method to kill threads that are stuck or taking too long.
Greetings
Javi
El 05/06/2022 a las 20:34, Rui Fontes escribió:
Hola Javi!
Comments in midle of your message marked with *...
Às 18:47 de 05/06/2022, Javi Domínguez escreveu:
When I try to recognize a file on the desktop two things happen:
1. If this is the first time a file is recognized, it says "file not supported" (tested with PDF and BMP file types). The same file recognized from a folder in Windows explorer works fine. * It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad!
2. If another file has been recognized before, it process any file even if it is not of a supported type. In any case, supported type or not, it always shows the result of the previous recognition, not the requested file. Even after manually deleting the oc.txt and ocr-xxx.png files from the addon's images folder, it re-processes the previously requested file.
* It was an error on code... The path of last document was not cleared, so list of ocr-xxx.png file was created again...
On the other hand, recognition from scanner does not work for me. My scanner is HP Scanjet G2410, It may not be supported but the addon does not speak any message about it. The thread that processes this remains active and never terminates. If the script is executed again, another thread is launched that also remains active and so on forever. It is normal for the user, if he does not receive a response, to try to run it again, so you can end up with a lot of active threads.
* The scanner is recognized as WIA compatible?
* What Windows version?
I have the habit of naming the treads that I use to be able to debug better with threading.enumerate(). I have added the line to __init__.py self._thread.name = "tesseractOCR" before starting the thread to do these tests.
* So, I should name each thread differently...
* And, before starting another thread, verify if it is active, right?
finally, in terms of user experience, I think you need to give more information about what is happening. Sometimes, if the recognition takes time, the user does not know if it is working correctly or not.
* It is schedulled for next version...
Thanks!
Rui Fontes
|
|
Hi Beqa!
Thanks by the suggestions!
Can you gave me an example of such callback?
My knowledge is still very poor!
Best regards,
Rui Fontes NVDA portuguese team
Às 13:49 de 28/06/2022, Beqa Gozalishvili escreveu:
toggle quoted messageShow quoted text
hello.
this addon have one very serious problem.
downloading of imported language happens in the main thread which locks up NVDA. If user have bad internet connection, they can stay without speech for several minutes. this should be corrected as soon as possible.
suggestion, tesseract can handle more than two languages, and instead of selecting one more language as second language, i suggest a following ui: one list, which will include all possible tesseract languages, add buttton, second list which will include all added languages from the first list, remove button, and move up/down buttons. on saving list of languages would be written in config and some callback should be called, which would check if some of just saved languages are missing, and download them in the background thread.
On 6/19/22, Rui Fontes <rui.fontes@...> wrote:
Hola Javi!
Firstly, thanks by your PR!
But, I would like to better it a litle more...
The case is:
When I have set this new laptop and installed Dropbox, I have selected to backup the desktop folder, and so my desktop full path is:
c:\Users\userName\dropbox\ambiente de trabalho
"Ambiente de trabalho" is the portuguese expression for "Desktop"...
So, I have tried to use shlobj.getKnownFolderId to get the correct desktop path for all cases...
In spite of modifying the shlobj.ini and importing it in the add-on, I didn't manage to do it...
I have added in shlobj.py, on the
class FolderId(str, Enum):
the following lines:
#Desktop folder # The typical path is "C:\Users\Utilizador\appData\desktop APP_DATA_DESKTOP = "{B2C5E279-7ADD-439F-B28C-C41FE1BBF672}"
the string between quotes was found at:
https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid"""
Someone can help on this?
Best regards,
Rui Fontes NVDA portuguese team
Às 17:59 de 11/06/2022, Javi Domínguez escreveu:
Hello.
You have a pull request that fixes both issues.
https://github.com/ruifontes/tesseractOCR/pull/2
Greetings
Javi Dominguez
El 05/06/2022 a las 23:01, Javi Domínguez via groups.io escribió:
Hello again.
I have run wia-cmd-scanner.exe directly from the command line, in the Windows CMD, and it has worked perfectly.
However from the addon it doesn't work. stderr shows:
b'The system cannot find the specified path.\r\n'
I hope this helps. It's late and I can't do any more research. Tomorrow dawns very early.
Good nitht
Javi
El 05/06/2022 a las 22:24, Javi Domínguez via groups.io escribió:
Hello.
* It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad! OK. I'll take a look at that.
* The scanner is recognized as WIA compatible? what do you mean with "is recognized as WIA compatible"? Yes, the scanner is WIA compliant, other apps recognize it but the addon I don't know, it just doesn't do anything.
* What Windows version? Windows 10 21H2 (x64) build 19044.1706
* So, I should name each thread differently... Yes, it would be convenient.
* And, before starting another thread, verify if it is active, right? I think so. I would wait for the current thread to finish before starting another.
Note that if you assign the new thread to self._thread, the old thread will continue to run until it finishes but you will no longer have a reference to it. You will only be able to access it via threading.enumerate().
You may need a method to kill threads that are stuck or taking too long.
Greetings
Javi
El 05/06/2022 a las 20:34, Rui Fontes escribió:
Hola Javi!
Comments in midle of your message marked with *...
Às 18:47 de 05/06/2022, Javi Domínguez escreveu:
When I try to recognize a file on the desktop two things happen:
1. If this is the first time a file is recognized, it says "file not supported" (tested with PDF and BMP file types). The same file recognized from a folder in Windows explorer works fine. * It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad!
2. If another file has been recognized before, it process any file even if it is not of a supported type. In any case, supported type or not, it always shows the result of the previous recognition, not the requested file. Even after manually deleting the oc.txt and ocr-xxx.png files from the addon's images folder, it re-processes the previously requested file. * It was an error on code... The path of last document was not cleared, so list of ocr-xxx.png file was created again...
On the other hand, recognition from scanner does not work for me. My scanner is HP Scanjet G2410, It may not be supported but the addon does not speak any message about it. The thread that processes this remains active and never terminates. If the script is executed again, another thread is launched that also remains active and so on forever. It is normal for the user, if he does not receive a response, to try to run it again, so you can end up with a lot of active threads.
* The scanner is recognized as WIA compatible?
* What Windows version?
I have the habit of naming the treads that I use to be able to debug better with threading.enumerate(). I have added the line to __init__.py self._thread.name = "tesseractOCR" before starting the thread to do these tests.
* So, I should name each thread differently...
* And, before starting another thread, verify if it is active, right?
finally, in terms of user experience, I think you need to give more information about what is happening. Sometimes, if the recognition takes time, the user does not know if it is working correctly or not.
* It is schedulled for next version...
Thanks!
Rui Fontes
|
|
Hello.
I wanted to refactor this addon, but unfortunately i don't have enough time yet, may be i will return to this in the near future, but as for suggestions, i wrote a minimal example how it should look.
I am sending a minimal code example here.
Maybe there is a better way of doing such thing, but this is what i could think off today morning.
import addonHandler import functools import globalPluginHandler import gui import ui import wx
class OCRSettingsPanel(gui.SettingsPanel): title = "TesseractOCR"
def makeSettings(self, settingsSizer): sHelper = gui.guiHelper.BoxSizerHelper(self, sizer = settingsSizer) self.onMoveUp = functools.partial(self.onMove, direction=-1) self.onMoveDown = functools.partial(self.onMove, direction=1) self.availableLangs = sHelper.addLabeledControl("Available languages", wx.ListBox, choices=[], style = wx.LB_SINGLE|wx.LB_SORT) self.addButton = sHelper.addItem(wx.Button(self, label ="&Add", name="Add")) self.addButton.Bind(wx.EVT_BUTTON, self.onAdd) self.enabledLangs = sHelper.addLabeledControl("Selected languages", wx.ListBox, choices=[], style = wx.LB_SINGLE) self.enabledLangs.Bind(wx.EVT_LISTBOX, self.onChange) self.enabledLangs.Bind(wx.EVT_KEY_DOWN, self.onKeyDown) self.removeButton = sHelper.addItem(wx.Button(self, label ="&Remove", name="Remove")) self.removeButton.Bind(wx.EVT_BUTTON, self.onRemove) self.moveUpButton = sHelper.addItem(wx.Button(self, label ="Move &up", name="Up")) self.moveUpButton.Bind(wx.EVT_BUTTON, self.onMoveUp) self.moveDownButton = sHelper.addItem(wx.Button(self, label ="Move &down", name="Down")) self.moveDownButton.Bind(wx.EVT_BUTTON, self.onMoveDown) self.updateControlls()
def onKeyDown(self, evt): if evt.KeyCode == wx.WXK_UP and evt.controlDown: self.onMoveUp(evt) elif evt.KeyCode == wx.WXK_DOWN and evt.controlDown: self.onMoveDown(evt) else: evt.Skip()
def onAdd(self, evt): self.swapItems(evt, self.availableLangs, self.enabledLangs)
def onRemove(self, evt): self.swapItems(evt, self.enabledLangs, self.availableLangs)
def swapItems(self, evt, source, target): index = source.GetSelection() if index == -1: return target.Append(source.GetString(index)) source.Delete(index) if len(source.Items) > 0: source.SetSelection(index if index < source.Count - 1 else index - 1) self.updateControlls(evt)
def onMove(self, evt, direction): curIndex = self.enabledLangs.GetSelection() if curIndex == -1: return if direction == -1 and curIndex == 0 or direction == 1 and curIndex == self.enabledLangs.Count - 1: return newIndex = curIndex + direction curItem = self.enabledLangs.GetString(curIndex) newItem = self.enabledLangs.GetString(newIndex) self.enabledLangs.SetString(curIndex, newItem) self.enabledLangs.SetString(newIndex, curItem) self.enabledLangs.SetSelection(newIndex) self.updateControlls(evt)
def onChange(self, evt): self.updateControlls()
def updateControlls(self, evt=None): # possibly adding temporary class fields to eliminate unnnecessary computations. index = self.enabledLangs.GetSelection() self.moveUpButton.Disable() if index == 0 or index == -1 else self.moveUpButton.Enable() self.moveDownButton.Disable() if index == self.enabledLangs.Count - 1 or index == -1 else self.moveDownButton.Enable() self.addButton.Disable() if len(self.availableLangs.Items) == 0 else self.addButton.Enable() self.removeButton.Disable() if len(self.enabledLangs.Items) == 0 else self.removeButton.Enable() if evt is not None and (isinstance(evt.EventObject, wx.Button) and evt.EventObject.Name in ["Up", "Down"] and (index == 0 or index == self.enabledLangs.Count -1) or evt.EventObject.Name == "Add" and len(self.availableLangs.Items) == 0 or evt.EventObject.Name == "Remove" and len(self.enabledLangs.Items) == 0): self.enabledLangs.SetFocus()
def onSave(self): # Config saving here self.onSaveCallback(self.enabledLangs.Items)
class GlobalPlugin(globalPluginHandler.GlobalPlugin):
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) OCRSettingsPanel.onSaveCallback = self.checkLanguages gui.NVDASettingsDialog.categoryClasses.append(OCRSettingsPanel)
def terminate(self): gui.NVDASettingsDialog.categoryClasses.remove(OCRSettingsPanel)
def checkLanguages(self, langs): ui.message("+".join(langs))
toggle quoted messageShow quoted text
On 6/28/22, Rui Fontes <rui.fontes@...> wrote: Hi Beqa!
Thanks by the suggestions!
Can you gave me an example of such callback?
My knowledge is still very poor!
Best regards,
Rui Fontes NVDA portuguese team
Às 13:49 de 28/06/2022, Beqa Gozalishvili escreveu:
hello.
this addon have one very serious problem.
downloading of imported language happens in the main thread which locks up NVDA. If user have bad internet connection, they can stay without speech for several minutes. this should be corrected as soon as possible.
suggestion, tesseract can handle more than two languages, and instead of selecting one more language as second language, i suggest a following ui: one list, which will include all possible tesseract languages, add buttton, second list which will include all added languages from the first list, remove button, and move up/down buttons. on saving list of languages would be written in config and some callback should be called, which would check if some of just saved languages are missing, and download them in the background thread.
On 6/19/22, Rui Fontes <rui.fontes@...> wrote:
Hola Javi!
Firstly, thanks by your PR!
But, I would like to better it a litle more...
The case is:
When I have set this new laptop and installed Dropbox, I have selected to backup the desktop folder, and so my desktop full path is:
c:\Users\userName\dropbox\ambiente de trabalho
"Ambiente de trabalho" is the portuguese expression for "Desktop"...
So, I have tried to use shlobj.getKnownFolderId to get the correct desktop path for all cases...
In spite of modifying the shlobj.ini and importing it in the add-on, I didn't manage to do it...
I have added in shlobj.py, on the
class FolderId(str, Enum):
the following lines:
#Desktop folder # The typical path is "C:\Users\Utilizador\appData\desktop APP_DATA_DESKTOP = "{B2C5E279-7ADD-439F-B28C-C41FE1BBF672}"
the string between quotes was found at:
https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid"""
Someone can help on this?
Best regards,
Rui Fontes NVDA portuguese team
Às 17:59 de 11/06/2022, Javi Domínguez escreveu:
Hello.
You have a pull request that fixes both issues.
https://github.com/ruifontes/tesseractOCR/pull/2
Greetings
Javi Dominguez
El 05/06/2022 a las 23:01, Javi Domínguez via groups.io escribió:
Hello again.
I have run wia-cmd-scanner.exe directly from the command line, in the Windows CMD, and it has worked perfectly.
However from the addon it doesn't work. stderr shows:
b'The system cannot find the specified path.\r\n'
I hope this helps. It's late and I can't do any more research. Tomorrow dawns very early.
Good nitht
Javi
El 05/06/2022 a las 22:24, Javi Domínguez via groups.io escribió:
Hello.
* It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad! OK. I'll take a look at that.
* The scanner is recognized as WIA compatible? what do you mean with "is recognized as WIA compatible"? Yes, the scanner is WIA compliant, other apps recognize it but the addon I don't know, it just doesn't do anything.
* What Windows version? Windows 10 21H2 (x64) build 19044.1706
* So, I should name each thread differently... Yes, it would be convenient.
* And, before starting another thread, verify if it is active, right? I think so. I would wait for the current thread to finish before starting another.
Note that if you assign the new thread to self._thread, the old thread will continue to run until it finishes but you will no longer have a reference to it. You will only be able to access it via threading.enumerate().
You may need a method to kill threads that are stuck or taking too long.
Greetings
Javi
El 05/06/2022 a las 20:34, Rui Fontes escribió:
Hola Javi!
Comments in midle of your message marked with *...
Às 18:47 de 05/06/2022, Javi Domínguez escreveu:
When I try to recognize a file on the desktop two things happen:
1. If this is the first time a file is recognized, it says "file not supported" (tested with PDF and BMP file types). The same file recognized from a folder in Windows explorer works fine. * It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad!
2. If another file has been recognized before, it process any file even if it is not of a supported type. In any case, supported type or not, it always shows the result of the previous recognition, not the requested file. Even after manually deleting the oc.txt and ocr-xxx.png files from the addon's images folder, it re-processes the previously requested file. * It was an error on code... The path of last document was not cleared, so list of ocr-xxx.png file was created again...
On the other hand, recognition from scanner does not work for me. My scanner is HP Scanjet G2410, It may not be supported but the addon does not speak any message about it. The thread that processes this remains active and never terminates. If the script is executed again, another thread is launched that also remains active and so on forever. It is normal for the user, if he does not receive a response, to try to run it again, so you can end up with a lot of active threads.
* The scanner is recognized as WIA compatible?
* What Windows version?
I have the habit of naming the treads that I use to be able to debug better with threading.enumerate(). I have added the line to __init__.py self._thread.name = "tesseractOCR" before starting the thread to do these tests.
* So, I should name each thread differently...
* And, before starting another thread, verify if it is active, right?
finally, in terms of user experience, I think you need to give more information about what is happening. Sometimes, if the recognition takes time, the user does not know if it is working correctly or not.
* It is schedulled for next version...
Thanks!
Rui Fontes
|
|
Hello Beqa! Thanks for your suggestion! See what I did with your suggestion: https://www.dropbox.com/s/658ua5z2sumt1hd/tesseractOCR_2022.07.nvda-addon?dl=1By the way, what was the purpose of: self.onMoveUp = functools.partial(self.onMove, direction=-1) self.onMoveDown = functools.partial(self.onMove, direction=1) Best regards, Best regards, Rui Fontes NVDA portuguese team Às 09:30 de 01/07/2022, Beqa Gozalishvili escreveu:
toggle quoted messageShow quoted text
Hello.
I wanted to refactor this addon, but unfortunately i don't have enough time yet, may be i will return to this in the near future, but as for suggestions, i wrote a minimal example how it should look.
I am sending a minimal code example here.
Maybe there is a better way of doing such thing, but this is what i could think off today morning.
import addonHandler import functools import globalPluginHandler import gui import ui import wx
class OCRSettingsPanel(gui.SettingsPanel): title = "TesseractOCR"
def makeSettings(self, settingsSizer): sHelper = gui.guiHelper.BoxSizerHelper(self, sizer = settingsSizer) self.onMoveUp = functools.partial(self.onMove, direction=-1) self.onMoveDown = functools.partial(self.onMove, direction=1) self.availableLangs = sHelper.addLabeledControl("Available languages", wx.ListBox, choices=[], style = wx.LB_SINGLE|wx.LB_SORT) self.addButton = sHelper.addItem(wx.Button(self, label ="&Add", name="Add")) self.addButton.Bind(wx.EVT_BUTTON, self.onAdd) self.enabledLangs = sHelper.addLabeledControl("Selected languages", wx.ListBox, choices=[], style = wx.LB_SINGLE) self.enabledLangs.Bind(wx.EVT_LISTBOX, self.onChange) self.enabledLangs.Bind(wx.EVT_KEY_DOWN, self.onKeyDown) self.removeButton = sHelper.addItem(wx.Button(self, label ="&Remove", name="Remove")) self.removeButton.Bind(wx.EVT_BUTTON, self.onRemove) self.moveUpButton = sHelper.addItem(wx.Button(self, label ="Move &up", name="Up")) self.moveUpButton.Bind(wx.EVT_BUTTON, self.onMoveUp) self.moveDownButton = sHelper.addItem(wx.Button(self, label ="Move &down", name="Down")) self.moveDownButton.Bind(wx.EVT_BUTTON, self.onMoveDown) self.updateControlls()
def onKeyDown(self, evt): if evt.KeyCode == wx.WXK_UP and evt.controlDown: self.onMoveUp(evt) elif evt.KeyCode == wx.WXK_DOWN and evt.controlDown: self.onMoveDown(evt) else: evt.Skip()
def onAdd(self, evt): self.swapItems(evt, self.availableLangs, self.enabledLangs)
def onRemove(self, evt): self.swapItems(evt, self.enabledLangs, self.availableLangs)
def swapItems(self, evt, source, target): index = source.GetSelection() if index == -1: return target.Append(source.GetString(index)) source.Delete(index) if len(source.Items) > 0: source.SetSelection(index if index < source.Count - 1 else index - 1) self.updateControlls(evt)
def onMove(self, evt, direction): curIndex = self.enabledLangs.GetSelection() if curIndex == -1: return if direction == -1 and curIndex == 0 or direction == 1 and curIndex == self.enabledLangs.Count - 1: return newIndex = curIndex + direction curItem = self.enabledLangs.GetString(curIndex) newItem = self.enabledLangs.GetString(newIndex) self.enabledLangs.SetString(curIndex, newItem) self.enabledLangs.SetString(newIndex, curItem) self.enabledLangs.SetSelection(newIndex) self.updateControlls(evt)
def onChange(self, evt): self.updateControlls()
def updateControlls(self, evt=None): # possibly adding temporary class fields to eliminate unnnecessary computations. index = self.enabledLangs.GetSelection() self.moveUpButton.Disable() if index == 0 or index == -1 else self.moveUpButton.Enable() self.moveDownButton.Disable() if index == self.enabledLangs.Count - 1 or index == -1 else self.moveDownButton.Enable() self.addButton.Disable() if len(self.availableLangs.Items) == 0 else self.addButton.Enable() self.removeButton.Disable() if len(self.enabledLangs.Items) == 0 else self.removeButton.Enable() if evt is not None and (isinstance(evt.EventObject, wx.Button) and evt.EventObject.Name in ["Up", "Down"] and (index == 0 or index == self.enabledLangs.Count -1) or evt.EventObject.Name == "Add" and len(self.availableLangs.Items) == 0 or evt.EventObject.Name == "Remove" and len(self.enabledLangs.Items) == 0): self.enabledLangs.SetFocus()
def onSave(self): # Config saving here self.onSaveCallback(self.enabledLangs.Items)
class GlobalPlugin(globalPluginHandler.GlobalPlugin):
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) OCRSettingsPanel.onSaveCallback = self.checkLanguages gui.NVDASettingsDialog.categoryClasses.append(OCRSettingsPanel)
def terminate(self): gui.NVDASettingsDialog.categoryClasses.remove(OCRSettingsPanel)
def checkLanguages(self, langs): ui.message("+".join(langs))
On 6/28/22, Rui Fontes <rui.fontes@...> wrote:
Hi Beqa!
Thanks by the suggestions!
Can you gave me an example of such callback?
My knowledge is still very poor!
Best regards,
Rui Fontes NVDA portuguese team
Às 13:49 de 28/06/2022, Beqa Gozalishvili escreveu:
hello.
this addon have one very serious problem.
downloading of imported language happens in the main thread which locks up NVDA. If user have bad internet connection, they can stay without speech for several minutes. this should be corrected as soon as possible.
suggestion, tesseract can handle more than two languages, and instead of selecting one more language as second language, i suggest a following ui: one list, which will include all possible tesseract languages, add buttton, second list which will include all added languages from the first list, remove button, and move up/down buttons. on saving list of languages would be written in config and some callback should be called, which would check if some of just saved languages are missing, and download them in the background thread.
On 6/19/22, Rui Fontes <rui.fontes@...> wrote:
Hola Javi!
Firstly, thanks by your PR!
But, I would like to better it a litle more...
The case is:
When I have set this new laptop and installed Dropbox, I have selected to backup the desktop folder, and so my desktop full path is:
c:\Users\userName\dropbox\ambiente de trabalho
"Ambiente de trabalho" is the portuguese expression for "Desktop"...
So, I have tried to use shlobj.getKnownFolderId to get the correct desktop path for all cases...
In spite of modifying the shlobj.ini and importing it in the add-on, I didn't manage to do it...
I have added in shlobj.py, on the
class FolderId(str, Enum):
the following lines:
#Desktop folder # The typical path is "C:\Users\Utilizador\appData\desktop APP_DATA_DESKTOP = "{B2C5E279-7ADD-439F-B28C-C41FE1BBF672}"
the string between quotes was found at:
https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid"""
Someone can help on this?
Best regards,
Rui Fontes NVDA portuguese team
Às 17:59 de 11/06/2022, Javi Domínguez escreveu:
Hello.
You have a pull request that fixes both issues.
https://github.com/ruifontes/tesseractOCR/pull/2
Greetings
Javi Dominguez
El 05/06/2022 a las 23:01, Javi Domínguez via groups.io escribió:
Hello again.
I have run wia-cmd-scanner.exe directly from the command line, in the Windows CMD, and it has worked perfectly.
However from the addon it doesn't work. stderr shows:
b'The system cannot find the specified path.\r\n'
I hope this helps. It's late and I can't do any more research. Tomorrow dawns very early.
Good nitht
Javi
El 05/06/2022 a las 22:24, Javi Domínguez via groups.io escribió:
Hello.
* It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad! OK. I'll take a look at that.
* The scanner is recognized as WIA compatible? what do you mean with "is recognized as WIA compatible"? Yes, the scanner is WIA compliant, other apps recognize it but the addon I don't know, it just doesn't do anything.
* What Windows version? Windows 10 21H2 (x64) build 19044.1706
* So, I should name each thread differently... Yes, it would be convenient.
* And, before starting another thread, verify if it is active, right? I think so. I would wait for the current thread to finish before starting another.
Note that if you assign the new thread to self._thread, the old thread will continue to run until it finishes but you will no longer have a reference to it. You will only be able to access it via threading.enumerate().
You may need a method to kill threads that are stuck or taking too long.
Greetings
Javi
El 05/06/2022 a las 20:34, Rui Fontes escribió:
Hola Javi!
Comments in midle of your message marked with *...
Às 18:47 de 05/06/2022, Javi Domínguez escreveu:
When I try to recognize a file on the desktop two things happen:
1. If this is the first time a file is recognized, it says "file not supported" (tested with PDF and BMP file types). The same file recognized from a folder in Windows explorer works fine. * It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad!
2. If another file has been recognized before, it process any file even if it is not of a supported type. In any case, supported type or not, it always shows the result of the previous recognition, not the requested file. Even after manually deleting the oc.txt and ocr-xxx.png files from the addon's images folder, it re-processes the previously requested file. * It was an error on code... The path of last document was not cleared, so list of ocr-xxx.png file was created again...
On the other hand, recognition from scanner does not work for me. My scanner is HP Scanjet G2410, It may not be supported but the addon does not speak any message about it. The thread that processes this remains active and never terminates. If the script is executed again, another thread is launched that also remains active and so on forever. It is normal for the user, if he does not receive a response, to try to run it again, so you can end up with a lot of active threads.
* The scanner is recognized as WIA compatible?
* What Windows version?
I have the habit of naming the treads that I use to be able to debug better with threading.enumerate(). I have added the line to __init__.py self._thread.name = "tesseractOCR" before starting the thread to do these tests.
* So, I should name each thread differently...
* And, before starting another thread, verify if it is active, right?
finally, in terms of user experience, I think you need to give more information about what is happening. Sometimes, if the recognition takes time, the user does not know if it is working correctly or not.
* It is schedulled for next version...
Thanks!
Rui Fontes
|
|
Hello.
These methods are generated to pass direction argument to handler function, because i didn't think of another way and i didn't want to define two similar methods.
Yes, it is better, one more suggestion would be to remove repetition in languages. you have list and dictionary of languages. Lets reuse dictionary for all possible needs and use ClientData from ItemContainer to associate item with needed data. Also generalise function to run things in subprocess, extract interface class in separate module, also do the same with languages
toggle quoted messageShow quoted text
On 7/5/22, Rui Fontes <rui.fontes@...> wrote: Hello Beqa!
Thanks for your suggestion!
See what I did with your suggestion:
https://www.dropbox.com/s/658ua5z2sumt1hd/tesseractOCR_2022.07.nvda-addon?dl=1
By the way, what was the purpose of:
self.onMoveUp = functools.partial(self.onMove, direction=-1) self.onMoveDown = functools.partial(self.onMove, direction=1)
Best regards,
Best regards,
Rui Fontes NVDA portuguese team
Às 09:30 de 01/07/2022, Beqa Gozalishvili escreveu:
Hello.
I wanted to refactor this addon, but unfortunately i don't have enough time yet, may be i will return to this in the near future, but as for suggestions, i wrote a minimal example how it should look.
I am sending a minimal code example here.
Maybe there is a better way of doing such thing, but this is what i could think off today morning.
import addonHandler import functools import globalPluginHandler import gui import ui import wx
class OCRSettingsPanel(gui.SettingsPanel): title = "TesseractOCR"
def makeSettings(self, settingsSizer): sHelper = gui.guiHelper.BoxSizerHelper(self, sizer = settingsSizer) self.onMoveUp = functools.partial(self.onMove, direction=-1) self.onMoveDown = functools.partial(self.onMove, direction=1) self.availableLangs = sHelper.addLabeledControl("Available languages", wx.ListBox, choices=[], style = wx.LB_SINGLE|wx.LB_SORT) self.addButton = sHelper.addItem(wx.Button(self, label ="&Add", name="Add")) self.addButton.Bind(wx.EVT_BUTTON, self.onAdd) self.enabledLangs = sHelper.addLabeledControl("Selected languages", wx.ListBox, choices=[], style = wx.LB_SINGLE) self.enabledLangs.Bind(wx.EVT_LISTBOX, self.onChange) self.enabledLangs.Bind(wx.EVT_KEY_DOWN, self.onKeyDown) self.removeButton = sHelper.addItem(wx.Button(self, label ="&Remove", name="Remove")) self.removeButton.Bind(wx.EVT_BUTTON, self.onRemove) self.moveUpButton = sHelper.addItem(wx.Button(self, label ="Move &up", name="Up")) self.moveUpButton.Bind(wx.EVT_BUTTON, self.onMoveUp) self.moveDownButton = sHelper.addItem(wx.Button(self, label ="Move &down", name="Down")) self.moveDownButton.Bind(wx.EVT_BUTTON, self.onMoveDown) self.updateControlls()
def onKeyDown(self, evt): if evt.KeyCode == wx.WXK_UP and evt.controlDown: self.onMoveUp(evt) elif evt.KeyCode == wx.WXK_DOWN and evt.controlDown: self.onMoveDown(evt) else: evt.Skip()
def onAdd(self, evt): self.swapItems(evt, self.availableLangs, self.enabledLangs)
def onRemove(self, evt): self.swapItems(evt, self.enabledLangs, self.availableLangs)
def swapItems(self, evt, source, target): index = source.GetSelection() if index == -1: return target.Append(source.GetString(index)) source.Delete(index) if len(source.Items) > 0: source.SetSelection(index if index < source.Count - 1 else index - 1) self.updateControlls(evt)
def onMove(self, evt, direction): curIndex = self.enabledLangs.GetSelection() if curIndex == -1: return if direction == -1 and curIndex == 0 or direction == 1 and curIndex == self.enabledLangs.Count - 1: return newIndex = curIndex + direction curItem = self.enabledLangs.GetString(curIndex) newItem = self.enabledLangs.GetString(newIndex) self.enabledLangs.SetString(curIndex, newItem) self.enabledLangs.SetString(newIndex, curItem) self.enabledLangs.SetSelection(newIndex) self.updateControlls(evt)
def onChange(self, evt): self.updateControlls()
def updateControlls(self, evt=None): # possibly adding temporary class fields to eliminate unnnecessary computations. index = self.enabledLangs.GetSelection() self.moveUpButton.Disable() if index == 0 or index == -1 else self.moveUpButton.Enable() self.moveDownButton.Disable() if index == self.enabledLangs.Count - 1 or index == -1 else self.moveDownButton.Enable() self.addButton.Disable() if len(self.availableLangs.Items) == 0 else self.addButton.Enable() self.removeButton.Disable() if len(self.enabledLangs.Items) == 0 else self.removeButton.Enable() if evt is not None and (isinstance(evt.EventObject, wx.Button) and evt.EventObject.Name in ["Up", "Down"] and (index == 0 or index == self.enabledLangs.Count -1) or evt.EventObject.Name == "Add" and len(self.availableLangs.Items) == 0 or evt.EventObject.Name == "Remove" and len(self.enabledLangs.Items) == 0): self.enabledLangs.SetFocus()
def onSave(self): # Config saving here self.onSaveCallback(self.enabledLangs.Items)
class GlobalPlugin(globalPluginHandler.GlobalPlugin):
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) OCRSettingsPanel.onSaveCallback = self.checkLanguages gui.NVDASettingsDialog.categoryClasses.append(OCRSettingsPanel)
def terminate(self): gui.NVDASettingsDialog.categoryClasses.remove(OCRSettingsPanel)
def checkLanguages(self, langs): ui.message("+".join(langs))
On 6/28/22, Rui Fontes <rui.fontes@...> wrote:
Hi Beqa!
Thanks by the suggestions!
Can you gave me an example of such callback?
My knowledge is still very poor!
Best regards,
Rui Fontes NVDA portuguese team
Às 13:49 de 28/06/2022, Beqa Gozalishvili escreveu:
hello.
this addon have one very serious problem.
downloading of imported language happens in the main thread which locks up NVDA. If user have bad internet connection, they can stay without speech for several minutes. this should be corrected as soon as possible.
suggestion, tesseract can handle more than two languages, and instead of selecting one more language as second language, i suggest a following ui: one list, which will include all possible tesseract languages, add buttton, second list which will include all added languages from the first list, remove button, and move up/down buttons. on saving list of languages would be written in config and some callback should be called, which would check if some of just saved languages are missing, and download them in the background thread.
On 6/19/22, Rui Fontes <rui.fontes@...> wrote:
Hola Javi!
Firstly, thanks by your PR!
But, I would like to better it a litle more...
The case is:
When I have set this new laptop and installed Dropbox, I have selected to backup the desktop folder, and so my desktop full path is:
c:\Users\userName\dropbox\ambiente de trabalho
"Ambiente de trabalho" is the portuguese expression for "Desktop"...
So, I have tried to use shlobj.getKnownFolderId to get the correct desktop path for all cases...
In spite of modifying the shlobj.ini and importing it in the add-on, I didn't manage to do it...
I have added in shlobj.py, on the
class FolderId(str, Enum):
the following lines:
#Desktop folder # The typical path is "C:\Users\Utilizador\appData\desktop APP_DATA_DESKTOP = "{B2C5E279-7ADD-439F-B28C-C41FE1BBF672}"
the string between quotes was found at:
https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid"""
Someone can help on this?
Best regards,
Rui Fontes NVDA portuguese team
Às 17:59 de 11/06/2022, Javi Domínguez escreveu:
Hello.
You have a pull request that fixes both issues.
https://github.com/ruifontes/tesseractOCR/pull/2
Greetings
Javi Dominguez
El 05/06/2022 a las 23:01, Javi Domínguez via groups.io escribió:
Hello again.
I have run wia-cmd-scanner.exe directly from the command line, in the Windows CMD, and it has worked perfectly.
However from the addon it doesn't work. stderr shows:
b'The system cannot find the specified path.\r\n'
I hope this helps. It's late and I can't do any more research. Tomorrow dawns very early.
Good nitht
Javi
El 05/06/2022 a las 22:24, Javi Domínguez via groups.io escribió:
Hello.
* It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad! OK. I'll take a look at that.
* The scanner is recognized as WIA compatible? what do you mean with "is recognized as WIA compatible"? Yes, the scanner is WIA compliant, other apps recognize it but the addon I don't know, it just doesn't do anything.
* What Windows version? Windows 10 21H2 (x64) build 19044.1706
* So, I should name each thread differently... Yes, it would be convenient.
* And, before starting another thread, verify if it is active, right? I think so. I would wait for the current thread to finish before starting another.
Note that if you assign the new thread to self._thread, the old thread will continue to run until it finishes but you will no longer have a reference to it. You will only be able to access it via threading.enumerate().
You may need a method to kill threads that are stuck or taking too long.
Greetings
Javi
El 05/06/2022 a las 20:34, Rui Fontes escribió:
Hola Javi!
Comments in midle of your message marked with *...
Às 18:47 de 05/06/2022, Javi Domínguez escreveu:
When I try to recognize a file on the desktop two things happen:
1. If this is the first time a file is recognized, it says "file not supported" (tested with PDF and BMP file types). The same file recognized from a folder in Windows explorer works fine. * It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad!
2. If another file has been recognized before, it process any file even if it is not of a supported type. In any case, supported type or not, it always shows the result of the previous recognition, not the requested file. Even after manually deleting the oc.txt and ocr-xxx.png files from the addon's images folder, it re-processes the previously requested file. * It was an error on code... The path of last document was not cleared, so list of ocr-xxx.png file was created again...
On the other hand, recognition from scanner does not work for me. My scanner is HP Scanjet G2410, It may not be supported but the addon does not speak any message about it. The thread that processes this remains active and never terminates. If the script is executed again, another thread is launched that also remains active and so on forever. It is normal for the user, if he does not receive a response, to try to run it again, so you can end up with a lot of active threads.
* The scanner is recognized as WIA compatible?
* What Windows version?
I have the habit of naming the treads that I use to be able to debug better with threading.enumerate(). I have added the line to __init__.py self._thread.name = "tesseractOCR" before starting the thread to do these tests.
* So, I should name each thread differently...
* And, before starting another thread, verify if it is active, right?
finally, in terms of user experience, I think you need to give more information about what is happening. Sometimes, if the recognition takes time, the user does not know if it is working correctly or not.
* It is schedulled for next version...
Thanks!
Rui Fontes
|
|
Thanks Beqa! You wrote: These methods are generated to pass direction argument to handler function, because i didn't think of another way and i didn't want to define two similar methods. Ok! I already make use of them... But you have created two similar methods, onAdd and onRemove... It is possible to use the same method with the parameters "target" and "source"? You wrote: ... one more suggestion would be to remove repetition in languages. you have list and dictionary of languages. Lets reuse dictionary for all possible needs and use ClientData from ItemContainer to associate item with needed data. Done! You wrote: Also generalise function to run things in subprocess... I don't think it is possible more... One function to generate .png files from .pdf, other to create the list of .png files, one to make OCR and one for scanning... Maybe joining the two first, but I don't see any advantage... You wrote: ... extract interface class in separate module... Create a settings.py only to create the TesseractOCR setting category? You wrote: ... also do the same with languages This one I did not understood... Create a languages.py to create all languages variables to be used? New version at: https://www.dropbox.com/s/mwtmupoetd0le8j/tesseractOCR_2022.07.nvda-addon?dl=1Best regards, Rui Fontes NVDA portuguese team On 7/5/22, Rui Fontes <rui.fontes@...> wrote:
Hello Beqa!
Thanks for your suggestion!
See what I did with your suggestion:
https://www.dropbox.com/s/658ua5z2sumt1hd/tesseractOCR_2022.07.nvda-addon?dl=1
By the way, what was the purpose of:
self.onMoveUp = functools.partial(self.onMove, direction=-1) self.onMoveDown = functools.partial(self.onMove, direction=1)
Best regards,
Best regards,
Rui Fontes NVDA portuguese team
Às 09:30 de 01/07/2022, Beqa Gozalishvili escreveu:
Hello.
I wanted to refactor this addon, but unfortunately i don't have enough time yet, may be i will return to this in the near future, but as for suggestions, i wrote a minimal example how it should look.
I am sending a minimal code example here.
Maybe there is a better way of doing such thing, but this is what i could think off today morning.
import addonHandler import functools import globalPluginHandler import gui import ui import wx
class OCRSettingsPanel(gui.SettingsPanel): title = "TesseractOCR"
def makeSettings(self, settingsSizer): sHelper = gui.guiHelper.BoxSizerHelper(self, sizer = settingsSizer) self.onMoveUp = functools.partial(self.onMove, direction=-1) self.onMoveDown = functools.partial(self.onMove, direction=1) self.availableLangs = sHelper.addLabeledControl("Available languages", wx.ListBox, choices=[], style = wx.LB_SINGLE|wx.LB_SORT) self.addButton = sHelper.addItem(wx.Button(self, label ="&Add", name="Add")) self.addButton.Bind(wx.EVT_BUTTON, self.onAdd) self.enabledLangs = sHelper.addLabeledControl("Selected languages", wx.ListBox, choices=[], style = wx.LB_SINGLE) self.enabledLangs.Bind(wx.EVT_LISTBOX, self.onChange) self.enabledLangs.Bind(wx.EVT_KEY_DOWN, self.onKeyDown) self.removeButton = sHelper.addItem(wx.Button(self, label ="&Remove", name="Remove")) self.removeButton.Bind(wx.EVT_BUTTON, self.onRemove) self.moveUpButton = sHelper.addItem(wx.Button(self, label ="Move &up", name="Up")) self.moveUpButton.Bind(wx.EVT_BUTTON, self.onMoveUp) self.moveDownButton = sHelper.addItem(wx.Button(self, label ="Move &down", name="Down")) self.moveDownButton.Bind(wx.EVT_BUTTON, self.onMoveDown) self.updateControlls()
def onKeyDown(self, evt): if evt.KeyCode == wx.WXK_UP and evt.controlDown: self.onMoveUp(evt) elif evt.KeyCode == wx.WXK_DOWN and evt.controlDown: self.onMoveDown(evt) else: evt.Skip()
def onAdd(self, evt): self.swapItems(evt, self.availableLangs, self.enabledLangs)
def onRemove(self, evt): self.swapItems(evt, self.enabledLangs, self.availableLangs)
def swapItems(self, evt, source, target): index = source.GetSelection() if index == -1: return target.Append(source.GetString(index)) source.Delete(index) if len(source.Items) > 0: source.SetSelection(index if index < source.Count - 1 else index - 1) self.updateControlls(evt)
def onMove(self, evt, direction): curIndex = self.enabledLangs.GetSelection() if curIndex == -1: return if direction == -1 and curIndex == 0 or direction == 1 and curIndex == self.enabledLangs.Count - 1: return newIndex = curIndex + direction curItem = self.enabledLangs.GetString(curIndex) newItem = self.enabledLangs.GetString(newIndex) self.enabledLangs.SetString(curIndex, newItem) self.enabledLangs.SetString(newIndex, curItem) self.enabledLangs.SetSelection(newIndex) self.updateControlls(evt)
def onChange(self, evt): self.updateControlls()
def updateControlls(self, evt=None): # possibly adding temporary class fields to eliminate unnnecessary computations. index = self.enabledLangs.GetSelection() self.moveUpButton.Disable() if index == 0 or index == -1 else self.moveUpButton.Enable() self.moveDownButton.Disable() if index == self.enabledLangs.Count - 1 or index == -1 else self.moveDownButton.Enable() self.addButton.Disable() if len(self.availableLangs.Items) == 0 else self.addButton.Enable() self.removeButton.Disable() if len(self.enabledLangs.Items) == 0 else self.removeButton.Enable() if evt is not None and (isinstance(evt.EventObject, wx.Button) and evt.EventObject.Name in ["Up", "Down"] and (index == 0 or index == self.enabledLangs.Count -1) or evt.EventObject.Name == "Add" and len(self.availableLangs.Items) == 0 or evt.EventObject.Name == "Remove" and len(self.enabledLangs.Items) == 0): self.enabledLangs.SetFocus()
def onSave(self): # Config saving here self.onSaveCallback(self.enabledLangs.Items)
class GlobalPlugin(globalPluginHandler.GlobalPlugin):
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) OCRSettingsPanel.onSaveCallback = self.checkLanguages gui.NVDASettingsDialog.categoryClasses.append(OCRSettingsPanel)
def terminate(self): gui.NVDASettingsDialog.categoryClasses.remove(OCRSettingsPanel)
def checkLanguages(self, langs): ui.message("+".join(langs))
On 6/28/22, Rui Fontes <rui.fontes@...> wrote:
Hi Beqa!
Thanks by the suggestions!
Can you gave me an example of such callback?
My knowledge is still very poor!
Best regards,
Rui Fontes NVDA portuguese team
Às 13:49 de 28/06/2022, Beqa Gozalishvili escreveu:
hello.
this addon have one very serious problem.
downloading of imported language happens in the main thread which locks up NVDA. If user have bad internet connection, they can stay without speech for several minutes. this should be corrected as soon as possible.
suggestion, tesseract can handle more than two languages, and instead of selecting one more language as second language, i suggest a following ui: one list, which will include all possible tesseract languages, add buttton, second list which will include all added languages from the first list, remove button, and move up/down buttons. on saving list of languages would be written in config and some callback should be called, which would check if some of just saved languages are missing, and download them in the background thread.
On 6/19/22, Rui Fontes <rui.fontes@...> wrote:
Hola Javi!
Firstly, thanks by your PR!
But, I would like to better it a litle more...
The case is:
When I have set this new laptop and installed Dropbox, I have selected to backup the desktop folder, and so my desktop full path is:
c:\Users\userName\dropbox\ambiente de trabalho
"Ambiente de trabalho" is the portuguese expression for "Desktop"...
So, I have tried to use shlobj.getKnownFolderId to get the correct desktop path for all cases...
In spite of modifying the shlobj.ini and importing it in the add-on, I didn't manage to do it...
I have added in shlobj.py, on the
class FolderId(str, Enum):
the following lines:
#Desktop folder # The typical path is "C:\Users\Utilizador\appData\desktop APP_DATA_DESKTOP = "{B2C5E279-7ADD-439F-B28C-C41FE1BBF672}"
the string between quotes was found at:
https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid"""
Someone can help on this?
Best regards,
Rui Fontes NVDA portuguese team
Às 17:59 de 11/06/2022, Javi Domínguez escreveu:
Hello.
You have a pull request that fixes both issues.
https://github.com/ruifontes/tesseractOCR/pull/2
Greetings
Javi Dominguez
El 05/06/2022 a las 23:01, Javi Domínguez via groups.io escribió:
Hello again.
I have run wia-cmd-scanner.exe directly from the command line, in the Windows CMD, and it has worked perfectly.
However from the addon it doesn't work. stderr shows:
b'The system cannot find the specified path.\r\n'
I hope this helps. It's late and I can't do any more research. Tomorrow dawns very early.
Good nitht
Javi
El 05/06/2022 a las 22:24, Javi Domínguez via groups.io escribió:
Hello.
* It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad! OK. I'll take a look at that.
* The scanner is recognized as WIA compatible? what do you mean with "is recognized as WIA compatible"? Yes, the scanner is WIA compliant, other apps recognize it but the addon I don't know, it just doesn't do anything.
* What Windows version? Windows 10 21H2 (x64) build 19044.1706
* So, I should name each thread differently... Yes, it would be convenient.
* And, before starting another thread, verify if it is active, right? I think so. I would wait for the current thread to finish before starting another.
Note that if you assign the new thread to self._thread, the old thread will continue to run until it finishes but you will no longer have a reference to it. You will only be able to access it via threading.enumerate().
You may need a method to kill threads that are stuck or taking too long.
Greetings
Javi
El 05/06/2022 a las 20:34, Rui Fontes escribió:
Hola Javi!
Comments in midle of your message marked with *...
Às 18:47 de 05/06/2022, Javi Domínguez escreveu:
When I try to recognize a file on the desktop two things happen:
1. If this is the first time a file is recognized, it says "file not supported" (tested with PDF and BMP file types). The same file recognized from a folder in Windows explorer works fine. * It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad!
2. If another file has been recognized before, it process any file even if it is not of a supported type. In any case, supported type or not, it always shows the result of the previous recognition, not the requested file. Even after manually deleting the oc.txt and ocr-xxx.png files from the addon's images folder, it re-processes the previously requested file. * It was an error on code... The path of last document was not cleared, so list of ocr-xxx.png file was created again...
On the other hand, recognition from scanner does not work for me. My scanner is HP Scanjet G2410, It may not be supported but the addon does not speak any message about it. The thread that processes this remains active and never terminates. If the script is executed again, another thread is launched that also remains active and so on forever. It is normal for the user, if he does not receive a response, to try to run it again, so you can end up with a lot of active threads.
* The scanner is recognized as WIA compatible?
* What Windows version?
I have the habit of naming the treads that I use to be able to debug better with threading.enumerate(). I have added the line to __init__.py self._thread.name = "tesseractOCR" before starting the thread to do these tests.
* So, I should name each thread differently...
* And, before starting another thread, verify if it is active, right?
finally, in terms of user experience, I think you need to give more information about what is happening. Sometimes, if the recognition takes time, the user does not know if it is working correctly or not.
* It is schedulled for next version...
Thanks!
Rui Fontes
|
|
Hello.
as for point 1: i ment to wrote a function which would accept command and arguments, and don't repeat all things with other things, like attaching startupinfo everytime and so on. 2. Yes, move all interface related code in a separate module to simplify code. 3. Also for languages, move language definitions into a separate module.
toggle quoted messageShow quoted text
On 7/5/22, Rui Fontes <rui.fontes@...> wrote: Thanks Beqa!
You wrote:
These methods are generated to pass direction argument to handler function, because i didn't think of another way and i didn't want to define two similar methods. Ok! I already make use of them...
But you have created two similar methods, onAdd and onRemove...
It is possible to use the same method with the parameters "target" and "source"?
You wrote:
... one more suggestion would be to remove repetition in languages. you have list and dictionary of languages. Lets reuse dictionary for all possible needs and use ClientData from ItemContainer to associate item with needed data. Done!
You wrote:
Also generalise function to run things in subprocess... I don't think it is possible more...
One function to generate .png files from .pdf, other to create the list of .png files, one to make OCR and one for scanning...
Maybe joining the two first, but I don't see any advantage...
You wrote:
... extract interface class in separate module... Create a settings.py only to create the TesseractOCR setting category?
You wrote:
... also do the same with languages This one I did not understood...
Create a languages.py to create all languages variables to be used?
New version at:
https://www.dropbox.com/s/mwtmupoetd0le8j/tesseractOCR_2022.07.nvda-addon?dl=1
Best regards,
Rui Fontes NVDA portuguese team
On 7/5/22, Rui Fontes <rui.fontes@...> wrote:
Hello Beqa!
Thanks for your suggestion!
See what I did with your suggestion:
https://www.dropbox.com/s/658ua5z2sumt1hd/tesseractOCR_2022.07.nvda-addon?dl=1
By the way, what was the purpose of:
self.onMoveUp = functools.partial(self.onMove, direction=-1) self.onMoveDown = functools.partial(self.onMove, direction=1)
Best regards,
Best regards,
Rui Fontes NVDA portuguese team
Às 09:30 de 01/07/2022, Beqa Gozalishvili escreveu:
Hello.
I wanted to refactor this addon, but unfortunately i don't have enough time yet, may be i will return to this in the near future, but as for suggestions, i wrote a minimal example how it should look.
I am sending a minimal code example here.
Maybe there is a better way of doing such thing, but this is what i could think off today morning.
import addonHandler import functools import globalPluginHandler import gui import ui import wx
class OCRSettingsPanel(gui.SettingsPanel): title = "TesseractOCR"
def makeSettings(self, settingsSizer): sHelper = gui.guiHelper.BoxSizerHelper(self, sizer = settingsSizer) self.onMoveUp = functools.partial(self.onMove, direction=-1) self.onMoveDown = functools.partial(self.onMove, direction=1) self.availableLangs = sHelper.addLabeledControl("Available languages", wx.ListBox, choices=[], style = wx.LB_SINGLE|wx.LB_SORT) self.addButton = sHelper.addItem(wx.Button(self, label ="&Add", name="Add")) self.addButton.Bind(wx.EVT_BUTTON, self.onAdd) self.enabledLangs = sHelper.addLabeledControl("Selected languages", wx.ListBox, choices=[], style = wx.LB_SINGLE) self.enabledLangs.Bind(wx.EVT_LISTBOX, self.onChange) self.enabledLangs.Bind(wx.EVT_KEY_DOWN, self.onKeyDown) self.removeButton = sHelper.addItem(wx.Button(self, label ="&Remove", name="Remove")) self.removeButton.Bind(wx.EVT_BUTTON, self.onRemove) self.moveUpButton = sHelper.addItem(wx.Button(self, label ="Move &up", name="Up")) self.moveUpButton.Bind(wx.EVT_BUTTON, self.onMoveUp) self.moveDownButton = sHelper.addItem(wx.Button(self, label ="Move &down", name="Down")) self.moveDownButton.Bind(wx.EVT_BUTTON, self.onMoveDown) self.updateControlls()
def onKeyDown(self, evt): if evt.KeyCode == wx.WXK_UP and evt.controlDown: self.onMoveUp(evt) elif evt.KeyCode == wx.WXK_DOWN and evt.controlDown: self.onMoveDown(evt) else: evt.Skip()
def onAdd(self, evt): self.swapItems(evt, self.availableLangs, self.enabledLangs)
def onRemove(self, evt): self.swapItems(evt, self.enabledLangs, self.availableLangs)
def swapItems(self, evt, source, target): index = source.GetSelection() if index == -1: return target.Append(source.GetString(index)) source.Delete(index) if len(source.Items) > 0: source.SetSelection(index if index < source.Count - 1 else index - 1) self.updateControlls(evt)
def onMove(self, evt, direction): curIndex = self.enabledLangs.GetSelection() if curIndex == -1: return if direction == -1 and curIndex == 0 or direction == 1 and curIndex == self.enabledLangs.Count - 1: return newIndex = curIndex + direction curItem = self.enabledLangs.GetString(curIndex) newItem = self.enabledLangs.GetString(newIndex) self.enabledLangs.SetString(curIndex, newItem) self.enabledLangs.SetString(newIndex, curItem) self.enabledLangs.SetSelection(newIndex) self.updateControlls(evt)
def onChange(self, evt): self.updateControlls()
def updateControlls(self, evt=None): # possibly adding temporary class fields to eliminate unnnecessary computations. index = self.enabledLangs.GetSelection() self.moveUpButton.Disable() if index == 0 or index == -1 else self.moveUpButton.Enable() self.moveDownButton.Disable() if index == self.enabledLangs.Count - 1 or index == -1 else self.moveDownButton.Enable() self.addButton.Disable() if len(self.availableLangs.Items) == 0 else self.addButton.Enable() self.removeButton.Disable() if len(self.enabledLangs.Items) == 0 else self.removeButton.Enable() if evt is not None and (isinstance(evt.EventObject, wx.Button) and evt.EventObject.Name in ["Up", "Down"] and (index == 0 or index == self.enabledLangs.Count -1) or evt.EventObject.Name == "Add" and len(self.availableLangs.Items) == 0 or evt.EventObject.Name == "Remove" and len(self.enabledLangs.Items) == 0): self.enabledLangs.SetFocus()
def onSave(self): # Config saving here self.onSaveCallback(self.enabledLangs.Items)
class GlobalPlugin(globalPluginHandler.GlobalPlugin):
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) OCRSettingsPanel.onSaveCallback = self.checkLanguages
gui.NVDASettingsDialog.categoryClasses.append(OCRSettingsPanel)
def terminate(self):
gui.NVDASettingsDialog.categoryClasses.remove(OCRSettingsPanel)
def checkLanguages(self, langs): ui.message("+".join(langs))
On 6/28/22, Rui Fontes <rui.fontes@...> wrote:
Hi Beqa!
Thanks by the suggestions!
Can you gave me an example of such callback?
My knowledge is still very poor!
Best regards,
Rui Fontes NVDA portuguese team
Às 13:49 de 28/06/2022, Beqa Gozalishvili escreveu:
hello.
this addon have one very serious problem.
downloading of imported language happens in the main thread which locks up NVDA. If user have bad internet connection, they can stay without speech for several minutes. this should be corrected as soon as possible.
suggestion, tesseract can handle more than two languages, and instead of selecting one more language as second language, i suggest a following ui: one list, which will include all possible tesseract languages, add buttton, second list which will include all added languages from the first list, remove button, and move up/down buttons. on saving list of languages would be written in config and some callback should be called, which would check if some of just saved languages are missing, and download them in the background thread.
On 6/19/22, Rui Fontes <rui.fontes@...> wrote:
Hola Javi!
Firstly, thanks by your PR!
But, I would like to better it a litle more...
The case is:
When I have set this new laptop and installed Dropbox, I have selected to backup the desktop folder, and so my desktop full path is:
c:\Users\userName\dropbox\ambiente de trabalho
"Ambiente de trabalho" is the portuguese expression for "Desktop"...
So, I have tried to use shlobj.getKnownFolderId to get the correct desktop path for all cases...
In spite of modifying the shlobj.ini and importing it in the add-on, I didn't manage to do it...
I have added in shlobj.py, on the
class FolderId(str, Enum):
the following lines:
#Desktop folder # The typical path is "C:\Users\Utilizador\appData\desktop APP_DATA_DESKTOP = "{B2C5E279-7ADD-439F-B28C-C41FE1BBF672}"
the string between quotes was found at:
https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid"""
Someone can help on this?
Best regards,
Rui Fontes NVDA portuguese team
Às 17:59 de 11/06/2022, Javi Domínguez escreveu:
Hello.
You have a pull request that fixes both issues.
https://github.com/ruifontes/tesseractOCR/pull/2
Greetings
Javi Dominguez
El 05/06/2022 a las 23:01, Javi Domínguez via groups.io escribió:
Hello again.
I have run wia-cmd-scanner.exe directly from the command line, in the Windows CMD, and it has worked perfectly.
However from the addon it doesn't work. stderr shows:
b'The system cannot find the specified path.\r\n'
I hope this helps. It's late and I can't do any more research. Tomorrow dawns very early.
Good nitht
Javi
El 05/06/2022 a las 22:24, Javi Domínguez via groups.io escribió:
Hello.
* It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad! OK. I'll take a look at that.
* The scanner is recognized as WIA compatible? what do you mean with "is recognized as WIA compatible"? Yes, the scanner is WIA compliant, other apps recognize it but the addon I don't know, it just doesn't do anything.
* What Windows version? Windows 10 21H2 (x64) build 19044.1706
* So, I should name each thread differently... Yes, it would be convenient.
* And, before starting another thread, verify if it is active, right? I think so. I would wait for the current thread to finish before starting another.
Note that if you assign the new thread to self._thread, the old thread will continue to run until it finishes but you will no longer have a reference to it. You will only be able to access it via threading.enumerate().
You may need a method to kill threads that are stuck or taking too long.
Greetings
Javi
El 05/06/2022 a las 20:34, Rui Fontes escribió:
Hola Javi!
Comments in midle of your message marked with *...
Às 18:47 de 05/06/2022, Javi Domínguez escreveu:
When I try to recognize a file on the desktop two things happen:
1. If this is the first time a file is recognized, it says "file not supported" (tested with PDF and BMP file types). The same file recognized from a folder in Windows explorer works fine. * It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad!
2. If another file has been recognized before, it process any file even if it is not of a supported type. In any case, supported type or not, it always shows the result of the previous recognition, not the requested file. Even after manually deleting the oc.txt and ocr-xxx.png files from the addon's images folder, it re-processes the previously requested file. * It was an error on code... The path of last document was not cleared, so list of ocr-xxx.png file was created again...
On the other hand, recognition from scanner does not work for me. My scanner is HP Scanjet G2410, It may not be supported but the addon does not speak any message about it. The thread that processes this remains active and never terminates. If the script is executed again, another thread is launched that also remains active and so on forever. It is normal for the user, if he does not receive a response, to try to run it again, so you can end up with a lot of active threads.
* The scanner is recognized as WIA compatible?
* What Windows version?
I have the habit of naming the treads that I use to be able to debug better with threading.enumerate(). I have added the line to __init__.py self._thread.name = "tesseractOCR" before starting the thread to do these tests.
* So, I should name each thread differently...
* And, before starting another thread, verify if it is active, right?
finally, in terms of user experience, I think you need to give more information about what is happening. Sometimes, if the recognition takes time, the user does not know if it is working correctly or not.
* It is schedulled for next version...
Thanks!
Rui Fontes
|
|
Hello Beqa! You wrote: as for point 1: i ment to wrote a function which would accept command and arguments, and don't repeat all things with other things, like attaching startupinfo everytime and so on. Done! Now, let's try point 2 and 3... 😊 Best regards, Rui Fontes NVDA portuguese team
|
|
Hello. Only the new test link for add-on was missing... Thanks.
Locutor Antonio Cezar
Em 05/07/2022 21:10, Rui Fontes
escreveu:
toggle quoted messageShow quoted text
Hello
Beqa!
You wrote:
as for point 1: i ment to wrote a function which would accept
command
and arguments, and don't repeat all things
with other things, like
attaching startupinfo everytime and so on.
Done!
Now, let's try point 2 and 3... 😊
Best regards,
Rui Fontes
NVDA portuguese team
|
|
Hello! I think I managed to do everything... Created various modules: configPanel.py with the construction of the settings panel to include in NVDA settings; languages.py where are listed all languages and created the variables related with choosing languages; vars.py where are declared almost all variables. I would like someone to review the add-on to include it in the repository... Download link: https://www.dropbox.com/s/j9jesl986m2hdlv/tesseractOCR_2022.07.nvda-addon?dl=1Best regards, Rui Fontes NVDA portuguese team Às 15:42 de 05/07/2022, Beqa Gozalishvili escreveu:
toggle quoted messageShow quoted text
Hello.
as for point 1: i ment to wrote a function which would accept command and arguments, and don't repeat all things with other things, like attaching startupinfo everytime and so on. 2. Yes, move all interface related code in a separate module to simplify code. 3. Also for languages, move language definitions into a separate module.
On 7/5/22, Rui Fontes <rui.fontes@...> wrote:
Thanks Beqa!
You wrote:
These methods are generated to pass direction argument to handler function, because i didn't think of another way and i didn't want to define two similar methods. Ok! I already make use of them...
But you have created two similar methods, onAdd and onRemove...
It is possible to use the same method with the parameters "target" and "source"?
You wrote:
... one more suggestion would be to remove repetition in languages. you have list and dictionary of languages. Lets reuse dictionary for all possible needs and use ClientData from ItemContainer to associate item with needed data. Done!
You wrote:
Also generalise function to run things in subprocess... I don't think it is possible more...
One function to generate .png files from .pdf, other to create the list of .png files, one to make OCR and one for scanning...
Maybe joining the two first, but I don't see any advantage...
You wrote:
... extract interface class in separate module... Create a settings.py only to create the TesseractOCR setting category?
You wrote:
... also do the same with languages This one I did not understood...
Create a languages.py to create all languages variables to be used?
New version at:
https://www.dropbox.com/s/mwtmupoetd0le8j/tesseractOCR_2022.07.nvda-addon?dl=1
Best regards,
Rui Fontes NVDA portuguese team
On 7/5/22, Rui Fontes <rui.fontes@...> wrote:
Hello Beqa!
Thanks for your suggestion!
See what I did with your suggestion:
https://www.dropbox.com/s/658ua5z2sumt1hd/tesseractOCR_2022.07.nvda-addon?dl=1
By the way, what was the purpose of:
self.onMoveUp = functools.partial(self.onMove, direction=-1) self.onMoveDown = functools.partial(self.onMove, direction=1)
Best regards,
Best regards,
Rui Fontes NVDA portuguese team
Às 09:30 de 01/07/2022, Beqa Gozalishvili escreveu:
Hello.
I wanted to refactor this addon, but unfortunately i don't have enough time yet, may be i will return to this in the near future, but as for suggestions, i wrote a minimal example how it should look.
I am sending a minimal code example here.
Maybe there is a better way of doing such thing, but this is what i could think off today morning.
import addonHandler import functools import globalPluginHandler import gui import ui import wx
class OCRSettingsPanel(gui.SettingsPanel): title = "TesseractOCR"
def makeSettings(self, settingsSizer): sHelper = gui.guiHelper.BoxSizerHelper(self, sizer = settingsSizer) self.onMoveUp = functools.partial(self.onMove, direction=-1) self.onMoveDown = functools.partial(self.onMove, direction=1) self.availableLangs = sHelper.addLabeledControl("Available languages", wx.ListBox, choices=[], style = wx.LB_SINGLE|wx.LB_SORT) self.addButton = sHelper.addItem(wx.Button(self, label ="&Add", name="Add")) self.addButton.Bind(wx.EVT_BUTTON, self.onAdd) self.enabledLangs = sHelper.addLabeledControl("Selected languages", wx.ListBox, choices=[], style = wx.LB_SINGLE) self.enabledLangs.Bind(wx.EVT_LISTBOX, self.onChange) self.enabledLangs.Bind(wx.EVT_KEY_DOWN, self.onKeyDown) self.removeButton = sHelper.addItem(wx.Button(self, label ="&Remove", name="Remove")) self.removeButton.Bind(wx.EVT_BUTTON, self.onRemove) self.moveUpButton = sHelper.addItem(wx.Button(self, label ="Move &up", name="Up")) self.moveUpButton.Bind(wx.EVT_BUTTON, self.onMoveUp) self.moveDownButton = sHelper.addItem(wx.Button(self, label ="Move &down", name="Down")) self.moveDownButton.Bind(wx.EVT_BUTTON, self.onMoveDown) self.updateControlls()
def onKeyDown(self, evt): if evt.KeyCode == wx.WXK_UP and evt.controlDown: self.onMoveUp(evt) elif evt.KeyCode == wx.WXK_DOWN and evt.controlDown: self.onMoveDown(evt) else: evt.Skip()
def onAdd(self, evt): self.swapItems(evt, self.availableLangs, self.enabledLangs)
def onRemove(self, evt): self.swapItems(evt, self.enabledLangs, self.availableLangs)
def swapItems(self, evt, source, target): index = source.GetSelection() if index == -1: return target.Append(source.GetString(index)) source.Delete(index) if len(source.Items) > 0: source.SetSelection(index if index < source.Count - 1 else index - 1) self.updateControlls(evt)
def onMove(self, evt, direction): curIndex = self.enabledLangs.GetSelection() if curIndex == -1: return if direction == -1 and curIndex == 0 or direction == 1 and curIndex == self.enabledLangs.Count - 1: return newIndex = curIndex + direction curItem = self.enabledLangs.GetString(curIndex) newItem = self.enabledLangs.GetString(newIndex) self.enabledLangs.SetString(curIndex, newItem) self.enabledLangs.SetString(newIndex, curItem) self.enabledLangs.SetSelection(newIndex) self.updateControlls(evt)
def onChange(self, evt): self.updateControlls()
def updateControlls(self, evt=None): # possibly adding temporary class fields to eliminate unnnecessary computations. index = self.enabledLangs.GetSelection() self.moveUpButton.Disable() if index == 0 or index == -1 else self.moveUpButton.Enable() self.moveDownButton.Disable() if index == self.enabledLangs.Count - 1 or index == -1 else self.moveDownButton.Enable() self.addButton.Disable() if len(self.availableLangs.Items) == 0 else self.addButton.Enable() self.removeButton.Disable() if len(self.enabledLangs.Items) == 0 else self.removeButton.Enable() if evt is not None and (isinstance(evt.EventObject, wx.Button) and evt.EventObject.Name in ["Up", "Down"] and (index == 0 or index == self.enabledLangs.Count -1) or evt.EventObject.Name == "Add" and len(self.availableLangs.Items) == 0 or evt.EventObject.Name == "Remove" and len(self.enabledLangs.Items) == 0): self.enabledLangs.SetFocus()
def onSave(self): # Config saving here self.onSaveCallback(self.enabledLangs.Items)
class GlobalPlugin(globalPluginHandler.GlobalPlugin):
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) OCRSettingsPanel.onSaveCallback = self.checkLanguages
gui.NVDASettingsDialog.categoryClasses.append(OCRSettingsPanel)
def terminate(self):
gui.NVDASettingsDialog.categoryClasses.remove(OCRSettingsPanel)
def checkLanguages(self, langs): ui.message("+".join(langs))
On 6/28/22, Rui Fontes <rui.fontes@...> wrote:
Hi Beqa!
Thanks by the suggestions!
Can you gave me an example of such callback?
My knowledge is still very poor!
Best regards,
Rui Fontes NVDA portuguese team
Às 13:49 de 28/06/2022, Beqa Gozalishvili escreveu:
hello.
this addon have one very serious problem.
downloading of imported language happens in the main thread which locks up NVDA. If user have bad internet connection, they can stay without speech for several minutes. this should be corrected as soon as possible.
suggestion, tesseract can handle more than two languages, and instead of selecting one more language as second language, i suggest a following ui: one list, which will include all possible tesseract languages, add buttton, second list which will include all added languages from the first list, remove button, and move up/down buttons. on saving list of languages would be written in config and some callback should be called, which would check if some of just saved languages are missing, and download them in the background thread.
On 6/19/22, Rui Fontes <rui.fontes@...> wrote:
Hola Javi!
Firstly, thanks by your PR!
But, I would like to better it a litle more...
The case is:
When I have set this new laptop and installed Dropbox, I have selected to backup the desktop folder, and so my desktop full path is:
c:\Users\userName\dropbox\ambiente de trabalho
"Ambiente de trabalho" is the portuguese expression for "Desktop"...
So, I have tried to use shlobj.getKnownFolderId to get the correct desktop path for all cases...
In spite of modifying the shlobj.ini and importing it in the add-on, I didn't manage to do it...
I have added in shlobj.py, on the
class FolderId(str, Enum):
the following lines:
#Desktop folder # The typical path is "C:\Users\Utilizador\appData\desktop APP_DATA_DESKTOP = "{B2C5E279-7ADD-439F-B28C-C41FE1BBF672}"
the string between quotes was found at:
https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid"""
Someone can help on this?
Best regards,
Rui Fontes NVDA portuguese team
Às 17:59 de 11/06/2022, Javi Domínguez escreveu:
Hello.
You have a pull request that fixes both issues.
https://github.com/ruifontes/tesseractOCR/pull/2
Greetings
Javi Dominguez
El 05/06/2022 a las 23:01, Javi Domínguez via groups.io escribió:
Hello again.
I have run wia-cmd-scanner.exe directly from the command line, in the Windows CMD, and it has worked perfectly.
However from the addon it doesn't work. stderr shows:
b'The system cannot find the specified path.\r\n'
I hope this helps. It's late and I can't do any more research. Tomorrow dawns very early.
Good nitht
Javi
El 05/06/2022 a las 22:24, Javi Domínguez via groups.io escribió:
Hello.
* It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad! OK. I'll take a look at that.
* The scanner is recognized as WIA compatible? what do you mean with "is recognized as WIA compatible"? Yes, the scanner is WIA compliant, other apps recognize it but the addon I don't know, it just doesn't do anything.
* What Windows version? Windows 10 21H2 (x64) build 19044.1706
* So, I should name each thread differently... Yes, it would be convenient.
* And, before starting another thread, verify if it is active, right? I think so. I would wait for the current thread to finish before starting another.
Note that if you assign the new thread to self._thread, the old thread will continue to run until it finishes but you will no longer have a reference to it. You will only be able to access it via threading.enumerate().
You may need a method to kill threads that are stuck or taking too long.
Greetings
Javi
El 05/06/2022 a las 20:34, Rui Fontes escribió:
Hola Javi!
Comments in midle of your message marked with *...
Às 18:47 de 05/06/2022, Javi Domínguez escreveu:
When I try to recognize a file on the desktop two things happen:
1. If this is the first time a file is recognized, it says "file not supported" (tested with PDF and BMP file types). The same file recognized from a folder in Windows explorer works fine. * It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad!
2. If another file has been recognized before, it process any file even if it is not of a supported type. In any case, supported type or not, it always shows the result of the previous recognition, not the requested file. Even after manually deleting the oc.txt and ocr-xxx.png files from the addon's images folder, it re-processes the previously requested file. * It was an error on code... The path of last document was not cleared, so list of ocr-xxx.png file was created again...
On the other hand, recognition from scanner does not work for me. My scanner is HP Scanjet G2410, It may not be supported but the addon does not speak any message about it. The thread that processes this remains active and never terminates. If the script is executed again, another thread is launched that also remains active and so on forever. It is normal for the user, if he does not receive a response, to try to run it again, so you can end up with a lot of active threads.
* The scanner is recognized as WIA compatible?
* What Windows version?
I have the habit of naming the treads that I use to be able to debug better with threading.enumerate(). I have added the line to __init__.py self._thread.name = "tesseractOCR" before starting the thread to do these tests.
* So, I should name each thread differently...
* And, before starting another thread, verify if it is active, right?
finally, in terms of user experience, I think you need to give more information about what is happening. Sometimes, if the recognition takes time, the user does not know if it is working correctly or not.
* It is schedulled for next version...
Thanks!
Rui Fontes
|
|
Edited message, since I have changed the keystroke for digitalize from scanner... Hello! I think I managed to do everything... Created various modules: configPanel.py with the construction of the settings panel to include in NVDA settings; languages.py where are listed all languages and created the variables related with choosing languages; vars.py where are declared almost all variables. The keystroke for digitalize from scanner was changed to: Windows+Control+w I would like someone to review the add-on to include it in the repository... Download link: https://www.dropbox.com/s/j9jesl986m2hdlv/tesseractOCR_2022.07.nvda-addon?dl=1Best regards, Rui Fontes NVDA portuguese team Às 15:42 de 05/07/2022, Beqa Gozalishvili escreveu:
toggle quoted messageShow quoted text
Hello.
as for point 1: i ment to wrote a function which would accept command and arguments, and don't repeat all things with other things, like attaching startupinfo everytime and so on. 2. Yes, move all interface related code in a separate module to simplify code. 3. Also for languages, move language definitions into a separate module.
On 7/5/22, Rui Fontes <rui.fontes@...> wrote:
Thanks Beqa!
You wrote:
These methods are generated to pass direction argument to handler function, because i didn't think of another way and i didn't want to define two similar methods. Ok! I already make use of them...
But you have created two similar methods, onAdd and onRemove...
It is possible to use the same method with the parameters "target" and "source"?
You wrote:
... one more suggestion would be to remove repetition in languages. you have list and dictionary of languages. Lets reuse dictionary for all possible needs and use ClientData from ItemContainer to associate item with needed data. Done!
You wrote:
Also generalise function to run things in subprocess... I don't think it is possible more...
One function to generate .png files from .pdf, other to create the list of .png files, one to make OCR and one for scanning...
Maybe joining the two first, but I don't see any advantage...
You wrote:
... extract interface class in separate module... Create a settings.py only to create the TesseractOCR setting category?
You wrote:
... also do the same with languages This one I did not understood...
Create a languages.py to create all languages variables to be used?
New version at:
https://www.dropbox.com/s/mwtmupoetd0le8j/tesseractOCR_2022.07.nvda-addon?dl=1
Best regards,
Rui Fontes NVDA portuguese team
On 7/5/22, Rui Fontes <rui.fontes@...> wrote:
Hello Beqa!
Thanks for your suggestion!
See what I did with your suggestion:
https://www.dropbox.com/s/658ua5z2sumt1hd/tesseractOCR_2022.07.nvda-addon?dl=1
By the way, what was the purpose of:
self.onMoveUp = functools.partial(self.onMove, direction=-1) self.onMoveDown = functools.partial(self.onMove, direction=1)
Best regards,
Best regards,
Rui Fontes NVDA portuguese team
Às 09:30 de 01/07/2022, Beqa Gozalishvili escreveu:
Hello.
I wanted to refactor this addon, but unfortunately i don't have enough time yet, may be i will return to this in the near future, but as for suggestions, i wrote a minimal example how it should look.
I am sending a minimal code example here.
Maybe there is a better way of doing such thing, but this is what i could think off today morning.
import addonHandler import functools import globalPluginHandler import gui import ui import wx
class OCRSettingsPanel(gui.SettingsPanel): title = "TesseractOCR"
def makeSettings(self, settingsSizer): sHelper = gui.guiHelper.BoxSizerHelper(self, sizer = settingsSizer) self.onMoveUp = functools.partial(self.onMove, direction=-1) self.onMoveDown = functools.partial(self.onMove, direction=1) self.availableLangs = sHelper.addLabeledControl("Available languages", wx.ListBox, choices=[], style = wx.LB_SINGLE|wx.LB_SORT) self.addButton = sHelper.addItem(wx.Button(self, label ="&Add", name="Add")) self.addButton.Bind(wx.EVT_BUTTON, self.onAdd) self.enabledLangs = sHelper.addLabeledControl("Selected languages", wx.ListBox, choices=[], style = wx.LB_SINGLE) self.enabledLangs.Bind(wx.EVT_LISTBOX, self.onChange) self.enabledLangs.Bind(wx.EVT_KEY_DOWN, self.onKeyDown) self.removeButton = sHelper.addItem(wx.Button(self, label ="&Remove", name="Remove")) self.removeButton.Bind(wx.EVT_BUTTON, self.onRemove) self.moveUpButton = sHelper.addItem(wx.Button(self, label ="Move &up", name="Up")) self.moveUpButton.Bind(wx.EVT_BUTTON, self.onMoveUp) self.moveDownButton = sHelper.addItem(wx.Button(self, label ="Move &down", name="Down")) self.moveDownButton.Bind(wx.EVT_BUTTON, self.onMoveDown) self.updateControlls()
def onKeyDown(self, evt): if evt.KeyCode == wx.WXK_UP and evt.controlDown: self.onMoveUp(evt) elif evt.KeyCode == wx.WXK_DOWN and evt.controlDown: self.onMoveDown(evt) else: evt.Skip()
def onAdd(self, evt): self.swapItems(evt, self.availableLangs, self.enabledLangs)
def onRemove(self, evt): self.swapItems(evt, self.enabledLangs, self.availableLangs)
def swapItems(self, evt, source, target): index = source.GetSelection() if index == -1: return target.Append(source.GetString(index)) source.Delete(index) if len(source.Items) > 0: source.SetSelection(index if index < source.Count - 1 else index - 1) self.updateControlls(evt)
def onMove(self, evt, direction): curIndex = self.enabledLangs.GetSelection() if curIndex == -1: return if direction == -1 and curIndex == 0 or direction == 1 and curIndex == self.enabledLangs.Count - 1: return newIndex = curIndex + direction curItem = self.enabledLangs.GetString(curIndex) newItem = self.enabledLangs.GetString(newIndex) self.enabledLangs.SetString(curIndex, newItem) self.enabledLangs.SetString(newIndex, curItem) self.enabledLangs.SetSelection(newIndex) self.updateControlls(evt)
def onChange(self, evt): self.updateControlls()
def updateControlls(self, evt=None): # possibly adding temporary class fields to eliminate unnnecessary computations. index = self.enabledLangs.GetSelection() self.moveUpButton.Disable() if index == 0 or index == -1 else self.moveUpButton.Enable() self.moveDownButton.Disable() if index == self.enabledLangs.Count - 1 or index == -1 else self.moveDownButton.Enable() self.addButton.Disable() if len(self.availableLangs.Items) == 0 else self.addButton.Enable() self.removeButton.Disable() if len(self.enabledLangs.Items) == 0 else self.removeButton.Enable() if evt is not None and (isinstance(evt.EventObject, wx.Button) and evt.EventObject.Name in ["Up", "Down"] and (index == 0 or index == self.enabledLangs.Count -1) or evt.EventObject.Name == "Add" and len(self.availableLangs.Items) == 0 or evt.EventObject.Name == "Remove" and len(self.enabledLangs.Items) == 0): self.enabledLangs.SetFocus()
def onSave(self): # Config saving here self.onSaveCallback(self.enabledLangs.Items)
class GlobalPlugin(globalPluginHandler.GlobalPlugin):
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) OCRSettingsPanel.onSaveCallback = self.checkLanguages
gui.NVDASettingsDialog.categoryClasses.append(OCRSettingsPanel)
def terminate(self):
gui.NVDASettingsDialog.categoryClasses.remove(OCRSettingsPanel)
def checkLanguages(self, langs): ui.message("+".join(langs))
On 6/28/22, Rui Fontes <rui.fontes@...> wrote:
Hi Beqa!
Thanks by the suggestions!
Can you gave me an example of such callback?
My knowledge is still very poor!
Best regards,
Rui Fontes NVDA portuguese team
Às 13:49 de 28/06/2022, Beqa Gozalishvili escreveu:
hello.
this addon have one very serious problem.
downloading of imported language happens in the main thread which locks up NVDA. If user have bad internet connection, they can stay without speech for several minutes. this should be corrected as soon as possible.
suggestion, tesseract can handle more than two languages, and instead of selecting one more language as second language, i suggest a following ui: one list, which will include all possible tesseract languages, add buttton, second list which will include all added languages from the first list, remove button, and move up/down buttons. on saving list of languages would be written in config and some callback should be called, which would check if some of just saved languages are missing, and download them in the background thread.
On 6/19/22, Rui Fontes <rui.fontes@...> wrote:
Hola Javi!
Firstly, thanks by your PR!
But, I would like to better it a litle more...
The case is:
When I have set this new laptop and installed Dropbox, I have selected to backup the desktop folder, and so my desktop full path is:
c:\Users\userName\dropbox\ambiente de trabalho
"Ambiente de trabalho" is the portuguese expression for "Desktop"...
So, I have tried to use shlobj.getKnownFolderId to get the correct desktop path for all cases...
In spite of modifying the shlobj.ini and importing it in the add-on, I didn't manage to do it...
I have added in shlobj.py, on the
class FolderId(str, Enum):
the following lines:
#Desktop folder # The typical path is "C:\Users\Utilizador\appData\desktop APP_DATA_DESKTOP = "{B2C5E279-7ADD-439F-B28C-C41FE1BBF672}"
the string between quotes was found at:
https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid"""
Someone can help on this?
Best regards,
Rui Fontes NVDA portuguese team
Às 17:59 de 11/06/2022, Javi Domínguez escreveu:
Hello.
You have a pull request that fixes both issues.
https://github.com/ruifontes/tesseractOCR/pull/2
Greetings
Javi Dominguez
El 05/06/2022 a las 23:01, Javi Domínguez via groups.io escribió:
Hello again.
I have run wia-cmd-scanner.exe directly from the command line, in the Windows CMD, and it has worked perfectly.
However from the addon it doesn't work. stderr shows:
b'The system cannot find the specified path.\r\n'
I hope this helps. It's late and I can't do any more research. Tomorrow dawns very early.
Good nitht
Javi
El 05/06/2022 a las 22:24, Javi Domínguez via groups.io escribió:
Hello.
* It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad! OK. I'll take a look at that.
* The scanner is recognized as WIA compatible? what do you mean with "is recognized as WIA compatible"? Yes, the scanner is WIA compliant, other apps recognize it but the addon I don't know, it just doesn't do anything.
* What Windows version? Windows 10 21H2 (x64) build 19044.1706
* So, I should name each thread differently... Yes, it would be convenient.
* And, before starting another thread, verify if it is active, right? I think so. I would wait for the current thread to finish before starting another.
Note that if you assign the new thread to self._thread, the old thread will continue to run until it finishes but you will no longer have a reference to it. You will only be able to access it via threading.enumerate().
You may need a method to kill threads that are stuck or taking too long.
Greetings
Javi
El 05/06/2022 a las 20:34, Rui Fontes escribió:
Hola Javi!
Comments in midle of your message marked with *...
Às 18:47 de 05/06/2022, Javi Domínguez escreveu:
When I try to recognize a file on the desktop two things happen:
1. If this is the first time a file is recognized, it says "file not supported" (tested with PDF and BMP file types). The same file recognized from a folder in Windows explorer works fine. * It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad!
2. If another file has been recognized before, it process any file even if it is not of a supported type. In any case, supported type or not, it always shows the result of the previous recognition, not the requested file. Even after manually deleting the oc.txt and ocr-xxx.png files from the addon's images folder, it re-processes the previously requested file. * It was an error on code... The path of last document was not cleared, so list of ocr-xxx.png file was created again...
On the other hand, recognition from scanner does not work for me. My scanner is HP Scanjet G2410, It may not be supported but the addon does not speak any message about it. The thread that processes this remains active and never terminates. If the script is executed again, another thread is launched that also remains active and so on forever. It is normal for the user, if he does not receive a response, to try to run it again, so you can end up with a lot of active threads.
* The scanner is recognized as WIA compatible?
* What Windows version?
I have the habit of naming the treads that I use to be able to debug better with threading.enumerate(). I have added the line to __init__.py self._thread.name = "tesseractOCR" before starting the thread to do these tests.
* So, I should name each thread differently...
* And, before starting another thread, verify if it is active, right?
finally, in terms of user experience, I think you need to give more information about what is happening. Sometimes, if the recognition takes time, the user does not know if it is working correctly or not.
* It is schedulled for next version...
Thanks!
Rui Fontes
|
|
Hello.
Yes, it is better organised now.
I'd suggest to use shutil to do deleting operation instead of calling del and such things.
toggle quoted messageShow quoted text
On 7/7/22, Rui Fontes <rui.fontes@...> wrote: Edited message, since I have changed the keystroke for digitalize from scanner...
Hello!
I think I managed to do everything...
Created various modules: configPanel.py with the construction of the settings panel to include in NVDA settings; languages.py where are listed all languages and created the variables related with choosing languages; vars.py where are declared almost all variables.
The keystroke for digitalize from scanner was changed to:
Windows+Control+w
I would like someone to review the add-on to include it in the repository...
Download link: https://www.dropbox.com/s/j9jesl986m2hdlv/tesseractOCR_2022.07.nvda-addon?dl=1
Best regards,
Rui Fontes NVDA portuguese team
Às 15:42 de 05/07/2022, Beqa Gozalishvili escreveu:
Hello.
as for point 1: i ment to wrote a function which would accept command and arguments, and don't repeat all things with other things, like attaching startupinfo everytime and so on. 2. Yes, move all interface related code in a separate module to simplify code. 3. Also for languages, move language definitions into a separate module.
On 7/5/22, Rui Fontes <rui.fontes@...> wrote:
Thanks Beqa!
You wrote:
These methods are generated to pass direction argument to handler function, because i didn't think of another way and i didn't want to define two similar methods. Ok! I already make use of them...
But you have created two similar methods, onAdd and onRemove...
It is possible to use the same method with the parameters "target" and "source"?
You wrote:
... one more suggestion would be to remove repetition in languages. you have list and dictionary of languages. Lets reuse dictionary for all possible needs and use ClientData from ItemContainer to associate item with needed data. Done!
You wrote:
Also generalise function to run things in subprocess... I don't think it is possible more...
One function to generate .png files from .pdf, other to create the list of .png files, one to make OCR and one for scanning...
Maybe joining the two first, but I don't see any advantage...
You wrote:
... extract interface class in separate module... Create a settings.py only to create the TesseractOCR setting category?
You wrote:
... also do the same with languages This one I did not understood...
Create a languages.py to create all languages variables to be used?
New version at:
https://www.dropbox.com/s/mwtmupoetd0le8j/tesseractOCR_2022.07.nvda-addon?dl=1
Best regards,
Rui Fontes NVDA portuguese team
On 7/5/22, Rui Fontes <rui.fontes@...> wrote:
Hello Beqa!
Thanks for your suggestion!
See what I did with your suggestion:
https://www.dropbox.com/s/658ua5z2sumt1hd/tesseractOCR_2022.07.nvda-addon?dl=1
By the way, what was the purpose of:
self.onMoveUp = functools.partial(self.onMove, direction=-1) self.onMoveDown = functools.partial(self.onMove, direction=1)
Best regards,
Best regards,
Rui Fontes NVDA portuguese team
Às 09:30 de 01/07/2022, Beqa Gozalishvili escreveu:
Hello.
I wanted to refactor this addon, but unfortunately i don't have enough time yet, may be i will return to this in the near future, but as for suggestions, i wrote a minimal example how it should look.
I am sending a minimal code example here.
Maybe there is a better way of doing such thing, but this is what i could think off today morning.
import addonHandler import functools import globalPluginHandler import gui import ui import wx
class OCRSettingsPanel(gui.SettingsPanel): title = "TesseractOCR"
def makeSettings(self, settingsSizer): sHelper = gui.guiHelper.BoxSizerHelper(self, sizer = settingsSizer) self.onMoveUp = functools.partial(self.onMove, direction=-1) self.onMoveDown = functools.partial(self.onMove, direction=1) self.availableLangs = sHelper.addLabeledControl("Available languages", wx.ListBox, choices=[], style = wx.LB_SINGLE|wx.LB_SORT) self.addButton = sHelper.addItem(wx.Button(self, label ="&Add", name="Add")) self.addButton.Bind(wx.EVT_BUTTON, self.onAdd) self.enabledLangs = sHelper.addLabeledControl("Selected languages", wx.ListBox, choices=[], style = wx.LB_SINGLE) self.enabledLangs.Bind(wx.EVT_LISTBOX, self.onChange) self.enabledLangs.Bind(wx.EVT_KEY_DOWN, self.onKeyDown) self.removeButton = sHelper.addItem(wx.Button(self, label ="&Remove", name="Remove")) self.removeButton.Bind(wx.EVT_BUTTON, self.onRemove) self.moveUpButton = sHelper.addItem(wx.Button(self, label ="Move &up", name="Up")) self.moveUpButton.Bind(wx.EVT_BUTTON, self.onMoveUp) self.moveDownButton = sHelper.addItem(wx.Button(self, label ="Move &down", name="Down")) self.moveDownButton.Bind(wx.EVT_BUTTON, self.onMoveDown) self.updateControlls()
def onKeyDown(self, evt): if evt.KeyCode == wx.WXK_UP and evt.controlDown: self.onMoveUp(evt) elif evt.KeyCode == wx.WXK_DOWN and evt.controlDown: self.onMoveDown(evt) else: evt.Skip()
def onAdd(self, evt): self.swapItems(evt, self.availableLangs, self.enabledLangs)
def onRemove(self, evt): self.swapItems(evt, self.enabledLangs, self.availableLangs)
def swapItems(self, evt, source, target): index = source.GetSelection() if index == -1: return target.Append(source.GetString(index)) source.Delete(index) if len(source.Items) > 0: source.SetSelection(index if index < source.Count - 1 else index - 1) self.updateControlls(evt)
def onMove(self, evt, direction): curIndex = self.enabledLangs.GetSelection() if curIndex == -1: return if direction == -1 and curIndex == 0 or direction == 1 and curIndex == self.enabledLangs.Count - 1: return newIndex = curIndex + direction curItem = self.enabledLangs.GetString(curIndex) newItem = self.enabledLangs.GetString(newIndex) self.enabledLangs.SetString(curIndex, newItem) self.enabledLangs.SetString(newIndex, curItem) self.enabledLangs.SetSelection(newIndex) self.updateControlls(evt)
def onChange(self, evt): self.updateControlls()
def updateControlls(self, evt=None): # possibly adding temporary class fields to eliminate unnnecessary computations. index = self.enabledLangs.GetSelection() self.moveUpButton.Disable() if index == 0 or index == -1 else self.moveUpButton.Enable() self.moveDownButton.Disable() if index == self.enabledLangs.Count - 1 or index == -1 else self.moveDownButton.Enable() self.addButton.Disable() if len(self.availableLangs.Items) == 0 else self.addButton.Enable() self.removeButton.Disable() if len(self.enabledLangs.Items) == 0 else self.removeButton.Enable() if evt is not None and (isinstance(evt.EventObject, wx.Button) and evt.EventObject.Name in ["Up", "Down"] and (index == 0 or index == self.enabledLangs.Count -1) or evt.EventObject.Name == "Add" and len(self.availableLangs.Items) == 0 or evt.EventObject.Name == "Remove" and len(self.enabledLangs.Items) == 0): self.enabledLangs.SetFocus()
def onSave(self): # Config saving here self.onSaveCallback(self.enabledLangs.Items)
class GlobalPlugin(globalPluginHandler.GlobalPlugin):
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) OCRSettingsPanel.onSaveCallback = self.checkLanguages
gui.NVDASettingsDialog.categoryClasses.append(OCRSettingsPanel)
def terminate(self):
gui.NVDASettingsDialog.categoryClasses.remove(OCRSettingsPanel)
def checkLanguages(self, langs): ui.message("+".join(langs))
On 6/28/22, Rui Fontes <rui.fontes@...> wrote:
Hi Beqa!
Thanks by the suggestions!
Can you gave me an example of such callback?
My knowledge is still very poor!
Best regards,
Rui Fontes NVDA portuguese team
Às 13:49 de 28/06/2022, Beqa Gozalishvili escreveu:
hello.
this addon have one very serious problem.
downloading of imported language happens in the main thread which locks up NVDA. If user have bad internet connection, they can stay without speech for several minutes. this should be corrected as soon as possible.
suggestion, tesseract can handle more than two languages, and instead of selecting one more language as second language, i suggest a following ui: one list, which will include all possible tesseract languages, add buttton, second list which will include all added languages from the first list, remove button, and move up/down buttons. on saving list of languages would be written in config and some callback should be called, which would check if some of just saved languages are missing, and download them in the background thread.
On 6/19/22, Rui Fontes <rui.fontes@...> wrote:
Hola Javi!
Firstly, thanks by your PR!
But, I would like to better it a litle more...
The case is:
When I have set this new laptop and installed Dropbox, I have selected to backup the desktop folder, and so my desktop full path is:
c:\Users\userName\dropbox\ambiente de trabalho
"Ambiente de trabalho" is the portuguese expression for "Desktop"...
So, I have tried to use shlobj.getKnownFolderId to get the correct desktop path for all cases...
In spite of modifying the shlobj.ini and importing it in the add-on, I didn't manage to do it...
I have added in shlobj.py, on the
class FolderId(str, Enum):
the following lines:
#Desktop folder # The typical path is "C:\Users\Utilizador\appData\desktop APP_DATA_DESKTOP = "{B2C5E279-7ADD-439F-B28C-C41FE1BBF672}"
the string between quotes was found at:
https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid"""
Someone can help on this?
Best regards,
Rui Fontes NVDA portuguese team
Às 17:59 de 11/06/2022, Javi Domínguez escreveu:
Hello.
You have a pull request that fixes both issues.
https://github.com/ruifontes/tesseractOCR/pull/2
Greetings
Javi Dominguez
El 05/06/2022 a las 23:01, Javi Domínguez via groups.io escribió:
Hello again.
I have run wia-cmd-scanner.exe directly from the command line, in the Windows CMD, and it has worked perfectly.
However from the addon it doesn't work. stderr shows:
b'The system cannot find the specified path.\r\n'
I hope this helps. It's late and I can't do any more research. Tomorrow dawns very early.
Good nitht
Javi
El 05/06/2022 a las 22:24, Javi Domínguez via groups.io escribió:
Hello.
* It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad! OK. I'll take a look at that.
* The scanner is recognized as WIA compatible? what do you mean with "is recognized as WIA compatible"? Yes, the scanner is WIA compliant, other apps recognize it but the addon I don't know, it just doesn't do anything.
* What Windows version? Windows 10 21H2 (x64) build 19044.1706
* So, I should name each thread differently... Yes, it would be convenient.
* And, before starting another thread, verify if it is active, right? I think so. I would wait for the current thread to finish before starting another.
Note that if you assign the new thread to self._thread, the old thread will continue to run until it finishes but you will no longer have a reference to it. You will only be able to access it via threading.enumerate().
You may need a method to kill threads that are stuck or taking too long.
Greetings
Javi
El 05/06/2022 a las 20:34, Rui Fontes escribió:
Hola Javi!
Comments in midle of your message marked with *...
Às 18:47 de 05/06/2022, Javi Domínguez escreveu:
When I try to recognize a file on the desktop two things happen:
1. If this is the first time a file is recognized, it says "file not supported" (tested with PDF and BMP file types). The same file recognized from a folder in Windows explorer works fine. * It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad!
2. If another file has been recognized before, it process any file even if it is not of a supported type. In any case, supported type or not, it always shows the result of the previous recognition, not the requested file. Even after manually deleting the oc.txt and ocr-xxx.png files from the addon's images folder, it re-processes the previously requested file. * It was an error on code... The path of last document was not cleared, so list of ocr-xxx.png file was created again...
On the other hand, recognition from scanner does not work for me. My scanner is HP Scanjet G2410, It may not be supported but the addon does not speak any message about it. The thread that processes this remains active and never terminates. If the script is executed again, another thread is launched that also remains active and so on forever. It is normal for the user, if he does not receive a response, to try to run it again, so you can end up with a lot of active threads.
* The scanner is recognized as WIA compatible?
* What Windows version?
I have the habit of naming the treads that I use to be able to debug better with threading.enumerate(). I have added the line to __init__.py self._thread.name = "tesseractOCR" before starting the thread to do these tests.
* So, I should name each thread differently...
* And, before starting another thread, verify if it is active, right?
finally, in terms of user experience, I think you need to give more information about what is happening. Sometimes, if the recognition takes time, the user does not know if it is working correctly or not.
* It is schedulled for next version...
Thanks!
Rui Fontes
|
|
In a quick search about shutils I didn't find a way to delete files... only directories...
Someone knows how to delete a file or group of files not deleting the directory?
Best regards,
Rui Fontes NVDA portuguese team
Às 20:52 de 07/07/2022, Beqa Gozalishvili escreveu:
toggle quoted messageShow quoted text
Hello.
Yes, it is better organised now.
I'd suggest to use shutil to do deleting operation instead of calling del and such things.
On 7/7/22, Rui Fontes <rui.fontes@...> wrote:
Edited message, since I have changed the keystroke for digitalize from scanner...
Hello!
I think I managed to do everything...
Created various modules: configPanel.py with the construction of the settings panel to include in NVDA settings; languages.py where are listed all languages and created the variables related with choosing languages; vars.py where are declared almost all variables.
The keystroke for digitalize from scanner was changed to:
Windows+Control+w
I would like someone to review the add-on to include it in the repository...
Download link: https://www.dropbox.com/s/j9jesl986m2hdlv/tesseractOCR_2022.07.nvda-addon?dl=1
Best regards,
Rui Fontes NVDA portuguese team
Às 15:42 de 05/07/2022, Beqa Gozalishvili escreveu:
Hello.
as for point 1: i ment to wrote a function which would accept command and arguments, and don't repeat all things with other things, like attaching startupinfo everytime and so on. 2. Yes, move all interface related code in a separate module to simplify code. 3. Also for languages, move language definitions into a separate module.
On 7/5/22, Rui Fontes <rui.fontes@...> wrote:
Thanks Beqa!
You wrote:
These methods are generated to pass direction argument to handler function, because i didn't think of another way and i didn't want to define two similar methods. Ok! I already make use of them...
But you have created two similar methods, onAdd and onRemove...
It is possible to use the same method with the parameters "target" and "source"?
You wrote:
... one more suggestion would be to remove repetition in languages. you have list and dictionary of languages. Lets reuse dictionary for all possible needs and use ClientData from ItemContainer to associate item with needed data. Done!
You wrote:
Also generalise function to run things in subprocess... I don't think it is possible more...
One function to generate .png files from .pdf, other to create the list of .png files, one to make OCR and one for scanning...
Maybe joining the two first, but I don't see any advantage...
You wrote:
... extract interface class in separate module... Create a settings.py only to create the TesseractOCR setting category?
You wrote:
... also do the same with languages This one I did not understood...
Create a languages.py to create all languages variables to be used?
New version at:
https://www.dropbox.com/s/mwtmupoetd0le8j/tesseractOCR_2022.07.nvda-addon?dl=1
Best regards,
Rui Fontes NVDA portuguese team
On 7/5/22, Rui Fontes <rui.fontes@...> wrote:
Hello Beqa!
Thanks for your suggestion!
See what I did with your suggestion:
https://www.dropbox.com/s/658ua5z2sumt1hd/tesseractOCR_2022.07.nvda-addon?dl=1
By the way, what was the purpose of:
self.onMoveUp = functools.partial(self.onMove, direction=-1) self.onMoveDown = functools.partial(self.onMove, direction=1)
Best regards,
Best regards,
Rui Fontes NVDA portuguese team
Às 09:30 de 01/07/2022, Beqa Gozalishvili escreveu:
Hello.
I wanted to refactor this addon, but unfortunately i don't have enough time yet, may be i will return to this in the near future, but as for suggestions, i wrote a minimal example how it should look.
I am sending a minimal code example here.
Maybe there is a better way of doing such thing, but this is what i could think off today morning.
import addonHandler import functools import globalPluginHandler import gui import ui import wx
class OCRSettingsPanel(gui.SettingsPanel): title = "TesseractOCR"
def makeSettings(self, settingsSizer): sHelper = gui.guiHelper.BoxSizerHelper(self, sizer = settingsSizer) self.onMoveUp = functools.partial(self.onMove, direction=-1) self.onMoveDown = functools.partial(self.onMove, direction=1) self.availableLangs = sHelper.addLabeledControl("Available languages", wx.ListBox, choices=[], style = wx.LB_SINGLE|wx.LB_SORT) self.addButton = sHelper.addItem(wx.Button(self, label ="&Add", name="Add")) self.addButton.Bind(wx.EVT_BUTTON, self.onAdd) self.enabledLangs = sHelper.addLabeledControl("Selected languages", wx.ListBox, choices=[], style = wx.LB_SINGLE) self.enabledLangs.Bind(wx.EVT_LISTBOX, self.onChange) self.enabledLangs.Bind(wx.EVT_KEY_DOWN, self.onKeyDown) self.removeButton = sHelper.addItem(wx.Button(self, label ="&Remove", name="Remove")) self.removeButton.Bind(wx.EVT_BUTTON, self.onRemove) self.moveUpButton = sHelper.addItem(wx.Button(self, label ="Move &up", name="Up")) self.moveUpButton.Bind(wx.EVT_BUTTON, self.onMoveUp) self.moveDownButton = sHelper.addItem(wx.Button(self, label ="Move &down", name="Down")) self.moveDownButton.Bind(wx.EVT_BUTTON, self.onMoveDown) self.updateControlls()
def onKeyDown(self, evt): if evt.KeyCode == wx.WXK_UP and evt.controlDown: self.onMoveUp(evt) elif evt.KeyCode == wx.WXK_DOWN and evt.controlDown: self.onMoveDown(evt) else: evt.Skip()
def onAdd(self, evt): self.swapItems(evt, self.availableLangs, self.enabledLangs)
def onRemove(self, evt): self.swapItems(evt, self.enabledLangs, self.availableLangs)
def swapItems(self, evt, source, target): index = source.GetSelection() if index == -1: return target.Append(source.GetString(index)) source.Delete(index) if len(source.Items) > 0: source.SetSelection(index if index < source.Count - 1 else index - 1) self.updateControlls(evt)
def onMove(self, evt, direction): curIndex = self.enabledLangs.GetSelection() if curIndex == -1: return if direction == -1 and curIndex == 0 or direction == 1 and curIndex == self.enabledLangs.Count - 1: return newIndex = curIndex + direction curItem = self.enabledLangs.GetString(curIndex) newItem = self.enabledLangs.GetString(newIndex) self.enabledLangs.SetString(curIndex, newItem) self.enabledLangs.SetString(newIndex, curItem) self.enabledLangs.SetSelection(newIndex) self.updateControlls(evt)
def onChange(self, evt): self.updateControlls()
def updateControlls(self, evt=None): # possibly adding temporary class fields to eliminate unnnecessary computations. index = self.enabledLangs.GetSelection() self.moveUpButton.Disable() if index == 0 or index == -1 else self.moveUpButton.Enable() self.moveDownButton.Disable() if index == self.enabledLangs.Count - 1 or index == -1 else self.moveDownButton.Enable() self.addButton.Disable() if len(self.availableLangs.Items) == 0 else self.addButton.Enable() self.removeButton.Disable() if len(self.enabledLangs.Items) == 0 else self.removeButton.Enable() if evt is not None and (isinstance(evt.EventObject, wx.Button) and evt.EventObject.Name in ["Up", "Down"] and (index == 0 or index == self.enabledLangs.Count -1) or evt.EventObject.Name == "Add" and len(self.availableLangs.Items) == 0 or evt.EventObject.Name == "Remove" and len(self.enabledLangs.Items) == 0): self.enabledLangs.SetFocus()
def onSave(self): # Config saving here self.onSaveCallback(self.enabledLangs.Items)
class GlobalPlugin(globalPluginHandler.GlobalPlugin):
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) OCRSettingsPanel.onSaveCallback = self.checkLanguages
gui.NVDASettingsDialog.categoryClasses.append(OCRSettingsPanel)
def terminate(self):
gui.NVDASettingsDialog.categoryClasses.remove(OCRSettingsPanel)
def checkLanguages(self, langs): ui.message("+".join(langs))
On 6/28/22, Rui Fontes <rui.fontes@...> wrote:
Hi Beqa!
Thanks by the suggestions!
Can you gave me an example of such callback?
My knowledge is still very poor!
Best regards,
Rui Fontes NVDA portuguese team
Às 13:49 de 28/06/2022, Beqa Gozalishvili escreveu:
hello.
this addon have one very serious problem.
downloading of imported language happens in the main thread which locks up NVDA. If user have bad internet connection, they can stay without speech for several minutes. this should be corrected as soon as possible.
suggestion, tesseract can handle more than two languages, and instead of selecting one more language as second language, i suggest a following ui: one list, which will include all possible tesseract languages, add buttton, second list which will include all added languages from the first list, remove button, and move up/down buttons. on saving list of languages would be written in config and some callback should be called, which would check if some of just saved languages are missing, and download them in the background thread.
On 6/19/22, Rui Fontes <rui.fontes@...> wrote:
Hola Javi!
Firstly, thanks by your PR!
But, I would like to better it a litle more...
The case is:
When I have set this new laptop and installed Dropbox, I have selected to backup the desktop folder, and so my desktop full path is:
c:\Users\userName\dropbox\ambiente de trabalho
"Ambiente de trabalho" is the portuguese expression for "Desktop"...
So, I have tried to use shlobj.getKnownFolderId to get the correct desktop path for all cases...
In spite of modifying the shlobj.ini and importing it in the add-on, I didn't manage to do it...
I have added in shlobj.py, on the
class FolderId(str, Enum):
the following lines:
#Desktop folder # The typical path is "C:\Users\Utilizador\appData\desktop APP_DATA_DESKTOP = "{B2C5E279-7ADD-439F-B28C-C41FE1BBF672}"
the string between quotes was found at:
https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid"""
Someone can help on this?
Best regards,
Rui Fontes NVDA portuguese team
Às 17:59 de 11/06/2022, Javi Domínguez escreveu:
Hello.
You have a pull request that fixes both issues.
https://github.com/ruifontes/tesseractOCR/pull/2
Greetings
Javi Dominguez
El 05/06/2022 a las 23:01, Javi Domínguez via groups.io escribió:
Hello again.
I have run wia-cmd-scanner.exe directly from the command line, in the Windows CMD, and it has worked perfectly.
However from the addon it doesn't work. stderr shows:
b'The system cannot find the specified path.\r\n'
I hope this helps. It's late and I can't do any more research. Tomorrow dawns very early.
Good nitht
Javi
El 05/06/2022 a las 22:24, Javi Domínguez via groups.io escribió:
Hello.
* It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad! OK. I'll take a look at that.
* The scanner is recognized as WIA compatible? what do you mean with "is recognized as WIA compatible"? Yes, the scanner is WIA compliant, other apps recognize it but the addon I don't know, it just doesn't do anything.
* What Windows version? Windows 10 21H2 (x64) build 19044.1706
* So, I should name each thread differently... Yes, it would be convenient.
* And, before starting another thread, verify if it is active, right? I think so. I would wait for the current thread to finish before starting another.
Note that if you assign the new thread to self._thread, the old thread will continue to run until it finishes but you will no longer have a reference to it. You will only be able to access it via threading.enumerate().
You may need a method to kill threads that are stuck or taking too long.
Greetings
Javi
El 05/06/2022 a las 20:34, Rui Fontes escribió:
Hola Javi!
Comments in midle of your message marked with *...
Às 18:47 de 05/06/2022, Javi Domínguez escreveu:
When I try to recognize a file on the desktop two things happen:
1. If this is the first time a file is recognized, it says "file not supported" (tested with PDF and BMP file types). The same file recognized from a folder in Windows explorer works fine. * It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad!
2. If another file has been recognized before, it process any file even if it is not of a supported type. In any case, supported type or not, it always shows the result of the previous recognition, not the requested file. Even after manually deleting the oc.txt and ocr-xxx.png files from the addon's images folder, it re-processes the previously requested file. * It was an error on code... The path of last document was not cleared, so list of ocr-xxx.png file was created again...
On the other hand, recognition from scanner does not work for me. My scanner is HP Scanjet G2410, It may not be supported but the addon does not speak any message about it. The thread that processes this remains active and never terminates. If the script is executed again, another thread is launched that also remains active and so on forever. It is normal for the user, if he does not receive a response, to try to run it again, so you can end up with a lot of active threads.
* The scanner is recognized as WIA compatible?
* What Windows version?
I have the habit of naming the treads that I use to be able to debug better with threading.enumerate(). I have added the line to __init__.py self._thread.name = "tesseractOCR" before starting the thread to do these tests.
* So, I should name each thread differently...
* And, before starting another thread, verify if it is active, right?
finally, in terms of user experience, I think you need to give more information about what is happening. Sometimes, if the recognition takes time, the user does not know if it is working correctly or not.
* It is schedulled for next version...
Thanks!
Rui Fontes
|
|
os.remove() removes a file.
os.rmdir() removes an empty directory.
shutil.rmtree() deletes a directory and all its contents.
toggle quoted messageShow quoted text
On 7/8/22, Rui Fontes <rui.fontes@...> wrote: In a quick search about shutils I didn't find a way to delete files... only directories...
Someone knows how to delete a file or group of files not deleting the directory?
Best regards,
Rui Fontes NVDA portuguese team
Às 20:52 de 07/07/2022, Beqa Gozalishvili escreveu:
Hello.
Yes, it is better organised now.
I'd suggest to use shutil to do deleting operation instead of calling del and such things.
On 7/7/22, Rui Fontes <rui.fontes@...> wrote:
Edited message, since I have changed the keystroke for digitalize from scanner...
Hello!
I think I managed to do everything...
Created various modules: configPanel.py with the construction of the settings panel to include in NVDA settings; languages.py where are listed all languages and created the variables related with choosing languages; vars.py where are declared almost all variables.
The keystroke for digitalize from scanner was changed to:
Windows+Control+w
I would like someone to review the add-on to include it in the repository...
Download link: https://www.dropbox.com/s/j9jesl986m2hdlv/tesseractOCR_2022.07.nvda-addon?dl=1
Best regards,
Rui Fontes NVDA portuguese team
Às 15:42 de 05/07/2022, Beqa Gozalishvili escreveu:
Hello.
as for point 1: i ment to wrote a function which would accept command and arguments, and don't repeat all things with other things, like attaching startupinfo everytime and so on. 2. Yes, move all interface related code in a separate module to simplify code. 3. Also for languages, move language definitions into a separate module.
On 7/5/22, Rui Fontes <rui.fontes@...> wrote:
Thanks Beqa!
You wrote:
These methods are generated to pass direction argument to handler function, because i didn't think of another way and i didn't want to define two similar methods. Ok! I already make use of them...
But you have created two similar methods, onAdd and onRemove...
It is possible to use the same method with the parameters "target" and "source"?
You wrote:
... one more suggestion would be to remove repetition in languages. you have list and dictionary of languages. Lets reuse dictionary for all possible needs and use ClientData from ItemContainer to associate item with needed data. Done!
You wrote:
Also generalise function to run things in subprocess... I don't think it is possible more...
One function to generate .png files from .pdf, other to create the list of .png files, one to make OCR and one for scanning...
Maybe joining the two first, but I don't see any advantage...
You wrote:
... extract interface class in separate module... Create a settings.py only to create the TesseractOCR setting category?
You wrote:
... also do the same with languages This one I did not understood...
Create a languages.py to create all languages variables to be used?
New version at:
https://www.dropbox.com/s/mwtmupoetd0le8j/tesseractOCR_2022.07.nvda-addon?dl=1
Best regards,
Rui Fontes NVDA portuguese team
On 7/5/22, Rui Fontes <rui.fontes@...> wrote:
Hello Beqa!
Thanks for your suggestion!
See what I did with your suggestion:
https://www.dropbox.com/s/658ua5z2sumt1hd/tesseractOCR_2022.07.nvda-addon?dl=1
By the way, what was the purpose of:
self.onMoveUp = functools.partial(self.onMove, direction=-1) self.onMoveDown = functools.partial(self.onMove, direction=1)
Best regards,
Best regards,
Rui Fontes NVDA portuguese team
Às 09:30 de 01/07/2022, Beqa Gozalishvili escreveu:
Hello.
I wanted to refactor this addon, but unfortunately i don't have enough time yet, may be i will return to this in the near future, but as for suggestions, i wrote a minimal example how it should look.
I am sending a minimal code example here.
Maybe there is a better way of doing such thing, but this is what i could think off today morning.
import addonHandler import functools import globalPluginHandler import gui import ui import wx
class OCRSettingsPanel(gui.SettingsPanel): title = "TesseractOCR"
def makeSettings(self, settingsSizer): sHelper = gui.guiHelper.BoxSizerHelper(self, sizer = settingsSizer) self.onMoveUp = functools.partial(self.onMove, direction=-1) self.onMoveDown = functools.partial(self.onMove, direction=1) self.availableLangs = sHelper.addLabeledControl("Available languages", wx.ListBox, choices=[], style = wx.LB_SINGLE|wx.LB_SORT) self.addButton = sHelper.addItem(wx.Button(self, label ="&Add", name="Add")) self.addButton.Bind(wx.EVT_BUTTON, self.onAdd) self.enabledLangs = sHelper.addLabeledControl("Selected languages", wx.ListBox, choices=[], style = wx.LB_SINGLE) self.enabledLangs.Bind(wx.EVT_LISTBOX, self.onChange) self.enabledLangs.Bind(wx.EVT_KEY_DOWN, self.onKeyDown) self.removeButton = sHelper.addItem(wx.Button(self, label ="&Remove", name="Remove")) self.removeButton.Bind(wx.EVT_BUTTON, self.onRemove) self.moveUpButton = sHelper.addItem(wx.Button(self, label ="Move &up", name="Up")) self.moveUpButton.Bind(wx.EVT_BUTTON, self.onMoveUp) self.moveDownButton = sHelper.addItem(wx.Button(self, label ="Move &down", name="Down")) self.moveDownButton.Bind(wx.EVT_BUTTON, self.onMoveDown) self.updateControlls()
def onKeyDown(self, evt): if evt.KeyCode == wx.WXK_UP and evt.controlDown: self.onMoveUp(evt) elif evt.KeyCode == wx.WXK_DOWN and evt.controlDown: self.onMoveDown(evt) else: evt.Skip()
def onAdd(self, evt): self.swapItems(evt, self.availableLangs, self.enabledLangs)
def onRemove(self, evt): self.swapItems(evt, self.enabledLangs, self.availableLangs)
def swapItems(self, evt, source, target): index = source.GetSelection() if index == -1: return target.Append(source.GetString(index)) source.Delete(index) if len(source.Items) > 0: source.SetSelection(index if index < source.Count - 1 else index - 1) self.updateControlls(evt)
def onMove(self, evt, direction): curIndex = self.enabledLangs.GetSelection() if curIndex == -1: return if direction == -1 and curIndex == 0 or direction == 1 and curIndex == self.enabledLangs.Count - 1: return newIndex = curIndex + direction curItem = self.enabledLangs.GetString(curIndex) newItem = self.enabledLangs.GetString(newIndex) self.enabledLangs.SetString(curIndex, newItem) self.enabledLangs.SetString(newIndex, curItem) self.enabledLangs.SetSelection(newIndex) self.updateControlls(evt)
def onChange(self, evt): self.updateControlls()
def updateControlls(self, evt=None): # possibly adding temporary class fields to eliminate unnnecessary computations. index = self.enabledLangs.GetSelection() self.moveUpButton.Disable() if index == 0 or index == -1 else self.moveUpButton.Enable() self.moveDownButton.Disable() if index == self.enabledLangs.Count - 1 or index == -1 else self.moveDownButton.Enable() self.addButton.Disable() if len(self.availableLangs.Items) == 0 else self.addButton.Enable() self.removeButton.Disable() if len(self.enabledLangs.Items) == 0 else self.removeButton.Enable() if evt is not None and (isinstance(evt.EventObject, wx.Button) and evt.EventObject.Name in ["Up", "Down"] and (index == 0 or index == self.enabledLangs.Count -1) or evt.EventObject.Name == "Add" and len(self.availableLangs.Items) == 0 or evt.EventObject.Name == "Remove" and len(self.enabledLangs.Items) == 0): self.enabledLangs.SetFocus()
def onSave(self): # Config saving here self.onSaveCallback(self.enabledLangs.Items)
class GlobalPlugin(globalPluginHandler.GlobalPlugin):
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) OCRSettingsPanel.onSaveCallback = self.checkLanguages
gui.NVDASettingsDialog.categoryClasses.append(OCRSettingsPanel)
def terminate(self):
gui.NVDASettingsDialog.categoryClasses.remove(OCRSettingsPanel)
def checkLanguages(self, langs): ui.message("+".join(langs))
On 6/28/22, Rui Fontes <rui.fontes@...> wrote:
Hi Beqa!
Thanks by the suggestions!
Can you gave me an example of such callback?
My knowledge is still very poor!
Best regards,
Rui Fontes NVDA portuguese team
Às 13:49 de 28/06/2022, Beqa Gozalishvili escreveu:
hello.
this addon have one very serious problem.
downloading of imported language happens in the main thread which locks up NVDA. If user have bad internet connection, they can stay without speech for several minutes. this should be corrected as soon as possible.
suggestion, tesseract can handle more than two languages, and instead of selecting one more language as second language, i suggest a following ui: one list, which will include all possible tesseract languages, add buttton, second list which will include all added languages from the first list, remove button, and move up/down buttons. on saving list of languages would be written in config and some callback should be called, which would check if some of just saved languages are missing, and download them in the background thread.
On 6/19/22, Rui Fontes <rui.fontes@...> wrote:
Hola Javi!
Firstly, thanks by your PR!
But, I would like to better it a litle more...
The case is:
When I have set this new laptop and installed Dropbox, I have selected to backup the desktop folder, and so my desktop full path is:
c:\Users\userName\dropbox\ambiente de trabalho
"Ambiente de trabalho" is the portuguese expression for "Desktop"...
So, I have tried to use shlobj.getKnownFolderId to get the correct desktop path for all cases...
In spite of modifying the shlobj.ini and importing it in the add-on, I didn't manage to do it...
I have added in shlobj.py, on the
class FolderId(str, Enum):
the following lines:
#Desktop folder # The typical path is "C:\Users\Utilizador\appData\desktop APP_DATA_DESKTOP = "{B2C5E279-7ADD-439F-B28C-C41FE1BBF672}"
the string between quotes was found at:
https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid"""
Someone can help on this?
Best regards,
Rui Fontes NVDA portuguese team
Às 17:59 de 11/06/2022, Javi Domínguez escreveu:
Hello.
You have a pull request that fixes both issues.
https://github.com/ruifontes/tesseractOCR/pull/2
Greetings
Javi Dominguez
El 05/06/2022 a las 23:01, Javi Domínguez via groups.io escribió:
Hello again.
I have run wia-cmd-scanner.exe directly from the command line, in the Windows CMD, and it has worked perfectly.
However from the addon it doesn't work. stderr shows:
b'The system cannot find the specified path.\r\n'
I hope this helps. It's late and I can't do any more research. Tomorrow dawns very early.
Good nitht
Javi
El 05/06/2022 a las 22:24, Javi Domínguez via groups.io escribió:
Hello.
* It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad! OK. I'll take a look at that.
* The scanner is recognized as WIA compatible? what do you mean with "is recognized as WIA compatible"? Yes, the scanner is WIA compliant, other apps recognize it but the addon I don't know, it just doesn't do anything.
* What Windows version? Windows 10 21H2 (x64) build 19044.1706
* So, I should name each thread differently... Yes, it would be convenient.
* And, before starting another thread, verify if it is active, right? I think so. I would wait for the current thread to finish before starting another.
Note that if you assign the new thread to self._thread, the old thread will continue to run until it finishes but you will no longer have a reference to it. You will only be able to access it via threading.enumerate().
You may need a method to kill threads that are stuck or taking too long.
Greetings
Javi
El 05/06/2022 a las 20:34, Rui Fontes escribió:
Hola Javi!
Comments in midle of your message marked with *...
Às 18:47 de 05/06/2022, Javi Domínguez escreveu:
When I try to recognize a file on the desktop two things happen:
1. If this is the first time a file is recognized, it says "file not supported" (tested with PDF and BMP file types). The same file recognized from a folder in Windows explorer works fine. * It is a limitation of the routine to get the complete path of the file...
If you can help bettering the routine, I will be glad!
2. If another file has been recognized before, it process any file even if it is not of a supported type. In any case, supported type or not, it always shows the result of the previous recognition, not the requested file. Even after manually deleting the oc.txt and ocr-xxx.png files from the addon's images folder, it re-processes the previously requested file. * It was an error on code... The path of last document was not cleared, so list of ocr-xxx.png file was created again...
On the other hand, recognition from scanner does not work for me. My scanner is HP Scanjet G2410, It may not be supported but the addon does not speak any message about it. The thread that processes this remains active and never terminates. If the script is executed again, another thread is launched that also remains active and so on forever. It is normal for the user, if he does not receive a response, to try to run it again, so you can end up with a lot of active threads.
* The scanner is recognized as WIA compatible?
* What Windows version?
I have the habit of naming the treads that I use to be able to debug better with threading.enumerate(). I have added the line to __init__.py self._thread.name = "tesseractOCR" before starting the thread to do these tests.
* So, I should name each thread differently...
* And, before starting another thread, verify if it is active, right?
finally, in terms of user experience, I think you need to give more information about what is happening. Sometimes, if the recognition takes time, the user does not know if it is working correctly or not.
* It is schedulled for next version...
Thanks!
Rui Fontes
|
|