I need to create functionality which allows a user to download a PDF file from my HTML5/JavaScript-based mobile application. I will be getting the PDF file as a Base 64 encoded byte stream. How can I allow the user to download the PDF to their device upon clicking a button in the page?
For IOS:
You can download a pdf on iPhone apps and show it in a WebView.
Some ways are listed at this (linked) question. You can also find there how to put the pdf in a folder of the device/iPhone running the app: How to download PDF and store it locally on iPhone?
let request = URLRequest(url: URL(string: "http://www.msy.com.au/Parts/PARTS.pdf")!)
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let task = session.dataTask(with: request, completionHandler: {(data, response, error) in
if error == nil{
if let pdfData = data {
let pathURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("\(filename).pdf")
do {
try pdfData.write(to: pathURL, options: .atomic)
}catch{
print("Error while writting")
}
DispatchQueue.main.async {
self.webView.delegate = self
self.webView.scalesPageToFit = true
self.webView.loadRequest(URLRequest(url: pathURL))
}
}
}else{
print(error?.localizedDescription ?? "")
}
}); task.resume()
For Android:
There are many ways to do it for Android. This one should work in most cases without any issue:
URL u = new URL("http://www.path.to/a.pdf");
//open a connection
HttpURLConnection c = (HttpURLConnection) u.openConnection();
c.setRequestMethod("GET");
c.setDoOutput(true);
c.connect();
FileOutputStream f = new FileOutputStream(new File(root,"file.pdf"));
//read the file
InputStream in = c.getInputStream();
byte[] buffer = new byte[1024];
int len1 = 0;
while ( (len1 = in.read(buffer)) > 0 ) {
f.write(buffer,0, len1);
}
f.close();
This other one-line option works to download a pdf in android, but seems to have different behavior depending on the device and other installed apps (pdf reader):
`startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("path/filename.pdf")));`
I used this question and it's reply to get a working code example. You can find a long answer at the bottom of the post with many different use-cases and their solutions explained at the same post.: How to download a pdf file in Android?
Related
I am running a Python HTTP server that host a captive portal. Basically I'm trying to upload a password protected file to the server.
Right now I am able to upload files to the server with JavaScript and FileReader. This is how I do it:
var file_cli_cert = document.getElementById(id="exa_cli_cert").files[0];
const xmlhttp1 = new XMLHttpRequest();
let name = file_cert.name;
let reader = new FileReader();
reader.readAsText(file_cert);
xmlhttp1.open("POST", '/load/cert');
reader.onload = function(){
xmlhttp1.send(name +"&CERT="+reader.result);
With non-password protected files this works well.
For password protected files my idea is to get the file and the password to access to the data. The problem is that I don't know how to access to password protected files in JS and i think it's not possible. So right now i am wondering how to send the file and the password to the server and access the file data there.
If I send the file object with XMLHttpRequest.send(), on the server side I get the object in string format.
To read the POST message, in the server side, I do:
ctype, pdict = cgi.parse_header(self.headers['content-type'])
content_len = int(self.headers.get('Content-length'))
post_body = self.rfile.read(content_len) #read credentials
self.send_response(201)
self.end_headers()
if self.path.endswith('/load/cert'): #if user loads a certificate
post_body = post_body.decode()
post_body = post_body.split("&CERT=") #split name and file content
name_cert = post_body[0]
file_content = post_body[1]
f = open("./certs/"+name_cert, "w")
f.write(file_content)
f.close()
I'm a newbie at this and I have been looking for a solution for hours. Any help will be appreciated.
No python expert but reading a encrypted file as Text with FileReader could be problematic as it could lead to some data loss when encoding it as text. You should rather be reading it as binary using reader.readAsArrayBuffer()
But there is no need to read the content of the file into memory and allocate memory, just upload the blob/file directly to the server and it will take care of sending the data from the disc to the network without touching the main javascript thread without any text transformation.
const [ file ] = document.querySelector('#exa_cli_cert').files
fetch('/load/cert', {
method: 'POST',
body: file,
headers: {
'x-file-name': file.name
}
})
.then(r => r.arrayBuffer())
I am developing a web application and one of my use cases is for users to have the ability to upload and download files from the server. I'm using ReactJs and Spring Boot.
Front-End code:
downloadFileClicked(id, fileName, fileType){
TestDataService.downloadFile(id)
.then(response=>{
console.log(response)
const file = new Blob(
[response.data],
{type: fileType}
)
let url = window.URL.createObjectURL(file)
let a = document.createElement('a')
a.href=url
a.download= fileName
a.click()
})
}
Back-End code:
#GetMapping("/downloadFile/{fileId:.+}")
public ResponseEntity<Resource> downloadFile(#PathVariable Long fileId, HttpServletRequest request ){
//Load file as a resource
DatabaseFile databaseFile = fileStorageService.getFile(fileId);
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(databaseFile.getFileType()))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\""+databaseFile.getFileName()+"\"")
.body(new ByteArrayResource(databaseFile.getData()));
}
When the user clicks download - the file does indeed download and seemingly in the correct format but when each application tries to open the file I am faced with such errors as the file format is not supported or the file is corrupt.
The file data is being stored as a byte array in a MySQL database. I have tried a number of different methods to download the file but I have encountered the same error each time. Any help would be greatly appreciated!
I'm trying to upload a local file (C:\sample.txt) to my server. I have tried to implement this with Chrome web driver and its working absolutely fine.
But during implementing the same with HTMLUnitDriver, i couldn't browse the file item from my local disk. I tried the below two methods as well,
1) Send keys:
WebElement inputFile = driver.findElement(By.id("file"));
System.out.println(driver.getCurrentUrl());
LocalFileDetector detector = new LocalFileDetector();
String path = "C:\\UploadSample1.txt";
File f = detector.getLocalFile(path);
inputFile.sendKeys(f.getAbsolutePath());
2) Using a Robot:
WebElement browseFile = fluentWait(By.id("browseFile"), driver);
browseFile.click();
File file = new File("C:\\UploadSample1.txt");
driver.switchTo().activeElement();
StringSelection fileNameToWrite = new StringSelection(
file.getAbsolutePath());
Toolkit.getDefaultToolkit().getSystemClipboard()
.setContents(fileNameToWrite, null);
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_ENTER);
robot.keyRelease(KeyEvent.VK_ENTER);
robot.keyPress(KeyEvent.VK_CONTROL);
robot.keyPress(KeyEvent.VK_V);
robot.keyRelease(KeyEvent.VK_V);
robot.keyRelease(KeyEvent.VK_CONTROL);
robot.keyPress(KeyEvent.VK_ENTER);
robot.keyRelease(KeyEvent.VK_ENTER);
I need the file item to be browsed, then only i can save it to my server. Because just sending the file path will be searching the file in server disk. Now i'm really stuck and couldn't move further.
Any help is highly appreciated. Thankyou!
If you need to browse to the file first, that isn't possible IMHO; for that you will need AutoIT (as Robot class is not recommended). So your best bet would be sending file path using sendKeys.
formInput.setValueAttribute(formValue); worked fine for me.
Code snippet:
Iterator<String> formValueIterator = formValues.keySet().iterator();
while(formValueIterator.hasNext()){
String formKey = formValueIterator.next();
String formValue = formValues.get(formKey);
HtmlInput formInput = form.getInputByName(formKey);
if (formInput != null)
if (formInput instanceof HtmlPasswordInput) {
((HtmlPasswordInput)formInput).setValueAttribute(formValue);
} else {
formInput.setValueAttribute(formValue);
}
}
My Goal is to print a RDLC report on the client machine without preview. I can not use the ReportViewer print button since it requires the installation of ActiveX object and there are no permissions for that. So, I'm using ITextSharp to create a PDF from the byte array returned from the rendered LocalReport, and add a JavaScript for print.
During Debug, I can see that the PDF is generated and has 2 pages, and everything looks OK. I don't receive any errors and the function exits OK, but it doesn't print. What am I doing wrong, or what am I missing?
This is my code:
string jsPrint = "var pp = this.getPrintParams();pp.interactive= pp.constants.interactionLevel.silent;this.print(pp);";
byte[] bytes = report.Render("PDF", null, out mimeType, out encoding, out extension, out streamids, out warnings);
using (MemoryStream ms = new MemoryStream())
{
Document doc = new Document();
PdfWriter writer = PdfWriter.GetInstance(doc, ms);
doc.SetPageSize(PageSize.A4);
doc.Open();
PdfContentByte cb = writer.DirectContent;
PdfImportedPage page;
PdfReader reader = new PdfReader(bytes);
int pages = reader.NumberOfPages;
for (int i = 1; i <= pages; i++)
{
doc.SetPageSize(PageSize.A4);
doc.NewPage();
page = writer.GetImportedPage(reader, i);
cb.AddTemplate(page, 0, 0);
}
PdfAction jAction = PdfAction.JavaScript(jsPrint, writer);
writer.AddJavaScript(jAction);
doc.Close();
}
Thanks.
Regarding your question about PdfStamper (in the comments). It should be as simple as this:
string jsPrint = "var pp = this.getPrintParams();pp.interactive= pp.constants.interactionLevel.silent;this.print(pp);";
PdfReader reader = new PdfReader(bytes);
MemoryStream stream = new MemoryStream();
PdfStamper stamper = new PdfStamper(pdfReader, stream);
stamper.Writer.AddJavaScript(jsPrint);
stamper.Close();
reader.Close();
Regarding your original question: automatic printing of PDF documents is considered being a security hazard: one could send a PDF to an end-user and that PDF would cause the printer to spew out pages. That used to be possible with (really) old PDF viewers, but modern viewers prevent this from happening.
In other words: you may be trying to meet a requirement of the past. Today's PDF viewers always require an action from the end user to print a PDF document.
Im trying to send a File to my server from a Windows Sidebar Gadget. I found this Link: http://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/23fad87b-8aad-4262-8c2c-b1fe0ca3b9f6/file-upload-with-sidebar-gadget?forum=sidebargadfetdevelopment
var adTypeBinary = 1;
var cfItem = System.Shell.chooseFile(true, "", "", "");
if (cfItem.path != "") {
oStream = new ActiveXObject("ADODB.Stream");
oStream.Type = adTypeBinary;
oStream.Open;
oStream.LoadFromFile(cfItem.path);
content = oStream.Read;
//upload content (as binary string)
oStream.Close;
oStream = null;
}
But this only explains how to read a file, not how to upload the resulting binary string. I tried several techniques (Blob, Uint8Array, ..) but none of them is working. Windows Sidebar has Internet Explorer 7 Standards.
If somebody provided a solution, this would be great (Either with jquery or plain javascript)