38

I'm new to using jsPDF but and for the life of me I can't get any css to apply to this thing! I've tried inline, internal, and external all to no avail! I read in another SO post that since it's technically printing stuff to a file I need a print style sheet, and that didn't work either.

I have a very basic page that I'm just trying to get any CSS to work with: JS:

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript" src="jspdf.js"></script>
<script type="text/javascript" src="./libs/FileSaver.js/FileSaver.js"></script>
<script type="text/javascript" src="./libs/Blob.js/BlobBuilder.js"></script>
<script type="text/javascript" src="jspdf.plugin.standard_fonts_metrics.js"></script> 
<script type="text/javascript" src="jspdf.plugin.split_text_to_size.js"></script>               
<script type="text/javascript" src="jspdf.plugin.from_html.js"></script>
<script>
    $(document).ready(function(){
        $('#dl').click(function(){
        var specialElementHandlers = {
            '#editor': function(element, renderer){
                return true;
            }
        };
        var doc = new jsPDF('landscape');
        doc.fromHTML($('body').get(0), 15, 15, {'width': 170,   'elementHandlers': specialElementHandlers});
        doc.output('save');
        });
    });
</script>

HTML:

<body>
    <div id="dl">Download Maybe?</div>
    <div id="testcase">
        <h1>  
            We support special element handlers. Register them with jQuery-style 
        </h1>
    </div>
</body>

And finally the stylesheet that is external:

h1{
    color: red;
}
div{
    color: red;
}

I'm sure all is getting included correctly, and that there are no errors, already checked all of that. Is there like some extra function I need to call to get the css to work as well? Let me know please! Thanks alot! Any other tips you may have are also appreciated!

EDIT: This is the exact webpage:

<html>
    <head>
        <link rel="stylesheet" href="print.css" type="text/css" media="print"/>
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
        <script type="text/javascript" src="jspdf.js"></script>
        <script type="text/javascript" src="./libs/FileSaver.js/FileSaver.js"></script>
        <script type="text/javascript" src="./libs/Blob.js/BlobBuilder.js"></script>
        <script type="text/javascript" src="jspdf.plugin.standard_fonts_metrics.js"></script>
        <script type="text/javascript" src="jspdf.plugin.split_text_to_size.js"></script>               
        <script type="text/javascript" src="jspdf.plugin.from_html.js"></script>
        <script>
            $(document).ready(function(){
                $('#dl').click(function(){
                var specialElementHandlers = {
                    '#editor': function(element, renderer){
                        return true;
                    }
                };
                var doc = new jsPDF('landscape');
                doc.fromHTML($('body').get(0), 15, 15, {'width': 170,   'elementHandlers': specialElementHandlers});
                doc.output('save');
                });
            });
        </script>
    </head>
    <body>
        <div id="dl">Download Maybe?</div>
        <div id="testcase">
            <h1>  
                We support special element handlers. Register them with jQuery-style 
            </h1>
        </div>
    </body>
</html>
samuraiseoul
  • 2,888
  • 9
  • 45
  • 65
  • Are you getting any errors in your console? Ie. - are all your resources loading correctly? . The reason I ask is because, in my developer environment: "//ajax.googleapis.com" gives me trouble where "h t t p : //ajax.googleapis.com" does not. To that point: could you tell me more about your development stack - ie. how are the pages getting rendered WAMP, MAMP, RoRails, Node? Not sure if any of this is too important, but who knows -- I'd like to see this question get answered. – sdailey Dec 09 '13 at 01:13
  • Everything is getting loaded, It's just a simple .html file, – samuraiseoul Dec 09 '13 at 01:17
  • I think we need all your code, or maybe you can upload it somewhere? Because when I use the code you provided styling works just fine. – Jarno Dec 11 '13 at 08:55
  • Added the full webpage, it pretty much has nothing different. – samuraiseoul Dec 11 '13 at 09:12

4 Answers4

29

I think the problem is that you use media="print" instead of media="screen". Try making two seperate files, one for print and one for the screen:

<link rel="stylesheet" href="print.css" type="text/css" media="print"/>
<link rel="stylesheet" href="screen.css" type="text/css" media="screen"/>

