Nimble Polyglot Microcosm

    gif-encoder-2

    1.0.5 • Public • Published

    gif-encoder-2

    Encode GIFs with Node.js

    Contents

    Installation

    npm install gif-encoder-2
    

    Overview

    This library builds on top of previous JavaScript GIF encoders including jsgif and gifencoder.

    This library adds the Octree quantization algorithm as an alternative to the original NeuQuant algorithm.

    This library adds a simple optimizer to speed up overall processing time of both algorithms.

    This library adds a progress event.

    This library is designed to be used in a Node environment, including the Electron renderer process. Node Canvas can be a useful peer library but isn't required. The [HTML Canvas API] can be used in Electron.

    Usage

    Constructor

    GIFEncoder(width, height, algorithm, useOptimizer, totalFrames)

    Parameter Type Description Required Default
    width number the width of images in pixels yes n/a
    height number the height of images in pixels yes n/a
    algorithm string neuquant or octree no neuquant
    useOptimizer boolean enables/disables optimizer no false
    totalFrames number total number of images no 0
    const encoder = new GIFEncoder(500, 500)
    const encoder = new GIFEncoder(1200, 800, 'octree', false)
    const encoder = new GIFEncoder(720, 480, 'neuquant', true, 20)

    Methods

    Method Parameter Description Notes
    start n/a Starts the encoder n/a
    addFrame Canvas Context Adds a frame to the GIF n/a
    setDelay number Number of milliseconds to display frame Can be set once or per frame
    setFramesPerSecond number Number of frames per second to display Another way to set delay
    setQuality number 1-30 Neuquant quality 1 is best/slowest
    setThreshold number 0-100 Optimizer threshold percentage Color table reused if current frame matches previous frame
    setRepeat number >= 0 Number of loops GIF does 0 is forever, anything else if literal number of loops
    finish n/a Stops the encoder Call after all frames are added

    Examples

    Canvas Animation

    Draw a square that changes color as it moves.

    const GIFEncoder = require('gif-encoder-2')
    const { createCanvas } = require('canvas')
    const { writeFile } = require('fs')
    const path = require('path')
     
    const size = 200
    const half = size / 2
     
    const canvas = createCanvas(size, size)
    const ctx = canvas.getContext('2d')
     
    function drawBackground() {
      ctx.fillStyle = '#ffffff'
      ctx.fillRect(0, 0, size, size)
    }
     
    const encoder = new GIFEncoder(size, size)
    encoder.setDelay(500)
    encoder.start()
     
    drawBackground()
    ctx.fillStyle = '#ff0000'
    ctx.fillRect(0, 0, half, half)
    encoder.addFrame(ctx)
     
    drawBackground()
    ctx.fillStyle = '#00ff00'
    ctx.fillRect(half, 0, half, half)
    encoder.addFrame(ctx)
     
    drawBackground()
    ctx.fillStyle = '#0000ff'
    ctx.fillRect(half, half, half, half)
    encoder.addFrame(ctx)
     
    drawBackground()
    ctx.fillStyle = '#ffff00'
    ctx.fillRect(0, half, half, half)
    encoder.addFrame(ctx)
     
    encoder.finish()
     
    const buffer = encoder.out.getData()
     
    writeFile(path.join(__dirname, 'output', 'beginner.gif'), buffer, error => {
      // gif drawn or error
    })

    Sequencial Images

    Create a function that reads a directory of images and turns them into a GIF.

    const GIFEncoder = require('gif-encoder-2')
    const { createCanvas, Image } = require('canvas')
    const { createWriteStream, readdir } = require('fs')
    const { promisify } = require('util')
    const path = require('path')
     
    const readdirAsync = promisify(readdir)
    const imagesFolder = path.join(__dirname, 'input')
     
    async function createGif(algorithm) {
      return new Promise(async resolve1 => {
        // read image directory
        const files = await readdirAsync(imagesFolder)
     
        // find the width and height of the image
        const [width, height] = await new Promise(resolve2 => {
          const image = new Image()
          image.onload = () => resolve2([image.width, image.height])
          image.src = path.join(imagesFolder, files[0])
        })
     
        // base GIF filepath on which algorithm is being used
        const dstPath = path.join(__dirname, 'output', `intermediate-${algorithm}.gif`)
        // create a write stream for GIF data
        const writeStream = createWriteStream(dstPath)
        // when stream closes GIF is created so resolve promise
        writeStream.on('close', () => {
          resolve1()
        })
     
        const encoder = new GIFEncoder(width, height, algorithm)
        // pipe encoder's read stream to our write stream
        encoder.createReadStream().pipe(writeStream)
        encoder.start()
        encoder.setDelay(200)
     
        const canvas = createCanvas(width, height)
        const ctx = canvas.getContext('2d')
     
        // draw an image for each file and add frame to encoder
        for (const file of files) {
          await new Promise(resolve3 => {
            const image = new Image()
            image.onload = () => {
              ctx.drawImage(image, 0, 0)
              encoder.addFrame(ctx)
              resolve3()
            }
            image.src = path.join(imagesFolder, file)
          })
        }
      })
    }
     
    createGif('neuquant')
    createGif('octree')

    NeuQuant Algorithm

    Octree Algorithm

    Algorithms

    • NeuQuant tends to perform faster than Octree
    • Octree tends to output a smaller file than NeuQuant
    • Octree produces a slight banding effect

    The example above encodes 20 images measuring 300px x 240px. The output file from NeuQuant is 1172KB and the Octree is less than half of that at 515KB.

    Optimizer

    The optimizer works by reusing the color palette from the previous image on the current image. This can reduce the overall processing time signifigantly but its best suited for a sequence of similarly colored images. Use the setThreshold method to set a percentage determining how similar the two images must be to trigger the optimizer. The default is 90%. The optimizer is only used if true is passed as the 4th argument to the constructor.

    Progress Event

    Works if totalFrames is expressed in constructor, otherwise this value will be 0.

    encoder.on('progress', percent => {
      // do something with percent value
    })

    Install

    npm i gif-encoder-2

    DownloadsWeekly Downloads

    2,810

    Version

    1.0.5

    License

    UNLICENSE

    Unpacked Size

    42.4 kB

    Total Files

    8

    Last publish

    Collaborators

    • benjaminadk