problem with network.request() using POST

Trying to follow along with the few examples in the Corona docs, but not fairing well.  I’m trying to send a network.request with an image, language and apikey attributes with the following code and it’s erroring out no matter what I try.  Any help is much appreciated.  Thanks.

local path = system.pathForFile("ocr1.jpg", system.ResourceDirectory) local img, errStr = io.open( path, "r" ) local headers = {} headers["Content-Type"] = "multipart/form-data" local body = "image=" .. img .. "&language=" .. language .. "&apikey=" .. ocrapiserviceApiKey local params = {} params.headers = headers params.body = body network.request("http://api.ocrapiservice.com/1.0/rest/ocr", "POST", networkListener, params)

I’ve never tried uploading a file with Corona SDK, and I’m not familiar with what you’ve looked at as a reference.

I see several things to be concerned with.  First when you do img = io.open(…) you are just getting a handle to the file to read it.  You are passing that handle as a parameter to your body image=.  The handle is a pointer and not the actual data.  I would think that you would need to actually read the image in, then base64 encode it.  There should also be a place where you tell the host what type of data is coming like image/jpeg.

We now have a network.upload() API call http://docs.coronalabs.com/api/library/network/upload.html

That might work better for you.

Sorry, I’m very new to Lua and even more new to network programming.  I’m basically trying to replicate the same functionality inside this app as an html form would have when posting to this url.  I also tried to experiment with the network.upload() function with similar failed results:

local function networkListener( event )

        if ( event.isError ) then

                print( “Network error!”)

        else

                print ( "RESPONSE: " … event.response )

        end

end

local params.body = { [“image”] = " ocr1.jpg", [“language”] = “en”, [“apikey”] = “myapikey” }

