utility.js 9.2 KB

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