Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you print page breaks with iOS?

I'm generating a multi-page html document that I'd like to send to an Airprint printer from my app. Each page is discrete and must begin on it's own sheet.

This should be relatively simple - the content of each page is immediately followed by a div element having display: block; page-break-after: always; Here is a simple example:

<html>
  <head>
    <title>Printing with Page Breaks</title>
    <style type="text/css">
      @media screen or print {
        div.pageb { display: block; page-break-after: always; }
      }
    </style>
  </head>

  <body>
        <h1>Page 1</h1>
        <p>Lorem ipsum dolor sit amet...</p>
        <div class="pageb"></div>  <!-- should page break here! -->

        <h1>Page 2</h1>
        <p>Lorem ipsum dolor sit amet...</p>
        <div class="pageb"></div>  <!-- should page break here! -->

        <h1>Page 3</h1>
        <p>Lorem ipsum dolor sit amet...</p>
        <div class="pageb"></div>  <!-- should page break here! -->
  </body>
</html>

This document prints perfectly from Safari and Chrome, which both put all page breaks where they should be. On iOS however, the page breaks aren't inserted.

To print the html I'm using a UIPrintInteractionController to print the contents of a UIWebView by way of UIViewPrintFormatter. Something like this:

UIPrintInteractionController *controller = [UIPrintInteractionController sharedPrintController];

UIPrintInfo *printInfo = [UIPrintInfo printInfo];
printInfo.outputType = UIPrintInfoOutputGeneral;
controller.printInfo = printInfo;

UIWebView *webViewPrint = [[UIWebView alloc] init];
[webViewPrint loadHTMLString:printHTML baseUrl:@"/"];

UIViewPrintFormatter *viewFormatter = [webViewPrint viewPrintFormatter];
controller.printFormatter = viewFormatter;
controller.showsPageRange = NO;

[controller presentAnimated:YES completionHandler:completionHandler];

This all seems very standard and I'm left wondering why page breaks print properly on other Webkit browsers but not UIWebView. Any ideas on how to do page breaks on iOS?

like image 951
weston Avatar asked Sep 10 '13 00:09

weston


3 Answers

I don't have a general solution but I did manage to get page breaks working after some fiddling. Seems like UIWebView is a little finicky with where page-break-before/page-break-after can be applied. Taking a hint from this question I decided to try adding my page break styles to the h1 elements instead of divs and to my surprise the pagebreaks appeared. Here's what it looks like now:

<style type="text/css">
  @media print {
    .pagebreak-before:first-child { display: block; page-break-before: avoid; }
    .pagebreak-before { display: block; page-break-before: always; }
  }
</style>

...

<body>
  <h1 class="pagebreak-before">Page 1</h1>
  <p>Lorem ipsum dolor sit amet...</p>

  <h1 class="pagebreak-before">Page 2</h1>
  <p>Lorem ipsum dolor sit amet...</p>

  <h1 class="pagebreak-before">Page 3</h1>
  <p>Lorem ipsum dolor sit amet...</p>
</body>

I also added a duplicate of the .pagebreak-before selector, now having a :first-child pseudo-element. This is to prevent a blank page at the beginning of the document.

like image 103
weston Avatar answered Sep 21 '22 17:09

weston


I'm pretty sure that it's not the h1 vs. the div that's the problem. But it did work a lot better when using an element before the content and using page-break-before: always.

First I tried something like this:

<div class="page">
    <h2>Header</h2>
    <p>Content</p>
</div>
<div class="page">
    <h2>Header</h2>
    <p>Content</p>
</div>
<div class="page">
    <h2>Header</h2>
    <p>Content</p>
</div>    

And the css:

.page { page-break-after: always; }

This gave me very strange page breaks and the header could be the only element vertically centered on the page.

Changing the markup to:

<div class="page">
    <div class="break"></div>
    <h2>Header</h2>
    <p>Content</p>
</div>
<div class="page">
    <div class="break"></div>
    <h2>Header</h2>
    <p>Content</p>
</div>
<div class="page">
    <div class="break"></div>
    <h2>Header</h2>
    <p>Content</p>
</div>

And the css to:

.break { page-break-before: always; }
.page:first-child .break { page-break-before: avoid; }

Worked as expected.

like image 32
Johan Nordberg Avatar answered Sep 19 '22 17:09

Johan Nordberg


I found that I had to set the paginationMode property of my UIWebView to UIWebPaginationModeTopToBottom (or any other value besides the default UIWebPaginationModeUnpaginated value) for the CSS page-break rules to be used.

like image 40
arlomedia Avatar answered Sep 18 '22 17:09

arlomedia