Currently, I have an array of images like this:
var images = [
"https://www.example.com/1.png",
"https://www.example.com/2.png",
"https://www.example.com/2.png"
];
So what is the best approach to handle the downloading process and also when all images download completed I need an event for that.
You can use fetch
which is a Promise
total = images.length
loaded = 0
progress = 0
progress = () => {
loaded += 1
progress = loaded / total
}
Promise.all(images.map(i => fetch(i).then(progress)))
.then(onComplete)
.catch(onError)
For downloading blob data refer to this question.
Related
I use JavaScript to change the background-image of a div dynamically every 4 seconds. my code looks like this:
const images = [
'img/landing-min.jpg',
'img/gallery-1.jpg',
'img/side-img.jpg',
];
window.onload = () => {
const landing = document.getElementById('landing');
landing.dataset.i = 0;
setInterval(() => {
landing.style.backgroundImage = `url(${images[landing.dataset.i]})`;
landing.dataset.i = (landing.dataset.i+1) % images.length;
}, 4000)
}
The problem is that the browser makes a request to get the file each time the interval changes the background image, which makes a lot of duplicate requests. I want all files to be requested only once.
Here's my code to capture an image from a Canvas playing video:
let drawImage = function(time) {
prevCtx.drawImage(videoPlayer, 0, 0, w, h);
requestAnimationFrame(drawImage);
}
requestAnimationFrame(drawImage);
let currIndex = 0;
setInterval(function () {
if(currIndex === 30) {
currIndex = 0;
console.log("Finishing video...");
videoWorker.postMessage({action : "finish"});
} else {
console.log("Adding frame...");
// w/o this `toDataURL` this loop runs at 30 cycle / second
// so that means, this is the hot-spot and needs optimization:
const base64img = preview.toDataURL(mimeType, 0.9);
videoWorker.postMessage({ action: "addFrame", data: base64img});
currIndex++;
}
}, 1000 / 30)
The goal is at each 30 frames (which should be at 1 second) it would trigger to transcode the frames added.
The problem here is that the preview.toDataURL(mimeType, 0.9); adds at least 1 second, without it the log shows the currIndex === 30 gets triggered every second. What would be the best approach to be able to capture at least about 30 FPS image. What is the fastest way to capture image from a HTML Canvas that it will not be the bottleneck of real-time video transcoding process?
You should probably revise your project, because saving the whole video as still images will blow out the memory of most devices in no time. Instead have a look at MediaStreams and MediaRecorder APIs, which are able to do the transcoding and compression in real time. You can request a MediaStream from a canvas through its captureStream() method.
The fastest is probably to send an ImageBitmap to your Worker thread, these are really fast to generate from a canvas (simple copy of the pixel buffer), and can be transferred to your worker script, from where you should be able to draw it on a an OffscreenCanvas.
Main drawback: it's currently only supported in latest Chrome and Firefox (through webgl), and this can't be polyfilled...
main.js
else {
console.log("Adding frame...");
const bitmap = await createImageBitmap(preview);
videoWorker.postMessage({ action: "addFrame", data: bitmap }, [bitmap]);
currIndex++;
}
worker.js
const canvas = new OffscreenCanvas(width,height);
const ctx = canvas.getContext('2d'); // Chrome only
onmessage = async (evt) => {
// ...
ctx.drawImage( evt.data.data, 0, 0 );
const image = await canvas.convertToBlob();
storeImage(image);
};
An other option is to transfer an ImageData data. Not as fast as an ImageBitmap, it still has the advantage of not stopping your main thread with the compression part and since it can be transferred, the message to the Worker isn't computation heavy either.
If you go this road, you may want to compress the data using something like pako (which uses the compression algorithm used by PNG images) from your Worker thread.
main.js
else {
console.log("Adding frame...");
const img_data = prevCtx.getImageData(0,0,width,height);
videoWorker.postMessage({ action: "addFrame", data: img_data }, [img_data.data]);
currIndex++;
}
worker.js
onmessage = (evt) => {
// ...
const image = pako.deflate(evt.data.data); // compress to store
storeImage(image);
};
i´m using pdfjs to load and merge some pdf files. I know how to show page number of a pdf document, but while merging files, i´d like to show a page number based on total pages of all pdf docs. But because it's asynchronous, just using and increment a counter variable is not working.
var actual_page = 1;
(async function loop() {
for (url_item of urls) {
var loadingTask = pdfjsLib.getDocument(url_item);
await loadingTask.promise.then(function (pdf) {
let i = 1;
while (i <= pdf.numPages) {
var pageNumber = i;
pdf.getPage(pageNumber).then(function (page) {
//render pdf and print actual_page++
});
}
}
}
}
First page show 1, second page show 3, and 2 will appear on page 10 and so it goes.
Thanks in advance.
I think you're going to need Promise.all or some equivalent to get the pages from getPage in the correct order. That might just make your page numbering thing work.
var pagePromises = [];
while (i <= pdf.numPages) {
pagePromises.push(pdf.getPage(i));
i++;
}
Promise.all(pagePromises).then(function (allPages) {
allPages.forEach(page => {
// render pdf and print actual_page++
});
});
});
I'm trying to do what I 'thought' would be a simple task. I have an array of URLs that I'd like to loop through and download on to the client machine when the user clicks a button.
Right now I have a parent component that contains the button and an array of the urls (in the state) that I'd like to loop through and download. For some reason, the way I'm doing it now only downloads one of the files, not all of the contents of the array.
Any idea how to do this correctly within React?
handleDownload(event){
var downloadUrls = this.state.downloadUrls;
downloadUrls.forEach(function (value) {
console.log('yo '+value)
const response = {
file: value,
};
window.location.href = response.file;
})
}
I would use setTimeout to wait a little bit between downloading each files.
handleDownload(event){
var downloadUrls = this.state.downloadUrls.slice();
downloadUrls.forEach(function (value, idx) {
const response = {
file: value,
};
setTimeout(() => {
window.location.href = response.file;
}, idx * 100)
})
}
In Chrome, this will also prompt the permission asking for multiple files download.
How can I store the contents of a folder which consist entirely of images.
I can do it this way.
var files = ["1.jpg","2.jpg",
"3.jpg","4.jpg","5.jpg","6.jpg",
"7.jpg","8.jpg","9.jpg","10.jpg",];
but I'd like to do it more dynamically I'm planning on having 100's of images in the folder.
I'm thinking something like this pseudo code
var images
for i to number_of_items_in_folder
images[i]= image_from_folder
The images are coming from a folder (local) called images
To do this on the client only you will need a trick or a hardcoded value
So
var images = [];
// you tell the script how many and they all have numbers from 0 to here 87
for (var i=0; i<87; i++) {
images.push(i+".jpg");
}
If you do NOT know how many you have, you need to preload them
var images = [],done=false,i=0;
while (!done) {
var image = new Image();
image.onerror=function() {
done=true;
}
image.onload=function() {
images.push(this.src);
}
image.src=i+".jpg";
i++;
}
and if they all have different names, then you need a server script that will build the array for you.