1

The user needs to be able to upload a bunch of images which my app will merge into a single PDF. Then the user needs to be able to save that PDF to their local machine. My Blazor C# application uses <InputFile...> to prompt the user to select one or more images from their local machine. The app then creates the PDF file and adds the images to it. I need a way for the user to specify where they want to save the PDF. Or, failing that, I need a way to save it to a pre-determined folder (the application folder or whatever) and a fixed name (such as mergedImages.pdf) and then open the saved file in a browser window from which the user can download it to wherever they want.

I've tried adding a button with an href that points to the downloaded file, but the browser always blocks the link, returning the error: "Not allowed to load local resource: file:///D:/IVG_Blazor/MergeImagesIntoPDF/mergedImages.pdf".

Another way I thought of was to have it write the PDF to the downloads folder and display an icon at the bottom of the page that gives the user the options "Open", "Always open files of this type", "Show in folder", "Cancel". But I don't know how to implement that.

Does anyone know how to give the user easy access to such a file? Thanks.

Tim
  • 185
  • 1
  • 3
  • 15
  • blazor wasm or server? – pm100 Mar 21 '22 at 00:50
  • "from the local machine." do you mean the web server or the browser hosting the web page? – pm100 Mar 21 '22 at 00:51
  • 1
    You can keep the pdf in memory until the user wishes to "download" it. But you can't read some random file from the user's pc without a file upload. That's not a blazor restriction, it's a browser restriction. Unless you go the electron route and host the web browser in a program you control. – Jeremy Lakeman Mar 21 '22 at 00:58
  • If you want to be able to push files to some place on the users machine, on some schedule that the server dictates, you're probably best looking at creating an app like Dropbox that the user runs, it connects and receives/writes files when the server hs them ready – Caius Jard Mar 21 '22 at 07:57
  • By "from the local machine", I mean the browser. The user will upload a bunch of photos that they took and the app will merge them into a PDF, which the user needs to be able to save to their machine. – Tim Mar 21 '22 at 13:29
  • 1
    What you want to do is not impossible. For example, see this Blazor File Manager from Syncfusion: https://www.syncfusion.com/blazor-components/blazor-file-manager However, the more standard way to handle this would be to simply have a button that the user clicks when they are finished uploading images. And the button would trigger the generation of the PDF and start the file download. – Yogi Mar 21 '22 at 20:16
  • Thanks for that Syncfusion link. Obviously, there's some way to do it. I don't know how though, short of buying their product. – Tim Mar 21 '22 at 21:25

2 Answers2

2

As I understand, you are able to get the result of the merge operation, I assume it is a Stream or a byte array. And you want the user to be able to download it, and the user should be able to save it in a specific folder.

It seems that the second point is not possible, according to this post : Download A File At Different Location Using HTML5

For the first point, the user be able to download the merged PDF File, all to do is to have the Stream (or byte array), and to have a javascript function to do so.

C# :

private async Task DownloadFileFromStream(Stream fileStream, string fileName)
{
    using var streamRef = new DotNetStreamReference(stream: fileStream);
    await jsRuntime.InvokeVoidAsync("downloadFileFromStream", fileName, streamRef);
}

Javascript :

async function downloadFileFromStream(fileName, contentStreamReference) {
    const arrayBuffer = await contentStreamReference.arrayBuffer();
    const blob = new Blob([arrayBuffer]);
    const url = URL.createObjectURL(blob);

    triggerFileDownload(fileName, url);

    URL.revokeObjectURL(url);
}

function triggerFileDownload(fileName, url) {
    const anchorElement = document.createElement('a');
    anchorElement.href = url;
    anchorElement.download = fileName ?? '';
    anchorElement.click();
    anchorElement.remove();
}

It will trigger the download procedure of the browser.

Good luck :)

Dylan El Bar
  • 783
  • 1
  • 14
0

I came across your question when I was trying to solve my problem. I wanted to bring up a window to save a file in which the user could select a folder. Before that, the system automatically saved to the Downloads folder.

As I understood, there was no such possibility before, but now it is possible thanks to filesystem api: https://web.dev/file-system-access/#ask-the-user-to-pick-a-file-to-read.

I found this solution in the answer to the question referenced by Dylan: https://stackoverflow.com/a/70001920/16740180.

Unfortunately, this doesn't work for mobile devices right now, but it works fine for windows. I hope this helps someone.