Converting image dataUrl to Blob image for AJAX POST with javascript - javascript

I have the following code which will take an image, allow the user to crop (with other code not shown or necessary for this question), and then render the image in base64 from canvas.
I need to be able to convert the image to binary, as the API endpoint its being submitted to can't take base64. I have functionality to convert to a Blob, but I'm not sure how to implement it correctly:
$(function () {
var fileInput = document.getElementById("file"),
renderButton = $("#renderButton"),
submit = $(".submit"),
imgly = new ImglyKit({
container: "#container",
ratio: 1 / 1
});
// As soon as the user selects a file...
fileInput.addEventListener("change", function (event) {
var file;
var fileToBlob = event.target.files[0];
var blob = new Blob([fileToBlob], {
"type": fileToBlob.type
});
// do stuff with blob
console.log(blob);
// Find the selected file
if (event.target.files) {
file = event.target.files[0];
} else {
file = event.target.value;
}
// Use FileReader to turn the selected
// file into a data url. ImglyKit needs
// a data url or an image
var reader = new FileReader();
reader.onload = (function (file) {
return function (e) {
data = e.target.result;
// Run ImglyKit with the selected file
try {
imgly.run(data);
} catch (e) {
if (e.name == "NoSupportError") {
alert("Your browser does not support canvas.");
} else if (e.name == "InvalidError") {
alert("The given file is not an image");
}
}
};
})(file);
reader.readAsDataURL(file);
});
// As soon as the user clicks the render button...
// Listen for "Render final image" click
renderButton.click(function (event) {
var dataUrl;
imgly.renderToDataURL("image/jpeg", {
size: "1200"
}, function (err, dataUrl) {
// `dataUrl` now contains a resized rendered image
//Convert DataURL to Blob to send over Ajax
function dataURItoBlob(dataUrl) {
// convert base64 to raw binary data held in a string
var byteString = atob(dataUrl.split(',')[1]);
// separate out the mime component
var mimeString = dataUrl.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to an ArrayBuffer
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
// write the ArrayBuffer to a blob, and you're done
//var bb = new BlobBuilder();
//bb.append(ab);
//return bb.getBlob(mimeString);
return new Blob([ab], {
type: 'image/jpeg'
});
}
var blob = dataURItoBlob(dataUrl);
//console.log("var blob: " + blob);
//var fd = new FormData(document.forms[0]);
var image = $("<img><br>").attr({
src: dataUrl
});
image.appendTo($(".result"))
$removeButton = $('<button class="btn btn-default remove">')
.text('Remove ' + imageid.value).appendTo($(".result"))
.on('click', function () {
panel.remove();
$(this).remove();
return false;
});
$submitButton = $('<div class="btn btn-default submit"></div>')
.text('Submit ' + imageid.value).appendTo($(".result"))
.on('click', function () {
var fd = new FormData;
fd.append('file', blob, 'image.png');
//console.log("var fd: " + fd);
var xhr = new XMLHttpRequest();
var saveImage = encodeURIComponent(dataUrl);
//console.log("SAVE IMAGE: " + saveImage);
//console.log(saveImage);
fd.append("myFile", blob);
xhr.open('POST', 'http://url.com/rest/v1/utils/guid/encode?' + saveImage + '&imageid=' + imageid.value, true);
xhr.send(fd);
});
});
});
});
On Submit, I get the following in the console:
http://url.com/rest/v1/utils/guid/encode?data%3Aimage%2Fjpeg%3Bbase64%2C%2F…CiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAP%2FZ
The current version in jsFiddle: LINK

Related

Generate Zip file contain list of Files without JSZip library

