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.

"Canvas area exceeds the maximum limit (width * height > 16777216)." on iOS

See original GitHub issue

Before you start - checklist

  • I followed instructions in documentation written for my React-PDF version
  • I have checked if this bug is not already reported
  • I have checked if an issue is not listed in Known issues
  • If I have a problem with PDF rendering, I checked if my PDF renders properly in PDF.js demo

Description

On iOS mobile + Safari (bug has been reported on iPhone 12, 13, 14), it can happen that the PDF does not display at all. We tracked down the issue and here is the reason:

Safari simply cannot draw large canvas elements. The limit is set at 16.777.216 pixels. Create a canvas with more pixels and iOS Safari will tell us it exceeds the memory limit. When we open this page on iOS Safari, it’ll show the following warning in the developer console.

More information about the issue: https://pqina.nl/blog/canvas-area-exceeds-the-maximum-limit/

Steps to reproduce

Here is some dummy code to produce the error:

const canvas = document.createElement('canvas');
canvas.width = 4097;
canvas.height = 4096;

const ctx = canvas.getContext('2d');
ctx.fillRect(0, 0, 100, 100);

Here is our actual code:

import React, { useState } from "react";
import PropTypes from "prop-types";
import { Document, Page } from "react-pdf/dist/esm/entry.webpack";
import "react-pdf/dist/esm/Page/AnnotationLayer.css";

const PDFViewer = ({ file, renderRightNav, renderLeftNav }) => {
  const [pages, setPages] = useState(null);
  const [pageNumber, setPageNumber] = useState(1);

  const onDocumentLoadSuccess = ({ numPages }) => {
    setPages(numPages);
  };

  const handleNext = () => {
    setPageNumber(pageNumber + 1);
  };

  const handlePrev = () => {
    setPageNumber(pageNumber - 1);
  };

  return (
    <div className="pdf-viewer">
      <Document file={file} onLoadSuccess={onDocumentLoadSuccess}>
        <Page pageNumber={pageNumber} />
      </Document>
      <p className="page-number">Page {pageNumber} of {pages}</p>
      {renderRightNav(handleNext, pageNumber === pages)}
      {renderLeftNav(handlePrev, pageNumber === 1)}
    </div>
  );
};

PDFViewer.propTypes = {
  file           : PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
  renderRightNav : PropTypes.func,
  renderLeftNav  : PropTypes.func
};

export default PDFViewer;

Expected behavior

The PDF should display fine. Like this: image

Actual behavior

PDF doesn’t display and we’re getting the following error in the console: image

image

Attaching the incriminated PDF that doesn’t display on Safari / iOS: Trashless Business Plan 10-28-22.pdf

Additional information

No response

Environment

  • Browser (if applicable): Safari on iOS
  • React-PDF version: v6
  • React version: 18
  • Webpack version (if applicable):

Issue Analytics

  • State:open
  • Created 10 months ago
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
wojtekmajcommented, Nov 22, 2022

In 45a19b6f0871cfd1fd48d5155532a5e54515467a, I’ve added a way to override devicePixelRatio canvas is rendering with. By default, it matches screen device pixel ratio, so for example 3 on most iPhones, 1 on standard resolution office monitor.

By setting this value manually we can lower the resolution of the canvas rendered, vastly reducing the number of pixels rendered, without changing actual physical canvas size.

For example, sample document on an iPhone renders 4,508,910 pixels, setting devicePixelRatio to 2 more than halves it to 2,003,960 pixels, and lowering it all the way to 1, while quite making things quite blurry, renders only 500,990 pixels.

Bonus tip: you could cap devicePixelRatio by passing e.g. Math.min(2, window.devicePixelRatio), preventing obscenely large pixel density, while maintaining good looks on most devices.

This might help you out!

1reaction
gitnamecommented, Nov 17, 2022

There’s an NPM package that people can use to detect the maximum canvas size supported by the web browser:

Users of react-pdf may be able to use that package to influence the size-related props they pass to the <Page> element, thereby influencing the size of the underlying <canvas> element.


I have never used it, myself.

In my case, I was running into issues on iOS when trying to render a PDF using this element:

<Page width={8.5 * 300} /* ... */ /> // in which case, the height becomes 11 * 300, since the pages are Letter-sized

As a temporary workaround, I am using the following “smaller” element, which works on iOS:

<Page width={8.5 * 72} /* ... */ /> // in which case, the height becomes 11 * 72, since the pages are Letter-sized

I plan to employ the above package in the future, but haven’t gotten around to it yet (due to some higher priorities).

Edit: Changed Document to Page (was a typo in original message).

Read more comments on GitHub >

github_iconTop Results From Across the Web

Canvas Area Exceeds The Maximum Limit - PQINA
We can create canvas elements that exceed 4096 pixels in width or height as long as the total amount of pixels is below...
Read more >
Total canvas memory use exceeds th… - Apple Developer
Total canvas memory use exceeds the maximum limit - iOS 15 beta with Safari.
Read more >
Maximum size of a <canvas> element - Stack Overflow
The maximum size for a canvas element is 3 megapixels for devices with less than 256 MB RAM and 5 megapixels for devices...
Read more >
OpenLayers 'Canvas area exceeds the maximum limit' error in ...
Canvas area exceeds the maximum limit (width * height > 16777216). If I decrease the window size again, the layers re-appear on the...
Read more >
Quick Dev Tip #2 – Canvas Sizing Bug and Pixel Density
After sorting out a different issue with Safari's remote debugging tool, I found the error message, "Canvas area exceeds the maximum limit ( ......
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