Jump to content
Sign in to follow this  
lynkfs

printing

Recommended Posts

Working on a component which involves printing.

I've used external libraries like jsPDF, which generate printable content and they generally work fine. They also have some drawbacks though. So this component is going to rely on the browsers native 'print' command to print a complete page/form, or part thereof.

1) The print command is tied to a window object (window.print), so the possible implementations are limited to manipulating either

  • the current window
  • an iFrame element, which encapsulates a window object
  • a new pop-up window (or new tab)

Just to try these out, button 1-3 in the code below correspond to these possible implementations. 

  var Button1 : TW3Button := TW3Button.Create(self);
  Button1.SetBounds(20,470,120,30);
  Button1.Caption := 'this window';
  Button1.OnClick := procedure(sender:TObject)
  begin
    var originalContents := browserapi.document.body.innerHTML;
    browserapi.document.body.innerHTML := SrcDoc;
    browserapi.window.print();
    browserapi.document.body.innerHTML = originalContents;
  end;

  var Button2 : TW3Button := TW3Button.Create(self);
  Button2.SetBounds(150,470,120,30);
  Button2.Caption := 'iframe window';
  var IFrame1 := TW3IFrameHtmlElement.Create(self);
  IFrame1.SetBounds(20,20,400,400);
  Button2.OnClick := procedure(sender:TObject)
  begin
    IFrame1.handle.srcdoc := SrcDoc;
    IFrame1.handle.contentWindow.print();
  end;

  var Button3 : TW3Button := TW3Button.Create(self);
  Button3.SetBounds(280,470,120,30);
  Button3.Caption := 'other window';
  Button3.OnClick := procedure(sender:TObject)
  begin
    asm
     var mywindow = window.open('', 'PRINT', 'height=400,width=600');
     mywindow.document.write(@SrcDoc);
     mywindow.setTimeout(function(){ mywindow.print(); mywindow.close(); }, 1000);
     //mywindow.print();
     //mywindow.close();
    end;
  end;

//SrcDoc content : see below

All of these approaches work. However if printable content contains images or other sizable resources, the actual printing must be delayed until all these resources have been downloaded - so either preload or set an appropriate Timeout, as in Button3

 

2) Screen and print layout differ in a couple of aspects :

  • screens are continuous, paper is not and some elements like tables and images should not be cut in half over page breaks
  • readability of fonts is different on screens and print output
  • hints like blue links on webpages don't translate well to printing
  • many web page elements like menus should not appear on print
  • and more. A good overview is given in this article

A separate print stylesheet can handle some/most/all of these concerns. A generic print stylesheet based on @media print is included below. Probably not the solution for each and every situation, but it handles most of the aspects above

  var SrcDoc : string := #'
      <!DOCTYPE html>
      <HTML>
      <HEAD>
      <style>
        @media print {

        @page { margin: 2cm }

        body {
          font: 13pt Georgia, "Times New Roman", Times, serif;
          line-height: 1.3;
          background: #fff !important;
          color: #000;
        }

        h1 {
          font-size: 24pt;
        }

        h2, h3, h4 {
          font-size: 14pt;
          margin-top: 25px;
        }

        a {
          page-break-inside:avoid
        }
        blockquote {
          page-break-inside: avoid;
        }
        h1, h2, h3, h4, h5, h6 { page-break-after:avoid;
          page-break-inside:avoid }
        img { page-break-inside:avoid;
          page-break-after:avoid; }
        table, pre { page-break-inside:avoid }
        ul, ol, dl  { page-break-before:avoid }

        a:link, a:visited, a {
          background: transparent;
          color: #520;
          font-weight: bold;
          text-decoration: underline;
          text-align: left;
        }

        a {
          page-break-inside:avoid
        }

        a[href^=http]:after {
          content:" <" attr(href) "> ";
        }

        $a:after > img {
          content: "";
        }

        article a[href^="#"]:after {
          content: "";
        }

        a:not(:local-link):after {
          content:" <" attr(href) "> ";
        }

        nav, .sidebar, .heading
        {
          display: none;
        }

        p, address, li, dt, dd, blockquote {
          font-size: 100%
        }

        code, pre { font-family: "Courier New", Courier, mono}

        ul, ol {
          list-style: square; margin-left: 18pt;
          margin-bottom: 20pt;
        }

        li {
          line-height: 1.6em;
        }

      }
      </style>
      </HEAD>
      <BODY BGCOLOR="FFFFFF">
      <CENTER><IMG SRC="res/logo.png"> </CENTER>
      <HR>
      <H1>Header H1</H1>
      <H2>Header H2</H2>
      <P>Paragraph
      <P><B>Bold paragraph</B>
      <BR><BR><B><I>This is a sentence with some length, longer than the iframe width,
      in bold italic.</I></B>
      <HR>
      </BODY>
      </HTML>';


This generates a print preview in all major browsers, with options to set paper size, select printer, orientation etc.

see https://www.lynkfs.com/Experiments/ReportWriter/www/reportwriter.html

Next thing to tackle is scaling.

 

 

Share this post


Link to post
Share on other sites

update :

on Android (Chrome) only the iFrame solution works as expected :

  • Button1 (manipulating the main window object) prints the whole page rather than just the demo html
  • Button3 (popup window) results in a rendering error

see https://www.lynkfs.com/Experiments/ReportWriter/www/reportwriter.html

Going with the IFrame solution

Share this post


Link to post
Share on other sites

update 2 :

after some more testing on different platforms, the conclusion is that the window.print() method basically works on all platforms (Windows, MacOs, iOS, Android) and modern browsers (Chrome, FireFox, Safari), but only using the iFrame setup as mentioned in the prev. posts. The other methods may or may not work.

The main exception is Chrome and FireFox on iOS where window.print() doesn't work at all : apparently Apple does not allow printing from Chrome in iOS due to it's policy on using alternative browser engines.

These guys deserve a thumbs down, really

 

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×