Anyone get pdf.js working in a custom Widget?

New to custom Widget development so please point me in a different direction if this doesn’t make sense. So I have this idea of modifying the image annotator widget to use PDFs instead of images. In theory I should be able to do this using the Modzilla pdf.js library which should let me load a pdf into a HTML canvas element. However I have been stuck getting the pdf.js library imported and working in my widget, before I continue hacking away at it wondering if folks have already done this and can help me out here.

Here’s my widget javascript code:

var pdfData = atob(
    'JVBERi0xLjcKCjEgMCBvYmogICUgZW50cnkgcG9pbnQKPDwKICAvVHlwZSAvQ2F0YWxvZwog' +
    'IC9QYWdlcyAyIDAgUgo+PgplbmRvYmoKCjIgMCBvYmoKPDwKICAvVHlwZSAvUGFnZXMKICAv' +
    'TWVkaWFCb3ggWyAwIDAgMjAwIDIwMCBdCiAgL0NvdW50IDEKICAvS2lkcyBbIDMgMCBSIF0K' +
    'Pj4KZW5kb2JqCgozIDAgb2JqCjw8CiAgL1R5cGUgL1BhZ2UKICAvUGFyZW50IDIgMCBSCiAg' +
    'L1Jlc291cmNlcyA8PAogICAgL0ZvbnQgPDwKICAgICAgL0YxIDQgMCBSIAogICAgPj4KICA+' +
    'PgogIC9Db250ZW50cyA1IDAgUgo+PgplbmRvYmoKCjQgMCBvYmoKPDwKICAvVHlwZSAvRm9u' +
    'dAogIC9TdWJ0eXBlIC9UeXBlMQogIC9CYXNlRm9udCAvVGltZXMtUm9tYW4KPj4KZW5kb2Jq' +
    'Cgo1IDAgb2JqICAlIHBhZ2UgY29udGVudAo8PAogIC9MZW5ndGggNDQKPj4Kc3RyZWFtCkJU' +
    'CjcwIDUwIFRECi9GMSAxMiBUZgooSGVsbG8sIHdvcmxkISkgVGoKRVQKZW5kc3RyZWFtCmVu' +
    'ZG9iagoKeHJlZgowIDYKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAwMDEwIDAwMDAwIG4g' +
    'CjAwMDAwMDAwNzkgMDAwMDAgbiAKMDAwMDAwMDE3MyAwMDAwMCBuIAowMDAwMDAwMzAxIDAw' +
    'MDAwIG4gCjAwMDAwMDAzODAgMDAwMDAgbiAKdHJhaWxlcgo8PAogIC9TaXplIDYKICAvUm9v' +
    'dCAxIDAgUgo+PgpzdGFydHhyZWYKNDkyCiUlRU9G');  

loadScripts();

async function loadScripts() {
    console.log(`Loading script...`);
    const response = await fetch('https://mozilla.github.io/pdf.js/build/pdf.js');
    const responseBody = await response.text();
    const scriptElm = document.createElement("script");
    const inlineCode = document.createTextNode(responseBody);
    scriptElm.appendChild(inlineCode);
    document.body.appendChild(scriptElm);
    
    console.log(`Script successfully loaded`);

    const workerResponse = await fetch('//mozilla.github.io/pdf.js/build/pdf.worker.js');
    pdfjsLib.GlobalWorkerOptions.workerSrc = await workerResponse.text();
    
    console.log(pdfjsLib)
  
    var loadingTask = pdfjsLib.getDocument({ data: pdfData, });
loadingTask.promise.then(function(pdf) {
  console.log('PDF loaded');
  
  // Fetch the first page
  var pageNumber = 1;
  pdf.getPage(pageNumber).then(function(page) {
    console.log('Page loaded');
    
    var scale = 1.5;
    var viewport = page.getViewport({scale: scale});

    // Prepare canvas using PDF page dimensions
    var canvas = document.getElementById('the-canvas');
    var context = canvas.getContext('2d');
    canvas.height = viewport.height;
    canvas.width = viewport.width;

    // Render PDF page into canvas context
    var renderContext = {
      canvasContext: context,
      viewport: viewport
    };
    var renderTask = page.render(renderContext);
    renderTask.promise.then(function () {
      console.log('Page rendered');
    });
  });
}, function (reason) {
  // PDF loading error
  console.error(reason);
});
}

FWIW I am getting the following when I run the code: Error: Setting up fake worker failed: "Cannot load script at: /**

Any help greatly appriciated.

Hey @trwilson -

Just digging into this one right now. A few things stand out:

  • loadScripts() sometimes fails because the underlying library has nested dependencies it is trying to download. This often is the case with large Js libraries (with lots of their own dependencies)
  • When running this code within a HTML file, It also fails to load. This is generally my first check to debug behavior I think is tied to something specific to CWs.
