UNPKG

4.42 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.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 });
23/**
24 * Return size information based on a buffer
25 *
26 * @param {Buffer} buffer
27 * @param {String} filepath
28 * @returns {Object}
29 */
30function lookup(buffer, filepath) {
31 // detect the file type.. don't rely on the extension
32 const type = detector_1.detector(buffer);
33 // find an appropriate handler for this file type
34 if (type && type in types_1.typeHandlers) {
35 const size = types_1.typeHandlers[type].calculate(buffer, filepath);
36 if (size !== undefined) {
37 size.type = type;
38 return size;
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 a buffer.
46 * @param {String} filepath
47 * @returns {Promise<Buffer>}
48 */
49function asyncFileToBuffer(filepath) {
50 return __awaiter(this, void 0, void 0, function* () {
51 const handle = yield fs.promises.open(filepath, 'r');
52 const { size } = yield handle.stat();
53 if (size <= 0) {
54 yield handle.close();
55 throw new Error('Empty file');
56 }
57 const bufferSize = Math.min(size, MaxBufferSize);
58 const buffer = Buffer.alloc(bufferSize);
59 yield handle.read(buffer, 0, bufferSize, 0);
60 yield handle.close();
61 return buffer;
62 });
63}
64/**
65 * Synchronously reads a file into a buffer, blocking the nodejs process.
66 *
67 * @param {String} filepath
68 * @returns {Buffer}
69 */
70function syncFileToBuffer(filepath) {
71 // read from the file, synchronously
72 const descriptor = fs.openSync(filepath, 'r');
73 const { size } = fs.fstatSync(descriptor);
74 if (size <= 0) {
75 fs.closeSync(descriptor);
76 throw new Error('Empty file');
77 }
78 const bufferSize = Math.min(size, MaxBufferSize);
79 const buffer = Buffer.alloc(bufferSize);
80 fs.readSync(descriptor, buffer, 0, bufferSize, 0);
81 fs.closeSync(descriptor);
82 return buffer;
83}
84// eslint-disable-next-line @typescript-eslint/no-use-before-define
85module.exports = exports = imageSize; // backwards compatibility
86exports.default = imageSize;
87/**
88 * @param {Buffer|string} input - buffer or relative/absolute path of the image file
89 * @param {Function=} [callback] - optional function for async detection
90 */
91function imageSize(input, callback) {
92 // Handle buffer input
93 if (Buffer.isBuffer(input)) {
94 return lookup(input);
95 }
96 // input should be a string at this point
97 if (typeof input !== 'string') {
98 throw new TypeError('invalid invocation');
99 }
100 // resolve the file path
101 const filepath = path.resolve(input);
102 if (typeof callback === 'function') {
103 queue.push(() => asyncFileToBuffer(filepath)
104 .then((buffer) => process.nextTick(callback, null, lookup(buffer, filepath)))
105 .catch(callback));
106 }
107 else {
108 const buffer = syncFileToBuffer(filepath);
109 return lookup(buffer, filepath);
110 }
111}
112exports.imageSize = imageSize;
113exports.setConcurrency = (c) => { queue.concurrency = c; };
114exports.types = Object.keys(types_1.typeHandlers);