-
Notifications
You must be signed in to change notification settings - Fork 4.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
addHTML image quality #339
Comments
I found out why the image quality is so bad and made myself a work around. Basically the image quality suffers every time you use the canvas method "drawImage", especially if you modify the size of the image (increasing or reducing the size doesn't matter). In the .addHTML() code, the logic was as follows: If you don't have the option pagesplit it will only render one pdf page. It will take the image / canvas you provide it and pass it straight through to the pdf.addImage() method. No other canvases at scaled sizes are created. If you do have that option enabled, it will create a canvas at whatever scale will match the pdf size, then draw the scaled image to that canvas. Then it'll pass data through to the pdf.addImage() method. Creating the additional canvas at a scaled size with a scaled image dramatically reduced the image quality. ** the workaround Here's the pseudo-code:
Here's the actual code (slightly modified but should still work):
|
Could you show some examplary usage of your functions? Som JsFiddle or something like that? I am trying to use them, but they are not working for me. Thanks |
Here you go @bhaal275 Here's a test page I whipped up quickly: http://run.plnkr.co/ZGk13nBcOi3XFW6n/ Just a couple side notes: Export 2: This is my workaround. It seems to work a lot better than export #1. For whatever reason, it is also showing a few style issues. Those aren't showing up in my actual implementation. |
Hi, Thanks for your answer. It looks it solves my problem as well, so I tried incorporating this approach. Unfortunately, for some reason addImage method work reeealllllyyy slow on IE 8 with Chrome Frame 23 (corporate requirements). Do you have any idea what might be the issue? |
@bhaal275 hmmm that seems pretty weird. I might have some time later to tinker with it but I don't think it'll be a quick fix. Hopefully I'll be able to come up with something worthy of a pull request and get it implemented in jsPDF so we don't need these workarounds. |
@bpmckee It would be great if you would be able to work on that. I was investigating the issue further, and from what I saw the problem is here: https://github.com/MrRio/jsPDF/blob/master/jspdf.plugin.addimage.js#L539 on line 539. I might be wrong here, but I think that it is just too memory intensive for the browser to append PNG like that. Maybe the images are too big. Another idea is that maybe the parameters that you pass to "addImage" make it so slow. Having a look here:https://github.com/MrRio/jsPDF/blob/master/jspdf.plugin.addhtml.js#L89 especially at lines: var args = [obj, x,y,w,h, format,alias,'SLOW'];
this.addImage.apply(this, args); I am wondering what is |
I'm thinking it might have something to do with that. Those parameters are for compression. I set it to "NONE" because theoretically it should give you the best image quality, but I haven't seen any of that code so I couldn't say that for sure. |
I tested it with new lines: var alias = Math.random().toString(35);
pdf.addImage(newCanvas, 0, 0, pdfPageWidth, 0, 'png', alias, 'SLOW'); And it started working faster, now without any major browser freezes or crashes. It seems to be the solution. Now my last problem is that this configuration works great in newest chrome, but it has errors in Chrome 23 (corporate support). In this version, with multi-page pdf's it prints only one page. The problems seems to be somewhere at the line: var newCanvas = canvasShiftImage(canvas, totalPdfHeight); Where on the first page it generates proper PDF page, but on the second run it generates an empty PDF. Any ideas what might be the issue? Something looks like a bug here? |
The problem occurs here: ctx.drawImage(img, 0, shiftAmt, img.width, img.height, 0, 0, img.width, img.height); For some reason when this line is invoked on the second page of PDF (second page of PDF is drawn on canvas), the output canvas has correct dimensions, but is totally blank. For some reason no content is placed there in chrome 23, no idea why... |
I finally managed to fix it. I got rid of var canvasShiftImage = function(oldCanvas,shiftAmt){
shiftAmt = parseInt(shiftAmt) || 0;
if(!shiftAmt){ return oldCanvas; }
var newCanvas = document.createElement('canvas');
newCanvas.height = oldCanvas.height - shiftAmt;
newCanvas.width = oldCanvas.width;
var ctx = newCanvas.getContext('2d');
Pixastic.process(oldCanvas, "crop", {rect: {left: 0, top: shiftAmt, width: oldCanvas.width, height: (oldCanvas.height - shiftAmt)}}, function (newCanvas) {
ctx.drawImage(newCanvas, 0, 0, newCanvas.width, newCanvas.height, 0, 0, newCanvas.width, newCanvas.height);
});
return newCanvas;
}; |
That's awesome! Sorry i didnt get to it yesterday. Had a lot to do at work. That sounds like a good solution because thats exactly what that canvasShiftImage does. Im surprised the pseudo canvas drawImage crop method didnt work in chrome 23 though. Im curious so ill look into that and see if theres a way to get it working without Pixastic. But glad you found a solution! |
If you would find something, post it here, thanks. |
Also, I created an angularJS module for printing webpages to PDF ngPrint available at: https://github.com/bhaal275/ng-print I used your code as print service to cooperate with jsPDF, I hope you don't mind? |
Haha awesome! I don't mind at all, that's what open source is all about! |
Great, if you have any ideas how to improve it, just leave a note. |
Thanks for the reply @diegocr :) I was playing around with a fork of that plnkr again to try and fix all of the other issues (super slow processing time, large file size, only exporting the first page in firefox). I also updated the logic to make a lot more sense. Sadly, firefox is being a huge pain. It seems to be hit and miss for when the drawImage canvas method wants to work. There are super weird things like this:
Things like that which don't make any sense at all. Maybe it just doesn't like plnkr.co because it's in an iframe, but that's just a wild guess. I'll play with it some more but I don't know how realistic it will be to get it to work with the weird issues I've seen so far. |
@bhaal275 http://plnkr.co/edit/iY9KmzL4Fmx0cZdPXO7c If everything checks out I'll try to cleanup a little bit of stuff and submit a pull request. |
Hi Guys, Sorry for a late response, I was out on holiday. I will try the new plunkr on Monday when I will be back at work. Though I wouldn't worry so much about my issues, I do have a workaround implemented there, and it is just a corporate requirement to support an old Chrome Frame 23, which I hope will be abandoned by the end of the year. Anyhow, I will let you know my results on Monday. Cheers. |
Hi, Sorry for the late response. I just tried to check your example on Chrome Frame 23, but noticed that plunkr does not support Chrome Frame, so I can't test it, without wiriting a separate example. As I told above, in such a case I would just loose support for Chrome Frames all together, as the product is officially no longer supported by Google. |
No worries! I have been swamped at work lately and haven't had enough time to do a good implementation. Hopefully I can find some time this week. |
Hmmm for whatever reason, when I tried my plnkr again, the text appears to be blurry. :( |
I tried it as well just now, and got the same effect. Maybe the page is somehow extrapolated to a bigger image? What browser do you use? |
I am currently using the latest version of Chrome (37) to do most of my testing. The solution I'm going to end up using (until I have a lot of time to dig through the code and see why it's not working well anymore is) is this:
(NOTE: converting the canvas to a Blob, then from a blob to an image cuts my file size down from 10+ MB to around 600kb with the same quality. Unfortunately it requires the canvas-toBlob.js polyfill). Here's the new solution I have. (Note: there will no longer be PDF pages, it renders all as one image at whatever size image comes out).
|
But doesn't that break the purpose of exporting the HTML to pdf, if we get one big picture? |
I agree. It's not ideal. I definitely want to take another crack at it. It seems that canvas.toDataURL() is making the image blurry and the file size huge. canvas.toBlob() makes a great image that is teeny tiny. The only problem is, canvas.toBlob() isn't supported in many web browsers. You have to use the canvas_to_blob polyfill. I doubt jsPDF will want yet another 3rd party library buried in their code. |
It's only a polyfil, so it won't even be noticable in some browsers, and in some future it could be removed completely. If users can save multiple MBs on the image size, I guess they would be fine with downloading additional several KBs for a polyfil. |
nvm, my issue has been fixed. Thanks |
I have close to 500 images which will be generated dynamically and those images are in a foreach loop. I have tried adding these images to pdf using addImage and it generated me a pdf of size 15mb and using SLOW param i tried to reduce the size and it worked but unfortunately instead of 500 different images it is showing only one image 500 times. could any one help me in this issue. Thanks in advance! |
Great contribution the problem but the only drawback is that it depends on the size of the screen that is displayed.They have some form of fix |
Great! But as I use an id ? it's possible? I do not have a selector main |
"If I don't use the option "pagesplit", it renders one PDF page in good quality. If I set pagesplit to true, then it renders the entire page but the image quality on each page is dramatically reduced. " Could someone tell me how to fix this? Thanks so much. |
@bpmckee But still I have a problem afer using the export2 codes, the page now is splited, (on PDF)but only on one page 1 I can see conents , on page 2 and page 3 there are blank. Could u pls give me some help? |
I tested the export2 codes with firefox ,IE10+ and chrome, on IE10+ and chrome, all are fine, PDF is properly splited, but on firefox , the output PDF only has contents on page 1, on page 2 or 3 there are blank. Could someone throw some light how to fix it? I just got caught by this issue for quite long time and don't konw how to do. |
@drizzt00s I haven't looked at this issue in a long time, but I remember firefox being a huge pain. I mentioned in one of the comments that there were errors that did not make any sense at all with firefox.
Things were very very strange and all seemed to happen around the canvas.drawImage and canvas.toDataUrl. |
I think I know what's wrong with firefox . in Your method
The problem with method is: when you set img.src = dataURL;, this is asynchronous, so on the next line when the method return img, on firefox the img has not been fully loaded. |
@bpmckee |
@bpmckee |
in the method canvasShiftImage change this line: to: ctx.drawImage(imgPreload,0,shiftAmt,imgPreload.width,imgPreload.height-shiftAmt,0,0,imgPreload.width,imgPreload.height-shiftAmt); It will fix the bug on firefox. All browsers are fine now. |
Does anyone know where pagesplits quality is fixed because i use 1.0.272 and there it is bad, i cant use the newest version because of any other issues, Ok nvm EDIT: |
Ok i found a solution : Use
K <-- to a 7 or 8 example. if you have to scale your content do it on the DOM before "sending" it to the pdf plugin I do it with a clone of the element |
I have found a workaround as well.
|
So has anyone come up with one definitive answer as to how best to use addhtml, output a pdf, and not have it blurry!!? |
I think mine is good enough.
|
Nope, 0% improvement in my single page pdf using your above method. Gunna switch to a new library, try out some server-side solutions I think. |
I had a problem with retina and blurry fonts i solved it with this workaround for A4: |
I solved it with the following steps:
This will resolve the blurry output in most cases. This hack was refused since this hasn't worked for some people.
(used versions jspdf 1.0.272 and html2canvas 0.4.1) Edit: You cannot get around the limits of the canvas for IE (8192px) and FF (16k px) which will lead into a canvas which is exactly at the limit of width or height resulting in another stretched canvas |
Hi Billy and Dominik, Thanks for sharing this method to convert the HTML page to PDF.Above approach worked fine for me :) accept one problem through which I am currently going through. |
Hi Bill and Domnik, I am fetching the images from CMS(Contentful) in my HTML and then trying to generate PDF of that HTML. function downloadPDF() { var canvasShiftImage = function(oldCanvas,shiftAmt){
}; var canvasToImageSuccess = function(canvas){ while(totalPdfHeight < htmlPageHeight && safetyNet < 15){
} var pageName = document.location.pathname.match(/[^\/]+$/)[0]; html2canvas($('body')[0], |
How can one compress the output file? |
`$(document).ready(function () {
Exception occurred: Uncaught (in promise) Invalid unit: px - |
So did anyone find the best solution for rendering html to pdf with good quality? :) I've been stuck with this for a month already. |
We are closing this issue, because we will not support any longer Explaination: Best Regards |
When I use rasterizeHTML to render the page as a canvas, then use jsPDF's addHTML, the image quality is variable.
If I don't use the option "pagesplit", it renders one PDF page in good quality. If I set pagesplit to true, then it renders the entire page but the image quality on each page is dramatically reduced.
Also, I found that the default code was stretching or compressing the images. I made some changes to the code. This is the code from line 1779.
Basically, I added 'scaledHeight' so the drawImage height is normal, then I changed the 'cy' amount.
I also checked already, bypassing the part where it takes the canvas and does .toDataUrl('image/png') does not improve the image quality.
The text was updated successfully, but these errors were encountered: