channel.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. /*!
  2. Copyright 2013 Lovell Fuller and others.
  3. SPDX-License-Identifier: Apache-2.0
  4. */
  5. const is = require('./is');
  6. /**
  7. * Boolean operations for bandbool.
  8. * @private
  9. */
  10. const bool = {
  11. and: 'and',
  12. or: 'or',
  13. eor: 'eor'
  14. };
  15. /**
  16. * Remove alpha channels, if any. This is a no-op if the image does not have an alpha channel.
  17. *
  18. * See also {@link /api-operation/#flatten flatten}.
  19. *
  20. * @example
  21. * sharp('rgba.png')
  22. * .removeAlpha()
  23. * .toFile('rgb.png', function(err, info) {
  24. * // rgb.png is a 3 channel image without an alpha channel
  25. * });
  26. *
  27. * @returns {Sharp}
  28. */
  29. function removeAlpha () {
  30. this.options.removeAlpha = true;
  31. return this;
  32. }
  33. /**
  34. * Ensure the output image has an alpha transparency channel.
  35. * If missing, the added alpha channel will have the specified
  36. * transparency level, defaulting to fully-opaque (1).
  37. * This is a no-op if the image already has an alpha channel.
  38. *
  39. * @since 0.21.2
  40. *
  41. * @example
  42. * // rgba.png will be a 4 channel image with a fully-opaque alpha channel
  43. * await sharp('rgb.jpg')
  44. * .ensureAlpha()
  45. * .toFile('rgba.png')
  46. *
  47. * @example
  48. * // rgba is a 4 channel image with a fully-transparent alpha channel
  49. * const rgba = await sharp(rgb)
  50. * .ensureAlpha(0)
  51. * .toBuffer();
  52. *
  53. * @param {number} [alpha=1] - alpha transparency level (0=fully-transparent, 1=fully-opaque)
  54. * @returns {Sharp}
  55. * @throws {Error} Invalid alpha transparency level
  56. */
  57. function ensureAlpha (alpha) {
  58. if (is.defined(alpha)) {
  59. if (is.number(alpha) && is.inRange(alpha, 0, 1)) {
  60. this.options.ensureAlpha = alpha;
  61. } else {
  62. throw is.invalidParameterError('alpha', 'number between 0 and 1', alpha);
  63. }
  64. } else {
  65. this.options.ensureAlpha = 1;
  66. }
  67. return this;
  68. }
  69. /**
  70. * Extract a single channel from a multi-channel image.
  71. *
  72. * The output colourspace will be either `b-w` (8-bit) or `grey16` (16-bit).
  73. *
  74. * @example
  75. * // green.jpg is a greyscale image containing the green channel of the input
  76. * await sharp(input)
  77. * .extractChannel('green')
  78. * .toFile('green.jpg');
  79. *
  80. * @example
  81. * // red1 is the red value of the first pixel, red2 the second pixel etc.
  82. * const [red1, red2, ...] = await sharp(input)
  83. * .extractChannel(0)
  84. * .raw()
  85. * .toBuffer();
  86. *
  87. * @param {number|string} channel - zero-indexed channel/band number to extract, or `red`, `green`, `blue` or `alpha`.
  88. * @returns {Sharp}
  89. * @throws {Error} Invalid channel
  90. */
  91. function extractChannel (channel) {
  92. const channelMap = { red: 0, green: 1, blue: 2, alpha: 3 };
  93. if (Object.keys(channelMap).includes(channel)) {
  94. channel = channelMap[channel];
  95. }
  96. if (is.integer(channel) && is.inRange(channel, 0, 4)) {
  97. this.options.extractChannel = channel;
  98. } else {
  99. throw is.invalidParameterError('channel', 'integer or one of: red, green, blue, alpha', channel);
  100. }
  101. return this;
  102. }
  103. /**
  104. * Join one or more channels to the image.
  105. * The meaning of the added channels depends on the output colourspace, set with `toColourspace()`.
  106. * By default the output image will be web-friendly sRGB, with additional channels interpreted as alpha channels.
  107. * Channel ordering follows vips convention:
  108. * - sRGB: 0: Red, 1: Green, 2: Blue, 3: Alpha.
  109. * - CMYK: 0: Magenta, 1: Cyan, 2: Yellow, 3: Black, 4: Alpha.
  110. *
  111. * Buffers may be any of the image formats supported by sharp.
  112. * For raw pixel input, the `options` object should contain a `raw` attribute, which follows the format of the attribute of the same name in the `sharp()` constructor.
  113. *
  114. * @param {Array<string|Buffer>|string|Buffer} images - one or more images (file paths, Buffers).
  115. * @param {Object} options - image options, see `sharp()` constructor.
  116. * @returns {Sharp}
  117. * @throws {Error} Invalid parameters
  118. */
  119. function joinChannel (images, options) {
  120. if (Array.isArray(images)) {
  121. images.forEach(function (image) {
  122. this.options.joinChannelIn.push(this._createInputDescriptor(image, options));
  123. }, this);
  124. } else {
  125. this.options.joinChannelIn.push(this._createInputDescriptor(images, options));
  126. }
  127. return this;
  128. }
  129. /**
  130. * Perform a bitwise boolean operation on all input image channels (bands) to produce a single channel output image.
  131. *
  132. * @example
  133. * sharp('3-channel-rgb-input.png')
  134. * .bandbool(sharp.bool.and)
  135. * .toFile('1-channel-output.png', function (err, info) {
  136. * // The output will be a single channel image where each pixel `P = R & G & B`.
  137. * // If `I(1,1) = [247, 170, 14] = [0b11110111, 0b10101010, 0b00001111]`
  138. * // then `O(1,1) = 0b11110111 & 0b10101010 & 0b00001111 = 0b00000010 = 2`.
  139. * });
  140. *
  141. * @param {string} boolOp - one of `and`, `or` or `eor` to perform that bitwise operation, like the C logic operators `&`, `|` and `^` respectively.
  142. * @returns {Sharp}
  143. * @throws {Error} Invalid parameters
  144. */
  145. function bandbool (boolOp) {
  146. if (is.string(boolOp) && is.inArray(boolOp, ['and', 'or', 'eor'])) {
  147. this.options.bandBoolOp = boolOp;
  148. } else {
  149. throw is.invalidParameterError('boolOp', 'one of: and, or, eor', boolOp);
  150. }
  151. return this;
  152. }
  153. /**
  154. * Decorate the Sharp prototype with channel-related functions.
  155. * @module Sharp
  156. * @private
  157. */
  158. module.exports = (Sharp) => {
  159. Object.assign(Sharp.prototype, {
  160. // Public instance functions
  161. removeAlpha,
  162. ensureAlpha,
  163. extractChannel,
  164. joinChannel,
  165. bandbool
  166. });
  167. // Class attributes
  168. Sharp.bool = bool;
  169. };