I am using React Native v0.67.2 and looking to generate PDF from HTML using react-native-html-to-pdf. This is the function I use to generate the PDF, but the location of generated Pdf isn't showing in the iOS file manager.
const createPDF = async () => {
let options = {
html: '<h1>PDF TEST</h1>',
fileName: 'testFile',
directory: 'Documents',
};
let file = await RNHTMLtoPDF.convert(options);
// console.log(file.filePath);
alert(file.filePath);
}
The file exists in an unknown location, but I'm expecting the downloaded PDF file in the 'Documents' directory of iPhone Files. How do I move the PDF to this location and resolve this issue?
Thank you in advance.
Duplicate of:
pdf created by react native html to pdf is not showing in provided path
On IOS you can only use that Documents path that you already have.
You cannot make it save anywhere else.
Directory where the file will be created (Documents folder in example above). Please note, on iOS Documents is the only custom value that is accepted.
Ref: https://github.com/christopherdro/react-native-html-to-pdf#options
Related
I am creating an App for Android using Cordova, and I would like to open and display a file (PDF or image) that is served from the server as Base64-encoded binary data.
Of course I have read the multiple other posts on the subject that already exist on this website, but none of the proposed solutions have worked for me, more details below.
To be more precise, the server sends a JSON-file to the app, which among many other things contains a string consisting of the base64-encoded contents of a PDF file. I want to convert this data back into the represented PDF and display it to the user.
If this were a pure browser page, I would simply package my base64 data into a data-URL, attach this as the href of some anchor, and add a download-attribute. Optionally I could wrap all of my data into a blob and create an object url for that first.
In Cordova, this does not work. Clicking the <a> does nothing. Here is what I have attempted so far:
Using the file plugin, I can write the binary data to a file on the device. This works, and using a terminal I can see that the file was downloaded correctly, but into an app-private directory which I cannot access normally (e.g. through the file explorer).
Accessing the user's "downloads" folder is blocked by the file system
Using window.open with the file path as the first argument and "_system" as the target does nothing. There is no error but also nothing happens. Setting the target to "_blank" instead, I get an error saying ACCESS_DENIED.
Using cordova.InAppBrowser behaves the same was as window.open
With the plugin file-opener2 installed, the app will not compile, because the plugin is looking for an android4 toolchain, and I am building for android 9 and up
The plugin document-viewer (restricting to PDFs for the time being) suffers the same problem and does not compile.
Passing the data-URI to window.open (or cordova.InAppBrowser) directly loads for a very long time and eventually tells me that the desired page could not be loaded.
The PDF file I am using for testing is roughly 17kb after converting to base64. I know this is technically above the spec for how long data-URIs can be, but Chrome in the browser has no trouble with it whatsoever, and using a much shorter URI (only a few dozen bytes) produces the same behavior.
Ideally, what I would like to do, is download the file and then trigger the user's standard browser to open the file itself. That was, I would not have to deal with MIME types and also it would look exactly how the user expected from their own device.
Alternatively, if that doesn't work, I would be ok with downloading the file into a system-wide directory and prompting the user to open it themselves. This is not optimal, but I would be able to swallow that pill.
And lastly, if there is a plugin or some other solution that solves the problem amazingly, but for PDFs only, then I can also work out something else for images (e.g. embedding a new into my app and assigning the URI to that).
I would be thankful for any suggestion you might have on how to solve this problem. The code I use to download the file currently is shown below.
Thank you for your time.
var filePath = cordova.file.externalDataDirectory; // Note: documentsDirectory is set to "" by Cordova, so I cannot use that
var fileName = "someFileName.pdf";
var mime = "application/pdf";
var dataBlob = /* some blob containing the binary data for a PDF */
function writeFile(fileEntry, dataBlob) {
// Create a FileWriter object for our FileEntry.
// This code is taken directly from the cordova-plugin-file documentation
fileEntry.createWriter(function (fileWriter) {
fileWriter.onwriteend = function() {
console.log("Successful file write...");
readFile(fileEntry);
};
fileWriter.onerror = function (e) {
console.log("Failed file write: " + e.toString());
};
fileWriter.write(dataBlob);
});
}
window.resolveLocalFileSystemURL(
filePath,
function onResolveSuccess (dirEntry) {
dirEntry.getFile(
fileName,
{ create: true },
function onGetFileSuccess (file) (
writeFile(file, dataBlob);
// At this point, the file has been downloaded successfully
window.open(file.toURL(), "_system"); // This line does nothing, and I don't understand why.
}
);
}
);
I managed to solve the problem.
As per the documentation of the file-opener2 plugin, you need to also add the androidx-adapter plugin to correct for the outdated (android 4) packages. With the plugins file, file-opener2 and androidx-adapter installed, the complete code is the following:
var filePath = cordova.file.externalDataDirectory; // Note: documentsDirectory is set to "" by Cordova, so I cannot use that
var fileName = "someFileName.pdf";
var mime = "application/pdf";
var dataBlob = /* some blob containing the binary data for a PDF */
function writeFile(fileEntry, dataBlob) {
// Create a FileWriter object for our FileEntry.
// This code is taken directly from the cordova-plugin-file documentation
fileEntry.createWriter(function (fileWriter) {
fileWriter.onwriteend = function() {
console.log("Successful file write...");
readFile(fileEntry);
};
fileWriter.onerror = function (e) {
console.log("Failed file write: " + e.toString());
};
fileWriter.write(dataBlob);
});
}
window.resolveLocalFileSystemURL(
filePath,
function onResolveSuccess (dirEntry) {
dirEntry.getFile(
fileName,
{ create: true },
function onGetFileSuccess (file) (
writeFile(file, dataBlob);
// At this point, the file has been downloaded successfully
cordova.plugins.fileOpener2.open(
filepath + filename,
mime,
{
error : function(){ },
success : function(){ }
}
);
}
);
}
);
I need to fetch a PDF file from s3.amazonaws.com and when I query it using Postman (or paste directly into the browser), it loads fine. However when I try to generate the file path for it (to pass to a viewer later), it didn't work:
fetch(<S3URL>).then(res => res.blob()).then(blob => {
// THIS STEP DOES NOT WORK
let myBlob = new Blob(blob, {type: 'application/pdf'});
// expect something like 'www.mysite.com/my-file.pdf'
let PDFLink = window.URL.createObjectURL(myBlob);
return PDFLink;
}
I'm using Autodesk's Forge PDF viewer and it works perfectly fine for local PDF files:
let myPDFLink = 'public/my-file.pdf';
Autodesk.Viewing.Initializer(options, () => {
viewer = new Autodesk.Viewing.Private.GuiViewer3D(document.getElementById('forgeViewer'));
viewer.start();
viewer.loadExtension('Autodesk.PDF').then( () => {
viewer.loadModel(myPDFLink, viewer); // <-- works fine here
});
});
// from https://github.com/wallabyway/offline-pdf-markup
So, how do I go from the S3 URL (e.g. s3.amazonaws.com/com.autodesk.oss-persistent/0d/ff/c4/2dfd1860d1...) to something the PDF viewer can understand (i.e. has .pdf extension in the URL)?
I know for JSON files I need to do res.json() to extract the JSON content, but for PDFs, what should I do with the res object?
Note: I don't have control over the S3 URL. Autodesk generates a temporary S3 link whenever I want to download documents from their BIM360 portal.
I tried a lot of options and the only way I could display a PDF fetched via API calls is by using an object element:
<object data='<PDF link>' type='application/pdf'>
Converting the downloaded blob to base64 doesn't work. Putting the PDF link in an iframe doesn't work either (it still downloads instead of displaying). All the options I have read only work if the PDFs are part of the frontend application (i.e. local files, not something fetched from a remote server).
I'm building an electron app with vue.js + vue-cli-plugin-electron-builder that shows the structure of the public folder which includes a "pdf" folder with PDF files.
I use pdf.js to show the pdfs.
To have that "pdf" folder later in my my app I copy that folder with
extraFiles: [
{
from: "./public/pdf",
to: "pdf"
}
The app shows all folders and included pdf files.
When I click on one pdf name a popup opens and shows the PDF.
Works great in development and in the final build.
I read the folder with this function:
readdir () {
var devPath = path.join(__static, '/pdf/Anbau')
console.log("devPath development : ", devPath);
var readFiles = new Promise((resolve, reject) => {
fs.readdir(devPath, (err,files) => {
if(err) {
alert('Lesen fehlgeschlagen!', {type: 'error'})
reject(err);
} else {
resolve(files);
this.list = files;
console.log('this.list: ', this.list, this.list.length)
}
});
});
},
The problem is now, when I add new folders and pdfs to that
public folder after the app is built, the app shows the new folders and pdfs, but if I click on the generated name "someNewPDF.pdf", pdf.js throws an error.
The console output with the path of the pdf is correct.
I found out that ONLY the files that exist before the build process are later accessible. When I rename a pdf, electron neither can show that file.
It seems like electron creates a map of the files when building the app and later it can't be changed.
So my question is:
What can I do to let the app read dynamically a folder that can be filled / expanded later.
The idea is, that the user can throw his pdf files into a folder and that can be viewed via my app.
I'm quite new in vue and electron.
i've found a solution:
the client can put his files now in a folder "pdf" on the desktop. Inside of this folder are also the necessary files of PDF.js.
The path to the desktop on MAC and Windows is
const desktopPath = app.getPath('desktop')
so now i can
window.open('file://' + desktopPath + '/pdf/web/viewer.html?file=' + url)
while url holds the path to the pdf.
I have several pdf docs for example 4, and I need merge them into 1 pdf file. I was trying to use merge-pdf but documentation for this package is lean, so I got my merged pdf's but it merged into several pages. I should probably use hummus.js or another package, but I'm not sure. Any help?
You can do this on any computer using a free online PDF merger called PDF Joiner, or you can use a free app called PDF Creator on Windows or the built-in Preview program on Mac.
or you can convert it by yourself by using copying content of all pdfs into doc file and save this doc file as pdf
You can use HummusJS for this purpose, here's an example of combining three PDF files. One might want to improve error handling / corner cases etc. but this certainly does the job.
const fs = require("fs")
const hummus = require("hummus");
const memoryStreams = require("memory-streams");
// Combine PDF files into one buffer.
function combinePDFs(...filePaths) {
const pdfBuffers = filePaths.map(filePath => fs.readFileSync(filePath));
const resultStream = new memoryStreams.WritableStream();
const writer = hummus.createWriterToModify(new hummus.PDFRStreamForBuffer(pdfBuffers[0]), new hummus.PDFStreamForResponse(resultStream));
// Add the subsequent files
pdfBuffers.slice(1).forEach(buffer => {
writer.appendPDFPagesFromPDF(new hummus.PDFRStreamForBuffer(buffer));
});
writer.end();
resultStream.end();
return resultStream.toBuffer();
};
const resultBuffer = combinePDFs("pdf1.pdf", "pdf2.pdf", "pdf3.pdf");
fs.writeFileSync("result.pdf", resultBuffer);
I am developing a website using react.js and admin-on-rest. One feature is allowing users to upload a pdf file.
I get the file as type FILE and want to get the file from FILE, compress it to zip, and then make it to type FILE.
So it should be FILE -> origin file -> zip file -> FILE from zip file.
I tried JSZip but still can not figure it out.
Any help is appreciated. Thanks
You can use JSZIP.
**use npm to install JSZIP
let zip = require('jszip')();
//hoping you have already taken input
let input = document.getElementById('fileInput'); // fileInput is id of my input element
let file = input.files[0];
let allZip = zip.file(file.name, file);
console.log(allZip)
Hi Garrick following are the steps you need to take.
1) handle fileupload in a rest wrapper
https://marmelab.com/admin-on-rest/RestClients.html#decorating-your-rest-client-example-of-file-upload
the above example is for image upload. But you will essentially be doing the same thing.
2)
const addUploadCapabilities = requestHandler => (type, resource, params) => {
if (type === 'UPDATE' && resource === 'posts') {
//use jszip to zip file here and package it however you need
// call the API with zipped file
} return requestHandler(type, resource, params);
};
There is a small app called jszip for this. Try, it would help. https://stuk.github.io/jszip/