I am creating a pdf from data on my react web app using jspdf and the autotable plugin. The table on my webpage is made with mui's table components and I use the data in an array to create the pdf very handily with the autotable plugin.
The issue I am having is when I try to add images to the pdf using jspdf.addImage()
it fails. The images load fine on the webpage in <img>
tags. All the images are loaded from external urls. I have tried adding the images in many different ways that I will try to detail below but all of them are done in the didDrawCell
handler property of the autoTable method call. To summarize:
Can some one tell me how to get an image from an external url to work something like this:
const pdf = new jsPDF({ unit: "mm", orientation: "l" });
autoTable(pdf, {
head: [headers],
body: data.map((i) => [
... //all my different column data
]),
didDrawCell: (cellData) => {
if (cellData.section === "body" && cellData.column.index === 0) {
const url = "https://www.someimagesite.com/someimage.jpg"
const dim = cellData.cell.height - cellData.cell.padding("vertical");
const textPos = cellData.cell.getTextPos();
pdf.addImage(url, textPos.x, textPos.y, dim, dim);
}
},
});
pdf.output("dataurlnewwindow");
Thank you in advance for the help!
Here are some things I've tried:
I have tried using the plain url in the method call:
pdf.addImage("https://www.somewebsitewithanImage.com/theimage.jpg", "JPEG", x, y, w, h)
This give back a cors error. It complains that the cors header is missing but this should be no-cors since it is an image.
---
I've tried creating a image element like this:
...
didDrawCell: (cellData) => {
if (cellData.section === "body" && cellData.column.index === 0) {
const url = data[cellData.row.index].pic; //the external url
const textPos = cellData.cell.getTextPos();
const img = new Image(),
canvas = document.createElement("canvas"),
ctx = canvas.getContext("2d");
img.crossOrigin = "anonymous";
img.onload = function () {
ctx?.drawImage(img, 0, 0);
const imgData = canvas.toDataURL("image/jpeg");
pdf.addImage(imgData, "JPEG", textPos.x, textPos.y, 109, 142);
};
img.src = url;
}
},
...
This also fails complaining about cors:
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Unless I take away the crossOrigin line of code and then it gives me this:
Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
at img.onload
---
I've tried making a fetch call for the image and transforming the blob response into something that the addImage method can ingest. This really encapsulate a lot of different things I tried but in general the code looked like this:
...
didDrawCell: (cellData) => {
if (cellData.section === "body" && cellData.column.index === 0) { //adds it to the first column
const url = data[cellData.row.index].pic; //the external url
const dim = cellData.cell.height - cellData.cell.padding("vertical");
const textPos = cellData.cell.getTextPos();
fetch(url, { mode: "no-cors" })
.then((response) => response.blob())
.then((blob) => {
// convert the blob into something usable here.
pdf.addImage(
img,//whatever I get back from above code
"JPEG",
textPos.x,
textPos.y,
dim,
dim
);
});
}
},
...
I've tried converting the blob to a dataUrl by drawing it to a canvas.
I've tried using the blob data to create an image element which I give to the addImage()
I've tried doing a couple different combinations of the above (I've started to lose track)
All the above methods don't explicitly fail but don't add the image to the pdf. ¯\_(ツ)_/¯
- I have also tried adding refs to all of the image tags and using refs to get them into the pdf but this started getting really messy as the table is auto generated from data from an api and not static images on a page.