JavaScript PDF File Download from SQL FileTable - javascript

I am working with Blazor Server in a .NET6 application, which obviously is not super JavaScript friendly. However, it appears to me that the easiest way to download a PDF is through JavaScript, so I'm using an interop to make it happen.
My PDF files are stored in a FileTable on SQL. I can pull the data quite easily into my C# code. I am also storing JPG, PNG, TXT files, etc, on the file table and these are all downloadable using the following code in my interop.
async (fileName, contentStreamReference) => {
const arrayBuffer = await contentStreamReference.arrayBuffer();
const blob = new Blob([arrayBuffer], {type: 'application/pdf'});
const url = URL.createObjectURL(blob);
const anchorElement = document.createElement('a');
anchorElement.href = url;
anchorElement.download = fileName ?? '';
anchorElement.click();
anchorElement.remove();
URL.revokeObjectURL(url);
};
Passed into my interop: The string value of the name of my PDF file, and a MemoryStream of the byte array stored in the SQL FileTable.
All file downloading works fine, regardless of the type that I set on my Blob. Downloading of the PDF seems like it works from the outside, since the download occurs without incident and the file size is identical, but opening the file results in an error. I suspect that it has something to do with header information, but I'm not entirely sure and nothing I'm finding is helping here.
The above code was found in other StackOverflow answers, and like I said, works quite nicely for everything that is not a PDF. Is there an easy solution here, or do I need to look elsewhere?
I have tried tweaking the code to do a few different things based on different answers I find, and nothing has helped make the PDF actually work, although the downloading of other files is surprisingly resilient to change.

Related

How do I let user save a file and keep editing that file in browser Javascript only?

I believe it would not be possible due to security reason as stated in many other articles on StackOverflow. However, when I use the Diagram app at https://app.diagrams.net/ I realized they could ask me to save a file, and somehow keep that file reference and whenever I click Save on the app, my local file on hard drive changes (no new download).
I know it's only possible to upload/download a file and believe you cannot edit it (using Blob with FileReader etc). How do they achieve that? The app is open source but unfortunately plowing through the source code of their File Handler I still cannot find out what API they are using. I don't remember installing any plugin or app in my browser.
I also notice there is this permission in my browser so I guess it's some standard API, but even using that as keyword, all leads back to StackOverflow articles saying it's not possible.
Is it a new API I am not aware of? What am I looking for?
You can use localStorage to achieve this without needing any other permission from the user.
localStorage.setItem("data", JSON.stringify(data));
If your data is just JSON then this would work, however if you have custom data types, you can take a look here.
Edit:
Since you wanted to save the file directly to the device and edit it, you can take a look at File System Access API. This article here explains it.
You can load the file first by using,
let fileHandle;
butOpenFile.addEventListener('click', async () => {
[fileHandle] = await window.showOpenFilePicker();
const file = await fileHandle.getFile();
const contents = await file.text();
textArea.value = contents;
});
Once you have the file handle you should be able to write to the file without requesting to download a new file everytime there is a change.
async function writeFile(fileHandle, contents) {
// Create a FileSystemWritableFileStream to write to.
const writable = await fileHandle.createWritable();
// Write the contents of the file to the stream.
await writable.write(contents);
// Close the file and write the contents to disk.
await writable.close();
}
The codes are from the article I have linked above and the article explains everything much clearly. It's worth reading.

display a video file after decryption in node js using crypto js

i am using electron and node js and trying to decrypt an encrypted file using crypto js, but i don't want to save it on user's local hard drive, i want to display it on video tag as i am reading it, meaning i don't want to use fs.createWriteStream after decryption, here is what i tried:
const decipher = crypto.createDecipher('des-ecb', 'a password');
const decInput = fs.createReadStream("encrypted video");
var file = decInput.pipe(decipher);
var file2 = fs.createReadStream(file);
is such thing is even possible? if i want to display the video i must have its url for source of video tag, but i can't make an URL for that file, and i cant even read it because it says object is passed to the fs.createReadStream and it says param must be string(path) or buffer or etc...
NOTE: the encryption and decryption works just fine so i ignored the rest of the code...
Similar question might already suit your needs. You already have the stream ready, let frontend reads it so that video is stored in the browser.

Creating a pdf file from mpdf string output?

I'm using mPDF server side to create a pdf file. It works okay if I output the file to the server, however, I would like to return a string back to the client and build a pdf file from it which I can then use like any normal file from a file input.
server side, the (simplified) code is
$output_dest = 'S';
$content = $mpdf->Output($post_data->fileName, $output_dest);
//$mpdf->Output($post_data->fileName, 'F'); //just to check that the output should be correct
$response->setContent($content);
and client side i've tried using Blobs to create a file
var fileObj = new Blob([offerString], {type : 'application/pdf'});
but there are 2 problems. First, the blob, when sent to the server, doesn't have the required name. Secondly, the pdf file created (using window.saveAs to save the blob) is blank. It has the correct number of pages and author information, but it's completely blank.
If I use mPDF's file output, the resulting file is correct, so the problem must lie somewhere within the string->blob process.
Edit: The solution is to create the Blob not straight from the string but from an arrayBuffer. I've created the arrayBuffer using the solution suggested in another answer here

encoding WAV data in Javascript

