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

@cloudrac3r/giframe

v0.4.3

Published

extract the first frame in GIF without reading whole bytes, support both browser and nodejs, using stream-like decoder

Downloads

35

Readme

Forked from https://github.com/alienzhou/giframe


It's fast (decode on-demand) and compatible (both in browsers and nodejs).

No need to wait for and read all bytes and decode chunk by chunk, especially when only extracting the first frame. So it may be used for improving GIFs loading experiences, providing more controllable GIF loading strategies and so on.

Motivation

Some websites contain a lot of GIF images. Displaying animation images in your homepage, item list and so on may attract users' attention. However, GIF images are much larger than static images (sometimes 20x~30x depends on how many frames).

As a result, users need to wait for a long time to see GIF images. A common method is to extract the first frame as a placeholder and load GIF lazily when in view or clicked. There are lots of libraries to extract frames in the server-side. However, it has some limitations:

  • Most libs need to read whole bytes in GIF for extracting frames, even though we only need the first one. It's a waste of computing and time. For example, the first frame only use about 16% bytes in example/img/4.gif (8-frames) and .
  • This solution needs the support of the server-side or CDN. Is there any frontend-only solution to improve user experience?

This repository aims to provide a stream-like (decode chunk by chunk) GIF decoder which can run in both browsers (client-side) and NodeJS (server-side).

  • It will try to extract the needed frame without reading all bytes. You can read bytes and decode at the same time. It is useful especially when using stream in I/O.
  • Running in browsers means you can display a early static frame when downloading GIF, or use the client itself to calculate.

Below is an browser example. The first frame is extracted and used as a placeholder while the GIF image is still loading.

You can also play with it by yourself. Go to the Example section >>

Basic Usage

Support both in browsers and NodeJS,

import GIFrame from 'giframe';
const giframe = new GIFrame();
giframe.getBase64().then(base64 => {
    // finally get the base64 string of the first frame
    console.log(base64);
});

// then read GIF bytes from network, local file and so on
const source = readGIF('xxx.gif');
// chunk need to be Uint8Array
source.on('data', chunk => giframe.feed(chunk));

More complex usages can be found in example/ directory. You can also run examples below ↓↓↓

Example

Nodejs required.

This repo provides some examples in example/ which give you a quick start.

Firstly, clone the repo and install dependencies.

git clone [email protected]:alienzhou/giframe.git
cd giframe

# install dependencies
npm i

Run in browsers,

npm run example:browser

Then it will open http://127.0.0.1:8080 (default port 8080), you will see a demo page ↓

Or run in NodeJS,

# extract the first frame image
# you can change the gif filename (1.gif ~ 5.gif)
npm run example:node:stream 1.gif

# or you can run
npm run example:node:limit 1.gif

# then the first frame image will be written in example/output

How it works

For a quick and robust start, the decoder is mostly a folk of omggif. GIF is composed of many blocks. Giframe treats every block as a valid unit and resets the position to the previous block's end when meet an incomplete block. It will try to continue to decoding when receiving another chunk (more bytes). It's like stream.

To generate the image's base64, Giframe uses the Canvas API - node-canvas in NodeJS and native canvas in browsers. The canvas uses all RGBA pixels which are provided by Giframe to render a image and exports base64 string by .toDataURL().

By the way, the example in example/browser uses Service Worker, fetch event, fetch API and Readable Stream. It tees a stream from the response in fetch API and read it. Every chunk received will be used to decode progressively. Once the first frame is ready, it will be displayed on screen as a static preview.

Compatibility

Discarded: ~~Now GIFrame.js uses Proxy object to throw an error when accessing an out-of-range item in Uin8Array and catch it in the decoder to reset to the previous valid block's tail position. Proxy object isn't compatible in some browsers.~~

After v0.2.0, GIFrame uses a basic get function instead of the Proxy object. So mostly its compatibility depends on Uint8Array and Int32Array which are supported in most browsers.

compatibility

License

MIT