UNPKG

@khoohaoyit/image-size

Version:

A stream based image size extractor in Node

80 lines (79 loc) 4.71 kB
"use strict"; var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); } var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); var g = generator.apply(thisArg, _arguments || []), i, q = []; return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } function fulfill(value) { resume("next", value); } function reject(value) { resume("throw", value); } function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } }; Object.defineProperty(exports, "__esModule", { value: true }); exports.extractJpgSize = void 0; const EXIF_MARKER = 0x45786966; const APP1_DATA_SIZE_BYTES = 2; const EXIF_HEADER_BYTES = 6; const TIFF_BYTE_ALIGN_BYTES = 2; const BIG_ENDIAN_BYTE_ALIGN = 0x4d4d; const LITTLE_ENDIAN_BYTE_ALIGN = 0x4949; // Each entry is exactly 12 bytes const IDF_ENTRY_BYTES = 12; const NUM_DIRECTORY_ENTRIES_BYTES = 2; exports.extractJpgSize = function (stream) { return __asyncGenerator(this, arguments, function* () { if ((yield __await(stream.readUInt16BE(0))) !== 0xffd8) return yield __await(void 0); let currentOffset = 4, orientation = null; while (true) { const blockSize = yield __await(stream.readUInt16BE(currentOffset)); if ((yield __await(stream.readUInt32BE(currentOffset + 2))) === EXIF_MARKER) { const byteAlignOffset = currentOffset + APP1_DATA_SIZE_BYTES + EXIF_HEADER_BYTES; const byteAlign = yield __await(stream.readUint16BE(byteAlignOffset)); if (byteAlign === BIG_ENDIAN_BYTE_ALIGN || byteAlign === LITTLE_ENDIAN_BYTE_ALIGN) { stream.setEndianness(byteAlign === BIG_ENDIAN_BYTE_ALIGN ? 'BE' : 'LE'); // TODO: assert that this contains 0x002A // let STATIC_MOTOROLA_TIFF_HEADER_BYTES = 2 // let TIFF_IMAGE_FILE_DIRECTORY_BYTES = 4 // TODO: derive from TIFF_IMAGE_FILE_DIRECTORY_BYTES const idfOffset = 8; // IDF osset works from right after the header bytes // (so the offset includes the tiff byte align) const offset = byteAlignOffset + idfOffset; const idfDirectoryEntries = yield __await(stream.readUInt16(offset)); let currentOffset = offset + NUM_DIRECTORY_ENTRIES_BYTES; for (let directoryEntryNumber = 0; directoryEntryNumber < idfDirectoryEntries; directoryEntryNumber++, currentOffset += IDF_ENTRY_BYTES) { const tagNumber = yield __await(stream.readUInt16(currentOffset)); // 0x0112 (decimal: 274) is the `orientation` tag ID if (tagNumber === 274) { const dataFormat = yield __await(stream.readUInt16(currentOffset + 2)); if (dataFormat !== 3) break; // unsinged int has 2 bytes per component // if there would more than 4 bytes in total it's a pointer const numberOfComponents = yield __await(stream.readUInt32(currentOffset + 4)); if (numberOfComponents !== 1) break; orientation = yield __await(stream.readUInt16(currentOffset + 8)); break; } } stream.setEndianness(); } } currentOffset += blockSize; const type = yield __await(stream.readUInt8(currentOffset + 1)); if ([0xc0, 0xc1, 0xc2].indexOf(type) === -1) { currentOffset += 2; continue; } return yield __await(yield yield __await({ height: yield __await(stream.readUInt16BE(currentOffset + 5)), width: yield __await(stream.readUInt16BE(currentOffset + 7)), orientation, })); } }); };