utility.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. // Copyright 2013 Lovell Fuller and others.
  2. // SPDX-License-Identifier: Apache-2.0
  3. 'use strict';
  4. const fs = require('fs');
  5. const path = require('path');
  6. const events = require('events');
  7. const detectLibc = require('detect-libc');
  8. const is = require('./is');
  9. const platformAndArch = require('./platform')();
  10. const sharp = require('./sharp');
  11. /**
  12. * An Object containing nested boolean values representing the available input and output formats/methods.
  13. * @member
  14. * @example
  15. * console.log(sharp.format);
  16. * @returns {Object}
  17. */
  18. const format = sharp.format();
  19. format.heif.output.alias = ['avif', 'heic'];
  20. format.jpeg.output.alias = ['jpe', 'jpg'];
  21. format.tiff.output.alias = ['tif'];
  22. format.jp2k.output.alias = ['j2c', 'j2k', 'jp2', 'jpx'];
  23. /**
  24. * An Object containing the available interpolators and their proper values
  25. * @readonly
  26. * @enum {string}
  27. */
  28. const interpolators = {
  29. /** [Nearest neighbour interpolation](http://en.wikipedia.org/wiki/Nearest-neighbor_interpolation). Suitable for image enlargement only. */
  30. nearest: 'nearest',
  31. /** [Bilinear interpolation](http://en.wikipedia.org/wiki/Bilinear_interpolation). Faster than bicubic but with less smooth results. */
  32. bilinear: 'bilinear',
  33. /** [Bicubic interpolation](http://en.wikipedia.org/wiki/Bicubic_interpolation) (the default). */
  34. bicubic: 'bicubic',
  35. /** [LBB interpolation](https://github.com/libvips/libvips/blob/master/libvips/resample/lbb.cpp#L100). Prevents some "[acutance](http://en.wikipedia.org/wiki/Acutance)" but typically reduces performance by a factor of 2. */
  36. locallyBoundedBicubic: 'lbb',
  37. /** [Nohalo interpolation](http://eprints.soton.ac.uk/268086/). Prevents acutance but typically reduces performance by a factor of 3. */
  38. nohalo: 'nohalo',
  39. /** [VSQBS interpolation](https://github.com/libvips/libvips/blob/master/libvips/resample/vsqbs.cpp#L48). Prevents "staircasing" when enlarging. */
  40. vertexSplitQuadraticBasisSpline: 'vsqbs'
  41. };
  42. /**
  43. * An Object containing the version numbers of sharp, libvips and its dependencies.
  44. * @member
  45. * @example
  46. * console.log(sharp.versions);
  47. */
  48. let versions = {
  49. vips: sharp.libvipsVersion()
  50. };
  51. try {
  52. versions = require(`../vendor/${versions.vips}/${platformAndArch}/versions.json`);
  53. } catch (_err) { /* ignore */ }
  54. versions.sharp = require('../package.json').version;
  55. /**
  56. * An Object containing the platform and architecture
  57. * of the current and installed vendored binaries.
  58. * @member
  59. * @example
  60. * console.log(sharp.vendor);
  61. */
  62. const vendor = {
  63. current: platformAndArch,
  64. installed: []
  65. };
  66. try {
  67. vendor.installed = fs.readdirSync(path.join(__dirname, `../vendor/${versions.vips}`));
  68. } catch (_err) { /* ignore */ }
  69. /**
  70. * Gets or, when options are provided, sets the limits of _libvips'_ operation cache.
  71. * Existing entries in the cache will be trimmed after any change in limits.
  72. * This method always returns cache statistics,
  73. * useful for determining how much working memory is required for a particular task.
  74. *
  75. * @example
  76. * const stats = sharp.cache();
  77. * @example
  78. * sharp.cache( { items: 200 } );
  79. * sharp.cache( { files: 0 } );
  80. * sharp.cache(false);
  81. *
  82. * @param {Object|boolean} [options=true] - Object with the following attributes, or boolean where true uses default cache settings and false removes all caching
  83. * @param {number} [options.memory=50] - is the maximum memory in MB to use for this cache
  84. * @param {number} [options.files=20] - is the maximum number of files to hold open
  85. * @param {number} [options.items=100] - is the maximum number of operations to cache
  86. * @returns {Object}
  87. */
  88. function cache (options) {
  89. if (is.bool(options)) {
  90. if (options) {
  91. // Default cache settings of 50MB, 20 files, 100 items
  92. return sharp.cache(50, 20, 100);
  93. } else {
  94. return sharp.cache(0, 0, 0);
  95. }
  96. } else if (is.object(options)) {
  97. return sharp.cache(options.memory, options.files, options.items);
  98. } else {
  99. return sharp.cache();
  100. }
  101. }
  102. cache(true);
  103. /**
  104. * Gets or, when a concurrency is provided, sets
  105. * the maximum number of threads _libvips_ should use to process _each image_.
  106. * These are from a thread pool managed by glib,
  107. * which helps avoid the overhead of creating new threads.
  108. *
  109. * This method always returns the current concurrency.
  110. *
  111. * The default value is the number of CPU cores,
  112. * except when using glibc-based Linux without jemalloc,
  113. * where the default is `1` to help reduce memory fragmentation.
  114. *
  115. * A value of `0` will reset this to the number of CPU cores.
  116. *
  117. * Some image format libraries spawn additional threads,
  118. * e.g. libaom manages its own 4 threads when encoding AVIF images,
  119. * and these are independent of the value set here.
  120. *
  121. * The maximum number of images that sharp can process in parallel
  122. * is controlled by libuv's `UV_THREADPOOL_SIZE` environment variable,
  123. * which defaults to 4.
  124. *
  125. * https://nodejs.org/api/cli.html#uv_threadpool_sizesize
  126. *
  127. * For example, by default, a machine with 8 CPU cores will process
  128. * 4 images in parallel and use up to 8 threads per image,
  129. * so there will be up to 32 concurrent threads.
  130. *
  131. * @example
  132. * const threads = sharp.concurrency(); // 4
  133. * sharp.concurrency(2); // 2
  134. * sharp.concurrency(0); // 4
  135. *
  136. * @param {number} [concurrency]
  137. * @returns {number} concurrency
  138. */
  139. function concurrency (concurrency) {
  140. return sharp.concurrency(is.integer(concurrency) ? concurrency : null);
  141. }
  142. /* istanbul ignore next */
  143. if (detectLibc.familySync() === detectLibc.GLIBC && !sharp._isUsingJemalloc()) {
  144. // Reduce default concurrency to 1 when using glibc memory allocator
  145. sharp.concurrency(1);
  146. }
  147. /**
  148. * An EventEmitter that emits a `change` event when a task is either:
  149. * - queued, waiting for _libuv_ to provide a worker thread
  150. * - complete
  151. * @member
  152. * @example
  153. * sharp.queue.on('change', function(queueLength) {
  154. * console.log('Queue contains ' + queueLength + ' task(s)');
  155. * });
  156. */
  157. const queue = new events.EventEmitter();
  158. /**
  159. * Provides access to internal task counters.
  160. * - queue is the number of tasks this module has queued waiting for _libuv_ to provide a worker thread from its pool.
  161. * - process is the number of resize tasks currently being processed.
  162. *
  163. * @example
  164. * const counters = sharp.counters(); // { queue: 2, process: 4 }
  165. *
  166. * @returns {Object}
  167. */
  168. function counters () {
  169. return sharp.counters();
  170. }
  171. /**
  172. * Get and set use of SIMD vector unit instructions.
  173. * Requires libvips to have been compiled with liborc support.
  174. *
  175. * Improves the performance of `resize`, `blur` and `sharpen` operations
  176. * by taking advantage of the SIMD vector unit of the CPU, e.g. Intel SSE and ARM NEON.
  177. *
  178. * @example
  179. * const simd = sharp.simd();
  180. * // simd is `true` if the runtime use of liborc is currently enabled
  181. * @example
  182. * const simd = sharp.simd(false);
  183. * // prevent libvips from using liborc at runtime
  184. *
  185. * @param {boolean} [simd=true]
  186. * @returns {boolean}
  187. */
  188. function simd (simd) {
  189. return sharp.simd(is.bool(simd) ? simd : null);
  190. }
  191. simd(true);
  192. /**
  193. * Block libvips operations at runtime.
  194. *
  195. * This is in addition to the `VIPS_BLOCK_UNTRUSTED` environment variable,
  196. * which when set will block all "untrusted" operations.
  197. *
  198. * @since 0.32.4
  199. *
  200. * @example <caption>Block all TIFF input.</caption>
  201. * sharp.block({
  202. * operation: ['VipsForeignLoadTiff']
  203. * });
  204. *
  205. * @param {Object} options
  206. * @param {Array<string>} options.operation - List of libvips low-level operation names to block.
  207. */
  208. function block (options) {
  209. if (is.object(options)) {
  210. if (Array.isArray(options.operation) && options.operation.every(is.string)) {
  211. sharp.block(options.operation, true);
  212. } else {
  213. throw is.invalidParameterError('operation', 'Array<string>', options.operation);
  214. }
  215. } else {
  216. throw is.invalidParameterError('options', 'object', options);
  217. }
  218. }
  219. /**
  220. * Unblock libvips operations at runtime.
  221. *
  222. * This is useful for defining a list of allowed operations.
  223. *
  224. * @since 0.32.4
  225. *
  226. * @example <caption>Block all input except WebP from the filesystem.</caption>
  227. * sharp.block({
  228. * operation: ['VipsForeignLoad']
  229. * });
  230. * sharp.unblock({
  231. * operation: ['VipsForeignLoadWebpFile']
  232. * });
  233. *
  234. * @example <caption>Block all input except JPEG and PNG from a Buffer or Stream.</caption>
  235. * sharp.block({
  236. * operation: ['VipsForeignLoad']
  237. * });
  238. * sharp.unblock({
  239. * operation: ['VipsForeignLoadJpegBuffer', 'VipsForeignLoadPngBuffer']
  240. * });
  241. *
  242. * @param {Object} options
  243. * @param {Array<string>} options.operation - List of libvips low-level operation names to unblock.
  244. */
  245. function unblock (options) {
  246. if (is.object(options)) {
  247. if (Array.isArray(options.operation) && options.operation.every(is.string)) {
  248. sharp.block(options.operation, false);
  249. } else {
  250. throw is.invalidParameterError('operation', 'Array<string>', options.operation);
  251. }
  252. } else {
  253. throw is.invalidParameterError('options', 'object', options);
  254. }
  255. }
  256. /**
  257. * Decorate the Sharp class with utility-related functions.
  258. * @private
  259. */
  260. module.exports = function (Sharp) {
  261. Sharp.cache = cache;
  262. Sharp.concurrency = concurrency;
  263. Sharp.counters = counters;
  264. Sharp.simd = simd;
  265. Sharp.format = format;
  266. Sharp.interpolators = interpolators;
  267. Sharp.versions = versions;
  268. Sharp.vendor = vendor;
  269. Sharp.queue = queue;
  270. Sharp.block = block;
  271. Sharp.unblock = unblock;
  272. };