I am trying to receive the file sent through AJAX. What's happening is that when the file sent using Chrome/Firefox the file goes to req.files but when it was sent using Safari, the file goes to req.params. The application treat the file as a string "[Object blob]". Thanks.
Sending userdata through ajax.
updatePartnerProfile: function(obj){
var parentObj = this;
var target = $(obj.target);
var parent = target.closest('#editPartnerDetailsForm');
var logoImg = parent.find('.cropped');
var companyLogoBase64 = logoImg.find('.croppedImage').attr('src');
var companyLogo = util.dataURItoBlob(companyLogoBase64);
var userData = new FormData();
userData.append('token', parentObj.token);
userData.append('companyLogo', companyLogo);
$.ajax({
type: 'POST',
url: parentObj.serverUrl + 'api/admin/update/organization/' + parentObj.partnerId,
processData: false,
contentType: false,
cache: false,
data: userData,
success: function(data){
//todo
}
},
error: function(err){
console.log(err);
}
});
},
dataURItoBlob : function(dataURI) {
// convert base64/URLEncoded data component to raw binary data held in a string
if (!_.isUndefined(dataURI)){
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});
} else {
return null;
}
}
Am I missing something in the code?
Well, as per this question, you need to be using the buffer property of ia, not just [ia]. Instead of
return new Blob([ia], {type:mimeString});
try
return new Blob([ia.buffer], {type:mimeString});
Related
I am getting this error that Chrome failed to load the PDF document. I can see the content of the data is the console window so I have the data being returned I just not sure why it will not display? If I File.WriteAllBytes to disk it will open fine so it maybe something with the creating the new Blob
Failed to load PDF document.
ts code
printItems(versionKeys: string[]): JQueryPromise<any> {
console.log('printItems');
$.ajax({
type: "post",
contentType: "application/json",
data: JSON.stringify(versionKeys),
url: this.apiUrls.PrintTemplates,
success: function (data, status, xhr) {
console.log('printItems');
console.log(data);
let blob = new Blob([data.Content], { type: data.ContentType });
var url = URL.createObjectURL(blob);
console.log(url);
window.open(url);
console.log('success');
}
});
return;
}
Error
I converted the base64 string to a bytes
var binary_string = window.atob(data.Content)
var len = data.Content.length;
var bytes = new Uint8Array(len);
for (var i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
let blob = new Blob([bytes.buffer], { type: data.ContentType })
var url = URL.createObjectURL(blob);
window.open(url);
I'm trying to send my canvas image to controller. I tried using ajax but it doesn't seem to work. Hope you can help me. This is my code.
function takeSnapshot() {
var video = document.querySelector('video')
, canvas;
var img = document.querySelector('img') || document.createElement('img');
var context;
var width = video.offsetWidth
, height = video.offsetHeight;
canvas = canvas || document.createElement('canvas');
canvas.width = width;
canvas.height = height;
context = canvas.getContext('2d');
context.drawImage(video, 0, 0, width, height);
img.src = canvas.toDataURL('image/png');
document.body.appendChild(img);
var dataURL = canvas.toDataURL('image/png');
var blob = dataURItoBlob(dataURL);
var fd = new FormData(document.forms[0]);
fd.append("uploadfile", blob, "test");
$.ajax({
type: "POST",
enctype: 'multipart/form-data',
url: "/api/file/upload",
data: fd,
processData: false, //prevent jQuery from automatically transforming the data into a query string
contentType: false,
cache: false,
success: (data) => {
alert("shit");
},
error: (e) => {
alert("error");
}
});
}
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});
}
And this is my controller that receives the submitted image.
#PostMapping("/api/file/upload")
public String uploadMultipartFile(#RequestParam("uploadfile") MultipartFile file) {
try {
fileStorage.store(file);
return "File uploaded successfully! -> filename = " + file.getOriginalFilename();
} catch (Exception e) {
return "Error -> message = " + e.getMessage();
}
}
I tried setting the value of input file type mannually but others said that it may lead to security problems. And I also I can't make it work. I want to do direct image capturing and save the image to server. I'm using spring and hibernate. Hoping you could help me. Thank you !!
I'm trying to record a video (already working) using HTML5 video tag, "getUserMedia" to access the device camera and MediaRecorder API to capture the frames and Angular1 to handle the file uploading. Now I'm having trouble uploading the Blob to my PHP server which is running on Laravel, I currently have 2 ways to upload the video, first is by "ng-click" this works fine but when I programmatically upload the Blob using the same function which "ng-click" run it seems to break the mimeType of my Blob here's how my code looks.
$scope.uploader = function() {
let fData = new FormData();
let blob = new Blob($scope.chunk, { type: 'video/webm' });
fData.append('vid', blob)
$http.post(url, fData, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined},
}, success, error)
})
$timeout(function() {
$scope.uploader();
}, 10000)
This issue here is when the "$scope.uploader()" is called using "ng-click" it works fine but when calling the "uploader" method using the "$timeout" it seems to change the mimeType to "application/octet-stream" which causes the issue.
Hello Try this code,
function base64ToBlob(base64Data, contentType) {
contentType = contentType || '';
var sliceSize = 1024;
var byteCharacters = atob(base64Data);
var bytesLength = byteCharacters.length;
var slicesCount = Math.ceil(bytesLength / sliceSize);
var byteArrays = new Array(slicesCount);
for (var sliceIndex = 0;sliceIndex <slicesCount;++sliceIndex) {
var begin = sliceIndex * sliceSize;
var end = Math.min(begin + sliceSize, bytesLength);
var bytes = new Array(end - begin);
for (var offset = begin, i = 0;offset <end;++i, ++offset) {
bytes[i] = byteCharacters[offset].charCodeAt(0);
}
byteArrays[sliceIndex] = new Uint8Array(bytes);
}
return new Blob(byteArrays, {
type: contentType});
}
Define scope
$scope.onFile = function(blob) {
Cropper.encode((file = blob)).then(function(dataUrl) {
$scope.dataUrl = dataUrl;
$scope.odataUrl = dataUrl;
$timeout(showCropper); // wait for $digest to set image's src
});
};
Submit method
$scope.uploadImage = function () {
if ($scope.myCroppedImage === '')
{
}
$scope.msgtype = "";
$scope.msgtxt = "";
var fd = new FormData();
var imgBlob = dataURItoBlob($scope.myCroppedImage);
fd.append('clogo', imgBlob);
fd.append('actionfile', 'editimage');
$http.post(
'../user/user_EditCompany.php',
fd, {
transformRequest: angular.identity,
headers: {
'Content-Type': undefined
}
}
)
.success(function (response) {
// console.log(response);
if (response.status == 'success')
{
//your code
}else{
//your code
}
})
.error(function (response) {
console.log('error', response);
});
};
function dataURItoBlob(dataURI) {
var binary = atob(dataURI.split(',')[1]);
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
var array = [];
for (var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], {
type: mimeString
});
}
Thanks, the issue was caused by upload and post limit in my php.ini.
I used a jquery plugin to crop images. The plugin will crop the image and give it to me as a base64 encoded string. In order to upload it to S3, I need to convert this into a file and pass the file into the upload function. How can I do this? I tried a lot of things including decoding the string using atob. None worked.
Here's the code of the cropping plugin ('croppie') which gives me the encoded string :
imageCropper.croppie('result', {
type: 'canvas',
size: 'viewport',
format: 'jpeg'
}).then(function (resp) {
updateAvatar(resp);
});
I pass it to a function called updateAvatar. Here's the updateAvatar function :
updateAvatar({Meteor, Slingshot}, avatar) {
const uploader = new Slingshot.Upload('userAvatarUpload');
uploader.send(avatar, function (error, downloadUrl) {
if (error) {
// Log service detailed response.
console.error('Error uploading', uploader.xhr.response);
console.log(error);
}
else {
console.log('uploaded', downloadUrl);
}
});
}
The uploader.send function expects a file or a url. It won't accept my encoded string.
The plugin which I use to upload files to S3 : https://github.com/CulturalMe/meteor-slingshot
It seems like the missing 'brick' in your code is a function that would take a base64-encoded image and convert it to a Blob.
So, I'm going to focus on that part exclusively with a short comment for each step.
The following function expects a string such as:
data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICA...
function base64ImageToBlob(str) {
// extract content type and base64 payload from original string
var pos = str.indexOf(';base64,');
var type = str.substring(5, pos);
var b64 = str.substr(pos + 8);
// decode base64
var imageContent = atob(b64);
// create an ArrayBuffer and a view (as unsigned 8-bit)
var buffer = new ArrayBuffer(imageContent.length);
var view = new Uint8Array(buffer);
// fill the view, using the decoded base64
for(var n = 0; n < imageContent.length; n++) {
view[n] = imageContent.charCodeAt(n);
}
// convert ArrayBuffer to Blob
var blob = new Blob([buffer], { type: type });
return blob;
}
Convert the base64 string to blob, to be used in upload to S3. There are tidier ways of doing this of course! :)
Original SO Answer here: https://stackoverflow.com/a/16245768/1350913
imageCropper.croppie('result', {
type: 'canvas',
size: 'viewport',
format: 'jpeg'
}).then(function(resp) {
var contentType = 'image/png';
var s3Blob = b64toBlob(resp, contentType);
updateAvatar(s3Blob);
});
updateAvatar({
Meteor,
Slingshot
}, avatar) {
const uploader = new Slingshot.Upload('userAvatarUpload');
uploader.send(avatar, function(error, downloadUrl) {
if (error) {
// Log service detailed response.
console.error('Error uploading', uploader.xhr.response);
console.log(error);
} else {
console.log('uploaded', downloadUrl);
}
});
}
function b64toBlob(b64Data, contentType, sliceSize) {
contentType = contentType || '';
sliceSize = sliceSize || 512;
var b64DataString = b64Data.substr(b64Data.indexOf(',') + 1);
var byteCharacters = atob(b64DataString);
var byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
var slice = byteCharacters.slice(offset, offset + sliceSize);
var byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
var blob = new Blob(byteArrays, {
type: contentType
});
return blob;
}
The base64ToFile function (.ts) converts the base64 string into a File. The codeUnits and charCodes part make sure you can read Unicode text as ASCII by converting the string such that each 16-bit unit occupies only one byte.
Finally the download function (.ts) downloads the converted file from your browser to your local machine.
function base64ToFile(base64data: string, myFileNameWithdotExtention: string,
fileType: string): File {
let content = decodeURIComponent(escape(window.atob(base64data)));
let fileName = myFileNameWithdotExtention;
const codeUnits = Uint16Array.from(
{ length: content.length },
( _, index) => content.charCodeAt(index)
);
const charCodes = new Uint8Array(codeUnits.buffer);
const type = fileType; // 'text/csv' for instance
const blob = new Blob([charCodes], { type });
return new File([blob], fileName, { lastModified: new Date().getTime(), type });
}
download(){
let res: string = getMyDataFromSomewhere(); // base64 string
let data = base64ToFile(res);
let element = document.createElement('a');
window.URL = window.URL || window.webkitURL;
element.setAttribute('href', window.URL.createObjectURL(data));
element.setAttribute('download', data.name);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
I want to download multiple types of files using AJAX.
I decided to generate a get requests with file name as query string using AJAX and get the response as base64 string and then convert it to blob object and download/save it using hyperlink a tag along with download attribute.
Kindly help me, how to use the optimized way/code to convert file to base64 string and then revert the base64 string to blob?
ASP.Net httpHandler code is here:
Imports System
Imports System.Web
Imports System.IO
Public Class FileDownload : Implements IHttpHandler
Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
Dim Request As HttpRequest = context.Request
Dim Response As HttpResponse = context.Response
Dim serverFile As String = Request.QueryString("filename")
Dim filePath As String = String.Empty
filePath = context.Server.MapPath("~") & "\" & serverFile
Dim file As New System.IO.FileInfo(filePath)
Try
If (file.Exists) Then
Response.Clear()
Response.ClearContent()
Using reader As New FileStream(filePath, FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read)
Dim buffer As Byte() = New Byte(reader.Length - 1) {}
reader.Read(buffer, 0, CInt(reader.Length))
Response.Write(Convert.ToBase64String(buffer))
End Using
Response.Flush()
Response.End()
Else
Response.Write("File Not Found!")
Response.StatusCode = 500
End If
Catch ex As Exception
Response.Write(ex.ToString)
Response.StatusCode = 500
context.ApplicationInstance.CompleteRequest()
End Try
End Sub
Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
Return False
End Get
End Property
End Class
Javascript function called with httphadler's application path as url and client side file name as filename
function downloadFileByAjax(filename, url) {
$.ajax({
type: 'GET',
url: url,
responseType: 'arraybuffer',
downloadid: filename,
success: function (result, status, xhr) {
var octetStreamMime = 'application/octet-stream';
var filename = this.downloadid;
var contentType = xhr.getResponseHeader('content-type') || octetStreamMime;
var a = document.createElement('a');
var urlCreator = window.URL || window.webkitURL || window.mozURL || window.msURL;
if (urlCreator && window.Blob && ('download' in a) && window.atob) {
var blob = base64ToBlob(result, contentType);
var url = window.URL.createObjectURL(blob);
a.setAttribute('href', url);
a.setAttribute("download", filename);
var event = document.createEvent('MouseEvents');
event.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
a.dispatchEvent(event);
//window.URL.revokeObjectURL(url);
}
},
error: function (xhr, msg, error) {
//console.log(xhr, msg, error);
//console.log(xhr.responseText);
console.log(msg);
},
complete: function (xhr, status) {
//console.log('completed');
}
});
}
function base64ToBlob(base64, mimetype, slicesize) {
if (!window.atob || !window.Uint8Array) {
console.log('The current browser doesnot have the atob function. Cannot continue');
return null;
}
mimetype = mimetype || '';
slicesize = slicesize || 512;
var bytechars = atob(base64);
var bytearrays = [];
for (var offset = 0; offset < bytechars.length; offset += slicesize) {
var slice = bytechars.slice(offset, offset + slicesize);
var bytenums = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
bytenums[i] = slice.charCodeAt(i);
}
var bytearray = new Uint8Array(bytenums);
bytearrays[bytearrays.length] = bytearray;
}
return new Blob(bytearrays, { type: mimetype });
}
To convert a file to base64 string use the following code
string data;
using (FileStream fs = new FileStream(dir + fileName, FileMode.Open, FileAccess.Read)) {
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, (int)fs.Length);
data = Convert.ToBase64String(buffer);
fs.Close();
}
return data;
In the success function of the ajax call convert the string to blob using the following code
var byteCharacters = atob(data);
var byteNumbers = new Array(byteCharacters.length);
for (var i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
var blob = null;
blob = new Blob([byteArray], { type: 'text/plain' });
blob = new Blob([byteArray], { type: 'application/pdf;base64' });
var blobUrl = URL.createObjectURL(blob);
Depending upon the file format you can specify the type attribute for the blob and then assign the blobUrl as the source to your anchor tag