<html>
<head>
	<script type="text/javascript">
		var pdfData = atob(
    'JVBERi0xLjcKCjEgMCBvYmogICUgZW50cnkgcG9pbnQKPDwKICAvVHlwZSAvQ2F0YWxvZwog' +
    'IC9QYWdlcyAyIDAgUgo+PgplbmRvYmoKCjIgMCBvYmoKPDwKICAvVHlwZSAvUGFnZXMKICAv' +
    'TWVkaWFCb3ggWyAwIDAgMjAwIDIwMCBdCiAgL0NvdW50IDEKICAvS2lkcyBbIDMgMCBSIF0K' +
    'Pj4KZW5kb2JqCgozIDAgb2JqCjw8CiAgL1R5cGUgL1BhZ2UKICAvUGFyZW50IDIgMCBSCiAg' +
    'L1Jlc291cmNlcyA8PAogICAgL0ZvbnQgPDwKICAgICAgL0YxIDQgMCBSIAogICAgPj4KICA+' +
    'PgogIC9Db250ZW50cyA1IDAgUgo+PgplbmRvYmoKCjQgMCBvYmoKPDwKICAvVHlwZSAvRm9u' +
    'dAogIC9TdWJ0eXBlIC9UeXBlMQogIC9CYXNlRm9udCAvVGltZXMtUm9tYW4KPj4KZW5kb2Jq' +
    'Cgo1IDAgb2JqICAlIHBhZ2UgY29udGVudAo8PAogIC9MZW5ndGggNDQKPj4Kc3RyZWFtCkJU' +
    'CjcwIDUwIFRECi9GMSAxMiBUZgooSGVsbG8sIHdvcmxkISkgVGoKRVQKZW5kc3RyZWFtCmVu' +
    'ZG9iagoKeHJlZgowIDYKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAwMDEwIDAwMDAwIG4g' +
    'CjAwMDAwMDAwNzkgMDAwMDAgbiAKMDAwMDAwMDE3MyAwMDAwMCBuIAowMDAwMDAwMzAxIDAw' +
    'MDAwIG4gCjAwMDAwMDAzODAgMDAwMDAgbiAKdHJhaWxlcgo8PAogIC9TaXplIDYKICAvUm9v' +
    'dCAxIDAgUgo+PgpzdGFydHhyZWYKNDkyCiUlRU9G');  
​
loadScripts();
​
async function loadScripts() {
    console.log(`Loading script...`);
    const response = await fetch('https://mozilla.github.io/pdf.js/build/pdf.js');
    const responseBody = await response.text();
    const scriptElm = document.createElement("script");
    const inlineCode = document.createTextNode(responseBody);
    scriptElm.appendChild(inlineCode);
    document.body.appendChild(scriptElm);
    
    console.log(`Script successfully loaded`);
​
    const workerResponse = await fetch('http://mozilla.github.io/pdf.js/build/pdf.worker.js');
    pdfjsLib.GlobalWorkerOptions.workerSrc = await workerResponse.text();
    
    console.log(pdfjsLib)
  
    var loadingTask = pdfjsLib.getDocument({ data: pdfData, });
loadingTask.promise.then(function(pdf) {
  console.log('PDF loaded');
  
  // Fetch the first page
  var pageNumber = 1;
  pdf.getPage(pageNumber).then(function(page) {
    console.log('Page loaded');
    
    var scale = 1.5;
    var viewport = page.getViewport({scale: scale});
​
    // Prepare canvas using PDF page dimensions
    var canvas = document.getElementById('the-canvas');
    var context = canvas.getContext('2d');
    canvas.height = viewport.height;
    canvas.width = viewport.width;
​
    // Render PDF page into canvas context
    var renderContext = {
      canvasContext: context,
      viewport: viewport
    };
    var renderTask = page.render(renderContext);
    renderTask.promise.then(function () {
      console.log('Page rendered');
    });
  });
}, function (reason) {
  // PDF loading error
  console.error(reason);
});
}
	</script>
</head>
</html>

I haven’t played much with anything outside of png, jpg, and base64 encoding for images, so I cant provide too much additional insight on this one.

Pete

Hey @Pete_Hartnett

If i have a base64 string of a PDF, is there any way to display that in a custom widget?

Hey @jjj -

This is a good question - I haven’t personally tried doing this, but it looks like there are a handful of useful guides floating around:

In giving both of these a once over, I see no reason these shouldn’t work in the CW runtime, but haven’t dug too deep into either of them.
Pete

1 Like

Okay, I’ll check them out. I was able to make this custom widget through the Co-pilot. It displays Base64 of images. So I was hoping to do the same for PDF.
customWidget-Base64 Image view (copy).json (1.5 KB)

@trwilson
You have to load the worker as seperate module (Script) File.

1 Like

Hello, to date, has anyone found a solution to this problem? I have APIs that return Base64 data that I would like to display in a PDF… So far, I only have a widget that allows me to convert Base64 to PNG but not to PDF. Thank you for your feedback.

You can use the lib pdf from Mozilla to achieve this.

You have to use the loadScript function (Using and requesting new external libraries) to load the necessary scripts (“https://mozilla.github.io/pdf.js/build/pdf.mjs” & “https://mozilla.github.io/pdf.js/build/pdf.worker.mjs”)

If the scripts are provided you have to define a pdfJSWoker which is necessary for the pdf lib then you have to load the base64 of the pdf via widget parameter or via request. So you can easily use the pdf lib samples (Examples).

Keep in mind that you have to define a function to handle more than one pdf pages.

1 Like