mileszs / wicked_pdf

PDF generator (from HTML) plugin for Ruby on Rails
http://www.mileszs.com/wicked-pdf-plugin
MIT License
3.53k stars 645 forks source link

Columnizing with FTColumnFlow #354

Open topherreynoso opened 9 years ago

topherreynoso commented 9 years ago

I have been searching for a way to get columnizing working from HTML to PDF. I have combined wicked_pdf and FTColumnFlow to make it happen. Basically I do this in the rails side:

av = ActionView::Base.new()
av.view_paths = ActionController::Base.view_paths
av.class_eval do
    include Rails.application.routes.url_helpers
    include ApplicationHelper
end
body_html = av.render :pdf => "#{@iteration.name}", 
                      :template => "iterations/show.pdf.erb", 
                      :locals => {:iteration_id => @iteration.id}, 
                      :javascript_delay => 3000
pdf = WickedPdf.new.pdf_from_string(body_html, 
                                    :page_size => 'Letter', 
                                    :margin => {:top => 10, :bottom => 10, :left => 15, :right => 15}, 
                                    :javascript_delay => 3000)

This allows me to set up the FTColumnFlow javascript action in the template with enough javascript_delay to make it happen.

And then I do this in my template:

<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="Content-Language" content="en-us" />
    <script src="//ajax.googleapis.com/ajax/libs/webfont/1.4.7/webfont.js"></script>
    <script>
      WebFont.load({
        google: {
          families: ['Droid Sans:n4,n7']
        }
      });
    </script>
    <%= wicked_pdf_javascript_include_tag "FTColumnflow" %>
    <%= wicked_pdf_stylesheet_link_tag 'pdf/iterations' %>
    <style>
      body { margin: 0; padding: 0; }
      #flowedContent, #fixedContent { opacity: 0; }
    </style>
  </head>
  <body>
    <section id="viewport">
      <article id="target"></article>
    </section>
    <div id="flowedContent">
      <%= @iteration.verbiage.html_safe %>
    </div>

    <% if !@iteration.fixed_verbiage.nil? && @iteration.fixed_verbiage != "" %>
      <div id="fixedContent">
        <%= @iteration.fixed_verbiage.html_safe %>
      </div>
    <% end %>
    <script type="text/javascript">
      var targetEl  = document.getElementById('target');
      var viewportEl = document.getElementById('viewport');
      var cf = new FTColumnflow(targetEl, viewportEl, {
        columnCount:             2,
        pageArrangement:         'vertical',
        standardiseLineHeight:   true,
        columnFragmentMinHeight: 30,
        pagePadding:             1,
        columnGap:               20,
        viewportWidth:           1095,
        viewportHeight:          1532,
        allowReflow:             false
      });
      if(<%= @iteration.fixed_verbiage.nil? %> == true || <%= @iteration.fixed_verbiage == "" %> == true){
        var flowedContent = document.getElementById('flowedContent');
        cf.flow(flowedContent, null);
      }else{
        var flowedContent = document.getElementById('flowedContent'),
            fixedContent = document.getElementById('fixedContent');
        cf.flow(flowedContent, fixedContent);
      }
    </script>
  </body>
</html>

Basically I tell FTColumnFlow to make its viewportWidth and viewportHeight equivalent to one letter size page with the margins I have added in wicked_pdf and this results in each FTColumnFlow page being a new PDF page, along with detecting if there are any fixedContent (like a cover page or an appendix page, etc).

This has let me get beautifully columnized PDF documents from HTML. One catch, FTColumnFlow is having some trouble rendering the text exactly right and on column or page breaks it can result in a repeated or deleted line occasionally. I believe it is related to the fact that while in wicked_pdf's show_as_html debug option there are no repeated or deleted lines, it all looks great, but as soon as I go back to PDF the columns and pages are breaking on different lines than what was shown in debug and the repeated and missing lines occur again occasionally at page and column breaks.

I am so close to being able to columnize HTML with wicked_pdf, anyone interested in helping me find this last piece of the puzzle?

unixmonkey commented 9 years ago

I use this css to help control page breaking as much as I can:

div.alwaysbreak { page-break-before: always; }
div.nobreak:before { clear:both; }
div.nobreak { page-break-inside: avoid; }

If possible with FTColumnFlow, try to wrap each of your rows with a <div class='nobreak'>. I know it isn't semantic if the rows are table rows (tr), but it will work.