UNPKG

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