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.
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 have a file in the file system named temp.gz
the temp gzip file contains files and folder
i would like to extract them and have them in a folder like we would normally unzip a file in OS.
i have tried below code but thats not meant for extracting files to folder.
const unzip = zlib.createUnzip();
var input = fs.createReadStream(inFilename); /path/to/temp.gz
var output = fs.createWriteStream(outFilename); /path/to/output/folder
Above didnt work and i believe the reason is that it writes to a file and i have provided a directoy.
my requirement is extract files to directory.
zlib.gzip(responseData, (err, buffer) => {
// Calling gunzip method
zlib.gunzip(buffer, (err, buffer) => {
console.log(buffer,pathFileName);
fs.appendFileSync(pathFileName, buffer);
});
});
above i was trying to unzip as per the docs and write buffer to the output file and didnt create a folder as expected and didnt add the files there
sure i am missing something but not sure what.
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
I have designed application using Node.js and I have converted into Desktop Application using ElectronJS. Downloading JSON object as a file is not downloading automatically to my downloads Folder, Instead it is asking Popup window to choose the path to save the file.
Below Code I have used:
HTML: <a id="downloadAnchorElem" style="display:none"></a>
var dataStr = "data:text/json;charset=utf-8," +
encodeURIComponent(JSON.stringify(storageObj));
var dlAnchorElem = document.getElementById('downloadAnchorElem');
dlAnchorElem.setAttribute("href", dataStr );
dlAnchorElem.setAttribute("download", "scene.json");
dlAnchorElem.click();
If i run this code as a normal webapplication, it is downloading automatically whereas if i run the same on on Desktop Application using ElectronJS NOT downloading automatically. Kindly tell me why this is happening and Alternative solution is appreciable.
electron-dl is your friend!. As its description goes in the github, it really simplifies file downloads for your Electron app.
Here is an example how you can initiate the download.
const {app, BrowserWindow, ipcMain} = require('electron');
const {download} = require('electron-dl');
ipcMain.on('download-btn', (e, args) => {
download(BrowserWindow.getFocusedWindow(), args.url)
.then(dl => console.log(dl.getSavePath()))
.catch(console.error);
});
Hope this helps!
Ive read a lot about the filesystem API and HTML5, but i just couldn't find a working solution so i ask you guys:
I want to have a file upload form, drag drop or regular input box doesnt matter, however i want to select a file, and after uploading it should take the file or a whole folder and "upload" it to the filesystem located on the clients computer. The upload is in brackets because i actually want to copy the file/folder to the clients local file system.
Is it even possible? Because i want to make an application, where a user can upload his files such as music or large videos and movies to his local filesystem and edit/watch etc them in my application. I know i have to upload those big files i have to cut them into pieces and load them stacked up, but i just want to start little :)
Thanks in advance
There's indeed little information on this subject at the moment, so I put together an example that combines:
Using the webkitdirectory attribute on <input type="file">.
This allows the user to select a directory using an appropriate dialog box.
Using the Filesystem API.
This is about the sandboxed filesystem which allows you to store files on the client's machine.
Using the File API.
This is the API that allows you to read files. The files are accessible through an <input type="file"> element, through a transfer using drag and drop, or through the Filesystem API.
As these are currently only working nicely in Chrome, I used the webkit prefix where necessary.
http://jsfiddle.net/zLna6/3/
The code itself has comments which I hope are clear:
var fs,
err = function(e) {
throw e;
};
// request the sandboxed filesystem
webkitRequestFileSystem(
window.TEMPORARY,
5 * 1024 * 1024,
function(_fs) {
fs = _fs;
},
err
);
// when a directory is selected
$(":file").on("change", function() {
$("ul").empty();
// the selected files
var files = this.files;
if(!files) return;
// this function copies the file into the sandboxed filesystem
function save(i) {
var file = files[i];
var text = file ? file.name : "Done!";
// show the filename in the list
$("<li>").text(text).appendTo("ul");
if(!file) return;
// create a sandboxed file
fs.root.getFile(
file.name,
{ create: true },
function(fileEntry) {
// create a writer that can put data in the file
fileEntry.createWriter(function(writer) {
writer.onwriteend = function() {
// when done, continue to the next file
save(i + 1);
};
writer.onerror = err;
// this will read the contents of the current file
var fr = new FileReader;
fr.onloadend = function() {
// create a blob as that's what the
// file writer wants
var builder = new WebKitBlobBuilder;
builder.append(fr.result);
writer.write(builder.getBlob());
};
fr.onerror = err;
fr.readAsArrayBuffer(file);
}, err);
},
err
);
}
save(0);
});
$("ul").on("click", "li:not(:last)", function() {
// get the entry with this filename from the sandboxed filesystem
fs.root.getFile($(this).text(), {}, function(fileEntry) {
// get the file from the entry
fileEntry.file(function(file) {
// this will read the contents of the sandboxed file
var fr = new FileReader;
fr.onloadend = function() {
// log part of it
console.log(fr.result.slice(0, 100));
};
fr.readAsBinaryString(file);
});
}, err);
});
That is not possible, exactly, but your app can still probably work. Reading the file is possible through a file input form element, but writing the file back to disk is where you'll run into trouble.
The two ways your browser can write to disk are 1) downloading a file and 2) the HTML5 filesystem API. Option #1 obviously doesn't let your application choose the destination and option #2 only works with browser-created sandbox filesystems. That restriction might not be a deal-breaker for you -- it just means that the folders that your app uses will be buried somewhere in your browser's data files.
Also, the Filesystem API is currently Chrome-only (but it is an open standard). If you want cross-platform support, maybe you can use IndexedDB. You could use localStorage, but Chrome has a hard 5MB limit, which would be terrible for a media application.