OCR REST - Jython, Web Dev?

Below is a Python script, two queries;

  1. Is it possible for this to run in Jython? Tried putting it into Script Console and it errored on line 79 (with open(FilePath, ‘rb’) as image_file: )

  2. Would I need the Web Dev module to run this or can it run straight from e.g. Gateway event script without that module installed

import json
import shutil

"""
    Sample project for OCRWebService.com (REST API).
    Extract text from scanned images and PDF documents and convert into editable formats.
    Please create new account with ocrwebservice.com via http://www.ocrwebservice.com/account/signup and get license code
"""

# Provide your username and license code
LicenseCode = '<username>';
UserName =  'license code';

try:
	import requests
except ImportError:
	print("You need the requests library to be installed in order to use this sample.")
	print("Run 'pip install requests' to fix it.")

	exit()


"""

        You should specify OCR settings. See full description http://www.ocrwebservice.com/service/restguide
         
        Input parameters:
         
	[language]     - Specifies the recognition language. 
	   		This parameter can contain several language names separated with commas. 
                        For example "language=english,german,spanish".
			Optional parameter. By default:english
        
	[pagerange]    - Enter page numbers and/or page ranges separated by commas. 
			For example "pagerange=1,3,5-12" or "pagerange=allpages".
                        Optional parameter. By default:allpages
         
        [tobw]	      - Convert image to black and white (recommend for color image and photo). 
			For example "tobw=false"
                        Optional parameter. By default:false
         
        [zone]         - Specifies the region on the image for zonal OCR. 
			The coordinates in pixels relative to the left top corner in the following format: top:left:height:width. 
			This parameter can contain several zones separated with commas. 
		        For example "zone=0:0:100:100,50:50:50:50"
                        Optional parameter.
          
        [outputformat] - Specifies the output file format.
                        Can be specified up to two output formats, separated with commas.
			For example "outputformat=pdf,txt"
                        Optional parameter. By default:doc

        [gettext]	- Specifies that extracted text will be returned.
			For example "tobw=true"
                        Optional parameter. By default:false
        
        [description]  - Specifies your task description. Will be returned in response.
                        Optional parameter. 


	!!!!  For getting result you must specify "gettext" or "outputformat" !!!!  

"""

# Build your OCR:

# Extract text with English language by default
RequestUrl = "http://www.ocrwebservice.com/restservices/processDocument?gettext=true";

# Extract text with English and german language using zonal OCR
#RequestUrl = 'http://www.ocrwebservice.com/restservices/processDocument?language=english,german&zone=0:0:600:400,500:1000:150:400';

# Convert first 5 pages of multipage document into doc and txt
# RequestUrl = 'http://www.ocrwebservice.com/restservices/processDocument?language=english&pagerange=1-5&outputformat=doc,txt';

#Full path to uploaded document
FilePath = "C:\\test_image.jpg"

with open(FilePath, 'rb') as image_file:
    image_data = image_file.read()
    
r = requests.post(RequestUrl, data=image_data, auth=(UserName, LicenseCode))

if r.status_code == 401:
    #Please provide valid username and license code
    print("Unauthorized request")
    exit()

# Decode Output response
jobj = json.loads(r.content)

ocrError = str(jobj["ErrorMessage"])

if ocrError != '':
        #Error occurs during recognition
        print ("Recognition Error: " + ocrError)
        exit()


# Task description
print("Task Description:" + str(jobj["TaskDescription"]))

# Available pages 
print("Available Pages:" + str(jobj["AvailablePages"]))

# Processed pages 
print("Processed Pages:" + str(jobj["ProcessedPages"]))

# For zonal or multipage OCR: OCRText[z][p]    z - zone, p - pages

# Extracted text from first or single page
print("Extracted Text:" + str(jobj["OCRText"][0][0]))

# Extracted text from second page (if multipage doc converted)
#print("Extracted Text:" + str(jobj["OCRText"][0][1]))

# Get extracted text from First zone for each page
print("Zone 1 Page 1 Text:" + str(jobj["OCRText"][0][0]))
print("Zone 1 Page 2 Text:" + str(jobj["OCRText"][0][1]))

