UNPKG

4.37 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.types = exports.setConcurrency = exports.disableTypes = exports.disableFS = exports.imageSize = void 0;
4const fs = require("fs");
5const path = require("path");
6const queue_1 = require("queue");
7const index_1 = require("./types/index");
8const detector_1 = require("./detector");
9// Maximum input size, with a default of 512 kilobytes.
10// TO-DO: make this adaptive based on the initial signature of the image
11const MaxInputSize = 512 * 1024;
12// This queue is for async `fs` operations, to avoid reaching file-descriptor limits
13const queue = new queue_1.default({ concurrency: 100, autostart: true });
14const globalOptions = {
15 disabledFS: false,
16 disabledTypes: [],
17};
18/**
19 * Return size information based on an Uint8Array
20 *
21 * @param {Uint8Array} input
22 * @param {String} filepath
23 * @returns {Object}
24 */
25function lookup(input, filepath) {
26 // detect the file type.. don't rely on the extension
27 const type = (0, detector_1.detector)(input);
28 if (typeof type !== 'undefined') {
29 if (globalOptions.disabledTypes.indexOf(type) > -1) {
30 throw new TypeError('disabled file type: ' + type);
31 }
32 // find an appropriate handler for this file type
33 if (type in index_1.typeHandlers) {
34 const size = index_1.typeHandlers[type].calculate(input, filepath);
35 if (size !== undefined) {
36 size.type = size.type ?? type;
37 return size;
38 }
39 }
40 }
41 // throw up, if we don't understand the file
42 throw new TypeError('unsupported file type: ' + type + ' (file: ' + filepath + ')');
43}
44/**
45 * Reads a file into an Uint8Array.
46 * @param {String} filepath
47 * @returns {Promise<Uint8Array>}
48 */
49async function readFileAsync(filepath) {
50 const handle = await fs.promises.open(filepath, 'r');
51 try {
52 const { size } = await handle.stat();
53 if (size <= 0) {
54 throw new Error('Empty file');
55 }
56 const inputSize = Math.min(size, MaxInputSize);
57 const input = new Uint8Array(inputSize);
58 await handle.read(input, 0, inputSize, 0);
59 return input;
60 }
61 finally {
62 await handle.close();
63 }
64}
65/**
66 * Synchronously reads a file into an Uint8Array, blocking the nodejs process.
67 *
68 * @param {String} filepath
69 * @returns {Uint8Array}
70 */
71function readFileSync(filepath) {
72 // read from the file, synchronously
73 const descriptor = fs.openSync(filepath, 'r');
74 try {
75 const { size } = fs.fstatSync(descriptor);
76 if (size <= 0) {
77 throw new Error('Empty file');
78 }
79 const inputSize = Math.min(size, MaxInputSize);
80 const input = new Uint8Array(inputSize);
81 fs.readSync(descriptor, input, 0, inputSize, 0);
82 return input;
83 }
84 finally {
85 fs.closeSync(descriptor);
86 }
87}
88// eslint-disable-next-line @typescript-eslint/no-use-before-define
89module.exports = exports = imageSize; // backwards compatibility
90exports.default = imageSize;
91/**
92 * @param {Uint8Array|string} input - Uint8Array or relative/absolute path of the image file
93 * @param {Function=} [callback] - optional function for async detection
94 */
95function imageSize(input, callback) {
96 // Handle Uint8Array input
97 if (input instanceof Uint8Array) {
98 return lookup(input);
99 }
100 // input should be a string at this point
101 if (typeof input !== 'string' || globalOptions.disabledFS) {
102 throw new TypeError('invalid invocation. input should be a Uint8Array');
103 }
104 // resolve the file path
105 const filepath = path.resolve(input);
106 if (typeof callback === 'function') {
107 queue.push(() => readFileAsync(filepath)
108 .then((input) => process.nextTick(callback, null, lookup(input, filepath)))
109 .catch(callback));
110 }
111 else {
112 const input = readFileSync(filepath);
113 return lookup(input, filepath);
114 }
115}
116exports.imageSize = imageSize;
117const disableFS = (v) => {
118 globalOptions.disabledFS = v;
119};
120exports.disableFS = disableFS;
121const disableTypes = (types) => {
122 globalOptions.disabledTypes = types;
123};
124exports.disableTypes = disableTypes;
125const setConcurrency = (c) => {
126 queue.concurrency = c;
127};
128exports.setConcurrency = setConcurrency;
129exports.types = Object.keys(index_1.typeHandlers);