Converting a Blob object into a File, for Ms Edge - javascript

I have a Blob Object, which is an image and I am trying to convert into a file object, But it shows errors in MS edge version 41. I am using formdata in 1st two attempts for the same
Attempt 1
fd.set('file', blobObj, fileName);
return (fd.get('file'));
This resulted in an error
object doesn't support this property or method 'set'
Attempt 2
I replaced set with append and then I got this
object doesn't support this property or method 'get'
Attempt 3
I replaced formdata entirely with a new logic which looked like this
let fileObject = new File([u8arr], fileName, { type: mime });
and I got an error saying
object doesn't support this action
Is there any other method that can be used? Can I directly use blob as a file?

AFAIK, Your third approach seems to be working ,
Try once by hard-coding the mime type to "image/jpeg" / "image/png" and include the date modeified and then verify once
var fileInstance = new File([blob], "FileName",{type:"image/jpeg", lastModified:new Date()})
If you are displaying it in javascript you should use something like this:
var URL = window.URL || window.webkitURL;
var url_instance = URL.createObjectURL(blob);
var image_source = new Image();
image_source.src = url_instance;
document.body.appendChild(image_source);

A File object is a specific kind of a Blob, it's just missing the two properties: lastModifiedDate and name(file name property).
So, you could convert the blob object to file object using the following code:
var blobtoFile = function blobToFile(theBlob, fileName) {
//A Blob() is almost a File() - it's just missing the two properties below which we will add
theBlob.lastModifiedDate = new Date();
theBlob.name = fileName;
return theBlob;
}
var file = blobtoFile(blob, "test.png");
More detail information about using the above code, please check this sample.
Besides, please check the FormData Method Browser compatibility, from it we can see most of the methods support Microsoft Edge 44+(EdgeHTML 18+, more detail, please check this article).
So, if you want to use FormData set or get method, please try to upgrade the Windows version(Microsoft Edge is part of the operating system and can't be updated separately. It receives updates through Windows Update, like the rest of the operating system.). Otherwise, you could use a JavaScript Object to store the blob or file object.
Detail updated steps as below: Select Start > Settings > Update & Security > Windows Update , then select Check for updates and install any available updates.

Related

How to create a modified copy of a File object in JavaScript?

Properties of files received from an <input type="file"> are read-only.
For example, the following attempt to re-write file.name would either fail silently or throw TypeError: Cannot assign to read only property 'name' of object '#<File>'.
<input onchange="onchange" type="file">
onchange = (event) => {
const file = event.target.files[0];
file.name = 'foo';
}
Attempting to create a copy via Object.assign({}, file) fails (creates an empty object).
So how does one clone a File object?
My solution lay in the File constructor:
https://developer.mozilla.org/en-US/docs/Web/API/File#Implementation_notes
Which itself is an extension of Blob:
https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob
let file = event.target.files[0];
if (this.props.distro) {
const name = 'new-name-here' + // Concat with file extension.
file.name.substring(file.name.lastIndexOf('.'));
// Instantiate copy of file, giving it new name.
file = new File([file], name, { type: file.type });
}
Note the first argument to File() must be an array, not simply the original file.
You can use FormData.prototype.append(), which also converts a Blob to a File object.
let file = event.target.files[0];
let data = new FormData();
data.append("file", file, file.name);
let _file = data.get("file");
A more cross browser solution
The accepted answer works for me too in modern browsers, but unfortunately it does not work in IE11, since IE11 does not support the File constructor.
However, IE11 does support the Blob constructor so it can be used as an alternative.
For example:
var newFile = new Blob([originalFile], {type: originalFile.type});
newFile.name = 'copy-of-'+originalFile.name;
newFile.lastModifiedDate = originalFile.lastModifiedDate;
Source: MSDN - How to create a file instannce using HTML 5 file API?

IE11 throw Invalid State error with this particular Blob construction

I have this code to save an excel using Blob
//Stream of data as res
var dataView = new DataView(res);
var blob = new Blob([dataView], {type: 'application/vnd.ms-excel'});
But in IE only the third line throw Invalid State Error even though in the document, it is fully supported
It seems that the issue pertains to IE. Uint8Array can be used in the constructor instead.
To convert a DataView to a equivalent Uint8Array:
var u8arr = new Uint8Array(dataView.buffer, dataView.byteOffset, dataView.byteLength);
Write a function to replace all DataView objects in the array passed to new Blob. Or see the polyfill here.

IE11 doesn't work well with Blob constructor & javascript array

I've been using Blob of HTML5 to consolidate a bunch of data including files and strings. Since the files and strings to be sent are not pre-specified in program, and I need to pack all data in a JS file and send them immediately, so I use Array of javascript to collect available data, then make this array as a parameter of Blob constructor. It works fine in Chrome and Firefox, but throws a javascript error when using IE11.
Unhandled exception at line 161, column 9 in ##$%.js
0x800a139e - JavaScript Runtime Error: InvalidStateError
My code is as follows:
var blobPackage_array = [];
if(userType != null)
blobPackage_array.push(userType);
if(userInfo != null)
blobPackage_array.push(userInfo);
for (var i = 0; i < fileList.length; i++) {
blobPackage_array.push(fileList[i]);
}
var blobPackage = new Blob(blobPackage_array); //throw javascript runtime error
I previously suspected that IE doesn't support Blob, so I tested this:
var blobPackage = new Blob(["test", fileList[0]]);
It worked fine, no error. My last guess is that IE doesn't recognise blobPackage_array as a valid parameter of Blob constructor. But Blob doesn't have a append method, meanwhile I can not know how many files that need to be appended, which means I can not construct a Blob once and for all.
Anyone ever encounter this? anything I can use to bypass this? I'd appreciate any suggestion.
Update! For some reason, I can not use FormData instead, It has to be blob...
anybody can help me on this?
Update again! Thanks to your kind reply, there are some progress. I checked MSDN, Blob's constructor should be like this: var blobObject = new Blob([new Uint8Array(array)], { type: 'image/png' });. I tried to construct a Uint8Array with blobPackage_array by this var uint8array = new Uint8Array(blobPackage_array);. I find that data is lost while this transformation. But in fact, var blobPackage = new Blob([uint8array]); can work, without errors. Thus I just need to fix the transformation problem.
I figured this out. I'm such an idiot..IE do not recognize my original blobPackage_array as a valid parameter because of those variables I append:
if(userType != null)
blobPackage_array.push(userType);
I just need to validate userType by this:
if(userType != null)
blobPackage_array.push(new String(userType));
So, don't bother to transform all data to UInt8Array type...

How to load a PDF into a blob so it can be uploaded?

I'm working on a testing framework that needs to pass files to the drop listener of a PLUpload instance. I need to create blob objects to pass inside a Data Transfer Object of the sort generated on a Drag / Drop event. I have it working fine for text files and image files. I would like to add support for PDF's, but it seems that I can't get the encoding right after retrieving the response. The response is coming back as text because I'm using Sahi to retrieve it in order to avoid Cross-Domain issues.
In short: the string I'm receiving is UTF-8 encoded and therefore the content looks like you opened a PDF with a text editor. I am wondering how to convert this back into the necessary format to create a blob, so that after the document gets uploaded everything looks okay.
What steps do I need to go through to convert the UTF-8 string into the proper blob object? (Yes, I am aware I could submit an XHR request and change the responseType property and (maybe) get closer, however due to complications with the way Sahi operates I'm not going to explain here why I would prefer not to go this route).
Also, I'm not familiar enough but I have a hunch maybe I lose data by retrieving it as a string? If that's the case I'll find another approach.
The existing code and the most recent approach I have tried is here:
var data = '%PDF-1.7%����115 0 obj<</Linearized 1/L ...'
var arr = [];
var utf8 = unescape(encodeURIComponent(data));
for (var i = 0; i < utf8.length; i++) {
arr.push(utf8.charCodeAt(i));
}
var file = new Blob(arr, {type: 'application/pdf'});
It looks like you were close. I just did this for a site which needed to read a PDF from another website and drop it into a fileuploader plugin. Here is what worked for me:
var url = "http://some-websites.com/Pdf/";
//You may not need this part if you have the PDF data locally already
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
//console.log(this.response, typeof this.response);
//now convert your Blob from the response into a File and give it a name
var fileOfBlob = new File([this.response], 'your_file.pdf');
// Now do something with the File
// for filuploader (blueimp), just use the add method
$('#fileupload').fileupload('add', {
files: [ fileOfBlob ],
fileInput: $(this)
});
}
}
xhr.open('GET', url);
xhr.responseType = 'blob';
xhr.send();
I found help on the XHR as blob here. Then this SO answer helped me with naming the File. You might be able to use the Blob by itself, but you won't be able to give it a name unless its passed into a File.

