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
Related
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.
I have a mobile app that wraps around the web-app, using webview.
The web-app has a button to open a large .zip file (e.g. 100 MB).
The user clicks a button, and selects a .zip file.
This triggers an onChange function with a variable of type File (Blob), which includes attributes like:
file name
file size
file type (application/zip)
The javascript code then parses the .zip file, extracts specific data within it and uses it within the web-app.
This works well within the web-app, when the app is called via the Chrome browser.
For example when operated in chrome browser on an Android phone, I can pull the .zip file and open it in the web-app.
I want to do the same but using the mobile app.
I am able to pick up the .zip file using a File Chooser, and pass it to Webview but I have problems to fetch the file from the Javascript code.
For reference, I am able to pass an image, by creating a data_uri using stringBuilder and passing the content (as data:image/jpeg;base64).
But the zip file is much larger.
When calling fetch(fileUri) from the Javascript side I'm getting errors.
I'm using the following uri
/storage/emulated/0/Android/data/com.example/files/Download/file2.zip
The fetch succeeds but returns a blob with size of 165 (i.e. not the actual size of the file) which hosts the error message:
{
"error": "Not Found",
"message": "The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again."
}
The program flow is like so:
I select a .zip file via FileChooser.
In onActivityResult, the uri value is /document/msf:12858 (seen via uri = intent.getData();)
The uri needs to be mapped into a real path file url, such that the fileUrl will be passed to webview.
Webview will then fetch the file using the fileUrl.
I searched how to get the real path file url when selecting a file with FileChooser, and found
this, and this links.
I wasn't able to get the real file path, so I decided to read the file and write it to another location, so I can get a file path. (this is not efficient and done just to check the functionality).
I create the new file using the following code:
InputStream stream = context.getContentResolver().openInputStream(uri);
File file2 = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "file2.zip");
writeBytesToFile(stream, file2);
I don't see any errors when creating the file, and when creating the file, the number of bytes that are read and written to the new file are as expected.
For file2, I get a value of:
/storage/emulated/0/Android/data/com.example/files/Download/file2.zip
Then, within the Javascript code I fetch this file path.
But I'm getting a Blob with the "file-not-found" content as above.
So:
How can I verify that the file is indeed created and that the path can be fetched from webview?
How can I get the real file path of the original selected file, so I don't have to read and write the original file to new location just to get the file path?
Thanks
I was able to get the file from external storage by doing the following steps:
create an initial uri (uri1)
The uri is created by:
creating a temporary file (file1) in the storage dir via
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
I'm not sure why a temporary file need to be created but if I don't create a file I cannot get the uri.
createFile3
get the uri via
Uri uri1 = FileProvider.getUriForFile(context, "com.example.android.fileprovider", file1);
create an intent with the following attributes:
Intent.ACTION_OPEN_DOCUMENT
category: Intent.CATEGORY_OPENABLE
type: "application/zip"
extra attribute: fileIntent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, uri1);
this opens a dialog box for selecting openable zip files in the Downloads directory,
after the file is selected, a new uri (uri2) is created that includes the name of the selected file.
extract the name of the file via
String fileName = getFileName(context, uri2);
create the dirPath by appending the filename
dirPath = "/data/user/0/com.example/" + fileName;
if the dirPath does not exist (first time), write the file to its dirPath location.
on successive ocassions dirPath exists, so there is no need to re-write the file.
open the file with regular Java means, e.g. via
ZipFile zip = new ZipFile(dirPath);
I am trying to create excel using poi at server side and sending it to browser.
Using href or form submit solution is working fine but tricky part is file creation taking too much time so i want to show user some message like "Processing file" so I have implemented this using simple get request and added loader before request and removed in success call back.
Problem is - instead of downloading file, file contain coming as responseText at client side and also always executes failure call back.
Please suggest how i can get file as download in success call back instead of byte data in response text.
Also tried to set content type as attachment, force download etc but nothing work for me browser not downloading file it's showing byte data in response text
Tried to open new window with download url but as mentioned file creation take time so browser shows no content error after few minute.
note hwb is workbook object in below code
file = new File(FileName+"_"+timeStamp+".xlsx");
FileOutputStream fos = new FileOutputStream(file);
hwb.write(fos);
fos.close();
file.deleteOnExit();
String contentType = "application/vnd.openxmlformats- officedocument.spreadsheetml.sheet";
ResponseBuilder response = Response.ok((Object) file, contentType);
response.header("Content-Disposition", "attachment; filename="+ file.getName());
return response.build();
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?
We are developing an app that is to download files from HTTP URLs, the extensions/file types of which we will not know until runtime. We've been following this tutorial as a starting point, but since we aren't dealing with images, it hasn't helped us.
The issue is that the code in the tutorial will get you a Blob object and I can't find any code that will allow us to either:
Convert the Blob to a byte array.
Save the Blob straight to the file system.
The ultimate goal is to seamlessly save the file at the given URL to the file system and launch it with the default application, or to just launch it from the URL directly (without the save prompt you get if you just call Windows.System.Launcher.launchUriAsync(uri);).
Any insight anyone might have is greatly appreciated.
Regarding downloading content into byte array:
Using WinJS.xhr with the responseType option as 'arraybuffer' will return the contents in ArrayBuffer. A javascript typed array can be instantiated from the ArrayBuffer for example UInt8Array. This way contents can be read into byte array. code should look something like this:
// todo add other options reqd
var options = { url: url, responseType: 'arraybuffer' };
WinJS.xhr(options).then(function onxhr(ab)
{
var bytes = new Uint8Array(ab, 0, ab.byteLength);
}, function onerror()
{
// handle error
});
Once you take care of permissions to save the file to file system either by user explicitly picking the save file location using SaveFilePicker or pick folder using folder picker - file can be saved on local file system. Also, file can be saved to app data folder.
AFAIK, html/js/css files from local file system or the app data cannot be loaded for security reasons. Although DOM can be manipulated under constraints, to add content. I am not sure of your application requirements. You might need to consider alternatives instead of launching downloaded html files.