I am generating WAV data using JavaScript, and I'm able to generate the data and store it in a variable waveFileOutput, then send it to an embedded player by setting the source to following dataURI I set up:
var dataURI = "data:audio/wav;base64," + escape(btoa(waveFileOutput));
I'm also able to get the file to (sort of) "save" by opening a window using the same data after encoding it and saving the window as a file. The problem is that the data is not properly encoded as a WAV file in the new window, even though the embedded play is fine with the encoding. I need to figure out the correct way to encode it. Here are a couple of things I've tried (but neither works):
Try #1: window.open("data:application/octet-stream," +
encodeURIComponent(waveFileOutput));
Try #2: window.open("data:application/octet-stream," +
escape(btoa(waveFileOutput)));
I can post the whole (working) file if that helps, but seemed like it might be a waste of space.
Suggestions for how to get the data encoded properly when "saving" it using this approach?

Chrome extension: How to save a file on disk

I'm currently creating an extension for google chrome which can save all images or links to images on the harddrive.
The problem is I don't know how to save file on disk with JS or with Google Chrome Extension API.
Have you got an idea ?
You can use HTML5 FileSystem features to write to disk using the Download API. That is the only way to download files to disk and it is limited.
You could take a look at NPAPI plugin. Another way to do what you need is simply send a request to an external website via XHR POST and then another GET request to retrieve the file back which will appear as a save file dialog.
For example, for my browser extension My Hangouts I created a utility to download a photo from HTML5 Canvas directly to disk. You can take a look at the code here capture_gallery_downloader.js the code that does that is:
var url = window.webkitURL || window.URL || window.mozURL || window.msURL;
var a = document.createElement('a');
a.download = 'MyHangouts-MomentCapture.jpg';
a.href = url.createObjectURL(dataURIToBlob(data.active, 'jpg'));
a.textContent = 'Click here to download!';
a.dataset.downloadurl = ['jpg', a.download, a.href].join(':');
If you would like the implementation of converting a URI to a Blob in HTML5 here is how I did it:
/**
* Converts the Data Image URI to a Blob.
*
* #param {string} dataURI base64 data image URI.
* #param {string} mimetype the image mimetype.
*/
var dataURIToBlob = function(dataURI, mimetype) {
var BASE64_MARKER = ';base64,';
var base64Index = dataURI.indexOf(BASE64_MARKER) + BASE64_MARKER.length;
var base64 = dataURI.substring(base64Index);
var raw = window.atob(base64);
var rawLength = raw.length;
var uInt8Array = new Uint8Array(rawLength);
for (var i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
var bb = new this.BlobBuilder();
bb.append(uInt8Array.buffer);
return bb.getBlob(mimetype);
};
Then after the user clicks on the download button, it will use the "download" HTML5 File API to download the blob URI into a file.
I had long been wishing to make a chrome extension for myself to batch download images. Yet every time I got frustrated because the only seemingly applicable option is NPAPI, which both chrome and firefox seem to have not desire in supporting any longer.
I suggest those who still wanted to implement 'save-file-on-disk' functionality to have a look at this Stackoverflow post, the comment below this post help me a lot.
Now since chrome 31+, the chrome.downloads API became stable. We can use it to programmatically download file. If the user didn't set the ask me before every download advance option in chrome setting, we can save file without prompting user to confirm!
Here is what I use (at extension's background page):
// remember to add "permissions": ["downloads"] to manifest.json
// this snippet is inside a onMessage() listener function
var imgurl = "https://www.google.com.hk/images/srpr/logo11w.png";
chrome.downloads.download({url:imgurl},function(downloadId){
console.log("download begin, the downId is:" + downloadId);
});
Though it's a pity that chrome still doesn't provide an Event when the download completes.chrome.downloads.download's callback function is called when the download begin successfully (not on completed)
The Official documentation about chrome.downloadsis here.
It's not my original idea about the solution, but I posted here hoping that it may be of some use to someone.
There's no way that I know of to silently save files to the user's drive, which is what it seems like you're hoping to do. I think you can ASK for files to be saved one at a time (prompting the user each time) using something like:
function saveAsMe (filename)
{
document.execCommand('SaveAs',null,filename)
}
If you wanted to only prompt the user once, you could grab all the images silently, zip them up in a bundle, then have the user download that. This might mean doing XmlHttpRequest on all the files, zipping them in Javascript, UPLOADING them to a staging area, and then asking the user if they would like to download the zip file. Sounds absurd, I know.
There are local storage options in the browser, but they are only for the developer's use, within the sandbox, as far as I know. (e.g. Gmail offline caching.) See recent announcements from Google like this one.
Google Webstore
Github
I made an extension that does something like this, if anyone here is still interested.
It uses an XMLHTTPRequest to grab the object, which in this case is presumed to be an image, then makes an ObjectURL to it, a link to that ObjectUrl, and clicks on the imaginary link.
Consider using the HTML5 FileSystem features that make writing to files possible using Javascript.
Looks like reading and writing files from browsers has become possible. Some newer Chromium based browsers can use the "Native File System API". This 2020 blog post shows code examples of reading from and writing to the local file system with JavaScript.
https://blog.merzlabs.com/posts/native-file-system/
This link shows which browsers support the Native File System API.
https://caniuse.com/native-filesystem-api
Since Javascript hitch-hikes to your computer with webpages from just about anywhere, it would be dangerous to give it the ability to write to your disk.
It's not allowed. Are you thinking that the Chrome extension will require user interaction? Otherwise it might fall into the same category.

Categories