# Get extracted text from Second zone for each page
#print("Zone 2 Page 1 Text:" + str(jobj["OCRText"][1][0]))
#print("Zone 2 Page 2 Text:" + str(jobj["OCRText"][1][1]))

#Download output file (if outputformat was specified)
#file_response = requests.get(jobj["OutputFileUrl"], stream=True)
#with open("outputDoc.doc", 'wb') as output_file:
#   shutil.copyfileobj(file_response.raw, output_file)




3). Tinkering more, fails also on import Json on 7.9, possible to add in 7.9 or will definitely work in 8.0?

the with keyword isn’t supported in the jython version used in Ignition 7.9. Instead you need to do:

image_file = open(FilePath, ‘rb’)
image_data = image_file.read()
image_file.close()

The json import and method call can be removed and replaced with a:
system.util.jsonDecode(r.content)

The requests import and method call can be removed and replaced with:
r = system.net.httpPost(url=RequestUrl,postData=image_data,username=UserName, password=LicenseCode)

Note I am not 100% positive on the last part as i did not test it as i do not have a login to that website.

You shouldn’t need webdev to do this unless the webdev module provides the system.net.http* methods.

Thanks! It’s failing on this bit,

 File "<buffer>", line 78, in <module>
AttributeError: 'unicode' object has no attribute 'status_code'

If I comment that out I get;

Traceback (most recent call last):
  File "<buffer>", line 84, in <module>
AttributeError: 'unicode' object has no attribute 'content'

however it would be nice to get that bit working with a different status code;

#if r.status_code == 200:
    #Please provide valid username and license code
   # print("OCR Success!")
   # exit()

I can PM a trial code across I signed up to test

Thanks again

Mostly true, although technically you can from __future__ import with_statement at the top of the file and it will work. Not necessary in 8.0, though, as you point out.

1 Like

The http* functions available in 7.9 don’t offer any access to the response metadata, such as status code. These (and many other limitations) are why system.net.httpClient() exists in 8.0. Importing requests is apparently possible (I’ve seen other people on the forum using it) - I’m not sure if any older version is required to work with Python 2.5/2.7, but it’s worth scanning through the forum just to get a mostly-sane API for interacting with webservices.

woah! i did not know that. Thank you for the info!

Thanks, installed and imported requests based on another forum post for httpGet

Tried a Get just to see and got:

IOError: Server returned HTTP response code: 405 for URL: http://www.ocrwebservice.com/restservices/processDocument?language=english&pagerange=1-5&gettext=true&outputformat=doc
>>> 

Error 405 isn’t in the list of Post functions, can I use requests with Post not Get?

ok so a bit further,

now at the output stage, not sure if I have requests imported right…

Inside requests is ini.py and core.py, so I added from request import core at the top

Inside packages is a single ini.py

Inside poster is ini.py encode.py and streaminghttp.py

>>> 
'\n    Sample project for OCRWebService.com (REST API).\n    Extract text from scanned images and PDF documents and convert into editable formats.\n    Please create new account with ocrwebservice.com via http://www.ocrwebservice.com/account/signup and get license code\n'
'\n\n        You should specify OCR settings. See full description http://www.ocrwebservice.com/service/restguide\n         \n        Input parameters:\n         \n\t[language]     - Specifies the recognition language. \n\t   \t\tThis parameter can contain several language names separated with commas. \n                        For example "language=english,german,spanish".\n\t\t\tOptional parameter. By default:english\n        \n\t[pagerange]    - Enter page numbers and/or page ranges separated by commas. \n\t\t\tFor example "pagerange=1,3,5-12" or "pagerange=allpages".\n                        Optional parameter. By default:allpages\n         \n        [tobw]\t      - Convert image to black and white (recommend for color image and photo). \n\t\t\tFor example "tobw=false"\n                        Optional parameter. By default:false\n         \n        [zone]         - Specifies the region on the image for zonal OCR. \n\t\t\tThe coordinates in pixels relative to the left top corner in the following format: top:left:height:width. \n\t\t\tThis parameter can contain several zones separated with commas. \n\t\t        For example "zone=0:0:100:100,50:50:50:50"\n                        Optional parameter.\n          \n        [outputformat] - Specifies the output file format.\n                        Can be specified up to two output formats, separated with commas.\n\t\t\tFor example "outputformat=pdf,txt"\n                        Optional parameter. By default:doc\n\n        [gettext]\t- Specifies that extracted text will be returned.\n\t\t\tFor example "tobw=true"\n                        Optional parameter. By default:false\n        \n        [description]  - Specifies your task description. Will be returned in response.\n                        Optional parameter. \n\n\n\t!!!!  For getting result you must specify "gettext" or "outputformat" !!!!  \n\n'
Task Description:None
Available Pages:1
Processed Pages:1
Extracted Text:No recognized text !
Zone 1 Page 1 Text:No recognized text !
Traceback (most recent call last):
  File "<buffer>", line 126, in <module>