The screen one will contain the styling for the page as seen in a browser. The print one will contain the styling for when you print your page, or in this case saving it as a PDF.

EDIT

I checked the jsPDF website but I think they don't support CSS. You could do something like this to create a document with different text colors though:

doc.setFontSize(22);
doc.setTextColor(255, 0, 0);
doc.text(20, 20, 'This is a title');

doc.setFontSize(16);
doc.setTextColor(0, 255, 0);
doc.text(20, 30, 'This is some normal sized text underneath.');

Put this code right under var doc = new jsPDF('landscape'); in your script.

1615903
  • 32,635
  • 12
  • 70
  • 99
Jarno
  • 653
  • 5
  • 13
  • I just tried this and while it styles the page normally, I still can't get it to style the pdf when I save it as a pdf. :( – samuraiseoul Dec 11 '13 at 19:15
  • I think they don't support CSS, check my updated answer. – Jarno Dec 11 '13 at 20:31
  • 11
    Well, JSPDF is useless to me if I can't apply CSS, do you know of any libraries that let me take a picture of a subset of the DOM? Image or PDF? The format isn't very important if I can capture a sub-element of the dom by Id! – samuraiseoul Dec 13 '13 at 13:26
  • @Samuraisoulification Not on the client-side but CasperJS can take a screenshot of a specific element on a page (http://docs.casperjs.org/en/latest/modules/casper.html#captureselector) on the server-side. – Evan Plaice Dec 17 '13 at 00:27
  • 4
    @Samuraisoulification You could use something like http://html2canvas.hertzen.com/ to take a screenshot and then print it. – liftarn Mar 05 '14 at 09:17
  • i too want to display some css but it is not working did any solution found? i am also not getting image – Mohammad Faizan khan Mar 18 '15 at 08:05
  • @samuraiseoul I think its easy for one to comment than we trying to fix it. JSPDF does work for simple html rendering :) – Johnson Samuel Apr 21 '18 at 12:34
7

you can try this option, that uses jsPDF, html2canvas and html2pdf libraries

from its README:

include this files:

<script src="jspdf.min.js"></script>
<script src="html2canvas.min.js"></script>
<script src="html2pdf.js"></script>

and then you can generate your pdf by running:

html2pdf($('body').get(0), {
   margin:       1,
   filename:     'myfile.pdf',
   image:        { type: 'jpeg', quality: 0.98 },
   html2canvas:  { dpi: 192, letterRendering: true },
   jsPDF:        { unit: 'in', format: 'letter', orientation: 'portrait' }
});
drizzt13
  • 630
  • 6
  • 15
3

You can capture a screenshot with jsPDF, but you'll need html2canvas as well. Use html2canvas to convert the html to canvas and grab the image content. Create an empty pdf with jsPDF and add the html image content into the pdf and save:

html2canvas(*html*, {
  onrendered: function(canvas) {
    const contentDataURL = canvas.toDataURL('image/png')
    let pdf = new jsPDF()
    pdf.addImage(contentDataURL, 'JPEG', 20, 20)
    pdf.save('form.pdf')
  }
})

This will retain all CSS but the quality will suffer a little (blurry).

flashmatrix
  • 185
  • 1
  • 2
  • 6
0

@samuraiseoul We can do complex HTML rendering with domtoimage

private async generatePDF(elemToPrint: HTMLElement): Promise<void> {
 this.printSection = document.createElement('div');
 this.printSection.id = 'printSection';
 document.body.appendChild(this.printSection);
 const dataUrl = await domtoimage.toPng(elemToPrint, {width: elemToPrint.clientWidth, height: elemToPrint.clientHeight});
 const img = document.createElement('img');
 img.src = dataUrl;
 img.alt = 'The Image';
 this.printSection.appendChild(img);
 setTimeout(() => window.print(), 500); //Just give some time to render stuff while playing with @media print css stuff  
}

Here is with the CSS

@media screen {
 #printSection { 
  display: none;
 }
}
@media print {
  #printSection , #printSection *{
   display: block; // We need the * because only if we display all the items inside the printSection to display as block. then only our mighty firefox will render the second page. :) Hey, that's a bug from FF.
  }
}
Fasid Mpm
  • 557
  • 6
  • 10