Add image in pdf using jspdf - javascript

I am using jspdf to convert an image into a PDF.
I have converted the image into a URI using base64encode. But the problem is that there are no errors or warnings shown in the console.
A PDF is generated with the text Hello World on it but no image is added in it.
Here is my code.
function convert(){
var doc = new jsPDF();
var imgData = 'data:image/jpeg;base64,'+ Base64.encode('Koala.jpeg');
console.log(imgData);
doc.setFontSize(40);
doc.text(30, 20, 'Hello world!');
doc.output('datauri');
doc.addImage(imgData, 'JPEG', 15, 40, 180, 160);
}

This worked for me in Angular 2:
var img = new Image()
img.src = 'assets/sample.png'
pdf.addImage(img, 'png', 10, 78, 12, 15)
jsPDF version 1.5.3
assets directory is in src directory of the Angular project root

Though I'm not sure, the image might not be added because you create the output before you add it. Try:
function convert(){
var doc = new jsPDF();
var imgData = 'data:image/jpeg;base64,'+ Base64.encode('Koala.jpeg');
console.log(imgData);
doc.setFontSize(40);
doc.text(30, 20, 'Hello world!');
doc.addImage(imgData, 'JPEG', 15, 40, 180, 160);
doc.output('datauri');
}

maybe a little bit late, but I come to this situation recently and found a simple solution, 2 functions are needed.
load the image.
function getImgFromUrl(logo_url, callback) {
var img = new Image();
img.src = logo_url;
img.onload = function () {
callback(img);
};
}
in onload event on first step, make a callback to use the jspdf doc.
function generatePDF(img){
var options = {orientation: 'p', unit: 'mm', format: custom};
var doc = new jsPDF(options);
doc.addImage(img, 'JPEG', 0, 0, 100, 50);}
use the above functions.
var logo_url = "/images/logo.jpg";
getImgFromUrl(logo_url, function (img) {
generatePDF(img);
});

No need to add any extra base64 library. Simple 5 line solution -
var img = new Image();
img.src = path.resolve('sample.jpg');
var doc = new jsPDF('p', 'mm', 'a3'); // optional parameters
doc.addImage(img, 'JPEG', 1, 2);
doc.save("new.pdf");

You defined Base64? If you not defined, occurs this error:
ReferenceError: Base64 is not defined

I find it useful.
var imgData = 'data:image/jpeg;base64,verylongbase64;'
var doc = new jsPDF();
doc.setFontSize(40);
doc.text(35, 25, "Octonyan loves jsPDF");
doc.addImage(imgData, 'JPEG', 15, 40, 180, 180);
http://mrrio.github.io/jsPDF/

The above code not worked for me.
I found new solution :
var pdf = new jsPDF();
var img = new Image;
img.onload = function() {
pdf.addImage(this, 10, 10);
pdf.save("test.pdf");
};
img.crossOrigin = "";
img.src = "assets/images/logo.png";

I had the same issue with Base64 not being defined. I went to an online encoder and then saved the output into a variable. This probably is not ideal for many images, but for my needs it was sufficient.
function makePDF(){
var doc = new jsPDF();
var image = "data:image/png;base64,iVBORw0KGgoAA..";
doc.addImage(image, 'JPEG', 15, 40, 180, 160);
doc.save('title');
}

if you have
ReferenceError: Base64 is not defined
you can upload your file here you will have something as :
data:image/jpeg;base64,/veryLongBase64Encode....
on your js do :
var imgData = 'data:image/jpeg;base64,/veryLongBase64Encode....'
var doc = new jsPDF()
doc.setFontSize(40)
doc.addImage(imgData, 'JPEG', 15, 40, 180, 160)
Can see example here

