0

I have an SVG in the browser

<svg>
    <image width="100" height="100" xlink:href="data:image/gif;base64,R0l...">
</svg>

Can I check somehow if the gif is animated?

I have tried some NPM packages:

https://www.npmjs.com/package/is-animated

https://www.npmjs.com/package/animated-gif-detector

But they seem to requite access to buffers that are not available in the browser.

Here is some code that does not work:

import isAnimated from "is-animated";

export function prepareImages(xml: Document) {
  xml.querySelectorAll("image").forEach((image) => {
    const hrefData = image.href.baseVal;
    const base64Data = hrefData.replace(/^data:.+?base64,/, "");
    const binaryData = atob(base64Data);
    const bufferData = new Buffer(binaryData, "binary");
    const animated = isAnimated(bufferData);
}

I get this error:

prepareImages.ts:8 Uncaught (in promise) ReferenceError: Buffer is not defined

johannchopin
  • 13,720
  • 10
  • 55
  • 101
user1283776
  • 19,640
  • 49
  • 136
  • 276

1 Answers1

0

Here is how I solved it. It seems to be working.

// adapted from: https://gist.github.com/zakirt/faa4a58cec5a7505b10e3686a226f285

const HEADER_LEN = 6; // offset bytes for the header section
const LOGICAL_SCREEN_DESC_LEN = 7; // offset bytes for logical screen description section

export function isGifAnimated(buffer: ArrayBuffer) {
  // Start from last 4 bytes of the Logical Screen Descriptor
  const dv = new DataView(buffer, HEADER_LEN + LOGICAL_SCREEN_DESC_LEN - 3);
  const globalColorTable = dv.getUint8(0); // aka packet byte
  let globalColorTableSize = 0;
  let offset = 0;

  // check first bit, if 0, then we don't have a Global Color Table
  if (globalColorTable & 0x80) {
    // grab the last 3 bits, to calculate the global color table size -> RGB * 2^(N+1)
    // N is the value in the last 3 bits.
    globalColorTableSize = 3 * Math.pow(2, (globalColorTable & 0x7) + 1);
  }

  // move on to the Graphics Control Extension
  offset = 3 + globalColorTableSize;

  var extensionIntroducer = dv.getUint8(offset);
  var graphicsConrolLabel = dv.getUint8(offset + 1);
  var delayTime = 0;

  // Graphics Control Extension section is where GIF animation data is stored
  // First 2 bytes must be 0x21 and 0xF9
  if (extensionIntroducer & 0x21 && graphicsConrolLabel & 0xf9) {
    // skip to the 2 bytes with the delay time
    delayTime = dv.getUint16(offset + 4);
  }

  return Boolean(delayTime);
}
user1283776
  • 19,640
  • 49
  • 136
  • 276