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

saving the same pixel data twice (or more) results in an invalid additional files #252

Open
ccoenen opened this issue Apr 17, 2021 · 1 comment

Comments

@ccoenen
Copy link

ccoenen commented Apr 17, 2021

I am saving a file to PNG, but the pixel data will keep updating (and I will need to save it over and over again).

Currently, the first file works out fine, and every subsequent file will be an invalid file. I also receive an error message after a few saved files ("info" lines are my own logger), this output was generated with node --trace-warnings index.js:

info: storing current image in public/stored/1618704065758.png
info: storing current image in public/stored/1618704066763.png
info: storing current image in public/stored/1618704067767.png
info: storing current image in public/stored/1618704068781.png
info: storing current image in public/stored/1618704069783.png
info: storing current image in public/stored/1618704070792.png
info: storing current image in public/stored/1618704071793.png
(node:16828) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 end listeners added to [Stream]. Use emitter.setMaxListeners() to increase limit
    at _addListener (node:events:451:17)
    at exports.PNG.addListener (node:events:467:10)
    at exports.PNG.Stream.pipe (node:internal/streams/legacy:38:12)
    at (my own code, redacted)
    at new Promise (<anonymous>)
    at (my own code, redacted)
    at Timeout._onTimeout ((my own code, redacted))
    at listOnTimeout (node:internal/timers:556:17)
    at processTimers (node:internal/timers:499:7)
(node:16828) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 close listeners added to [Stream]. Use emitter.setMaxListeners() to increase limit
    at _addListener (node:events:451:17)
    at exports.PNG.addListener (node:events:467:10)
    at exports.PNG.Stream.pipe (node:internal/streams/legacy:39:12)
    at (my own code, redacted)
    at new Promise (<anonymous>)
    at Canvas.store (my own code, redacted)
    at Timeout._onTimeout (my own code, redacted)
    at listOnTimeout (node:internal/timers:556:17)
    at processTimers (node:internal/timers:499:7)
info: storing current image in public/stored/1618704072801.png
... (info lines continue) ...

Here's a pretty minimal example to illustrate my problem:

import fs from 'fs';
import { PNG } from 'pngjs';

const width = 256;
const height = 256;
const canvas = new PNG({width, height});

for (let x = 0; x < width; x++) {
	for (let y = 0; y < height; y++) {
		// drawing something nice, just so that we have something to look at.
		canvas.data[(y * width + x) * 4 + 0] = x;
		canvas.data[(y * width + x) * 4 + 1] = y;
		canvas.data[(y * width + x) * 4 + 2] = 0;
		canvas.data[(y * width + x) * 4 + 3] = 0xFF; // FF => fully opaque.
	}
}

const out = fs.createWriteStream('file 1.png');
canvas.pack().pipe(out);
out.on('finish', () => {
	const out2 = fs.createWriteStream('file 2.png');
	canvas.pack().pipe(out2);
});

What currently happens

file 1.png will show a nice demo pattern and is about 1KB in size. file 2.png is broken and (usually) 33 bytes. If it is larger (which also happens) it's a multiple of 33 bytes.

What I would like it to do

I'd like it to store the pixel data over and over again. I would also be fine with a workaround.

@Claytonn
Copy link

I'm not sure if there is a proper way to do this, but I ran into the same issue. I worked around it by just creating a copy of the PNG before I pack it with PNG.bitblt

import fs from 'fs';
import { PNG } from 'pngjs';

const width = 256;
const height = 256;
const canvas = new PNG({ width, height });

for (let x = 0; x < width; x++) {
    for (let y = 0; y < height; y++) {
        // drawing something nice, just so that we have something to look at.
        canvas.data[(y * width + x) * 4 + 0] = x;
        canvas.data[(y * width + x) * 4 + 1] = y;
        canvas.data[(y * width + x) * 4 + 2] = 0;
        canvas.data[(y * width + x) * 4 + 3] = 0xFF; // FF => fully opaque.
    }
}

const exportPNG = (png, fileName) => {
    const pngCopy = new PNG({ width: png.width, height: png.height });
    PNG.bitblt(png, pngCopy, 0, 0, png.width, png.height, 0, 0);
    pngCopy.pack().pipe(fs.createWriteStream(fileName));
}

exportPNG(png, 'file 1.png');
exportPNG(png, 'file 2.png');

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