How to POST base64 encodes an in-memory image as a file parameter
I have an image encoded as a base64 String and I am trying to POST
use it as a parameter for another REST API ( http://ocrapiservice.com/documentation/ ).
I don't want to store the file on disk - I want to keep the file in memory because eventually I want to create an image using getUserMedia
on the client and I will most likely use a hosted service that does not allow direct file I / O.
The problem is that most of the examples I can find zip images from disk using fs.createReadStream(somePath);
eg.
https://github.com/mikeal/request/blob/master/README.md#forms
I would prefer to use a library like the request library , but it might not be possible.
The code I have now:
var fs = require( 'fs' );
var path = require( 'path' );
var request = require( 'request' );
var WS_URL = 'http://api.ocrapiservice.com/1.0/rest/ocr';
function ocr( postData ) {
var r = request.post(WS_URL, completed);
var form = r.form();
form.append('apikey', 'REMOVED');
form.append('language', 'en' );
form.append('image', postData );
function completed(error, response, body) {
console.log( body );
}
}
// This works
ocr( fs.createReadStream(path.join(__dirname, 'example.png' ) ) );
// This does not work
// ignore that it being read from a file (the next line)
var base64Str = fs.readFileSync( 'example.png' ).toString('base64');
var buffer = new Buffer(base64Str, 'base64');
ocr( buffer.toString( 'binary' ) );
form.append
allows you to send an additional parameter, so if you need to set additional headers, then this is possible.
Is there any wrapper Stream
that I can use? I tried using this StringReader and it can be modified to at least send the filename and correct Content-Type.
How do I achieve this memory file allocation as a parameter of the web service?
Update:
I have corrected / updated the code above.
The response I am getting from the REST APIs listed above is:
HTTP / 1.1 400 Bad Request
File not provided
Here is the actual code I'm running: https://gist.github.com/leggetter/4968764
source to share
In the streamed version, you are working with chunks of a file, but in the version, base64Image
you are working with a base64 string. Since the stream version is working, the API ocr
obviously expects the form to just contain binary data, so you need to decode the base64 data before submitting.
// Reading straight from a Buffer.
var imageData = fs.readFileSync('example.png');
ocr( imageData );
// Reading from a new Buffer created from a base64 string.
var base64Image = '...';
ocr(new Buffer(base64Image, 'base64'));
Also note that in your example code:
// This line:
var base64Image = new Buffer(imageData, 'binary').toString('base64');
// does the same thing as this, because 'imageData' is alreadya Buffer
var base64Image = imageData.toString('base64');
source to share
I'm sure you can use Buffer
directly to query, without having to embed it in Stream
.
Doesn't work because you are using the wrong encoding. readFileSync
returns Buffer
by default if there is no encoding. The buffer uses utf-8 by default as its encoding. But you used the encoding as binary in between, which doesn't match what you have in the buffer.
var imageData = fs.readFileSync('example.png');//After you get imageData
var base64Image = imageData.toString('base64'); //base64 encoded string
var decodedImage = new Buffer(base64Image, 'base64'); //base64 encoded buffer
ocr (imageData); //You can use the file directly
ocr (base64Image); //Or you can use either the base-64 string or the base64-buffer
Look here for more encoding / decoding details NodeJS base64 encoding / decoding doesn't quite work
source to share
You can use the base64-image-upload NPM package that I whipped up as I had the same problem.
What this does is exactly the approach described by user568109, creating a buffer from a base64 string and POSTing. The important part is that it abstracts working with encodings, MIME types, and request headers, and this will greatly simplify your code.
source to share