mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 18:40:16 +02:00
Allow ensureAlpha to set alpha transparency level #2634
This commit is contained in:
parent
fe0767df13
commit
8c33d0aa56
@ -18,18 +18,33 @@ Returns **Sharp**
|
|||||||
|
|
||||||
## ensureAlpha
|
## ensureAlpha
|
||||||
|
|
||||||
Ensure alpha channel, if missing. The added alpha channel will be fully opaque. This is a no-op if the image already has an alpha channel.
|
Ensure the output image has an alpha transparency channel.
|
||||||
|
If missing, the added alpha channel will have the specified
|
||||||
|
transparency level, defaulting to fully-opaque (1).
|
||||||
|
This is a no-op if the image already has an alpha channel.
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
- `alpha` **[number][1]** alpha transparency level (0=fully-transparent, 1=fully-opaque) (optional, default `1`)
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
sharp('rgb.jpg')
|
// rgba.png will be a 4 channel image with a fully-opaque alpha channel
|
||||||
|
await sharp('rgb.jpg')
|
||||||
.ensureAlpha()
|
.ensureAlpha()
|
||||||
.toFile('rgba.png', function(err, info) {
|
.toFile('rgba.png')
|
||||||
// rgba.png is a 4 channel image with a fully opaque alpha channel
|
|
||||||
});
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// rgba is a 4 channel image with a fully-transparent alpha channel
|
||||||
|
const rgba = await sharp(rgb)
|
||||||
|
.ensureAlpha(0)
|
||||||
|
.toBuffer();
|
||||||
|
```
|
||||||
|
|
||||||
|
- Throws **[Error][2]** Invalid alpha transparency level
|
||||||
|
|
||||||
Returns **Sharp**
|
Returns **Sharp**
|
||||||
|
|
||||||
**Meta**
|
**Meta**
|
||||||
@ -42,7 +57,7 @@ Extract a single channel from a multi-channel image.
|
|||||||
|
|
||||||
### Parameters
|
### Parameters
|
||||||
|
|
||||||
- `channel` **([number][1] \| [string][2])** zero-indexed channel/band number to extract, or `red`, `green`, `blue` or `alpha`.
|
- `channel` **([number][1] \| [string][3])** zero-indexed channel/band number to extract, or `red`, `green`, `blue` or `alpha`.
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
@ -56,7 +71,7 @@ sharp(input)
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
- Throws **[Error][3]** Invalid channel
|
- Throws **[Error][2]** Invalid channel
|
||||||
|
|
||||||
Returns **Sharp**
|
Returns **Sharp**
|
||||||
|
|
||||||
@ -75,11 +90,11 @@ For raw pixel input, the `options` object should contain a `raw` attribute, whic
|
|||||||
|
|
||||||
### Parameters
|
### Parameters
|
||||||
|
|
||||||
- `images` **([Array][4]<([string][2] \| [Buffer][5])> | [string][2] \| [Buffer][5])** one or more images (file paths, Buffers).
|
- `images` **([Array][4]<([string][3] \| [Buffer][5])> | [string][3] \| [Buffer][5])** one or more images (file paths, Buffers).
|
||||||
- `options` **[Object][6]** image options, see `sharp()` constructor.
|
- `options` **[Object][6]** image options, see `sharp()` constructor.
|
||||||
|
|
||||||
|
|
||||||
- Throws **[Error][3]** Invalid parameters
|
- Throws **[Error][2]** Invalid parameters
|
||||||
|
|
||||||
Returns **Sharp**
|
Returns **Sharp**
|
||||||
|
|
||||||
@ -89,7 +104,7 @@ Perform a bitwise boolean operation on all input image channels (bands) to produ
|
|||||||
|
|
||||||
### Parameters
|
### Parameters
|
||||||
|
|
||||||
- `boolOp` **[string][2]** one of `and`, `or` or `eor` to perform that bitwise operation, like the C logic operators `&`, `|` and `^` respectively.
|
- `boolOp` **[string][3]** one of `and`, `or` or `eor` to perform that bitwise operation, like the C logic operators `&`, `|` and `^` respectively.
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
@ -103,15 +118,15 @@ sharp('3-channel-rgb-input.png')
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
- Throws **[Error][3]** Invalid parameters
|
- Throws **[Error][2]** Invalid parameters
|
||||||
|
|
||||||
Returns **Sharp**
|
Returns **Sharp**
|
||||||
|
|
||||||
[1]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
|
[1]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
|
||||||
|
|
||||||
[2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
|
[2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error
|
||||||
|
|
||||||
[3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error
|
[3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
|
||||||
|
|
||||||
[4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array
|
[4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array
|
||||||
|
|
||||||
|
@ -8,6 +8,9 @@ Requires libvips v8.10.6
|
|||||||
|
|
||||||
* Ensure all installation errors are logged with a more obvious prefix.
|
* Ensure all installation errors are logged with a more obvious prefix.
|
||||||
|
|
||||||
|
* Allow `ensureAlpha` to set the alpha transparency level.
|
||||||
|
[#2634](https://github.com/lovell/sharp/issues/2634)
|
||||||
|
|
||||||
### v0.28.0 - 29th March 2021
|
### v0.28.0 - 29th March 2021
|
||||||
|
|
||||||
* Prebuilt binaries now include mozjpeg and libimagequant (BSD 2-Clause).
|
* Prebuilt binaries now include mozjpeg and libimagequant (BSD 2-Clause).
|
||||||
|
File diff suppressed because one or more lines are too long
@ -30,21 +30,39 @@ function removeAlpha () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure alpha channel, if missing. The added alpha channel will be fully opaque. This is a no-op if the image already has an alpha channel.
|
* Ensure the output image has an alpha transparency channel.
|
||||||
|
* If missing, the added alpha channel will have the specified
|
||||||
|
* transparency level, defaulting to fully-opaque (1).
|
||||||
|
* This is a no-op if the image already has an alpha channel.
|
||||||
*
|
*
|
||||||
* @since 0.21.2
|
* @since 0.21.2
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* sharp('rgb.jpg')
|
* // rgba.png will be a 4 channel image with a fully-opaque alpha channel
|
||||||
|
* await sharp('rgb.jpg')
|
||||||
* .ensureAlpha()
|
* .ensureAlpha()
|
||||||
* .toFile('rgba.png', function(err, info) {
|
* .toFile('rgba.png')
|
||||||
* // rgba.png is a 4 channel image with a fully opaque alpha channel
|
|
||||||
* });
|
|
||||||
*
|
*
|
||||||
|
* @example
|
||||||
|
* // rgba is a 4 channel image with a fully-transparent alpha channel
|
||||||
|
* const rgba = await sharp(rgb)
|
||||||
|
* .ensureAlpha(0)
|
||||||
|
* .toBuffer();
|
||||||
|
*
|
||||||
|
* @param {number} [alpha=1] - alpha transparency level (0=fully-transparent, 1=fully-opaque)
|
||||||
* @returns {Sharp}
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid alpha transparency level
|
||||||
*/
|
*/
|
||||||
function ensureAlpha () {
|
function ensureAlpha (alpha) {
|
||||||
this.options.ensureAlpha = true;
|
if (is.defined(alpha)) {
|
||||||
|
if (is.number(alpha) && is.inRange(alpha, 0, 1)) {
|
||||||
|
this.options.ensureAlpha = alpha;
|
||||||
|
} else {
|
||||||
|
throw is.invalidParameterError('alpha', 'number between 0 and 1', alpha);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.options.ensureAlpha = 1;
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,7 +221,7 @@ const Sharp = function (input, options) {
|
|||||||
joinChannelIn: [],
|
joinChannelIn: [],
|
||||||
extractChannel: -1,
|
extractChannel: -1,
|
||||||
removeAlpha: false,
|
removeAlpha: false,
|
||||||
ensureAlpha: false,
|
ensureAlpha: -1,
|
||||||
colourspace: 'srgb',
|
colourspace: 'srgb',
|
||||||
composite: [],
|
composite: [],
|
||||||
// output
|
// output
|
||||||
|
@ -799,10 +799,10 @@ namespace sharp {
|
|||||||
/*
|
/*
|
||||||
Ensures alpha channel, if missing.
|
Ensures alpha channel, if missing.
|
||||||
*/
|
*/
|
||||||
VImage EnsureAlpha(VImage image) {
|
VImage EnsureAlpha(VImage image, double const value) {
|
||||||
if (!HasAlpha(image)) {
|
if (!HasAlpha(image)) {
|
||||||
std::vector<double> alpha;
|
std::vector<double> alpha;
|
||||||
alpha.push_back(sharp::MaximumImageAlpha(image.interpretation()));
|
alpha.push_back(value * sharp::MaximumImageAlpha(image.interpretation()));
|
||||||
image = image.bandjoin_const(alpha);
|
image = image.bandjoin_const(alpha);
|
||||||
}
|
}
|
||||||
return image;
|
return image;
|
||||||
|
@ -296,7 +296,7 @@ namespace sharp {
|
|||||||
/*
|
/*
|
||||||
Ensures alpha channel, if missing.
|
Ensures alpha channel, if missing.
|
||||||
*/
|
*/
|
||||||
VImage EnsureAlpha(VImage image);
|
VImage EnsureAlpha(VImage image, double const value);
|
||||||
|
|
||||||
} // namespace sharp
|
} // namespace sharp
|
||||||
|
|
||||||
|
@ -346,7 +346,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
bool const shouldModulate = baton->brightness != 1.0 || baton->saturation != 1.0 || baton->hue != 0.0;
|
bool const shouldModulate = baton->brightness != 1.0 || baton->saturation != 1.0 || baton->hue != 0.0;
|
||||||
|
|
||||||
if (shouldComposite && !sharp::HasAlpha(image)) {
|
if (shouldComposite && !sharp::HasAlpha(image)) {
|
||||||
image = sharp::EnsureAlpha(image);
|
image = sharp::EnsureAlpha(image, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool const shouldPremultiplyAlpha = sharp::HasAlpha(image) &&
|
bool const shouldPremultiplyAlpha = sharp::HasAlpha(image) &&
|
||||||
@ -594,7 +594,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
// Ensure image to composite is sRGB with premultiplied alpha
|
// Ensure image to composite is sRGB with premultiplied alpha
|
||||||
compositeImage = compositeImage.colourspace(VIPS_INTERPRETATION_sRGB);
|
compositeImage = compositeImage.colourspace(VIPS_INTERPRETATION_sRGB);
|
||||||
if (!sharp::HasAlpha(compositeImage)) {
|
if (!sharp::HasAlpha(compositeImage)) {
|
||||||
compositeImage = sharp::EnsureAlpha(compositeImage);
|
compositeImage = sharp::EnsureAlpha(compositeImage, 1);
|
||||||
}
|
}
|
||||||
if (!composite->premultiplied) compositeImage = compositeImage.premultiply();
|
if (!composite->premultiplied) compositeImage = compositeImage.premultiply();
|
||||||
// Calculate position
|
// Calculate position
|
||||||
@ -691,8 +691,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ensure alpha channel, if missing
|
// Ensure alpha channel, if missing
|
||||||
if (baton->ensureAlpha) {
|
if (baton->ensureAlpha != -1) {
|
||||||
image = sharp::EnsureAlpha(image);
|
image = sharp::EnsureAlpha(image, baton->ensureAlpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert image to sRGB, if not already
|
// Convert image to sRGB, if not already
|
||||||
@ -1341,7 +1341,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|||||||
baton->affineInterpolator = vips::VInterpolate::new_from_name(sharp::AttrAsStr(options, "affineInterpolator").data());
|
baton->affineInterpolator = vips::VInterpolate::new_from_name(sharp::AttrAsStr(options, "affineInterpolator").data());
|
||||||
|
|
||||||
baton->removeAlpha = sharp::AttrAsBool(options, "removeAlpha");
|
baton->removeAlpha = sharp::AttrAsBool(options, "removeAlpha");
|
||||||
baton->ensureAlpha = sharp::AttrAsBool(options, "ensureAlpha");
|
baton->ensureAlpha = sharp::AttrAsDouble(options, "ensureAlpha");
|
||||||
if (options.Has("boolean")) {
|
if (options.Has("boolean")) {
|
||||||
baton->boolean = sharp::CreateInputDescriptor(options.Get("boolean").As<Napi::Object>());
|
baton->boolean = sharp::CreateInputDescriptor(options.Get("boolean").As<Napi::Object>());
|
||||||
baton->booleanOp = sharp::GetBooleanOperation(sharp::AttrAsStr(options, "booleanOp"));
|
baton->booleanOp = sharp::GetBooleanOperation(sharp::AttrAsStr(options, "booleanOp"));
|
||||||
|
@ -178,7 +178,7 @@ struct PipelineBaton {
|
|||||||
VipsOperationBoolean bandBoolOp;
|
VipsOperationBoolean bandBoolOp;
|
||||||
int extractChannel;
|
int extractChannel;
|
||||||
bool removeAlpha;
|
bool removeAlpha;
|
||||||
bool ensureAlpha;
|
double ensureAlpha;
|
||||||
VipsInterpretation colourspace;
|
VipsInterpretation colourspace;
|
||||||
int pageHeight;
|
int pageHeight;
|
||||||
std::vector<int> delay;
|
std::vector<int> delay;
|
||||||
@ -297,7 +297,7 @@ struct PipelineBaton {
|
|||||||
bandBoolOp(VIPS_OPERATION_BOOLEAN_LAST),
|
bandBoolOp(VIPS_OPERATION_BOOLEAN_LAST),
|
||||||
extractChannel(-1),
|
extractChannel(-1),
|
||||||
removeAlpha(false),
|
removeAlpha(false),
|
||||||
ensureAlpha(false),
|
ensureAlpha(-1.0),
|
||||||
colourspace(VIPS_INTERPRETATION_LAST),
|
colourspace(VIPS_INTERPRETATION_LAST),
|
||||||
pageHeight(0),
|
pageHeight(0),
|
||||||
delay{-1},
|
delay{-1},
|
||||||
|
@ -155,4 +155,27 @@ describe('Alpha transparency', function () {
|
|||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Valid ensureAlpha value used for alpha channel', async () => {
|
||||||
|
const background = { r: 255, g: 0, b: 0 };
|
||||||
|
const [r, g, b, alpha] = await sharp({
|
||||||
|
create: {
|
||||||
|
width: 8,
|
||||||
|
height: 8,
|
||||||
|
channels: 3,
|
||||||
|
background
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.ensureAlpha(0.5)
|
||||||
|
.raw()
|
||||||
|
.toBuffer();
|
||||||
|
|
||||||
|
assert.deepStrictEqual({ r, g, b, alpha }, { ...background, alpha: 127 });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Invalid ensureAlpha value throws', async () => {
|
||||||
|
assert.throws(() => {
|
||||||
|
sharp().ensureAlpha('fail');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user