First you need to load the image, convert data, and then pass to jspdf (in typescript):
loadImage(imagePath): ng.IPromise<any> {
var defer = this.q.defer<any>();
var img = new Image();
img.src = imagePath;
img.addEventListener('load',()=>{
var canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
var context = canvas.getContext('2d');
context.drawImage(img, 0, 0);
var dataURL = canvas.toDataURL('image/jpeg');
defer.resolve(dataURL);
});
return defer.promise;
}
generatePdf() {
this.loadImage('img/businessLogo.jpg').then((data) => {
var pdf = new jsPDF();
pdf.addImage(data,'JPEG', 15, 40, 180, 160);
pdf.text(30, 20, 'Hello world!');
var pdf_container = angular.element(document.getElementById('pdf_preview'));
pdf_container.attr('src', pdf.output('datauristring'));
});
}

For result in base64, before convert to canvas:
var getBase64ImageUrl = function(url, callback, mine) {
var img = new Image();
url = url.replace("http://","//");
img.setAttribute('crossOrigin', 'anonymous');
img.onload = function () {
var canvas = document.createElement("canvas");
canvas.width =this.width;
canvas.height =this.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0);
var dataURL = canvas.toDataURL(mine || "image/jpeg");
callback(dataURL);
};
img.src = url;
img.onerror = function(){
console.log('on error')
callback('');
}
}
getBase64ImageUrl('Koala.jpeg', function(img){
//img is a base64encode result
//return img;
console.log(img);
var doc = new jsPDF();
doc.setFontSize(40);
doc.text(30, 20, 'Hello world!');
doc.output('datauri');
doc.addImage(img, 'JPEG', 15, 40, 180, 160);
});

In TypeScript, you can do:
private getImage(imagePath): ng.IPromise<any> {
var defer = this.q.defer<any>();
var img = new Image();
img.src = imagePath;
img.addEventListener('load',()=>{
defer.resolve(img);
});
return defer.promise;
}
Use the above function to getimage object. Then the following to add to pdf file:
pdf.addImage(getImage(url), 'png', x, y, imagewidth, imageheight);
In plain JavaScript, the function looks like this:
function (imagePath) {
var defer = this.q.defer();
var img = new Image();
img.src = imagePath;
img.addEventListener('load', function () {
defer.resolve(img);
});
return defer.promise;
};

Related

Uncaught Error: Incomplete or corrupt PNG file

I am trying to add a couple of images to a pdf. I am using the jspdf plugin for this. My code is as following:
document.getElementById("help").addEventListener("click",function(){
var base1="";
var base2="";
var base3="";
var doc = new jsPDF();
var img=new Image();
var img1=new Image();
var img2=new Image();
img.onload = function() {
var canvas = document.createElement("canvas");
ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
base1 = canvas.toDataURL();
}
img.src='/Screenshot (1).png';
img1.onload = function() {
var canvas = document.createElement("canvas");
ctx = canvas.getContext('2d');
ctx.drawImage(img1, 0, 0);
base2 = canvas.toDataURL();
}
img1.src='/Screenshot (2).png';
img2.onload = function() {
var canvas = document.createElement("canvas");
ctx = canvas.getContext('2d');
ctx.drawImage(img2, 0, 0);
base3 = canvas.toDataURL();
}
img2.src='/Screenshot (3).png';
doc.addImage(base1,'PNG',20,36,100,120);
doc.addImage(base2,'PNG',20,158,100,120);
doc.addImage(base3,'PNG',20,281,100,120);
doc.save("example.pdf");
})
But when I execute the code, I get the following error in addImage():
Uncaught Error: Incomplete or corrupt PNG file
How do I fix this?
EDIT: After implementing #AKX's solution, the code works in the local machine. But when tested live, it throws this error:
Uncaught (in promise) Event {isTrusted: true, type: 'error', target:
null, currentTarget: null, eventPhase: 0, …}
You're not waiting for all the images to load. You can refactor things to use a promisified function to load an image and turn it into a data URI (though according to the docs for jspdf, a HTMLImageElement would also do, so you could skip the canvas bit), and then turn your handler into an async function to make it easy to just await for all the loads.
function loadImageAsDataURL(url) {
return new Promise((resolve, reject) => {
var img = new Image();
img.onload = function () {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
resolve(canvas.toDataURL());
}
img.onerror = reject;
img.src = url;
});
}
document.getElementById('help').addEventListener('click', async function () {
// Load all images first...
var base1 = await loadImageAsDataURL("/Screenshot (1).png");
var base2 = await loadImageAsDataURL("/Screenshot (2).png");
var base3 = await loadImageAsDataURL("/Screenshot (3).png");
// ... and then generate the PDF.
var doc = new jsPDF();
doc.addImage(base1, 'PNG', 20, 36, 100, 120);
doc.addImage(base2, 'PNG', 20, 158, 100, 120);
doc.addImage(base3, 'PNG', 20, 281, 100, 120);
doc.save('example.pdf');
})