NameError: name 'requests' is not defined
>>> ![requests|140x314](upload://w0gxZXiCRqY40P0GyWxeUCHIseL.png) 
__init__.py

it changed this in my above post to ini.py

requests

image

got Import requests working… still a few hoops to go through

OK, so I don’t think the Json decode is going right,

{"ErrorMessage":"","OutputInformation":null,"AvailablePages":965,"ProcessedPages":1,"OCRText":[["No recognized text !"]],"OutputFileUrl":"http://147.135.97.125/uploads/_output/8f22_0224e9a7-edcc-473b-831e-6e920cf8cc42.xlsx","OutputFileUrl2":"","OutputFileUrl3":"","Reserved":[],"OCRWords":[],"TaskDescription":null}
<type 'dict'>
Task Description:None
Available Pages:965
Processed Pages:1
url:http://147.135.97.125/uploads/_output/8f22_0224e9a7-edcc-473b-831e-6e920cf8cc42.xlsx
Extracted Text:No recognized text !
Zone 1 Page 1 Text:No recognized text !
Traceback (most recent call last):
  File "<buffer>", line 123, in <module>
AttributeError: 'Response' object has no attribute 'raw'

The original code was r.content,

I changed it to just r

# Decode Output response
jobj = system.util.jsonDecode(r)
print type(jobj)

Which as you can see above the type is a Dict.

If I leave it at r.content I get:

Traceback (most recent call last):
  File "<buffer>", line 86, in <module>
AttributeError: 'unicode' object has no attribute 'content'

Gonna give it a go in 8.0 later to see how it goes there

Line 6 (in attached image) is import requests, my patience ran out trying to add all the sub-dependencies that it requires.

Monday bump :slight_smile:

Can’t offer much advice on requests - if you can get it installed, it’s a sane API, but I don’t know what hoops you have to jump through to get it property installed. You could try this method: Procedure for installing python libraries from source
Beyond that, I’d definitely recommend upgrading to 8 to get access to the new http client. It’s not something that can be backported, since it’s backed by Java 11’s HTTP client.

1 Like

Thanks Paul, the last image is version 8(.0.14), it can import Json so should help a bit there… perhaps I just grabbed the wrong version of Requests to work with V8… I grabbed V2.24.0, as at a glance it was the closest match.

Most of my prior searches on the forum for Requests I was intentionally choosing V7.9 threads, I will continue the search…

If you’re on 8, then I’d skip trying to import requests and use system.net.httpClient() - it’s not quite the same API, but will definitely get the job done. I rewrote your original post to use httpClient:

import shutil

"""
    Sample project for OCRWebService.com (REST API).
    Extract text from scanned images and PDF documents and convert into editable formats.
    Please create new account with ocrwebservice.com via http://www.ocrwebservice.com/account/signup and get license code
"""

# Provide your username and license code
LicenseCode = '<username>';
UserName =  'license code';

"""

        You should specify OCR settings. See full description http://www.ocrwebservice.com/service/restguide
         
        Input parameters:
         
	[language]     - Specifies the recognition language. 
	   		This parameter can contain several language names separated with commas. 
                        For example "language=english,german,spanish".
			Optional parameter. By default:english
        
	[pagerange]    - Enter page numbers and/or page ranges separated by commas. 
			For example "pagerange=1,3,5-12" or "pagerange=allpages".
                        Optional parameter. By default:allpages
         
        [tobw]	      - Convert image to black and white (recommend for color image and photo). 
			For example "tobw=false"
                        Optional parameter. By default:false
         
        [zone]         - Specifies the region on the image for zonal OCR. 
			The coordinates in pixels relative to the left top corner in the following format: top:left:height:width. 
			This parameter can contain several zones separated with commas. 
		        For example "zone=0:0:100:100,50:50:50:50"
                        Optional parameter.
          
        [outputformat] - Specifies the output file format.
                        Can be specified up to two output formats, separated with commas.
			For example "outputformat=pdf,txt"
                        Optional parameter. By default:doc

        [gettext]	- Specifies that extracted text will be returned.
			For example "tobw=true"
                        Optional parameter. By default:false
        
        [description]  - Specifies your task description. Will be returned in response.
                        Optional parameter. 


	!!!!  For getting result you must specify "gettext" or "outputformat" !!!!  

"""

# Build your OCR:

# Extract text with English language by default
RequestUrl = "http://www.ocrwebservice.com/restservices/processDocument?gettext=true";
client = system.net.httpClient(username=UserName, password=LicenseCode)

# Extract text with English and german language using zonal OCR
#RequestUrl = 'http://www.ocrwebservice.com/restservices/processDocument?language=english,german&zone=0:0:600:400,500:1000:150:400';

# Convert first 5 pages of multipage document into doc and txt
# RequestUrl = 'http://www.ocrwebservice.com/restservices/processDocument?language=english&pagerange=1-5&outputformat=doc,txt';

#Full path to uploaded document
FilePath = "C:\\test_image.jpg"
    
r = client.post(RequestUrl, file=FilePath)

if r.statusCode == 401:
    #Please provide valid username and license code
    print("Unauthorized request")
    exit()

# Decode Output response
jobj = r.json

ocrError = str(jobj["ErrorMessage"])

if ocrError != '':
        #Error occurs during recognition
        print ("Recognition Error: " + ocrError)
        exit()


# Task description
print("Task Description:" + str(jobj["TaskDescription"]))

# Available pages 
print("Available Pages:" + str(jobj["AvailablePages"]))

# Processed pages 
print("Processed Pages:" + str(jobj["ProcessedPages"]))

# For zonal or multipage OCR: OCRText[z][p]    z - zone, p - pages

# Extracted text from first or single page
print("Extracted Text:" + str(jobj["OCRText"][0][0]))

# Extracted text from second page (if multipage doc converted)
#print("Extracted Text:" + str(jobj["OCRText"][0][1]))

# Get extracted text from First zone for each page
print("Zone 1 Page 1 Text:" + str(jobj["OCRText"][0][0]))
print("Zone 1 Page 2 Text:" + str(jobj["OCRText"][0][1]))

# Get extracted text from Second zone for each page
#print("Zone 2 Page 1 Text:" + str(jobj["OCRText"][1][0]))
#print("Zone 2 Page 2 Text:" + str(jobj["OCRText"][1][1]))

#Download output file (if outputformat was specified)
#file_response = requests.get(jobj["OutputFileUrl"], stream=True)
#with open("outputDoc.doc", 'wb') as output_file:
#   shutil.copyfileobj(file_response.raw, output_file)

I agree with Paul that the httpClient() is the way to go if you can use it.

For posterity, anyone who wants or needs to use requests from Ignition 8, it does seem to work well.

Steps:

  1. Install Jython 2.7 with the installer
  2. Run ‘jython -m ensurepip’ and then ‘jython -m pip install requests’
  3. Copy the site-packages contents from your Jython install directory into Ignition’s user-lib/pylib/site-packages

A handful of python packages are accessible like that. Much easier than trying to work out all the dependency management yourself.

Note: most Python packages don’t work in Ignition, since most require CPython for dependencies like numpy. requests is one of the ones that does seem to work well. When it comes to encryption, though, ymmv.

2 Likes

Thanks Paul and Kevin.

It’s past midnight here so I’ll get testing this after my morning coffee.

Paul,

I skimmed the code you provided and have one query;

Line 68 Filepath; the comment line above it refers to uploaded document.

The process is: file on gateway (PDF) is sent to REST API to be OCR’d and returned to the gateway as e.g. XLSX.

The original code had reference to a local file, the return of the information from OCR (JSON format) and also at the very bottom (commented out in the example) output as the converted format.

Kevin,

for my own intrigue (and others following along), can you please link to the source of the Requests download that you tested?