Jspdf: addImage produces an blur or too low quality image in the pdf

Created on 25 May 2016  ·  59Comments  ·  Source: MrRio/jsPDF

I am using the latest version of jsPDF 1.2.61, While adding an image it adds an blur image even though the image is of high quality, if I the same base64 in on-line decoder it produces the perfect image as the original, but the base64 produces low quality when I use addImage functionality of jsPDF.

Snippet:

var doc = new jsPDF('landscape');
var Imagebase64=null;
doc.setFontSize(20);
doc.text(35, 25, "GoodYear");
var Imagebase64='data:image/jpeg;base64,/';
doc.addImage(imagePath, 'jpeg',0, 5, 210, 35);
doc.save("mypdf.pdf");

Bug addimage.js

Most helpful comment

I am using jspdf version 1.5.3 and the problem persists.

All 59 comments

I'm seeing the same thing. I just migrated to 1.2.61 from 1.0.272 (I didn't change anything else in my code) and images and texts drawn on canvas get very blurred when it gets pushed to pdf. This seems different then my previous results.

Canvas in browser.
tubenotcherissue_canvas

PDF extract.
tubenotcher_pdf_test

The pixel mapping from canvas to pdf seems off a bit. Oh, and for reference: each of those top 'tick' marks is spaced exactly 1" from each other.

Don't get me wrong, this is an awesome product, and I'm more than grateful. I will say with this many open issues, I'm feeling mighty guilty for not pitching in and trying to close out an item or two. I will say I found this product pretty confusing on the code side.

And for reference, here's the actual site. Its something custom bike frame manufacturers or custom off-road hobbyists would use. http://dogfeatherdesign.com/ttn_js

Same problem here when adding an image from a canvas. I can confirm that image quality looks good in 1.0.272, but is very poor in 1.2.61. I see the issue for both PNG and JPG.

I'm too getting the same issue.

confirmed in 1.2.61, but only for PNG, JPEG quality is ok but with black background:

the png in 1.0.272 looks like:
old version pn

the png in 1.2.61 looks like:
new version pn

the jpeg in 1.2.61 looks like:
new version jpeg

Same issue here, good quality on 1.0.272 and average/low quality on 1.2.61, both JPG as PNG.

in prerelease 1.1.135, the quality is ok

Same issue on 1.2.61

+1 Same issue for me

Use below code, it will help you in clearing blur image:

$scope.doc.internal.scaleFactor = 1.55;

@bhavik4748 tested with the line, the image quality is slightly improved, but still very poor(aliasing), can not be used in production.

png in 1.2.61

Anyway many thanks.

same issue for me on 1.2.61
@bhavik4748 thanks that really helped, I've found it better to do doc.internal.scaleFactor = 1.33;

try scalefactor of 1.7 or 1.8, image will be small be would be more precise.

Still getting the same problem even after using the scaling line

@Sketched360 ,

notice that you should set right mimetype for the images ("image/jpeg" , "image/png")

I debugged versions 1 and 2 side by side, and came to the conclusion that this is caused by an undocumented change to the jsPDFAPI.arrayBufferToBinaryString function (line 4267 in the jspdf.debug.js). In this function, the following lines have been added:
if('TextDecoder' in window){ var decoder = new TextDecoder('ascii'); return decoder.decode(buffer); }
Commenting these out and the correct way of rendering the PNG is restored. I'm not sure why it's in there, or why it causes this problem, but at least there's a workaround.

@jalgithub Nice find. Thanks!

@jalgithub thx. Work fine

@bhavik4748 where do I insert that line of code? in jspdf.debug.js or in my own code?

@burtontanner Read my comment above to properly restore the old working.

@jalgithub Those lines are commented out in the version of jspdf that I have and the final image is still blurry. I am just searching to see if there is anything else that I can do.

@burtontanner Mmm, that's weird, especially since it worked for me and two others at least. Must be something else then... The line @bhavik4748 is talking about (the scaling factor) can be in your code.

