I've got a drag and drop script that uses readAsArrayBuffer(). The length of the buffer is perfect, but I can't seem to figure out how to pull the data out of the buffer.
Apparently I've got to make a DataView or an Uint8Array or something, then iterate through its byteLength...help!
EDIT
Pertinent code (there's not much of it):
var reader = new FileReader();
reader.onload = function(e) {
// do something with e.target.result, which is an ArrayBuffer
}
reader.readAsArrayBuffer(someFileHandle);
This might change based on your answer to my comment, but if I assume that you are using a FileReader somewhere, you need to read it's result attribute in the loaded callback that you need to provide:
function loaded(evt) {
var datastring = evt.target.result;
// do something here
}
reader.onload = loaded; // where reader is a FileReader, FileReaderSync
Update: Ah, I see. Well then your best course of action is to follow to this duplicate:
Converting between strings and ArrayBuffers
Update2: Note that you could probably use readAsText() then, but I don't know if you're at liberty to do this.
Related
I'm using the following approach in order to preview images before uploading them:
$("#file").change(function() {
var reader = new FileReader();
reader.readAsArrayBuffer(this.files[0]);
var fileName = this.files[0].name;
var fileType = this.files[0].type;
alert(fileType)
reader.onloadend = function() {
var base64Image = btoa(String.fromCharCode.apply(null, new Uint8Array(this.result)));
// I show the image now and convert the data to base 64
}
}
I have noticed that when the image is large, the method fails and I cannot preview the image.
I am unsure if the problem is due to base64 conversion or the FileReader.
Is there any setting to increase the max size, or is there any work around?
Here is the error message thrown in the console :
Uncaught RangeError: Maximum call stack size exceeded
at FileReader.reader.onloadend
Your problem is that you use Function.apply which will convert your Typed Array items to arguments to the String.fromCharCode method.
Functions have a maximum arguments length limit.
To avoid this, when dealing with large files, the best way is to not process it at all.
If you need to send the file to your server, simply send the Blob directly, this can be easily achieved with the FormData API.
If you need to display the file i.e in HTML media element, then use URL.createObjectURL(yourFile) method.
And if you really need a dataURI version of the file, then use reader.readAsDataURL(yourFile) method.
Works for me:
var reader = new FileReader();
reader.onload = function (evt) {
var binary = '';
var bytes = new Uint8Array(reader.result);
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
console.log(btoa(binary))
}
reader.readAsArrayBuffer(file)
If you read the file using the FileReader, the whole file will be loaded into the memory. If you'd like handle large files, this will simply result in your web browser crashing right away. If you are really interested in passing your file as a Base64 String, I recommend you to add file size constraints in order to prevent any potential problems. As a conclusion, none of the methods of the FileReader class would be suitable for this purpose unless and again unless you are dealing with small files not larger than 100MG or so, otherwise you will run into problems.
After playing around here's the solution:
$("#file").change(function () {
var reader = new FileReader();
reader.readAsBinaryString(this.files[0]);
var fileName = this.files[0].name;
var fileType = this.files[0].type;
alert(fileType)
reader.onloadend = function () {
var base64Image = btoa(this.result);
}
}
I used File Reader to generate img tags when there are changes to file input and render thumbnails by passing in the data URLs to the img src. However, when I try to access these img tags later (during another Submit button click), they are always undefined.
After looking up many answers to similar questions, I realise that it's because of the asynchronous nature of the readAsDataURL(file) function. So now, instead of trying to reference the data URLs from the img src, I'm running File Reader again in my submitForm(), hoping to get the callback and process the dataURLs in submitForm(). I can't immediately run the submit after loading my image files either because there are other form details that need to be filled in.
This seems a bit silly to me, not to mention it isn't working :( (probably because of the .onloadend, given that the files are already loaded!). Is there a better way to (1) retrieve the data URLs from my previously loaded img src? or (2) perhaps a totally different approach?
I'm quite new to javascript callbacks and am reading and learning as much as I can from online tutorials and examples and I beg your pardon if my question sounds dumb.
var fileReaderURL = function(callback){
const files = document.getElementById("file-input").files;
var dataURL;
for(var i=0; i<files.length; i++) {
var reader = new FileReader();
if(files[i]){
reader.readAsDataURL(files[i]);
dataURL[i] = reader.result;
}
reader.onloadend = function() {
dataURL[i] = reader.result;
};
}
callback(dataURL);
console.log(dataURL);
};
This is embarrassing, I just managed to retrieve the img data URLs from the loaded files using simple document.getElementsByClassName('thumbnail'). Probably something else I did wrong the previous time round caused the undefined error. Apologies for the question!
I have three failing versions of the following code in a chrome extension, which attempts to intercept a click to a link pointing to a pdf file, fetch that file, convert it to base64, and then log it. But I'm afraid I don't really know anything about binary formats and encodings, so I'm royally sucking this up.
var links = document.getElementsByTagName("a");
function transform(blob) {
return btoa(String.fromCharCode.apply(null, new Uint8Array(blob)));
};
function getlink(link) {
var x = new XMLHttpRequest();
x.open("GET", link, true);
x.responseType = 'blob';
x.onload = function(e) {
console.log("Raw response:");
console.log(x.response);
console.log("Direct transformation:");
console.log(btoa(x.response));
console.log("Mysterious thing I got from SO:");
console.log(transform(x.response));
window.location.href = link;
};
x.onerror = function (e) {
console.error(x.statusText);
};
x.send(null);
};
for (i = 0, len = links.length; i < len; i++) {
var l = links[i]
l.addEventListener("click", function(e) {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
getlink(this.href);
}, false);
};
Version 1 doesn't have the call to x.responseType, or the call to transform. It was my original, naive, implementation. It threw an error: "The string to be encoded contains characters outside of the Latin1 range."
After googling that error, I found this prior SO, which suggests that in parsing an image:
The response type needs to be set to blob. So this code does that.
There's some weird line, I don't know what it does at all: String.fromCharCode.apply(null, new Uint8Array(blob)).
Because I know nothing about binary formats, I guessed, probably stupidly, that making a PDF base64 would be the same as making some random image format base64. So, in fine SO tradition, I copied code that I don't really understand. In stages.
Version 2 of the code just set the response type to blob but didn't try the second transformation. And the code worked, and logged something that looked like a base64 string, but a clearly incorrect string. In its entirety, it logged:
W29iamVjdCBCbG9iXQ==
Which is just goofily wrong. It's obviously too short for a 46k pdf file, and a reference base64 encoding I created with python from the commandline was much much much longer, as one would expect.
Version 3 of the code then also applies the mysterious transformation using stringFromCharCode and all the rest, which I shoved into the transform function.
However, that doesn't log anything at all---a blank line appears in the console in its appropriate place. No errors, no nonsense output, just a blank line.
I know I'm getting the correct file from prior testing. Also, the call to log the raw response object produces Blob {size: 45587, type: "application/pdf"}, which is the correct filesize for the pdf I'm experimenting with, so the blob actually contains what it should when it gets into the browser.
I'm using, and only need to support, a current version of chrome.
Can someone tell me what I'm doing wrong?
Thanks!
If you only need to support modern browsers, you should also be able to use FileReader#readAsDataURL.
That would let you do something like this:
var reader = new FileReader();
reader.addEventListener("load", function () {
console.log(reader.result);
}, false);
// The function accepts Blobs and Files
reader.readAsDataURL(x.response);
This logs a data URI, which will contain your base64 data.
I think I've found my own solution. The response type needs to be arraybuffer not blob.
I have the following file structure:
test.html
test.json
And the following JS function:
function get_file(){
var app_path = app.activeDocument.path,
file = new File(app_path + '/test.json');
console.log(file);
}
How can I make the function log the file's content?
I'm not sure if everything you can do in the browsers environment translates to everything you can do in photoshops environment. But you should look at a few things.
Doing This in the Browser
The File object.
https://developer.mozilla.org/en-US/docs/Web/API/File
Notable that it extends the Blob object.
https://developer.mozilla.org/en-US/docs/Web/API/Blob
Which if you researched you would find it can be read using the FileReader.
https://developer.mozilla.org/en-US/docs/Web/API/FileReader
So this would work in the browser but may/may-not work in the photoshop scripting set.
function get_file(){
var app_path = app.activeDocument.path,
file = new File(app_path + '/test.json');
var reader = new FileReader();
reader.onloadend = function() {
console.log(reader.result);
}
reader.readAsText(file);
}
This is asynchronous so you may need to use a callback depending on what you're trying to do with this. You won't be able to return the string from inside the reader.onloadend event.
Doing This in Photoshop
Take a look at their scripting references. Specifically the javascript reference.
All Resources: http://www.adobe.com/devnet/photoshop/scripting.html
Javascript PDF: http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/photoshop/pdfs/photoshop-cc-javascript-ref-2015.pdf
It looks like they don't have the FileReader but instead the File object can be used to read content. The File API begins on page 109 but it's empty! The documentation is a bit pathetic so I can see why you'd have trouble finding this. With some searching I found someone doing this in 2012 (but I don't know if it will still work- worth a shot)
var b = new File("c:\test.txt");
b.open('r');
var str = "";
while(!b.eof) {
str += b.readln();
}
b.close();
alert(str);
Let me know if that works.
I get the original code from here: Using Javascript FileReader with huge files
But my purpose is different, the author wants to get just a part of the whole but I want them all.
I'm trying modify it with loop, mixed with this technique: slice large file into chunks and upload using ajax and html5 FileReader
All fails, is there anyway I can get what I want.
var getSource = function(file) {
var reader = new FileReader();
reader.onload = function(e) {
if (e.target.readyState == FileReader.DONE) {
process(e.target.result);
}
};
var part = file.slice(0, 1024*1024);
reader.readAsBinaryString(part);
};
function process(data) {
// data processes here
}
Thank you,