views:

371

answers:

8

I have a system that takes dynamic data, puts it in HTML for layout and then converts that to PDF. However the problem I am having is that if an element becomes too big for the remaining page space or pushes something else off the bottom how can I detect this and move the element myself to the right position on the next page? (Currently it gets in the way of the footer elements.)

Any ideas?

A: 

You'll have to track the specific heights of all items, even dynamic, on a page and determine when you need to insert a page break.

rvarcher
+1  A: 

Have you considered just writing two views for the data instead?

This will allow you to address and of PDF issues on the PDF version and address any html issues on the HTML version.

Edit: Since HTML itself has no real concept of "page size", beyond it's own viewport (through javascript), this will be tough.

You can find out the calculated height of a given DOM element using javascript:

document.getelementById("anElement").clientheight

Then if you know the number of pixels in a given page, you can add line breaks as needed to push it down if it will be too big.

Zack
A: 

From your question, I assume you use static positioning (position: absolute) for all content elements?

If your content interrupts footer elements in HTML, then its quite possible that you can fix this by letting the HTML render the footer under all content, as normally done in HTML.

Still, it would be very helpful if you can describe how you convert the HTML to PDF.

Guss
A: 

Guss: I/we are using the winover libraries (wnvhtmlconvert.dll) for the conversion. The positions aren't absolute (with the exceptions of the header and footers) because they need to shuffle down if the elements above them expand. It all needs to be dynamic because the contents of the elements will vary with user input. Each element may need to be split or move depending on how much free space there is on the "page".

zack: I'm creating the HTML in order to convert it to PDF its just used for template layout. The HTML will never be seen.

Rob
A: 

I'd take off the absolute positioning on your footer, and just let it flow after the content.

If you render it as one big page, then PDF can break the page where it needs to.

John Dunagan
This doesn't allow us to brand the footer of the pages though. Unfortunately its a requirement.
Rob
A: 

I'm going to assume you have control over the generated html and can make some changes there. You will need to empirically determine the exact height and width of the pdf. You will also need to determine the maximum number of pdf pages an html page will fill.

The basic plan is to put the html content in its own containing div and repeat that div for however many pages you might possibly fill. Each div will then be styled and sized to fit on one page, with the overflow being hidden (we can think of each div as a "window"). The repeat divs will have their content shifted so that a different part of the content is in the window. In the following example, I'm going to assume a pdf page dimensions of 500px by 500px (I know this is unrealistic), that the maximum number of pages content will take up is 3, and that your html is being rendered by the pdf converter in a standards-compliant fashion.

<!DOCTYPE html>
<html>
<head>
  <title>PDF Pagination Example</title>
  <style>
    .header {background:blue; height:25px}
    .footer {background:green; height:25px}
    .window {height:500px; width:500px}
    #window1, #window2, #window3 {height:450px; overflow:hidden}
    #spacer2 {height:0; margin-top:-450px}
    #spacer3 {height:0; margin-top:-900px}
    li {font-size:30px; padding:10px}
  </style>
</head>
<body>

<div class='window'>
<div class='header'>A header</div>
  <div id='window1'>
    <ol>
     <li>Content of variable height that may or may not overflow.</li>
     <li>Content of variable height that may or may not overflow.</li>
     <li>Content of variable height that may or may not overflow.</li>
     <li>Content of variable height that may or may not overflow.</li>
     <li>Content of variable height that may or may not overflow.</li>
     <li>Content of variable height that may or may not overflow.</li>
     <li>Content of variable height that may or may not overflow.</li>
     <li>Content of variable height that may or may not overflow.</li>
     <li>Content of variable height that may or may not overflow.</li>
    </ol>
  </div>
<div class='footer'>A footer</div>
</div>

<div class='window'>
<div class='header'>A header</div>
  <div id='window2'>
  <div id='spacer2'></div>
    <ol>
      <li>Content of variable height that may or may not overflow.</li>
      <li>Content of variable height that may or may not overflow.</li>
      <li>Content of variable height that may or may not overflow.</li>
      <li>Content of variable height that may or may not overflow.</li>
      <li>Content of variable height that may or may not overflow.</li>
      <li>Content of variable height that may or may not overflow.</li>
      <li>Content of variable height that may or may not overflow.</li>
      <li>Content of variable height that may or may not overflow.</li>
      <li>Content of variable height that may or may not overflow.</li>
 </ol>
  </div>
<div class='footer'>A footer</div>
</div>

<div class='window'>
<div class='header'>A header</div>
  <div id='window3'>
  <div id='spacer3'></div>
    <ol>
      <li>Content of variable height that may or may not overflow.</li>
      <li>Content of variable height that may or may not overflow.</li>
      <li>Content of variable height that may or may not overflow.</li>
      <li>Content of variable height that may or may not overflow.</li>
      <li>Content of variable height that may or may not overflow.</li>
      <li>Content of variable height that may or may not overflow.</li>
      <li>Content of variable height that may or may not overflow.</li>
      <li>Content of variable height that may or may not overflow.</li>
      <li>Content of variable height that may or may not overflow.</li>
    </ol>
</div>
<div class='footer'>A footer</div>
</div>

</body>
</html>

At a font size of 30px, the content splits between two pages. If you increase the font size to 50px, the content will spread to fill all three.

The last piece of the puzzle is a bit of javascript. You will need to write a snippet that calculates the height of the content and adds padding to the bottom of each window so you don't get cutoff like in the example. The javascript should also set windows with no content in them to display:none. I'm not sure if this is even the css you are looking for, so I won't work out the javascript, but I am also certain that if you need help with that you can find it here on SO :).

vamin
This is the best solution so far however if the section is structurally to big (e.g a table that has the amount of rows added dynamically) then this wont work and even if it did like I said before the HTML itself is never seen aka run in a browser.
Rob
A: 

maybe helpfull to consider some of the CSS print attributes, but without further info its hard to tell

http://www.w3schools.com/Css/css_ref_print.asp

nickmorss
A: 

I found that by using the WebBrowser control and checking the OffsetRectangle.Bottom property of the element in question I could tell if it was lower than the top of the footer then I could tell if the element had overflowed and by how much.

Thanks for your help anyway guys and gals.

Rob