UNPKG

image-size

Version:

get dimensions of any image file

128 lines (127 loc) • 4.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TIFF = void 0; const utils_1 = require("./utils"); const CONSTANTS = { TAG: { WIDTH: 256, HEIGHT: 257, COMPRESSION: 259, }, TYPE: { SHORT: 3, LONG: 4, LONG8: 16, }, ENTRY_SIZE: { STANDARD: 12, BIG: 20, }, COUNT_SIZE: { STANDARD: 2, BIG: 8, }, }; function readIFD(input, { isBigEndian, isBigTiff }) { const ifdOffset = isBigTiff ? Number((0, utils_1.readUInt64)(input, 8, isBigEndian)) : (0, utils_1.readUInt)(input, 32, 4, isBigEndian); const entryCountSize = isBigTiff ? CONSTANTS.COUNT_SIZE.BIG : CONSTANTS.COUNT_SIZE.STANDARD; return input.slice(ifdOffset + entryCountSize); } function readTagValue(input, type, offset, isBigEndian) { switch (type) { case CONSTANTS.TYPE.SHORT: return (0, utils_1.readUInt)(input, 16, offset, isBigEndian); case CONSTANTS.TYPE.LONG: return (0, utils_1.readUInt)(input, 32, offset, isBigEndian); case CONSTANTS.TYPE.LONG8: { const value = Number((0, utils_1.readUInt64)(input, offset, isBigEndian)); if (value > Number.MAX_SAFE_INTEGER) { throw new TypeError('Value too large'); } return value; } default: return 0; } } function nextTag(input, isBigTiff) { const entrySize = isBigTiff ? CONSTANTS.ENTRY_SIZE.BIG : CONSTANTS.ENTRY_SIZE.STANDARD; if (input.length > entrySize) { return input.slice(entrySize); } } function extractTags(input, { isBigEndian, isBigTiff }) { const tags = {}; let temp = input; while (temp?.length) { const code = (0, utils_1.readUInt)(temp, 16, 0, isBigEndian); const type = (0, utils_1.readUInt)(temp, 16, 2, isBigEndian); const length = isBigTiff ? Number((0, utils_1.readUInt64)(temp, 4, isBigEndian)) : (0, utils_1.readUInt)(temp, 32, 4, isBigEndian); if (code === 0) break; if (length === 1 && (type === CONSTANTS.TYPE.SHORT || type === CONSTANTS.TYPE.LONG || (isBigTiff && type === CONSTANTS.TYPE.LONG8))) { const valueOffset = isBigTiff ? 12 : 8; tags[code] = readTagValue(temp, type, valueOffset, isBigEndian); } temp = nextTag(temp, isBigTiff); } return tags; } function determineFormat(input) { const signature = (0, utils_1.toUTF8String)(input, 0, 2); const version = (0, utils_1.readUInt)(input, 16, 2, signature === 'MM'); return { isBigEndian: signature === 'MM', isBigTiff: version === 43, }; } function validateBigTIFFHeader(input, isBigEndian) { const byteSize = (0, utils_1.readUInt)(input, 16, 4, isBigEndian); const reserved = (0, utils_1.readUInt)(input, 16, 6, isBigEndian); if (byteSize !== 8 || reserved !== 0) { throw new TypeError('Invalid BigTIFF header'); } } const signatures = new Set([ '49492a00', '4d4d002a', '49492b00', '4d4d002b', ]); exports.TIFF = { validate: (input) => { const signature = (0, utils_1.toHexString)(input, 0, 4); return signatures.has(signature); }, calculate(input) { const format = determineFormat(input); if (format.isBigTiff) { validateBigTIFFHeader(input, format.isBigEndian); } const ifdBuffer = readIFD(input, format); const tags = extractTags(ifdBuffer, format); const info = { height: tags[CONSTANTS.TAG.HEIGHT], width: tags[CONSTANTS.TAG.WIDTH], type: format.isBigTiff ? 'bigtiff' : 'tiff', }; if (tags[CONSTANTS.TAG.COMPRESSION]) { info.compression = tags[CONSTANTS.TAG.COMPRESSION]; } if (!info.width || !info.height) { throw new TypeError('Invalid Tiff. Missing tags'); } return info; }, };