blobinfo

0.1.2 • Public • Published

BlobInfo

Lightweight JavaScript library designed for inspecting blobs, mostly for getting image properties.

Introduction

BlobInfo allows to get useful information about binary data (blob). The library is specialized for getting image properties, but it can be extended in the future to get properties of other media files as well. BlobInfo doesn't depend on any other library and should run in node.js and browser environments without any modifications.

BlobInfo has been designed in a portable way. It doesn't use filesystem or any other APIs to read files directly from a storage. It expects that you have already the content of a file or at least some part of it. It accepts a node.js Buffer or just String with binary data that is to be inspected.

BlobInfo can be considered as a high-performance library. It doesn't create any temporary objects while inspecting, it doesn't use Buffer.slice() or String.substr() to get a part of inspected buffer and it tries to bail out as fast as possible to not waste time on inspecting something that will fail at later phase.

Usage

BlobInfo has a very simple API, basically all you need to start is to import the library and use inspect() function that returns an object of recognized properties of a given blob on success; on failure null would be returned.

var blobinfo = require("blobinfo");
 
// This is a PNG image from PNG test suite, also part of BlobInfo's unit test.
var buffer = new Buffer([
  0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
  0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x08,0x08,0x02,0x00,0x00,0x00,0x17,0xe7,0x6a,
  0xf8,0x00,0x00,0x00,0x04,0x67,0x41,0x4d,0x41,0x00,0x01,0x86,0xa0,0x31,0xe8,0x96,
  0x5f,0x00,0x00,0x00,0x03,0x73,0x42,0x49,0x54,0x04,0x04,0x04,0x77,0xf8,0xb5,0xa3,
  0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x01,
  0x00,0x1f,0xe8,0x55,0x65,0x00,0x00,0x00,0xeb,0x49,0x44,0x41,0x54,0x78,0x9c,0x7d,
  0x92,0x6b,0xb1,0xc3,0x20,0x14,0x84,0xbf,0xcc,0xd4,0xc0,0x5a,0xc0,0x42,0x2c,0xc4,
  0x42,0x2c,0xc4,0x42,0x2c,0xdc,0x58,0xa8,0x85,0x58,0xc0,0x02,0x16,0x8e,0x85,0x23,
  0x21,0xf7,0x07,0x8f,0x42,0xdb,0x74,0x87,0x01,0x06,0xe6,0xbc,0x76,0x77,0xba,0xf8,
  0x40,0x00,0xd5,0xc5,0xb8,0x37,0x78,0xdd,0xf3,0xc5,0xba,0xfb,0x88,0x47,0x39,0x05,
  0x33,0xac,0xb0,0x96,0x87,0x16,0xd2,0x07,0x7a,0x57,0xa8,0xf5,0x10,0xda,0xa3,0xc1,
  0x01,0x09,0xac,0x2f,0x20,0x58,0x20,0x94,0xde,0x5d,0x44,0x88,0xf0,0x2c,0xb3,0x6c,
  0xb8,0x70,0x61,0xdd,0x14,0x72,0xe4,0x04,0x20,0xc1,0x29,0xfc,0x0f,0x66,0x98,0x03,
  0xe4,0xe5,0x10,0x4b,0x99,0x07,0xeb,0x2b,0xd0,0x4a,0x5e,0x1c,0x91,0x3f,0xce,0x5d,
  0x4f,0xb6,0xc8,0x46,0xac,0xc3,0xc8,0x08,0x07,0x73,0xdc,0x61,0x4d,0xcc,0x82,0x68,
  0x24,0x03,0x6b,0xf3,0xe7,0xe8,0x13,0xac,0x51,0x74,0x07,0x81,0x30,0x91,0x90,0xaa,
  0x14,0x86,0x9c,0x4e,0xa4,0x3b,0x38,0xc0,0x74,0xf5,0x14,0x2d,0xf8,0xf2,0x46,0xd1,
  0x02,0x01,0x07,0xd7,0x20,0x42,0x66,0x09,0x83,0x18,0xf0,0x3d,0x53,0xe4,0x70,0xd4,
  0xd4,0x95,0xa2,0xe9,0x6a,0x9d,0x86,0x41,0x64,0x1f,0xad,0xf1,0x66,0x10,0x8d,0x22,
  0xbf,0x28,0x3e,0xc0,0x06,0x91,0xa7,0x2f,0x36,0xed,0x9d,0xf1,0x83,0x87,0xde,0xa9,
  0x7e,0x6b,0xd3,0x7f,0x08,0xcd,0x5c,0xaa,0x68,0xbe,0xfb,0xa4,0x00,0x00,0x00,0x00,
  0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
]);
 
