export DOM Node to GIF with gif-encoder and dom-to

2019-08-25 16:27发布

I am desperately trying to get a non-animated gif export from a DOM Node, on client-side, but without any success yet.

I use for that the lib dom-to-image which, thanks to it's method toPixelData, return some pixels. Then I want these pixels to give me a gif. I use for this the lib gif-encoder which sounds great. I thought about using a Promise for that because the last step is to put this gif in a ZIP file created by JSZip.

Here is the code below. Consider that I already have the DOM Node as an input, with predefined height and width. Everything is going pretty well, until the step where I need to convert my GifEncoder instance to a blob, in order to download it.

import domtoimage from 'dom-to-image';
import GifEncoder from 'gif-encoder';
const fs = require('localstorage-fs');
const toBlob = require('stream-to-blob');
import JSZip from 'jszip';

const pixelsToGIF = (pixels, width, height) =>
  new Promise((resolve, reject) => {
    const gif = new GifEncoder(width, height);
    const gifFile = fs.createWriteStream('image.gif');
    gif.pipe(gifFile);
    gif.writeHeader();
    gif.addFrame(pixels);
    gif.finish();
    gif.on('data', function() {
      console.log(this); //GIFEncoder, a constructor function which extends readable-stream@~1.1.9 (cf doc.)
      toBlob(this, function (err, blob) {
        console.error(err) // No error
        console.log(blob) // Blob of size 0
        resolve(blob)
      })
    })
    gif.on('error', reject)
  })

const zip = new JSZip();
domtoimage
.toPixelData(DOMNode, { width, height })
.then(pixels => pixelsToGIF(pixels, 'image.gif', width, height))
.then(gif => { 
  console.log(gif); // Blob of size 0
  zip.file('image.gif', gif)
})
.catch(e => console.log('couldn\'t export to GIF', e));

I also tried to use gif.on('end', function () {} ) instead of gif.on('data'), but except for the property readable which is true for the event data, and false for the event end, the result is the same: Blob of size 0. Where is the mistake ?

1条回答
你好瞎i
2楼-- · 2019-08-25 16:51

So the creator of gif-encoder lib found the solution, and here it is below. If I may quote him :

Our library outputs the GIF as data, not as an DOM element or similar. To aggregate this content, you can collect the stream into a buffer or pass it along to its target

So the proper code for this is finally :

import domtoimage from 'dom-to-image';
import concat from 'concat-stream';
import GifEncoder from 'gif-encoder';
import JSZip from 'jszip';

const pixelsToGIF = (pixels, width, height) =>
  new Promise((resolve, reject) => {
    const gif = new GifEncoder(width, height);
    gif.pipe(concat(resolve));
    gif.writeHeader();
    gif.addFrame(pixels);
    gif.finish();
    gif.on('error', reject);
  })

const zip = new JSZip();
domtoimage
.toPixelData(DOMNode, { width, height })
.then(pixels => pixelsToGIF(pixels, 'image.gif', width, height))
.then(gif => zip.file('image.gif', gif))
.catch(e => console.log('couldn\'t export to GIF', e));
查看更多
登录 后发表回答