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.
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?
Watilin's answer was not added, so here is the working snippet copied from Codepen:
function onUpload(input) {
let originalFile = input.files[0];
let reader = new FileReader();
reader.readAsDataURL(originalFile);
reader.onload = () => {
let json = JSON.stringify({ dataURL: reader.result });
// View the file
let fileURL = JSON.parse(json).dataURL;
$("#display-pdf").empty();
$("#display-pdf").append(`<object data="${fileURL}"
type="application/pdf" width="400px" height="200px">
</object>`);
// View the original file
let originalFileURL = URL.createObjectURL(originalFile);
$("#display-pdf").append(`<object data="${originalFileURL}"
type="application/pdf" width="400px" height="200px">
</object>`)
.onload(() => {
URL.revokeObjectURL(originalFileURL);
});
};
}
HTML:
<input id="file-input" type="file" onchange="onUpload(this)" />
<div id="display-pdf"></div>