Skip to content
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

Creating PDF from HTML #34

Closed
Ranjith42k opened this issue Sep 25, 2012 · 19 comments
Closed

Creating PDF from HTML #34

Ranjith42k opened this issue Sep 25, 2012 · 19 comments

Comments

@Ranjith42k
Copy link

I am trying to create pdf from html using form_html plugin. But what is "setting" argument in fromHTML API. i got some error when using the below code.

MY actual code is like this.

var htmlString ="<html><body ><label>INPUT TYPE</label></body></html>";
var doc = new jsPDF('landscape','pt');
doc.fromHTML(htmlString,100,100,{});
doc.output('datauri');
@dvdotsenko
Copy link
Collaborator

API (and the internal code) for this plugin is still in development, so, apologies for the rough edges. In this case, "BETA" (as mentioned in the plugin header) really means that - wrong step and it will misbehave.

Take a look at /examples. Look for 'fromHTML' inside 'basic.js' What you might be missing is the "width" parameter, which, at this point, is required for internal logic.

There are a few fixes (which I did not yet push upstream) for this module here https://github.com/willowsystems/jsPDF/tree/master

Again, this plugin is Alpha-ish Beta, so be patient with it. :)

@Ranjith42k
Copy link
Author

Thank you.

@eljeffeg
Copy link

dvdotsenko, noticed your working on this... couple things I had issue with.

Couple things were undefined and causing an issue. Not sure if I fixed them in the right way, but it worked.

css_font_family_string

if (typeof css_font_family_string == "undefined") {
        css_font_family_string = ""
    }

css_line_height_string
I did the following:

    if (typeof css_line_height_string != "undefined") {
        value = css_line_height_string.match( /([\d\.]+)(px)/ )
        if (value.length === 3) {
            // caching, returning
            return UnitedNumberMap[css_line_height_string] = parseFloat( value[1] ) / 16.00
        }
    }

@dvdotsenko
Copy link
Collaborator

@jeffg2k

The code changes are against which repo/branch?

Not everything done by me is pushed to upstream (MrRio's) repo. (Mostly because this pool request, rebase on top of MrRio's merge commit routine is annoying for small, non-urgent commits. Partly because some of the code, especially from_html, is still ugly.)

