I am attempting to send image data to a server API, though, the documentation included with the API only contains an example for JQuery, which I don't want to use with my nodejs project. Also, the JQuery example contains things that don't exist in Node, such as Blobs.
The example provided by the API is:
var sourceImage = new Image();
sourceImage.src = image; // add image data to object
sourceImage.onload = function() {
// Create a canvas with the desired dimensions
var canvas = document.createElement("canvas");
var dim = 256; // the image size
canvas.width = dim;
canvas.height = dim;
// Scale and draw the source image to the canvas
canvas.getContext("2d").drawImage(sourceImage, 0, 0, dim, dim);
var formDataWithCanvasImage = createFormData(canvas);
// Make ajax call here
}
function createFormData(canvas) {
var b64Img = canvas.toDataURL();
var binImg = dataURItoBlob(b64Img);
var fileName = new Date().getTime();// Name the file with the current timestamp and no extension
var fd = new FormData();
fd.append("imageClass", "preview");
fd.append("X-Requested-With", "Iframe");
fd.append("X-HTTP-Accept", "application/json, text/javascript, */*; q=0.01");
fd.append("file", binImg,fileName);
return fd;
}
$.ajax({
url: imageURL,
data: formDataWithCanvasImage,
processData: false,
contentType: false,
type: 'POST',
error: function() {alert("error uploading image");},
success: function(data){
console.log(data);
}
});
However, this wouldn't work with nodejs, because there is no canvas in nodejs, and no such thing as a blob. So, what I've done is read an image from the local disc and convert that buffer into an ArrayBuffer then encode it in analog-nico's request-promise like so:
let opts = {
uri: 'https://*****.com/api/images',
contentType: false,
processData: false,
type: 'POST',
formData: {
"imageClass": "application",
"X-Requested-With": "Iframe",
"X-HTTP-Accept": "application/json, text/javascript, */*; q=0.01"
"file": arraybuffer
},
}
request.post(opts).then(data => {....});
but the code throws TypeError: source.on is not a function. Has anyone encountered this problem before? How did you resolve it?
You could try loading the image from disk as a ReadStream and piping that using the request module to the API.
Rough Example:
fs.createReadStream(filename).pipe(request.put('http://example.com/api/images'))
The module is available via npm install request.
Related
I have two audio files from RecordRTC both local & remote streams. Now I want to merge the two files into one file and upload it to the server via AJAX.
e.g. (audio1.webm) and (audio2.webm).
mediaRecorder.stopRecording(function() {
var blob = mediaRecorder.getBlob();
var fileName = getFileName('webm');
var fileObject = new File([blob], fileName, {
type: 'audio/webm'
});
var formData = new FormData();
formData.append('blob', fileObject);
formData.append('filename', fileObject.name);
$.ajax({
url: '{{ url('/') }}/save-audio',
data: formData,
cache: false,
contentType: false,
processData: false,
type: 'POST',
success: function(response) {
console.log(response);
}
});
});
Thank you in advance.
UPDATE:
I made it this way instead of recorder.addStreams, and still I can get the recorded.
var remoteVideos = $('#remoteVideos video');
var el = [];
$.each($('#remoteVideos video'), function(index, val) {
el[index] = val.srcObject;
});
el.push(stream);
multiMediaRecorder = new MultiStreamRecorder(el);
You can use a similar library: MediaStreamRecorder. Then use MultiStreamRecorder and pass two streams as below,
recorder = new MultiStreamRecorder([localStream, remoteStream]);
You will get localStream from getUserMedia and remoteStream from onaddstream event listener.
You may want to just pass the audio tracks in the array. The rest of the things as it is. FFmpeg and file merging is not necessary.
I got it now by doing this, as below;
function onMediaSuccess(localStream) {
var remoteVideos = $('#remoteVideos video')[0];
multiMediaRecorder = new MultiStreamRecorder([localStream, remoteVideos.srcObject]);
multiMediaRecorder.ondataavailable = function (blob) {
// POST/PUT "Blob" using FormData/XHR2
var blobURL = URL.createObjectURL(blob);
console.log(blobURL);
};
multiMediaRecorder.start();
}
But now there's another problem, ondataavailable is called twice but the first video is playable and working properly, while the second video is playable but (less than one second) I think it might be corrupted.
Cheers!
I need to send an image from client to server using blob
I have converted a image to BLOB in jquery (client side) and sending the blob to python flask (server side) the problem is, I can't recreate image from BLOB. I have tried the following code in python but failed to get the image
Jquery code to convert image to blob:
function changeFile() {
var file = this.files[0];
var reader = new FileReader();
reader.addEventListener('load', readFile);
reader.readAsText(file);
}
function readFile(event) {
document.body.textContent = event.target.result;
console.log(event.target.result);
appendFileAndSubmit(event.target.result);
}
function appendFileAndSubmit(imageUrl){
var ImageURL = imageUrl
var data = {
'logo':ImageURL
}
$.ajax({
url: 'http://sdsdss/User/imgBlob',
method: 'POST',
dataType : 'json',
data: JSON.stringify(data),
contentType: 'application/json; charset=utf-8'
}).done(function(response){
var datas = JSON.parse(response);
console.log(datas);
});
}
document.getElementById("inp").addEventListener("change", changeFile);
Python Code: To recreate BLOB to image
function getImage(self):
reqData = json.loads(request.data)
Logo = reqData['logo']
png_recovered = base64.decodestring(Logo)
f = open("temp.png", "w")
f.write(png_recovered)
f.close()
Don't read the file as text, You are dealing with binary data. Best way to transfer binary with json is if you read the file as base64 instead reader.readAsDataURL(file) This will encode all bytes to a web safe base64 string (no slash or plus). Then you have to decode it with python as well.
I discourage you from using json when dealing with file transfer as it will increase the bandwidth with ~3 times as much (not to mention the time it also takes to decode and encode it back and forth) For this I recommend you instead use FormData.
var fd = new FormData()
fd.append('logo', files[0])
$.ajax({
url: 'http://sdsdss/User/imgBlob',
method: 'POST',
data: fd,
// Setting false prevent jQuery from transforming the data
processData: false,
contentType: false
}).then(function(response) {
console.log(JSON.parse(response))
})
or simpler yet, just post the file without any formdata, json or extra fields if they are not necessary.
fetch(uploudUrl, { method 'PUT', body: this.files[0] })
i am using cropperjs to crop images
Using the method getCroppedCanvas to get reference to the cropped canvas image
Using the canvas method canvas.toDataURL to compress the images into a jpeg files.
I don't use canvas.toBlob as its browser support is not clear.
My question is how can i turn the string i get from canvas.toDataURL into a blob so i can later use it in formData.
Update
server expect form data - multi-part
One method that I used while working on some tool is to convert the dataURL to Blob using this function:
function dataURLtoBlob(dataurl) {
var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], {type:mime});
}
And then you can send the Blob to the server using native xhr like this:
var blob = dataURLtoBlob(dataURI);
var fd = new FormData();
var xhr = new XMLHttpRequest ();
fd.append ('file', blob);
xhr.open('POST', '/endpoint', true);
xhr.onerror = function () {
console.log('error');
}
xhr.onload = function () {
console.log('success')
}
xhr.send (fd);
The blob builder code is taken from here: https://stackoverflow.com/a/30407840/2386736
use canvas.toDataURL to generate an JPEG image:
var JPEG_QUALITY=0.5;
var dataUrl = canvas.toDataURL('image/jpeg', JPEG_QUALITY).replace('data:image/jpeg;base64,', '');
And then send it to AJAX as data-multi-part:
jQuery.ajax({
url: 'php/upload.php',
data: dataUrl,
cache: false,
contentType: false,
processData: false,
type: 'POST',
success: function(data){
}
});
Depending on what your server side expects to receive.
By the way: You wrote "I don't use canvas.toBlob as its browser support is not clear" - You can see the browser support here:
I need help with HTML canvas element.I'm new to HTML.
I need to capture image from the webcam and send it to Microsoft cognitive API to find the emotions in the picture.
The API accepts image in octet-stream. The API is https://westus.dev.cognitive.microsoft.com/docs/services/5639d931ca73072154c1ce89/operations/563b31ea778daf121cc3a5fa
The code is
canvas = document.getElementById("myCanvas");
ctx = canvas.getContext('2d');
dataUrl = canvas.toDataURL("image/png");
$.ajax({
url: apiUrl,
beforeSend: function(xhrObj) {
xhrObj.setRequestHeader("Content-Type", "application/octet-stream");
xhrObj.setRequestHeader("Ocp-Apim-Subscription-Key", apiKey);
},
type: "POST",
data: dataUrl,
processData: false
}).done(function(response) {
...
});
HTTP Response code is 400 and the response message is as below.
{"error":{"code":"BadBody","message":"Invalid face image."}}
logging the dataUrl shows the data as
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAYAAAB5fY51AAAgAElEQVR4XqS92bOm2Vnlt7/pZGZVCU3IGkFCDhoxChDQBknQtGUBJtzd4Vvf+a7RUFklqVQC/xu.....
I have tried by removing data:image/png but no use.
I'm right canvas.toDataURL returns string form of base64 encoded data of the image. I can display this image on html page. I also did a right click saved it to local drive, and called API with file, it works.
So, the issue would be while moving the data from canvas element to the request body in binary format.
How can this be done ?. Thanks in advance for your help.
This might work. Try creating Blob from your dataUrl and pass it in to the ajax, as:
function createBlob(dataURL) {
var BASE64_MARKER = ';base64,';
if (dataURL.indexOf(BASE64_MARKER) == -1) {
var parts = dataURL.split(',');
var contentType = parts[0].split(':')[1];
var raw = decodeURIComponent(parts[1]);
return new Blob([raw], { type: contentType });
}
var parts = dataURL.split(BASE64_MARKER);
var contentType = parts[0].split(':')[1];
var raw = window.atob(parts[1]);
var rawLength = raw.length;
var uInt8Array = new Uint8Array(rawLength);
for (var i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
return new Blob([uInt8Array], { type: contentType });
}
in ajax, pass the blobData,
...
var blobData = createBlob(dataUrl);
$.ajax({
url : apiUrl,
beforeSend : function(xhrObj) {
xhrObj.setRequestHeader("Content-Type", "application/octet-stream");
xhrObj.setRequestHeader("Ocp-Apim-Subscription-Key", apiKey);
},
type : "POST",
data : blobData,
processData : false
}).done(function(response) {...}
I'm trying to save the photo captured using Phonegap's camera API. The function returns the file uri. When I save this, it directly saves the string uri and not the file.
I even tried specifying the content type as image in ajax header file. Gives me a broken link.
function capturePhoto(){
//alert(address);
navigator.camera.getPicture(uploadPhoto,onFail,{sourceType:1,quality:60,destinationType: Camera.DestinationType.FILE_URI});
}
function uploadPhoto(data){
var serverUrl = 'https://api.parse.com/1/files/myphoto.jpg';
$.ajax({
type: "POST",
headers: {'X-Parse-Application-Id': PARSE_APP,
'X-Parse-REST-API-Key':PARSE_REST
// "Content-Type": "image/png"
},
url: serverUrl,
data: data,
processData: false,
contentType: false,
success:function(e){
console.log(e.url);
},
error:function(){
console.loh("ERROR");
}
});
}
You will want to use destinationType: Camera.DestinationType.Native_URI. This will return the image's actual location on the device, typically something like file://storage/0/sdcard/.... You can then use this location to load/send/manipulate the image.
You need the FileTransfer API to get the contents of the file. In your uploadPhoto callback insert the following:
function uploadPhoto(data){
var ft = new FileTransfer();
var options = new FileUploadOptions();
options.mimeType = "image/jpeg";
options.chunkedMode = false;
options.params = { // Any params you need...
};
ft.upload(data, 'https://api.parse.com/1/files/myphoto.jpg',
function (e) {
console.log('Success');
},
function (e) {
alert("Upload failed");
}, options);
}
You might need to change some of the options and parameters depending on your backend (which you have not specified). Christopher Coenraets has a good video tutorial with code on how to do this. The other solution is base64 the result, in this you set the src of a image that you create to be the fileUri and then draw the image onto a canvas and get the dataUrl of the canvas. This method works with older versions of PhoneGap but is considerably slower than directly uploading using FileTransfer API.