How to give a Blob uploaded as FormData a file name?

I am currently uploading images pasted from the clipboard with the following code:
// Turns out getAsFile will return a blob, not a file
var blob = event.clipboardData.items[0].getAsFile(),
form = new FormData(),
request = new XMLHttpRequest();
form.append("blob",blob);
request.open(
"POST",
"/upload",
true
);
request.send(form);
Turns out the uploaded form field with receive a name similar to this: Blob157fce71535b4f93ba92ac6053d81e3a
Is there any way to set this or receive this file name client side, without doing any server side communication?
For Chrome, Safari and Firefox, just use this:
form.append("blob", blob, filename);
(see MDN documentation)
Adding this here as it doesn't seem to be here.
Aside from the excellent solution of form.append("blob",blob, filename); you can also turn the blob into a File instance:
var blob = new Blob([JSON.stringify([0,1,2])], {type : 'application/json'});
var fileOfBlob = new File([blob], 'aFileName.json');
form.append("upload", fileOfBlob);
Since you're getting the data pasted to clipboard, there is no reliable way of knowing the origin of the file and its properties (including name).
Your best bet is to come up with a file naming scheme of your own and send along with the blob.
form.append("filename",getFileName());
form.append("blob",blob);
function getFileName() {
// logic to generate file names
}
That name looks derived from an object URL GUID. Do the following to get the object URL that the name was derived from.
var URL = self.URL || self.webkitURL || self;
var object_url = URL.createObjectURL(blob);
URL.revokeObjectURL(object_url);
object_url will be formatted as blob:{origin}{GUID} in Google Chrome and moz-filedata:{GUID} in Firefox. An origin is the protocol+host+non-standard port for the protocol. For example, blob:http://stackoverflow.com/e7bc644d-d174-4d5e-b85d-beeb89c17743 or blob:http://[::1]:123/15111656-e46c-411d-a697-a09d23ec9a99. You probably want to extract the GUID and strip any dashes.
Haven't tested it, but that should alert the blobs data url:
var blob = event.clipboardData.items[0].getAsFile(),
form = new FormData(),
request = new XMLHttpRequest();
var reader = new FileReader();
reader.onload = function(event) {
alert(event.target.result); // <-- data url
};
reader.readAsDataURL(blob);
It really depends on how the server on the other side is configured and with what modules for how it handles a blob post. You can try putting the desired name in the path for your post.
request.open(
"POST",
"/upload/myname.bmp",
true
);
Are you using Google App Engine?
You could use cookies (made with JavaScript) to maintain a relationship between filenames and the name received from the server.
When you are using Google Chrome you can use/abuse the Google Filesystem API for this. Here you can create a file with a specified name and write the content of a blob to it. Then you can return the result to the user.
I have not found a good way for Firefox yet; probably a small piece of Flash like downloadify is required to name a blob.
IE10 has a msSaveBlob() function in the BlobBuilder.
Maybe this is more for downloading a blob, but it is related.

Categories

Resources