Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Total canvas memory use exceeds the maximum limit (384 MB) #1020

Closed
4 tasks done
walpolsh opened this issue Jun 28, 2022 · 7 comments
Closed
4 tasks done

Total canvas memory use exceeds the maximum limit (384 MB) #1020

walpolsh opened this issue Jun 28, 2022 · 7 comments
Labels
bug Something isn't working stale

Comments

@walpolsh
Copy link

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

Loading a 15mb pdf on iOS triggers this error ^ over and over, locking up the whole application for a minute or two. Scrolling on the PDF seems to trigger it? It also might be zooming in and out. Hard to tell at this point.

Steps to reproduce

Here's how I'm using react-pdf in a component:

import { IconButton, Toolbar } from "@mui/material";
import React, { useState } from "react";
import { pdfjs, Document, Page } from "react-pdf";
import { Add, Remove, GetApp } from "@mui/icons-material/";
import styled from "styled-components";
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.min.js`;
const PDFDocument = styled(Document)`
  overflow: auto;
  height: 100%;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
`;
const PDFPage = styled(Page)`
  margin: 0.5em;
`;
export function PDFViewer({ file }) {
  const [numPages, setNumPages] = useState(null);
  const [scale, setScale] = useState(1);
  function onDocumentLoadSuccess({ numPages }) {
    setNumPages(numPages);
  }

  return (
    <div style={{ height: "100%", width: "100%" }}>
      <Toolbar
        id="pdfToolbar"
        style={{
          justifyContent: "center",
          backgroundColor: "rgb(51 51 51)",
          color: "white",
        }}
      >
        <IconButton
          style={{ color: "white" }}
          disabled={scale === 0.1}
          onClick={() => setScale(parseFloat((scale - 0.1).toFixed(1)))}
        >
          <Remove />
        </IconButton>
        <span>{Math.round(scale * 100)}%</span>
        <IconButton
          style={{ color: "white" }}
          disabled={scale === 10}
          onClick={() => setScale(parseFloat((scale + 0.1).toFixed(1)))}
        >
          <Add />
        </IconButton>
        <IconButton
          component={"a"}
          href={file}
          target="_blank"
          style={{ color: "white" }}
          onClick={(e) => e.stopPropagation()}
        >
          <GetApp />
        </IconButton>
      </Toolbar>
      <div
        style={{
          backgroundColor: "rgb(82, 86, 89)",
          height: `calc(100% - 60px)`,
          width: "100%",
        }}
      >
        <PDFDocument file={file} onLoadSuccess={onDocumentLoadSuccess}>
          {Array.from(new Array(numPages), (el, index) => (
            <PDFPage key={`page_${index + 1}`} pageNumber={index + 1} scale={scale} />
          ))}
        </PDFDocument>
      </div>
    </div>
  );
}

^ Maybe I'm implementing this wrong or inefficiently?

Expected behavior

Should just work without locking up I suppose?

Actual behavior

Here's a screenshot of the error:

image

Additional information

No response

Environment

  • Device: iPhone 11 Pro and iPad 7th gen
  • OS: iOS 15.4.1
  • Browser: iOS Safari
  • React-pdf version: 5.2.0 and bumping to 5.7.2 didn't help it
@walpolsh walpolsh added the bug Something isn't working label Jun 28, 2022
@bng41986
Copy link

We are experiencing the same issue with iOS users. It seems Safari holds on to canvases for a while. In our testing, the document usually loaded initially but if we tried to refresh the page a couple times it would fail. The scenario being that when the document is big, a person might get impatient waiting for it to download/render and then try to refresh several times to get it to load. We figure this then creates multiple canvases which causes the browser to exceed the memory limit. If that is the case, a solution could be to clear the canvas on an unload event (like on refresh or navigating away from the page or closing the tab etc).

@obeces
Copy link

obeces commented Jul 28, 2022

Probably the canvas exceeds the size allowed by Safari and retina displays.
Checkout this links for more info:
https://github.com/jhildenbiddle/canvas-size
https://stackoverflow.com/questions/6081483/maximum-size-of-a-canvas-element/53677532#53677532

@github-actions
Copy link
Contributor

This issue is stale because it has been open 90 days with no activity. Remove stale label or comment or this issue will be closed in 14 days.

@github-actions github-actions bot added the stale label Oct 31, 2022
@github-actions
Copy link
Contributor

This issue was closed because it has been stalled for 14 days with no activity.

@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Nov 21, 2022
@wojtekmaj
Copy link
Owner

wojtekmaj commented Nov 22, 2022

In 45a19b6, 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, and thus also lowering memory usage.

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!

@walpolsh
Copy link
Author

walpolsh commented Dec 13, 2022

@wojtekmaj Hi, I've tried adding the devicePixelRatio and fixing it at 1, 2 and using the Math.min formula but it's still freezing on large PDFs. There's no more error message but i think it locks up before having a chance to throw something.

@walpolsh
Copy link
Author

@wojtekmaj I think I've fixed it by using your suggestion to add react-window for large PDFs. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working stale
Projects
None yet
Development

No branches or pull requests

4 participants