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

Max size of image #1082

Closed
eNepper opened this issue Jan 29, 2018 · 13 comments
Closed

Max size of image #1082

eNepper opened this issue Jan 29, 2018 · 13 comments

Comments

@eNepper
Copy link

eNepper commented Jan 29, 2018

Hi

Is there a max size on image?
I trying to set the src paramter of an image to a buffer containing an 28086x19866 px image and my node app just quits after that, no error no nothing.

-- Esben N.

@zbjornson
Copy link
Collaborator

I think the max image size is 32,767 px in either dimension, but you're likely hitting some allocation failure for the format parser. What type of image is in the buffer (PNG, GIF, JPEG, SVG)?

@eNepper
Copy link
Author

eNepper commented Jan 29, 2018

If I'm not mistaken it's a PNG image.

@zbjornson
Copy link
Collaborator

I just successfully loaded a 1.45GB PNG (28,000 x 18,666 px).

const fs = require("fs");
const {Image} = require("./index");

const buff = fs.readFileSync("big.png");
console.log(buff.byteLength);

const img = new Image();
img.src = buff;
console.log(img);

Any more info you can provide?

@eNepper
Copy link
Author

eNepper commented Jan 29, 2018

It's another canvas I'm turning in to an image not sure if that any different.
I also tried to reuse the canvas but then I get this error: GLib-GObject-CRITICAL **: g_object_unref: assertion 'G_IS_OBJECT (object)' failed

@eNepper
Copy link
Author

eNepper commented Jan 29, 2018

The canvas buffer is "only" 24092988 bytes long :/

@zbjornson
Copy link
Collaborator

Can you post a short code example that reproduces it please?

If the error is in some use of GLib then I might have missed it by trying to reproduce it on Windows. I can try on linux later.

@eNepper
Copy link
Author

eNepper commented Jan 29, 2018

I'll see if I can create a sample that reproduces this that I'm able to share with you.
I'm running it on a Ubuntu 17.10 with Node v8.9.4

@zbjornson
Copy link
Collaborator

That's a Cairo message/limitation that we can't do anything about. In the Cairo source I only see it raised if there is one dimension >32767 px (or <=0) though, which is larger than the dimensions you mentioned...

@eNepper
Copy link
Author

eNepper commented Jan 30, 2018

I found a mistake I made trying to set the src to a PDF canvas buffer, but I'm getting "Error: out of memory" now. But when I look at the memory usages on my machine it's no more than 40%

@eNepper
Copy link
Author

eNepper commented Jan 30, 2018

const { createCanvas, Image } = require('canvas');
const fs = require('fs');

const size = { width: 28086, height: 19866 };

let base = new Promise((resolve, reject) => {
    let canvas = createCanvas(size.width, size.height);
    let ctx = canvas.getContext('2d');

    let gradient = ctx.createLinearGradient(0, 0, size.width, size.height);
    gradient.addColorStop(0, '#8FBC8F');
    gradient.addColorStop(0.25, '#BA55D3');
    gradient.addColorStop(0.5, '#FF00FF');
    gradient.addColorStop(0.75, '#7CFC00');
    gradient.addColorStop(1, '#00BFFF');

    ctx.fillStyle = gradient;
    ctx.fillRect(0, 0, size.width, size.height);

    resolve(canvas.toBuffer());
});

let overlay = new Promise((resolve, reject) => {
    let canvas = createCanvas(size.width, size.height);
    let ctx = canvas.getContext('2d');

    ctx.beginPath();
    ctx.arc(size.width / 2, size.height / 2, size.width / 4, 0, 2 * Math.PI);
    ctx.fillStyle = '#9932CC';
    ctx.fill();

    resolve(canvas.toBuffer());
});


Promise.all([base, overlay]).then(layers => {
    return new Promise((resolve, reject) => {
        let canvas = createCanvas(size.width, size.height);
        let ctx = canvas.getContext('2d');
        let img = new Image();
        img.onload = _ => {
            ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
            img.src = null;
            if (layers.length > 0) {
                drawLayers(layers);
            } else {
                resolve(canvas);
            }
        };
        img.onerror = (err) => {
            console.log(err.toString());
        };
        

        drawLayers(layers.reverse());

        function drawLayers(layers) {
            img.src = layers.pop();
        }
    });
}).then(canvas => {
    fs.writeFile(`issue-#1082.png`, canvas.toBuffer(), function (err) {
        if (err) throw err;
    });
});

This code results in a "Error: out of memory" on my machine, which I don't get why as I got 16 gigs and the usages is no more than 40%.

@zbjornson
Copy link
Collaborator

"Error: out of memory" on my machine, which I don't get why as I got 16 gigs and the usages is no more than 40%.

That means that the next attempted allocation failed, so if you have 60% of 16 GB and try to allocate 61% of 16 GB, you would get that error. (Depending on how you're looking at available memory you might also just be seeing used memory but not committed memory.)

You're using a 64-bit build, right?


I don't think there's anything we can do here to allow more memory to be used as it's a limitation of Cairo and/or your hardware.

Some tips that might help reduce memory needs, looking at your example:

  • I'm not sure how different your real code is from your sample above, but the base and overlay look like they don't need to be created on separate canvases -- you could render those bits directly to the final canvas.
  • You're holding ~3 canvases in memory at once. You could have the final canvas and just one of the other layers at a time (do the layers sequentially).
  • PDF surfaces often use less memory because the vector elements are held instead of rasterized immediately like an image surface.
  • In the final then you're calling toBuffer(). Try piping a canvas.pngStream() instead.

img.src = null;

I hope I fixed this some time ago in #1003 (canvas 2.x) btw. If you're in 2.x and still seeing a need for it, let me know.

@eNepper
Copy link
Author

eNepper commented Jan 30, 2018

The sample resembles the structure of the code I'm working on but base is a layer of image tiles from another process which I'm stitching together before rendering an overlay on top from SVG data. I working on parallelizing the processes as much as possible to cut down process time.

Yes I'm running on 64bit

I'll look into implementing some of your recommendations.

@zbjornson
Copy link
Collaborator

Closing since I don't think there's anything we can do within node-canvas...

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