PDF is corrupted after reconstructing it using URL.createObjectURL - javascript

I'm trying to pass a PDF file from the server and display it inside the browser, but the output comes out corrupted.
var blob = atob(data.Package);
console.log(blob);
var file = new Blob([blob], { type: "application/pdf" });
const fileURL = URL.createObjectURL(file);
window.open(fileURL);
Console log outputs something that appears to be correct PDF (just the beginning of output):
I'm saving a copy of the PDF on the server before transfer to make sure it is not corrupt and it works.
URL constructed with URL.createObjectURL(file) seems to be short:
blob:http://localhost:61631/ad749684-2992-4311-8b17-f382a7c687be
server side code:
Object doc = Convert.ToBase64String(_Document.DocumentStream.ToArray());
JObject response = new JObject(new JProperty("Package", JObject.FromObject(doc)));
return new AspResponse<Object>(response);

It looks like the issue is because you need to convert the PDF data into an actual byte array, then pass that into the Blob constructor. Try this:
function convertToByteArray(input) {
var sliceSize = 512;
var bytes = [];
for (var offset = 0; offset < input.length; offset += sliceSize) {
var slice = input.slice(offset, offset + sliceSize);
var byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
bytes.push(byteArray);
}
return bytes;
}
var blob = atob(data.Package);
console.log(blob);
var file = new Blob(convertToByteArray(blob), { type: "application/pdf" });
const fileURL = URL.createObjectURL(file);
window.open(fileURL);

This solution worked for me, basically generating the pdf as a base64 string in the backend and rendering the content in an anchor tag for downloading the pdf file.
https://kainikhil.medium.com/nodejs-how-to-generate-and-properly-serve-pdf-6835737d118e

Related

Sending Javascript POST XMLHttpRequest File Contents in Hex

I'm trying to upload a static file from within my JS code. I have a .tgz file that I want to send as POST parameter. I've dumped my file to a hex string fileDatalike:
var file = "\xff\x01\x08 .....
I want to send as the body content of a multi form post data. It seems like when I try to just .send(file) the hex values become mangled and the file is corrupted.
JS looks something like this:
var url = "/index/upload/"
var fileData = '\xF1\x08\x00\x00........\x00\x00';
//whole file binary content in hex)
boundary = "----------3333338220322",
xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "multipart/form-data, boundary="+boundary);
var body = "--" + boundary + "\r\n";
body += 'Content-Disposition: form-data; name="newFile"; filename="filename.tgz"\r\n';
body += "Content-Type: application/x-gzip\r\n\r\n";
body += fileData + "\r\n";
body += "--" + boundary + "--";
xhr.send(body);
Not sure what goes wrong. The request seems to look exactly like if I manually upload the file, but the binary data seems different when observing through a proxy. Is there a better way to send files if i need to have its whole content in the JS code itself?
Figured out a wait to make it work. Using base64 to encode the file instead of hex.
var b64data = 'H4sIAHegu.....';
const b64toBlob = (b64Data, contentType='', sliceSize=512) => {
const byteCharacters = atob(b64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob = new Blob(byteArrays, {type: contentType});
return blob;
}
const contentType = 'application/x-gzip';
const blob = b64toBlob(b64data, contentType);
Then used this blob as the file content.
Solution found from here:
Convert base64 png data to javascript file objects
offsec/awae ;)

apply stylesheet to html file that was generating using atob

I generated html file from base64 format using javascript after that i'm open that file in new tab , and i did that with succes , now i would like to apply stylesheet on my file.
here is my code to generate and open the file :
//s_utf8String is result of the content that i use to generate the file.
var binary = atob(a.s_utf8String.replace(/\s/g, ''));
var len = binary.length;
var buffer = new ArrayBuffer(len);
var view = new Uint8Array(buffer);
for (var i = 0; i < len; i++)
{
view[i] = binary.charCodeAt(i);
}
var blob = new Blob([view], {type: "application"});
var url = URL.createObjectURL(blob);
window.open(url);
Any one have an idea how i can add the stylesheet

How to generate PDF in React js using byte data