Hello Developers,
I'm trying to download the list of files getting form XMLHttpRequest() request method and store it in the array of files. I wanted to zip all the files in an array using javascript without using any 3rd party library.
I have tried to achieve this by URL.createObjectURL(url) and URL.revokeObjectURL(url) method but the file I'm getting is corrupted.
I'm Sharing my code snippet please help me out
const URLS = [
'https://vr.josh.earth/assets/2dimages/saturnv.jpg',
'https://vr.josh.earth/assets/360images/hotel_small.jpg',
'https://vr.josh.earth/assets/360images/redwoods.jpg'
];
$(document).ready(function () {
debugger
$("#downloadAll").click(function () {
var blob = new Array();
var files = new Array();
URLS.forEach(function (url, i) {
getRawData(url, function (err, data) {
debugger
var mydata = data;
// mydata = btoa(encodeURIComponent(data));
// var blobData = b64toBlob(mydata , 'image/jpg');
var blobData = new Blob([mydata], { type: 'image/jpg' });
blob.push(blobData);
var filename = "testFiles" + i + ".jpg";
var file = blobToFile(blobData, filename);
files.push(file);
debugger
if (files.length == URLS.length) {
// saveData(blob, "fileName.zip");
var AllBlobData = new Blob([blob], { type: 'application/zip' });
saveData(AllBlobData, "Test.zip");
// saveFile("DownloadFiles.zip", "application/zip", files)
}
});
});
});
});
//Retriving record using XMLHttpRequest() method.
function getRawData(urlPath, callback, progress) {
var request = new XMLHttpRequest();
request.open("GET", urlPath, true);
request.setRequestHeader('Accept', '');
if ('responseType' in request)
request.responseType = "arraybuffer"
if (request.overrideMimeType)
request.overrideMimeType('text/plain; charset=x-user-defined');
request.send();
var file, err;
request.onreadystatechange = function () {
if (this.readyState === 4) {
request.onreadystatechange = null;
if (this.status === 200) {
try {
debugger
var file = request.response || request.responseText;
} catch (error) {
throw error;
}
callback(err, file);
} else {
debugger
callback(new Error("Ajax Error!!"))
}
} else {
debugger
}
}
}
//For Saving the file into zip
var saveData = (function () {
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
return function (data, fileName) {
// var AllBlobs = new Blob([data], { type: "" });//application/zip //octet/stream
// var url = window.URL.createObjectURL(AllBlobs);
var url = window.URL.createObjectURL(data);
a.href = url;
a.download = fileName;
a.click();
window.URL.revokeObjectURL(url);
};
}());
//Downloaded Zip File
enter image description here

A image converted with canvas fails to be read by python PIL _io.BytesIO

