eugeneware / gifencoder

Server side animated gif generation for node.js
Other
472 stars 49 forks source link

incorrect generating gif when using sharp #26

Closed hbakhtiyor closed 6 years ago

hbakhtiyor commented 6 years ago

the sample code

const fs = require('fs');
const sharp = require('sharp');
const GIFEncoder = require('gifencoder');

(async () => {
  const image = await sharp('thumbs.jpeg').raw().toBuffer({resolveWithObject: true});

  const encoder = new GIFEncoder(image.info.width, image.info.height);

  encoder.createReadStream().pipe(fs.createWriteStream('thumbs.gif'));

  encoder.start();
  encoder.setRepeat(-1);   
  encoder.setDelay(500);  
  encoder.setQuality(100);   

  encoder.addFrame(image.data);
  encoder.finish();
})()

the jpeg input and gif result. thumbs thumbs

heikkipora commented 6 years ago

encoder.addFrame() expects the data to be in RGBA layout (4 bytes per pixel). I assume sharp's .raw() produces 3 bytes per pixel by default. Are there options in sharp to change that to 4 bytes/channels per pixel?

heikkipora commented 6 years ago

I took a look at the issue you referenced only now - do I read it correctly that you tried four channels already but had no luck? Anyway, the mangled output image you posted above clearly looks like it's missing one channel.

hbakhtiyor commented 6 years ago

played with raw option in constructor, but doesn't work.

const imageData = await sharp('thumbs.jpeg', {raw: {width: 1200, height: 630, channels: 4}}).raw().toBuffer();
hbakhtiyor commented 6 years ago

just used the .joinChannel(Buffer.alloc(width * height, 255), { raw: { channels: 1, width, height} }) workaround and works well

const fs = require('fs');
const sharp = require('sharp');
const GIFEncoder = require('gifencoder');

(async () => {
  const width = 1200, height = 630;
  const imageData = await sharp('thumbs.jpeg')
  .joinChannel(Buffer.alloc(width * height, 255), { raw: { channels: 1, width, height} })
  .raw().toBuffer();

  const encoder = new GIFEncoder(width, height);

  encoder.createReadStream().pipe(fs.createWriteStream('thumbs.gif'));

  encoder.start();
  encoder.setRepeat(-1);   
  encoder.setDelay(500);  
  encoder.setQuality(100);   

  encoder.addFrame(imageData);
  encoder.finish();
})()
heikkipora commented 6 years ago

Good to hear that!

hbakhtiyor commented 6 years ago

generating a bit blur image than original

elemarin commented 5 years ago

Hi, I came across a similar issue, and tried the suggested workaround, but this caused the image to look different than expected when resizing.

here's how it looked with the workaround:

gitExample

after investigating, it seems like there is a simpler way to add the missing channel when using Sharp's raw()

here's the code I used

const fs = require('fs');
const sharp = require('sharp');
const GIFEncoder = require('gifencoder');

(async () => {

    let transform = sharp('imagen.jpg');

    transform.resize(200, 800, {
        fit: 'contain',
        background: {
            r: 255,
            g: 255,
            b: 255,
            alpha: 1
        }
    });

    transform.ensureAlpha();

    transform.raw();

    let buffer = await transform.toBuffer();

    const encoder = new GIFEncoder(200, 800);

    encoder.createReadStream().pipe(fs.createWriteStream('gitExample.gif'));

    encoder.start();
    encoder.addFrame(buffer);
    encoder.finish();
})()

and the image that this produces:

gitExample