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