I am getting the response from rest api as:
<Response>
<PDFContent>SlZCRVJpMHhMalFLSmVMano5TUtNU0F3SUc5aWFnbzhQQzlUTDBwaGRtRlRZM0pwY0hRdlNsTW9kR2hwY3k1NmIyOXRJRDBnTVRBd095aytQZ3BsYm1Sdlltb0tOU0F3SUc5aWFnbzhQQzlEYjJ4dmNsTndZV05sTDBSbGRtbGpaVWR5WVhrdlUzVmlkSGx3WlM5SmJXRm5aUzlJWldsbmFIUWdNVFV3TDBacGJIUmxjaTlHYkdGMFpVUmxZMjlrWlM5VWVYQmxMMWhQWW1wbFkzUXZWMmxrZEdnZ056Y3lMMHhsYm1kMGFDQTNNek0zTDBKcGRITlV3cjFTdkgvd0JvNy9rbm1uLzloV1AvQU5GUzBBZUFmOEozNHcvNkd2WFAvQmpOL3dERlVmOEFDZCtNUCtocXhycFg5L2V5ZlRZRURvYTRmdUNBNWNDQjFVSjJEd005cWwyZE9LbzlOSDVhVXdkdjVTVFRYbkMwVWVZbnlyVE5N6bnRLaXRSWHV1REUxUHNSL2lGQ2FpdGhvTUlacGQ0NmxMU0d3aVdZSkZoVVVaRm5KbnN5NHpPWE9BZS94ZDEIyOTBJREl6SURBZ1VpOVRhWHBsSURJMVBqNEtjM1JoY25SNGNtVm1DakUzT1RjMU5Rb2xKVVZQUmdvPQ==</PDFContent>
<Success>True</Success>
</Response>
How to get the response inside and generate pdf using React js
you can simply add in object tab in reactjs
<div>
<object
style={{width: '100%', height: '200pt'}}
type="application/pdf"
data={'data:application/pdf;base64,'+base64data}></object>
</div>
I am assuming the bytes within <PDFContent> tag are base64 encoded bytes of the PDF file. If this is incorrect, you need to update your REST API to perform base64 encoding on the PDF bytes first. You can't have your server send raw PDF bytes to the web client as is.
In the javascript, once you have received the base64 encoded PDF bytes, you can generate the PDF in two steps:
Convert the base64 encoded bytes to a PDF BLOB.
Create a file URL out of this BLOB and open the URL.
Here's a sample JavaScript code for the same:
<script>
function displayPDF() {
//The PDFContent bytes are mapped to an input element called pdfString
if($('#pdfString').val() == '')
return;
var file = b64toBlob($('#pdfString').val(), 'application/pdf');
//If the browser is IE or Edge
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(file);
}
else {
var fileURL = URL.createObjectURL(file);
window.open(fileURL);
}
}
function b64toBlob(b64Data, contentType, sliceSize) {
contentType = contentType || '';
sliceSize = sliceSize || 512;
var byteCharacters = atob(b64Data);
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;
}
</script>

Generating a File from a base64 string

I'm using a webservice to get a base64 string and I need to show that document to the user as a PDF.
var charactersArray = atob(base64String);
var byteNumbers = new ArrayBuffer(charactersArray.length);
for (var i = 0; i < charactersArray.length; i++) {
byteNumbers[i] = charactersArray.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
var file = new File([byteArray], "file.pdf", {
type: "application/pdf",
});
I'm then using this "file" to create a url with
var url = URL.createObjectURL(file);
I'm opening this url in a button with the ng-click directive, but I'm getting loading the PDF.
You need to write the character codes to the byteArray rather than the ArrayBuffer
var charactersArray = atob(base64String);
var len = charactersArray.length;
var byteNumbers = new ArrayBuffer(len);
var byteArray = new Uint8Array(byteNumbers);
for (var i = 0; i < len; i++) {
byteArray[i] = charactersArray.charCodeAt(i);
}
var file = new File([byteArray], "file.pdf", {
type: "application/pdf",
});
I recently work on a project like this and had the same issue. I used the base64-arraybuffer NPM library to convert a base64 string to a byte array.
It's a JS library so it needs to be imported like this after it's installed:
import * as buffer from 'base64-arraybuffer';
The object URL is created like this:
var byteArray = buffer.decode(base64String);
var file = new Blob([byteArray], {type: 'application/pdf'});
var pdfUrl = URL.createObjectURL(file);
I hope this helps!

How can I save a JPEG from a URL to a file in angularjs(ionic)?

I have got base64data from ng-src, but I can't make a jpeg file with this base64data. I have ever been trying as follow:
First I have removed the data:image/jpeg:base64, chunk from data:image/jpeg:base64,/9/DEefesdfae453/sdDFEYEUdfdief8fe ... and write this data with test.jpg file by use of $cordovaFile. Here is my code:
var base64Image = angular.element(document.querySelectorAll('#my-photo')).attr('src');
var writeData = base64Image.replace(/data:image\/jpeg;base64,/g, '');
alert(writeData);
// Writing filtered image -----------------------------------------------------------------
$cordovaFile.writeFile(ROOT_DIR + PM_DATA_DIR_NAME + '/', $scope.photo.name, writeData, true)
.then(function (success) {
// success
$ionicLoading.hide();
$ionicPopup.alert({
template : "Updated Photo!!"
});
}, function (error) {
// error
$ionicLoading.hide();
$ionicPopup.alert({
template : "Failed to update Photo!!"
});
});
But I can't show the file as image file. It is showing only black screen. (original file size : 19K ---> result file size : 66K)
What's wrong?
Please help me.
Thank you everybody to help.
FileWriter’s write method does not take a base64 string. According to the docs (http://docs.phonegap.com/en/edge/cordova_file_file.md.html#FileWriter) text will be encoded as UTF-8 before being written. So your base64 string is being encoded before writing to the file so it’s not valid image data. You have to pass your image data as a Blob or an ArrayBuffer. Note this only works on iOS and Android. Have a look at Jeremy Banks’ b64toBlob function in this answer: https://stackoverflow.com/a/16245768
function b64toBlob(b64Data, contentType, sliceSize) {
contentType = contentType || '';
sliceSize = sliceSize || 512;
var byteCharacters = atob(b64Data);
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;
}
You can pass the resulting blob into the write method.

Categories

Resources