Find why an Img is failing to load in HTML on a dynamically created image

So I basically generate a giant SVG dynamically and show it on screen. I need to provide the option to print to PDF. Son once the SVG is on screen on the push of a button I do this:
function printReportAsPDF(W,H){
var svg = document.getElementById("report-svg");
var svgData = new XMLSerializer().serializeToString( svg );
//console.log(svgData)
var canvas = document.createElement("canvas");
canvas.width = W;
canvas.height = H;
var ctx = canvas.getContext("2d");
// Internally display the image.
var img = document.createElement( "img" );
//console.log(btoa(svgData));
img.setAttribute( "src", "data:image/svg+xml;base64," + btoa( svgData ) );
img.onload = function() {
console.log("onload");
ctx.drawImage( img, 0, 0 );
var imgData = canvas.toDataURL('image/png');
let doc = new jsPDF();
var PAGE_WIDTH = doc.internal.pageSize.getWidth();
var PAGE_HEIGHT = doc.internal.pageSize.getHeight();
console.log("done");
doc.addImage(imgData, 'PNG', 0, 0, PAGE_WIDTH, PAGE_HEIGHT,"","FAST");
doc.save("report.pdf");
};
img.onerror = function() {
console.log("There was an error loading the image");
}
}
My problem is that even though btoa seems to work fine and svgData is not null and all fo that I get the onerror being invoked rather than the onload being invoked.
How can I know what the problem is here?

Canvas - Save canvas as png and do not show canvas

I did this image with my canvas because I had to modify it and merge two images. However I don't want to show it on my html page but use the url saved of the second canvas in my javascript.
How can I do that ?
Here is my fiddle : http://jsfiddle.net/acbo6m6o/7/
var ctx = document.getElementById('canvas').getContext("2d");
var ctx2 = document.getElementById('canvas2').getContext("2d");
var img = new Image();
img.src = "https://scontent-mad1-1.xx.fbcdn.net/v/t1.0-9/10400072_76198580294_2746326_n.jpg?oh=b8cc93c35d6badfffb65ab5c9cbfce28&oe=5941AAB6";
var img2 = new Image();
img2.src = "https://icc-static-files.s3.amazonaws.com/ICC/photo/2017/01/31/f3a228a9-30ca-453e-99c5-ee6150c714a5/Facebook_Logo.png";
img.addEventListener('load', function(e) {
ctx.arc(150, 150, 150, 0, Math.PI * 2, true);
ctx.save();
ctx.clip();
ctx.drawImage(this, 0, 0, 300, 300);
ctx.restore();
ctx2.drawImage(ctx.canvas, 35, 60, 230, 230);
ctx2.drawImage(img2, 200, 60, 75, 75);
}, true);
var dataURL = canvas2.toDataURL();
var dataURL = canvas2.toDataURL("image/png").replace("image/png", "image/octet-stream");
window.location.href=dataURL; //it save local

Converting images to base64 within a loop before adding to jspdf - javascript

