mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 10:30:15 +02:00
Add pipelineColourspace operator
This commit is contained in:
parent
536412515f
commit
bb48d0d857
@ -40,6 +40,51 @@ Alternative spelling of `greyscale`.
|
|||||||
|
|
||||||
Returns **Sharp**
|
Returns **Sharp**
|
||||||
|
|
||||||
|
## pipelineColourspace
|
||||||
|
|
||||||
|
Set the pipeline colourspace.
|
||||||
|
|
||||||
|
The input image will be converted to the provided colourspace at the start of the pipeline.
|
||||||
|
All operations will use this colourspace before converting to the output colourspace, as defined by [toColourspace][6].
|
||||||
|
|
||||||
|
This feature is experimental and has not yet been fully-tested with all operations.
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
* `colourspace` **[string][1]?** pipeline colourspace e.g. `rgb16`, `scrgb`, `lab`, `grey16` [...][7]
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Run pipeline in 16 bits per channel RGB while converting final result to 8 bits per channel sRGB.
|
||||||
|
await sharp(input)
|
||||||
|
.pipelineColourspace('rgb16')
|
||||||
|
.toColourspace('srgb')
|
||||||
|
.toFile('16bpc-pipeline-to-8bpc-output.png')
|
||||||
|
```
|
||||||
|
|
||||||
|
* Throws **[Error][4]** Invalid parameters
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
**Meta**
|
||||||
|
|
||||||
|
* **since**: 0.29.0
|
||||||
|
|
||||||
|
## pipelineColorspace
|
||||||
|
|
||||||
|
Alternative spelling of `pipelineColourspace`.
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
* `colorspace` **[string][1]?** pipeline colorspace.
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
|
||||||
|
* Throws **[Error][4]** Invalid parameters
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
## toColourspace
|
## toColourspace
|
||||||
|
|
||||||
Set the output colourspace.
|
Set the output colourspace.
|
||||||
@ -47,7 +92,7 @@ By default output image will be web-friendly sRGB, with additional channels inte
|
|||||||
|
|
||||||
### Parameters
|
### Parameters
|
||||||
|
|
||||||
* `colourspace` **[string][1]?** output colourspace e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...][6]
|
* `colourspace` **[string][1]?** output colourspace e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...][8]
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
@ -86,4 +131,8 @@ Returns **Sharp**
|
|||||||
|
|
||||||
[5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
|
[5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
|
||||||
|
|
||||||
[6]: https://github.com/libvips/libvips/blob/3c0bfdf74ce1dc37a6429bed47fa76f16e2cd70a/libvips/iofuncs/enumtypes.c#L777-L794
|
[6]: #tocolourspace
|
||||||
|
|
||||||
|
[7]: https://github.com/libvips/libvips/blob/41cff4e9d0838498487a00623462204eb10ee5b8/libvips/iofuncs/enumtypes.c#L774
|
||||||
|
|
||||||
|
[8]: https://github.com/libvips/libvips/blob/3c0bfdf74ce1dc37a6429bed47fa76f16e2cd70a/libvips/iofuncs/enumtypes.c#L777-L794
|
||||||
|
File diff suppressed because one or more lines are too long
@ -54,6 +54,45 @@ function grayscale (grayscale) {
|
|||||||
return this.greyscale(grayscale);
|
return this.greyscale(grayscale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pipeline colourspace.
|
||||||
|
*
|
||||||
|
* The input image will be converted to the provided colourspace at the start of the pipeline.
|
||||||
|
* All operations will use this colourspace before converting to the output colourspace, as defined by {@link toColourspace}.
|
||||||
|
*
|
||||||
|
* This feature is experimental and has not yet been fully-tested with all operations.
|
||||||
|
*
|
||||||
|
* @since 0.29.0
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Run pipeline in 16 bits per channel RGB while converting final result to 8 bits per channel sRGB.
|
||||||
|
* await sharp(input)
|
||||||
|
* .pipelineColourspace('rgb16')
|
||||||
|
* .toColourspace('srgb')
|
||||||
|
* .toFile('16bpc-pipeline-to-8bpc-output.png')
|
||||||
|
*
|
||||||
|
* @param {string} [colourspace] - pipeline colourspace e.g. `rgb16`, `scrgb`, `lab`, `grey16` [...](https://github.com/libvips/libvips/blob/41cff4e9d0838498487a00623462204eb10ee5b8/libvips/iofuncs/enumtypes.c#L774)
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid parameters
|
||||||
|
*/
|
||||||
|
function pipelineColourspace (colourspace) {
|
||||||
|
if (!is.string(colourspace)) {
|
||||||
|
throw is.invalidParameterError('colourspace', 'string', colourspace);
|
||||||
|
}
|
||||||
|
this.options.colourspaceInput = colourspace;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alternative spelling of `pipelineColourspace`.
|
||||||
|
* @param {string} [colorspace] - pipeline colorspace.
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid parameters
|
||||||
|
*/
|
||||||
|
function pipelineColorspace (colorspace) {
|
||||||
|
return this.pipelineColourspace(colorspace);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the output colourspace.
|
* Set the output colourspace.
|
||||||
* By default output image will be web-friendly sRGB, with additional channels interpreted as alpha channels.
|
* By default output image will be web-friendly sRGB, with additional channels interpreted as alpha channels.
|
||||||
@ -119,6 +158,8 @@ module.exports = function (Sharp) {
|
|||||||
tint,
|
tint,
|
||||||
greyscale,
|
greyscale,
|
||||||
grayscale,
|
grayscale,
|
||||||
|
pipelineColourspace,
|
||||||
|
pipelineColorspace,
|
||||||
toColourspace,
|
toColourspace,
|
||||||
toColorspace,
|
toColorspace,
|
||||||
// Private
|
// Private
|
||||||
|
@ -204,6 +204,7 @@ const Sharp = function (input, options) {
|
|||||||
removeAlpha: false,
|
removeAlpha: false,
|
||||||
ensureAlpha: -1,
|
ensureAlpha: -1,
|
||||||
colourspace: 'srgb',
|
colourspace: 'srgb',
|
||||||
|
colourspaceInput: 'last',
|
||||||
composite: [],
|
composite: [],
|
||||||
// output
|
// output
|
||||||
fileOut: '',
|
fileOut: '',
|
||||||
|
@ -68,6 +68,13 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
sharp::ImageType inputImageType;
|
sharp::ImageType inputImageType;
|
||||||
std::tie(image, inputImageType) = sharp::OpenInput(baton->input);
|
std::tie(image, inputImageType) = sharp::OpenInput(baton->input);
|
||||||
|
|
||||||
|
if (baton->colourspaceInput != VIPS_INTERPRETATION_LAST) {
|
||||||
|
if (image.interpretation() != baton->colourspaceInput) {
|
||||||
|
image = image.colourspace(baton->colourspaceInput,
|
||||||
|
VImage::option()->set("source_space", image.interpretation()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate angle of rotation
|
// Calculate angle of rotation
|
||||||
VipsAngle rotation;
|
VipsAngle rotation;
|
||||||
if (baton->useExifOrientation) {
|
if (baton->useExifOrientation) {
|
||||||
@ -214,7 +221,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
double yresidual = static_cast<double>(yshrink) / yfactor;
|
double yresidual = static_cast<double>(yshrink) / yfactor;
|
||||||
|
|
||||||
// If integral x and y shrink are equal, try to use shrink-on-load for JPEG and WebP,
|
// If integral x and y shrink are equal, try to use shrink-on-load for JPEG and WebP,
|
||||||
// but not when applying gamma correction, pre-resize extract or trim
|
// but not when applying gamma correction, pre-resize extract, trim or input colourspace
|
||||||
int shrink_on_load = 1;
|
int shrink_on_load = 1;
|
||||||
|
|
||||||
int shrink_on_load_factor = 1;
|
int shrink_on_load_factor = 1;
|
||||||
@ -227,6 +234,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
xshrink == yshrink && xshrink >= 2 * shrink_on_load_factor &&
|
xshrink == yshrink && xshrink >= 2 * shrink_on_load_factor &&
|
||||||
(inputImageType == sharp::ImageType::JPEG || inputImageType == sharp::ImageType::WEBP) &&
|
(inputImageType == sharp::ImageType::JPEG || inputImageType == sharp::ImageType::WEBP) &&
|
||||||
baton->gamma == 0 && baton->topOffsetPre == -1 && baton->trimThreshold == 0.0 &&
|
baton->gamma == 0 && baton->topOffsetPre == -1 && baton->trimThreshold == 0.0 &&
|
||||||
|
baton->colourspaceInput == VIPS_INTERPRETATION_LAST &&
|
||||||
image.width() > 3 && image.height() > 3 && baton->input->pages == 1
|
image.width() > 3 && image.height() > 3 && baton->input->pages == 1
|
||||||
) {
|
) {
|
||||||
if (xshrink >= 8 * shrink_on_load_factor) {
|
if (xshrink >= 8 * shrink_on_load_factor) {
|
||||||
@ -1385,6 +1393,10 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|||||||
baton->recombMatrix[i] = sharp::AttrAsDouble(recombMatrix, i);
|
baton->recombMatrix[i] = sharp::AttrAsDouble(recombMatrix, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
baton->colourspaceInput = sharp::GetInterpretation(sharp::AttrAsStr(options, "colourspaceInput"));
|
||||||
|
if (baton->colourspaceInput == VIPS_INTERPRETATION_ERROR) {
|
||||||
|
baton->colourspaceInput = VIPS_INTERPRETATION_LAST;
|
||||||
|
}
|
||||||
baton->colourspace = sharp::GetInterpretation(sharp::AttrAsStr(options, "colourspace"));
|
baton->colourspace = sharp::GetInterpretation(sharp::AttrAsStr(options, "colourspace"));
|
||||||
if (baton->colourspace == VIPS_INTERPRETATION_ERROR) {
|
if (baton->colourspace == VIPS_INTERPRETATION_ERROR) {
|
||||||
baton->colourspace = VIPS_INTERPRETATION_sRGB;
|
baton->colourspace = VIPS_INTERPRETATION_sRGB;
|
||||||
|
@ -185,6 +185,7 @@ struct PipelineBaton {
|
|||||||
int extractChannel;
|
int extractChannel;
|
||||||
bool removeAlpha;
|
bool removeAlpha;
|
||||||
double ensureAlpha;
|
double ensureAlpha;
|
||||||
|
VipsInterpretation colourspaceInput;
|
||||||
VipsInterpretation colourspace;
|
VipsInterpretation colourspace;
|
||||||
int pageHeight;
|
int pageHeight;
|
||||||
std::vector<int> delay;
|
std::vector<int> delay;
|
||||||
@ -308,6 +309,7 @@ struct PipelineBaton {
|
|||||||
extractChannel(-1),
|
extractChannel(-1),
|
||||||
removeAlpha(false),
|
removeAlpha(false),
|
||||||
ensureAlpha(-1.0),
|
ensureAlpha(-1.0),
|
||||||
|
colourspaceInput(VIPS_INTERPRETATION_LAST),
|
||||||
colourspace(VIPS_INTERPRETATION_LAST),
|
colourspace(VIPS_INTERPRETATION_LAST),
|
||||||
pageHeight(0),
|
pageHeight(0),
|
||||||
delay{-1},
|
delay{-1},
|
||||||
|
BIN
test/fixtures/expected/colourspace-gradients-gamma-resize.png
vendored
Normal file
BIN
test/fixtures/expected/colourspace-gradients-gamma-resize.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 56 KiB |
BIN
test/fixtures/gradients-rgb8.png
vendored
Normal file
BIN
test/fixtures/gradients-rgb8.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 777 KiB |
1
test/fixtures/index.js
vendored
1
test/fixtures/index.js
vendored
@ -74,6 +74,7 @@ module.exports = {
|
|||||||
inputJpgLossless: getPath('testimgl.jpg'), // Lossless JPEG from ftp://ftp.fu-berlin.de/unix/X11/graphics/ImageMagick/delegates/ljpeg-6b.tar.gz
|
inputJpgLossless: getPath('testimgl.jpg'), // Lossless JPEG from ftp://ftp.fu-berlin.de/unix/X11/graphics/ImageMagick/delegates/ljpeg-6b.tar.gz
|
||||||
|
|
||||||
inputPng: getPath('50020484-00001.png'), // http://c.searspartsdirect.com/lis_png/PLDM/50020484-00001.png
|
inputPng: getPath('50020484-00001.png'), // http://c.searspartsdirect.com/lis_png/PLDM/50020484-00001.png
|
||||||
|
inputPngGradients: getPath('gradients-rgb8.png'),
|
||||||
inputPngWithTransparency: getPath('blackbug.png'), // public domain
|
inputPngWithTransparency: getPath('blackbug.png'), // public domain
|
||||||
inputPngCompleteTransparency: getPath('full-transparent.png'),
|
inputPngCompleteTransparency: getPath('full-transparent.png'),
|
||||||
inputPngWithGreyAlpha: getPath('grey-8bit-alpha.png'),
|
inputPngWithGreyAlpha: getPath('grey-8bit-alpha.png'),
|
||||||
|
@ -90,7 +90,29 @@ describe('Colour space conversion', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Invalid input', function () {
|
it('From sRGB with RGB16 pipeline, resize with gamma, to sRGB', function (done) {
|
||||||
|
sharp(fixtures.inputPngGradients)
|
||||||
|
.pipelineColourspace('rgb16')
|
||||||
|
.resize(320)
|
||||||
|
.gamma()
|
||||||
|
.toColourspace('srgb')
|
||||||
|
.toBuffer(function (err, data, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(320, info.width);
|
||||||
|
fixtures.assertSimilar(fixtures.expected('colourspace-gradients-gamma-resize.png'), data, {
|
||||||
|
threshold: 0
|
||||||
|
}, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Invalid pipelineColourspace input', function () {
|
||||||
|
assert.throws(function () {
|
||||||
|
sharp(fixtures.inputJpg)
|
||||||
|
.pipelineColorspace(null);
|
||||||
|
}, /Expected string for colourspace but received null of type object/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Invalid toColourspace input', function () {
|
||||||
assert.throws(function () {
|
assert.throws(function () {
|
||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.toColourspace(null);
|
.toColourspace(null);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user