I have a electron application using jszip to create a zip file that the user is then able save. Everything works fine but my problem is my application uses the users download folder. Im guessing its making a temporary file. I've submitted my application to the mac store and they want me to use another location instead of the users downloads folder for the temporary file. Is there anyway I can specify the temporary location or maybe something else other then jszip that will do this?
Here is the code I use
savePNGButton.addEventListener('click', function(e) {
var zip = new JSZip();
if (WatermarkText == ""){
var img = zip.folder("images");
} else {
var img = zip.folder(WatermarkText);
}
$(".WatermarkPhoto").each(function(index) {
imgsrc = this.src;
var DataURL = imgsrc.replace('data:image/png;base64,','');
img.file(WatermarkText+index+".png", DataURL, {base64: true});
});
zip.generateAsync({type:"blob"})
.then(function(content) {
saveAs(content, WatermarkText+".zip");
});
});
[edit]
Looking more into this it looks like my problem is not with JSZip but with chrome or FileSaver.js using the downloads folder as a temp folder for the file before the users chooses where to place the file. Is there anyway I can change the temp location for my electron app?
If anyone comes across this, I never figured a way around the HTML5 filesystem way of moving the temp file before the users selects the download location. Instead I am using nodejs file system with electrons showSaveDialog. I also had to change JSZip to use .generateNodeStream instead of .generateAsync. Below is my function that I got working for me.
savePNGButton.addEventListener('click', function(e) {
var zip = new JSZip();
if (WatermarkText == ""){
var img = zip.folder("images");
} else {
var img = zip.folder(WatermarkText);
}
$(".WatermarkPhoto").each(function(index) {
imgsrc = this.src;
var DataURL = imgsrc.replace('data:image/png;base64,','');
img.file(WatermarkText+index+".png", DataURL, {base64: true});
});
// zip.file("file", content);
// ... and other manipulations
dialog.showSaveDialog({title: 'Test',defaultPath: '~/'+WatermarkText+'.zip',extensions: ['zip']},(fileName) => {
if (fileName === undefined){
console.log("You didn't save the file");
return;
}
zip
.generateNodeStream({type:'nodebuffer',streamFiles:true})
.pipe(fs.createWriteStream(fileName))
.on('finish', function () {
// JSZip generates a readable stream with a "end" event,
// but is piped here in a writable stream which emits a "finish" event.
console.log("zip written.");
});
});
});
Related
I'm looking forward to save/upload picture in a local directory in Windows using IONIC 3 / Cordova. Indeed, the user has to choose a file (jpg) from a folder, and I want to copy this file in another directory.
I tried with this.file.copyFile(path, name, newPath, newName) but it doesn't work and I don't understand why. I also tried with file-transfer plugin (https://ionicframework.com/docs/native/file-transfer/), but it seems I have to get an endpoint in an API to upload the file.
Please find below the function I use to copy the file when the user clicks on a submit button:
private copyFileToLocalDirBrowser(namePath, currentName, newFileName) {
this.file.copyFile(namePath, currentName, "file:///C://Users//myName//Desktop//imgs//", newFileName).then(success => {
console.log("Picture imported!");
}, error => {
this.presentToast("Error:" + error);
});
}
In the constructor, I declared private file: File and the import is import { File } from '#ionic-native/file';.
The user clicks on an input node (type file), to choose the file he/she wants :
<input name="pictureID" id="inputFile" type="file" (change)="showThumb($event)"/>
And here the showThumb function:
var files = e.target.files;
for (var i = 0, f; f = files[i]; i++) {
// Only process image files.
if (!f.type.match('image.*')) {
continue;
}
var reader = new FileReader();
// Closure to capture the file information.
reader.onload = (function(theFile) {
return function(e) {
//Getting URI :
if (e.target.result) {
this.imageURI = e.target.result;
// Render thumbnail.
var img = document.createElement("img");
img.setAttribute('src', this.imageURI);
img.setAttribute('title', theFile.name);
img.setAttribute('id', "thumb");
document.getElementById('thumb-for-browser').appendChild(img);
}
};
})(f);
// Read in the image file as a data URL.
reader.readAsDataURL(f);
}
Then, when the user clicks on a "Submit" button, I want to save the picture that I displayed a thumb on a local directory "file:///C://Users//myName//Desktop//imgs//".
Thanks in advance for your help.
Kind regards,
I would like display some images inside html page(offLine) using JS.
I have a folder with an index.html and a folder called "images" with JPG inside.
If I have 10 images, display 10, if I have 3 display 3 inside html
Is it possible do this?
I tried lots of tutorials but unsuccessfully.
Regards, Fernando.
I think you can't browse read file from js on your computer. However you can browse file using FileReader API of HTML5.
It's not possible to list directory contents by opening a local page in the browser. However if these files were named following a predictable pattern then you could try to display them by "guessing" the file names.
For example assuming images are named 1.jpg, 2.jpg etc. The script will try to append images 1...N as long as N.jpg exists and will terminate upon the first file name that fails to load.
var index = 1;
var tempImg = new Image();
tempImg.onload = function(){
appendImage();
}
var tryLoadImage = function( index ){
tempImg.src = 'images/' + index + '.jpg';
}
var appendImage = function(){
var img = document.createElement('img');
img.src = tempImg.src;
document.body.appendChild( img )
tryLoadImage( index++ )
}
tryLoadImage( index );
You can load images with javascript, it will depending on how you name the files.
// create image
var img = new Image();
// add src attribute
img.src = "images/" + filename;
// when image is loaded, add it to my div
img.addEventListener("load", function(){
document.getElementById("mydiv").appendChild(this);
});
You can achieve this using ajax like in this jQuery example:
var dir = "Src/themes/base/images/";
var fileextension = ".png";
$.ajax({
//This will retrieve the contents of the folder if the folder is configured as 'browsable'
url: dir,
success: function (data) {
//List all .png file names in the page
$(data).find("a:contains(" + fileextension + ")").each(function () {
var filename = this.href.replace(window.location.host, "").replace("http://", "");
$("body").append("<img src='" + dir + filename + "'>");
});
}
});
taken from:
How to load all the images from one of my folder into my web page, using Jquery/Javascript
I am trying to use jquery to take a picture from my comp via a form.
- So I want the entire URL out of the form in an array
It works + / - in Dreamweaver, but not in the explorer browsers not even chrome
The end goal is a calendar with picture / app for people with disabilities, but as long as I get to go through the phone gap
var foto= new Array();
var i=-1;
//foto=["toets.png"];
$('#fotouit').append("FOTO UIT");
$('#knop01').click(function(){
$('input:file[name=foto]').each(function(){
//alert($(this).val());
foto.push($(this).val());
foto.forEach( function(){
i++;
$('#fotouit').append(foto[i]);
$('#fotouit').append('<img src=" '+ foto[i] + ' " width="100" height="100" />');
});
});
})
I don't think it is possible to get the URL of the picture in you computer's local filesystem, but you can use Javascript's FileReader API to read the contents of the uploaded file (in your case, the picture). The read contents can be used in the src of the img element as you did in your example code.
This is an in depth explanation of what you're trying to accomplish: https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications
Example:
function handleFiles(files) {
for (var i = 0; i < files.length; i++) {
var file = files[i];
var imageType = /image.*/;
if (!file.type.match(imageType)) {
continue;
}
var img = document.createElement("img");
img.classList.add("obj");
img.file = file;
preview.appendChild(img); // Assuming that "preview" is a the div output where the content will be displayed.
var reader = new FileReader();
reader.onload = (function(aImg) { return function(e) { aImg.src = e.target.result; }; })(img);
reader.readAsDataURL(file);
}
}
Note:
You can use the multiple attribute on a file input to allow selecting many files with one input
You can use the file inputs change event to immediately capture the files rather than providing a second button to click
What I want to implement is:
In the front end, I use the html5 file api to read the file, and then upload the file's content to the php backend using ajax, and it's ok if the filesize is small. However,if the file is big enough, it causes chrome to crash. So I split the large file into chunks using file.slice, when all chunks are uploaded to the php, merge the chunks into a single complete one.
the code is as follows:
the front end:
<style>
#container {
min-width:300px;
min-height:200px;
border:3px dashed #000;
}
</style>
<div id='container'>
</div>
<script>
function addDNDListener(obj){
obj.addEventListener('dragover',function(e){
e.preventDefault();
e.stopPropagation();
},false);
obj.addEventListener('dragenter',function(e){
e.preventDefault();
e.stopPropagation();
},false);
obj.addEventListener('drop',function(e){
e.preventDefault();
e.stopPropagation();
var ul = document.createElement("ul");
var filelist = e.dataTransfer.files;
for(var i=0;i<filelist.length;i++){
var file = filelist[i];
var li = document.createElement('li');
li.innerHTML = '<label id="'+file.name+'">'+file.name+':</label> <progress value="0" max="100"></progress>';
ul.appendChild(li);
}
document.getElementById('container').appendChild(ul);
for(var i=0;i<filelist.length;i++){
var file = filelist[i];
uploadFile(file);
}
},false);
}
function uploadFile(file){
var loaded = 0;
var step = 1024*1024;
var total = file.size;
var start = 0;
var progress = document.getElementById(file.name).nextSibling;
var reader = new FileReader();
reader.onprogress = function(e){
loaded += e.loaded;
progress.value = (loaded/total) * 100;
};
reader.onload = function(e){
var xhr = new XMLHttpRequest();
var upload = xhr.upload;
upload.addEventListener('load',function(){
if(loaded <= total){
blob = file.slice(loaded,loaded+step+1);
reader.readAsBinaryString(blob);
}else{
loaded = total;
}
},false);
xhr.open("POST", "upload.php?fileName="+file.name+"&nocache="+new Date().getTime());
xhr.overrideMimeType("application/octet-stream");
xhr.sendAsBinary(e.target.result);
};
var blob = file.slice(start,start+step+1);
reader.readAsBinaryString(blob);
}
window.onload = function(){
addDNDListener(document.getElementById('container'));
if(!XMLHttpRequest.prototype.sendAsBinary){
XMLHttpRequest.prototype.sendAsBinary = function(datastr) {
function byteValue(x) {
return x.charCodeAt(0) & 0xff;
}
var ords = Array.prototype.map.call(datastr, byteValue);
var ui8a = new Uint8Array(ords);
try{
this.send(ui8a);
}catch(e){
this.send(ui8a.buffer);
}
};
}
};
</script>
the php code:
<?php
$filename = "upload/".$_GET['fileName'];
//$filename = "upload/".$_GET['fileName']."_".$_GET['nocache'];
$xmlstr = $GLOBALS['HTTP_RAW_POST_DATA'];
if(empty($xmlstr)){
$xmlstr = file_get_contents('php://input');
}
$is_ok = false;
while(!$is_ok){
$file = fopen($filename,"ab");
if(flock($file,LOCK_EX)){
fwrite($file,$xmlstr);
flock($file,LOCK_UN);
fclose($file);
$is_ok = true;
}else{
fclose($file);
sleep(3);
}
}
The problem is, after the chunks of the file all being uploaded to the server and merged into a new one, the total file size is smaller than the original, and the merged one is broken. Where is the problem and how to fix it?
Using the readAsBinaryString fn is just bad practice
SendAsBinary is also depricated
Reading the chunks content is just pure dum. Slicing them is enough. xhr.send(blob.slice(0,10))
Slicing is also unnecessary unless the server don't accept such large files (such as dropbox limited REST API)
So if anyone trying to be smart about using worker threads, base64 or FileReader for uploading large files - don't do that, it's all unnecessary.
Only time it's okey to read/slice the file is if you are deciding to encrypt/decrypt/zip the files before sending it to the server.
But only for a limited time until all browser start supporting streams.
Then you should take a look at fetch and ReadableStream
fetch(url, {method: 'post', body: new ReadableStream({...})})
if you just need to forward the blob to the server, just do:
xhr.send(blob_or_file) and the browser will take care of reading it (correctly) and not consume any memory. And the file can be however large the file/blob is
There is a small error in your js script
I noticed that the reader.onprogress event is triggered more times than the xhr load event. In this case some chunks are skipped. Try to increment the loaded variable inside the load function.
function uploadFile(file){
var loaded = 0;
var step = 1024*1024;
var total = file.size;
var start = 0;
var progress = document.getElementById(file.name).nextSibling.nextSibling;
var reader = new FileReader();
reader.onload = function(e){
var xhr = new XMLHttpRequest();
var upload = xhr.upload;
upload.addEventListener('load',function(){
loaded += step;
progress.value = (loaded/total) * 100;
if(loaded <= total){
blob = file.slice(loaded,loaded+step);
reader.readAsBinaryString(blob);
}else{
loaded = total;
}
},false);
xhr.open("POST", "upload.php?fileName="+file.name+"&nocache="+new Date().getTime());
xhr.overrideMimeType("application/octet-stream");
xhr.sendAsBinary(e.target.result);
};
var blob = file.slice(start,step);
reader.readAsBinaryString(blob); }
This Problem is caused mostly by global restrictions of shared Hosts. They often control the amount of data and drop the Connection if Limit is overridden.
I tried this several times and several ways. Always stucking at the same Position. target file was smaller and corrupted. Even taking a smaller file for upload than this size, so that the merged data fits in the limit, the result was OK.
YOu have only one Chance: Get the max size increased, for files to be opened.
Every time you open the target file and write the chunk Content into it, and the size overrides the Limit, the hoster will break the Connection. Example hoster: Strato
Here the Limit is globally set to 16MB. I get max merge-result size double this size. No Chance to override it.
I have an 'browser application' where users should be able to drag and drop local mp3 files to Chrome and should see some mp3 info (without uploading files to server)...
So far, I can successfully read and display mp3 tags (with JavaScript-ID3-Reader library), but I'm struggling a bit with displaying mp3's duration. Is it possible to get that info with js/jQuery only? If not, what would you recommend for resolving this simple problem?
Code I'm using to handle dropping files to browser looks like this:
function initialize() {
var target = document;
if (target === null) {
return false;
}
target.addEventListener('drop', function(event) {
event.preventDefault();
var files = event.dataTransfer.files;
console.log(files);
for (var i = 0; i < files.length; i++) {
processFile(files[i]);
objectURL = window.URL.createObjectURL(files[i]);
console.log(objectURL);
}
}, true);
}
Thanks!
Try this
var audio = new Audio()
audio.addEventListener("timeupdate", function() {
console.log(audio.currentTime)
})
audio.addEventListener("canplaythrough", function() {
console.log(audio.duration)
})
target.on("change", function(e) {
var file = e.currentTarget.files[0]
var objectUrl = URL.createObjectURL(file)
audio.src = objectUrl
$("#duration").html(audio.duration)
})
If you are using latest browsers that support audio tag, you can load the mp3 in an <audio> element and access the duration property via the DOM.
To load a audio file to browser see: window.URL.createObjectURL