How to serve blob and have good filename for all users? - javascript

I have a PDF file as a blob object. I want to serve to my users, and right now I'm doing:
html = '<iframe src="' + URL.createURL(blob) + '">';
That works fine for people that want to use their in-browser PDF tool.
But...some people have their browser set to automatically download PDFs. For those people, the name of the downloaded file is some random string based on the blob URL. That's a bad experience for them.
I know I can also do:
<a href="blobURL" download="some-filename.pdf">
But that's a bad experience for the people who want to use in-browser PDF readers, since it forces them to download the file.
Is there a way to make everybody have good file names and to allow everybody to read the PDF the way they want to (in their browser or in their OS's reader)?
Thanks

At least looking at Google Chrome, if the user disables the PDF Viewer (using the option "Download PDF files instead of automatically opening them in Chrome") then window.navigator.plugins will show neither "Chromium PDF Plugin" nor "Chromium PDF Viewer". If the option is left at the default setting, the viewer will show in the plugin list.
Using this method, one can utilize window.navigator.plugins to check if any of the elements' names are either of the aforementioned plugins. Then, depending upon that result, either display a <iframe> or a <a href="blobUrl" download="file.pdf">. For other browsers I imagine that different methods would have to be used. You can also check for a "Acrobat Reader" plugin, which some machines may have instead, or even just the word "PDF".
On a side note, it does look like it is possible to detect if the default Firefox PDF viewer is enabled by using http://www.pinlady.net/PluginDetect/PDFjs/ .

Try to append &filename=thename.pdf to the binary, metadata or http header:
Content-Disposition: attachment; filename="thename.pdf"

I have looked through the documentation of createObjectURL(blob), it will always return a unique and specific format of url. It is not possible to change the URL here.
The plugin thing is not consistent across browsers.
Now here is my radical idea
Find or create(if not available) a js library that can create and save PDF files to server from blob. (I looked through some of them like 'jsPDF','pdfkit' but none of them use blob)
Save the file to server with a valid name
use the above name in the iframe.

Related

Preview generated docx before downloading [duplicate]

I have successfully done code to display a PDF file in the browser instead of the "Open/Save" dialog. Now, I'm stuck trying to display a Word document in the browser. I want to display a Word document in Firefox, IE7+, Chrome etc.
Can any one help? I am always getting the "Open/Save" dialog while displaying the Word doc in browser. I want to implement this functionality using JavaScript.
No browsers currently have the code necessary to render Word Documents, and as far as I know, there are no client-side libraries that currently exist for rendering them either.
However, if you only need to display the Word Document, but don't need to edit it, you can use Google Documents' Viewer via an <iframe> to display a remotely hosted .doc/.docx.
<iframe src="https://docs.google.com/gview?url=http://remote.url.tld/path/to/document.doc&embedded=true"></iframe>
Solution adapted from "How to display a word document using fancybox".
Example:
JSFiddle
However, if you'd rather have native support, in most, if not all browsers, I'd recommend resaving the .doc/.docx as a PDF file Those can also be independently rendered using PDF.js by Mozilla.
Edit:
Huge thanks to cubeguerrero for posting the Microsoft Office 365 viewer in the comments.
<iframe src='https://view.officeapps.live.com/op/embed.aspx?src=http://remote.url.tld/path/to/document.doc' width='1366px' height='623px' frameborder='0'>This is an embedded <a target='_blank' href='http://office.com'>Microsoft Office</a> document, powered by <a target='_blank' href='http://office.com/webapps'>Office Online</a>.</iframe>
One more important caveat to keep in mind, as pointed out by lightswitch05, is that this will upload your document to a third-party server. If this is unacceptable, then this method of display isn't the proper course of action.
Live Examples:
Google Docs Viewer
Microsoft Office Viewer
The answers by Brandon and fatbotdesigns are both correct, but having implemented the Google docs preview, we found multiple .docx files that couldn't be handled by Google. Switched to the MS Office Online preview and works likes a charm.
My recommendation would be to use the MS Office Preview URL over Google's.
https://view.officeapps.live.com/op/embed.aspx?src=http://remote.url.tld/path/to/document.doc'
There are a few JS libraries that can handle .docx (not .doc) to HTML conversion client-side (in no particular order):
https://github.com/VolodymyrBaydalka/docxjs — works in the browser, docx only, complex layouts might be off, live demo
https://github.com/lalalic/docx2html (npm) — docx to html, most elements are supported, works in browser or nodejs
https://github.com/mwilliamson/mammoth.js — supports headings, lists, tables, endnotes, footnotes, images and text boxes
https://github.com/artburkart/docx2html — apparently, works in the browser
Note: If you are looking for the best way to convert a doc/docx file on the client side, then probably the answer is don't do it. If you really need to do it then do it server-side, i.e. with libreoffice in headless mode, apache-poi (java), pandoc etc.
A great solution if your data is confidential
Since the documents are confidential, they should not be processed on third-party resources.
This solution is open-source:
On the server-side: use Gotenberg to convert word & excel files to PDF.Note: Gotenberg works like a charm, it is based on the LibreOffice engine.
On the frontend: It's very easy to render the PDF file with javascript. (You can use libraries like: pdf.js, react-pdf, etc.)
ViewerJS is helpful to view/embed openoffice format like odt,odp,ods and also pdf.
For embed openoffice/pdf document
<iframe src = "/ViewerJS/#../demo/ohm2013.odp" width='700' height='550' allowfullscreen webkitallowfullscreen></iframe>
/ViewerJS/ is the path of ViewerJS
#../demo/ohm2013 is the path of your file want to embed
I think I have an idea.
This has been doing my nut in too and I'm still having trouble getting it to display in Chrome.
Save document(name.docx) in word as single file webpage (name.mht)
In your html use
<iframe src= "name.mht" width="100%" height="800"> </iframe>
Alter the heights and widths as you see fit.
If you wanted to pre-process your DOCX files, rather than waiting until runtime you could convert them into HTML first by using a file conversion API such as Zamzar. You could use the API to programatically convert from DOCX to HMTL, save the output to your server and then serve that HTML up to your end users.
Conversion is pretty easy:
curl https://api.zamzar.com/v1/jobs \
-u API_KEY: \
-X POST \
-F "source_file=#my.docx" \
-F "target_format=html5"
This would remove any runtime dependencies on Google & Microsoft's services (for example if they were down, or you were rate limited by them).
It also has the benefit that you could extend to other filetypes if you wanted (PPTX, XLS, DOC etc)
Native Documents (in which I have an interest) makes a viewer (and editor) specifically for Word documents (both legacy binary .doc and modern docx formats). It does so without lossy conversion to HTML. Here's how to get started https://github.com/NativeDocuments/nd-WordFileEditor/blob/master/README.md
PDFTron WebViewer supports rendering of Word (and other Office formats) directly in any browser and without any server side dependencies.
To test, try https://www.pdftron.com/webviewer/demo
You can also use some existing API's like GroupDocs.Viewer which can convert your document into image or html and then you will be able to display it in your own application.
Use Libre Office API
Here is an example
libreoffice --headless --convert-to html docx-file-path --outdir html-dir-path

Octet-stream data URI ignoring <a> 'download' attribute

I have a download button on my page that looks like this:
<a download="test.jpg" href="data:application/octet-stream;base64,/9j/4AAQSkZ...">Download</a>
The href attribute is populated by JavaScript, and on my test server it functions exactly as I'd expect it to: it prompts a 'Save As' dialogue box with the filename "test.jpg".
However, when I use the exact same code on a different, live server, the filename is dropped.
In Chrome it saves as 'download', without a file extension
In Firefox it saves as a seemingly random string, again without a file extension
Any ideas what could be causing this difference in behaviour across the two servers?
This is a security measure applies when saving off-site downloads. since the prototcols don't match (data vs http), it's considered a different site, and a default names gets applies. Use URL.createObjectURL instead of base64 to feed the download's href. you can get a dataURL to Blob routine in my downlod.js library, then feed the Blob to createObjectURL().

Is It Possibly to Access Firefox Save As Command Using JS?

I'm trying to figure out how to call the File Save As Command in Firefox
(the one you get when you right click an image and save it) to save an image using JS (or if there is something else I can use, I would be grateful if you pointed me in that direction). I am looking for an example of how to open the Save As menu and pre-fill the file name field ... I've been searching furiously and have come up with zip. In my search I saw that you cannot directly save a file to disk, but is it impossible to call the save as function? Any suggestions would be greatly appreciated!
Edit:
I'm not looking to make this code available to everyone, and the java script is client side, I'm just writing a small script to make saving photos a little easier in terms of naming them.
-Will
No you can't do this, and really you are trying to find a solution in a way that does not embrace the internet and the way people interact with content. What you are trying to do is call on Operating System operation from Javascript. If there were anyway this would be possible, I don't think it is at all, it would be a very poor solution. Think about all the different Operating Systems Firefox is being used on. If you found a solution for Windows 7, what about an Apple Mac running Firefox?
What you should consider is that a User decides whether to Save something to their computer, not the programmer of the application. Provide a link to the file, most users know how to right click a link and select Save As. Add help tip explaining what to do as well.
To give a File a specific name or even start an automatic download when a User clicks or takes some kind of action, you can create a response from your server that is a PDF,Excel,Jpeg,Doc,Docx or many other files types. The server can load the file in memory and sent it as a response with the proper header information in the response.
For example to set a specific name for the file when the user downloads you can set your Response header with something like:
header('Content-Disposition: attachment; filename="downloaded.pdf"');
You can use the anchor element's download attribute to specify that a link is to be downloaded. Note that this is not implemented in all browsers, Chrome, Firefox, and Opera currently support it
https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
HTMLAnchorElement.download
Is a DOMString indicating that the linked
resource is intended to be downloaded rather than displayed in the
browser. The value represent the proposed name of the file. If the
name is not a valid filename of the underlying OS, browser will adapt
it. The value is a URL with a scheme like http:, file:, data: or even
blob: (created with URL.createObjectURL).
Demo
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.fillRect(25,25,100,100);
ctx.clearRect(45,45,60,60);
ctx.strokeRect(50,50,50,50);
var link = document.getElementById("link");
//Set href to the data url that you want downloaded
link.href = "http://placehold.it/350x350";
//set download to the default filename you want to use
link.download = "image.png";
<canvas id="canvas" width="150" height="150"></canvas>
Click to download
You can also specify a regular url to a file, but note that if the server sends a filename header: Content-Disposition ... filename... that it will overwrite whatever you have in the download attribute.

Get binary image data from input type "file" using JavaScript/jQuery for use with picture preview with AJAX in WebMatrix [duplicate]

This question already has answers here:
Closed 10 years ago.
I have had trouble when researching or otherwise trying to figure out how (if it's even possible) to get binary image data using JavaScript/jQuery from an html input element of type file.
I'm using WebMatrix (C#), but it may not be necessary to know that, if the purposes of this question can be answered using JavaScript/jQuery alone.
I can take the image, save it in the database (as binary data), then later show the pic on the page, from the binary data, after posting. This does, however, leave me without a pic preview, before uploading, for which I am almost certain I must use AJAX.
Again, this may not even be possible, but as long as I can get the binary image data, I believe I can push it to the server with AJAX and process the image the same way I would if I were taking it from a database (note that I don't save the image files themselves using GUID and all that,I just save the binary data).
If there is an easier way to show a pic preview using the input element, that would work fine, too, of course, as the whole idea behind me trying to do this is to show a pic preview before they hit the submit form button (or at least create that illusion).
**********UPDATE***********
I do not consider this a duplicate of another question because, my real question is:
How can I get image data from an input type "file", with JavaScript/jQuery?
If I can just get the data (in the right format) back to the server, I should be able to work with it there, and then return it with AJAX (although, I am absolutely no AJAX expert).
There is, according to the research that I have done, NO WAY to get picture previews in all IE versions using only javascript (this is because getting the full file path is seen, by them, as a potential security risk). I could ask my users to add the site to the trusted sites, but you don't usually ask users to tamper with those kinds of settings (not to mention the quickest way to make your site seem suspicious to users is to ask them to directly add your site to the trusted sites list. That's like sending an email and asking for a password. "Just trust me! I'm soooo safe!" :)
Short answer: Use the jQuery form plugin, it suports AJAX-like form submits even for file uploads.
tl;dr
Thumbnail preview is popular websites is usually done by a number of steps, basically the website do these steps:
upload the RAW image
Resize and optimise the image for data storage
Generate a temporary link to that file (usually stored in a server maintained HTTP session)
Send it back to the user, to enable a 'preview'
Actually store the image after user confirms the image
A few bad solutions are:
Most of the modern browsers has options to enable script access to local files, but usually you don't ask your users to tinker with those low level settings.
Earlier Internet Explorer (ah... yes it's a shame) and ancient versions of modern browsers will expose the full file path by reading the 'value' of file input box, which you can directly generates an tag and use that value. (Now it is replaced by some c:/fakepath/... thing.)
Use Adobe Flash to mimic the file selection panel, it can properly read local files. But passing it into JavaScript is another topic...
Hope these helps. ;)
UPDATE
I actually came across a situation that requires a preview before uploading, I'd like to also put it here. As I could recall, there were no transitional versions in modern browsers that do not implement FileReader before masking the real file path, but feel free to correct me if so. This solution should caters most of the browsers, as long as they are supported by jQuery.
// 1. Listen to change event
$(':file').change(function() {
// 2. Check if it has the FileReader class
if (!this.files) {
// 2.1. Old enough to assume a real path
setPreview(this.value);
}
else {
// 2.2. Read the file content.
var reader = new FileReader();
reader.onload = function() {
setPreview(reader.result);
};
reader.readAsDataURL();
}
});
function setPreview(url) {
// Do preview things.
$('.preview').attr('src', url);
}

Saving file from JavaScript string without hitting server

If I have an in-memory string in JavaScript that is let's say Excel or PDF format, and I want to pop open a save dialog so the user can save those bytes to a file, how would I go about doing this? I am trying to avoid going back to the server. If I was going back to the server I could send the correct HTTP headers in the response to tell the browser that I'm sending a file. But I want to do this from JavaScript instead because I already have the bytes I need on the client.
Is this possible?
Edit:
I should clarify what I'm actually looking for here. I am working with a Silverlight app. From Silverlight, I can pop up a save dialog and save the bytes (in this case, let's say they are Excel bytes). This seems to be what people are suggesting below when they suggest using Flash. Silverlight gives the same functionality.
But, I would prefer the the Excel file just opens in a new browser window. I could do that pretty easily if I was generating the file on the server, because I could just send the correct headers. But I already have the bytes in Silverlight on the client. Any way to open that doc in a new browser window so the user can just hit an Open button without having to pick a save location and navigate to the file?
And I can't use the out-of-browser application option. I know it would be possible using that by talking with Excel through COM-interop. But that's a no go in this case.
But I can interop with JavaScript from Silverlight. So I was hoping I could use JavaScript in some way to open a browser window and stream the Excel bytes to it.
You can use data URIs to embed the file in the HTML document; e.g., http://jsfiddle.net/dqWae/ creates a link that initiates a download of the Wikipedia title image. (The MIME type is hard coded as application/octet-stream but you can of course specify it as PDF or XLS).
You will need to encode the bytes of the file as base 64 and create a data URI for the resource. Then, create a new anchor element whose href attribute is the data URI. If you want to automatically initiate the download, programmatically issue a click event to the anchor element.
In JavaScript? I hope not, think of all the millions of security implications that would cause..
In pure javascript this will be possible only with html5 but not for now.
but you can do some javascript/flash 10 bridge, you pass the bytes to Flash who open the "save as" dialog and then you can save 100% client side.
The flash can be loaded dynamically.
see some code here : http://sujitreddyg.wordpress.com/2008/11/04/filereference-in-flash-player-10/
There are one non cross-browser solution (works only in Firefox, and only when user grant permissions).
// ask for security grants
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var pngBinary = 'some string';
var aFile = Components.classes["#mozilla.org/file/local;1"].
createInstance(Components.interfaces.nsILocalFile);
aFile.initWithPath( "/tmp/somefile.png" );
aFile.createUnique( Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 600);
var stream = Components.classes["#mozilla.org/network/safe-file-output-stream;1"].
createInstance(Components.interfaces.nsIFileOutputStream);
stream.init(aFile, 0x04 | 0x08 | 0x20, 0600, 0);
stream.write(pngBinary, pngBinary.length);
if (stream instanceof Components.interfaces.nsISafeOutputStream) {
stream.finish();
} else {
stream.close();
}
But I recommend you to make cross-browser applications and choose Flash solution.

Categories

Resources