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

Calling getImageData in Safari raises InvalidStateError #231

Open
1 task
sandstrom opened this issue May 5, 2022 · 1 comment
Open
1 task

Calling getImageData in Safari raises InvalidStateError #231

sandstrom opened this issue May 5, 2022 · 1 comment

Comments

@sandstrom
Copy link
Contributor

sandstrom commented May 5, 2022

When doing resizes with Pica, we sometimes get an error when pica calls getImageData.

The error that Safari throws is:

InvalidStateError · The object is in an invalid state.

It's called on this line:

https://github.com/nodeca/pica/blob/6.1.1/index.js#L362

So it's the canvas we're passing into pica. In other words, this could very well be an issue outside pica, since the canvas in question wasn't created by pica.

In any case, I wanted to open this issue to see if others had the same problem, and to store some of my thoughts around this.

Possible causes

I've done some searching and found these two blog posts:

https://pqina.nl/blog/canvas-area-exceeds-the-maximum-limit/
https://pqina.nl/blog/total-canvas-memory-use-exceeds-the-maximum-limit/

According to them this could be caused by using using a too large canvas (max width/height is 4096 x 4096), however I know pica does tiling, so that shouldn't happen. Another possible cause mentioned in that blog post, is that Safari has trouble with releasing memory allocated to canvas after they're discarded.

They offer a suggestion to remedy this:

function releaseCanvas(canvas) {
    canvas.width = 1;
    canvas.height = 1;
    const ctx = canvas.getContext('2d');
    ctx && ctx.clearRect(0, 0, 1, 1);
}

Quoting from the blog post:

We’re going to have to help out Safari to clean up its mess. Get rid of the things it can’t or won’t throw away.

When we’re done with a element we have to manually “release” it.

Meaning we resize the canvas to a very small size and clear its contents, this tricks Safari in to replacing the canvas in its storage with our compressed version.

The [above] function will do just that.

Safari will still hold on to the for a while, but at least now it won’t blow the roof of its storage depot.

Possible fixes

Applying the releaseCanvas method above may help. I checked the source and pica already sort of does this:

pica/index.js

Lines 526 to 530 in e4e6616

if (tmpCanvas) {
// Safari 12 workaround
// https://github.com/nodeca/pica/issues/199
tmpCanvas.width = tmpCanvas.height = 0;
}

Apparently I'm the one who suggested it 2 years ago (#199). Memory is short 😅

But maybe also calling clearRect would help further.

Basically enhance the existing fix to do what releaseCanvas above does. The author of that blog post has built an image editor based on canvas, so hopefully knows this area pretty well.

Versions

Pica Version: 6.1.1
Safari Version: 15.3.1, 15.4.0, 15.4.1 (we've seen this issue across ~250 users during the past few months)

TODO

  • We're going to try passing in something other than a canvas, and see if that helps.
@vedmant
Copy link

vedmant commented Mar 8, 2024

Having the same issue when trying to downsize the 10208x10208px image on iPhone, any way to resolve this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants