pngjs icon indicating copy to clipboard operation
pngjs copied to clipboard

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

Open ccoenen opened this issue 3 years ago • 1 comments

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.

ccoenen avatar Apr 17 '21 23:04 ccoenen