mirror of
https://github.com/lovell/sharp.git
synced 2026-02-04 13:46:19 +01:00
Compare commits
36 Commits
v0.34.0-rc
...
v0.34.2-rc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
956d72ddc0 | ||
|
|
00e66efbee | ||
|
|
db3a4528eb | ||
|
|
d36fd5064d | ||
|
|
8e17c6f518 | ||
|
|
94481a967e | ||
|
|
32872ef840 | ||
|
|
7c7f960b60 | ||
|
|
0b5f131df8 | ||
|
|
e922ef7450 | ||
|
|
73bec629cf | ||
|
|
758d7e63cc | ||
|
|
eba3e9aeb2 | ||
|
|
701143afb3 | ||
|
|
38b6f44611 | ||
|
|
5b5dfbad77 | ||
|
|
a642767329 | ||
|
|
5cae1abe8f | ||
|
|
66ffc48707 | ||
|
|
3c7dbb8fba | ||
|
|
a9e191328f | ||
|
|
7323dbee98 | ||
|
|
d7a771ca7a | ||
|
|
7d0585fad1 | ||
|
|
ddc1eb8c4c | ||
|
|
c26e67cc5b | ||
|
|
a00ee26d17 | ||
|
|
6dfb60cda2 | ||
|
|
dbb7606129 | ||
|
|
031c808aa5 | ||
|
|
03e1b19764 | ||
|
|
3e41f8b65e | ||
|
|
3fd818c4b5 | ||
|
|
d419aba76d | ||
|
|
3fb1091114 | ||
|
|
2035492fd9 |
13
.github/workflows/ci.yml
vendored
13
.github/workflows/ci.yml
vendored
@@ -110,6 +110,17 @@ jobs:
|
||||
nodejs_version: "^22.9.0"
|
||||
nodejs_version_major: 22
|
||||
platform: win32-x64
|
||||
- os: windows-11-arm
|
||||
nodejs_arch: arm64
|
||||
nodejs_version: "^20.3.0"
|
||||
nodejs_version_major: 20
|
||||
platform: win32-arm64
|
||||
prebuild: true
|
||||
- os: windows-11-arm
|
||||
nodejs_arch: arm64
|
||||
nodejs_version: "^22.9.0"
|
||||
nodejs_version_major: 22
|
||||
platform: win32-arm64
|
||||
steps:
|
||||
- name: Dependencies (Rocky Linux glibc)
|
||||
if: contains(matrix.container, 'rockylinux')
|
||||
@@ -208,7 +219,7 @@ jobs:
|
||||
contents: write
|
||||
name: wasm32 - prebuild
|
||||
runs-on: ubuntu-24.04
|
||||
container: "emscripten/emsdk:4.0.5"
|
||||
container: "emscripten/emsdk:4.0.6"
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# sharp
|
||||
|
||||
<img src="https://cdn.jsdelivr.net/gh/lovell/sharp@main/docs/image/sharp-logo.svg" width="160" height="160" alt="sharp logo" align="right">
|
||||
<img src="https://sharp.pixelplumbing.com/sharp-logo.svg" width="160" height="160" alt="sharp logo" align="right">
|
||||
|
||||
The typical use case for this high speed Node-API module
|
||||
is to convert large images in common formats to
|
||||
|
||||
@@ -18,7 +18,7 @@ export default defineConfig({
|
||||
tag: 'meta',
|
||||
attrs: {
|
||||
'http-equiv': 'Content-Security-Policy',
|
||||
content: "default-src 'self'; connect-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://cdn.jsdelivr.net/gh/lovell/; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://static.cloudflareinsights.com/beacon.min.js/;"
|
||||
content: "default-src 'self'; connect-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://static.cloudflareinsights.com/beacon.min.js/;"
|
||||
}
|
||||
}, {
|
||||
tag: 'link',
|
||||
|
||||
@@ -11,99 +11,6 @@
|
||||
{ "key": "X-Frame-Options", "value": "SAMEORIGIN" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"redirects": [
|
||||
{
|
||||
"source": "**/install/**",
|
||||
"destination": "/install",
|
||||
"type": 301
|
||||
},
|
||||
{
|
||||
"source": "/page/install",
|
||||
"destination": "/install",
|
||||
"type": 301
|
||||
},
|
||||
{
|
||||
"source": "**/api-constructor/**",
|
||||
"destination": "/api-constructor",
|
||||
"type": 301
|
||||
},
|
||||
{
|
||||
"source": "**/api-input/**",
|
||||
"destination": "/api-input",
|
||||
"type": 301
|
||||
},
|
||||
{
|
||||
"source": "**/api-output/**",
|
||||
"destination": "/api-output",
|
||||
"type": 301
|
||||
},
|
||||
{
|
||||
"source": "**/api-resize/**",
|
||||
"destination": "/api-resize",
|
||||
"type": 301
|
||||
},
|
||||
{
|
||||
"source": "**/api-compsite/**",
|
||||
"destination": "/api-compsite",
|
||||
"type": 301
|
||||
},
|
||||
{
|
||||
"source": "**/api-operation/**",
|
||||
"destination": "/api-operation",
|
||||
"type": 301
|
||||
},
|
||||
{
|
||||
"source": "**/api-colour/**",
|
||||
"destination": "/api-colour",
|
||||
"type": 301
|
||||
},
|
||||
{
|
||||
"source": "**/api-channel/**",
|
||||
"destination": "/api-channel",
|
||||
"type": 301
|
||||
},
|
||||
{
|
||||
"source": "**/api-utility/**",
|
||||
"destination": "/api-utility",
|
||||
"type": 301
|
||||
},
|
||||
{
|
||||
"source": "/page/api",
|
||||
"destination": "/api-constructor",
|
||||
"type": 301
|
||||
},
|
||||
{
|
||||
"source": "**/performance/**",
|
||||
"destination": "/performance",
|
||||
"type": 301
|
||||
},
|
||||
{
|
||||
"source": "/page/performance",
|
||||
"destination": "/performance",
|
||||
"type": 301
|
||||
},
|
||||
{
|
||||
"source": "**/changelog/**",
|
||||
"destination": "/changelog",
|
||||
"type": 301
|
||||
},
|
||||
{
|
||||
"source": "/page/changelog",
|
||||
"destination": "/changelog",
|
||||
"type": 301
|
||||
},
|
||||
{
|
||||
"source": "/en/**",
|
||||
"destination": "/",
|
||||
"type": 301
|
||||
}
|
||||
],
|
||||
"rewrites": [
|
||||
{
|
||||
"source": "**",
|
||||
"destination": "/index.html"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/starlight": "^0.31.0",
|
||||
"astro": "^5.1.7"
|
||||
"@astrojs/starlight": "^0.32.3",
|
||||
"astro": "^5.5.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,3 +314,9 @@ GitHub: https://github.com/happycollision
|
||||
|
||||
Name: Florent Zabera
|
||||
GitHub: https://github.com/florentzabera
|
||||
|
||||
Name: Quentin Pinçon
|
||||
GitHub: https://github.com/qpincon
|
||||
|
||||
Name: Hans Chen
|
||||
GitHub: https://github.com/hans00
|
||||
|
||||
@@ -284,6 +284,52 @@ const gaussianBlurred = await sharp(input)
|
||||
```
|
||||
|
||||
|
||||
## dilate
|
||||
> dilate([width]) ⇒ <code>Sharp</code>
|
||||
|
||||
Expand foreground objects using the dilate morphological operator.
|
||||
|
||||
|
||||
**Throws**:
|
||||
|
||||
- <code>Error</code> Invalid parameters
|
||||
|
||||
|
||||
| Param | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| [width] | <code>Number</code> | <code>1</code> | dilation width in pixels. |
|
||||
|
||||
**Example**
|
||||
```js
|
||||
const output = await sharp(input)
|
||||
.dilate()
|
||||
.toBuffer();
|
||||
```
|
||||
|
||||
|
||||
## erode
|
||||
> erode([width]) ⇒ <code>Sharp</code>
|
||||
|
||||
Shrink foreground objects using the erode morphological operator.
|
||||
|
||||
|
||||
**Throws**:
|
||||
|
||||
- <code>Error</code> Invalid parameters
|
||||
|
||||
|
||||
| Param | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| [width] | <code>Number</code> | <code>1</code> | erosion width in pixels. |
|
||||
|
||||
**Example**
|
||||
```js
|
||||
const output = await sharp(input)
|
||||
.erode()
|
||||
.toBuffer();
|
||||
```
|
||||
|
||||
|
||||
## flatten
|
||||
> flatten([options]) ⇒ <code>Sharp</code>
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ When both a `width` and `height` are provided, the possible methods by which the
|
||||
|
||||
Some of these values are based on the [object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit) CSS property.
|
||||
|
||||
<img alt="Examples of various values for the fit property when resizing" width="100%" style="aspect-ratio: 998/243" src="https://cdn.jsdelivr.net/gh/lovell/sharp@main/docs/image/api-resize-fit.svg">
|
||||
<img alt="Examples of various values for the fit property when resizing" width="100%" style="aspect-ratio: 998/243" src="/api-resize-fit.svg">
|
||||
|
||||
When using a **fit** of `cover` or `contain`, the default **position** is `centre`. Other options are:
|
||||
- `sharp.position`: `top`, `right top`, `right`, `right bottom`, `bottom`, `left bottom`, `left`, `left top`.
|
||||
|
||||
@@ -6,7 +6,38 @@ title: Changelog
|
||||
|
||||
Requires libvips v8.16.1
|
||||
|
||||
### v0.34.0 - TBD
|
||||
### v0.34.2 - TBD
|
||||
|
||||
* Ensure animated GIF to WebP conversion retains loop (regression in 0.34.0).
|
||||
[#3394](https://github.com/lovell/sharp/issues/3394)
|
||||
|
||||
* Ensure `pdfBackground` constructor property is used.
|
||||
[#4207](https://github.com/lovell/sharp/pull/4207)
|
||||
|
||||
* Add support for prebuilt Windows ARM64 binaries.
|
||||
[#4375](https://github.com/lovell/sharp/pull/4375)
|
||||
[@hans00](https://github.com/hans00)
|
||||
|
||||
* Ensure resizing with a `fit` of `contain` supports multiple alpha channels.
|
||||
[#4382](https://github.com/lovell/sharp/issues/4382)
|
||||
|
||||
* TypeScript: Ensure `metadata` response more closely matches reality.
|
||||
[#4383](https://github.com/lovell/sharp/issues/4383)
|
||||
|
||||
* TypeScript: Ensure `smartDeblock` property is included in WebP definition.
|
||||
[#4387](https://github.com/lovell/sharp/pull/4387)
|
||||
[@Stephen-X](https://github.com/Stephen-X)
|
||||
|
||||
* Ensure support for wide-character filenames on Windows (regression in 0.34.0).
|
||||
[#4391](https://github.com/lovell/sharp/issues/4391)
|
||||
|
||||
### v0.34.1 - 7th April 2025
|
||||
|
||||
* TypeScript: Ensure new `autoOrient` property is optional.
|
||||
[#4362](https://github.com/lovell/sharp/pull/4362)
|
||||
[@styfle](https://github.com/styfle)
|
||||
|
||||
### v0.34.0 - 4th April 2025
|
||||
|
||||
* Breaking: Support array of input images to be joined or animated.
|
||||
[#1580](https://github.com/lovell/sharp/issues/1580)
|
||||
@@ -14,6 +45,9 @@ Requires libvips v8.16.1
|
||||
* Breaking: Ensure `removeAlpha` removes all alpha channels.
|
||||
[#2266](https://github.com/lovell/sharp/issues/2266)
|
||||
|
||||
* Breaking: Non-animated GIF output defaults to no-loop instead of loop-forever.
|
||||
[#3394](https://github.com/lovell/sharp/issues/3394)
|
||||
|
||||
* Breaking: Support `info.size` on wide-character systems via upgrade to C++17.
|
||||
[#3943](https://github.com/lovell/sharp/issues/3943)
|
||||
|
||||
@@ -24,6 +58,8 @@ Requires libvips v8.16.1
|
||||
|
||||
* Expose WebP `smartDeblock` output option.
|
||||
|
||||
* Prevent use of linux-x64 binaries with v1 microarchitecture.
|
||||
|
||||
* Add `autoOrient` operation and constructor option.
|
||||
[#4151](https://github.com/lovell/sharp/pull/4151)
|
||||
[@happycollision](https://github.com/happycollision)
|
||||
@@ -40,10 +76,17 @@ Requires libvips v8.16.1
|
||||
[#4207](https://github.com/lovell/sharp/pull/4207)
|
||||
[@calebmer](https://github.com/calebmer)
|
||||
|
||||
* Expose erode and dilate operations.
|
||||
[#4243](https://github.com/lovell/sharp/pull/4243)
|
||||
[@qpincon](https://github.com/qpincon)
|
||||
|
||||
* Add support for RGBE images. Requires libvips compiled with radiance support.
|
||||
[#4316](https://github.com/lovell/sharp/pull/4316)
|
||||
[@florentzabera](https://github.com/florentzabera)
|
||||
|
||||
* Allow wide-gamut HEIF output at higher bitdepths.
|
||||
[#4344](https://github.com/lovell/sharp/issues/4344)
|
||||
|
||||
## v0.33 - *gauge*
|
||||
|
||||
Requires libvips v8.15.3
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: "High performance Node.js image processing"
|
||||
---
|
||||
|
||||
<img src="https://cdn.jsdelivr.net/gh/lovell/sharp@main/docs/image/sharp-logo.svg" width="160" height="160" alt="sharp logo" align="right">
|
||||
<img src="/sharp-logo.svg" width="160" height="160" alt="sharp logo" align="right">
|
||||
|
||||
The typical use case for this high speed Node-API module
|
||||
is to convert large images in common formats to
|
||||
|
||||
@@ -53,6 +53,7 @@ Ready-compiled sharp and libvips binaries are provided for use on the most commo
|
||||
* Linux x64 (glibc >= 2.26, musl >= 1.2.2, CPU with SSE4.2)
|
||||
* Windows x64
|
||||
* Windows x86
|
||||
* Windows ARM64
|
||||
|
||||
This provides support for the
|
||||
JPEG, PNG, WebP, AVIF (limited to 8-bit depth), TIFF, GIF and SVG (input) image formats.
|
||||
@@ -286,6 +287,10 @@ option.
|
||||
}
|
||||
```
|
||||
|
||||
When using `electron-forge` with [Webpack](#webpack),
|
||||
you may also need to add
|
||||
[forge-externals-plugin](https://www.npmjs.com/package/@timfish/forge-externals-plugin).
|
||||
|
||||
### vite
|
||||
|
||||
Ensure `sharp` is excluded from bundling via the
|
||||
|
||||
@@ -134,6 +134,26 @@ function toColorspace (colorspace) {
|
||||
return this.toColourspace(colorspace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a RGBA colour array from a given value.
|
||||
* @private
|
||||
* @param {string|Object} value
|
||||
* @throws {Error} Invalid value
|
||||
*/
|
||||
function _getBackgroundColourOption (value) {
|
||||
if (is.object(value) || is.string(value)) {
|
||||
const colour = color(value);
|
||||
return [
|
||||
colour.red(),
|
||||
colour.green(),
|
||||
colour.blue(),
|
||||
Math.round(colour.alpha() * 255)
|
||||
];
|
||||
} else {
|
||||
throw is.invalidParameterError('background', 'object or string', value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a colour attribute of the this.options Object.
|
||||
* @private
|
||||
@@ -143,17 +163,7 @@ function toColorspace (colorspace) {
|
||||
*/
|
||||
function _setBackgroundColourOption (key, value) {
|
||||
if (is.defined(value)) {
|
||||
if (is.object(value) || is.string(value)) {
|
||||
const colour = color(value);
|
||||
this.options[key] = [
|
||||
colour.red(),
|
||||
colour.green(),
|
||||
colour.blue(),
|
||||
Math.round(colour.alpha() * 255)
|
||||
];
|
||||
} else {
|
||||
throw is.invalidParameterError('background', 'object or string', value);
|
||||
}
|
||||
this.options[key] = _getBackgroundColourOption(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,6 +183,7 @@ module.exports = function (Sharp) {
|
||||
toColourspace,
|
||||
toColorspace,
|
||||
// Private
|
||||
_getBackgroundColourOption,
|
||||
_setBackgroundColourOption
|
||||
});
|
||||
// Class attributes
|
||||
|
||||
@@ -263,6 +263,8 @@ const Sharp = function (input, options) {
|
||||
trimBackground: [],
|
||||
trimThreshold: -1,
|
||||
trimLineArt: false,
|
||||
dilateWidth: 0,
|
||||
erodeWidth: 0,
|
||||
gamma: 0,
|
||||
gammaOut: 0,
|
||||
greyscale: false,
|
||||
@@ -296,6 +298,8 @@ const Sharp = function (input, options) {
|
||||
withExif: {},
|
||||
withExifMerge: true,
|
||||
resolveWithObject: false,
|
||||
loop: -1,
|
||||
delay: [],
|
||||
// output format
|
||||
jpegQuality: 80,
|
||||
jpegProgressive: false,
|
||||
|
||||
77
lib/index.d.ts
vendored
77
lib/index.d.ts
vendored
@@ -504,6 +504,22 @@ declare namespace sharp {
|
||||
*/
|
||||
blur(sigma?: number | boolean | BlurOptions): Sharp;
|
||||
|
||||
/**
|
||||
* Expand foreground objects using the dilate morphological operator.
|
||||
* @param {Number} [width=1] dilation width in pixels.
|
||||
* @throws {Error} Invalid parameters
|
||||
* @returns A sharp instance that can be used to chain operations
|
||||
*/
|
||||
dilate(width?: number): Sharp;
|
||||
|
||||
/**
|
||||
* Shrink foreground objects using the erode morphological operator.
|
||||
* @param {Number} [width=1] erosion width in pixels.
|
||||
* @throws {Error} Invalid parameters
|
||||
* @returns A sharp instance that can be used to chain operations
|
||||
*/
|
||||
erode(width?: number): Sharp;
|
||||
|
||||
/**
|
||||
* Merge alpha transparency channel, if any, with background.
|
||||
* @param flatten true to enable and false to disable (defaults to true)
|
||||
@@ -955,7 +971,7 @@ declare namespace sharp {
|
||||
*
|
||||
* Using this option will remove the EXIF `Orientation` tag, if any.
|
||||
*/
|
||||
autoOrient?: boolean;
|
||||
autoOrient?: boolean | undefined;
|
||||
/**
|
||||
* When to abort processing of invalid pixel data, one of (in order of sensitivity):
|
||||
* 'none' (least), 'truncated', 'error' or 'warning' (most), highers level imply lower levels, invalid metadata will always abort. (optional, default 'warning')
|
||||
@@ -1130,13 +1146,13 @@ declare namespace sharp {
|
||||
/** Number value of the EXIF Orientation header, if present */
|
||||
orientation?: number | undefined;
|
||||
/** Name of decoder used to decompress image data e.g. jpeg, png, webp, gif, svg */
|
||||
format?: keyof FormatEnum | undefined;
|
||||
format: keyof FormatEnum;
|
||||
/** Total size of image in bytes, for Stream and Buffer input only */
|
||||
size?: number | undefined;
|
||||
/** Number of pixels wide (EXIF orientation is not taken into consideration) */
|
||||
width?: number | undefined;
|
||||
width: number;
|
||||
/** Number of pixels high (EXIF orientation is not taken into consideration) */
|
||||
height?: number | undefined;
|
||||
height: number;
|
||||
/** Any changed metadata after the image orientation is applied. */
|
||||
autoOrient: {
|
||||
/** Number of pixels wide (EXIF orientation is taken into consideration) */
|
||||
@@ -1145,19 +1161,19 @@ declare namespace sharp {
|
||||
height: number;
|
||||
};
|
||||
/** Name of colour space interpretation */
|
||||
space?: keyof ColourspaceEnum | undefined;
|
||||
space: keyof ColourspaceEnum;
|
||||
/** Number of bands e.g. 3 for sRGB, 4 for CMYK */
|
||||
channels?: Channels | undefined;
|
||||
channels: Channels;
|
||||
/** Name of pixel depth format e.g. uchar, char, ushort, float ... */
|
||||
depth?: string | undefined;
|
||||
depth: keyof DepthEnum;
|
||||
/** Number of pixels per inch (DPI), if present */
|
||||
density?: number | undefined;
|
||||
/** String containing JPEG chroma subsampling, 4:2:0 or 4:4:4 for RGB, 4:2:0:4 or 4:4:4:4 for CMYK */
|
||||
chromaSubsampling?: string | undefined;
|
||||
/** Boolean indicating whether the image is interlaced using a progressive scan */
|
||||
isProgressive?: boolean | undefined;
|
||||
isProgressive: boolean;
|
||||
/** Boolean indicating whether the image is palette-based (GIF, PNG). */
|
||||
isPalette?: boolean | undefined;
|
||||
isPalette: boolean;
|
||||
/** Number of bits per sample for each channel (GIF, PNG). */
|
||||
bitsPerSample?: number | undefined;
|
||||
/** Number of pages/frames contained within the image, with support for TIFF, HEIF, PDF, animated GIF and animated WebP */
|
||||
@@ -1171,9 +1187,9 @@ declare namespace sharp {
|
||||
/** Number of the primary page in a HEIF image */
|
||||
pagePrimary?: number | undefined;
|
||||
/** Boolean indicating the presence of an embedded ICC profile */
|
||||
hasProfile?: boolean | undefined;
|
||||
hasProfile: boolean;
|
||||
/** Boolean indicating the presence of an alpha transparency channel */
|
||||
hasAlpha?: boolean | undefined;
|
||||
hasAlpha: boolean;
|
||||
/** Buffer containing raw EXIF data, if present */
|
||||
exif?: Buffer | undefined;
|
||||
/** Buffer containing raw ICC profile data, if present */
|
||||
@@ -1320,6 +1336,8 @@ declare namespace sharp {
|
||||
nearLossless?: boolean | undefined;
|
||||
/** Use high quality chroma subsampling (optional, default false) */
|
||||
smartSubsample?: boolean | undefined;
|
||||
/** Auto-adjust the deblocking filter, slow but can improve low contrast edges (optional, default false) */
|
||||
smartDeblock?: boolean | undefined;
|
||||
/** Level of CPU effort to reduce file size, integer 0-6 (optional, default 4) */
|
||||
effort?: number | undefined;
|
||||
/** Prevent use of animation key frames to minimise file size (slow) (optional, default false) */
|
||||
@@ -1683,6 +1701,10 @@ declare namespace sharp {
|
||||
/** When using the attention crop strategy, the focal point of the cropped region */
|
||||
attentionX?: number | undefined;
|
||||
attentionY?: number | undefined;
|
||||
/** Number of pages/frames contained within the image, with support for TIFF, HEIF, PDF, animated GIF and animated WebP */
|
||||
pages?: number | undefined;
|
||||
/** Number of pixels high each page in a multi-page image will be. */
|
||||
pageHeight?: number | undefined;
|
||||
}
|
||||
|
||||
interface AvailableFormatInfo {
|
||||
@@ -1723,11 +1745,38 @@ declare namespace sharp {
|
||||
}
|
||||
|
||||
interface ColourspaceEnum {
|
||||
multiband: string;
|
||||
'b-w': string;
|
||||
bw: string;
|
||||
cmc: string;
|
||||
cmyk: string;
|
||||
fourier: string;
|
||||
grey16: string;
|
||||
histogram: string;
|
||||
hsv: string;
|
||||
lab: string;
|
||||
labq: string;
|
||||
labs: string;
|
||||
lch: string;
|
||||
matrix: string;
|
||||
multiband: string;
|
||||
rgb: string;
|
||||
rgb16: string;
|
||||
scrgb: string;
|
||||
srgb: string;
|
||||
xyz: string;
|
||||
yxy: string;
|
||||
}
|
||||
|
||||
interface DepthEnum {
|
||||
char: string;
|
||||
complex: string;
|
||||
double: string;
|
||||
dpcomplex: string;
|
||||
float: string;
|
||||
int: string;
|
||||
short: string;
|
||||
uchar: string;
|
||||
uint: string;
|
||||
ushort: string;
|
||||
}
|
||||
|
||||
type FailOnOptions = 'none' | 'truncated' | 'error' | 'warning';
|
||||
@@ -1796,6 +1845,7 @@ declare namespace sharp {
|
||||
interface FormatEnum {
|
||||
avif: AvailableFormatInfo;
|
||||
dz: AvailableFormatInfo;
|
||||
exr: AvailableFormatInfo;
|
||||
fits: AvailableFormatInfo;
|
||||
gif: AvailableFormatInfo;
|
||||
heif: AvailableFormatInfo;
|
||||
@@ -1809,6 +1859,7 @@ declare namespace sharp {
|
||||
pdf: AvailableFormatInfo;
|
||||
png: AvailableFormatInfo;
|
||||
ppm: AvailableFormatInfo;
|
||||
rad: AvailableFormatInfo;
|
||||
raw: AvailableFormatInfo;
|
||||
svg: AvailableFormatInfo;
|
||||
tiff: AvailableFormatInfo;
|
||||
|
||||
19
lib/input.js
19
lib/input.js
@@ -3,7 +3,6 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const color = require('color');
|
||||
const is = require('./is');
|
||||
const sharp = require('./sharp');
|
||||
|
||||
@@ -249,7 +248,7 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
||||
}
|
||||
// PDF background colour
|
||||
if (is.defined(inputOptions.pdfBackground)) {
|
||||
this._setBackgroundColourOption('pdfBackground', inputOptions.pdfBackground);
|
||||
inputDescriptor.pdfBackground = this._getBackgroundColourOption(inputOptions.pdfBackground);
|
||||
}
|
||||
// Create new image
|
||||
if (is.defined(inputOptions.create)) {
|
||||
@@ -288,13 +287,7 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
||||
if (!is.inRange(inputOptions.create.channels, 3, 4)) {
|
||||
throw is.invalidParameterError('create.channels', 'number between 3 and 4', inputOptions.create.channels);
|
||||
}
|
||||
const background = color(inputOptions.create.background);
|
||||
inputDescriptor.createBackground = [
|
||||
background.red(),
|
||||
background.green(),
|
||||
background.blue(),
|
||||
Math.round(background.alpha() * 255)
|
||||
];
|
||||
inputDescriptor.createBackground = this._getBackgroundColourOption(inputOptions.create.background);
|
||||
} else {
|
||||
throw new Error('Expected valid noise or background to create a new input image');
|
||||
}
|
||||
@@ -410,13 +403,7 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
||||
}
|
||||
}
|
||||
if (is.defined(inputOptions.join.background)) {
|
||||
const background = color(inputOptions.join.background);
|
||||
inputDescriptor.joinBackground = [
|
||||
background.red(),
|
||||
background.green(),
|
||||
background.blue(),
|
||||
Math.round(background.alpha() * 255)
|
||||
];
|
||||
inputDescriptor.joinBackground = this._getBackgroundColourOption(inputOptions.join.background);
|
||||
}
|
||||
if (is.defined(inputOptions.join.halign)) {
|
||||
if (is.string(inputOptions.join.halign) && is.string(this.constructor.align[inputOptions.join.halign])) {
|
||||
|
||||
@@ -18,9 +18,9 @@ const minimumLibvipsVersion = semverCoerce(minimumLibvipsVersionLabelled).versio
|
||||
|
||||
const prebuiltPlatforms = [
|
||||
'darwin-arm64', 'darwin-x64',
|
||||
'linux-arm', 'linux-arm64', 'linux-s390x', 'linux-x64',
|
||||
'linux-arm', 'linux-arm64', 'linux-ppc64', 'linux-s390x', 'linux-x64',
|
||||
'linuxmusl-arm64', 'linuxmusl-x64',
|
||||
'win32-ia32', 'win32-x64'
|
||||
'win32-arm64', 'win32-ia32', 'win32-x64'
|
||||
];
|
||||
|
||||
const spawnSyncOptions = {
|
||||
@@ -113,7 +113,9 @@ const sha512 = (s) => createHash('sha512').update(s).digest('hex');
|
||||
const yarnLocator = () => {
|
||||
try {
|
||||
const identHash = sha512(`imgsharp-libvips-${buildPlatformArch()}`);
|
||||
const npmVersion = semverCoerce(optionalDependencies[`@img/sharp-libvips-${buildPlatformArch()}`]).version;
|
||||
const npmVersion = semverCoerce(optionalDependencies[`@img/sharp-libvips-${buildPlatformArch()}`], {
|
||||
includePrerelease: true
|
||||
}).version;
|
||||
return sha512(`${identHash}npm:${npmVersion}`).slice(0, 10);
|
||||
} catch {}
|
||||
return '';
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const color = require('color');
|
||||
const is = require('./is');
|
||||
|
||||
/**
|
||||
@@ -67,13 +66,7 @@ function rotate (angle, options) {
|
||||
} else if (is.number(angle)) {
|
||||
this.options.rotationAngle = angle;
|
||||
if (is.object(options) && options.background) {
|
||||
const backgroundColour = color(options.background);
|
||||
this.options.rotationBackground = [
|
||||
backgroundColour.red(),
|
||||
backgroundColour.green(),
|
||||
backgroundColour.blue(),
|
||||
Math.round(backgroundColour.alpha() * 255)
|
||||
];
|
||||
this._setBackgroundColourOption('rotationBackground', options.background);
|
||||
}
|
||||
} else {
|
||||
throw is.invalidParameterError('angle', 'numeric', angle);
|
||||
@@ -443,6 +436,52 @@ function blur (options) {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand foreground objects using the dilate morphological operator.
|
||||
*
|
||||
* @example
|
||||
* const output = await sharp(input)
|
||||
* .dilate()
|
||||
* .toBuffer();
|
||||
*
|
||||
* @param {Number} [width=1] dilation width in pixels.
|
||||
* @returns {Sharp}
|
||||
* @throws {Error} Invalid parameters
|
||||
*/
|
||||
function dilate (width) {
|
||||
if (!is.defined(width)) {
|
||||
this.options.dilateWidth = 1;
|
||||
} else if (is.integer(width) && width > 0) {
|
||||
this.options.dilateWidth = width;
|
||||
} else {
|
||||
throw is.invalidParameterError('dilate', 'positive integer', dilate);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shrink foreground objects using the erode morphological operator.
|
||||
*
|
||||
* @example
|
||||
* const output = await sharp(input)
|
||||
* .erode()
|
||||
* .toBuffer();
|
||||
*
|
||||
* @param {Number} [width=1] erosion width in pixels.
|
||||
* @returns {Sharp}
|
||||
* @throws {Error} Invalid parameters
|
||||
*/
|
||||
function erode (width) {
|
||||
if (!is.defined(width)) {
|
||||
this.options.erodeWidth = 1;
|
||||
} else if (is.integer(width) && width > 0) {
|
||||
this.options.erodeWidth = width;
|
||||
} else {
|
||||
throw is.invalidParameterError('erode', 'positive integer', erode);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge alpha transparency channel, if any, with a background, then remove the alpha channel.
|
||||
*
|
||||
@@ -958,6 +997,8 @@ module.exports = function (Sharp) {
|
||||
flop,
|
||||
affine,
|
||||
sharpen,
|
||||
erode,
|
||||
dilate,
|
||||
median,
|
||||
blur,
|
||||
flatten,
|
||||
|
||||
@@ -129,7 +129,7 @@ function isResizeExpected (options) {
|
||||
*
|
||||
* Some of these values are based on the [object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit) CSS property.
|
||||
*
|
||||
* <img alt="Examples of various values for the fit property when resizing" width="100%" style="aspect-ratio: 998/243" src="https://cdn.jsdelivr.net/gh/lovell/sharp@main/docs/image/api-resize-fit.svg">
|
||||
* <img alt="Examples of various values for the fit property when resizing" width="100%" style="aspect-ratio: 998/243" src="/api-resize-fit.svg">
|
||||
*
|
||||
* When using a **fit** of `cover` or `contain`, the default **position** is `centre`. Other options are:
|
||||
* - `sharp.position`: `top`, `right top`, `right`, `right bottom`, `bottom`, `left bottom`, `left`, `left top`.
|
||||
|
||||
12
lib/sharp.js
12
lib/sharp.js
@@ -17,9 +17,9 @@ const paths = [
|
||||
'@img/sharp-wasm32/sharp.node'
|
||||
];
|
||||
|
||||
let sharp;
|
||||
let path, sharp;
|
||||
const errors = [];
|
||||
for (const path of paths) {
|
||||
for (path of paths) {
|
||||
try {
|
||||
sharp = require(path);
|
||||
break;
|
||||
@@ -29,6 +29,14 @@ for (const path of paths) {
|
||||
}
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (sharp && path.startsWith('@img/sharp-linux-x64') && !sharp._isUsingX64V2()) {
|
||||
const err = new Error('Prebuilt binaries for linux-x64 require v2 microarchitecture');
|
||||
err.code = 'Unsupported CPU';
|
||||
errors.push(err);
|
||||
sharp = null;
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (sharp) {
|
||||
module.exports = sharp;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@img/sharp-darwin-arm64",
|
||||
"version": "0.34.0-rc.0",
|
||||
"version": "0.34.2-rc.0",
|
||||
"description": "Prebuilt sharp for use with macOS 64-bit ARM",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"preferUnplugged": true,
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-darwin-arm64": "1.1.0-rc4"
|
||||
"@img/sharp-libvips-darwin-arm64": "1.1.0"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@img/sharp-darwin-x64",
|
||||
"version": "0.34.0-rc.0",
|
||||
"version": "0.34.2-rc.0",
|
||||
"description": "Prebuilt sharp for use with macOS x64",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"preferUnplugged": true,
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-darwin-x64": "1.1.0-rc4"
|
||||
"@img/sharp-libvips-darwin-x64": "1.1.0"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@img/sharp-linux-arm",
|
||||
"version": "0.34.0-rc.0",
|
||||
"version": "0.34.2-rc.0",
|
||||
"description": "Prebuilt sharp for use with Linux (glibc) ARM (32-bit)",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"preferUnplugged": true,
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-arm": "1.1.0-rc4.1"
|
||||
"@img/sharp-libvips-linux-arm": "1.1.0"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@img/sharp-linux-arm64",
|
||||
"version": "0.34.0-rc.0",
|
||||
"version": "0.34.2-rc.0",
|
||||
"description": "Prebuilt sharp for use with Linux (glibc) 64-bit ARM",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"preferUnplugged": true,
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-arm64": "1.1.0-rc4"
|
||||
"@img/sharp-libvips-linux-arm64": "1.1.0"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@img/sharp-linux-ppc64",
|
||||
"version": "0.34.0-rc.0",
|
||||
"version": "0.34.2-rc.0",
|
||||
"description": "Prebuilt sharp for use with Linux (glibc) ppc64",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"preferUnplugged": true,
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-ppc64": "1.1.0-rc4"
|
||||
"@img/sharp-libvips-linux-ppc64": "1.1.0"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@img/sharp-linux-s390x",
|
||||
"version": "0.34.0-rc.0",
|
||||
"version": "0.34.2-rc.0",
|
||||
"description": "Prebuilt sharp for use with Linux (glibc) s390x",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"preferUnplugged": true,
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-s390x": "1.1.0-rc4"
|
||||
"@img/sharp-libvips-linux-s390x": "1.1.0"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@img/sharp-linux-x64",
|
||||
"version": "0.34.0-rc.0",
|
||||
"version": "0.34.2-rc.0",
|
||||
"description": "Prebuilt sharp for use with Linux (glibc) x64",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"preferUnplugged": true,
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-x64": "1.1.0-rc4"
|
||||
"@img/sharp-libvips-linux-x64": "1.1.0"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@img/sharp-linuxmusl-arm64",
|
||||
"version": "0.34.0-rc.0",
|
||||
"version": "0.34.2-rc.0",
|
||||
"description": "Prebuilt sharp for use with Linux (musl) 64-bit ARM",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"preferUnplugged": true,
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linuxmusl-arm64": "1.1.0-rc4"
|
||||
"@img/sharp-libvips-linuxmusl-arm64": "1.1.0"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@img/sharp-linuxmusl-x64",
|
||||
"version": "0.34.0-rc.0",
|
||||
"version": "0.34.2-rc.0",
|
||||
"description": "Prebuilt sharp for use with Linux (musl) x64",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"preferUnplugged": true,
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linuxmusl-x64": "1.1.0-rc4"
|
||||
"@img/sharp-libvips-linuxmusl-x64": "1.1.0"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@img/sharp",
|
||||
"version": "0.34.0-rc.0",
|
||||
"version": "0.34.2-rc.0",
|
||||
"private": "true",
|
||||
"workspaces": [
|
||||
"darwin-arm64",
|
||||
@@ -13,6 +13,7 @@
|
||||
"linuxmusl-arm64",
|
||||
"linuxmusl-x64",
|
||||
"wasm32",
|
||||
"win32-arm64",
|
||||
"win32-ia32",
|
||||
"win32-x64"
|
||||
]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@img/sharp-wasm32",
|
||||
"version": "0.34.0-rc.0",
|
||||
"version": "0.34.2-rc.0",
|
||||
"description": "Prebuilt sharp for use with wasm32",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
@@ -31,7 +31,7 @@
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emnapi/runtime": "^1.3.1"
|
||||
"@emnapi/runtime": "^1.4.3"
|
||||
},
|
||||
"cpu": [
|
||||
"wasm32"
|
||||
|
||||
39
npm/win32-arm64/package.json
Normal file
39
npm/win32-arm64/package.json
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "@img/sharp-win32-arm64",
|
||||
"version": "0.34.2-rc.0",
|
||||
"description": "Prebuilt sharp for use with Windows 64-bit ARM",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/lovell/sharp.git",
|
||||
"directory": "npm/win32-arm64"
|
||||
},
|
||||
"license": "Apache-2.0 AND LGPL-3.0-or-later",
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"preferUnplugged": true,
|
||||
"files": [
|
||||
"lib",
|
||||
"versions.json"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"type": "commonjs",
|
||||
"exports": {
|
||||
"./sharp.node": "./lib/sharp-win32-arm64.node",
|
||||
"./package": "./package.json",
|
||||
"./versions": "./versions.json"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
},
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"cpu": [
|
||||
"arm64"
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@img/sharp-win32-ia32",
|
||||
"version": "0.34.0-rc.0",
|
||||
"version": "0.34.2-rc.0",
|
||||
"description": "Prebuilt sharp for use with Windows x86 (32-bit)",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@img/sharp-win32-x64",
|
||||
"version": "0.34.0-rc.0",
|
||||
"version": "0.34.2-rc.0",
|
||||
"description": "Prebuilt sharp for use with Windows x64",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
|
||||
64
package.json
64
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "sharp",
|
||||
"description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images",
|
||||
"version": "0.34.0-rc.0",
|
||||
"version": "0.34.2-rc.0",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
"contributors": [
|
||||
@@ -138,52 +138,54 @@
|
||||
],
|
||||
"dependencies": {
|
||||
"color": "^4.2.3",
|
||||
"detect-libc": "^2.0.3",
|
||||
"semver": "^7.7.1"
|
||||
"detect-libc": "^2.0.4",
|
||||
"semver": "^7.7.2"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-darwin-arm64": "0.34.0-rc.0",
|
||||
"@img/sharp-darwin-x64": "0.34.0-rc.0",
|
||||
"@img/sharp-libvips-darwin-arm64": "1.1.0-rc4",
|
||||
"@img/sharp-libvips-darwin-x64": "1.1.0-rc4",
|
||||
"@img/sharp-libvips-linux-arm": "1.1.0-rc4.1",
|
||||
"@img/sharp-libvips-linux-arm64": "1.1.0-rc4",
|
||||
"@img/sharp-libvips-linux-ppc64": "1.1.0-rc4",
|
||||
"@img/sharp-libvips-linux-s390x": "1.1.0-rc4",
|
||||
"@img/sharp-libvips-linux-x64": "1.1.0-rc4",
|
||||
"@img/sharp-libvips-linuxmusl-arm64": "1.1.0-rc4",
|
||||
"@img/sharp-libvips-linuxmusl-x64": "1.1.0-rc4",
|
||||
"@img/sharp-linux-arm": "0.34.0-rc.0",
|
||||
"@img/sharp-linux-arm64": "0.34.0-rc.0",
|
||||
"@img/sharp-linux-s390x": "0.34.0-rc.0",
|
||||
"@img/sharp-linux-x64": "0.34.0-rc.0",
|
||||
"@img/sharp-linuxmusl-arm64": "0.34.0-rc.0",
|
||||
"@img/sharp-linuxmusl-x64": "0.34.0-rc.0",
|
||||
"@img/sharp-wasm32": "0.34.0-rc.0",
|
||||
"@img/sharp-win32-ia32": "0.34.0-rc.0",
|
||||
"@img/sharp-win32-x64": "0.34.0-rc.0"
|
||||
"@img/sharp-darwin-arm64": "0.34.2-rc.0",
|
||||
"@img/sharp-darwin-x64": "0.34.2-rc.0",
|
||||
"@img/sharp-libvips-darwin-arm64": "1.1.0",
|
||||
"@img/sharp-libvips-darwin-x64": "1.1.0",
|
||||
"@img/sharp-libvips-linux-arm": "1.1.0",
|
||||
"@img/sharp-libvips-linux-arm64": "1.1.0",
|
||||
"@img/sharp-libvips-linux-ppc64": "1.1.0",
|
||||
"@img/sharp-libvips-linux-s390x": "1.1.0",
|
||||
"@img/sharp-libvips-linux-x64": "1.1.0",
|
||||
"@img/sharp-libvips-linuxmusl-arm64": "1.1.0",
|
||||
"@img/sharp-libvips-linuxmusl-x64": "1.1.0",
|
||||
"@img/sharp-linux-arm": "0.34.2-rc.0",
|
||||
"@img/sharp-linux-arm64": "0.34.2-rc.0",
|
||||
"@img/sharp-linux-s390x": "0.34.2-rc.0",
|
||||
"@img/sharp-linux-x64": "0.34.2-rc.0",
|
||||
"@img/sharp-linuxmusl-arm64": "0.34.2-rc.0",
|
||||
"@img/sharp-linuxmusl-x64": "0.34.2-rc.0",
|
||||
"@img/sharp-wasm32": "0.34.2-rc.0",
|
||||
"@img/sharp-win32-arm64": "0.34.2-rc.0",
|
||||
"@img/sharp-win32-ia32": "0.34.2-rc.0",
|
||||
"@img/sharp-win32-x64": "0.34.2-rc.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@emnapi/runtime": "^1.3.1",
|
||||
"@img/sharp-libvips-dev": "1.1.0-rc4",
|
||||
"@img/sharp-libvips-dev-wasm32": "1.1.0-rc4",
|
||||
"@img/sharp-libvips-win32-ia32": "1.1.0-rc4",
|
||||
"@img/sharp-libvips-win32-x64": "1.1.0-rc4",
|
||||
"@emnapi/runtime": "^1.4.3",
|
||||
"@img/sharp-libvips-dev": "1.1.0",
|
||||
"@img/sharp-libvips-dev-wasm32": "1.1.0",
|
||||
"@img/sharp-libvips-win32-arm64": "1.1.0",
|
||||
"@img/sharp-libvips-win32-ia32": "1.1.0",
|
||||
"@img/sharp-libvips-win32-x64": "1.1.0",
|
||||
"@types/node": "*",
|
||||
"cc": "^3.0.1",
|
||||
"emnapi": "^1.3.1",
|
||||
"emnapi": "^1.4.3",
|
||||
"exif-reader": "^2.0.2",
|
||||
"extract-zip": "^2.0.1",
|
||||
"icc": "^3.0.0",
|
||||
"jsdoc-to-markdown": "^9.1.1",
|
||||
"license-checker": "^25.0.1",
|
||||
"mocha": "^11.1.0",
|
||||
"mocha": "^11.2.2",
|
||||
"node-addon-api": "^8.3.1",
|
||||
"nyc": "^17.1.0",
|
||||
"prebuild": "^13.0.1",
|
||||
"semistandard": "^17.0.0",
|
||||
"tar-fs": "^3.0.8",
|
||||
"tsd": "^0.31.2"
|
||||
"tsd": "^0.32.0"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
|
||||
@@ -19,7 +19,10 @@
|
||||
'type': 'shared_library',
|
||||
'defines': [
|
||||
'_VIPS_PUBLIC=__declspec(dllexport)',
|
||||
'_ALLOW_KEYWORD_MACROS'
|
||||
'_ALLOW_KEYWORD_MACROS',
|
||||
'G_DISABLE_ASSERT',
|
||||
'G_DISABLE_CAST_CHECKS',
|
||||
'G_DISABLE_CHECKS'
|
||||
],
|
||||
'sources': [
|
||||
'<(sharp_libvips_cplusplus_dir)/VConnection.cpp',
|
||||
@@ -80,6 +83,9 @@
|
||||
}, {
|
||||
'target_name': 'sharp-<(platform_and_arch)',
|
||||
'defines': [
|
||||
'G_DISABLE_ASSERT',
|
||||
'G_DISABLE_CAST_CHECKS',
|
||||
'G_DISABLE_CHECKS',
|
||||
'NAPI_VERSION=9',
|
||||
'NODE_ADDON_API_DISABLE_DEPRECATED',
|
||||
'NODE_API_SWALLOW_UNTHROWABLE_EXCEPTIONS'
|
||||
@@ -179,6 +185,7 @@
|
||||
'-Wl,-s',
|
||||
'-Wl,--disable-new-dtags',
|
||||
'-Wl,-z,nodelete',
|
||||
'-Wl,-Bsymbolic-functions',
|
||||
'-Wl,-rpath=\'$$ORIGIN/../../sharp-libvips-<(platform_and_arch)/lib\'',
|
||||
'-Wl,-rpath=\'$$ORIGIN/../../../sharp-libvips-<(platform_and_arch)/<(sharp_libvips_version)/lib\'',
|
||||
'-Wl,-rpath=\'$$ORIGIN/../../node_modules/@img/sharp-libvips-<(platform_and_arch)/lib\'',
|
||||
|
||||
@@ -651,22 +651,21 @@ namespace sharp {
|
||||
*/
|
||||
VImage SetAnimationProperties(VImage image, int nPages, int pageHeight, std::vector<int> delay, int loop) {
|
||||
bool hasDelay = !delay.empty();
|
||||
|
||||
// Avoid a copy if none of the animation properties are needed.
|
||||
if (nPages == 1 && !hasDelay && loop == -1) return image;
|
||||
|
||||
if (delay.size() == 1) {
|
||||
// We have just one delay, repeat that value for all frames.
|
||||
delay.insert(delay.end(), nPages - 1, delay[0]);
|
||||
}
|
||||
|
||||
// Attaching metadata, need to copy the image.
|
||||
VImage copy = image.copy();
|
||||
|
||||
// Only set page-height if we have more than one page, or this could
|
||||
// accidentally turn into an animated image later.
|
||||
if (nPages > 1) copy.set(VIPS_META_PAGE_HEIGHT, pageHeight);
|
||||
if (hasDelay) copy.set("delay", delay);
|
||||
if (hasDelay) {
|
||||
if (delay.size() == 1) {
|
||||
// We have just one delay, repeat that value for all frames.
|
||||
delay.insert(delay.end(), nPages - 1, delay[0]);
|
||||
}
|
||||
copy.set("delay", delay);
|
||||
}
|
||||
if (nPages == 1 && !hasDelay && loop == -1) {
|
||||
loop = 1;
|
||||
}
|
||||
if (loop != -1) copy.set("loop", loop);
|
||||
|
||||
return copy;
|
||||
@@ -952,14 +951,6 @@ namespace sharp {
|
||||
return interpretation == VIPS_INTERPRETATION_RGB16 || interpretation == VIPS_INTERPRETATION_GREY16;
|
||||
}
|
||||
|
||||
/*
|
||||
Return the image alpha maximum. Useful for combining alpha bands. scRGB
|
||||
images are 0 - 1 for image data, but the alpha is 0 - 255.
|
||||
*/
|
||||
double MaximumImageAlpha(VipsInterpretation const interpretation) {
|
||||
return Is16Bit(interpretation) ? 65535.0 : 255.0;
|
||||
}
|
||||
|
||||
/*
|
||||
Convert RGBA value to another colourspace
|
||||
*/
|
||||
@@ -1002,16 +993,16 @@ namespace sharp {
|
||||
0.0722 * colour[2])
|
||||
};
|
||||
}
|
||||
// Add alpha channel to alphaColour colour
|
||||
// Add alpha channel(s) to alphaColour colour
|
||||
if (colour[3] < 255.0 || image.has_alpha()) {
|
||||
alphaColour.push_back(colour[3] * multiplier);
|
||||
int extraBands = image.bands() > 4 ? image.bands() - 3 : 1;
|
||||
alphaColour.insert(alphaColour.end(), extraBands, colour[3] * multiplier);
|
||||
}
|
||||
// Ensure alphaColour colour uses correct colourspace
|
||||
alphaColour = sharp::GetRgbaAsColourspace(alphaColour, image.interpretation(), premultiply);
|
||||
// Add non-transparent alpha channel, if required
|
||||
if (colour[3] < 255.0 && !image.has_alpha()) {
|
||||
image = image.bandjoin(
|
||||
VImage::new_matrix(image.width(), image.height()).new_from_image(255 * multiplier).cast(image.format()));
|
||||
image = image.bandjoin_const({ 255 * multiplier });
|
||||
}
|
||||
return std::make_tuple(image, alphaColour);
|
||||
}
|
||||
@@ -1031,9 +1022,7 @@ namespace sharp {
|
||||
*/
|
||||
VImage EnsureAlpha(VImage image, double const value) {
|
||||
if (!image.has_alpha()) {
|
||||
std::vector<double> alpha;
|
||||
alpha.push_back(value * sharp::MaximumImageAlpha(image.interpretation()));
|
||||
image = image.bandjoin_const(alpha);
|
||||
image = image.bandjoin_const({ value * vips_interpretation_max_alpha(image.interpretation()) });
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
@@ -357,12 +357,6 @@ namespace sharp {
|
||||
*/
|
||||
bool Is16Bit(VipsInterpretation const interpretation);
|
||||
|
||||
/*
|
||||
Return the image alpha maximum. Useful for combining alpha bands. scRGB
|
||||
images are 0 - 1 for image data, but the alpha is 0 - 255.
|
||||
*/
|
||||
double MaximumImageAlpha(VipsInterpretation const interpretation);
|
||||
|
||||
/*
|
||||
Convert RGBA value to another colourspace
|
||||
*/
|
||||
|
||||
@@ -472,4 +472,26 @@ namespace sharp {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Dilate an image
|
||||
*/
|
||||
VImage Dilate(VImage image, int const width) {
|
||||
int const maskWidth = 2 * width + 1;
|
||||
VImage mask = VImage::new_matrix(maskWidth, maskWidth);
|
||||
return image.morph(
|
||||
mask,
|
||||
VIPS_OPERATION_MORPHOLOGY_DILATE).invert();
|
||||
}
|
||||
|
||||
/*
|
||||
* Erode an image
|
||||
*/
|
||||
VImage Erode(VImage image, int const width) {
|
||||
int const maskWidth = 2 * width + 1;
|
||||
VImage mask = VImage::new_matrix(maskWidth, maskWidth);
|
||||
return image.morph(
|
||||
mask,
|
||||
VIPS_OPERATION_MORPHOLOGY_ERODE).invert();
|
||||
}
|
||||
|
||||
} // namespace sharp
|
||||
|
||||
@@ -120,6 +120,15 @@ namespace sharp {
|
||||
VImage EmbedMultiPage(VImage image, int left, int top, int width, int height,
|
||||
VipsExtend extendWith, std::vector<double> background, int nPages, int *pageHeight);
|
||||
|
||||
/*
|
||||
* Dilate an image
|
||||
*/
|
||||
VImage Dilate(VImage image, int const maskWidth);
|
||||
|
||||
/*
|
||||
* Erode an image
|
||||
*/
|
||||
VImage Erode(VImage image, int const maskWidth);
|
||||
} // namespace sharp
|
||||
|
||||
#endif // SRC_OPERATIONS_H_
|
||||
|
||||
@@ -609,6 +609,16 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
image = sharp::Threshold(image, baton->threshold, baton->thresholdGrayscale);
|
||||
}
|
||||
|
||||
// Dilate - must happen before blurring, due to the utility of dilating after thresholding
|
||||
if (baton->dilateWidth != 0) {
|
||||
image = sharp::Dilate(image, baton->dilateWidth);
|
||||
}
|
||||
|
||||
// Erode - must happen before blurring, due to the utility of eroding after thresholding
|
||||
if (baton->erodeWidth != 0) {
|
||||
image = sharp::Erode(image, baton->erodeWidth);
|
||||
}
|
||||
|
||||
// Blur
|
||||
if (shouldBlur) {
|
||||
image = sharp::Blur(image, baton->blurSigma, baton->precision, baton->minAmpl);
|
||||
@@ -1032,7 +1042,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
(baton->formatOut == "input" && inputImageType == sharp::ImageType::HEIF)) {
|
||||
// Write HEIF to buffer
|
||||
sharp::AssertImageTypeDimensions(image, sharp::ImageType::HEIF);
|
||||
image = sharp::RemoveAnimationProperties(image).cast(VIPS_FORMAT_UCHAR);
|
||||
image = sharp::RemoveAnimationProperties(image);
|
||||
VipsArea *area = reinterpret_cast<VipsArea*>(image.heifsave_buffer(VImage::option()
|
||||
->set("keep", baton->keepMetadata)
|
||||
->set("Q", baton->heifQuality)
|
||||
@@ -1227,7 +1237,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
(willMatchInput && inputImageType == sharp::ImageType::HEIF)) {
|
||||
// Write HEIF to file
|
||||
sharp::AssertImageTypeDimensions(image, sharp::ImageType::HEIF);
|
||||
image = sharp::RemoveAnimationProperties(image).cast(VIPS_FORMAT_UCHAR);
|
||||
image = sharp::RemoveAnimationProperties(image);
|
||||
image.heifsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
|
||||
->set("keep", baton->keepMetadata)
|
||||
->set("Q", baton->heifQuality)
|
||||
@@ -1349,7 +1359,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
// Add file size to info
|
||||
if (baton->formatOut != "dz" || sharp::IsDzZip(baton->fileOut)) {
|
||||
try {
|
||||
uint32_t const size = static_cast<uint32_t>(std::filesystem::file_size(baton->fileOut));
|
||||
uint32_t const size = static_cast<uint32_t>(
|
||||
std::filesystem::file_size(std::filesystem::u8path(baton->fileOut)));
|
||||
info.Set("size", size);
|
||||
} catch (...) {}
|
||||
}
|
||||
@@ -1621,6 +1632,8 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
||||
baton->gammaOut = sharp::AttrAsDouble(options, "gammaOut");
|
||||
baton->linearA = sharp::AttrAsVectorOfDouble(options, "linearA");
|
||||
baton->linearB = sharp::AttrAsVectorOfDouble(options, "linearB");
|
||||
baton->dilateWidth = sharp::AttrAsUint32(options, "dilateWidth");
|
||||
baton->erodeWidth = sharp::AttrAsUint32(options, "erodeWidth");
|
||||
baton->greyscale = sharp::AttrAsBool(options, "greyscale");
|
||||
baton->normalise = sharp::AttrAsBool(options, "normalise");
|
||||
baton->normaliseLower = sharp::AttrAsUint32(options, "normaliseLower");
|
||||
@@ -1705,6 +1718,8 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
||||
}
|
||||
baton->withExifMerge = sharp::AttrAsBool(options, "withExifMerge");
|
||||
baton->timeoutSeconds = sharp::AttrAsUint32(options, "timeoutSeconds");
|
||||
baton->loop = sharp::AttrAsUint32(options, "loop");
|
||||
baton->delay = sharp::AttrAsInt32Vector(options, "delay");
|
||||
// Format-specific
|
||||
baton->jpegQuality = sharp::AttrAsUint32(options, "jpegQuality");
|
||||
baton->jpegProgressive = sharp::AttrAsBool(options, "jpegProgressive");
|
||||
@@ -1774,13 +1789,6 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
||||
baton->jxlEffort = sharp::AttrAsUint32(options, "jxlEffort");
|
||||
baton->jxlLossless = sharp::AttrAsBool(options, "jxlLossless");
|
||||
baton->rawDepth = sharp::AttrAsEnum<VipsBandFormat>(options, "rawDepth", VIPS_TYPE_BAND_FORMAT);
|
||||
// Animated output properties
|
||||
if (sharp::HasAttr(options, "loop")) {
|
||||
baton->loop = sharp::AttrAsUint32(options, "loop");
|
||||
}
|
||||
if (sharp::HasAttr(options, "delay")) {
|
||||
baton->delay = sharp::AttrAsInt32Vector(options, "delay");
|
||||
}
|
||||
baton->tileSize = sharp::AttrAsUint32(options, "tileSize");
|
||||
baton->tileOverlap = sharp::AttrAsUint32(options, "tileOverlap");
|
||||
baton->tileAngle = sharp::AttrAsInt32(options, "tileAngle");
|
||||
|
||||
@@ -101,6 +101,8 @@ struct PipelineBaton {
|
||||
int trimOffsetTop;
|
||||
std::vector<double> linearA;
|
||||
std::vector<double> linearB;
|
||||
int dilateWidth;
|
||||
int erodeWidth;
|
||||
double gamma;
|
||||
double gammaOut;
|
||||
bool greyscale;
|
||||
@@ -274,6 +276,8 @@ struct PipelineBaton {
|
||||
trimOffsetTop(0),
|
||||
linearA{},
|
||||
linearB{},
|
||||
dilateWidth(0),
|
||||
erodeWidth(0),
|
||||
gamma(0.0),
|
||||
greyscale(false),
|
||||
normalise(false),
|
||||
|
||||
@@ -33,6 +33,7 @@ Napi::Object init(Napi::Env env, Napi::Object exports) {
|
||||
exports.Set("block", Napi::Function::New(env, block));
|
||||
exports.Set("_maxColourDistance", Napi::Function::New(env, _maxColourDistance));
|
||||
exports.Set("_isUsingJemalloc", Napi::Function::New(env, _isUsingJemalloc));
|
||||
exports.Set("_isUsingX64V2", Napi::Function::New(env, _isUsingX64V2));
|
||||
exports.Set("stats", Napi::Function::New(env, stats));
|
||||
return exports;
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ class StatsWorker : public Napi::AsyncWorker {
|
||||
// Image is not opaque when alpha layer is present and contains a non-mamixa value
|
||||
if (image.has_alpha()) {
|
||||
double const minAlpha = static_cast<double>(stats.getpoint(STAT_MIN_INDEX, bands).front());
|
||||
if (minAlpha != sharp::MaximumImageAlpha(image.interpretation())) {
|
||||
if (minAlpha != vips_interpretation_max_alpha(image.interpretation())) {
|
||||
baton->isOpaque = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,3 +267,20 @@ Napi::Value _isUsingJemalloc(const Napi::CallbackInfo& info) {
|
||||
return Napi::Boolean::New(env, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && defined(__x86_64__)
|
||||
// Are SSE 4.2 intrinsics available at runtime?
|
||||
Napi::Value _isUsingX64V2(const Napi::CallbackInfo& info) {
|
||||
Napi::Env env = info.Env();
|
||||
unsigned int eax, ebx, ecx, edx;
|
||||
__asm__ __volatile__("cpuid"
|
||||
: "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
|
||||
: "a"(1));
|
||||
return Napi::Boolean::New(env, (ecx & 1U << 20) != 0);
|
||||
}
|
||||
#else
|
||||
Napi::Value _isUsingX64V2(const Napi::CallbackInfo& info) {
|
||||
Napi::Env env = info.Env();
|
||||
return Napi::Boolean::New(env, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -15,5 +15,6 @@ Napi::Value format(const Napi::CallbackInfo& info);
|
||||
void block(const Napi::CallbackInfo& info);
|
||||
Napi::Value _maxColourDistance(const Napi::CallbackInfo& info);
|
||||
Napi::Value _isUsingJemalloc(const Napi::CallbackInfo& info);
|
||||
Napi::Value _isUsingX64V2(const Napi::CallbackInfo& info);
|
||||
|
||||
#endif // SRC_UTILITIES_H_
|
||||
|
||||
BIN
test/fixtures/dot-and-lines.png
vendored
Normal file
BIN
test/fixtures/dot-and-lines.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 463 B |
BIN
test/fixtures/expected/dilate-1.png
vendored
Normal file
BIN
test/fixtures/expected/dilate-1.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 540 B |
BIN
test/fixtures/expected/erode-1.png
vendored
Normal file
BIN
test/fixtures/expected/erode-1.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 450 B |
2
test/fixtures/index.js
vendored
2
test/fixtures/index.js
vendored
@@ -128,6 +128,8 @@ module.exports = {
|
||||
|
||||
inputJPGBig: getPath('flowers.jpeg'),
|
||||
|
||||
inputPngDotAndLines: getPath('dot-and-lines.png'),
|
||||
|
||||
inputPngStripesV: getPath('stripesV.png'),
|
||||
inputPngStripesH: getPath('stripesH.png'),
|
||||
|
||||
|
||||
@@ -740,3 +740,8 @@ sharp([input, input], {
|
||||
valign: 'bottom'
|
||||
}
|
||||
});
|
||||
|
||||
sharp().erode();
|
||||
sharp().erode(1);
|
||||
sharp().dilate();
|
||||
sharp().dilate(1);
|
||||
|
||||
38
test/unit/dilate.js
Normal file
38
test/unit/dilate.js
Normal file
@@ -0,0 +1,38 @@
|
||||
'use strict';
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
const sharp = require('../../');
|
||||
const fixtures = require('../fixtures');
|
||||
|
||||
describe('Dilate', function () {
|
||||
it('dilate 1 png', function (done) {
|
||||
sharp(fixtures.inputPngDotAndLines)
|
||||
.dilate(1)
|
||||
.toBuffer(function (err, data, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual('png', info.format);
|
||||
assert.strictEqual(100, info.width);
|
||||
assert.strictEqual(100, info.height);
|
||||
fixtures.assertSimilar(fixtures.expected('dilate-1.png'), data, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('dilate 1 png - default width', function (done) {
|
||||
sharp(fixtures.inputPngDotAndLines)
|
||||
.dilate()
|
||||
.toBuffer(function (err, data, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual('png', info.format);
|
||||
assert.strictEqual(100, info.width);
|
||||
assert.strictEqual(100, info.height);
|
||||
fixtures.assertSimilar(fixtures.expected('dilate-1.png'), data, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('invalid dilation width', function () {
|
||||
assert.throws(function () {
|
||||
sharp(fixtures.inputJpg).dilate(-1);
|
||||
});
|
||||
});
|
||||
});
|
||||
38
test/unit/erode.js
Normal file
38
test/unit/erode.js
Normal file
@@ -0,0 +1,38 @@
|
||||
'use strict';
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
const sharp = require('../../');
|
||||
const fixtures = require('../fixtures');
|
||||
|
||||
describe('Erode', function () {
|
||||
it('erode 1 png', function (done) {
|
||||
sharp(fixtures.inputPngDotAndLines)
|
||||
.erode(1)
|
||||
.toBuffer(function (err, data, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual('png', info.format);
|
||||
assert.strictEqual(100, info.width);
|
||||
assert.strictEqual(100, info.height);
|
||||
fixtures.assertSimilar(fixtures.expected('erode-1.png'), data, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('erode 1 png - default width', function (done) {
|
||||
sharp(fixtures.inputPngDotAndLines)
|
||||
.erode()
|
||||
.toBuffer(function (err, data, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual('png', info.format);
|
||||
assert.strictEqual(100, info.width);
|
||||
assert.strictEqual(100, info.height);
|
||||
fixtures.assertSimilar(fixtures.expected('erode-1.png'), data, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('invalid erosion width', function () {
|
||||
assert.throws(function () {
|
||||
sharp(fixtures.inputJpg).erode(-1);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -224,4 +224,29 @@ describe('GIF input', () => {
|
||||
const after = await input.gif({ interPaletteMaxError: 100 }).toBuffer();
|
||||
assert.strict(before.length > after.length);
|
||||
});
|
||||
|
||||
it('non-animated input defaults to no-loop', async () => {
|
||||
for (const input of [fixtures.inputGif, fixtures.inputPng]) {
|
||||
const data = await sharp(input)
|
||||
.resize(8)
|
||||
.gif({ effort: 1 })
|
||||
.toBuffer();
|
||||
|
||||
const { format, pages, loop } = await sharp(data).metadata();
|
||||
assert.strictEqual('gif', format);
|
||||
assert.strictEqual(1, pages);
|
||||
assert.strictEqual(1, loop);
|
||||
}
|
||||
});
|
||||
|
||||
it('Animated GIF to animated WebP merges identical frames', async () => {
|
||||
const webp = await sharp(fixtures.inputGifAnimated, { animated: true })
|
||||
.webp()
|
||||
.toBuffer();
|
||||
|
||||
const { delay, loop, pages } = await sharp(webp).metadata();
|
||||
assert.deepStrictEqual([120, 120, 90, 120, 120, 90, 120, 90, 30], delay);
|
||||
assert.strictEqual(0, loop);
|
||||
assert.strictEqual(9, pages);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1036,4 +1036,21 @@ describe('Input/output', function () {
|
||||
});
|
||||
readable.pipe(inPipeline).pipe(badPipeline);
|
||||
});
|
||||
|
||||
it('supports wide-character filenames', async () => {
|
||||
const filename = fixtures.path('output.图片.jpg');
|
||||
const create = {
|
||||
width: 8,
|
||||
height: 8,
|
||||
channels: 3,
|
||||
background: 'green'
|
||||
};
|
||||
await sharp({ create }).toFile(filename);
|
||||
|
||||
const { width, height, channels, format } = await sharp(filename).metadata();
|
||||
assert.strictEqual(width, 8);
|
||||
assert.strictEqual(height, 8);
|
||||
assert.strictEqual(channels, 3);
|
||||
assert.strictEqual(format, 'jpeg');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -806,4 +806,33 @@ describe('Resize fit=contain', function () {
|
||||
fixtures.assertSimilar(fixtures.expected('./embedgravitybird/9-c.png'), data, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('multiple alpha channels', async () => {
|
||||
const create = {
|
||||
width: 20,
|
||||
height: 12,
|
||||
channels: 4,
|
||||
background: 'green'
|
||||
};
|
||||
const multipleAlphaChannels = await sharp({ create })
|
||||
.joinChannel({ create })
|
||||
.tiff({ compression: 'deflate' })
|
||||
.toBuffer();
|
||||
|
||||
const data = await sharp(multipleAlphaChannels)
|
||||
.resize({
|
||||
width: 8,
|
||||
height: 8,
|
||||
fit: 'contain',
|
||||
background: 'blue'
|
||||
})
|
||||
.tiff({ compression: 'deflate' })
|
||||
.toBuffer();
|
||||
const { format, width, height, space, channels } = await sharp(data).metadata();
|
||||
assert.deepStrictEqual(format, 'tiff');
|
||||
assert.deepStrictEqual(width, 8);
|
||||
assert.deepStrictEqual(height, 8);
|
||||
assert.deepStrictEqual(space, 'srgb');
|
||||
assert.deepStrictEqual(channels, 8);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -59,7 +59,7 @@ describe('Text to image', function () {
|
||||
assert.strictEqual('png', info.format);
|
||||
assert.strictEqual(3, info.channels);
|
||||
assert.ok(inRange(info.width, 400, 600), `Actual width ${info.width}`);
|
||||
assert.ok(inRange(info.height, 300, 500), `Actual height ${info.height}`);
|
||||
assert.ok(inRange(info.height, 290, 500), `Actual height ${info.height}`);
|
||||
assert.ok(inRange(info.textAutofitDpi, 900, 1300), `Actual textAutofitDpi ${info.textAutofitDpi}`);
|
||||
done();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user