Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FileReader losing data when reading PDF

I have the constraint of sending data to a server in JSON format only, and I need to send a PDF file together with other form data in the JSON. I though I could make a string from it with base64 like in this solution I found on SO:

let data = {foo: 1, bar: 2};
let reader = new FileReader();
reader.readAsDataURL(pdf);
reader.onload = () => {
  data.file = reader.result;
  $.ajax({type: 'POST', dataType: "json", data: JSON.stringify(data), ...});
}

But it happened that reader.result does not contain the whole PDF (whether I save it to file instead of sending, or get it back from the server). In a text editor the content is the same, but a binary editor says that some bytes are missing. My browser can load it as a pdf and the title shows, but the page is blank.

I also tried reader.readAsBinaryString and transform to base64 myself with btoa, but same result.

Edit: CodePen example: https://codepen.io/jdelafon/pen/eRWLdz?editors=1011

Edit: to verify, I did this:

let reader = new FileReader();
reader.readAsBinaryString(pdf);
reader.onload = () => {
    let blob = reader.result;
    let file = new Blob([blob], {type: 'application/pdf'});
    let fileURL = window.URL.createObjectURL(file);
    // make it display in <embed>
};

The body of the pdf is empty. If I replace file by the original pdf, it gets displayed entirely. So FileReader loses data in the process.

It knows the title and number of pages, but the body of each page is empty

Is there a better way? Is it an encoding issue with FileReader?

I also though about using FormData like this:

let data = {foo: 1, bar: 2};
let fd = new FormData();
fd.append('file', pdf);
data.file = btoa(fd);
$.ajax({type: 'POST', dataType: "json", data: JSON.stringify(data), ...});

But now when I fetch the data back from the server, JS has no idea that it represents a FormData object, so I don't know how to get the file back for display in a browser. Is it possible?

like image 259
JulienD Avatar asked Jun 21 '17 00:06

JulienD


People also ask

What does FileReader result return?

The FileReader result property returns the file's contents. This property is only valid after the read operation is complete, and the format of the data depends on which of the methods was used to initiate the read operation.


1 Answers

You weren’t far from succeeding when you tried btoa, except you can’t “btoa-ize” a FormData.

reader.readAsBinaryString(pdf); // don’t use this! See edit below
reader.onload = () => {
  let b64payload = btoa(reader.result);
  $.ajax({
    type: 'POST',
    dataType: "json",
    data: JSON.stringify({ "file": b64payload }),
  });
}

I’m not sure why the readAsDataURL solution failed though.


Edit: although not sure, it’s been suspected that the deprecated readAsBinaryString method might be the source of the problem. The following solution, based on readAsDataURL, is working:

reader.readAsDataURL(pdf);
reader.onload = () => {
  $.ajax({
    type: 'POST',
    dataType: "json",
    data: JSON.stringify({ "dataURL": reader.result }),
  });
};
like image 158
Watilin Avatar answered Oct 21 '22 20:10

Watilin