console.log(blobinfo.inspect(buffer));

The code above should output something like:

{
  "type"     : "image",
  "mime"     : ["image/png"],
  "extension": [".png"],
  "width"    : 32,
  "height"   : 8
}

There is also a second and purely optional parameter, which can be used to specify file types that will be accepted:

console.log(blobinfo.inspect(buffer, ["images/png", "image/jpeg"])); // Success.
console.log(blobinfo.inspect(buffer, ["images/bmp", "image/jpeg"])); // Failure.

The first call to inspect in the code above returns exactly the same object as in the first example, however, the second call returns null, because PNG data doesn't match BMP or JPEG signature.

Supported File Types

  • BMP (image/bmp or image/x-bmp)
  • GIF (image/gif)
  • JPEG (image/jpeg)
  • PNG (image/png)

Implementation Details

BlobInfo has been designed for future extensions and adding more file types is welcome. The core of the library itself is very small and uses inspectors that are specialized for a particular file formats. Mandatory properties of the inspector are:

var Inspector = {
  // Function that is called to inspect a data buffer.
  inspect: function(reader, data) {
    ...
  },
 
  type: "string",         // Optional  - file-type.
  mime: ["string"],       // Mandatory - list of mime types.
  extension: [".string"], // Optional  - list of file extensions.
  lead: 0x00              // Optional  - magic byte.
};

The most interesting part is the inspect() function. It accepts reader and data parameters. The reader is an instance of BufferReader or StringReader, both private objects not accessible outside of BlobInfo, which is used to access bytes stored in data. Reader is basically an interface to access String or Buffer without having to worry about the data type.

The reader object provides the following methods:

// Methods to read BYTE, WORD, or DWORD.
function read8(data, offset)
function read16LE(data, offset);
function read16BE(data, offset);
function read32LE(data, offset);
function read32BE(data, offset);

// Comparison.
function equals(data, offset, pattern);

Methods, which starts with read are used to read BYTE, WORD or DWORD depending on suffix and endianness. Function equals is used to compare bytes in data starting from offset against pattern (pattern can be Array of bytes or Buffer, but not String).

Adding a new, global, inspector is possible through addInspector() function. The following example shows how to create a new inspector for inspecting a PCX file and to how add it dynamically to the global inspectors list:

blobinfo.addInspector({
  inspect: function(reader, data) {
    var len = data.length;
    var fileSize;

    // We need at least 12 bytes to determine image width and height.
    if (len < 12)
      return null;

    // Check the file signature, see `fileSig` (0A 05).
    if (!reader.equals(data, 0, this.fileSig))
      return null;

    // Read the most interesting information stored in the header.
    var xMin = reader.read16LE(data, 4);
    var yMin = reader.read16LE(data, 6);
    var xMax = reader.read16LE(data, 8);
    var yMax = reader.read16LE(data, 10);

    // Broken or no PCX.
    if (xMin >= xMax || yMin >= yMax)
      return null;

    // Probably PCX.
    return {
      type        : this.type,
      mime        : this.mime,
      extension   : this.extension,
      width       : xMax - xMin + 1,
      height      : yMax - yMin + 1,
      bitsPerPixel: reader.read8(data, 3)
    };
  },

  type: "image",
  mime: ["application/pcx"],
  extension: [".pcx"],

  // Leading byte, not required, but helps to determine the file type faster
  // without calling `inspect()`.
  lead: 0x0A,

  // This is not required, but fileSig is used by nearly all inspectors.
  fileSig: [0x0A, 0x05]
});

Please note that PCX is not part of files recognized by BlobInfo. It's just an example, which tries to explain the concept on something that is working.

Package Sidebar

Install

npm i blobinfo

Weekly Downloads

0

Version

0.1.2

License

Unlicense

Last publish

Collaborators

  • kobalicek