Python PIL rejects to read an image you have resized with Javascript canvas
I resize an image on the client-side with Javascript:
var reader = new FileReader();
reader.onload = function (e) {
el('image-picked').src = e.target.result;
el('image-picked').className = '';
var image = new Image();
//compress Image
image.onload=function(){
el("image-picked").src=image.src;
var canvas=document.createElement("canvas");
var context=canvas.getContext("2d");
new_size = get_sizes(image.width,image.height,max_side_px)
[canvas.width,canvas.height] = new_size;
context.drawImage(image,
0,
0,
image.width,
image.height,
0,
0,
canvas.width,
canvas.height
);
console.log("Converted");
//el('image-picked').className = 'no-display'
//el('image-picked').src=""
el('upload-Preview').className = ''
el('upload-Preview').src = canvas.toDataURL("image/png", quality);
The result seems ok, less size, seemingly ok:
There are only minor differences on the files with identify:
(base) ➜ Desktop file before.png after.png
before.png: PNG image data, 4048 x 3036, 8-bit/color RGB, non-interlaced
after.png: PNG image data, 500 x 375, 8-bit/color RGBA, non-interlaced
Then I send the file via POST:
var xhr = new XMLHttpRequest();
var loc = window.location
xhr.open('POST', `${loc.protocol}//${loc.hostname}:${loc.port}/analyze`, true);
xhr.onerror = function() {alert (xhr.responseText);}
xhr.onload = function(e) {
if (this.readyState === 4) {
var response = JSON.parse(e.target.responseText);
el('result-label').innerHTML = `Result = ${response['result']}`;
}
}
var fileData = new FormData();
var file = new File([el('upload-Preview').src],
"image.png", { type: "image/png",
lastModified : new Date()});
fileData.append('file', uploadFiles[0]);
xhr.send(fileData);
And then I read on the server with python open_image(BytesIO(img_bytes)) :
#app.route('/analyze', methods=['POST'])
async def analyze(request):
data = await request.form()
img_bytes = await (data['file'].read())
img = open_image(BytesIO(img_bytes))
The above works without problems with any normal image, but it fails with any image that is the result of the resize with js, and the error is
File "/Users/brunosan/anaconda3/envs/fastai/lib/python3.7/site-packages/PIL/Image.py", line 2705, in open
% (filename if filename else fp))
OSError: cannot identify image file <_io.BytesIO object at 0x124ce6360>```
I've tried canvas.toDataURL("image/jpeg", quality) on the JS side, and reading directly with PIL (not fastai, which calls PIL). It's the same error :frowning_face:
Found the answer here.
I was injecting the image as a a DataURL, when the POST expected a binary. I could see the difference using the "Network" tab:
To convert a DataURL into the binary we need to make a Blob, and then put it into a File:
function dataURItoBlob(dataURI) {
// convert base64/URLEncoded data component to raw binary data held in a string
var byteString;
if (dataURI.split(',')[0].indexOf('base64') >= 0)
byteString = atob(dataURI.split(',')[1]);
else
byteString = unescape(dataURI.split(',')[1]);
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to a typed array
var ia = new Uint8Array(byteString.length);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ia], {type:mimeString});
}
blob=dataURItoBlob(el('upload-Preview').src)
var file = new File([blob],
"image.png", { type: "image/png",
lastModified : new Date()});
var fileData = new FormData();
fileData.append('file', file);

convert blob js to file image php

i try to send an DataUri image using xhr and FormData() ,
so i find a method tho convert DataUri To blob
function dataURItoBlob(dataURI) {
// convert base64/URLEncoded data component to raw binary data held in a string
var byteString;
if (dataURI.split(',')[0].indexOf('base64') >= 0)
byteString = atob(dataURI.split(',')[1]);
else
byteString = unescape(dataURI.split(',')[1]);
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to a typed array
var ia = new Uint8Array(byteString.length);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
and i send the blob var using xhr
var blob = dataURItoBlob(dataURL);
var data = new FormData();
data.append('photos[]', blob, "file.png");
var xhr = new XMLHttpRequest();
xhr.open('POST', '/upload', true);
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
var percentComplete = (e.loaded / e.total) * 100;
console.log(percentComplete + '% uploaded');
}
};
xhr.onload = function() {
alert(this.response);
var resp = JSON.parse(this.response);
console.log('Server got:', resp);
};
xhr.send(data);
next , i recive the var photos[] and i get the blob object , but i cant save it as file
function storeBlob($blob, $fileName)
{
$blobRE = '/^data:((\w+)\/(\w+));base64,(.*)$/';
if (preg_match($blobRE, $blob, $m))
{
$imageName = (preg_match('/\.\w{2,4}$/', $fileName) ? $fileName : sprintf('%s.%s', $fileName, $m[3]));
return file_put_contents($imageName,base64_decode($m[4]));
}
return false; // error
}

Length of uploaded couchDB attachment always 0 Bytes

So...I'm new to all this stuff and I'm developing an app for android with AngularJS and Ionic Framework and try to upload an audiofile I have recorded with the cordova capture Plugin like this:
// gets called from scope
$scope.captureAudio = function() {
var options = { limit: 1, duration: 10 };
$cordovaCapture.captureAudio(options).then(function(audioData) {
uploadFile(documentID, audioData);
}, function(err) {
console.log('error code: ' + err);
});
};
var uploadFile = function (document, file) {
var baseUrl = 'urltomydatabase';
var name = encodeURIComponent'test.3gpp'),
type = file[0].type,
fileReader = new FileReader(),
putRequest = new XMLHttpRequest();
$http.get(baseUrl + encodeURIComponent(document))
.success(function (data) {
putRequest.open('PUT', baseUrl + encodeURIComponent(document) + '/' + name + '?rev=' + data._rev, true);
putRequest.setRequestHeader('Content-Type', type);
fileReader.readAsArrayBuffer(file[0]);
fileReader.onload = function (readerEvent) {
putRequest.send(readerEvent);
};
putRequest.onreadystatechange = function (response) {
if (putRequest.readyState == 4) {
//success - be happy
}
};
})
.error(function () {
// failure
});
};
How the file looks in the console.log:
Playing the recorded file on the device works nice.
But everytime I upload the recording and the upload has finished, the uploaded attachment inside the document has the length '0' in the couchDB.
How the created file looks in the database after the upload:
What am I doing wrong?
EDIT: I just found out, when I upload an image, passed from this function as blob, it works well:
function upload(imageURL) {
var image = new Image();
var onload = function () {
var canvas = document.createElement("canvas");
canvas.width = this.width;
canvas.height = this.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0);
canvas.toBlob(function (blob) {
uploadFile(documentID, blob);
});
};
image.onload = onload;
image.src = imageURL;
}
So maybe the solution is creating a blob from the audiofile? But everytime I try it, my blob has the size of 0 bytes even before uploading it and I don't find somewhere a great explanation of how to convert a MediaFile object to blob...
It looks like your code does not send the content of your file as multipart attachment. To see what is really send to couchdb, capture the traffic with wireshark (https://www.wireshark.org/) or such.
This thread brought me to the solution, PouchDB purifies it. Now my upload function looks like this and can handle every file format
// e.g capture Audio
$scope.captureAudio = function () {
var options = {limit: 1, duration: 10};
$cordovaCapture.captureAudio(options).then(function (audioData) {
uploadFile(documentID, audioData, 'audio');
}, function (err) {
console.log('error code: ' + err);
});
};
var uploadFile = function (id, file, mediatype) {
var fileName = makeID();
if (mediatype == 'image') var name = encodeURIComponent(fileName + '.jpg');
if (mediatype == 'audio') var name = encodeURIComponent(fileName + '.3gpp');
if (mediatype == 'video') var name = encodeURIComponent(fileName + '.3gp');
db.get(id).then(function (doc) {
var path = file.fullPath;
window.resolveLocalFileSystemURL(path, function (fileEntry) {
return fileEntry.file(function (data) {
var reader = new FileReader();
reader.onloadend = function (e) {
var blob = b64toBlobAlt(e.target.result, file.type);
if (blob) {
db.putAttachment(id, name, doc._rev, blob, file.type).then(function () {
if (mediatype == 'video' || mediatype == 'image') getMedia();
if (mediatype == 'audio') $scope.audios.push(source);
});
}
};
return reader.readAsDataURL(data);
});
});
});
};
// creating the blob from the base64 string
function b64toBlobAlt(dataURI, contentType) {
var ab, byteString, i, ia;
byteString = atob(dataURI.split(',')[1]);
ab = new ArrayBuffer(byteString.length);
ia = new Uint8Array(ab);
i = 0;
while (i < byteString.length) {
ia[i] = byteString.charCodeAt(i);
i++;
}
return new Blob([ab], {
type: contentType
});
}

Cordova - Capture video and retrieve base64 data

I am using phonegap to record a video and I am wanting to save the base64 data-encoded string. So far I have tried this..
function captureSuccess(mediaFiles) {
var i, path, len;
path = mediaFiles[0];
win(path);
}
function win(file) {
var reader = new FileReader();
reader.onloadend = function (evt) {
console.log("read success");
console.log(evt.target.result);
};
reader.readAsDataURL(file);
};
function captureError(error) {
navigator.notification.alert('Error code: ' + error.code, null, 'Capture Error');
}
function captureVideo() {
navigator.device.capture.captureVideo(captureSuccess, captureError, {limit: 1});
}
I have used readAsDataURL as specified in the documentation. The output of evt.target.result is "data:video/mp4;base64," but there isn't any encoded data after the filetype.
Is there anything else I need to add in order to get the full base64 data of the video?
I am really struggling to find anything that can help me. Any help would be greatly appreciated.
var b64toBlobAlt = function(dataURI, contentType) {
var ab, byteString, i, ia;
byteString = atob(dataURI.split(',')[1]);
ab = new ArrayBuffer(byteString.length);
ia = new Uint8Array(ab);
i = 0;
while (i < byteString.length) {
ia[i] = byteString.charCodeAt(i);
i++;
}
return new Blob([ab], {
type: contentType
});
};
var path = mediaFiles[0].fullPath;
window.resolveLocalFileSystemURL(path, function(fileEntry) {
return fileEntry.file(function(data) {
var reader = new FileReader();
reader.onloadend = function(e) {
var blob = b64toBlobAlt(e.target.result, 'video/mp4');
if (blob) {
// do whatever you want with blob
});
}
};
return reader.readAsDataURL(data);
});
});

Categories