mirror of
https://github.com/lovell/sharp.git
synced 2025-07-12 20:10:13 +02:00
Add premultiplied option to composite operation (#1835)
This commit is contained in:
parent
3fa91bb4ce
commit
4ae8999f62
@ -31,6 +31,7 @@ and [https://www.cairographics.org/operators/][2]
|
|||||||
- `images[].top` **[Number][7]?** the pixel offset from the top edge.
|
- `images[].top` **[Number][7]?** the pixel offset from the top edge.
|
||||||
- `images[].left` **[Number][7]?** the pixel offset from the left edge.
|
- `images[].left` **[Number][7]?** the pixel offset from the left edge.
|
||||||
- `images[].tile` **[Boolean][9]** set to true to repeat the overlay image across the entire image with the given `gravity`. (optional, default `false`)
|
- `images[].tile` **[Boolean][9]** set to true to repeat the overlay image across the entire image with the given `gravity`. (optional, default `false`)
|
||||||
|
- `images[].premultiplied` **[Boolean][9]** set to true to avoid premultipling the image below. Equivalent to the `--premultiplied` vips option. (optional, default `false`)
|
||||||
- `images[].density` **[Number][7]** number representing the DPI for vector overlay image. (optional, default `72`)
|
- `images[].density` **[Number][7]** number representing the DPI for vector overlay image. (optional, default `72`)
|
||||||
- `images[].raw` **[Object][4]?** describes overlay when using raw pixel data.
|
- `images[].raw` **[Object][4]?** describes overlay when using raw pixel data.
|
||||||
- `images[].raw.width` **[Number][7]?**
|
- `images[].raw.width` **[Number][7]?**
|
||||||
|
@ -105,7 +105,8 @@ function composite (images) {
|
|||||||
tile: false,
|
tile: false,
|
||||||
left: -1,
|
left: -1,
|
||||||
top: -1,
|
top: -1,
|
||||||
gravity: 0
|
gravity: 0,
|
||||||
|
premultiplied: false
|
||||||
};
|
};
|
||||||
if (is.defined(image.blend)) {
|
if (is.defined(image.blend)) {
|
||||||
if (is.string(blend[image.blend])) {
|
if (is.string(blend[image.blend])) {
|
||||||
@ -147,6 +148,14 @@ function composite (images) {
|
|||||||
throw is.invalidParameterError('gravity', 'valid gravity', image.gravity);
|
throw is.invalidParameterError('gravity', 'valid gravity', image.gravity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (is.defined(image.premultiplied)) {
|
||||||
|
if (is.bool(image.premultiplied)) {
|
||||||
|
composite.premultiplied = image.premultiplied;
|
||||||
|
} else {
|
||||||
|
throw is.invalidParameterError('premultiplied', 'boolean', image.premultiplied);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return composite;
|
return composite;
|
||||||
});
|
});
|
||||||
return this;
|
return this;
|
||||||
|
@ -591,7 +591,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|||||||
if (!HasAlpha(compositeImage)) {
|
if (!HasAlpha(compositeImage)) {
|
||||||
compositeImage = sharp::EnsureAlpha(compositeImage);
|
compositeImage = sharp::EnsureAlpha(compositeImage);
|
||||||
}
|
}
|
||||||
compositeImage = compositeImage.premultiply();
|
if (!composite->premultiplied) compositeImage = compositeImage.premultiply();
|
||||||
// Calculate position
|
// Calculate position
|
||||||
int left;
|
int left;
|
||||||
int top;
|
int top;
|
||||||
@ -1230,6 +1230,7 @@ NAN_METHOD(pipeline) {
|
|||||||
composite->left = AttrTo<int32_t>(compositeObject, "left");
|
composite->left = AttrTo<int32_t>(compositeObject, "left");
|
||||||
composite->top = AttrTo<int32_t>(compositeObject, "top");
|
composite->top = AttrTo<int32_t>(compositeObject, "top");
|
||||||
composite->tile = AttrTo<bool>(compositeObject, "tile");
|
composite->tile = AttrTo<bool>(compositeObject, "tile");
|
||||||
|
composite->premultiplied = AttrTo<bool>(compositeObject, "premultiplied");
|
||||||
baton->composite.push_back(composite);
|
baton->composite.push_back(composite);
|
||||||
}
|
}
|
||||||
// Resize options
|
// Resize options
|
||||||
|
@ -41,6 +41,7 @@ struct Composite {
|
|||||||
int left;
|
int left;
|
||||||
int top;
|
int top;
|
||||||
bool tile;
|
bool tile;
|
||||||
|
bool premultiplied;
|
||||||
|
|
||||||
Composite():
|
Composite():
|
||||||
input(nullptr),
|
input(nullptr),
|
||||||
@ -48,7 +49,8 @@ struct Composite {
|
|||||||
gravity(0),
|
gravity(0),
|
||||||
left(-1),
|
left(-1),
|
||||||
top(-1),
|
top(-1),
|
||||||
tile(false) {}
|
tile(false),
|
||||||
|
premultiplied(false) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PipelineBaton {
|
struct PipelineBaton {
|
||||||
|
BIN
test/fixtures/expected/expected.absent.composite.premultiplied.png
vendored
Executable file
BIN
test/fixtures/expected/expected.absent.composite.premultiplied.png
vendored
Executable file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
test/fixtures/expected/expected.false.composite.premultiplied.png
vendored
Executable file
BIN
test/fixtures/expected/expected.false.composite.premultiplied.png
vendored
Executable file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
test/fixtures/expected/expected.true.composite.premultiplied.png
vendored
Executable file
BIN
test/fixtures/expected/expected.true.composite.premultiplied.png
vendored
Executable file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
BIN
test/fixtures/input.above.composite.premultiplied.png
vendored
Executable file
BIN
test/fixtures/input.above.composite.premultiplied.png
vendored
Executable file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
test/fixtures/input.below.composite.premultiplied.png
vendored
Executable file
BIN
test/fixtures/input.below.composite.premultiplied.png
vendored
Executable file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
65
test/unit/composite.js
Normal file → Executable file
65
test/unit/composite.js
Normal file → Executable file
@ -62,6 +62,65 @@ describe('composite', () => {
|
|||||||
})
|
})
|
||||||
));
|
));
|
||||||
|
|
||||||
|
it('premultiplied true', () => {
|
||||||
|
const filename = 'composite.premultiplied.png';
|
||||||
|
const below = fixtures.path(`input.below.${filename}`);
|
||||||
|
const above = fixtures.path(`input.above.${filename}`);
|
||||||
|
const actual = fixtures.path(`output.true.${filename}`);
|
||||||
|
const expected = fixtures.expected(`expected.true.${filename}`);
|
||||||
|
return sharp(below)
|
||||||
|
.composite([{
|
||||||
|
input: above,
|
||||||
|
blend: 'color-burn',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
premultiplied: true
|
||||||
|
}])
|
||||||
|
.toFile(actual)
|
||||||
|
.then(() => {
|
||||||
|
fixtures.assertMaxColourDistance(actual, expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('premultiplied false', () => {
|
||||||
|
const filename = 'composite.premultiplied.png';
|
||||||
|
const below = fixtures.path(`input.below.${filename}`);
|
||||||
|
const above = fixtures.path(`input.above.${filename}`);
|
||||||
|
const actual = fixtures.path(`output.false.${filename}`);
|
||||||
|
const expected = fixtures.expected(`expected.false.${filename}`);
|
||||||
|
return sharp(below)
|
||||||
|
.composite([{
|
||||||
|
input: above,
|
||||||
|
blend: 'color-burn',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
premultiplied: false
|
||||||
|
}])
|
||||||
|
.toFile(actual)
|
||||||
|
.then(() => {
|
||||||
|
fixtures.assertMaxColourDistance(actual, expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('premultiplied absent', () => {
|
||||||
|
const filename = 'composite.premultiplied.png';
|
||||||
|
const below = fixtures.path(`input.below.${filename}`);
|
||||||
|
const above = fixtures.path(`input.above.${filename}`);
|
||||||
|
const actual = fixtures.path(`output.absent.${filename}`);
|
||||||
|
const expected = fixtures.expected(`expected.absent.${filename}`);
|
||||||
|
return sharp(below)
|
||||||
|
.composite([{
|
||||||
|
input: above,
|
||||||
|
blend: 'color-burn',
|
||||||
|
top: 0,
|
||||||
|
left: 0
|
||||||
|
}])
|
||||||
|
.toFile(actual)
|
||||||
|
.then(() => {
|
||||||
|
fixtures.assertMaxColourDistance(actual, expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('multiple', () => {
|
it('multiple', () => {
|
||||||
const filename = 'composite-multiple.png';
|
const filename = 'composite-multiple.png';
|
||||||
const actual = fixtures.path(`output.${filename}`);
|
const actual = fixtures.path(`output.${filename}`);
|
||||||
@ -265,6 +324,12 @@ describe('composite', () => {
|
|||||||
}, /Expected boolean for tile but received invalid of type string/);
|
}, /Expected boolean for tile but received invalid of type string/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('invalid premultiplied', () => {
|
||||||
|
assert.throws(() => {
|
||||||
|
sharp().composite([{ input: 'test', premultiplied: 'invalid' }]);
|
||||||
|
}, /Expected boolean for premultiplied but received invalid of type string/);
|
||||||
|
});
|
||||||
|
|
||||||
it('invalid left', () => {
|
it('invalid left', () => {
|
||||||
assert.throws(() => {
|
assert.throws(() => {
|
||||||
sharp().composite([{ input: 'test', left: 0.5 }]);
|
sharp().composite([{ input: 'test', left: 0.5 }]);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user