Compare commits

..

28 Commits

Author SHA1 Message Date
Lovell Fuller
eefaa99872 Release v0.32.6 2023-09-18 20:33:39 +01:00
Lovell Fuller
dbce6fab79 Upgrade to libvips v8.14.5 2023-09-18 20:09:54 +01:00
Lovell Fuller
af0fcb37c2 Docs: changelog for #3799 2023-09-18 14:56:03 +01:00
Lovell Fuller
c6f54e59da Bump devDeps 2023-09-18 14:53:44 +01:00
ldrick
846563e45f TypeScript: add definitions for block and unblock (#3799) 2023-09-18 10:42:13 +01:00
Lovell Fuller
9c217ab580 Ensure withMetadata can add RGB16 profiles #3773 2023-08-31 12:49:50 +01:00
Lovell Fuller
e7381e522e Alternative fix for 4340d60, uses existing StaySequential 2023-08-31 12:09:11 +01:00
Lovell Fuller
4340d60ccf Ensure composite tile images fully decoded #3767 2023-08-31 09:04:51 +01:00
Lovell Fuller
7f64d464de Docs: add missing returns property to raw 2023-08-29 11:17:35 +01:00
Lovell Fuller
67e927bdb6 Docs: ensure all functions include method signature #3777 2023-08-29 11:16:18 +01:00
Lovell Fuller
9c7713ed54 Docs: remove mention of EXIF from flip/flop ops 2023-08-29 10:49:21 +01:00
Lovell Fuller
8be6da1def Docs: clarify when rotate op will remove EXIF Orientation 2023-08-29 10:19:07 +01:00
Lovell Fuller
95635683ac Ensure withMetadata skips default profile for RGB16 #3773 2023-08-24 18:13:00 +01:00
Lovell Fuller
44a0ee3fd3 Release v0.32.5 2023-08-15 19:29:42 +01:00
Lovell Fuller
ccd51c8cbf Upgrade to libvips v8.14.4 2023-08-15 16:40:22 +01:00
Lovell Fuller
bb7469b2d1 Ensure withMetadata adds default sRGB profile #3761 2023-08-15 13:02:20 +01:00
Kleis Auke Wolthuizen
a2cac61209 Simplify 90/270 orient-before-resize logic (#3762) 2023-08-15 07:56:07 +01:00
Lovell Fuller
5c19f6dd9b Ensure resize fit=inside respects 90/270 rotate #3756 2023-08-14 13:45:23 +01:00
Lovell Fuller
3d01775972 Docs: changelog entries for #3748 #3755 #3758 2023-08-14 13:33:13 +01:00
sho-xizz
87562a5111 TypeScript: Ensure WebpOptions minSize is boolean (#3758) 2023-08-09 13:45:10 +01:00
Kleis Auke Wolthuizen
2829e17743 Fix build with musl 1.2.4 (#3755) 2023-08-07 21:57:00 +01:00
pilotso11
ffefbd2ecc TypeScript: add missing WebpPresetEnum (#3748) 2023-08-04 10:51:06 +01:00
Kleis Auke Wolthuizen
bc8f983329 Tests: ensure Jimp benchmark uses bicubic as resizing kernel (#3745) 2023-07-30 11:25:45 +01:00
Kleis Auke Wolthuizen
440936a699 Tests: update benchmark deps and container (#3744)
Use Node 18.x in benchmark container
2023-07-30 11:24:27 +01:00
Lovell Fuller
0bc79cdb95 Docs: include paletteBitDepth metadata 2023-07-28 16:04:02 +01:00
Lovell Fuller
9a66e25f53 Docs: ensure resize fit image supports dark mode 2023-07-25 10:06:44 +01:00
Lovell Fuller
8370935ccf Docs: ensure 'fit' values are clearly separated
Smaller text, slightly closer to image, varied fill colour
2023-07-21 23:07:57 +01:00
Kleis Auke Wolthuizen
f908987f35 Docs: use SVG image for the resize fit property example (#3735) 2023-07-21 21:58:02 +01:00
31 changed files with 489 additions and 76 deletions

View File

@@ -1,4 +1,6 @@
## removeAlpha
> removeAlpha() ⇒ <code>Sharp</code>
Remove alpha channel, if any. This is a no-op if the image does not have an alpha channel.
See also [flatten](/api-operation#flatten).
@@ -15,6 +17,8 @@ sharp('rgba.png')
## ensureAlpha
> ensureAlpha([alpha]) ⇒ <code>Sharp</code>
Ensure the output image has an alpha transparency channel.
If missing, the added alpha channel will have the specified
transparency level, defaulting to fully-opaque (1).
@@ -48,6 +52,8 @@ const rgba = await sharp(rgb)
## extractChannel
> extractChannel(channel) ⇒ <code>Sharp</code>
Extract a single channel from a multi-channel image.
@@ -78,6 +84,8 @@ const [red1, red2, ...] = await sharp(input)
## joinChannel
> joinChannel(images, options) ⇒ <code>Sharp</code>
Join one or more channels to the image.
The meaning of the added channels depends on the output colourspace, set with `toColourspace()`.
By default the output image will be web-friendly sRGB, with additional channels interpreted as alpha channels.
@@ -102,6 +110,8 @@ For raw pixel input, the `options` object should contain a `raw` attribute, whic
## bandbool
> bandbool(boolOp) ⇒ <code>Sharp</code>
Perform a bitwise boolean operation on all input image channels (bands) to produce a single channel output image.

View File

@@ -1,4 +1,6 @@
## tint
> tint(rgb) ⇒ <code>Sharp</code>
Tint the image using the provided chroma while preserving the image luminance.
An alpha channel may be present and will be unchanged by the operation.
@@ -21,6 +23,8 @@ const output = await sharp(input)
## greyscale
> greyscale([greyscale]) ⇒ <code>Sharp</code>
Convert to 8-bit greyscale; 256 shades of grey.
This is a linear operation. If the input image is in a non-linear colour space such as sRGB, use `gamma()` with `greyscale()` for the best results.
By default the output image will be web-friendly sRGB and contain three (identical) color channels.
@@ -41,6 +45,8 @@ const output = await sharp(input).greyscale().toBuffer();
## grayscale
> grayscale([grayscale]) ⇒ <code>Sharp</code>
Alternative spelling of `greyscale`.
@@ -52,6 +58,8 @@ Alternative spelling of `greyscale`.
## pipelineColourspace
> pipelineColourspace([colourspace]) ⇒ <code>Sharp</code>
Set the pipeline colourspace.
The input image will be converted to the provided colourspace at the start of the pipeline.
@@ -82,6 +90,8 @@ await sharp(input)
## pipelineColorspace
> pipelineColorspace([colorspace]) ⇒ <code>Sharp</code>
Alternative spelling of `pipelineColourspace`.
@@ -97,6 +107,8 @@ Alternative spelling of `pipelineColourspace`.
## toColourspace
> toColourspace([colourspace]) ⇒ <code>Sharp</code>
Set the output colourspace.
By default output image will be web-friendly sRGB, with additional channels interpreted as alpha channels.
@@ -120,6 +132,8 @@ await sharp(input)
## toColorspace
> toColorspace([colorspace]) ⇒ <code>Sharp</code>
Alternative spelling of `toColourspace`.

View File

@@ -1,4 +1,6 @@
## composite
> composite(images) ⇒ <code>Sharp</code>
Composite image(s) over the processed (resized, extracted etc.) image.
The images to composite must be the same size or smaller than the processed image.

View File

@@ -1,9 +1,13 @@
## Sharp
> Sharp
**Emits**: <code>Sharp#event:info</code>, <code>Sharp#event:warning</code>
<a name="new_Sharp_new"></a>
### new
> new Sharp([input], [options])
Constructor factory to create an instance of `sharp`, to which further methods are chained.
JPEG, PNG, WebP, GIF, AVIF or TIFF format image data can be streamed out from this object.
@@ -159,6 +163,8 @@ await sharp({
## clone
> clone() ⇒ [<code>Sharp</code>](#Sharp)
Take a "snapshot" of the Sharp instance, returning a new instance.
Cloned instances inherit the input of their parent instance.
This allows multiple output Streams and therefore multiple processing pipelines to share a single input Stream.

View File

@@ -1,4 +1,6 @@
## metadata
> metadata([callback]) ⇒ <code>Promise.&lt;Object&gt;</code> \| <code>Sharp</code>
Fast access to (uncached) image metadata without decoding any compressed pixel data.
This is read from the header of the input image.
@@ -22,6 +24,7 @@ A `Promise` is returned when `callback` is not provided.
- `isProgressive`: Boolean indicating whether the image is interlaced using a progressive scan
- `pages`: Number of pages/frames contained within the image, with support for TIFF, HEIF, PDF, animated GIF and animated WebP
- `pageHeight`: Number of pixels high each page in a multi-page image will be.
- `paletteBitDepth`: Bit depth of palette-based image (GIF, PNG).
- `loop`: Number of times to loop an animated image, zero refers to a continuous loop.
- `delay`: Delay in ms between each page in an animated image, provided as an array of integers.
- `pagePrimary`: Number of the primary page in a HEIF image
@@ -80,6 +83,8 @@ function getNormalSize({ width, height, orientation }) {
## stats
> stats([callback]) ⇒ <code>Promise.&lt;Object&gt;</code>
Access to pixel-derived image statistics for every channel in the image.
A `Promise` is returned when `callback` is not provided.

View File

@@ -1,4 +1,6 @@
## rotate
> rotate([angle], [options]) ⇒ <code>Sharp</code>
Rotate the output image by either an explicit angle
or auto-orient based on the EXIF `Orientation` tag.
@@ -11,7 +13,7 @@ the background colour can be provided with the `background` option.
If no angle is provided, it is determined from the EXIF data.
Mirroring is supported and may infer the use of a flip operation.
The use of `rotate` implies the removal of the EXIF `Orientation` tag, if any.
The use of `rotate` without an angle will remove the EXIF `Orientation` tag, if any.
Only one rotation can occur per pipeline.
Previous calls to `rotate` in the same pipeline will be ignored.
@@ -57,11 +59,11 @@ const resizeThenRotate = await sharp(input)
## flip
> flip([flip]) ⇒ <code>Sharp</code>
Mirror the image vertically (up-down) about the x-axis.
This always occurs before rotation, if any.
The use of `flip` implies the removal of the EXIF `Orientation` tag, if any.
This operation does not work correctly with multi-page images.
@@ -77,11 +79,11 @@ const output = await sharp(input).flip().toBuffer();
## flop
> flop([flop]) ⇒ <code>Sharp</code>
Mirror the image horizontally (left-right) about the y-axis.
This always occurs before rotation, if any.
The use of `flop` implies the removal of the EXIF `Orientation` tag, if any.
| Param | Type | Default |
@@ -95,6 +97,8 @@ const output = await sharp(input).flop().toBuffer();
## affine
> affine(matrix, [options]) ⇒ <code>Sharp</code>
Perform an affine transform on an image. This operation will always occur after resizing, extraction and rotation, if any.
You must provide an array of length 4 or a 2x2 affine transformation matrix.
@@ -146,6 +150,8 @@ inputStream
## sharpen
> sharpen([options], [flat], [jagged]) ⇒ <code>Sharp</code>
Sharpen the image.
When used without parameters, performs a fast, mild sharpen of the output image.
@@ -197,6 +203,8 @@ const data = await sharp(input)
## median
> median([size]) ⇒ <code>Sharp</code>
Apply median filter.
When used without parameters the default window is 3x3.
@@ -221,6 +229,8 @@ const output = await sharp(input).median(5).toBuffer();
## blur
> blur([sigma]) ⇒ <code>Sharp</code>
Blur the image.
When used without parameters, performs a fast 3x3 box blur (equivalent to a box linear filter).
@@ -252,6 +262,8 @@ const gaussianBlurred = await sharp(input)
## flatten
> flatten([options]) ⇒ <code>Sharp</code>
Merge alpha transparency channel, if any, with a background, then remove the alpha channel.
See also [removeAlpha](/api-channel#removealpha).
@@ -272,6 +284,8 @@ await sharp(rgbaInput)
## unflatten
> unflatten()
Ensure the image has an alpha channel
with all white pixel values made fully transparent.
@@ -297,6 +311,8 @@ await sharp(rgbInput)
## gamma
> gamma([gamma], [gammaOut]) ⇒ <code>Sharp</code>
Apply a gamma correction by reducing the encoding (darken) pre-resize at a factor of `1/gamma`
then increasing the encoding (brighten) post-resize at a factor of `gamma`.
This can improve the perceived brightness of a resized image in non-linear colour spaces.
@@ -319,6 +335,8 @@ Supply a second argument to use a different output gamma value, otherwise the fi
## negate
> negate([options]) ⇒ <code>Sharp</code>
Produce the "negative" of the image.
@@ -343,6 +361,8 @@ const output = await sharp(input)
## normalise
> normalise([options]) ⇒ <code>Sharp</code>
Enhance output image contrast by stretching its luminance to cover a full dynamic range.
Uses a histogram-based approach, taking a default range of 1% to 99% to reduce sensitivity to noise at the extremes.
@@ -373,6 +393,8 @@ const output = await sharp(input)
## normalize
> normalize([options]) ⇒ <code>Sharp</code>
Alternative spelling of normalise.
@@ -392,6 +414,8 @@ const output = await sharp(input)
## clahe
> clahe(options) ⇒ <code>Sharp</code>
Perform contrast limiting adaptive histogram equalization
[CLAHE](https://en.wikipedia.org/wiki/Adaptive_histogram_equalization#Contrast_Limited_AHE).
@@ -423,6 +447,8 @@ const output = await sharp(input)
## convolve
> convolve(kernel) ⇒ <code>Sharp</code>
Convolve the image with the specified kernel.
@@ -457,6 +483,8 @@ sharp(input)
## threshold
> threshold([threshold], [options]) ⇒ <code>Sharp</code>
Any pixel value greater than or equal to the threshold value will be set to 255, otherwise it will be set to 0.
@@ -475,6 +503,8 @@ Any pixel value greater than or equal to the threshold value will be set to 255,
## boolean
> boolean(operand, operator, [options]) ⇒ <code>Sharp</code>
Perform a bitwise boolean operation with operand image.
This operation creates an output image where each pixel is the result of
@@ -499,6 +529,8 @@ the selected bitwise boolean `operation` between the corresponding pixels of the
## linear
> linear([a], [b]) ⇒ <code>Sharp</code>
Apply the linear formula `a` * input + `b` to the image to adjust image levels.
When a single number is provided, it will be used for all image channels.
@@ -533,6 +565,8 @@ await sharp(rgbInput)
## recomb
> recomb(inputMatrix) ⇒ <code>Sharp</code>
Recombine the image with the specified matrix.
@@ -563,6 +597,8 @@ sharp(input)
## modulate
> modulate([options]) ⇒ <code>Sharp</code>
Transforms the image using brightness, saturation, hue rotation, and lightness.
Brightness and lightness both operate on luminance, with the difference being that
brightness is multiplicative whereas lightness is additive.

View File

@@ -1,4 +1,6 @@
## toFile
> toFile(fileOut, [callback]) ⇒ <code>Promise.&lt;Object&gt;</code>
Write output image data to a file.
If an explicit output format is not selected, it will be inferred from the extension,
@@ -39,6 +41,8 @@ sharp(input)
## toBuffer
> toBuffer([options], [callback]) ⇒ <code>Promise.&lt;Buffer&gt;</code>
Write output to a Buffer.
JPEG, PNG, WebP, AVIF, TIFF, GIF and raw pixel data output are supported.
@@ -108,9 +112,11 @@ await sharp(pixelArray, { raw: { width, height, channels } })
## withMetadata
> withMetadata([options]) ⇒ <code>Sharp</code>
Include all metadata (EXIF, XMP, IPTC) from the input image in the output image.
This will also convert to and add a web-friendly sRGB ICC profile unless a custom
output profile is provided.
This will also convert to and add a web-friendly sRGB ICC profile if appropriate,
unless a custom output profile is provided.
The default behaviour, when `withMetadata` is not used, is to convert to the device-independent
sRGB colour space and strip all metadata, including the removal of any ICC profile.
@@ -167,6 +173,8 @@ const data = await sharp(input)
## toFormat
> toFormat(format, options) ⇒ <code>Sharp</code>
Force output to a given format.
@@ -190,6 +198,8 @@ const data = await sharp(input)
## jpeg
> jpeg([options]) ⇒ <code>Sharp</code>
Use these JPEG options for output image.
@@ -235,6 +245,8 @@ const data = await sharp(input)
## png
> png([options]) ⇒ <code>Sharp</code>
Use these PNG options for output image.
By default, PNG output is full colour at 8 or 16 bits per pixel.
@@ -278,6 +290,8 @@ const data = await sharp(input)
## webp
> webp([options]) ⇒ <code>Sharp</code>
Use these WebP options for output image.
@@ -319,6 +333,8 @@ const outputWebp = await sharp(inputWebp, { animated: true })
## gif
> gif([options]) ⇒ <code>Sharp</code>
Use these GIF options for the output image.
The first entry in the palette is reserved for transparency.
@@ -378,6 +394,8 @@ await sharp('in.gif', { animated: true })
## jp2
> jp2([options]) ⇒ <code>Sharp</code>
Use these JP2 options for output image.
Requires libvips compiled with support for OpenJPEG.
@@ -420,6 +438,8 @@ const data = await sharp(input)
## tiff
> tiff([options]) ⇒ <code>Sharp</code>
Use these TIFF options for output image.
The `density` can be set in pixels/inch via [withMetadata](#withmetadata)
@@ -461,6 +481,8 @@ sharp('input.svg')
## avif
> avif([options]) ⇒ <code>Sharp</code>
Use these AVIF options for output image.
Whilst it is possible to create AVIF images smaller than 16x16 pixels,
@@ -498,6 +520,8 @@ const data = await sharp(input)
## heif
> heif([options]) ⇒ <code>Sharp</code>
Use these HEIF options for output image.
Support for patent-encumbered HEIC images using `hevc` compression requires the use of a
@@ -528,6 +552,8 @@ const data = await sharp(input)
## jxl
> jxl([options]) ⇒ <code>Sharp</code>
Use these JPEG-XL (JXL) options for output image.
This feature is experimental, please do not use in production systems.
@@ -557,6 +583,8 @@ Image metadata (EXIF, XMP) is unsupported.
## raw
> raw([options]) ⇒ <code>Sharp</code>
Force output to be raw, uncompressed pixel data.
Pixel ordering is left-to-right, top-to-bottom, without padding.
Channel ordering will be RGB or RGBA for non-greyscale colourspaces.
@@ -592,6 +620,8 @@ const data = await sharp('input.png')
## tile
> tile([options]) ⇒ <code>Sharp</code>
Use tile-based deep zoom (image pyramid) output.
Set the format and options for tile images via the `toFormat`, `jpeg`, `png` or `webp` functions.
@@ -653,6 +683,8 @@ readableStream
## timeout
> timeout(options) ⇒ <code>Sharp</code>
Set a timeout for processing, in seconds.
Use a value of zero to continue processing indefinitely, the default behaviour.

View File

@@ -1,4 +1,6 @@
## resize
> resize([width], [height], [options]) ⇒ <code>Sharp</code>
Resize image to `width`, `height` or `width x height`.
When both a `width` and `height` are provided, the possible methods by which the image should **fit** these are:
@@ -10,7 +12,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.png">
<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">
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`.
@@ -146,6 +148,8 @@ const scaleByHalf = await sharp(input)
## extend
> extend(extend) ⇒ <code>Sharp</code>
Extend / pad / extrude one or more edges of the image with either
the provided background colour or pixels derived from the image.
This operation will always occur after resizing and extraction, if any.
@@ -204,6 +208,8 @@ sharp(input)
## extract
> extract(options) ⇒ <code>Sharp</code>
Extract/crop a region of the image.
- Use `extract` before `resize` for pre-resize extraction.
@@ -245,6 +251,8 @@ sharp(input)
## trim
> trim(trim) ⇒ <code>Sharp</code>
Trim pixels from all edges that contain values similar to the given background colour, which defaults to that of the top-left pixel.
Images with an alpha channel will use the combined bounding box of alpha and non-alpha channels.

View File

@@ -1,4 +1,6 @@
## versions
> versions
An Object containing the version numbers of sharp, libvips and its dependencies.
@@ -9,6 +11,8 @@ console.log(sharp.versions);
## interpolators
> interpolators : <code>enum</code>
An Object containing the available interpolators and their proper values
@@ -27,6 +31,8 @@ An Object containing the available interpolators and their proper values
## format
> format ⇒ <code>Object</code>
An Object containing nested boolean values representing the available input and output formats/methods.
@@ -37,6 +43,8 @@ console.log(sharp.format);
## vendor
> vendor
An Object containing the platform and architecture
of the current and installed vendored binaries.
@@ -48,6 +56,8 @@ console.log(sharp.vendor);
## queue
> queue
An EventEmitter that emits a `change` event when a task is either:
- queued, waiting for _libuv_ to provide a worker thread
- complete
@@ -62,6 +72,8 @@ sharp.queue.on('change', function(queueLength) {
## cache
> cache([options]) ⇒ <code>Object</code>
Gets or, when options are provided, sets the limits of _libvips'_ operation cache.
Existing entries in the cache will be trimmed after any change in limits.
This method always returns cache statistics,
@@ -89,6 +101,8 @@ sharp.cache(false);
## concurrency
> concurrency([concurrency]) ⇒ <code>number</code>
Gets or, when a concurrency is provided, sets
the maximum number of threads _libvips_ should use to process _each image_.
These are from a thread pool managed by glib,
@@ -132,6 +146,8 @@ sharp.concurrency(0); // 4
## counters
> counters() ⇒ <code>Object</code>
Provides access to internal task counters.
- queue is the number of tasks this module has queued waiting for _libuv_ to provide a worker thread from its pool.
- process is the number of resize tasks currently being processed.
@@ -144,6 +160,8 @@ const counters = sharp.counters(); // { queue: 2, process: 4 }
## simd
> simd([simd]) ⇒ <code>boolean</code>
Get and set use of SIMD vector unit instructions.
Requires libvips to have been compiled with liborc support.
@@ -169,6 +187,8 @@ const simd = sharp.simd(false);
## block
> block(options)
Block libvips operations at runtime.
This is in addition to the `VIPS_BLOCK_UNTRUSTED` environment variable,
@@ -191,6 +211,8 @@ sharp.block({
## unblock
> unblock(options)
Unblock libvips operations at runtime.
This is useful for defining a list of allowed operations.

View File

@@ -29,7 +29,7 @@ const jsdoc2md = require('jsdoc-to-markdown');
});
const cleanMarkdown = markdown
.replace(/(## [A-Za-z0-9]+)[^\n]*/g, '$1') // simplify headings to match those of documentationjs, ensures existing URLs work
.replace(/(## )([A-Za-z0-9]+)([^\n]*)/g, '$1$2\n> $2$3\n') // simplify headings to match those of documentationjs, ensures existing URLs work
.replace(/<a name="[A-Za-z0-9+]+"><\/a>/g, '') // remove anchors, let docute add these (at markdown to HTML render time)
.replace(/\*\*Kind\*\*: global[^\n]+/g, '') // remove all "global" Kind labels (requires JSDoc refactoring)
.trim();

View File

@@ -2,7 +2,46 @@
## v0.32 - *flow*
Requires libvips v8.14.3
Requires libvips v8.14.5
### v0.32.6 - 18th September 2023
* Upgrade to libvips v8.14.5 for upstream bug fixes.
* Ensure composite tile images are fully decoded (regression in 0.32.0).
[#3767](https://github.com/lovell/sharp/issues/3767)
* Ensure `withMetadata` can add ICC profiles to RGB16 output.
[#3773](https://github.com/lovell/sharp/issues/3773)
* Ensure `withMetadata` does not reduce 16-bit images to 8-bit (regression in 0.32.5).
[#3773](https://github.com/lovell/sharp/issues/3773)
* TypeScript: Add definitions for block and unblock.
[#3799](https://github.com/lovell/sharp/pull/3799)
[@ldrick](https://github.com/ldrick)
### v0.32.5 - 15th August 2023
* Upgrade to libvips v8.14.4 for upstream bug fixes.
* TypeScript: Add missing `WebpPresetEnum` to definitions.
[#3748](https://github.com/lovell/sharp/pull/3748)
[@pilotso11](https://github.com/pilotso11)
* Ensure compilation using musl v1.2.4.
[#3755](https://github.com/lovell/sharp/pull/3755)
[@kleisauke](https://github.com/kleisauke)
* Ensure resize with a `fit` of `inside` respects 90/270 degree rotation.
[#3756](https://github.com/lovell/sharp/issues/3756)
* TypeScript: Ensure `minSize` property of `WebpOptions` is boolean.
[#3758](https://github.com/lovell/sharp/pull/3758)
[@sho-xizz](https://github.com/sho-xizz)
* Ensure `withMetadata` adds default sRGB profile.
[#3761](https://github.com/lovell/sharp/issues/3761)
### v0.32.4 - 21st July 2023

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="998" height="243" viewBox="0 0 998 243">
<defs>
<g id="placeholder">
<rect width="180" height="128" fill="#64bed8"/>
<circle cx="61.1" cy="36.8" r="19.3" fill="#ffefa9"/>
<circle cx="61.1" cy="36.8" r="18.1" fill="#fdda42"/>
<path d="m67.2 34.7 15.2 46L90 57.9l30.4 38 7.8-15.2 7.5 15.4H44z" fill="#6a696f"/>
<path d="m82.4 80.7-15.2-46-.3 69h22.9z" fill="#474749"/>
<path d="m90.1 58 12.2 15 18.2 23-13.9.1z" fill="#474749"/>
<path d="M135.8 96H131l-2.8-15.3z" fill="#474749"/>
<path d="M35.2 96h107.1c0 1.7-1.4 3.2-3.2 3.2H38.4a3.2 3.2 0 0 1-3.2-3.2z" fill="#b9c861"/>
<path d="m67.2 34.7-.1 31-6.2-3-5.3 2.7z" fill="#fff"/>
<path d="m67.2 34.7 7.6 23-7.7 8z" fill="#b3b1b4"/>
<rect width="30.8" height="7.7" x="71.1" y="27.2" rx="2.8" ry="4.1" fill="#fff"/>
<rect width="30.8" height="7.7" x="82.2" y="34.8" rx="2.8" ry="4.1" fill="#fff"/>
<rect width="30.8" height="7.7" x="36.2" y="19.6" rx="2.8" ry="4.1" fill="#fff"/>
<path d="m89.6 72.8-7.2 7.9L90 57.9l10 23z" fill="#fff"/>
<path d="m90.1 58 10 23 2.2-8z" fill="#b3b1b4"/>
<path d="M131.2 85.2 137 68l9 17.2-8 6z" fill="#8da128"/>
<rect width="109.4" height="6.8" x="33.9" y="99.1" rx="13.2" ry="11.4" fill="#22b0d6"/>
<path d="m137 68-5.8 17.2 6.8 6.1.3-13.7z" fill="#727d2e"/>
<rect width="83.3" height="6.8" x="50.8" y="103.6" rx="10" ry="11.4" fill="#22b0d6"/>
<rect width=".7" height="18.4" x="138" y="77.6" fill="#585657"/>
<rect width=".5" height="5.2" x="2" y="-161.3" fill="#585657" transform="rotate(120)"/>
<rect width=".5" height="5.3" x="5.5" y="-163.3" fill="#585657" transform="rotate(120)"/>
<rect width=".5" height="4.8" x="-142.4" y="77.7" fill="#585657" transform="rotate(240)"/>
<rect width=".5" height="5.1" x="-146" y="75.6" fill="#585657" transform="rotate(240)"/>
</g>
<pattern id="img" height="100%" width="100%" viewBox="0 0 180 128">
<use xlink:href="#placeholder"/>
</pattern>
<pattern id="img-fill" width="100%" height="100%" viewBox="0 0 180 128" preserveAspectRatio="none">
<use xlink:href="#placeholder"/>
</pattern>
</defs>
<rect x="0" y="0" width="998" height="243" fill="#ddd"/>
<g id="cover">
<rect x="22" y="28" width="180" height="132" fill="url(#img)"/>
<rect x="48" y="30" width="128" height="128" fill="none" stroke="#000" stroke-width="4"/>
<text x="112" y="85%" dominant-baseline="middle" text-anchor="middle" font-family="sans" font-size="32" font-weight="bold">cover</text>
</g>
<g id="contain">
<rect x="240" y="30" width="128" height="128" fill="url(#img)" stroke="#000" stroke-width="4"/>
<text x="304" y="85%" dominant-baseline="middle" text-anchor="middle" font-family="sans" font-size="32" font-weight="bold" fill="#555">contain</text>
</g>
<g id="fill">
<rect x="432" y="30" width="128" height="128" fill="url(#img-fill)" stroke="#000" stroke-width="4"/>
<text x="496" y="85%" dominant-baseline="middle" text-anchor="middle" font-family="sans" font-size="32" font-weight="bold">fill</text>
</g>
<g id="inside">
<rect x="624" y="48" width="128" height="92" fill="url(#img)" stroke="#000" stroke-width="4"/>
<rect x="624" y="30" width="128" height="128" fill="none" stroke="#000" stroke-width="4" stroke-dasharray="12 4" stroke-dashoffset="6"/>
<text x="688" y="85%" dominant-baseline="middle" text-anchor="middle" font-family="sans" font-size="32" font-weight="bold" fill="#555">inside</text>
</g>
<g id="outside">
<rect x="792" y="30" width="176" height="128" fill="url(#img)" stroke="#000" stroke-width="4"/>
<rect x="816" y="30" width="128" height="128" fill="none" stroke="#000" stroke-width="4" stroke-dasharray="12 4" stroke-dashoffset="-2"/>
<text x="880" y="85%" dominant-baseline="middle" text-anchor="middle" font-family="sans" font-size="32" font-weight="bold">outside</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

File diff suppressed because one or more lines are too long

View File

@@ -40,7 +40,7 @@ for (const match of matches) {
].forEach((section) => {
const contents = fs.readFileSync(path.join(__dirname, '..', `api-${section}.md`), 'utf8');
const matches = contents.matchAll(
/## (?<title>[A-Za-z]+)\n(?<firstparagraph>.+?)\n\n.+?(?<parameters>\| Param .+?\n\n)?\*\*Example/gs
/## (?<title>[A-Za-z]+)\n[^\n]+\n(?<firstparagraph>.+?)\n\n.+?(?<parameters>\| Param .+?\n\n)?\*\*Example/gs
);
for (const match of matches) {
const { title, firstparagraph, parameters } = match.groups;

59
lib/index.d.ts vendored
View File

@@ -139,6 +139,52 @@ declare namespace sharp {
*/
function simd(enable?: boolean): boolean;
/**
* Block libvips operations at runtime.
*
* This is in addition to the `VIPS_BLOCK_UNTRUSTED` environment variable,
* which when set will block all "untrusted" operations.
*
* @since 0.32.4
*
* @example <caption>Block all TIFF input.</caption>
* sharp.block({
* operation: ['VipsForeignLoadTiff']
* });
*
* @param {Object} options
* @param {Array<string>} options.operation - List of libvips low-level operation names to block.
*/
function block(options: { operation: string[] }): void;
/**
* Unblock libvips operations at runtime.
*
* This is useful for defining a list of allowed operations.
*
* @since 0.32.4
*
* @example <caption>Block all input except WebP from the filesystem.</caption>
* sharp.block({
* operation: ['VipsForeignLoad']
* });
* sharp.unblock({
* operation: ['VipsForeignLoadWebpFile']
* });
*
* @example <caption>Block all input except JPEG and PNG from a Buffer or Stream.</caption>
* sharp.block({
* operation: ['VipsForeignLoad']
* });
* sharp.unblock({
* operation: ['VipsForeignLoadJpegBuffer', 'VipsForeignLoadPngBuffer']
* });
*
* @param {Object} options
* @param {Array<string>} options.operation - List of libvips low-level operation names to unblock.
*/
function unblock(options: { operation: string[] }): void;
//#endregion
const gravity: GravityEnum;
@@ -1124,9 +1170,11 @@ declare namespace sharp {
/** 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) */
minSize?: number;
minSize?: boolean;
/** Allow mixture of lossy and lossless animation frames (slow) (optional, default false) */
mixed?: boolean;
/** Preset options: one of default, photo, picture, drawing, icon, text (optional, default 'default') */
preset?: keyof PresetEnum | undefined;
}
interface AvifOptions extends OutputOptions {
@@ -1476,6 +1524,15 @@ declare namespace sharp {
lanczos3: 'lanczos3';
}
interface PresetEnum {
default: 'default';
picture: 'picture';
photo: 'photo';
drawing: 'drawing';
icon: 'icon';
text: 'text';
}
interface BoolEnum {
and: 'and';
or: 'or';

View File

@@ -432,6 +432,7 @@ function _isStreamInput () {
* - `isProgressive`: Boolean indicating whether the image is interlaced using a progressive scan
* - `pages`: Number of pages/frames contained within the image, with support for TIFF, HEIF, PDF, animated GIF and animated WebP
* - `pageHeight`: Number of pixels high each page in a multi-page image will be.
* - `paletteBitDepth`: Bit depth of palette-based image (GIF, PNG).
* - `loop`: Number of times to loop an animated image, zero refers to a continuous loop.
* - `delay`: Delay in ms between each page in an animated image, provided as an array of integers.
* - `pagePrimary`: Number of the primary page in a HEIF image

View File

@@ -19,7 +19,7 @@ const is = require('./is');
* If no angle is provided, it is determined from the EXIF data.
* Mirroring is supported and may infer the use of a flip operation.
*
* The use of `rotate` implies the removal of the EXIF `Orientation` tag, if any.
* The use of `rotate` without an angle will remove the EXIF `Orientation` tag, if any.
*
* Only one rotation can occur per pipeline.
* Previous calls to `rotate` in the same pipeline will be ignored.
@@ -83,8 +83,6 @@ function rotate (angle, options) {
* Mirror the image vertically (up-down) about the x-axis.
* This always occurs before rotation, if any.
*
* The use of `flip` implies the removal of the EXIF `Orientation` tag, if any.
*
* This operation does not work correctly with multi-page images.
*
* @example
@@ -102,8 +100,6 @@ function flip (flip) {
* Mirror the image horizontally (left-right) about the y-axis.
* This always occurs before rotation, if any.
*
* The use of `flop` implies the removal of the EXIF `Orientation` tag, if any.
*
* @example
* const output = await sharp(input).flop().toBuffer();
*

View File

@@ -162,8 +162,8 @@ function toBuffer (options, callback) {
/**
* Include all metadata (EXIF, XMP, IPTC) from the input image in the output image.
* This will also convert to and add a web-friendly sRGB ICC profile unless a custom
* output profile is provided.
* This will also convert to and add a web-friendly sRGB ICC profile if appropriate,
* unless a custom output profile is provided.
*
* The default behaviour, when `withMetadata` is not used, is to convert to the device-independent
* sRGB colour space and strip all metadata, including the removal of any ICC profile.
@@ -1046,6 +1046,7 @@ function jxl (options) {
*
* @param {Object} [options] - output options
* @param {string} [options.depth='uchar'] - bit depth, one of: char, uchar (default), short, ushort, int, uint, float, complex, double, dpcomplex
* @returns {Sharp}
* @throws {Error} Invalid options
*/
function raw (options) {

View File

@@ -126,7 +126,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.png">
* <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">
*
* 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`.

View File

@@ -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.32.4",
"version": "0.32.6",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://github.com/lovell/sharp",
"contributors": [
@@ -153,25 +153,25 @@
"mocha": "^10.2.0",
"mock-fs": "^5.2.0",
"nyc": "^15.1.0",
"prebuild": "lovell/prebuild#add-nodejs-20-drop-nodejs-10-and-12",
"prebuild": "^12.0.0",
"semistandard": "^16.0.1",
"tsd": "^0.28.1"
"tsd": "^0.29.0"
},
"license": "Apache-2.0",
"config": {
"libvips": "8.14.3",
"libvips": "8.14.5",
"integrity": {
"darwin-arm64v8": "sha512-zeb7jQ/5ARZfBH9Uy5wlpN05bFpiIN0qN3gIIpfJhpN0rhGDnjJZQgK0W+pOmG1YiLL42BMCS0SHldb0xE33rA==",
"darwin-x64": "sha512-C3N6smxdfprfz58cjojv0aekYXDl6+f9SwpGpxPG5RrZnrDMn5NOXtUQOEQ8PZ3Hd9VzfkJTnW/s36EvcMPfYg==",
"linux-arm64v8": "sha512-hT6B+OswqVQH10Fggq3jpOdn+GhxNx+5bk+EMr3lY3RZy72PZ+n4ZHJDfYSxAymdiz5rCdzGxsRLMb9GgD4OSw==",
"linux-armv6": "sha512-cW9giVrBssHXFt07l+PgqGu7P7XRDv7oW8jC6iXGBcjG75N7rXz2CK0DyPclfnyoWH4IQ78dh5SkQWmb6X4tig==",
"linux-armv7": "sha512-hgqFt3UkZHK6D91JtYrYmT1niznh+N93Zxj2EWXgTLAdcS1D3QqaDPEg2EhInHbXqYvfOuQYAAXPxt7zVtKqcw==",
"linux-x64": "sha512-FKbMBbCcFcSugRtuiTsA6Cov+M2WQ8nzvmmJ5xYYpRg/rsrWvObFT+6x/YBpblur9uXGjGIehjXVZtB3VXc+pg==",
"linuxmusl-arm64v8": "sha512-RTf6mrFyLGWnyt0DH4nHeXv5oSZMSJWxTdTt4cjvJsgp2Husz3mNJLQJGeehCuqPCYj/liJ9NIczw8u71eHFng==",
"linuxmusl-x64": "sha512-y/8UOkHzKhi/5UM1/ONyPvpuhO11nPQmuJWfzqUKj8kSKnDasmxv3FN46yI0XY3xA2oFC8lQNFBnLudQsi3Nvw==",
"win32-arm64v8": "sha512-D3PiVL981S7V0bSUwW3OqDS48H9QRw2vqQhYIY3JcIEssOnjWxmJGaz0Y9Zb8TYF5DHnnD6g5kEhob5Y2PIVEw==",
"win32-ia32": "sha512-FuLIaSIYJGJAcxyKkG/3/uuTzputekKSCcRCpRHkQS9J8IwM+yHzQeJ5W2PyAvNdeGIEwlYq3wnCNcXe1UGXWA==",
"win32-x64": "sha512-VQg4aBqpEfybgV8bjnrjfvnosxQDII/23mouFUfKHCsH5kvvHV5tTuPsxm6qbl+SCVploDK/zK1qpjop8YEvtg=="
"darwin-arm64v8": "sha512-1QZzICfCJd4wAO0P6qmYI5e5VFMt9iCE4QgefI8VMMbdSzjIXA9L/ARN6pkMQPZ3h20Y9RtJ2W1skgCsvCIccw==",
"darwin-x64": "sha512-sMIKMYXsdU9FlIfztj6Kt/SfHlhlDpP0Ups7ftVFqwjaszmYmpI9y/d/q3mLb4jrzuSiSUEislSWCwBnW7MPTw==",
"linux-arm64v8": "sha512-CD8owELzkDumaom+O3jJ8fKamILAQdj+//KK/VNcHK3sngUcFpdjx36C8okwbux9sml/T7GTB/gzpvReDrAejQ==",
"linux-armv6": "sha512-wk6IPHatDFVWKJy7lI1TJezHGHPQut1wF2bwx256KlZwXUQU3fcVcMpV1zxXjgLFewHq2+uhyMkoSGBPahWzlA==",
"linux-armv7": "sha512-HEZC9KYtkmBK5rUR2MqBhrVarnQVZ/TwLUeLkKq0XuoM2pc/eXI6N0Fh5NGEFwdXI2XE8g1ySf+OYS6DDi+xCQ==",
"linux-x64": "sha512-SlFWrITSW5XVUkaFPQOySAaSGXnhkGJCj8X2wGYYta9hk5piZldQyMp4zwy0z6UeRu1qKTKtZvmq28W3Gnh9xA==",
"linuxmusl-arm64v8": "sha512-ga9iX7WUva3sG/VsKkOD318InLlCfPIztvzCZKZ2/+izQXRbQi8VoXWMHgEN4KHACv45FTl7mJ/8CRqUzhS8wQ==",
"linuxmusl-x64": "sha512-yeaHnpfee1hrZLok2l4eFceHzlfq8gN3QOu0R4Mh8iMK5O5vAUu97bdtxeZZeJJvHw8tfh2/msGi0qysxKN8bw==",
"win32-arm64v8": "sha512-kR91hy9w1+GEXK56hLh51+hBCBo7T+ijM4Slkmvb/2PsYZySq5H7s61n99iDYl6kTJP2y9sW5Xcvm3uuXDaDgg==",
"win32-ia32": "sha512-HrnofEbzHNpHJ0vVnjsTj5yfgVdcqdWshXuwFO2zc8xlEjA83BvXZ0lVj9MxPxkxJ2ta+/UlLr+CFzc5bOceMw==",
"win32-x64": "sha512-BwKckinJZ0Fu/EcunqiLPwOLEBWp4xf8GV7nvmVuKKz5f6B+GxoA2k9aa2wueqv4r4RJVgV/aWXZWFKOIjre/Q=="
},
"runtime": "napi",
"target": 7

View File

@@ -964,12 +964,7 @@ namespace sharp {
}
std::pair<double, double> ResolveShrink(int width, int height, int targetWidth, int targetHeight,
Canvas canvas, bool swap, bool withoutEnlargement, bool withoutReduction) {
if (swap && canvas != Canvas::IGNORE_ASPECT) {
// Swap input width and height when requested.
std::swap(width, height);
}
Canvas canvas, bool withoutEnlargement, bool withoutReduction) {
double hshrink = 1.0;
double vshrink = 1.0;

View File

@@ -15,8 +15,8 @@
#if (VIPS_MAJOR_VERSION < 8) || \
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 14) || \
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 14 && VIPS_MICRO_VERSION < 3)
#error "libvips version 8.14.3+ is required - please see https://sharp.pixelplumbing.com/install"
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 14 && VIPS_MICRO_VERSION < 5)
#error "libvips version 8.14.5+ is required - please see https://sharp.pixelplumbing.com/install"
#endif
#if ((!defined(__clang__)) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)))
@@ -362,13 +362,10 @@ namespace sharp {
VImage EnsureAlpha(VImage image, double const value);
/*
Calculate the shrink factor, taking into account auto-rotate, the canvas
mode, and so on. The hshrink/vshrink are the amount to shrink the input
image axes by in order for the output axes (ie. after rotation) to match
the required thumbnail width/height and canvas mode.
Calculate the horizontal and vertical shrink factors, taking the canvas mode into account.
*/
std::pair<double, double> ResolveShrink(int width, int height, int targetWidth, int targetHeight,
Canvas canvas, bool swap, bool withoutEnlargement, bool withoutReduction);
Canvas canvas, bool withoutEnlargement, bool withoutReduction);
/*
Ensure decoding remains sequential.

View File

@@ -20,18 +20,15 @@
#include "operations.h"
#include "pipeline.h"
#if defined(WIN32)
#ifdef _WIN32
#define STAT64_STRUCT __stat64
#define STAT64_FUNCTION _stat64
#elif defined(__APPLE__)
#define STAT64_STRUCT stat
#define STAT64_FUNCTION stat
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
#define STAT64_STRUCT stat
#define STAT64_FUNCTION stat
#else
#elif defined(_LARGEFILE64_SOURCE)
#define STAT64_STRUCT stat64
#define STAT64_FUNCTION stat64
#else
#define STAT64_STRUCT stat
#define STAT64_FUNCTION stat
#endif
class PipelineWorker : public Napi::AsyncWorker {
@@ -160,15 +157,18 @@ class PipelineWorker : public Napi::AsyncWorker {
int targetResizeWidth = baton->width;
int targetResizeHeight = baton->height;
// Swap input output width and height when rotating by 90 or 270 degrees
bool swap = !baton->rotateBeforePreExtract &&
(rotation == VIPS_ANGLE_D90 || rotation == VIPS_ANGLE_D270 ||
autoRotation == VIPS_ANGLE_D90 || autoRotation == VIPS_ANGLE_D270);
// When auto-rotating by 90 or 270 degrees, swap the target width and
// height to ensure the behavior aligns with how it would have been if
// the rotation had taken place *before* resizing.
if (!baton->rotateBeforePreExtract &&
(autoRotation == VIPS_ANGLE_D90 || autoRotation == VIPS_ANGLE_D270)) {
std::swap(targetResizeWidth, targetResizeHeight);
}
// Shrink to pageHeight, so we work for multi-page images
std::tie(hshrink, vshrink) = sharp::ResolveShrink(
inputWidth, pageHeight, targetResizeWidth, targetResizeHeight,
baton->canvas, swap, baton->withoutEnlargement, baton->withoutReduction);
baton->canvas, baton->withoutEnlargement, baton->withoutReduction);
// The jpeg preload shrink.
int jpegShrinkOnLoad = 1;
@@ -302,7 +302,7 @@ class PipelineWorker : public Napi::AsyncWorker {
// Shrink to pageHeight, so we work for multi-page images
std::tie(hshrink, vshrink) = sharp::ResolveShrink(
inputWidth, pageHeight, targetResizeWidth, targetResizeHeight,
baton->canvas, swap, baton->withoutEnlargement, baton->withoutReduction);
baton->canvas, baton->withoutEnlargement, baton->withoutReduction);
int targetHeight = static_cast<int>(std::rint(static_cast<double>(pageHeight) / vshrink));
int targetPageHeight = targetHeight;
@@ -326,7 +326,7 @@ class PipelineWorker : public Napi::AsyncWorker {
try {
image = image.icc_transform(processingProfile, VImage::option()
->set("embedded", TRUE)
->set("depth", image.interpretation() == VIPS_INTERPRETATION_RGB16 ? 16 : 8)
->set("depth", sharp::Is16Bit(image.interpretation()) ? 16 : 8)
->set("intent", VIPS_INTENT_PERCEPTUAL));
} catch(...) {
sharp::VipsWarningCallback(nullptr, G_LOG_LEVEL_WARNING, "Invalid embedded profile", nullptr);
@@ -653,7 +653,7 @@ class PipelineWorker : public Napi::AsyncWorker {
if (across != 0 || down != 0) {
int left;
int top;
compositeImage = compositeImage.replicate(across, down);
compositeImage = sharp::StaySequential(compositeImage, access).replicate(across, down);
if (composite->hasOffset) {
std::tie(left, top) = sharp::CalculateCrop(
compositeImage.width(), compositeImage.height(), image.width(), image.height(),
@@ -763,6 +763,7 @@ class PipelineWorker : public Napi::AsyncWorker {
if (baton->withMetadata && sharp::HasProfile(image) && baton->withMetadataIcc.empty()) {
image = image.icc_transform("srgb", VImage::option()
->set("embedded", TRUE)
->set("depth", sharp::Is16Bit(image.interpretation()) ? 16 : 8)
->set("intent", VIPS_INTENT_PERCEPTUAL));
}
}
@@ -788,12 +789,13 @@ class PipelineWorker : public Napi::AsyncWorker {
}
// Apply output ICC profile
if (!baton->withMetadataIcc.empty()) {
if (baton->withMetadata) {
image = image.icc_transform(
const_cast<char*>(baton->withMetadataIcc.data()),
baton->withMetadataIcc.empty() ? "srgb" : const_cast<char*>(baton->withMetadataIcc.data()),
VImage::option()
->set("input_profile", processingProfile)
->set("embedded", TRUE)
->set("depth", sharp::Is16Bit(image.interpretation()) ? 16 : 8)
->set("intent", VIPS_INTENT_PERCEPTUAL));
}
// Override EXIF Orientation tag

View File

@@ -5,7 +5,7 @@ ARG BRANCH=main
RUN apt-get -y update && apt-get install -y build-essential curl git
# Install latest Node.js LTS
RUN curl -fsSL https://deb.nodesource.com/setup_16.x | bash -
RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash -
RUN apt-get install -y nodejs
# Install benchmark dependencies
@@ -23,4 +23,9 @@ RUN cat /etc/os-release | grep VERSION=
RUN node -v
WORKDIR /tmp/sharp/test/bench
# Workaround for: https://github.com/emscripten-core/emscripten/pull/16917
# This could be removed once Squoosh is an optional dependency.
ENV NODE_OPTIONS="--no-experimental-fetch"
CMD [ "node", "perf" ]

View File

@@ -9,15 +9,15 @@
},
"dependencies": {
"@squoosh/cli": "0.7.3",
"@squoosh/lib": "0.4.0",
"@squoosh/lib": "0.5.3",
"async": "3.2.4",
"benchmark": "2.1.4",
"gm": "1.25.0",
"imagemagick": "0.1.3",
"jimp": "0.22.7"
"jimp": "0.22.10"
},
"optionalDependencies": {
"@tensorflow/tfjs-node": "4.2.0",
"@tensorflow/tfjs-node": "4.9.0",
"mapnik": "4.5.9"
},
"license": "Apache-2.0",

View File

@@ -109,7 +109,7 @@ async.series({
jpegSuite.add('squoosh-lib-buffer-buffer', {
defer: true,
fn: function (deferred) {
const pool = new squoosh.ImagePool();
const pool = new squoosh.ImagePool(os.cpus().length);
const image = pool.ingestImage(inputJpgBuffer);
image.decoded
.then(function () {
@@ -652,7 +652,7 @@ async.series({
throw err;
} else {
image
.resize(width, heightPng)
.resize(width, heightPng, jimp.RESIZE_BICUBIC)
.deflateLevel(6)
.filterType(0)
.getBuffer(jimp.MIME_PNG, function (err) {
@@ -673,7 +673,7 @@ async.series({
throw err;
} else {
image
.resize(width, heightPng)
.resize(width, heightPng, jimp.RESIZE_BICUBIC)
.deflateLevel(6)
.filterType(0)
.write(outputPng, function (err) {
@@ -707,7 +707,7 @@ async.series({
pngSuite.add('squoosh-lib-buffer-buffer', {
defer: true,
fn: function (deferred) {
const pool = new squoosh.ImagePool();
const pool = new squoosh.ImagePool(os.cpus().length);
const image = pool.ingestImage(inputPngBuffer);
image.decoded
.then(function () {

View File

@@ -524,7 +524,7 @@ sharp('input.tiff').jxl({ lossless: true }).toFile('out.jxl');
sharp('input.tiff').jxl({ effort: 7 }).toFile('out.jxl');
// Support `minSize` and `mixed` webp options
sharp('input.tiff').webp({ minSize: 1000, mixed: true }).toFile('out.gif');
sharp('input.tiff').webp({ minSize: true, mixed: true }).toFile('out.gif');
// 'failOn' input param
sharp('input.tiff', { failOn: 'none' });
@@ -651,3 +651,13 @@ sharp(input).composite([
unlimited: true,
}
]);
// Support for webp preset in types
// https://github.com/lovell/sharp/issues/3747
sharp('input.tiff').webp({ preset: 'photo' }).toFile('out.webp');
sharp('input.tiff').webp({ preset: 'picture' }).toFile('out.webp');
sharp('input.tiff').webp({ preset: 'icon' }).toFile('out.webp');
sharp('input.tiff').webp({ preset: 'drawing' }).toFile('out.webp');
sharp('input.tiff').webp({ preset: 'text' }).toFile('out.webp');
sharp('input.tiff').webp({ preset: 'default' }).toFile('out.webp');

View File

@@ -472,4 +472,28 @@ describe('composite', () => {
assert.strictEqual(b, 19);
assert.strictEqual(a, 128);
});
it('Ensure tiled overlay is fully decoded', async () => {
const tile = await sharp({
create: {
width: 8, height: 513, channels: 3, background: 'red'
}
})
.png({ compressionLevel: 0 })
.toBuffer();
const { info } = await sharp({
create: {
width: 8, height: 514, channels: 3, background: 'green'
}
})
.composite([{
input: tile,
tile: true
}])
.toBuffer({ resolveWithObject: true });
assert.strictEqual(info.width, 8);
assert.strictEqual(info.height, 514);
});
});

View File

@@ -781,6 +781,55 @@ describe('Image metadata', function () {
});
});
it('withMetadata adds default sRGB profile', async () => {
const data = await sharp(fixtures.inputJpg)
.resize(32, 24)
.withMetadata()
.toBuffer();
const metadata = await sharp(data).metadata();
const { colorSpace, deviceClass, intent } = icc.parse(metadata.icc);
assert.strictEqual(colorSpace, 'RGB');
assert.strictEqual(deviceClass, 'Monitor');
assert.strictEqual(intent, 'Perceptual');
});
it('withMetadata adds default sRGB profile to RGB16', async () => {
const data = await sharp({
create: {
width: 8, height: 8, channels: 4, background: 'orange'
}
})
.toColorspace('rgb16')
.png()
.withMetadata()
.toBuffer();
const metadata = await sharp(data).metadata();
assert.strictEqual(metadata.depth, 'ushort');
const { description } = icc.parse(metadata.icc);
assert.strictEqual(description, 'sRGB');
});
it('withMetadata adds P3 profile to 16-bit PNG', async () => {
const data = await sharp({
create: {
width: 8, height: 8, channels: 4, background: 'orange'
}
})
.toColorspace('rgb16')
.png()
.withMetadata({ icc: 'p3' })
.toBuffer();
const metadata = await sharp(data).metadata();
assert.strictEqual(metadata.depth, 'ushort');
const { description } = icc.parse(metadata.icc);
assert.strictEqual(description, 'sP3C');
});
it('File input with corrupt header fails gracefully', function (done) {
sharp(fixtures.inputJpgWithCorruptHeader)
.metadata(function (err) {

View File

@@ -192,6 +192,23 @@ describe('Rotation', function () {
});
});
it('Auto-rotate by 270 degrees, rectangular output ignoring aspect ratio', function (done) {
sharp(fixtures.inputJpgWithLandscapeExif8)
.resize(320, 240, { fit: sharp.fit.fill })
.rotate()
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(320, info.width);
assert.strictEqual(240, info.height);
sharp(data).metadata(function (err, metadata) {
if (err) throw err;
assert.strictEqual(320, metadata.width);
assert.strictEqual(240, metadata.height);
done();
});
});
});
it('Rotate by 30 degrees, rectangular output ignoring aspect ratio', function (done) {
sharp(fixtures.inputJpg)
.resize(320, 240, { fit: sharp.fit.fill })
@@ -489,4 +506,28 @@ describe('Rotation', function () {
.timeout({ seconds: 5 })
.toBuffer()
);
it('Rotate 90 then resize with inside fit', async () => {
const data = await sharp({ create: { width: 16, height: 8, channels: 3, background: 'red' } })
.rotate(90)
.resize({ width: 6, fit: 'inside' })
.png({ compressionLevel: 0 })
.toBuffer();
const { width, height } = await sharp(data).metadata();
assert.strictEqual(width, 6);
assert.strictEqual(height, 12);
});
it('Resize with inside fit then rotate 90', async () => {
const data = await sharp({ create: { width: 16, height: 8, channels: 3, background: 'red' } })
.resize({ width: 6, fit: 'inside' })
.rotate(90)
.png({ compressionLevel: 0 })
.toBuffer();
const { width, height } = await sharp(data).metadata();
assert.strictEqual(width, 3);
assert.strictEqual(height, 6);
});
});