network.upload(“http://api.ocrapiservice.com/1.0/rest/ocr”,  “POST”,  networkListener,  params, “ocr1.jpg”,  system.ResourceDirectory, “multipart/form-data”)

I think the problem is how to format the params variable and the docs for the upload function aren’t very clear and the “object.json” notation in the docs makes it even more confusing.  I tried to declare local params.body = { [“image”] = " ocr1.jpg", [“language”] = “en”, [“apikey”] = “myapikey” } before calling network.upload but it still did not work.  Any suggestions or examples would be very helpful.  I’m really not sure what I’m doing wrong and the usual methods of troubleshooting are not working.  Thanks.

[lua]

local params.body = { [“image”] = " ocr1.jpg", [“language”] = “en”, [“apikey”] = “myapikey” }

network.upload(“http://api.ocrapiservice.com/1.0/rest/ocr”,  “POST”,  networkListener,  params, “ocr1.jpg”,  system.ResourceDirectory, “multipart/form-data”)

[/lua]

I would try this first:

[lua]

local params.body = { image = " ocr1.jpg", language = “en”, apikey = “myapikey” }

network.upload(“http://api.ocrapiservice.com/1.0/rest/ocr”,  “POST”,  networkListener,  params, “ocr1.jpg”,  system.ResourceDirectory, “image/jpeg”)

[/lua]

Now is the image really in your app bundle or is it saved in some other place like system.DocumentsDirectory?  You can’t write to system.ResourcesDirectory, so that would be a file you would have to ship with your app.  I’m not sure why you would want to upload a fixed file like that.  I would expect that you’ve used the camera to scan an image and that file would not be in system.ResourcesDirectory.
 

I tried your code but it gives a syntax error, so I tried the following:

local params = {}

params.body = { image = “ocr1.jpg”, language = “en”, apikey = “myapikey” }

network.upload(“http://api.ocrapiservice.com/1.0/rest/ocr”,  “POST”,  networkListener,  params, “ocr1.jpg”,  system.ResourceDirectory, “image/jpeg”)

This still results in the same “HTTP 400 the language parameter is missing” error that I was getting before.

I have the ocr1.jpg image in the same directory as my main.lua file for simplicity.  Eventually, the image will be generated by the user from the camera, but I figured it’s best not to overcomplicate things just yet and build one piece at a time.  Since the entire app hinges on this network connection working I’m trying to tackle it first.

Due to my lack of experience with Corona and its network functionality, I’m not sure if it’s a bug in Corona or the ocr api I’m trying to use.  The parameters I’m inputting work just fine on a web form on the ocr company’s site.

[lua]

local body = “language=en&apikey=yourapikeynoquotes”

local params.body = body

network.upload(“http://api.ocrapiservice.com/1.0/rest/ocr”,  “POST”,  networkListener,  params, “ocr1.jpg”,  system.ResourceDirectory, “image/jpeg”)

[/lua]

try that.

getting a syntax error now:

Syntax error

/Users/John/Library/Application Support/Outlaw/Sandbox/3/main.lua:37: unexpected symbol near ‘.’

 

-- create network request local body = "language=en&apikey=myapikey" local params.body = body network.upload("http://api.ocrapiservice.com/1.0/rest/ocr", "POST", networkListener, params, "ocr1.jpg", system.ResourceDirectory, "image/jpeg")

Actually, the reason the file upload fails is because your resource file inside of the APK, which is really a zip file.  Our network API on Android currently does not support uploading files inside of the APK (ie: your ResourceDirectory).

That said, there is a way to “trick” Corona into extracting your image file.  You have to do the following:

  1. Change the extension of your image from *.jpg to *.jpg_ (notice the underscore).

  2. Call system.pathForFile() on that image file.  Corona will automatically extract the image file to a hidden temporary directory.   Ignore the returned path.  You don’t need it.

  3. Finally, call network.upload() to upload your image file using the ResourceDirectory as the base. Do *not* use the returned path from the above function.

Wow.  That I would have never known.  Is there a different place I can put the file for the time being for testing purposes that’s a little more simple?

Also change line 36 to:

local params = {}

params.body = “language=en&apikey=myapikey”

Still giving me errors… Here’s what I have

– create network request
local params = {}
params.body = “language=en&apikey=myapikey”

– for testing
system.pathForFile(“ocr1.jpg_”)
– end for testing

network.upload(“http://api.ocrapiservice.com/1.0/rest/ocr”, “POST”, networkListener, params, “ocr1.jpg_”, system.ResourceDirectory, “image/jpeg”)

and I’m getting the error:
WARNING: Cannot create path for resource file ‘ocr1.jpg_’. File does not exist.

Runtime error

…repo5/main/plugins/network/mac/…/shared/network.lua:113: attempt to index field ‘body’ (a string value)

stack traceback:

…repo5/main/plugins/network/mac/…/shared/network.lua:113: in function ‘upload’

…ibrary/Application Support/Outlaw/Sandbox/3/main.lua:42: in function ‘_onEvent’

?: in function <?:931>

?: in function <?:218>

Oh your service is making this a challenge…  Our upload function doesn’t want to pass additional parameters to the host via the body structure and you have to use the body parameter to send in the API key and the language.  I think you were more on the right track (since we can’t pass additional post parameters using the network.upload() call)

So lets go back to your original code (and if you’re on Android and need to test from the Resource directory, you will need to follow Josh’s steps above too.

You need to read the data in from the file, not just open it.  Then you will need to base64 encode the data.

[lua]

local function _b64enc( data )
    – character table string
    local b=‘ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/’

    return ( (data:gsub( ‘.’, function( x )
        local r,b=’’, x:byte()
        for i=8,1,-1 do r=r … ( b % 2 ^ i - b % 2 ^ ( i - 1 ) > 0 and ‘1’ or ‘0’ ) end
        return r;
    end ) …‘0000’ ):gsub( ‘%d%d%d?%d?%d?%d?’, function( x )
        if ( #x < 6 ) then return ‘’ end
        local c = 0
        for i = 1, 6 do c = c + ( x:sub( i, i ) == ‘1’ and 2 ^ ( 6 - i ) or 0 ) end
        return b:sub( c+1, c+1 )
    end) … ( { ‘’, ‘==’, ‘=’ } )[#data %3 + 1] )
end

     local path = system.pathForFile(“ocr1.jpg”, system.ResourceDirectory)

     local file, errStr = io.open( path, “rb” )

     if file then

            local content = file:read( “*a” )

            local img = _b64enc(content)

    

            local headers = {}

            headers[“Content-Type”] = “multipart/form-data”

            local body = “image=” … img … “&language=” … language … “&apikey=” … ocrapiserviceApiKey

            

            local params = {}

            params.headers = headers

            params.body = body

            network.request(“http://api.ocrapiservice.com/1.0/rest/ocr”, “POST”, networkListener, params)

     end

[/lua]

Same error again!  Error 400.  This is the most frustrating thing I’ve ever dealt with.  I don’t know if it’s Corona or the ocr api that is a mess.  If I had to guess, it’s probably the ocr api.

Ok!  So I decided to scrap that ocrapiservice and move straight to an aws ec2 tesseract ocr solution.  I’ve tested it in my web browser by passing this:

myaddress.amazonaws.com/?img=http://www.alink.com/to/sometext.jpg

It gives me back an expected result using this php code server side:

\<?php $img = $\_REQUEST['img']; $callback = $\_REQUEST['callback']; $format = $\_REQUEST['format']; $tmpFile = uniqid(); file\_put\_contents("tmp/$tmpFile",file\_get\_contents($img)); $cmd = "/usr/local/bin/tesseract tmp/$tmpFile tmp/$tmpFile"; exec($cmd); @unlink("tmp/$tmpFile"); $res = file\_get\_contents("tmp/$tmpFile.txt"); @unlink("tmp/$tmpFile.txt"); switch($format) { case 'json': default: header('Content-type: application/json'); $json = json\_encode( array("success" =\> true, "img" =\> $img, "value" =\> $res) ); if ($callback != '') { print $callback . "(" . $json . ")"; } else { print $json; } break; case 'raw': case 'txt': print $res; break; } ?\>

Now, I’m still unclear if network.request or network.upload is the appropriate function to interact with this server side script, a little advice please?  Thanks!

The URL string you are passing is assuming the file to be processed is located on a website somewhere and you are accessing via a URL.   PHP’s file_get_contents() knows how to fetch a file from a web server and give you it’s contents.

To make this work, you are still going to have to upload the image from your device to a webserver somewhere then point your script at the webserver to run.

This looks like you have the ability to do your own PHP is that correct?

Yes, I have full control over the server side and can run any application on it.  I just have to figure out how to upload the image to the server and send a result as some sort of data back to the corona app.  All the heavy lifting will happen server side.

Basically I need to:

take a photo from the corona app (using a sample image for now)

upload that image to the server

process the ocr

return the result as data to the corona app

Thanks!

I’ve never tried uploading a file with Corona SDK, and I’m not familiar with what you’ve looked at as a reference.

I see several things to be concerned with.  First when you do img = io.open(…) you are just getting a handle to the file to read it.  You are passing that handle as a parameter to your body image=.  The handle is a pointer and not the actual data.  I would think that you would need to actually read the image in, then base64 encode it.  There should also be a place where you tell the host what type of data is coming like image/jpeg.

We now have a network.upload() API call http://docs.coronalabs.com/api/library/network/upload.html

That might work better for you.

Sorry, I’m very new to Lua and even more new to network programming.  I’m basically trying to replicate the same functionality inside this app as an html form would have when posting to this url.  I also tried to experiment with the network.upload() function with similar failed results:

local function networkListener( event )

        if ( event.isError ) then

                print( “Network error!”)

        else

                print ( "RESPONSE: " … event.response )

        end

end

local params.body = { [“image”] = " ocr1.jpg", [“language”] = “en”, [“apikey”] = “myapikey” }

network.upload(“http://api.ocrapiservice.com/1.0/rest/ocr”,  “POST”,  networkListener,  params, “ocr1.jpg”,  system.ResourceDirectory, “multipart/form-data”)

I think the problem is how to format the params variable and the docs for the upload function aren’t very clear and the “object.json” notation in the docs makes it even more confusing.  I tried to declare local params.body = { [“image”] = " ocr1.jpg", [“language”] = “en”, [“apikey”] = “myapikey” } before calling network.upload but it still did not work.  Any suggestions or examples would be very helpful.  I’m really not sure what I’m doing wrong and the usual methods of troubleshooting are not working.  Thanks.

[lua]

local params.body = { [“image”] = " ocr1.jpg", [“language”] = “en”, [“apikey”] = “myapikey” }

network.upload(“http://api.ocrapiservice.com/1.0/rest/ocr”,  “POST”,  networkListener,  params, “ocr1.jpg”,  system.ResourceDirectory, “multipart/form-data”)

[/lua]

I would try this first:

[lua]

local params.body = { image = " ocr1.jpg", language = “en”, apikey = “myapikey” }

network.upload(“http://api.ocrapiservice.com/1.0/rest/ocr”,  “POST”,  networkListener,  params, “ocr1.jpg”,  system.ResourceDirectory, “image/jpeg”)

[/lua]

Now is the image really in your app bundle or is it saved in some other place like system.DocumentsDirectory?  You can’t write to system.ResourcesDirectory, so that would be a file you would have to ship with your app.  I’m not sure why you would want to upload a fixed file like that.  I would expect that you’ve used the camera to scan an image and that file would not be in system.ResourcesDirectory.
 

I tried your code but it gives a syntax error, so I tried the following:

local params = {}

params.body = { image = “ocr1.jpg”, language = “en”, apikey = “myapikey” }

network.upload(“http://api.ocrapiservice.com/1.0/rest/ocr”,  “POST”,  networkListener,  params, “ocr1.jpg”,  system.ResourceDirectory, “image/jpeg”)

This still results in the same “HTTP 400 the language parameter is missing” error that I was getting before.

I have the ocr1.jpg image in the same directory as my main.lua file for simplicity.  Eventually, the image will be generated by the user from the camera, but I figured it’s best not to overcomplicate things just yet and build one piece at a time.  Since the entire app hinges on this network connection working I’m trying to tackle it first.

Due to my lack of experience with Corona and its network functionality, I’m not sure if it’s a bug in Corona or the ocr api I’m trying to use.  The parameters I’m inputting work just fine on a web form on the ocr company’s site.