I have researched issues with the base64 conversion and jspdf function quite a bit. ( PS this is my first question on stackoverflow, please bare with any rookie mistakes ).
All seems to work fine with the below code except that the pdf is generated and saved before the loop where the images are converted to base64 and placed to the document is finished. I added a couple alerts to check timing. Would the solution be to check when the loop is finished, the images placed before continuing with the pdf function? if so, how? please help.
$(document).ready(function(){
$("a#getdoc").click(function(){
var doc = new jsPDF('landscape, in, legal');
var myimages = 'img1.jpg|img2.jpg|img3.png';
var myimgarray = myimages.split('|');
function convertImgToBase64(url, callback, outputFormat){
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
return canvas.toDataURL("image/jpeg");
var dataURL = canvas.toDataURL("image/jpeg");
callback(dataURL);
canvas = null;
}
for(var i = 0; i < myimgarray.length; i++)
{
icount.count = i;
var img = new Image();
alert(checkoutimgarray);
img.src = '/Portals/0/repair-images/' + myimgarray[i];
img.onload = function(){
newData = convertImgToBase64(img);
alert(newData);
doc.addImage(newData, 'JPEG', (icount * 100), 10, 70, 15); // would doc be undefined here? out of scope?
};
}
doc.setFontSize(20);
doc.text(100, 20, "This is a test to see if images will show");
doc.save('My_file.pdf');
});
});
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
function convertImgToBase64(img, outputFormat){
// clear canvas
canvas.width = img.width;
canvas.height = img.height;
// draw image
ctx.drawImage(img, 0, 0);
// get data url of output format or defaults to jpeg if not set
return canvas.toDataURL("image/" + (outputFormat || "jpeg"));
}
var images = [];
for(var i = 0; i < myimgarray.length; i++) {
var img = new Image();
img.onload = function() {
images.push({
base64: convertImgToBase64(this),
width: this.width,
height: this.height
});
// all images loaded
if(images.length === myimgarray.length) {
for(var j = 0; j < images.length; j++) {
doc.addImage(images[j].base64, 'JPEG', (j * 100), 10, 70, 15);
}
doc.setFontSize(20);
doc.text(100, 20, "This is a test to see if images will show");
doc.save('My_file.pdf');
}
};
img.src = '/Portals/0/repair-images/' + myimgarray[i];
}

Missing image when saving image from canvas

I use this code to save images in Javascript :
function saveImage() {
var canvas = document.getElementById('myPicture');
var ctx = canvas.getContext('2d');
var img = new Image();
ctx.rect(0, 0, 460, 600);
ctx.fillStyle = 'white';
img = new Image();
img.crossOrigin = 'anonymous';
img.src = "http://localhost/upload/abc.jpg";
ctx.drawImage(img,0,0,_item.width(),_item.height());
return canvas.toDataURL("image/jpeg");
}
When i click button save image:
$("#save").on('click', function () {
var rawImageData = saveImage();
$(this).attr('download', 'your_pic_name.jpeg').attr('href', rawImageData);
});
However the result I get is white image.
And I click on the save button again (ie 2 times) then is now right result. how do I can just click one time only?
Thank you.
It is because the first time you click, anchor doesn't have image data url... You may set the url and forget about the click event.
//$("#save").on('click', function () {
var rawImageData = saveImage();
$(this).attr('download', 'your_pic_name.jpeg')
.attr('href', rawImageData);
//});
OR
$("#save").on('click', function () {
var rawImageData = saveImage();
/*$(this).attr('download', 'your_pic_name.jpeg')
.attr('href', rawImageData);*/
window.location=rawImageData;
});
OR alternatively, you need this file to use following code
var canvas = document.getElementById('myPicture');
function saveImage() {
var ctx = canvas.getContext('2d');
var img = new Image();
ctx.rect(0, 0, 460, 600);
ctx.fillStyle = 'white';
img = new Image();
img.crossOrigin = 'anonymous';
img.src = "http://localhost/upload/abc.jpg";
// ctx.fill...
return canvas.toDataURL("image/jpeg");
}
$("#save").on('click', function () {
var rawImageData = saveImage();
var png= Canvas2Image.saveAsPNG(canvas , true);
});
PS: I don't see where you feel canvas with the image...int the saveImage function

Categories