devongovett / png-stream

A streaming PNG encoder and decoder
29 stars 4 forks source link

How to decode and then encode the decoded data #1

Closed MichalPaszkiewicz closed 9 years ago

MichalPaszkiewicz commented 9 years ago

I am struggling to figure out how to read a stream from one file, editing the pixel values and then writing to another. I have tried:

    fs.createReadStream('in.png')
    .pipe(new PNGDecoder)
    .pipe(concat(function(frames) {
                     //Editing the pixel values in here;
    }))
    .pipe(new PNGEncoder)
    .pipe(fs.createWriteStream('out.png'));

and also this:

fs.createReadStream('default.png')
    .pipe(new PNGDecoder)
    .pipe(concat(function(frames) {

        var encoder = new PNGEncoder(100,100,{animated: true});
                         .pipe(fs.createWriteStream('out.png'));

        for(var i = 0; i < frames.length; i++){
            var pixels = frames[i].pixels;

            for(var j = 0; j < pixels.length; j+=4){
                var r = pixels[j];
                var g = pixels[j+1];
                var b = pixels[j+2];
                var a = pixels[j+3];

                r = Math.max(255, r + 20);

                frames[i].pixels[j] = r;
                frames[i].pixels[j+1] = g;
                frames[i].pixels[j+2] = b;
                frames[i].pixels[j+3] = a;
            }

            encoder.write(frames[i]);
        }

        encoder.end();

    }));

Neither of which work.

It would be great if there was some documentation as to how to use the encoder...

devongovett commented 9 years ago

The second example is really close. It should work with encoder.write(frames[i].pixels). You can also use encoder.addFrame(frame) before calling encoder.write to set frame metadata, like the delay between frames, etc.

Unfortunately, this requires the entire PNG to be decoded before you do any encoding, which isn't necessary for your example. You are just modifying some pixels it looks like, so it would be better to do this in a streaming way so that the whole file and not even a whole frame needs to be decoded at once. To do this, you can write a pixel-stream implementation to transform the pixels, and then pipe the image through it before getting to the encoder (see below). For a good example of writing a transform stream that modifies pixels, see color-transform.

fs.createReadStream('in.png')
    .pipe(new PNGDecoder)
    .pipe(new MyTransformStream)
    .pipe(new PNGEncoder)
    .pipe(fs.createWriteStream('out.png'));
MichalPaszkiewicz commented 9 years ago

Awesome, thanks!