Reputation: 35
Argument 'link' is an array of images' links.
function genPDF_fromUrl(link) {
var doc = new jsPDF();
doc.setFontSize(40);
doc.text(80, 25, 'MAP001');
const rtnimg = compute(doc, link);
console.log(rtnimg)
Promise.all(rtnimg).then((success) => {
doc.save("map.pdf");
});
console.log("Finish hello PDF!")
}
function compute(doc, link) {
return link.map(l => {
let x = 0;
let y = 0;
x += 10;
y += 10;
return new Promise((resolve, reject) => {
var genImg = new Image();
genImg.setAttribute('crossOrigin', 'anonymous');
genImg.src = l;
console.log("genimg: ", genImg);
genImg.onload = function () {
console.log("doc: ", doc);
doc.addImage(genImg, 'PNG', x, y, 100, 100);
}
resolve();
});
});
}
The result is always a PDF with only text 'MAP001', I am not sure why the image would not be shown.
Below is the console output:
genImg: is a img tag like < img crossorigin="anonymous" src="https://cors.now.sh ... a link" >
rtnimg : (33) [Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise]
Finish hello PDF!
doc: {internal: {…}, addPage: ƒ, setPage: ƒ, insertPage: ƒ, movePage: ƒ, …}
Below is my successful attempt of printing only a image on PDF.
function genPDF_fromUrl(link) {
var genImg = new Image();
genImg.setAttribute('crossOrigin', 'anonymous');
genImg.src = link[0];
genImg.onload = function () {
var doc = new jsPDF();
doc.setFontSize(40);
doc.text(80, 25, 'MAP001');
doc.addImage(genImg, 'PNG', 0, 0, 100, 100);
doc.save("map.pdf");
}
}
Seem like "var doc = new jsPDF();" has to be in onload function but I cannot do that for multiple images.
Upvotes: 1
Views: 4923
Reputation: 7677
You are starting the PDF creation, and then waiting for each image. Instead of doing such way, my proposal is to preload all images and wait for a callback when all images have been downloaded and are ready to print in jsPDF by invoking the addImage
function.
I did it in following way some time ago, as a part of a more complex jsPDF plugin
function Picture(src) {
this.src = src;
this.img = null;
}
function Preloader() {
this.pictures = [];
this.onpicturesloaded = null;
}
Preloader.prototype.setPicture = function(src) {
var id = src.split("/").pop().split(".")[0].toLowerCase();
this.pictures[id] = new Picture(src);
return this.pictures[id];
};
Preloader.prototype.loadPictures = function() {
var self = this, pictures = self.pictures, n = 0;
for(var id in pictures) {
if(pictures.hasOwnProperty(id)) {
var pic = self.pictures[id];
n++;
}
}
for(var id in pictures) {
if(pictures.hasOwnProperty(id)) {
var pic = self.pictures[id];
var decrease = function(e) {
if(--n == 0) {
self.onpicturesloaded();
}
}
var img = new Image();
img.onload = function() {
var pic = self.pictures[this.alt];
pic.img = this;
decrease();
};
img.alt = id;
img.src = pic.src;
}
}
};
I'm using the stripped filename as ìd
to get directly the associated image, for that reason there is this slightly overhead of the double loop inside the loadPictures
function, if you find this too bad, feel free to change it to a true array, where you can get directly the picture count as pictures.length
.
This id
is then also used in jsPDF as alias
for each image, to speed up the whole process, whereby the full image path is stored instead in picture.src
.
This is (more pr less) the usage of all that stuff above:
var pl = new Preloader();
pl.setPicture("pdf/a.jpg");
pl.setPicture("pdf/b.jpg");
pl.setPicture("pdf/c.jpg");
pl.onpicturesloaded = function() {
var doc = new jsPDF();
var pic = pl.pictures["a"];
doc.addImage(pic.img, "jpg", 10, 10, 100, 100, pic.img.alt, "FAST");
// add more images, print text, and so on
doc.save('mydocument.pdf');
};
pl.loadPictures();
Please note, this is just an extract on-the-fly of that jsPDF plugin, without some parts which i needed for example, to draw inside a canvas
and add on the fly the picture data to the PDF.
So, I am sure this can be further simplified and stripped down, but anyway, you can get the idea.
Upvotes: 1