mirror of
https://github.com/lovell/sharp.git
synced 2026-02-04 13:46:19 +01:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e40a881ab4 | ||
|
|
c1b13adac3 | ||
|
|
29e09898f7 | ||
|
|
853a20358e | ||
|
|
8bb30d7801 | ||
|
|
a333b87f5d | ||
|
|
4662527a17 | ||
|
|
b10d8f89ca | ||
|
|
f903e1465e | ||
|
|
a75718565c | ||
|
|
4d82331bf6 |
@@ -69,7 +69,7 @@ image
|
|||||||
const size = getNormalSize(await sharp(input).metadata());
|
const size = getNormalSize(await sharp(input).metadata());
|
||||||
|
|
||||||
function getNormalSize({ width, height, orientation }) {
|
function getNormalSize({ width, height, orientation }) {
|
||||||
return orientation || 0 >= 5
|
return (orientation || 0) >= 5
|
||||||
? { width: height, height: width }
|
? { width: height, height: width }
|
||||||
: { width, height };
|
: { width, height };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ Possible interpolation kernels are:
|
|||||||
* `options.height` **[String][10]?** alternative means of specifying `height`. If both are present this take priority.
|
* `options.height` **[String][10]?** alternative means of specifying `height`. If both are present this take priority.
|
||||||
* `options.fit` **[String][10]** how the image should be resized to fit both provided dimensions, one of `cover`, `contain`, `fill`, `inside` or `outside`. (optional, default `'cover'`)
|
* `options.fit` **[String][10]** how the image should be resized to fit both provided dimensions, one of `cover`, `contain`, `fill`, `inside` or `outside`. (optional, default `'cover'`)
|
||||||
* `options.position` **[String][10]** position, gravity or strategy to use when `fit` is `cover` or `contain`. (optional, default `'centre'`)
|
* `options.position` **[String][10]** position, gravity or strategy to use when `fit` is `cover` or `contain`. (optional, default `'centre'`)
|
||||||
* `options.background` **([String][10] | [Object][9])** background colour when using a `fit` of `contain`, parsed by the [color][11] module, defaults to black without transparency. (optional, default `{r:0,g:0,b:0,alpha:1}`)
|
* `options.background` **([String][10] | [Object][9])** background colour when `fit` is `contain`, parsed by the [color][11] module, defaults to black without transparency. (optional, default `{r:0,g:0,b:0,alpha:1}`)
|
||||||
* `options.kernel` **[String][10]** the kernel to use for image reduction. (optional, default `'lanczos3'`)
|
* `options.kernel` **[String][10]** the kernel to use for image reduction. (optional, default `'lanczos3'`)
|
||||||
* `options.withoutEnlargement` **[Boolean][12]** do not enlarge if the width *or* height are already less than the specified dimensions, equivalent to GraphicsMagick's `>` geometry option. (optional, default `false`)
|
* `options.withoutEnlargement` **[Boolean][12]** do not enlarge if the width *or* height are already less than the specified dimensions, equivalent to GraphicsMagick's `>` geometry option. (optional, default `false`)
|
||||||
* `options.withoutReduction` **[Boolean][12]** do not reduce if the width *or* height are already greater than the specified dimensions, equivalent to GraphicsMagick's `<` geometry option. (optional, default `false`)
|
* `options.withoutReduction` **[Boolean][12]** do not reduce if the width *or* height are already greater than the specified dimensions, equivalent to GraphicsMagick's `<` geometry option. (optional, default `false`)
|
||||||
|
|||||||
@@ -4,6 +4,19 @@
|
|||||||
|
|
||||||
Requires libvips v8.12.2
|
Requires libvips v8.12.2
|
||||||
|
|
||||||
|
### v0.30.7 - 22nd June 2022
|
||||||
|
|
||||||
|
* Ensure tiled composition always works with outside resizing.
|
||||||
|
[#3227](https://github.com/lovell/sharp/issues/3227)
|
||||||
|
|
||||||
|
* Allow WebP encoding effort of 0.
|
||||||
|
[#3261](https://github.com/lovell/sharp/pull/3261)
|
||||||
|
[@AlexanderTheGrey](https://github.com/AlexanderTheGrey)
|
||||||
|
|
||||||
|
* Prevent upsampling via libwebp.
|
||||||
|
[#3267](https://github.com/lovell/sharp/pull/3267)
|
||||||
|
[@blacha](https://github.com/blacha)
|
||||||
|
|
||||||
### v0.30.6 - 30th May 2022
|
### v0.30.6 - 30th May 2022
|
||||||
|
|
||||||
* Allow values for `limitInputPixels` larger than 32-bit.
|
* Allow values for `limitInputPixels` larger than 32-bit.
|
||||||
|
|||||||
@@ -248,3 +248,9 @@ GitHub: https://github.com/ankurparihar
|
|||||||
|
|
||||||
Name: Joona Heinikoski
|
Name: Joona Heinikoski
|
||||||
GitHub: https://github.com/joonamo
|
GitHub: https://github.com/joonamo
|
||||||
|
|
||||||
|
Name: AlexanderTheGrey
|
||||||
|
GitHub: https://github.com/AlexanderTheGrey
|
||||||
|
|
||||||
|
Name: Blayne Chard
|
||||||
|
GitHub: https://github.com/blacha
|
||||||
|
|||||||
@@ -98,6 +98,14 @@ use the following flags:
|
|||||||
npm install --arch=x64 --platform=linux --libc=glibc sharp
|
npm install --arch=x64 --platform=linux --libc=glibc sharp
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Multiple platforms and architectures can be supported within the same installation tree.
|
||||||
|
The following example for macOS installs x64 binaries then adds (via a rebuild) arm64 binaries:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm install --platform=darwin --arch=x64 sharp
|
||||||
|
npm rebuild --platform=darwin --arch=arm64 sharp
|
||||||
|
```
|
||||||
|
|
||||||
## Custom libvips
|
## Custom libvips
|
||||||
|
|
||||||
To use a custom, globally-installed version of libvips instead of the provided binaries,
|
To use a custom, globally-installed version of libvips instead of the provided binaries,
|
||||||
@@ -136,6 +144,16 @@ To install the prebuilt sharp binaries from a directory on the local filesystem,
|
|||||||
set the `sharp_local_prebuilds` npm config option
|
set the `sharp_local_prebuilds` npm config option
|
||||||
or the `npm_config_sharp_local_prebuilds` environment variable.
|
or the `npm_config_sharp_local_prebuilds` environment variable.
|
||||||
|
|
||||||
|
URL example:
|
||||||
|
if `sharp_binary_host` is set to `https://hostname/path`
|
||||||
|
and the sharp version is `1.2.3` then the resultant URL will be
|
||||||
|
`https://hostname/path/sharp-v1.2.3-napi-v5-platform-arch.tar.gz`.
|
||||||
|
|
||||||
|
Filename example:
|
||||||
|
if `sharp_local_prebuilds` is set to `/path`
|
||||||
|
and the sharp version is `1.2.3` then the resultant filename will be
|
||||||
|
`/path/sharp-v1.2.3-napi-v5-platform-arch.tar.gz`.
|
||||||
|
|
||||||
### Prebuilt libvips binaries
|
### Prebuilt libvips binaries
|
||||||
|
|
||||||
To install the prebuilt libvips binaries from a custom URL,
|
To install the prebuilt libvips binaries from a custom URL,
|
||||||
@@ -147,9 +165,16 @@ set the `sharp_libvips_local_prebuilds` npm config option
|
|||||||
or the `npm_config_sharp_libvips_local_prebuilds` environment variable.
|
or the `npm_config_sharp_libvips_local_prebuilds` environment variable.
|
||||||
|
|
||||||
The version subpath and filename are appended to these.
|
The version subpath and filename are appended to these.
|
||||||
For example, if `sharp_libvips_binary_host` is set to `https://hostname/path`
|
|
||||||
and the libvips version is `1.2.3` then the resultant URL will be
|
URL example:
|
||||||
`https://hostname/path/v1.2.3/libvips-1.2.3-platform-arch.tar.br`.
|
if `sharp_libvips_binary_host` is set to `https://hostname/path`
|
||||||
|
and the libvips version is `4.5.6` then the resultant URL will be
|
||||||
|
`https://hostname/path/v4.5.6/libvips-4.5.6-platform-arch.tar.br`.
|
||||||
|
|
||||||
|
Filename example:
|
||||||
|
if `sharp_libvips_local_prebuilds` is set to `/path`
|
||||||
|
and the libvips version is `4.5.6` then the resultant filename will be
|
||||||
|
`/path/v4.5.6/libvips-4.5.6-platform-arch.tar.br`.
|
||||||
|
|
||||||
See the Chinese mirror below for a further example.
|
See the Chinese mirror below for a further example.
|
||||||
|
|
||||||
|
|||||||
@@ -357,7 +357,7 @@ function _isStreamInput () {
|
|||||||
* const size = getNormalSize(await sharp(input).metadata());
|
* const size = getNormalSize(await sharp(input).metadata());
|
||||||
*
|
*
|
||||||
* function getNormalSize({ width, height, orientation }) {
|
* function getNormalSize({ width, height, orientation }) {
|
||||||
* return orientation || 0 >= 5
|
* return (orientation || 0) >= 5
|
||||||
* ? { width: height, height: width }
|
* ? { width: height, height: width }
|
||||||
* : { width, height };
|
* : { width, height };
|
||||||
* }
|
* }
|
||||||
|
|||||||
@@ -495,7 +495,7 @@ function webp (options) {
|
|||||||
if (is.defined(options.smartSubsample)) {
|
if (is.defined(options.smartSubsample)) {
|
||||||
this._setBooleanOption('webpSmartSubsample', options.smartSubsample);
|
this._setBooleanOption('webpSmartSubsample', options.smartSubsample);
|
||||||
}
|
}
|
||||||
const effort = options.effort || options.reductionEffort;
|
const effort = is.defined(options.effort) ? options.effort : options.reductionEffort;
|
||||||
if (is.defined(effort)) {
|
if (is.defined(effort)) {
|
||||||
if (is.integer(effort) && is.inRange(effort, 0, 6)) {
|
if (is.integer(effort) && is.inRange(effort, 0, 6)) {
|
||||||
this.options.webpEffort = effort;
|
this.options.webpEffort = effort;
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ function isRotationExpected (options) {
|
|||||||
* @param {String} [options.height] - alternative means of specifying `height`. If both are present this take priority.
|
* @param {String} [options.height] - alternative means of specifying `height`. If both are present this take priority.
|
||||||
* @param {String} [options.fit='cover'] - how the image should be resized to fit both provided dimensions, one of `cover`, `contain`, `fill`, `inside` or `outside`.
|
* @param {String} [options.fit='cover'] - how the image should be resized to fit both provided dimensions, one of `cover`, `contain`, `fill`, `inside` or `outside`.
|
||||||
* @param {String} [options.position='centre'] - position, gravity or strategy to use when `fit` is `cover` or `contain`.
|
* @param {String} [options.position='centre'] - position, gravity or strategy to use when `fit` is `cover` or `contain`.
|
||||||
* @param {String|Object} [options.background={r: 0, g: 0, b: 0, alpha: 1}] - background colour when using a `fit` of `contain`, parsed by the [color](https://www.npmjs.org/package/color) module, defaults to black without transparency.
|
* @param {String|Object} [options.background={r: 0, g: 0, b: 0, alpha: 1}] - background colour when `fit` is `contain`, parsed by the [color](https://www.npmjs.org/package/color) module, defaults to black without transparency.
|
||||||
* @param {String} [options.kernel='lanczos3'] - the kernel to use for image reduction.
|
* @param {String} [options.kernel='lanczos3'] - the kernel to use for image reduction.
|
||||||
* @param {Boolean} [options.withoutEnlargement=false] - do not enlarge if the width *or* height are already less than the specified dimensions, equivalent to GraphicsMagick's `>` geometry option.
|
* @param {Boolean} [options.withoutEnlargement=false] - do not enlarge if the width *or* height are already less than the specified dimensions, equivalent to GraphicsMagick's `>` geometry option.
|
||||||
* @param {Boolean} [options.withoutReduction=false] - do not reduce if the width *or* height are already greater than the specified dimensions, equivalent to GraphicsMagick's `<` geometry option.
|
* @param {Boolean} [options.withoutReduction=false] - do not reduce if the width *or* height are already greater than the specified dimensions, equivalent to GraphicsMagick's `<` geometry option.
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ try {
|
|||||||
help.push('- Update Homebrew: "brew update && brew upgrade vips"');
|
help.push('- Update Homebrew: "brew update && brew upgrade vips"');
|
||||||
} else {
|
} else {
|
||||||
const [platform, arch] = platformAndArch.split('-');
|
const [platform, arch] = platformAndArch.split('-');
|
||||||
|
if (platform === 'linux' && /Module did not self-register/.test(err.message)) {
|
||||||
|
help.push('- Using worker threads? See https://sharp.pixelplumbing.com/install#worker-threads');
|
||||||
|
}
|
||||||
help.push(
|
help.push(
|
||||||
'- Install with verbose logging and look for errors: "npm install --ignore-scripts=false --foreground-scripts --verbose sharp"',
|
'- Install with verbose logging and look for errors: "npm install --ignore-scripts=false --foreground-scripts --verbose sharp"',
|
||||||
`- Install for the current ${platformAndArch} runtime: "npm install --platform=${platform} --arch=${arch} sharp"`
|
`- Install for the current ${platformAndArch} runtime: "npm install --platform=${platform} --arch=${arch} sharp"`
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "sharp",
|
"name": "sharp",
|
||||||
"description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images",
|
"description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images",
|
||||||
"version": "0.30.6",
|
"version": "0.30.7",
|
||||||
"author": "Lovell Fuller <npm@lovell.info>",
|
"author": "Lovell Fuller <npm@lovell.info>",
|
||||||
"homepage": "https://github.com/lovell/sharp",
|
"homepage": "https://github.com/lovell/sharp",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
@@ -131,14 +131,14 @@
|
|||||||
"color": "^4.2.3",
|
"color": "^4.2.3",
|
||||||
"detect-libc": "^2.0.1",
|
"detect-libc": "^2.0.1",
|
||||||
"node-addon-api": "^5.0.0",
|
"node-addon-api": "^5.0.0",
|
||||||
"prebuild-install": "^7.1.0",
|
"prebuild-install": "^7.1.1",
|
||||||
"semver": "^7.3.7",
|
"semver": "^7.3.7",
|
||||||
"simple-get": "^4.0.1",
|
"simple-get": "^4.0.1",
|
||||||
"tar-fs": "^2.1.1",
|
"tar-fs": "^2.1.1",
|
||||||
"tunnel-agent": "^0.6.0"
|
"tunnel-agent": "^0.6.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"async": "^3.2.3",
|
"async": "^3.2.4",
|
||||||
"cc": "^3.0.1",
|
"cc": "^3.0.1",
|
||||||
"decompress-zip": "^0.3.3",
|
"decompress-zip": "^0.3.3",
|
||||||
"documentation": "^13.2.5",
|
"documentation": "^13.2.5",
|
||||||
|
|||||||
@@ -188,8 +188,10 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
if (jpegShrinkOnLoad > 1 && static_cast<int>(shrink) == jpegShrinkOnLoad) {
|
if (jpegShrinkOnLoad > 1 && static_cast<int>(shrink) == jpegShrinkOnLoad) {
|
||||||
jpegShrinkOnLoad /= 2;
|
jpegShrinkOnLoad /= 2;
|
||||||
}
|
}
|
||||||
} else if (inputImageType == sharp::ImageType::WEBP ||
|
} else if (inputImageType == sharp::ImageType::WEBP && shrink > 1.0) {
|
||||||
inputImageType == sharp::ImageType::SVG ||
|
// Avoid upscaling via webp
|
||||||
|
scale = 1.0 / shrink;
|
||||||
|
} else if (inputImageType == sharp::ImageType::SVG ||
|
||||||
inputImageType == sharp::ImageType::PDF) {
|
inputImageType == sharp::ImageType::PDF) {
|
||||||
scale = 1.0 / shrink;
|
scale = 1.0 / shrink;
|
||||||
}
|
}
|
||||||
@@ -607,14 +609,14 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
int across = 0;
|
int across = 0;
|
||||||
int down = 0;
|
int down = 0;
|
||||||
// Use gravity in overlay
|
// Use gravity in overlay
|
||||||
if (compositeImage.width() <= baton->width) {
|
if (compositeImage.width() <= image.width()) {
|
||||||
across = static_cast<int>(ceil(static_cast<double>(image.width()) / compositeImage.width()));
|
across = static_cast<int>(ceil(static_cast<double>(image.width()) / compositeImage.width()));
|
||||||
// Ensure odd number of tiles across when gravity is centre, north or south
|
// Ensure odd number of tiles across when gravity is centre, north or south
|
||||||
if (composite->gravity == 0 || composite->gravity == 1 || composite->gravity == 3) {
|
if (composite->gravity == 0 || composite->gravity == 1 || composite->gravity == 3) {
|
||||||
across |= 1;
|
across |= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (compositeImage.height() <= baton->height) {
|
if (compositeImage.height() <= image.height()) {
|
||||||
down = static_cast<int>(ceil(static_cast<double>(image.height()) / compositeImage.height()));
|
down = static_cast<int>(ceil(static_cast<double>(image.height()) / compositeImage.height()));
|
||||||
// Ensure odd number of tiles down when gravity is centre, east or west
|
// Ensure odd number of tiles down when gravity is centre, east or west
|
||||||
if (composite->gravity == 0 || composite->gravity == 2 || composite->gravity == 4) {
|
if (composite->gravity == 0 || composite->gravity == 2 || composite->gravity == 4) {
|
||||||
|
|||||||
@@ -420,4 +420,31 @@ describe('composite', () => {
|
|||||||
|
|
||||||
assert.deepStrictEqual(red, { r, g, b });
|
assert.deepStrictEqual(red, { r, g, b });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Ensure tiled composition works with resized fit=outside', async () => {
|
||||||
|
const { info } = await sharp({
|
||||||
|
create: {
|
||||||
|
width: 41, height: 41, channels: 3, background: 'red'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.resize({
|
||||||
|
width: 10,
|
||||||
|
height: 40,
|
||||||
|
fit: 'outside'
|
||||||
|
})
|
||||||
|
.composite([
|
||||||
|
{
|
||||||
|
input: {
|
||||||
|
create: {
|
||||||
|
width: 16, height: 16, channels: 3, background: 'green'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tile: true
|
||||||
|
}
|
||||||
|
])
|
||||||
|
.toBuffer({ resolveWithObject: true });
|
||||||
|
|
||||||
|
assert.strictEqual(info.width, 40);
|
||||||
|
assert.strictEqual(info.height, 40);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -121,6 +121,20 @@ describe('Resize dimensions', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Webp resize then extract large image', function (done) {
|
||||||
|
sharp(fixtures.inputWebP)
|
||||||
|
.resize(0x4000, 0x4000)
|
||||||
|
.extract({ top: 0x2000, left: 0x2000, width: 256, height: 256 })
|
||||||
|
.webp()
|
||||||
|
.toBuffer(function (err, data, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual('webp', info.format);
|
||||||
|
assert.strictEqual(256, info.width);
|
||||||
|
assert.strictEqual(256, info.height);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('WebP shrink-on-load rounds to zero, ensure recalculation is correct', function (done) {
|
it('WebP shrink-on-load rounds to zero, ensure recalculation is correct', function (done) {
|
||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.resize(1080, 607)
|
.resize(1080, 607)
|
||||||
|
|||||||
@@ -133,6 +133,12 @@ describe('WebP', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should set effort to 0', () => {
|
||||||
|
const effort = sharp().webp({ effort: 0 }).options.webpEffort;
|
||||||
|
|
||||||
|
assert.strictEqual(effort, 0);
|
||||||
|
});
|
||||||
|
|
||||||
it('invalid loop throws', () => {
|
it('invalid loop throws', () => {
|
||||||
assert.throws(() => {
|
assert.throws(() => {
|
||||||
sharp().webp({ loop: -1 });
|
sharp().webp({ loop: -1 });
|
||||||
|
|||||||
Reference in New Issue
Block a user