npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@luxbug/gif-encoder-2

v1.0.0

Published

GIF generator for Node.js

Downloads

14

Readme

gif-encoder-2

Encode GIFs with Node.js

Contents

Installation

npm install @luxbug/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
})