The link I posted above is to "my" jsPDF repo (https://github.com/willowsystems/jsPDF) and I could not find the offending lines in there. I indeed had some issues with IE giving me undefined values for things that Chrome and others calc the values for. So, it's possible the items you had issue with are already paved over in my repo. Try. I welcome feedback.

@eljeffeg
Copy link

It was from your repo.. the offending lines were:

, parts = css_font_family_string.split(',') // yes, we don't care about , inside quotes

and

value = css_line_height_string.match( /([\d\.]+)(px)/ )

They didn't check for undefined, so it gave me an error when it got to them. So I just put in the check to essentially skip it if they were undefined, which is what the code above was. Sorry for the confusion.

@jcook-logixml
Copy link

I know that the from_html plugin is in active development, but I've implemented a custom renderer for the html2canvas library that translates all of the canvas instructions it generates into instructions for jspdf + addimage plugin.

repo is https://github.com/jcook-logixml/html2canvas/ and renderer is https://github.com/jcook-logixml/html2canvas/blob/master/src/renderers/PDF.js

@dvdotsenko
Copy link
Collaborator

@jcook-logixml

Yeah. html2canvas is very cool. I was looking at it for a long time, thinking about just adopting it, but found the "canvas" side inflexible.

canvas API has no notion of paragraphs, line spacing, etc. There is definitely no way to inject paging. There is no (obvious to me) way to inject custom handlers selected DOM element blocks.

For example, we do contract conversion from browser screen to PDF. Part of the presentation is http://willowsystems.github.com/jSignature/ which is already a chunk of canvas. I don't want it to be drawn as shown. I want the signature data to be exported as SVG and inserted as clean vectors into resulting PDF = custom rendering handler for an inner block of the page.

Custom handlers, paging, font and paragraph control are hard to finetune with html2canvas, as all you get is a "photo" of the page, not its semantic textual representation that is refitted to size of the PDF pages.

So, it is with this profound sadness in my heart i must say that I personally don't see a bright future for "canvas" somewhere in between "html" and "pdf." I am truly sad about this realization as it means I need to write more code and maintain something like fromHTML jsPDF plugin.

@allenmoatallen
Copy link

Do I need to have any eventHandlers defined or does the plugin take care of them by default? It won't let me run it without eventHandlers and if I use the one in your example to keep it from being undefined, I don't get any PDF output to screen, just a white page.

P.S. this is using the from_HTML plugin.

@dvdotsenko
Copy link
Collaborator

@allenmoatallen

The simplest example of from_html implementation is in examples folder. Load examples/basic.html and look at the "text" tab for example.

https://github.com/willowsystems/jsPDF/blob/stable/examples/js/basic.js#L310

The code should work just fine without elementHandlers defined, but I don't remember trying without it :) At worst, you should get by with

pdf.fromHTML(
    source // HTML string or DOM elem ref.
    , 0.5 // x start coord
    , 0.5 // y start coord
    , {
        'width':7.5 // max width of content on PDF
        , 'elementHandlers': {} // <- empty object
    }
)

@antiroach
Copy link

I've been trying for the majority of this weekend to get the from_html plugin to work. Unfortunately, each time I try to call the plugin, I get some sort of a null-related error. I fixed a few, but more popup down the line. So, I am trying to start over from the beginning.

The initial error I receive is "Cannot call method 'appendTo' of null" This is originating in the process() function of the from_html code. Has anyone had this issue? Am I missing something dumb?

I'm working in a cloud platform that has the .min file for jQuery v1.4.4 and NoConflict mode is enabled.

*****NOTE: I have just now been able to circumnavigate this issue. I was forced to declare and initialize variables that are found in the process() function. I'm still not sure why I have to, though. I'm also not sure if this approach will hurt me on down the line somewhere. Here's how the guts of my process() function now looks:

if (typeof element === 'string') {
    element = (function(element) {
       var framename = "jsPDFhtmlText" + Date.now().toString() + (Math.random() * 1000).toFixed(0);
       var visuallyhidden = 'position: absolute !important;' +
            'clip: rect(1px 1px 1px 1px); /* IE6, IE7 */' +
            'clip: rect(1px, 1px, 1px, 1px);' +
            'padding:0 !important;' +
            'border:0 !important;' +
            'height: 1px !important;' + 
            'width: 1px !important; ' +
            'top:auto;' +
            'left:-100px;' +
            'overflow: hidden;';

        framename, 
           visuallyhidden, 
              $j('<div style="'+visuallyhidden+'">' +
            '<iframe style="height:1px;width:1px" name="'+framename+'" />' +
            '</div>'
        ).appendTo(document.body)
        , window.frames[framename]
        return $j(window.frames[framename].document.body).html(element)[0]
    })( element )
 }

var r = new Renderer( pdf, x, y, settings )
, a = DrillForContent( element, r, settings.elementHandlers )

@dvdotsenko
Copy link
Collaborator

@antiroach

The problem you were having originally is the "noConflict" part.

fromHTML assumes global $ is jQuery, while in your case I don't know what it is, Moo? Prototype?

Although $ is used twice in Process(), this line is likely the problem:

https://github.com/willowsystems/jsPDF/blob/stable/jspdf.plugin.from_html.js#L537

It uses jQuery-specific ability to materialize a DOM fragment from a string of HTML. All other toolkits likely don't know what to do with it and just silently continue without creating the actual iframe.

There is nothing technically wrong with my version of Process(), but the whole of jsPDF, or just the fromHTML piece would need to be wrapped into a closure that captures jQuery as $:

;(function($){

    // entirety of jsPDF fromHTML plugin goes here

})(window.jQuery);

I also apologize for my unusual coding style (no semicolons, comma first, one var on top). It helps me tremendously to avoid mistakes, but I see how it confused the crap out of you.

@antiroach
Copy link

@dvdotsenko

No apologies necessary! The formatting didn't confuse me, but it's certainly not what I'm used to viewing. I had to change it for my own sanity.

You're absolutely right. That is the line that caused my issues. I kept trying to work around it with not much luck at first.

What you've pointed out makes absolute sense to me. We use Jelly, so after what you said, I'm quite sure that is the default $. Being fairly new to the client-side of things, I was unaware of that.

Thanks very much for your tips.

@MrRio MrRio closed this as completed Jan 8, 2013
@kurtzarefoss
Copy link

Trying to use the fromHTML plug-in and take control over formatting from the DOM elements passed in via the initial call. I thought hooking in an elementHandler would do it but the code is never getting reached. For example:

    doc.fromHTML($('div.task_list ul.inner_list').get(0), 15, 15, {
        'width': "8in",
        'elementHandlers': specialElementHandlers
    });

    var specialElementHandlers = {
        'li': function(element, renderer){

                    alert('here');
            return true;
        }
    };

The alert never is reached so I can override the formatting via other calls to the APIs. All LI elements are processed via the default behavior. Is what I am trying to do not supported or am I just botching this up?

UPDATE: Looks like you can only do it based on IDs. I change 'li' above to '#test_id' and the code fires. Would be nice if elements or at least classes could be used as selectors (I know this is very early beta).

@dvdotsenko
Copy link
Collaborator

@kurtzarefoss

https://github.com/MrRio/jsPDF/blob/master/jspdf.plugin.from_html.js#L458 :

handlers = elementHandlers['#'+element.id]

Because the matching is done against every element in the node tree, my desire was to make it as fast as possible. In that case, it meant "Only element IDs are matched" The element IDs are still done in jQuery style "#id", but it does not mean that all jQuery selectors are supported.

There is still room for full support of jQuery selectors, but then instead of doing a simple object property look up, the code would need to loop over all special handler selector strings and see if any one matches the elem. So, instead of that one simple line above, we would need something like this:

var elementHandler
Object.keys( elementHandlers ).some(function(selector){
    if ($(element).filter(selector).length) {
        elementHandler = elementHandlers[selector]
        return true
    }
    return false
})

I certainly don't mind having full jQuery selector functionality, but am currently preferring speed for flexibility.

I would not want to have a switch or option for this, as it just complicates the things. I guess what I would prefer if someone finds the most efficient logic for finding a matching selector to an elem. If the overall parsing code's speed is hindered by only some 2-5% I would not see this as a problem.

Daniel.

@jmrezende
Copy link

Hi,

I have a program in .NET 1.1 and I'm trying use the example HTML Renderer, but in IE8 show the error, in javascript debug, 'fof' is null or is not a object. Reference line 48 in jspdf.plugin.split_text_to_size.js: widthsFractionOf = widths.fof ? widths.fof : 1.

My page aspx have only this:

<h1>test</h1>

<input id="Button1" type="button" value="button" onclick="return Button1_onclick()"  /> 

<div id="downloadify"></div>

<div id="editor" class="bypass"></div>

and this is my javascript:


 function Button1_onclick() {
    var doc = new jsPDF();
    // We'll make our own renderer to skip this editor
    var specialElementHandlers = {
        '#editor': function (element, renderer) {
            return true;
        }
    };
    // All units are in the set measurement for the document
    // This can be changed to "pt" (points), "mm" (Default), "cm", "in"
    doc.fromHTML($('body').get(0), 15, 15, {
        'width': 170,
        'elementHandlers': specialElementHandlers
    });
    Downloadify.create('downloadify', {
        filename: 'Simple.pdf',
        data: function () {
            return doc.output();
        },
        onComplete: function () { alert('Your File Has Been Saved!'); },
        onCancel: function () { alert('You have cancelled the saving of this file.'); },
        onError: function () { alert('You must put something in the File Contents or there will be nothing to save!'); },
        downloadImage: 'images/download.png',
        swf: 'images/downloadify.swf',
        width: 100,
        height: 30,
        transparent: true,
        append: false
    });
}

If I delete the tag < h1 > it's work. But in my real case I have much more tags HTML.

This same code works for IE9, but I need that's works IE9 and below.
Could you helpe me?

@sureeebabu
Copy link

how to create dynamic table using jspdf ????.
Anyone please help me out . Im trying for past 3 weeks

@stephaneAG
Copy link

Hi there

I'm pretty new to jsPDF, but after some digging I was wondering if there were any ways to get content ( in my case HTML or SVG ) to PDF WITHOUT rastersizing it ( aka preserve text selection as well as scalable graphics within it ).

From what I get by now, the "rastersizing" comes from using in the plugins used by jsPDF ?

Among other stuff, I tried "printing" to a PDF file using Chrome & the resulting PDF ( whether it contains divs with svg backgrounds or embed svgs ) has the scalability & text selections preserved, as well as the PDF "pages" have the correct dimensions ( set using css @print & @page rules )
While this solutions works, it would be better to have a similar solution that's not browser-dependent & that could save directly to a file ( with or without a file save dialog prompt ) or open the generated document in a new tab/window of the device's browser (..)

I still have to try using the "html with background svg" version with jsPDF, hoping it will preserve the vector aspect of the div background as well as print it on the resulting doc

In case anyone is interested, some magic seems to happen here ( I'm currently digging it ;p )
chrome://print/print_preview.js

Moreover, I'd be happy to write some plugin if someone had a working solution :P

This being said, thanks for the nice js lib ;)

Cheers +

@belenbuffa
Copy link

@stephaneAG
Good work, I'm from Argentina and I'm working hard to jsPDF works in my site!
I would like to know your work, could you share some information? thank you very much!

@toraritte
Copy link

toraritte commented May 1, 2020

Is there a reason why fromHTML is not documented? At least I couldn't find it at the official docs:
http://raw.githack.com/MrRio/jsPDF/master/docs/jsPDF.html

This is a great thread though, and thank for jsPDF!


This explains it: issue #516 (comment)

Uzlopak commented on Sep 6, 2018
We are closing this issue, because we will not support any longer fromHTML and addHTML.

Explaination:
We are working on a new html2pdf plugin, which will be based on html2canvas and our context2d plugin. This should lead to more reliable results for your projects. And it will give us the time to focus on the core functionality of pdf-generation because we will not use our energy for writing/supporting/extending 2 html plugins. If you still want to use addHTML or fromHTML you can still use jsPDF 1.4.1.

Best Regards

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests