mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 10:30:15 +02:00
Add premultiplied boolean flag for raw pixel data input (#2685)
This commit is contained in:
parent
309918a878
commit
9a1e8ed574
@ -37,6 +37,8 @@ Implements the [stream.Duplex][1] class.
|
|||||||
* `options.raw.width` **[number][8]?** integral number of pixels wide.
|
* `options.raw.width` **[number][8]?** integral number of pixels wide.
|
||||||
* `options.raw.height` **[number][8]?** integral number of pixels high.
|
* `options.raw.height` **[number][8]?** integral number of pixels high.
|
||||||
* `options.raw.channels` **[number][8]?** integral number of channels, between 1 and 4.
|
* `options.raw.channels` **[number][8]?** integral number of channels, between 1 and 4.
|
||||||
|
* `options.raw.premultiplied` **[boolean][7]?** specifies that the raw input has already been premultiplied, set to `true`
|
||||||
|
to avoid sharp premultiplying the image. (optional, default `false`)
|
||||||
* `options.create` **[Object][6]?** describes a new image to be created.
|
* `options.create` **[Object][6]?** describes a new image to be created.
|
||||||
|
|
||||||
* `options.create.width` **[number][8]?** integral number of pixels wide.
|
* `options.create.width` **[number][8]?** integral number of pixels wide.
|
||||||
|
@ -139,6 +139,8 @@ const debuglog = util.debuglog('sharp');
|
|||||||
* @param {number} [options.raw.width] - integral number of pixels wide.
|
* @param {number} [options.raw.width] - integral number of pixels wide.
|
||||||
* @param {number} [options.raw.height] - integral number of pixels high.
|
* @param {number} [options.raw.height] - integral number of pixels high.
|
||||||
* @param {number} [options.raw.channels] - integral number of channels, between 1 and 4.
|
* @param {number} [options.raw.channels] - integral number of channels, between 1 and 4.
|
||||||
|
* @param {boolean} [options.raw.premultiplied] - specifies that the raw input has already been premultiplied, set to `true`
|
||||||
|
* to avoid sharp premultiplying the image. (optional, default `false`)
|
||||||
* @param {Object} [options.create] - describes a new image to be created.
|
* @param {Object} [options.create] - describes a new image to be created.
|
||||||
* @param {number} [options.create.width] - integral number of pixels wide.
|
* @param {number} [options.create.width] - integral number of pixels wide.
|
||||||
* @param {number} [options.create.height] - integral number of pixels high.
|
* @param {number} [options.create.height] - integral number of pixels high.
|
||||||
|
@ -103,6 +103,7 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
|||||||
inputDescriptor.rawWidth = inputOptions.raw.width;
|
inputDescriptor.rawWidth = inputOptions.raw.width;
|
||||||
inputDescriptor.rawHeight = inputOptions.raw.height;
|
inputDescriptor.rawHeight = inputOptions.raw.height;
|
||||||
inputDescriptor.rawChannels = inputOptions.raw.channels;
|
inputDescriptor.rawChannels = inputOptions.raw.channels;
|
||||||
|
inputDescriptor.rawPremultiplied = !!inputOptions.raw.premultiplied;
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Expected width, height and channels for raw pixel input');
|
throw new Error('Expected width, height and channels for raw pixel input');
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,8 @@
|
|||||||
"Manan Jadhav <manan@motionden.com>",
|
"Manan Jadhav <manan@motionden.com>",
|
||||||
"Leon Radley <leon@radley.se>",
|
"Leon Radley <leon@radley.se>",
|
||||||
"alza54 <alza54@thiocod.in>",
|
"alza54 <alza54@thiocod.in>",
|
||||||
"Jacob Smith <jacob@frende.me>"
|
"Jacob Smith <jacob@frende.me>",
|
||||||
|
"Michael Nutt <michael@nutt.im>"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"install": "(node install/libvips && node install/dll-copy && prebuild-install) || (node-gyp rebuild && node install/dll-copy)",
|
"install": "(node install/libvips && node install/dll-copy && prebuild-install) || (node-gyp rebuild && node install/dll-copy)",
|
||||||
|
@ -95,6 +95,7 @@ namespace sharp {
|
|||||||
descriptor->rawChannels = AttrAsUint32(input, "rawChannels");
|
descriptor->rawChannels = AttrAsUint32(input, "rawChannels");
|
||||||
descriptor->rawWidth = AttrAsUint32(input, "rawWidth");
|
descriptor->rawWidth = AttrAsUint32(input, "rawWidth");
|
||||||
descriptor->rawHeight = AttrAsUint32(input, "rawHeight");
|
descriptor->rawHeight = AttrAsUint32(input, "rawHeight");
|
||||||
|
descriptor->rawPremultiplied = AttrAsBool(input, "rawPremultiplied");
|
||||||
}
|
}
|
||||||
// Multi-page input (GIF, TIFF, PDF)
|
// Multi-page input (GIF, TIFF, PDF)
|
||||||
if (HasAttr(input, "pages")) {
|
if (HasAttr(input, "pages")) {
|
||||||
@ -302,6 +303,9 @@ namespace sharp {
|
|||||||
} else {
|
} else {
|
||||||
image.get_image()->Type = VIPS_INTERPRETATION_sRGB;
|
image.get_image()->Type = VIPS_INTERPRETATION_sRGB;
|
||||||
}
|
}
|
||||||
|
if (descriptor->rawPremultiplied) {
|
||||||
|
image = image.unpremultiply();
|
||||||
|
}
|
||||||
imageType = ImageType::RAW;
|
imageType = ImageType::RAW;
|
||||||
} else {
|
} else {
|
||||||
// Compressed data
|
// Compressed data
|
||||||
|
@ -57,6 +57,7 @@ namespace sharp {
|
|||||||
int rawChannels;
|
int rawChannels;
|
||||||
int rawWidth;
|
int rawWidth;
|
||||||
int rawHeight;
|
int rawHeight;
|
||||||
|
bool rawPremultiplied;
|
||||||
int pages;
|
int pages;
|
||||||
int page;
|
int page;
|
||||||
int level;
|
int level;
|
||||||
@ -80,6 +81,7 @@ namespace sharp {
|
|||||||
rawChannels(0),
|
rawChannels(0),
|
||||||
rawWidth(0),
|
rawWidth(0),
|
||||||
rawHeight(0),
|
rawHeight(0),
|
||||||
|
rawPremultiplied(false),
|
||||||
pages(1),
|
pages(1),
|
||||||
page(0),
|
page(0),
|
||||||
level(0),
|
level(0),
|
||||||
|
1
test/fixtures/index.js
vendored
1
test/fixtures/index.js
vendored
@ -90,6 +90,7 @@ module.exports = {
|
|||||||
inputPngEmbed: getPath('embedgravitybird.png'), // Released to sharp under a CC BY 4.0
|
inputPngEmbed: getPath('embedgravitybird.png'), // Released to sharp under a CC BY 4.0
|
||||||
inputPngRGBWithAlpha: getPath('2569067123_aca715a2ee_o.png'), // http://www.flickr.com/photos/grizdave/2569067123/ (same as inputJpg)
|
inputPngRGBWithAlpha: getPath('2569067123_aca715a2ee_o.png'), // http://www.flickr.com/photos/grizdave/2569067123/ (same as inputJpg)
|
||||||
inputPngImageInAlpha: getPath('image-in-alpha.png'), // https://github.com/lovell/sharp/issues/1597
|
inputPngImageInAlpha: getPath('image-in-alpha.png'), // https://github.com/lovell/sharp/issues/1597
|
||||||
|
inputPngSolidAlpha: getPath('with-alpha.png'), // https://github.com/lovell/sharp/issues/1599
|
||||||
|
|
||||||
inputWebP: getPath('4.webp'), // http://www.gstatic.com/webp/gallery/4.webp
|
inputWebP: getPath('4.webp'), // http://www.gstatic.com/webp/gallery/4.webp
|
||||||
inputWebPWithTransparency: getPath('5_webp_a.webp'), // http://www.gstatic.com/webp/gallery3/5_webp_a.webp
|
inputWebPWithTransparency: getPath('5_webp_a.webp'), // http://www.gstatic.com/webp/gallery3/5_webp_a.webp
|
||||||
|
BIN
test/fixtures/with-alpha.png
vendored
Normal file
BIN
test/fixtures/with-alpha.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
@ -107,6 +107,52 @@ describe('Raw pixel data', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('RGBA premultiplied', function (done) {
|
||||||
|
// Convert to raw pixel data
|
||||||
|
sharp(fixtures.inputPngSolidAlpha)
|
||||||
|
.resize(256)
|
||||||
|
.raw()
|
||||||
|
.toBuffer(function (err, data, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(256, info.width);
|
||||||
|
assert.strictEqual(192, info.height);
|
||||||
|
assert.strictEqual(4, info.channels);
|
||||||
|
|
||||||
|
const originalData = Buffer.from(data);
|
||||||
|
|
||||||
|
// Premultiply image data
|
||||||
|
for (let i = 0; i < data.length; i += 4) {
|
||||||
|
const alpha = data[i + 3];
|
||||||
|
const norm = alpha / 255;
|
||||||
|
|
||||||
|
if (alpha < 255) {
|
||||||
|
data[i] = Math.round(data[i] * norm);
|
||||||
|
data[i + 1] = Math.round(data[i + 1] * norm);
|
||||||
|
data[i + 2] = Math.round(data[i + 2] * norm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert back to PNG
|
||||||
|
sharp(data, {
|
||||||
|
raw: {
|
||||||
|
width: info.width,
|
||||||
|
height: info.height,
|
||||||
|
channels: info.channels,
|
||||||
|
premultiplied: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.raw()
|
||||||
|
.toBuffer(function (err, data, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(256, info.width);
|
||||||
|
assert.strictEqual(192, info.height);
|
||||||
|
assert.strictEqual(4, info.channels);
|
||||||
|
assert.equal(data.compare(originalData), 0, 'output buffer matches unpremultiplied input buffer');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('JPEG to raw Stream and back again', function (done) {
|
it('JPEG to raw Stream and back again', function (done) {
|
||||||
const width = 32;
|
const width = 32;
|
||||||
const height = 24;
|
const height = 24;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user