question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Font lost when rendered in an iframe

See original GitHub issue

I’m trying to use an iframe to print a PDF easily, everything is ok but the fonts.

Configuration:

  • Web browser and its version: chrome 57
  • Operating system and its version: MacOS Sierra 10.12.7
  • PDF.js version: pdfjs-dist 1.8.177

Steps to reproduce the problem:

  1. Dynamically create an iframe with a canvas, render the pdf in the canvas

Here is my print function which takes the pdfDoc as parameter (from PDFJS.getDocument(url))

function print(pdfDoc) {
      if (!pdfDoc || !pdfDoc.numPages) {
        return ;
      }

      var scale = 5;
      var iframe = window.document.createElement('iframe');
      var doc = iframe.contentDocument || iframe.contentWindow.document;
    
      window.document.body.append(iframe);

      doc.open();
      doc.write(
        '<!DOCTYPE html>' +
          '<html>' +
            '<head>' +
              '<style>' +
                '* {margin: 0 !important; padding: 0 !important}' +
                'div{width:612pt; height:792pt;}' +
                'canvas{width:100%; height:100%;}' +
            '</style>' +
          '</head>' +
          '<body></body>' +
        '</html>'
      );
      doc.close();

      function renderPage(num) {
        console.log('Rendering page %d of %d', num, pdfDoc.numPages);

        return pdfDoc
          .getPage(num)
          .then(function (page) {
            var div = doc.createElement('div');
            var canvas = doc.createElement('canvas');
            div.appendChild(canvas);
            doc.body.appendChild(div);
            var viewport = page.getViewport(scale);
            var ctx = canvas.getContext('2d');
            canvas.width = viewport.width;
            canvas.height = viewport.height;
            return page.render({canvasContext: ctx, viewport: viewport}).promise;
          })
          .then(function () {
            if (num < pdfDoc.numPages) {
              return renderPage(num + 1);
            }
          });
      }

      renderPage(1)
        .then(function () {
          iframe.contentWindow.print();
          iframe.remove();
        });
    }

On the left, the main page canvas, on the right, the iframe canvas.

image

The rendering in the iframe seems to not embed the fonts.

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:9 (2 by maintainers)

github_iconTop GitHub Comments

2reactions
bastijns-jeroencommented, Mar 18, 2020

Hi, if somebody visits this issue again, here is a workarround. I followed the steps @Rob--W provided above and can confirm it works on all browsers (Safari, Chrome, Firefox and Edge).

Here is the code snippet (Renders all pages at once):

import {PDFPageViewport} from 'pdfjs-dist';
import pdfjsLib from 'pdfjs-dist/webpack';
import {range} from 'lodash';

const renderPage = async (page: any, container: HTMLElement) => {
	// This gives us the page's dimensions at full scale
	const viewport: PDFPageViewport = page.getViewport({ scale: 1 });

	// We'll create a canvas for each page to draw it on
	const canvas = document.createElement('canvas');
	canvas.style.display = 'block';
	container.appendChild(canvas);

	const context = canvas.getContext('2d');
	canvas.height = viewport.height;
	canvas.width = viewport.width;

	// Draw it on the canvas
	await page.render({ canvasContext: context, viewport }).promise;

	// eslint-disable-next-line max-len
	return new Promise<{ blob: Blob, height: number, width: number }>(((resolve) => canvas.toBlob((result) => resolve({ blob: result!, height: viewport.height, width: viewport.width }))));
};

// Render a hidden container element to add all canvases (canvas per page in the pdf) 
const container = document.createElement('div') as HTMLDivElement;
container.style.visibility = 'hidden';
document.body.appendChild(container);

// Create the iframe
const iframe = document.createElement('iframe') as HTMLIFrameElement;
iframe.style.visibility = 'hidden';
iframe.src = 'about:blank';
document.body.appendChild(iframe);
iframe.contentWindow!.onbeforeunload = () => document.body.removeChild(iframe);
iframe.contentWindow!.onafterprint = () => document.body.removeChild(iframe);

const pdf = await pdfjsLib.getDocument(source).promise;
const numPages = pdf.numPages;

const pageNumbers = range(1, numPages + 1);
// Create the canvas for each page and retrieve the image blob data
const imageBlobData = await Promise.all(pageNumbers.map(async number => {
	return renderPage(await pdf.getPage(number), container);
}));
// Due to a bug we need to copy the canvas image to the iframe instead of writing the canvas directly
// in the iframe. (https://github.com/mozilla/pdf.js/issues/8271)
imageBlobData.forEach((blobData) => {
	const image = document.createElement('img');
	image.style.height = `${blobData.height}`;
	image.style.width = `${blobData.width}`;
	image.src = URL.createObjectURL(blobData.blob);
	iframe.contentWindow!.document.body.appendChild(image);
});
// Remove the intermediary container element
document.body.removeChild(container);

// Wait for the content to be fully rendered and print
await setTimeout(() => {
                iframe.contentWindow!.focus();
                iframe.contentWindow!.print();
            }, 500);
1reaction
amitsin6hcommented, May 18, 2017

can I work on this bug ?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Chrome text rendering different when same page is inside an ...
I'm asking because some fonts appear to be slightly blurry in an iframe. There's no transforms applied on the iframe whatsoever. css ·...
Read more >
Solved: Re: Consistent style for pages with embedded text
When we use the Canvas editor to write text-based content into a page, the style of the text displayed when the page is...
Read more >
325697 - Font size changing on iframe reload - chromium
Hitting "run" within jsfiddle sometimes causes the "result" iframe to occasionally use an incorrect font size (compare good.png and bad.png)
Read more >
Using inline frames (iframe elements) to embed documents ...
A detailed description of inline frames ("floating frames", iframe elements), as by the HTML specifications and the IE implementation.
Read more >
How to put an iFrame into Confluence
Purpose. An IFrame (Inline Frame) is an HTML document embedded inside another HTML document on a website. The IFrame HTML element is often ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found