Mittwoch, 9. März 2016

Scaleable PDF preview (first page) in SWT using PDF.js and XulRunner

I desired to have a fast PDF preview in my Document Management Software. The DMS is based on Eclipse RCP (SWT).

The best way to render PDF in SWT is to use Mozilla PDF.js in an embedded org.eclipse.swt.browser.Browser using the SWT.MOZILLA flag (XulRunner).

Setting up XulRunner with different Eclipse/SWT versions and OS-architectures is not quite easy and would fill an own blog post.
I assume that there is a ready-to-use SWT browser created with SWT.MOZILLA flag.

Before implementing the preview we need the following setup steps.


Download PDF.js


Clone or download Mozilla PDF.js: https://mozilla.github.io/pdf.js. Place the sources in your project directory.

Enable local file access


For security reasons local file access (using the file:// protocol) is disabled in XulRunners JavaScript setup.
If yout want to display documents using the file:// protocol you must first disable the option

security.fileuri.strict_origin_policy

Do so by going to URL about:config in the embeded browser and change the setting.


Test with the shipped full featured PDF viewer


PDF.js comes with a full featured PDF viewer. The following code creates a SWT Browser and points the URL to PDF.js viewer.html. The PDF document to display is passed via URLs query string.


// Create Browser with SWT.MOZILLA flag (XulRunner)
Browser browser = new Browser(parent, SWT.MOZILLA);
  
// Sample PDF document to display
File file = new File("documents/test.pdf");
  
// Set URL
browser.setUrl("file://pdfjs/web/viewer.html?file=" +
  URLEncoder.encode(file.toURI().toString(), "utf-8") );

You will have to adjust the locations of the sample PDF and the PDF.js web directory.

If everything is setup correctly you will see the sample document viewer in your application. The PDF.js viewer is nice and offers navigation, zooming etc.


Implement one page preview


To have just a lightweight preview of the document my wishlist contained the follwing:
  1. PDF rendering using PDF.js
  2. Only first page should be rendered
  3. Scale to 100% of available width
  4. No toolbar and user actions available

The solution is quite simple. You will have to create a new HTML-file:


<body onload="load()">

  <canvas id="the-canvas" 
    style="border: 1px solid black; width: 100%;">

</canvas></body>


The HTML is basically taken from the PDF.js example. I only added width:100% to CSS attributes.

The follwing JavaScript will extract the PDF URL from the site URL and renders page 1:


 function parseQueryString(query) {  
    var parts = query.split('&');  
    var params = {};  
      
    for (var i = 0, ii = parts.length; i < ii; ++i) {  
       var param = parts[i].split('=');  
       var key = param[0].toLowerCase();  
       var value = param.length > 1 ? param[1] : null;  
       params[decodeURIComponent(key)] = decodeURIComponent(value);  
    }  
      
    return params;  
 }  
   
 function load() {  
    var DEFAULT_URL = '../web/compressed.tracemonkey-pldi-09.pdf';  
   
    var queryString = document.location.search.substring(1);  
    var params = parseQueryString(queryString);  
    var file = 'file' in params ? params.file : DEFAULT_URL;  
   
    PDFJS.getDocument(file).then(function(pdf) {  
       pdf.getPage(1).then(function(page) {  
          var canvas = document.getElementById('the-canvas');  
          var context = canvas.getContext('2d');  
            
          var viewport = page.getViewport(1);  
          var scale = canvas.width / viewport.width;  
          var scaledViewport = page.getViewport(scale);           
            
          canvas.height = viewport.height;  
          canvas.width = viewport.width;  
            
          var renderContext = {  
           canvasContext: context,  
           viewport: viewport  
          };  
            
          page.render(renderContext);      
       });  
    });  
 }  


All that is left to do is to open the new HTML file instead of the shipped viewer.html.

Preview integrated in RCP application

The image shows the result. The preview is placed in a seperate ViewPart and scales smoothly when resizing the part.
With the platforms SelectionService the preview follows the Workbench Selection. The preview will then always show the currently selected document - no matter where in the application it is selected.





Keine Kommentare:

Kommentar veröffentlichen