v1.3.2 of jsPDF has been updated with the lines @jalgithub mentioned commented out, so you don't have to manually change it. Increasing the scaleFactor does improve text quality, although things such as radio buttons still appear a bit blurred. any updates on a viable solution?

Still looking for Solution
Using Cdn still, don't fix the issue.

I have the same error, quality is really poor, i tried the code, always the same. is there any other solutions?

any news about it ?

Still having trouble. It doesn't look like anyone is actively working on this though. We have taken out the code from: jsPDFAPI.arrayBufferToBinaryString and tried the other scaleFactor items without success.

@CaptBli - I'm not sure what you have tried exactly, but removing line 4268-4271 (debug version) worked for us, which is this code:

    if('TextDecoder' in window){
        var decoder = new TextDecoder('ascii');
        return decoder.decode(buffer);
    }

The only other change we made seems non-related, viz. lines 9481-9485 caused an exception on the require, so we removed those as well. It's this code:

    try {
        var buffer = require('buffer');
        if (typeof buffer.Buffer === 'function')
            _Buffer = buffer.Buffer;
    } catch (error) {}

(Dunno why the catch didn't work, it's quite a while ago and I'm no JavaScript expert.)

This fork for me, i use html2canvas

downloadFile() {
let pdfName = "licencia";
var doc = new jsPDF({
format: "a4"
});

  html2canvas(document.getElementById("pdf-doc"), {
    scale: "5"
  }).then(canvas => {
    console.log("Capturando");
    this.imgFile = canvas;
    doc.addImage(this.imgFile, "JPEG", 5, 5, 200, 285);
    doc.save(pdfName + ".pdf");
  });
}

I had the same Issue : I had an image of (96 DPI) generated from canvas
1 -I change it to 600 DPI by seting the dpi on the canvas using this function found here

function setDPI(canvas, dpi) {
            // Set up CSS size.
            canvas.style.width = canvas.style.width || canvas.width + 'px';
            canvas.style.height = canvas.style.height || canvas.height + 'px';

            // Resize canvas and scale future draws.
            var scaleFactor = dpi / 96;
            canvas.width = Math.ceil(canvas.width * scaleFactor);
            canvas.height = Math.ceil(canvas.height * scaleFactor);
            var ctx = canvas.getContext('2d');
            ctx.scale(scaleFactor, scaleFactor);
     }

2- in AddImage define width and height of image converted to the unit choosen in jsPDF (in my case px to mm) .

doc.addImage(this.imgFile, "JPEG", 5, 5, convertedImageWidth, convertedImageHeight);

Using Jspdf fromHTML image size different in pdf, Any solution?

https://github.com/MrRio/jsPDF/issues/762#issuecomment-399024074
The answer of shaouari is perfectly working for me, I also had an image generated from canvas. I have absolutely perfect images now.

Guys I am using Version 1.4.1 of jsPDF, i was led here in my pursuit of answer to this problem that's haunting, i have tried everything that's been written here but nothing seems to be working for me! What is the actual and conclusive answer to this image blurriness that's generated by jsPDF? Please, please please somebody save me, anyone!
Regards

I lack of an example. If I had an example I could look into it.

I meet the same issue.
Is there any good solution?

I tried shaouari's solution,but I got a blank canvas.

I am very anxious. Who can help me.

Where's the mistake???

function setDPI(canvas, dpi) {
    console.log('0',canvas.toDataURL()); // **I's normal.**
    var scaleFactor = dpi / 96;
    canvas.width = Math.ceil(canvas.width * scaleFactor);
    canvas.height = Math.ceil(canvas.height * scaleFactor);
    console.log('1',canvas.toDataURL()); // **Canvas becomes blank.** ?????
    var ctx = canvas.getContext('2d');
    ctx.scale(scaleFactor, scaleFactor);
}
function save(canvas, fileName = "dashboard.pdf") {
  setDPI(canvas, 100)
  var ctx = canvas.getContext('2d');
  ctx.scale(2,2);
  const contentWidth = canvas.width;
  const contentHeight = canvas.height;
  const pageData = canvas.toDataURL('image/png', 1.0);
  const rotate = ['l', 'p'][(contentWidth < contentHeight) + 0];
  const pdf = new jsPDF(rotate, 'mm', [contentWidth, contentHeight]);
  pdf.addImage(pageData, 'png', 0, 0, contentWidth, contentHeight);
  pdf.save(fileName);
}

Do you realize you are calling ctx.scale() twice, the first time from within setDPI() and the second time from within save(). And you are using dramatically different scaling factors.. first time 100/96 and the second call is using a scale factor of 2. Remember javascript is asynchronous. . My guess those two calls are futzing stuff up after a millisecond delay.

It might be fun to add a bunch of console.log messages after each step, in those two functions so you can see the actual order of what's going on. console.log("setDPI, Line 1") and console.log("save, Line 1")

function setDPI(canvas, dpi) { 
     console.log('0',canvas.toDataURL()); // **I's normal.** 
     var scaleFactor = dpi / 96; 
     canvas.width = Math.ceil(canvas.width * scaleFactor); 
     canvas.height = Math.ceil(canvas.height * scaleFactor); 
     console.log('1',canvas.toDataURL()); // **Canvas becomes blank** ???? 
     var ctx = canvas.getContext('2d'); 
     ctx.scale(scaleFactor, scaleFactor); 
}

function save(canvas, fileName = "dashboard.pdf") { 
     setDPI(canvas1, 100)                     // <----- canvas1  ?
     var ctx = canvas.getContext('2d'); 
     ctx.scale(2,2); 
     const contentWidth = canvas.width; 
     const contentHeight = canvas.height; 
      const pageData = canvas.toDataURL('image/png', 1.0); 
     const rotate = ['l', 'p'][(contentWidth < contentHeight) + 0];// l 横向, p 纵向 
     const pdf = new jsPDF(rotate, 'mm', [contentWidth, contentHeight]); pdf.addImage(pageData, 'png', 0, 0, contentWidth, contentHeight);// 添加图片 
     pdf.save(fileName);// 导出 
}
  1. See how this is easier to read?
  2. What is the difference between canvas and canvas1 ? those two things are not equal....
  3. Frankly this kind of question might be better answered in StackOverflow..
    I apologize for being kinda rude... but do you see how the formatting stuff to make it really pretty makes it easier to understand what the code is doing? no offense intended. I know you are just learning this stuff, us. too.

Thank you anyway.

@catherinezhxj
1 - you don't have to use scale two times setDpi is doing the job
2 - try to use setDpi(canvas , 192) , instead of 100
3 - you are using jsPDF in MM and the ContentWidth + ContentHeight is in px , you should convert to mm try this to convert px to mm ( Math.round((ContentWidth * 25.4) / 96);)

if you still have the issue can you please share a JsFiddle I may help you to solve this issue

With my application i get the PDF i want it is just blurry, where can i improve my code to get clear PDF?
Thank you
My code is as follows:

           function genPDF()
               {
                html2canvas(document.getElementById("invoicing"), {
                onrendered: function(canvas){

                var img=canvas.toDataURL("image/png");
                var doc=new jsPDF();
                doc.addImage(img, 'PNG', 20, 20);
                doc.save('Invoice for {{=invoice.Room.Room_Number}}.pdf');
                 }
                });
                }
              </script>

Not sure if this is happening to anyone on this thread but I was using the jsPDF library in conjunction with html2canvas and found that if I placed the jsPDF script include _after_ the html2canvas script I was getting blurry images as well. At the time I was troubleshooting the issue, the jsPDF library included an earlier version of the html2canvas library that had blurry image issues and it was overriding the version I was including. jsPDF might be using the new html2canvas library now, I'm not sure. To fix this, just make sure the html2canvas library is the latest version and it is included in your scripts after the jsPDF library is loaded.

When i click my download link for the code below:

<script type="text/javascript">
    function genPDF()
    {
        html2canvas(document.getElementById("invoicing"), {
        onrendered: function(canvas){
        var img=canvas.toDataURL("image/png");
         var doc=new jsPDF();
         doc.addImage(img, 'PNG', 10, 10);
         doc.save('Invoice for {{=invoice.Client_Surname}} {{=invoice.Client_Name}}.pdf');
            }
        });
    }
  </script>

I get the following message in my web developer console and no pdf:

0ms html2canvas: onrendered option is deprecated, html2canvas returns a Promise with the canvas as the value html2canvas.js:2688:17
160ms html2canvas: Document cloned, using computed rendering html2canvas.js:2674:17
160ms html2canvas: Starting node parsing html2canvas.js:2674:17
189ms html2canvas: Finished parsing node tree html2canvas.js:2674:17
190ms html2canvas: Finished loading 0 images
Array []
html2canvas.js:2674:17
190ms html2canvas: Starting renderer html2canvas.js:2674:17
190ms html2canvas: Canvas renderer initialized (700x681 at 333,417) with scale 1 html2canvas.js:2674:17
198ms html2canvas: Render completed

Please Help me!!! What am i doing wrong???!!!

Hi Ira,
This topic is specifically about the blurry image problem. It's _not_ a generic "please help me" topic. Please start a new topic if you have different questions.

I did stipulate that I'm getting a blurry PDF in my 2nd comment above & i hoped to get some help, i tweaked up my code & did not get anything that's when i posted the _"please help me"_ comment but thanks anyway.

TBH I tried to cut out the canvas code out of addimage.js and have direct file actions. Thus avoiding the problems we have here. If you do a build of the snapshot you will maybe have no blurry images anymore. I will do some final changes this weekend and then post a snapshot of the build to test.

Did necessary changes to avoid the internal use of canvas, #2140. Canvas is now used if the supplied imagedata is a canvas element or if the file you want to load can not be loaded by the file loading algorythm. But if you anyway cant load the file with the file loading algorythm, you will get anyway a tainted canvas error.

If you use canvas element to supply images, to jsPDF you should increase the dpi/scale and then supply the jpeg-dataurl from the canvas to addImage.

Will supply later a snapshot build.

@irathegod
If you use latest html2canvas you have to handle the result as a Promise.

For my solution I used @nats-afs solution above & it worked like a charm, thak you very very very much @nats-afs, my PDFs are clear as day.

This fork for me, i use html2canvas

downloadFile() {
let pdfName = "licencia";
var doc = new jsPDF({
format: "a4"
});

  html2canvas(document.getElementById("pdf-doc"), {
    scale: "5"
  }).then(canvas => {
    console.log("Capturando");
    this.imgFile = canvas;
    doc.addImage(this.imgFile, "JPEG", 5, 5, 200, 285);
    doc.save(pdfName + ".pdf");
  });
}

Thanks alot, nice one mate, solved my problem after weeks of struggling!

Hello @irathegod

It seems like that your problems described have nothing to do with the problem discussed in this issue.
If you need to extend your knowledge about JavaScript you should read about the Promise technology, as mentioned before.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises

Please stop hijacking this thread, which is about addimage issues and not about the lack of basic JavaScript knowledge, which can be googled in 5 minutes.

Hello @irathegod

It seems like that your problems described have nothing to do with the problem discussed in this issue.
If you need to extend your knowledge about JavaScript you should read about the Promise technology, as mentioned before.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises

Please stop hijacking this thread, which is about addimage issues and not about the lack of basic JavaScript knowledge, which can be googled in 5 minutes.

Thank you Mr @arasabbasi for your cordiality and courtesy, I wish you all the best in all your life endeavors taking into consideration your overwhelming knowledge & understanding in all things, your etiquette will take you far & beyond I promise!

Hello @irathegod

I understand the sarcasm of your post. If you think I violated the code of conduct of this project, you are free to report me to James.

Fact is that a good amount of people have subscribed this thread and want to be informed about the progress.

From now on off-topic will be deleted.

Tonight I will finally supply a snapshot build and I hope soms people will test it.

@jalgithub
@BrianMikinski
@shaouari
@zipzit
@Balaji-Gopal

And all others who maybe still interested in the issue:

Here is a snapshot/nightly build of the dist files.

https://github.com/MrRio/jsPDF/issues/1819#issuecomment-448051429

Can you test if it works for you?

Changes released in v. 1.5.2

I am using jspdf version 1.5.3 and the problem persists.

On my side, it looked like the _presisting_ problem was with the canvas I used, not with jsPDF itself. When I set the scale to 5 in the canvas generation with html2canvas, I get a very crisp image in the PDF. However, the PDF file gets substancially larger so I figured 3 was a good tradeoff.

see https://github.com/MrRio/jsPDF/issues/762#issuecomment-392837680

Don't expect this to be "one line / one minute" fix. Since the default scale is 1 (on my device that is), and I specify 3 for the scale, 1 px on the screen does not equal 1 px on the canvas anymore so some additional calculations were needed to adjust positions and sizes.

Hope this helps.

Here is my code, and I got the same problem with version 1.5.3 too:

      html2canvas(doc.getElementsByTagName('html')[0]).then(canvas => {
            if (window.fsscConfig.debugPrint) {
                document.body.appendChild(canvas);
                canvas.style.position = 'absolute';
            }

            let contentWidth = canvas.width;
            let contentHeight = canvas.height;
            // 一页pdf显示html页面生成的canvas高度
            let pageHeight = contentWidth / 592.28 * 841.89;
            // 未生成pdf的html页面高度
            let leftHeight = contentHeight;
            // a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
            let imgWidth = 595.28;
            let imgHeight = 592.28 / contentWidth * contentHeight;
            var position = 0;
            let pageData = canvas.toDataURL('image/jpeg', 1.0);
            let pdf = new jsPDF('', 'pt', 'a4');
            // 有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
            // 当内容未超过pdf一页显示的范围,无需分页
            if (leftHeight < pageHeight) {
                pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight);
            } else {
                while (leftHeight > 0) {
                    pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight);
                    leftHeight -= pageHeight;
                    position -= 841.89;
                    if (leftHeight > 0) {
                        pdf.addPage();
                    }
                }
            }
            // let pdf = new jsPDF('', 'mm', [canvas.width, canvas.height]);
            // pdf.addImage(pageData, 'png', 0, 0, canvas.width, canvas.height);

            let newServer = server.webServer || server.server;
            let parm;
            // 判断是否以/结尾
            if (newServer.charAt(newServer.length - 1) === '/') {
                parm = `${newServer}#/printToPdf?TOKEN=${sessionStorageUtil.get('TOKEN') || ''}&MenuId=${sessionStorageUtil.get('menuId')}&rdm=${Math.random() * 10}`;
            } else {
                parm = `${newServer}/#/printToPdf?TOKEN=${sessionStorageUtil.get('TOKEN') || ''}&MenuId=${sessionStorageUtil.get('menuId')}&rdm=${Math.random() * 10}`;
            }
            let src = pdf.output('datauristring');
            localStorageUtil.set('billPrint', src);
            let browserInfo = getBrowserInfo();
            if (browserInfo.type === 'IE' && browserInfo.version !== 'edge') {
                pdf.save('打印.pdf');
            } else {
                window.open(parm);
            };
        });

Same issue still available on 2.1.1

any update?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Pinank picture Pinank  ·  3Comments

tarekis picture tarekis  ·  4Comments

MelanieCroce picture MelanieCroce  ·  4Comments

0721Betty picture 0721Betty  ·  4Comments

baluMallisetty picture baluMallisetty  ·  4Comments